From d7911ff2796162691a50725ceaa6e92bb37968cb Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Wed, 4 Jan 2023 17:18:45 +0900 Subject: [PATCH] cli: move ui.cwd() to CommandHelper I'm going to remove owned UserSettings from Ui so that UserSettings can be instantiated after both user and repo configs are loaded. ui.cwd() belongs to the same category (random environment stuff), and Ui doesn't depend on it, so let's remove it first from Ui. I'm not pretty sure if CommandHelper and WorkspaceCommandHelper should be a permanent home for cwd and settings, but it works for now as CommandHelper is immutable. --- examples/custom-backend/main.rs | 4 ++-- src/cli_util.rs | 17 ++++++++++++++--- src/commands.rs | 13 +++++++------ src/ui.rs | 8 -------- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/examples/custom-backend/main.rs b/examples/custom-backend/main.rs index 03d138c95..3dfe04a9c 100644 --- a/examples/custom-backend/main.rs +++ b/examples/custom-backend/main.rs @@ -45,12 +45,12 @@ fn create_store_factories() -> StoreFactories { fn run_custom_command( ui: &mut Ui, - _command_helper: &CommandHelper, + command_helper: &CommandHelper, command: CustomCommands, ) -> Result<(), CommandError> { match command { CustomCommands::InitJit => { - let wc_path = ui.cwd(); + let wc_path = command_helper.cwd(); // Initialize a workspace with the custom backend Workspace::init_with_backend(ui.settings(), wc_path, |store_path| { Box::new(JitBackend::init(store_path)) diff --git a/src/cli_util.rs b/src/cli_util.rs index e07fa135b..abeb8451d 100644 --- a/src/cli_util.rs +++ b/src/cli_util.rs @@ -13,7 +13,7 @@ // limitations under the License. use std::collections::{HashSet, VecDeque}; -use std::env::{ArgsOs, VarError}; +use std::env::{self, ArgsOs, VarError}; use std::ffi::{OsStr, OsString}; use std::fmt::Debug; use std::iter; @@ -260,6 +260,7 @@ impl TracingSubscription { pub struct CommandHelper { app: clap::Command, + cwd: PathBuf, string_args: Vec, global_args: GlobalArgs, store_factories: StoreFactories, @@ -268,12 +269,14 @@ pub struct CommandHelper { impl CommandHelper { pub fn new( app: clap::Command, + cwd: PathBuf, string_args: Vec, global_args: GlobalArgs, store_factories: StoreFactories, ) -> Self { Self { app, + cwd, string_args, global_args, store_factories, @@ -284,6 +287,10 @@ impl CommandHelper { &self.app } + pub fn cwd(&self) -> &Path { + &self.cwd + } + pub fn string_args(&self) -> &Vec { &self.string_args } @@ -301,7 +308,7 @@ impl CommandHelper { pub fn load_workspace(&self, ui: &Ui) -> Result { let wc_path_str = self.global_args.repository.as_deref().unwrap_or("."); - let wc_path = ui.cwd().join(wc_path_str); + let wc_path = self.cwd.join(wc_path_str); Workspace::load(ui.settings(), &wc_path, &self.store_factories).map_err(|err| match err { WorkspaceLoadError::NoWorkspaceHere(wc_path) => { let message = format!("There is no jj repo in \"{wc_path_str}\""); @@ -383,6 +390,7 @@ jj init --git-repo=.", WorkspaceCommandHelper::new( ui, workspace, + self.cwd.clone(), self.string_args.clone(), &self.global_args, repo, @@ -408,6 +416,7 @@ impl WorkspaceCommandHelper { pub fn new( ui: &mut Ui, workspace: Workspace, + cwd: PathBuf, string_args: Vec, global_args: &GlobalArgs, repo: Arc, @@ -426,7 +435,7 @@ impl WorkspaceCommandHelper { working_copy_shared_with_git = git_workdir == workspace.workspace_root().as_path(); } Ok(Self { - cwd: ui.cwd().to_owned(), + cwd, string_args, global_args: global_args.clone(), settings, @@ -1764,11 +1773,13 @@ impl CliRunner { } pub fn run(self, ui: &mut Ui) -> Result<(), CommandError> { + let cwd = env::current_dir().unwrap(); // TODO: maybe map_err to CommandError? ui.reset(crate::config::read_config()?); let string_args = expand_args(ui, &self.app, std::env::args_os())?; let (matches, args) = parse_args(ui, &self.app, &self.tracing_subscription, &string_args)?; let command_helper = CommandHelper::new( self.app, + cwd, string_args, args.global_args, self.store_factories.unwrap_or_default(), diff --git a/src/commands.rs b/src/commands.rs index 59b616a0b..aa6e5a199 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1130,7 +1130,7 @@ fn cmd_init(ui: &mut Ui, command: &CommandHelper, args: &InitArgs) -> Result<(), if command.global_args().repository.is_some() { return Err(user_error("'--repository' cannot be used with 'init'")); } - let wc_path = ui.cwd().join(&args.destination); + let wc_path = command.cwd().join(&args.destination); match fs::create_dir(&wc_path) { Ok(()) => {} Err(_) if wc_path.is_dir() => {} @@ -1141,7 +1141,7 @@ fn cmd_init(ui: &mut Ui, command: &CommandHelper, args: &InitArgs) -> Result<(), .map_err(|e| user_error(format!("Failed to create workspace: {e}")))?; // raced? if let Some(git_store_str) = &args.git_repo { - let mut git_store_path = ui.cwd().join(git_store_str); + let mut git_store_path = command.cwd().join(git_store_str); git_store_path = git_store_path .canonicalize() .map_err(|_| user_error(format!("{} doesn't exist", git_store_path.display())))?; @@ -1190,7 +1190,7 @@ Set `ui.allow-init-native` to allow initializing a repo with the native backend. } Workspace::init_local(ui.settings(), &wc_path)?; }; - let cwd = ui.cwd().canonicalize().unwrap(); + let cwd = command.cwd().canonicalize().unwrap(); let relative_wc_path = file_util::relative_path(&cwd, &wc_path); writeln!(ui, "Initialized repo in \"{}\"", relative_wc_path.display())?; if args.git && wc_path.join(".git").exists() { @@ -3430,7 +3430,7 @@ fn cmd_workspace_add( args: &WorkspaceAddArgs, ) -> Result<(), CommandError> { let old_workspace_command = command.workspace_helper(ui)?; - let destination_path = ui.cwd().join(&args.destination); + let destination_path = command.cwd().join(&args.destination); if destination_path.exists() { return Err(user_error("Workspace already exists")); } else { @@ -3469,6 +3469,7 @@ fn cmd_workspace_add( let mut new_workspace_command = WorkspaceCommandHelper::new( ui, new_workspace, + command.cwd().to_owned(), command.string_args().clone(), command.global_args(), repo, @@ -3793,13 +3794,13 @@ fn cmd_git_clone( if command.global_args().repository.is_some() { return Err(user_error("'--repository' cannot be used with 'git clone'")); } - let source = absolute_git_source(ui.cwd(), &args.source); + let source = absolute_git_source(command.cwd(), &args.source); let wc_path_str = args .destination .as_deref() .or_else(|| clone_destination_for_source(&source)) .ok_or_else(|| user_error("No destination specified and wasn't able to guess it"))?; - let wc_path = ui.cwd().join(wc_path_str); + let wc_path = command.cwd().join(wc_path_str); let wc_path_existed = wc_path.exists(); if wc_path_existed { if !is_empty_dir(&wc_path) { diff --git a/src/ui.rs b/src/ui.rs index a5d43b9a6..f5c15c614 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -13,7 +13,6 @@ // limitations under the License. use std::io::{Stderr, Stdout, Write}; -use std::path::{Path, PathBuf}; use std::process::{Child, ChildStdin, Stdio}; use std::str::FromStr; use std::{fmt, io, mem}; @@ -28,7 +27,6 @@ pub struct Ui { color: bool, paginate: PaginationChoice, progress_indicator: bool, - cwd: PathBuf, formatter_factory: FormatterFactory, output: UiOutput, settings: UserSettings, @@ -123,13 +121,11 @@ impl Default for Ui { impl Ui { pub fn new() -> Ui { let settings = UserSettings::from_config(crate::config::default_config()); - let cwd = std::env::current_dir().unwrap(); let color = use_color(color_setting(&settings)); let progress_indicator = progress_indicator_setting(&settings); let formatter_factory = FormatterFactory::prepare(&settings, color); Ui { color, - cwd, formatter_factory, paginate: PaginationChoice::Auto, progress_indicator, @@ -177,10 +173,6 @@ impl Ui { self.color } - pub fn cwd(&self) -> &Path { - &self.cwd - } - pub fn settings(&self) -> &UserSettings { &self.settings }