diff --git a/rust/rhg/src/commands/cat.rs b/rust/rhg/src/commands/cat.rs --- a/rust/rhg/src/commands/cat.rs +++ b/rust/rhg/src/commands/cat.rs @@ -1,14 +1,10 @@ use crate::error::CommandError; -use crate::ui::Ui; use clap::Arg; -use clap::ArgMatches; -use hg::config::Config; use hg::operations::cat; use hg::repo::Repo; use hg::utils::hg_path::HgPathBuf; use micro_timer::timed; use std::convert::TryFrom; -use std::path::Path; pub const HELP_TEXT: &str = " Output the current or given revision of files @@ -36,19 +32,14 @@ } #[timed] -pub fn run( - ui: &Ui, - config: &Config, - repo_path: Option<&Path>, - args: &ArgMatches, -) -> Result<(), CommandError> { - let rev = args.value_of("rev"); - let file_args = match args.values_of("files") { +pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> { + let rev = invocation.subcommand_args.value_of("rev"); + let file_args = match invocation.subcommand_args.values_of("files") { Some(files) => files.collect(), None => vec![], }; - let repo = Repo::find(config, repo_path)?; + let repo = Repo::find(invocation.non_repo_config, invocation.repo_path)?; let cwd = hg::utils::current_dir()?; let mut files = vec![]; @@ -67,7 +58,7 @@ match rev { Some(rev) => { let data = cat(&repo, rev, &files).map_err(|e| (e, rev))?; - ui.write_stdout(&data)?; + invocation.ui.write_stdout(&data)?; Ok(()) } None => Err(CommandError::Unimplemented.into()), diff --git a/rust/rhg/src/commands/config.rs b/rust/rhg/src/commands/config.rs --- a/rust/rhg/src/commands/config.rs +++ b/rust/rhg/src/commands/config.rs @@ -1,13 +1,9 @@ use crate::error::CommandError; -use crate::ui::Ui; use clap::Arg; -use clap::ArgMatches; use format_bytes::format_bytes; -use hg::config::Config; use hg::errors::HgError; use hg::repo::Repo; use hg::utils::SliceExt; -use std::path::Path; pub const HELP_TEXT: &str = " With one argument of the form section.name, print just the value of that config item. @@ -25,20 +21,16 @@ .about(HELP_TEXT) } -pub fn run( - ui: &Ui, - config: &Config, - repo_path: Option<&Path>, - args: &ArgMatches, -) -> Result<(), CommandError> { - let opt_repo = Repo::find_optional(config, repo_path)?; +pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> { + let opt_repo = + Repo::find_optional(invocation.non_repo_config, invocation.repo_path)?; let config = if let Some(repo) = &opt_repo { repo.config() } else { - config + invocation.non_repo_config }; - - let (section, name) = args + let (section, name) = invocation + .subcommand_args .value_of("name") .expect("missing required CLI argument") .as_bytes() @@ -47,6 +39,6 @@ let value = config.get(section, name).unwrap_or(b""); - ui.write_stdout(&format_bytes!(b"{}\n", value))?; + invocation.ui.write_stdout(&format_bytes!(b"{}\n", value))?; Ok(()) } diff --git a/rust/rhg/src/commands/debugdata.rs b/rust/rhg/src/commands/debugdata.rs --- a/rust/rhg/src/commands/debugdata.rs +++ b/rust/rhg/src/commands/debugdata.rs @@ -1,13 +1,9 @@ use crate::error::CommandError; -use crate::ui::Ui; use clap::Arg; use clap::ArgGroup; -use clap::ArgMatches; -use hg::config::Config; use hg::operations::{debug_data, DebugDataKind}; use hg::repo::Repo; use micro_timer::timed; -use std::path::Path; pub const HELP_TEXT: &str = " Dump the contents of a data file revision @@ -42,12 +38,8 @@ } #[timed] -pub fn run( - ui: &Ui, - config: &Config, - repo_path: Option<&Path>, - args: &ArgMatches, -) -> Result<(), CommandError> { +pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> { + let args = invocation.subcommand_args; let rev = args .value_of("rev") .expect("rev should be a required argument"); @@ -63,10 +55,10 @@ } }; - let repo = Repo::find(config, repo_path)?; + let repo = Repo::find(invocation.non_repo_config, invocation.repo_path)?; let data = debug_data(&repo, rev, kind).map_err(|e| (e, rev))?; - let mut stdout = ui.stdout_buffer(); + let mut stdout = invocation.ui.stdout_buffer(); stdout.write_all(&data)?; stdout.flush()?; diff --git a/rust/rhg/src/commands/debugrequirements.rs b/rust/rhg/src/commands/debugrequirements.rs --- a/rust/rhg/src/commands/debugrequirements.rs +++ b/rust/rhg/src/commands/debugrequirements.rs @@ -1,9 +1,5 @@ use crate::error::CommandError; -use crate::ui::Ui; -use clap::ArgMatches; -use hg::config::Config; use hg::repo::Repo; -use std::path::Path; pub const HELP_TEXT: &str = " Print the current repo requirements. @@ -13,13 +9,8 @@ clap::SubCommand::with_name("debugrequirements").about(HELP_TEXT) } -pub fn run( - ui: &Ui, - config: &Config, - repo_path: Option<&Path>, - _args: &ArgMatches, -) -> Result<(), CommandError> { - let repo = Repo::find(config, repo_path)?; +pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> { + let repo = Repo::find(invocation.non_repo_config, invocation.repo_path)?; let mut output = String::new(); let mut requirements: Vec<_> = repo.requirements().iter().collect(); requirements.sort(); @@ -27,6 +18,6 @@ output.push_str(req); output.push('\n'); } - ui.write_stdout(output.as_bytes())?; + invocation.ui.write_stdout(output.as_bytes())?; Ok(()) } diff --git a/rust/rhg/src/commands/files.rs b/rust/rhg/src/commands/files.rs --- a/rust/rhg/src/commands/files.rs +++ b/rust/rhg/src/commands/files.rs @@ -1,14 +1,11 @@ use crate::error::CommandError; use crate::ui::Ui; use clap::Arg; -use clap::ArgMatches; -use hg::config::Config; use hg::operations::list_rev_tracked_files; use hg::operations::Dirstate; use hg::repo::Repo; use hg::utils::files::{get_bytes_from_path, relativize_path}; use hg::utils::hg_path::{HgPath, HgPathBuf}; -use std::path::Path; pub const HELP_TEXT: &str = " List tracked files. @@ -29,23 +26,18 @@ .about(HELP_TEXT) } -pub fn run( - ui: &Ui, - config: &Config, - repo_path: Option<&Path>, - args: &ArgMatches, -) -> Result<(), CommandError> { - let rev = args.value_of("rev"); +pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> { + let rev = invocation.subcommand_args.value_of("rev"); - let repo = Repo::find(config, repo_path)?; + let repo = Repo::find(invocation.non_repo_config, invocation.repo_path)?; if let Some(rev) = rev { let files = list_rev_tracked_files(&repo, rev).map_err(|e| (e, rev))?; - display_files(ui, &repo, files.iter()) + display_files(invocation.ui, &repo, files.iter()) } else { let distate = Dirstate::new(&repo)?; let files = distate.tracked_files()?; - display_files(ui, &repo, files) + display_files(invocation.ui, &repo, files) } } diff --git a/rust/rhg/src/commands/root.rs b/rust/rhg/src/commands/root.rs --- a/rust/rhg/src/commands/root.rs +++ b/rust/rhg/src/commands/root.rs @@ -1,11 +1,7 @@ use crate::error::CommandError; -use crate::ui::Ui; -use clap::ArgMatches; use format_bytes::format_bytes; -use hg::config::Config; use hg::repo::Repo; use hg::utils::files::get_bytes_from_path; -use std::path::Path; pub const HELP_TEXT: &str = " Print the root directory of the current repository. @@ -17,14 +13,11 @@ clap::SubCommand::with_name("root").about(HELP_TEXT) } -pub fn run( - ui: &Ui, - config: &Config, - repo_path: Option<&Path>, - _args: &ArgMatches, -) -> Result<(), CommandError> { - let repo = Repo::find(config, repo_path)?; +pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> { + let repo = Repo::find(invocation.non_repo_config, invocation.repo_path)?; let bytes = get_bytes_from_path(repo.working_directory_path()); - ui.write_stdout(&format_bytes!(b"{}\n", bytes.as_slice()))?; + invocation + .ui + .write_stdout(&format_bytes!(b"{}\n", bytes.as_slice()))?; Ok(()) } diff --git a/rust/rhg/src/main.rs b/rust/rhg/src/main.rs --- a/rust/rhg/src/main.rs +++ b/rust/rhg/src/main.rs @@ -1,9 +1,11 @@ extern crate log; +use crate::ui::Ui; use clap::App; use clap::AppSettings; use clap::Arg; use clap::ArgMatches; use format_bytes::format_bytes; +use hg::config::Config; use std::path::Path; mod error; @@ -48,31 +50,41 @@ let (subcommand_name, subcommand_matches) = matches.subcommand(); let run = subcommand_run_fn(subcommand_name) .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired"); - let args = subcommand_matches + let subcommand_args = subcommand_matches .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired"); // Global arguments can be in either based on e.g. `hg -R ./foo log` v.s. // `hg log -R ./foo` - let value_of_global_arg = - |name| args.value_of_os(name).or_else(|| matches.value_of_os(name)); + let value_of_global_arg = |name| { + subcommand_args + .value_of_os(name) + .or_else(|| matches.value_of_os(name)) + }; // For arguments where multiple occurences are allowed, return a // possibly-iterator of all values. let values_of_global_arg = |name: &str| { let a = matches.values_of_os(name).into_iter().flatten(); - let b = args.values_of_os(name).into_iter().flatten(); + let b = subcommand_args.values_of_os(name).into_iter().flatten(); a.chain(b) }; - let repo_path = value_of_global_arg("repository").map(Path::new); let config_args = values_of_global_arg("config") // `get_bytes_from_path` works for OsStr the same as for Path .map(hg::utils::files::get_bytes_from_path); - let config = hg::config::Config::load(config_args)?; - run(&ui, &config, repo_path, args) + let non_repo_config = &hg::config::Config::load(config_args)?; + + let repo_path = value_of_global_arg("repository").map(Path::new); + + run(&CliInvocation { + ui, + subcommand_args, + non_repo_config, + repo_path, + }) } fn main() { - let ui = ui::Ui::new(); + let ui = Ui::new(); let exit_code = match main_with_result(&ui) { Ok(()) => exitcode::OK, @@ -109,12 +121,9 @@ )+ } - fn subcommand_run_fn(name: &str) -> Option, - &ArgMatches, - ) -> Result<(), CommandError>> { + pub type RunFn = fn(&CliInvocation) -> Result<(), CommandError>; + + fn subcommand_run_fn(name: &str) -> Option { match name { $( stringify!($command) => Some(commands::$command::run), @@ -133,3 +142,9 @@ root config } +pub struct CliInvocation<'a> { + ui: &'a Ui, + subcommand_args: &'a ArgMatches<'a>, + non_repo_config: &'a Config, + repo_path: Option<&'a Path>, +}