From ceb6c152a12864f3a9d637ed0823aafaa354153d Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2022 14:44:30 -0800 Subject: [PATCH] working_copy: record sparse patterns in the tree state (#52) This patch makes room for sparse patterns in the `TreeState` proto message. We also start setting that value to a list of just the pattern `.` when we create new working copies. Old working copies without the sparse patterns are also interpreted as having that single pattern. Note that this absence of sparse patterns is different from a present list of no patterns. The latter is a valid state and means that no paths are included in the sparse checkout. --- lib/protos/working_copy.proto | 5 ++++ lib/src/working_copy.rs | 53 ++++++++++++++++++++++++++++++++++ lib/tests/test_working_copy.rs | 1 + 3 files changed, 59 insertions(+) diff --git a/lib/protos/working_copy.proto b/lib/protos/working_copy.proto index 7104208c5..ab4cc8df3 100644 --- a/lib/protos/working_copy.proto +++ b/lib/protos/working_copy.proto @@ -29,9 +29,14 @@ message FileState { bytes conflict_id = 4; } +message SparsePatterns { + repeated string prefixes = 1; +} + message TreeState { bytes tree_id = 1; map file_states = 2; + SparsePatterns sparse_patterns = 3; } message Checkout { diff --git a/lib/src/working_copy.rs b/lib/src/working_copy.rs index 79b476823..1c49453b7 100644 --- a/lib/src/working_copy.rs +++ b/lib/src/working_copy.rs @@ -84,6 +84,8 @@ pub struct TreeState { state_path: PathBuf, tree_id: TreeId, file_states: BTreeMap, + // Currently only path prefixes + sparse_patterns: Vec, own_mtime: MillisSinceEpoch, } @@ -132,6 +134,20 @@ fn file_states_from_proto( file_states } +fn sparse_patterns_from_proto(proto: &crate::protos::working_copy::TreeState) -> Vec { + let mut sparse_patterns = vec![]; + if proto.has_sparse_patterns() { + for prefix in &proto.get_sparse_patterns().prefixes { + sparse_patterns.push(RepoPath::from_internal_string(prefix.as_str())); + } + } else { + // For compatibility with old working copies. + // TODO: Delete this is late 2022 or so. + sparse_patterns.push(RepoPath::root()); + } + sparse_patterns +} + fn create_parent_dirs(disk_path: &Path) { fs::create_dir_all(disk_path.parent().unwrap()) .unwrap_or_else(|_| panic!("failed to create parent directories for {:?}", &disk_path)); @@ -206,6 +222,10 @@ impl TreeState { &self.file_states } + pub fn sparse_patterns(&self) -> &Vec { + &self.sparse_patterns + } + pub fn init(store: Arc, working_copy_path: PathBuf, state_path: PathBuf) -> TreeState { let mut wc = TreeState::empty(store, working_copy_path, state_path); wc.save(); @@ -222,6 +242,7 @@ impl TreeState { state_path, tree_id, file_states: BTreeMap::new(), + sparse_patterns: vec![RepoPath::root()], own_mtime: MillisSinceEpoch(0), } } @@ -256,6 +277,7 @@ impl TreeState { Message::parse_from_reader(&mut file).unwrap(); self.tree_id = TreeId::new(proto.tree_id.clone()); self.file_states = file_states_from_proto(&proto); + self.sparse_patterns = sparse_patterns_from_proto(&proto); } fn save(&mut self) { @@ -267,6 +289,13 @@ impl TreeState { file_state_to_proto(file_state), ); } + let mut sparse_patterns = crate::protos::working_copy::SparsePatterns::new(); + for path in &self.sparse_patterns { + sparse_patterns + .prefixes + .push(path.to_internal_file_string()); + } + proto.set_sparse_patterns(sparse_patterns); let mut temp_file = NamedTempFile::new_in(&self.state_path).unwrap(); proto.write_to_writer(temp_file.as_file_mut()).unwrap(); @@ -555,6 +584,10 @@ impl TreeState { Ok(stats) } + pub fn set_sparse_patterns(&mut self, sparse_patterns: Vec) { + self.sparse_patterns = sparse_patterns; + } + fn update( &mut self, old_tree: &Tree, @@ -800,6 +833,14 @@ impl WorkingCopy { self.tree_state().as_ref().unwrap().file_states().clone() } + pub fn sparse_patterns(&self) -> Vec { + self.tree_state() + .as_ref() + .unwrap() + .sparse_patterns() + .clone() + } + fn save(&mut self) { let mut proto = crate::protos::working_copy::Checkout::new(); proto.operation_id = self.operation_id().to_bytes(); @@ -894,6 +935,18 @@ impl LockedWorkingCopy<'_> { self.wc.tree_state().as_mut().unwrap().reset(new_tree) } + pub fn sparse_patterns(&self) -> Vec { + self.wc.sparse_patterns() + } + + pub fn set_sparse_patterns(&mut self, new_sparse_patterns: Vec) { + self.wc + .tree_state() + .as_mut() + .unwrap() + .set_sparse_patterns(new_sparse_patterns) + } + pub fn finish(mut self, operation_id: OperationId) { self.wc.tree_state().as_mut().unwrap().save(); self.wc.operation_id.replace(Some(operation_id)); diff --git a/lib/tests/test_working_copy.rs b/lib/tests/test_working_copy.rs index 55a0b4faf..831f4ea22 100644 --- a/lib/tests/test_working_copy.rs +++ b/lib/tests/test_working_copy.rs @@ -39,6 +39,7 @@ fn test_root(use_git: bool) { let repo = &test_workspace.repo; let wc = test_workspace.workspace.working_copy_mut(); + assert_eq!(wc.sparse_patterns(), vec![RepoPath::root()]); let mut locked_wc = wc.start_mutation(); let new_tree_id = locked_wc.write_tree(GitIgnoreFile::empty()); locked_wc.discard();