blob: 8d098efba5b638be6ce6f3e0a2992013ad017285 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use lazy_static::lazy_static;
use regex::Regex;
use std::{
fs::File,
io::{self, BufRead, BufReader},
path::{Path, PathBuf},
};
#[derive(Clone, Debug)]
pub struct Owners {
#[allow(unused)]
pub path: PathBuf,
pub users: Vec<String>,
pub component: Option<String>,
}
impl Owners {
/// Reads an OWNERS file and parses out the usernames and component name.
/// NOTE: this ignores per-file components/owners for simplicity, as
/// well as multiple-components (which are quite rare). "include" syntax
/// currently isn't supported either, but may be handled in the future.
pub fn from_file(filename: &Path) -> io::Result<Self> {
lazy_static! {
static ref USER: Regex = Regex::new(r"(\w+)@google.com").unwrap();
static ref COMP: Regex = Regex::new(r"COMPONENT: *(\S+)").unwrap();
}
let mut users = Vec::new();
let mut component = None;
for line in BufReader::new(File::open(&filename)?).lines() {
let line = line?;
if let Some(cap) = USER.captures(&line) {
users.push(cap.get(1).unwrap().as_str().to_owned());
} else if let Some(cap) = COMP.captures(&line) {
component = Some(cap.get(1).unwrap().as_str().to_owned());
}
}
Ok(Self { path: filename.to_path_buf(), users, component })
}
}
/// Walks up the directory tree and gathers any OWNERS files found. The
/// returned list starts with the _closest_ OWNERS file to the given path, and
/// it does NOT include OWNERS files in the root dir.
pub fn get_owners(path: &Path, root: &Path) -> Vec<Owners> {
let mut prev: &Path = &root.join(path);
let mut all_owners = Vec::new();
while let Some(current) = prev.parent() {
if current == root {
break;
}
let ownersfile = current.join("OWNERS");
if ownersfile.exists() {
if let Ok(owners) = Owners::from_file(&ownersfile) {
all_owners.push(owners);
}
}
prev = current;
}
all_owners
}