git-codeowners 0.1.2

Rust cli for working with Github CODEOWNERS files
extern crate codeowners;
extern crate clap;

use codeowners::Owner;
use clap::{App, Arg};
use std::path::Path;
use std::process::exit;
use std::io::{self, BufRead};

fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .about("Github CODEOWNERS answer sheet")
        .arg(
            Arg::with_name("codeowners")
                .help("An explicit path for a CODEOWNERS file. program will exit 1 if file can not be resolved")
                .takes_value(true)
                .short("c")
                .long("codeowners"),
        )
        .arg(
            Arg::with_name("teams")
                .help("Only return teams")
                .short("t")
                .long("teams")
                .conflicts_with("users")
                .conflicts_with("emails"),
        )
        .arg(
            Arg::with_name("users")
                .help("Only return users")
                .short("u")
                .long("users")
                .conflicts_with("teams")
                .conflicts_with("emails"),
        )
        .arg(
            Arg::with_name("emails")
                .help("Only return emails")
                .short("e")
                .long("emails")
                .conflicts_with("teams")
                .conflicts_with("users"),
        )
        .arg(
            Arg::with_name("path")
                .help(
                    "Path of file in git repo. if '-' is provided path will \
                     be read from stdin. program will exit 2 if no owners can \
                     be resolved",
                )
                .index(1)
                .required(true),
        )
        .get_matches();
    let ownersfile = match matches.value_of("codeowners") {
        Some(path) => {
            let p = Path::new(path);
            if p.exists() {
                Some(p.to_path_buf())
            } else {
                None
            }
        }
        _ => codeowners::locate("."),
    };
    match ownersfile {
        Some(file) => {
            let resolve = |path: &str| {
                let owners = codeowners::from_path(file.clone());
                let (teams, users, emails) = (
                    matches.occurrences_of("teams") > 0,
                    matches.occurrences_of("users") > 0,
                    matches.occurrences_of("emails") > 0,
                );
                match owners.of(path) {
                    None => exit(2),
                    Some(owners) => {
                        let owned = owners
                            .iter()
                            .filter_map(|owner| if teams {
                                match owner {
                                    &Owner::Team(ref inner) => Some(inner.clone()),
                                    _ => None,
                                }
                            } else if users {
                                match owner {
                                    &Owner::Username(ref inner) => Some(inner.clone()),
                                    _ => None,
                                }
                            } else if emails {
                                match owner {
                                    &Owner::Email(ref inner) => Some(inner.clone()),
                                    _ => None,
                                }
                            } else {
                                Some(owner.to_string())
                            })
                            .collect::<Vec<_>>();
                        if owned.is_empty() {
                            exit(2)
                        } else {
                            println!("{}", owned.join(" "));
                        }
                    }
                }
            };
            match matches.value_of("path").unwrap().as_ref() {
                "-" => {
                    let stdin = io::stdin();
                    for path in stdin.lock().lines().filter_map(Result::ok) {
                        resolve(&path);
                    }
                }
                path => resolve(path),
            }
        }
        _ => exit(1),
    }

}