forked from mirrors/jj
working copy: return Box<dyn WorkingCopy>
from finish()
This commit is contained in:
parent
6a13fa8264
commit
580586d008
9 changed files with 61 additions and 37 deletions
|
@ -41,7 +41,7 @@ use jj_lib::git_backend::GitBackend;
|
|||
use jj_lib::gitignore::GitIgnoreFile;
|
||||
use jj_lib::hex_util::to_reverse_hex;
|
||||
use jj_lib::id_prefix::IdPrefixContext;
|
||||
use jj_lib::local_working_copy::{LocalWorkingCopy, LockedLocalWorkingCopy};
|
||||
use jj_lib::local_working_copy::LockedLocalWorkingCopy;
|
||||
use jj_lib::matchers::{EverythingMatcher, Matcher, PrefixMatcher, Visit};
|
||||
use jj_lib::merged_tree::{MergedTree, MergedTreeBuilder};
|
||||
use jj_lib::op_heads_store::{self, OpHeadResolutionError, OpHeadsStore};
|
||||
|
@ -853,7 +853,7 @@ impl WorkspaceCommandHelper {
|
|||
&self.user_repo.repo
|
||||
}
|
||||
|
||||
pub fn working_copy(&self) -> &LocalWorkingCopy {
|
||||
pub fn working_copy(&self) -> &dyn WorkingCopy {
|
||||
self.workspace.working_copy()
|
||||
}
|
||||
|
||||
|
|
|
@ -12,14 +12,16 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::any::Any;
|
||||
use std::fmt::Debug;
|
||||
use std::io::Write as _;
|
||||
|
||||
use clap::Subcommand;
|
||||
use jj_lib::backend::ObjectId;
|
||||
use jj_lib::default_index_store::{DefaultIndexStore, ReadonlyIndexWrapper};
|
||||
use jj_lib::local_working_copy::{LocalWorkingCopy, LockedLocalWorkingCopy};
|
||||
use jj_lib::revset;
|
||||
use jj_lib::working_copy::WorkingCopy;
|
||||
use jj_lib::working_copy::{LockedWorkingCopy, WorkingCopy};
|
||||
|
||||
use crate::cli_util::{resolve_op_for_load, user_error, CommandError, CommandHelper};
|
||||
use crate::template_parser;
|
||||
|
@ -103,7 +105,7 @@ pub fn cmd_debug(
|
|||
DebugCommands::Revset(args) => cmd_debug_revset(ui, command, args)?,
|
||||
DebugCommands::WorkingCopy(_wc_matches) => {
|
||||
let workspace_command = command.workspace_helper(ui)?;
|
||||
let wc = workspace_command.working_copy();
|
||||
let wc = check_local_disk_wc(workspace_command.working_copy().as_any())?;
|
||||
writeln!(ui.stdout(), "Current operation: {:?}", wc.operation_id())?;
|
||||
writeln!(ui.stdout(), "Current tree: {:?}", wc.tree_id()?)?;
|
||||
for (file, state) in wc.file_states()? {
|
||||
|
@ -250,16 +252,25 @@ fn cmd_debug_watchman(
|
|||
let repo = workspace_command.repo().clone();
|
||||
match subcommand {
|
||||
DebugWatchmanSubcommand::QueryClock => {
|
||||
let (clock, _changed_files) = workspace_command.working_copy().query_watchman()?;
|
||||
let wc = check_local_disk_wc(workspace_command.working_copy().as_any())?;
|
||||
let (clock, _changed_files) = wc.query_watchman()?;
|
||||
writeln!(ui.stdout(), "Clock: {clock:?}")?;
|
||||
}
|
||||
DebugWatchmanSubcommand::QueryChangedFiles => {
|
||||
let (_clock, changed_files) = workspace_command.working_copy().query_watchman()?;
|
||||
let wc = check_local_disk_wc(workspace_command.working_copy().as_any())?;
|
||||
let (_clock, changed_files) = wc.query_watchman()?;
|
||||
writeln!(ui.stdout(), "Changed files: {changed_files:?}")?;
|
||||
}
|
||||
DebugWatchmanSubcommand::ResetClock => {
|
||||
let (mut locked_ws, _commit) = workspace_command.start_working_copy_mutation()?;
|
||||
locked_ws.locked_wc().reset_watchman()?;
|
||||
let Some(locked_local_wc): Option<&mut LockedLocalWorkingCopy> =
|
||||
locked_ws.locked_wc().as_any_mut().downcast_mut()
|
||||
else {
|
||||
return Err(user_error(
|
||||
"This command requires a standard local-disk working copy",
|
||||
));
|
||||
};
|
||||
locked_local_wc.reset_watchman()?;
|
||||
locked_ws.finish(repo.op_id().clone())?;
|
||||
writeln!(ui.stderr(), "Reset Watchman clock")?;
|
||||
}
|
||||
|
@ -277,3 +288,8 @@ fn cmd_debug_watchman(
|
|||
"Cannot query Watchman because jj was not compiled with the `watchman` feature",
|
||||
))
|
||||
}
|
||||
|
||||
fn check_local_disk_wc(x: &dyn Any) -> Result<&LocalWorkingCopy, CommandError> {
|
||||
x.downcast_ref()
|
||||
.ok_or_else(|| user_error("This command requires a standard local-disk working copy"))
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ use jj_lib::revset_graph::{
|
|||
};
|
||||
use jj_lib::rewrite::{back_out_commit, merge_commit_trees, rebase_commit, DescendantRebaser};
|
||||
use jj_lib::settings::UserSettings;
|
||||
use jj_lib::working_copy::{LockedWorkingCopy, SnapshotOptions, WorkingCopy};
|
||||
use jj_lib::working_copy::{LockedWorkingCopy, SnapshotOptions};
|
||||
use jj_lib::workspace::Workspace;
|
||||
use jj_lib::{conflicts, file_util, revset};
|
||||
use maplit::{hashmap, hashset};
|
||||
|
|
|
@ -1490,6 +1490,10 @@ impl LockedWorkingCopy for LockedLocalWorkingCopy {
|
|||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn old_operation_id(&self) -> &OperationId {
|
||||
&self.old_operation_id
|
||||
}
|
||||
|
@ -1563,7 +1567,7 @@ impl LockedWorkingCopy for LockedLocalWorkingCopy {
|
|||
fn finish(
|
||||
mut self,
|
||||
operation_id: OperationId,
|
||||
) -> Result<LocalWorkingCopy, WorkingCopyStateError> {
|
||||
) -> Result<Box<dyn WorkingCopy>, WorkingCopyStateError> {
|
||||
assert!(self.tree_state_dirty || &self.old_tree_id == self.wc.tree_id()?);
|
||||
if self.tree_state_dirty {
|
||||
self.wc
|
||||
|
@ -1579,7 +1583,7 @@ impl LockedWorkingCopy for LockedLocalWorkingCopy {
|
|||
self.wc.save();
|
||||
}
|
||||
// TODO: Clear the "pending_checkout" file here.
|
||||
Ok(self.wc)
|
||||
Ok(Box::new(self.wc))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ use thiserror::Error;
|
|||
use crate::backend::{BackendError, MergedTreeId};
|
||||
use crate::fsmonitor::FsmonitorKind;
|
||||
use crate::gitignore::GitIgnoreFile;
|
||||
use crate::local_working_copy::{LocalWorkingCopy, LockedLocalWorkingCopy};
|
||||
use crate::local_working_copy::LockedLocalWorkingCopy;
|
||||
use crate::merged_tree::MergedTree;
|
||||
use crate::op_store::{OperationId, WorkspaceId};
|
||||
use crate::repo_path::RepoPath;
|
||||
|
@ -69,6 +69,9 @@ pub trait LockedWorkingCopy {
|
|||
/// Should return `self`. For down-casting purposes.
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
||||
/// Should return `self`. For down-casting purposes.
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
||||
/// The operation at the time the lock was taken
|
||||
fn old_operation_id(&self) -> &OperationId;
|
||||
|
||||
|
@ -101,8 +104,10 @@ pub trait LockedWorkingCopy {
|
|||
|
||||
/// Finish the modifications to the working copy by writing the updated
|
||||
/// states to disk. Returns the new (unlocked) working copy.
|
||||
// TODO: return a `Box<dyn WorkingCopy>` instead
|
||||
fn finish(self, operation_id: OperationId) -> Result<LocalWorkingCopy, WorkingCopyStateError>;
|
||||
fn finish(
|
||||
self,
|
||||
operation_id: OperationId,
|
||||
) -> Result<Box<dyn WorkingCopy>, WorkingCopyStateError>;
|
||||
}
|
||||
|
||||
/// An error while snapshotting the working copy.
|
||||
|
|
|
@ -78,7 +78,7 @@ pub struct Workspace {
|
|||
// working copy files live.
|
||||
workspace_root: PathBuf,
|
||||
repo_loader: RepoLoader,
|
||||
working_copy: LocalWorkingCopy,
|
||||
working_copy: Box<dyn WorkingCopy>,
|
||||
}
|
||||
|
||||
fn create_jj_dir(workspace_root: &Path) -> Result<PathBuf, WorkspaceInitError> {
|
||||
|
@ -98,7 +98,7 @@ fn init_working_copy(
|
|||
workspace_root: &Path,
|
||||
jj_dir: &Path,
|
||||
workspace_id: WorkspaceId,
|
||||
) -> Result<(LocalWorkingCopy, Arc<ReadonlyRepo>), WorkspaceInitError> {
|
||||
) -> Result<(Box<dyn WorkingCopy>, Arc<ReadonlyRepo>), WorkspaceInitError> {
|
||||
let working_copy_state_path = jj_dir.join("working_copy");
|
||||
std::fs::create_dir(&working_copy_state_path).context(&working_copy_state_path)?;
|
||||
|
||||
|
@ -120,13 +120,13 @@ fn init_working_copy(
|
|||
repo.op_id().clone(),
|
||||
workspace_id,
|
||||
)?;
|
||||
Ok((working_copy, repo))
|
||||
Ok((Box::new(working_copy), repo))
|
||||
}
|
||||
|
||||
impl Workspace {
|
||||
fn new(
|
||||
workspace_root: &Path,
|
||||
working_copy: LocalWorkingCopy,
|
||||
working_copy: Box<dyn WorkingCopy>,
|
||||
repo_loader: RepoLoader,
|
||||
) -> Result<Workspace, PathError> {
|
||||
let workspace_root = workspace_root.canonicalize().context(workspace_root)?;
|
||||
|
@ -295,8 +295,8 @@ impl Workspace {
|
|||
&self.repo_loader
|
||||
}
|
||||
|
||||
pub fn working_copy(&self) -> &LocalWorkingCopy {
|
||||
&self.working_copy
|
||||
pub fn working_copy(&self) -> &dyn WorkingCopy {
|
||||
self.working_copy.as_ref()
|
||||
}
|
||||
|
||||
pub fn start_working_copy_mutation(
|
||||
|
@ -415,7 +415,7 @@ impl WorkspaceLoader {
|
|||
self.workspace_root.clone(),
|
||||
self.working_copy_state_path.clone(),
|
||||
);
|
||||
let workspace = Workspace::new(&self.workspace_root, working_copy, repo_loader)?;
|
||||
let workspace = Workspace::new(&self.workspace_root, Box::new(working_copy), repo_loader)?;
|
||||
Ok(workspace)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,9 +34,7 @@ use jj_lib::op_store::{OperationId, WorkspaceId};
|
|||
use jj_lib::repo::{ReadonlyRepo, Repo};
|
||||
use jj_lib::repo_path::{RepoPath, RepoPathComponent, RepoPathJoin};
|
||||
use jj_lib::settings::UserSettings;
|
||||
use jj_lib::working_copy::{
|
||||
CheckoutStats, LockedWorkingCopy, SnapshotError, SnapshotOptions, WorkingCopy,
|
||||
};
|
||||
use jj_lib::working_copy::{CheckoutStats, LockedWorkingCopy, SnapshotError, SnapshotOptions};
|
||||
use jj_lib::workspace::LockedWorkspace;
|
||||
use test_case::test_case;
|
||||
use testutils::{create_tree, write_random_commit, TestRepoBackend, TestWorkspace};
|
||||
|
@ -417,7 +415,7 @@ fn test_reset() {
|
|||
|
||||
// Test the setup: the file should exist on disk and in the tree state.
|
||||
assert!(ignored_path.to_fs_path(&workspace_root).is_file());
|
||||
let wc = ws.working_copy();
|
||||
let wc: &LocalWorkingCopy = ws.working_copy().as_any().downcast_ref().unwrap();
|
||||
assert!(wc.file_states().unwrap().contains_key(&ignored_path));
|
||||
|
||||
// After we reset to the commit without the file, it should still exist on disk,
|
||||
|
@ -427,7 +425,7 @@ fn test_reset() {
|
|||
locked_ws.locked_wc().reset(&tree_without_file).unwrap();
|
||||
locked_ws.finish(op_id.clone()).unwrap();
|
||||
assert!(ignored_path.to_fs_path(&workspace_root).is_file());
|
||||
let wc = ws.working_copy();
|
||||
let wc: &LocalWorkingCopy = ws.working_copy().as_any().downcast_ref().unwrap();
|
||||
assert!(!wc.file_states().unwrap().contains_key(&ignored_path));
|
||||
let new_tree = test_workspace.snapshot().unwrap();
|
||||
assert_eq!(new_tree.id(), tree_without_file.id());
|
||||
|
@ -439,7 +437,7 @@ fn test_reset() {
|
|||
locked_ws.locked_wc().reset(&tree_with_file).unwrap();
|
||||
locked_ws.finish(op_id.clone()).unwrap();
|
||||
assert!(ignored_path.to_fs_path(&workspace_root).is_file());
|
||||
let wc = ws.working_copy();
|
||||
let wc: &LocalWorkingCopy = ws.working_copy().as_any().downcast_ref().unwrap();
|
||||
assert!(wc.file_states().unwrap().contains_key(&ignored_path));
|
||||
let new_tree = test_workspace.snapshot().unwrap();
|
||||
assert_eq!(new_tree.id(), tree_with_file.id());
|
||||
|
@ -464,11 +462,12 @@ fn test_checkout_discard() {
|
|||
|
||||
let ws = &mut test_workspace.workspace;
|
||||
ws.check_out(repo.op_id().clone(), None, &tree1).unwrap();
|
||||
let state_path = ws.working_copy().state_path().to_path_buf();
|
||||
let wc: &LocalWorkingCopy = ws.working_copy().as_any().downcast_ref().unwrap();
|
||||
let state_path = wc.state_path().to_path_buf();
|
||||
|
||||
// Test the setup: the file should exist on disk and in the tree state.
|
||||
assert!(file1_path.to_fs_path(&workspace_root).is_file());
|
||||
let wc = ws.working_copy();
|
||||
let wc: &LocalWorkingCopy = ws.working_copy().as_any().downcast_ref().unwrap();
|
||||
assert!(wc.file_states().unwrap().contains_key(&file1_path));
|
||||
|
||||
// Start a checkout
|
||||
|
@ -484,7 +483,7 @@ fn test_checkout_discard() {
|
|||
drop(locked_ws);
|
||||
|
||||
// The change should remain in the working copy, but not in memory and not saved
|
||||
let wc = ws.working_copy();
|
||||
let wc: &LocalWorkingCopy = ws.working_copy().as_any().downcast_ref().unwrap();
|
||||
assert!(wc.file_states().unwrap().contains_key(&file1_path));
|
||||
assert!(!wc.file_states().unwrap().contains_key(&file2_path));
|
||||
assert!(!file1_path.to_fs_path(&workspace_root).is_file());
|
||||
|
@ -538,6 +537,7 @@ fn test_snapshot_special_file() {
|
|||
let mut test_workspace = TestWorkspace::init(&settings);
|
||||
let workspace_root = test_workspace.workspace.workspace_root().clone();
|
||||
let store = test_workspace.repo.store();
|
||||
let ws = &mut test_workspace.workspace;
|
||||
|
||||
let file1_path = RepoPath::from_internal_string("file1");
|
||||
let file1_disk_path = file1_path.to_fs_path(&workspace_root);
|
||||
|
@ -552,10 +552,7 @@ fn test_snapshot_special_file() {
|
|||
assert!(!socket_disk_path.is_file());
|
||||
|
||||
// Snapshot the working copy with the socket file
|
||||
let mut locked_ws = test_workspace
|
||||
.workspace
|
||||
.start_working_copy_mutation()
|
||||
.unwrap();
|
||||
let mut locked_ws = ws.start_working_copy_mutation().unwrap();
|
||||
let tree_id = locked_ws
|
||||
.locked_wc()
|
||||
.snapshot(SnapshotOptions::empty_for_test())
|
||||
|
@ -567,7 +564,7 @@ fn test_snapshot_special_file() {
|
|||
tree.entries().map(|(path, _value)| path).collect_vec(),
|
||||
vec![file1_path.clone(), file2_path.clone()]
|
||||
);
|
||||
let wc = test_workspace.workspace.working_copy();
|
||||
let wc: &LocalWorkingCopy = ws.working_copy().as_any().downcast_ref().unwrap();
|
||||
assert_eq!(
|
||||
wc.file_states().unwrap().keys().cloned().collect_vec(),
|
||||
vec![file1_path, file2_path.clone()]
|
||||
|
@ -582,7 +579,8 @@ fn test_snapshot_special_file() {
|
|||
tree.entries().map(|(path, _value)| path).collect_vec(),
|
||||
vec![file2_path.clone()]
|
||||
);
|
||||
let wc = test_workspace.workspace.working_copy();
|
||||
let ws = &mut test_workspace.workspace;
|
||||
let wc: &LocalWorkingCopy = ws.working_copy().as_any().downcast_ref().unwrap();
|
||||
assert_eq!(
|
||||
wc.file_states().unwrap().keys().cloned().collect_vec(),
|
||||
vec![file2_path]
|
||||
|
|
|
@ -18,7 +18,7 @@ use std::thread;
|
|||
use assert_matches::assert_matches;
|
||||
use jj_lib::repo::Repo;
|
||||
use jj_lib::repo_path::RepoPath;
|
||||
use jj_lib::working_copy::{CheckoutError, LockedWorkingCopy, SnapshotOptions, WorkingCopy};
|
||||
use jj_lib::working_copy::{CheckoutError, LockedWorkingCopy, SnapshotOptions};
|
||||
use jj_lib::workspace::Workspace;
|
||||
use testutils::{create_tree, write_working_copy_file, TestRepo, TestWorkspace};
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ fn test_sparse_checkout() {
|
|||
|
||||
// Write the new state to disk
|
||||
locked_ws.finish(repo.op_id().clone()).unwrap();
|
||||
let wc = ws.working_copy();
|
||||
let wc: &LocalWorkingCopy = ws.working_copy().as_any().downcast_ref().unwrap();
|
||||
assert_eq!(
|
||||
wc.file_states().unwrap().keys().collect_vec(),
|
||||
vec![&dir1_file1_path, &dir1_file2_path, &dir1_subdir1_file1_path]
|
||||
|
@ -130,6 +130,7 @@ fn test_sparse_checkout() {
|
|||
.exists());
|
||||
assert!(dir2_file1_path.to_fs_path(&working_copy_path).exists());
|
||||
let wc = locked_wc.finish(repo.op_id().clone()).unwrap();
|
||||
let wc: &LocalWorkingCopy = wc.as_any().downcast_ref().unwrap();
|
||||
assert_eq!(
|
||||
wc.file_states().unwrap().keys().collect_vec(),
|
||||
vec![&dir1_subdir1_file1_path, &dir2_file1_path, &root_file1_path]
|
||||
|
|
Loading…
Reference in a new issue