use std::path::PathBuf; use structopt::StructOpt; use structopt::clap::ErrorKind as ClapError; // To get effective user id (EUID) so that setuid works use users::{get_effective_uid,get_user_by_uid}; // For home directory use users::os::unix::UserExt; use crate::log; use crate::log::Context; #[derive(Debug, StructOpt)] #[structopt( name = "forgebuild", about = "Update your repositories and trigger tasks" )] pub struct Cli { #[structopt(short = "f", long = "force")] pub force: bool, #[structopt(short = "b", long = "basedir")] pub basedir: Option, #[structopt(long = "inbox")] pub inbox: bool, #[structopt(long = "inbox-folder")] pub inboxdir: Option, //#[structopt(def)] pub tasks: Vec, } impl Cli { /// Builds the command-line from passed arguments /// Returns the Cli instance alongside a PathBuf of the basedir pub fn build() -> (Self, PathBuf) { // We create a dedicated context so we don't have to pass it as argument let mut context = Context::new(); // We don't want to use structopt's error handler for unknown argument as we have our own // error message for that case (unknown_arg). So we use from_iter_safe() not from_args() match Cli::from_iter_safe(std::env::args()) { Ok(cmd) => { // Parsing was successful, but we'd like to ensure requested basedir exists match cmd.basedir().canonicalize() { Ok(p) => { (cmd, p) }, Err(_) => { // Missing basedir context.insert("$i18n_basedir".to_string(), cmd.basedir().to_str().unwrap().to_string()); log::error("missing_basedir", &context); std::process::exit(1); } } }, Err(e) => { match &e.kind { ClapError::UnknownArgument => { context.insert("$i18n_arg".to_string(), e.info.unwrap().first().unwrap().to_string()); log::error("unknown_arg", &context); std::process::exit(1); }, _ => e.exit() } } } } /// Returns a PathBuf to the basedir. If it's a relative link, /// it's not expanded here! Panics if no basedir is provided and $HOME isn't defined pub fn basedir(&self) -> PathBuf { if let Some(basedir) = &self.basedir { // Returns an error when the path doesn't exist PathBuf::from(basedir) } else { let owner = get_effective_uid(); let mut home_path = get_user_by_uid(owner).expect("Failed owner profile") .home_dir().to_path_buf(); home_path.push(".forgebuild"); home_path } } }