diff --git a/cli/examples/custom-working-copy/main.rs b/cli/examples/custom-working-copy/main.rs index fb31f19fe..deae4544c 100644 --- a/cli/examples/custom-working-copy/main.rs +++ b/cli/examples/custom-working-copy/main.rs @@ -32,11 +32,9 @@ use jj_lib::signing::Signer; use jj_lib::store::Store; use jj_lib::working_copy::{ CheckoutError, CheckoutStats, LockedWorkingCopy, ResetError, SnapshotError, SnapshotOptions, - WorkingCopy, WorkingCopyStateError, -}; -use jj_lib::workspace::{ - default_working_copy_factories, WorkingCopyInitializer, Workspace, WorkspaceInitError, + WorkingCopy, WorkingCopyFactory, WorkingCopyStateError, }; +use jj_lib::workspace::{default_working_copy_factories, Workspace, WorkspaceInitError}; #[derive(clap::Parser, Clone, Debug)] enum CustomCommand { @@ -67,7 +65,7 @@ fn run_custom_command( &ReadonlyRepo::default_op_heads_store_initializer(), &ReadonlyRepo::default_index_store_initializer(), &ReadonlyRepo::default_submodule_store_initializer(), - &ConflictsWorkingCopy::initializer(), + &ConflictsWorkingCopyFactory {}, WorkspaceId::default(), )?; Ok(()) @@ -79,13 +77,7 @@ fn main() -> std::process::ExitCode { let mut working_copy_factories = default_working_copy_factories(); working_copy_factories.insert( ConflictsWorkingCopy::name().to_owned(), - Box::new(|store, working_copy_path, state_path| { - Box::new(ConflictsWorkingCopy::load( - store.clone(), - working_copy_path.to_owned(), - state_path.to_owned(), - )) - }), + Box::new(ConflictsWorkingCopyFactory {}), ); CliRunner::init() .set_working_copy_factories(working_copy_factories) @@ -113,8 +105,8 @@ impl ConflictsWorkingCopy { store: Arc, working_copy_path: PathBuf, state_path: PathBuf, - workspace_id: WorkspaceId, operation_id: OperationId, + workspace_id: WorkspaceId, ) -> Result { let inner = LocalWorkingCopy::init( store, @@ -128,21 +120,6 @@ impl ConflictsWorkingCopy { }) } - fn initializer() -> Box> { - Box::new( - |store, working_copy_path, state_path, workspace_id, operation_id| { - let wc = Self::init( - store, - working_copy_path, - state_path, - workspace_id, - operation_id, - )?; - Ok(Box::new(wc)) - }, - ) - } - fn load(store: Arc, working_copy_path: PathBuf, state_path: PathBuf) -> Self { let inner = LocalWorkingCopy::load(store, working_copy_path, state_path); ConflictsWorkingCopy { @@ -189,6 +166,40 @@ impl WorkingCopy for ConflictsWorkingCopy { } } +struct ConflictsWorkingCopyFactory {} + +impl WorkingCopyFactory for ConflictsWorkingCopyFactory { + fn init_working_copy( + &self, + store: Arc, + working_copy_path: PathBuf, + state_path: PathBuf, + operation_id: OperationId, + workspace_id: WorkspaceId, + ) -> Result, WorkingCopyStateError> { + Ok(Box::new(ConflictsWorkingCopy::init( + store, + working_copy_path, + state_path, + operation_id, + workspace_id, + )?)) + } + + fn load_working_copy( + &self, + store: Arc, + working_copy_path: PathBuf, + state_path: PathBuf, + ) -> Box { + Box::new(ConflictsWorkingCopy::load( + store, + working_copy_path, + state_path, + )) + } +} + struct LockedConflictsWorkingCopy { wc_path: PathBuf, inner: Box, diff --git a/cli/src/cli_util.rs b/cli/src/cli_util.rs index 078f69c62..37d1b8776 100644 --- a/cli/src/cli_util.rs +++ b/cli/src/cli_util.rs @@ -63,11 +63,11 @@ use jj_lib::transaction::Transaction; use jj_lib::tree::TreeMergeError; use jj_lib::working_copy::{ CheckoutStats, LockedWorkingCopy, ResetError, SnapshotError, SnapshotOptions, WorkingCopy, - WorkingCopyStateError, + WorkingCopyFactory, WorkingCopyStateError, }; use jj_lib::workspace::{ - default_working_copy_factories, LockedWorkspace, WorkingCopyFactory, Workspace, - WorkspaceInitError, WorkspaceLoadError, WorkspaceLoader, + default_working_copy_factories, LockedWorkspace, Workspace, WorkspaceInitError, + WorkspaceLoadError, WorkspaceLoader, }; use jj_lib::{dag_walk, file_util, git, op_walk, revset}; use once_cell::unsync::OnceCell; @@ -515,7 +515,7 @@ pub struct CommandHelper { layered_configs: LayeredConfigs, maybe_workspace_loader: Result, store_factories: StoreFactories, - working_copy_factories: HashMap, + working_copy_factories: HashMap>, } impl CommandHelper { @@ -530,7 +530,7 @@ impl CommandHelper { layered_configs: LayeredConfigs, maybe_workspace_loader: Result, store_factories: StoreFactories, - working_copy_factories: HashMap, + working_copy_factories: HashMap>, ) -> Self { // `cwd` is canonicalized for consistency with `Workspace::workspace_root()` and // to easily compute relative paths between them. @@ -2775,7 +2775,7 @@ pub struct CliRunner { app: Command, extra_configs: Option, store_factories: Option, - working_copy_factories: Option>, + working_copy_factories: Option>>, dispatch_fn: CliDispatchFn, process_global_args_fns: Vec, } @@ -2822,7 +2822,7 @@ impl CliRunner { /// Replaces working copy factories to be used. pub fn set_working_copy_factories( mut self, - working_copy_factories: HashMap, + working_copy_factories: HashMap>, ) -> Self { self.working_copy_factories = Some(working_copy_factories); self @@ -2928,7 +2928,7 @@ impl CliRunner { let settings = UserSettings::from_config(config); let working_copy_factories = self .working_copy_factories - .unwrap_or_else(|| default_working_copy_factories()); + .unwrap_or_else(default_working_copy_factories); let command_helper = CommandHelper::new( self.app, cwd, diff --git a/cli/src/commands/workspace.rs b/cli/src/commands/workspace.rs index c15f5614f..585b8519e 100644 --- a/cli/src/commands/workspace.rs +++ b/cli/src/commands/workspace.rs @@ -23,7 +23,7 @@ use jj_lib::object_id::ObjectId; use jj_lib::op_store::WorkspaceId; use jj_lib::repo::Repo; use jj_lib::rewrite::merge_commit_trees; -use jj_lib::workspace::{default_working_copy_initializer, Workspace}; +use jj_lib::workspace::{default_working_copy_factory, Workspace}; use tracing::instrument; use crate::cli_util::{ @@ -153,7 +153,7 @@ fn cmd_workspace_add( command.settings(), &destination_path, repo, - default_working_copy_initializer(), + &*default_working_copy_factory(), workspace_id, )?; writeln!( diff --git a/lib/src/local_working_copy.rs b/lib/src/local_working_copy.rs index 3e351f4cf..70d286d14 100644 --- a/lib/src/local_working_copy.rs +++ b/lib/src/local_working_copy.rs @@ -64,7 +64,7 @@ use crate::store::Store; use crate::tree::Tree; use crate::working_copy::{ CheckoutError, CheckoutStats, LockedWorkingCopy, ResetError, SnapshotError, SnapshotOptions, - SnapshotProgress, WorkingCopy, WorkingCopyStateError, + SnapshotProgress, WorkingCopy, WorkingCopyFactory, WorkingCopyStateError, }; #[cfg(unix)] @@ -1653,6 +1653,36 @@ impl LocalWorkingCopy { } } +pub struct LocalWorkingCopyFactory {} + +impl WorkingCopyFactory for LocalWorkingCopyFactory { + fn init_working_copy( + &self, + store: Arc, + working_copy_path: PathBuf, + state_path: PathBuf, + operation_id: OperationId, + workspace_id: WorkspaceId, + ) -> Result, WorkingCopyStateError> { + Ok(Box::new(LocalWorkingCopy::init( + store, + working_copy_path, + state_path, + operation_id, + workspace_id, + )?)) + } + + fn load_working_copy( + &self, + store: Arc, + working_copy_path: PathBuf, + state_path: PathBuf, + ) -> Box { + Box::new(LocalWorkingCopy::load(store, working_copy_path, state_path)) + } +} + /// A working copy that's locked on disk. The lock is held until you call /// `finish()` or `discard()`. pub struct LockedLocalWorkingCopy { diff --git a/lib/src/working_copy.rs b/lib/src/working_copy.rs index 7222afc51..db8870ad7 100644 --- a/lib/src/working_copy.rs +++ b/lib/src/working_copy.rs @@ -30,6 +30,7 @@ use crate::merged_tree::MergedTree; use crate::op_store::{OperationId, WorkspaceId}; use crate::repo_path::{RepoPath, RepoPathBuf}; use crate::settings::HumanByteSize; +use crate::store::Store; /// The trait all working-copy implementations must implement. pub trait WorkingCopy { @@ -63,6 +64,27 @@ pub trait WorkingCopy { fn start_mutation(&self) -> Result, WorkingCopyStateError>; } +/// The factory which creates and loads a specific type of working copy. +pub trait WorkingCopyFactory { + /// Create a new working copy from scratch. + fn init_working_copy( + &self, + store: Arc, + working_copy_path: PathBuf, + state_path: PathBuf, + operation_id: OperationId, + workspace_id: WorkspaceId, + ) -> Result, WorkingCopyStateError>; + + /// Load an existing working copy. + fn load_working_copy( + &self, + store: Arc, + working_copy_path: PathBuf, + state_path: PathBuf, + ) -> Box; +} + /// A working copy that's being modified. pub trait LockedWorkingCopy { /// Should return `self`. For down-casting purposes. diff --git a/lib/src/workspace.rs b/lib/src/workspace.rs index a39fdc9e1..752d2a542 100644 --- a/lib/src/workspace.rs +++ b/lib/src/workspace.rs @@ -28,7 +28,7 @@ use crate::commit::Commit; use crate::file_util::{self, IoResultExt as _, PathError}; use crate::git_backend::{canonicalize_git_repo_path, GitBackend}; use crate::local_backend::LocalBackend; -use crate::local_working_copy::LocalWorkingCopy; +use crate::local_working_copy::{LocalWorkingCopy, LocalWorkingCopyFactory}; use crate::op_store::{OperationId, WorkspaceId}; use crate::repo::{ read_store_type_compat, BackendInitializer, CheckOutCommitError, IndexStoreInitializer, @@ -39,7 +39,8 @@ use crate::settings::UserSettings; use crate::signing::{SignInitError, Signer}; use crate::store::Store; use crate::working_copy::{ - CheckoutError, CheckoutStats, LockedWorkingCopy, WorkingCopy, WorkingCopyStateError, + CheckoutError, CheckoutStats, LockedWorkingCopy, WorkingCopy, WorkingCopyFactory, + WorkingCopyStateError, }; #[derive(Error, Debug)] @@ -102,7 +103,7 @@ fn init_working_copy( repo: &Arc, workspace_root: &Path, jj_dir: &Path, - working_copy_initializer: &WorkingCopyInitializer, + working_copy_factory: &dyn WorkingCopyFactory, workspace_id: WorkspaceId, ) -> Result<(Box, Arc), WorkspaceInitError> { let working_copy_state_path = jj_dir.join("working_copy"); @@ -116,12 +117,12 @@ fn init_working_copy( )?; let repo = tx.commit(format!("add workspace '{}'", workspace_id.as_str())); - let working_copy = working_copy_initializer( + let working_copy = working_copy_factory.init_working_copy( repo.store().clone(), workspace_root.to_path_buf(), working_copy_state_path.clone(), - workspace_id, repo.op_id().clone(), + workspace_id, )?; let working_copy_type_path = working_copy_state_path.join("type"); fs::write(&working_copy_type_path, working_copy.name()).context(&working_copy_type_path)?; @@ -243,7 +244,7 @@ impl Workspace { op_heads_store_initializer: &OpHeadsStoreInitializer, index_store_initializer: &IndexStoreInitializer, submodule_store_initializer: &SubmoduleStoreInitializer, - working_copy_initializer: &WorkingCopyInitializer, + working_copy_factory: &dyn WorkingCopyFactory, workspace_id: WorkspaceId, ) -> Result<(Self, Arc), WorkspaceInitError> { let jj_dir = create_jj_dir(workspace_root)?; @@ -269,7 +270,7 @@ impl Workspace { &repo, workspace_root, &jj_dir, - working_copy_initializer, + working_copy_factory, workspace_id, )?; let repo_loader = repo.loader(); @@ -297,7 +298,7 @@ impl Workspace { ReadonlyRepo::default_op_heads_store_initializer(), ReadonlyRepo::default_index_store_initializer(), ReadonlyRepo::default_submodule_store_initializer(), - default_working_copy_initializer(), + &*default_working_copy_factory(), WorkspaceId::default(), ) } @@ -306,7 +307,7 @@ impl Workspace { user_settings: &UserSettings, workspace_root: &Path, repo: &Arc, - working_copy_initializer: &WorkingCopyInitializer, + working_copy_factory: &dyn WorkingCopyFactory, workspace_id: WorkspaceId, ) -> Result<(Self, Arc), WorkspaceInitError> { let jj_dir = create_jj_dir(workspace_root)?; @@ -328,7 +329,7 @@ impl Workspace { repo, workspace_root, &jj_dir, - working_copy_initializer, + working_copy_factory, workspace_id, )?; let workspace = Workspace::new(workspace_root, working_copy, repo.loader())?; @@ -339,7 +340,7 @@ impl Workspace { user_settings: &UserSettings, workspace_path: &Path, store_factories: &StoreFactories, - working_copy_factories: &HashMap, + working_copy_factories: &HashMap>, ) -> Result { let loader = WorkspaceLoader::init(workspace_path)?; let workspace = loader.load(user_settings, store_factories, working_copy_factories)?; @@ -475,7 +476,7 @@ impl WorkspaceLoader { &self, user_settings: &UserSettings, store_factories: &StoreFactories, - working_copy_factories: &HashMap, + working_copy_factories: &HashMap>, ) -> Result { let repo_loader = RepoLoader::init(user_settings, &self.repo_dir, store_factories)?; let working_copy = self.load_working_copy(repo_loader.store(), working_copy_factories)?; @@ -486,7 +487,7 @@ impl WorkspaceLoader { fn load_working_copy( &self, store: &Arc, - working_copy_factories: &HashMap, + working_copy_factories: &HashMap>, ) -> Result, StoreLoadError> { // For compatibility with existing repos. TODO: Delete default in 0.17+ let working_copy_type = read_store_type_compat( @@ -501,46 +502,24 @@ impl WorkspaceLoader { store: "working copy", store_type: working_copy_type.to_string(), })?; - let working_copy = - working_copy_factory(store, &self.workspace_root, &self.working_copy_state_path); - Ok(working_copy) + + Ok(working_copy_factory.load_working_copy( + store.clone(), + self.workspace_root.to_owned(), + self.working_copy_state_path.to_owned(), + )) } } -pub fn default_working_copy_initializer() -> &'static WorkingCopyInitializer<'static> { - &|store: Arc, working_copy_path, state_path, workspace_id, operation_id| { - let wc = LocalWorkingCopy::init( - store, - working_copy_path, - state_path, - operation_id, - workspace_id, - )?; - Ok(Box::new(wc)) - } -} - -pub fn default_working_copy_factories() -> HashMap { - let mut factories: HashMap = HashMap::new(); +pub fn default_working_copy_factories() -> HashMap> { + let mut factories: HashMap> = HashMap::new(); factories.insert( LocalWorkingCopy::name().to_owned(), - Box::new(|store, working_copy_path, store_path| { - Box::new(LocalWorkingCopy::load( - store.clone(), - working_copy_path.to_owned(), - store_path.to_owned(), - )) - }), + Box::new(LocalWorkingCopyFactory {}), ); factories } -pub type WorkingCopyInitializer<'a> = dyn Fn( - Arc, - PathBuf, - PathBuf, - WorkspaceId, - OperationId, - ) -> Result, WorkingCopyStateError> - + 'a; -pub type WorkingCopyFactory = Box, &Path, &Path) -> Box>; +pub fn default_working_copy_factory() -> Box { + Box::new(LocalWorkingCopyFactory {}) +} diff --git a/lib/tests/test_workspace.rs b/lib/tests/test_workspace.rs index cb5d8767f..7f97e3654 100644 --- a/lib/tests/test_workspace.rs +++ b/lib/tests/test_workspace.rs @@ -16,7 +16,7 @@ use assert_matches::assert_matches; use jj_lib::op_store::WorkspaceId; use jj_lib::repo::Repo; use jj_lib::workspace::{ - default_working_copy_factories, default_working_copy_initializer, Workspace, WorkspaceLoadError, + default_working_copy_factories, default_working_copy_factory, Workspace, WorkspaceLoadError, }; use testutils::{TestRepo, TestWorkspace}; @@ -51,7 +51,7 @@ fn test_init_additional_workspace() { &settings, &ws2_root, &test_workspace.repo, - default_working_copy_initializer(), + &*default_working_copy_factory(), ws2_id.clone(), ) .unwrap();