diff --git a/src/cli.rs b/src/cli.rs index 754709f..23700af 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,12 +1,16 @@ use std::env; 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", @@ -24,6 +28,42 @@ pub struct Cli { } 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 { diff --git a/src/main.rs b/src/main.rs index e4e9610..485e91c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,4 @@ use std::env::{set_current_dir as cd, set_var}; -use structopt::StructOpt; -use structopt::clap::ErrorKind as ClapError; -// For UNIX extended metadata mod cli; mod db; @@ -13,41 +10,8 @@ use log::Context; fn main() -> Result<(), std::io::Error> { let mut context = Context::new(); - - // TODO: use StructOpt::from_iter_safe so we can hook on Cli error - // to display additional unknown_arg error message. - //let cmd = cli::Cli::from_args(); - let res = cli::Cli::from_iter_safe(std::env::args()); - if res.is_err() { - let e = res.unwrap_err(); - 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); - }, - /*ClapError::HelpDisplayed { - e.exit() - }*/ - _ => e.exit() - } - } - let cmd = res.unwrap(); - - let basedir = cmd.basedir(); + let (cmd, basedir) = cli::Cli::build(); context.insert("$i18n_basedir".to_string(), basedir.to_str().unwrap().to_string()); - - let basedir = match basedir.canonicalize() { - Ok(p) => { - context.insert("$i18n_basedir".to_string(), p.to_str().unwrap().to_string()); - p - }, - Err(_) => { - log::error("missing_basedir", &context); - std::process::exit(1); - } - }; - let basedir_str = basedir.to_str().unwrap().to_string(); set_var("GITBUILDDIR", &basedir);