History

wire everything up to have all data where it needs to be, but… (#301)

proper error handling needs more bounds on error E which can be done but really is a lot of typing. Nothing to be done here except for doing it I guess.

Sebastian Thiel committed 4 years ago

Commit 34d0d5c1 parent 883d78d6 files · +100 −37Browse files

Unified · Split

6 files
  1. git-worktree/src/fs/cache/mod.rs +11 −4
  2. git-worktree/src/fs/cache/platform.rs +13 −2
  3. git-worktree/src/fs/cache/state.rs +34 −9
  4. git-worktree/src/fs/mod.rs +2 −2
  5. git-worktree/src/index/entry.rs +1 −1
  6. git-worktree/tests/worktree/fs/cache.rs +39 −19
git-worktree/src/fs/cache/mod.rs+11−4
@@ -1,6 +1,7 @@
11 use super::Cache;
22 use crate::fs;
3−use crate::fs::PathIdMapping;
3+use crate::fs::PathOidMapping;
4+use git_hash::oid;
45 use std::path::{Path, PathBuf};
56
67 #[derive(Clone)]
@@ -66,7 +67,7 @@ impl<'paths> Cache<'paths> { · 59 unmodified lines
6667 state: State,
6768 case: git_glob::pattern::Case,
6869 buf: Vec<u8>,
69− attribute_files_in_index: Vec<PathIdMapping<'paths>>,
70+ attribute_files_in_index: Vec<PathOidMapping<'paths>>,
7071 ) -> Self {
7172 let root = worktree_root.into();
7273 Cache {
@@ -83,15 +84,21 @@ impl<'paths> Cache<'paths> { · 10 unmodified lines
8384 /// path is created as directory. If it's not known it is assumed to be a file.
8485 ///
8586 /// Provide access to cached information for that `relative` entry via the platform returned.
86− pub fn at_entry(
87+ pub fn at_entry<Find, E>(
8788 &mut self,
8889 relative: impl AsRef<Path>,
8990 is_dir: Option<bool>,
90− ) -> std::io::Result<Platform<'_, 'paths>> {
91+ find: Find,
92+ ) -> std::io::Result<Platform<'_, 'paths>>
93+ where
94+ Find: for<'a> FnMut(&oid, &'a mut Vec<u8>) -> Result<git_object::BlobRef<'a>, E>,
95+ {
9196 let mut platform = platform::StackDelegate {
9297 state: &mut self.state,
9398 buf: &mut self.buf,
9499 is_dir,
100+ attribute_files_in_index: &self.attribute_files_in_index,
101+ find,
95102 };
96103 self.stack.make_relative_path_current(relative, &mut platform)?;
97104 Ok(Platform { parent: self, is_dir })
git-worktree/src/fs/cache/platform.rs+13−2
@@ -1,5 +1,7 @@
11 use crate::fs;
22 use crate::fs::cache::{Platform, State};
3+use crate::fs::PathOidMapping;
4+use git_hash::oid;
35 use std::path::Path;
46
57 impl<'a, 'paths> Platform<'a, 'paths> {
@@ -43,13 +45,18 @@ impl<'a, 'paths> std::fmt::Debug for Platform<'a, 'paths> { · 37 unmodified lines
4345 }
4446 }
4547
46−pub struct StackDelegate<'a> {
48+pub struct StackDelegate<'a, 'paths, Find> {
4749 pub state: &'a mut State,
4850 pub buf: &'a mut Vec<u8>,
4951 pub is_dir: Option<bool>,
52+ pub attribute_files_in_index: &'a Vec<PathOidMapping<'paths>>,
53+ pub find: Find,
5054 }
5155
52−impl<'a> fs::stack::Delegate for StackDelegate<'a> {
56+impl<'a, 'paths, Find, E> fs::stack::Delegate for StackDelegate<'a, 'paths, Find>
57+where
58+ Find: for<'b> FnMut(&oid, &'b mut Vec<u8>) -> Result<git_object::BlobRef<'b>, E>,
59+{
5360 fn push(&mut self, is_last_component: bool, stack: &fs::Stack) -> std::io::Result<()> {
5461 match &mut self.state {
5562 State::CreateDirectoryAndAttributesStack {
@@ -77,11 +84,15 @@ impl<'a> fs::stack::Delegate for StackDelegate<'a> { · 21 unmodified lines
7784 &stack.root,
7885 stack.current.parent().expect("component was just pushed"),
7986 self.buf,
87+ self.attribute_files_in_index,
88+ &mut self.find,
8089 )?,
8190 State::IgnoreStack(ignore) => ignore.push(
8291 &stack.root,
8392 stack.current.parent().expect("component was just pushed"),
8493 self.buf,
94+ self.attribute_files_in_index,
95+ &mut self.find,
8596 )?,
8697 }
8798 Ok(())
git-worktree/src/fs/cache/state.rs+34−9
@@ -1,7 +1,8 @@
11 use crate::fs::cache::{state, State};
2−use crate::fs::PathIdMapping;
2+use crate::fs::PathOidMapping;
33 use bstr::{BStr, BString, ByteSlice};
44 use git_glob::pattern::Case;
5+use git_hash::oid;
56 use std::path::Path;
67
78 type AttributeMatchGroup = git_attributes::MatchGroup<git_attributes::Attributes>;
@@ -51,16 +52,40 @@ impl Ignore { · 43 unmodified lines
5152 }
5253 }
5354
54− pub fn push(&mut self, root: &Path, dir: &Path, buf: &mut Vec<u8>) -> std::io::Result<()> {
55− let follow_symlinks = true;
55+ pub fn push<Find, E>(
56+ &mut self,
57+ root: &Path,
58+ dir: &Path,
59+ buf: &mut Vec<u8>,
60+ attribute_files_in_index: &Vec<PathOidMapping<'_>>,
61+ _find: Find,
62+ ) -> std::io::Result<()>
63+ where
64+ Find: for<'b> FnMut(&oid, &'b mut Vec<u8>) -> Result<git_object::BlobRef<'b>, E>,
65+ {
66+ let ignore_path = git_features::path::convert::to_unix_separators(
67+ git_features::path::into_bytes_or_panic_on_windows(dir.join(".gitignore")),
68+ );
69+ let ignore_file_in_index = attribute_files_in_index.binary_search_by(|t| t.0.cmp(ignore_path.as_bstr()));
70+ let ignore_path = git_features::path::from_byte_vec_or_panic_on_windows(ignore_path);
71+ let follow_symlinks = ignore_file_in_index.is_err();
5672 if !self
5773 .stack
58− .add_patterns_file(dir.join(".gitignore"), follow_symlinks, Some(root), buf)?
74+ .add_patterns_file(ignore_path, follow_symlinks, Some(root), buf)?
5975 {
60− // Need one stack level per component so push and pop matches.
61− self.stack.patterns.push(Default::default());
76+ match ignore_file_in_index {
77+ Ok(_idx) => {
78+ // let ignore_blob = find(&attribute_files_in_index[0].1, buf)
79+ // .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?;
80+ // self.stack.add_patterns_buffer(ignore_blob.data);
81+ todo!()
82+ }
83+ Err(_) => {
84+ // Need one stack level per component so push and pop matches.
85+ self.stack.patterns.push(Default::default())
86+ }
87+ }
6288 }
63− // TODO: from index
6489 Ok(())
6590 }
6691 }
@@ -108,12 +133,12 @@ impl State { · 41 unmodified lines
108133 /// - ignores entries which aren't blobs
109134 /// - ignores ignore entries which are not skip-worktree
110135 /// - within merges, picks 'our' stage both for ignore and attribute files.
111− pub(crate) fn build_attribute_list<'paths>(
136+ pub fn build_attribute_list<'paths>(
112137 &self,
113138 index: &git_index::State,
114139 paths: &'paths git_index::PathStorage,
115140 case: git_glob::pattern::Case,
116− ) -> Vec<PathIdMapping<'paths>> {
141+ ) -> Vec<PathOidMapping<'paths>> {
117142 let a1_backing;
118143 let a2_backing;
119144 let names = match self {
git-worktree/src/fs/mod.rs+2−2
@@ -65,10 +65,10 @@ pub struct Cache<'paths> { · 64 unmodified lines
6565 /// If case folding should happen when looking up attributes or exclusions.
6666 case: git_glob::pattern::Case,
6767 /// A lookup table for object ids to read from in some situations when looking up attributes or exclusions.
68− attribute_files_in_index: Vec<PathIdMapping<'paths>>,
68+ attribute_files_in_index: Vec<PathOidMapping<'paths>>,
6969 }
7070
71−pub(crate) type PathIdMapping<'paths> = (&'paths BStr, git_hash::ObjectId);
71+pub(crate) type PathOidMapping<'paths> = (&'paths BStr, git_hash::ObjectId);
7272
7373 ///
7474 pub mod cache;
git-worktree/src/index/entry.rs+1−1
@@ -38,7 +38,7 @@ where · 37 unmodified lines
3838 path: entry_path.to_owned(),
3939 })?;
4040 let is_dir = Some(entry.mode == git_index::entry::Mode::COMMIT || entry.mode == git_index::entry::Mode::DIR);
41− let dest = path_cache.at_entry(dest_relative, is_dir)?.path();
41+ let dest = path_cache.at_entry(dest_relative, is_dir, &mut *find)?.path();
4242
4343 let object_size = match entry.mode {
4444 git_index::entry::Mode::FILE | git_index::entry::Mode::FILE_EXECUTABLE => {
git-worktree/tests/worktree/fs/cache.rs+39−19
@@ -4,6 +4,13 @@ mod create_directory { · 3 unmodified lines
44 use git_worktree::fs;
55 use tempfile::{tempdir, TempDir};
66
7+ fn panic_on_find<'buf>(
8+ _oid: &git_hash::oid,
9+ _buf: &'buf mut Vec<u8>,
10+ ) -> std::io::Result<git_object::BlobRef<'buf>> {
11+ unreachable!("find should nto be called")
12+ }
13+
714 #[test]
815 fn root_is_assumed_to_exist_and_files_in_root_do_not_create_directory() {
916 let dir = tempdir().unwrap();
@@ -16,7 +23,7 @@ mod create_directory { · 6 unmodified lines
1623 );
1724 assert_eq!(cache.num_mkdir_calls(), 0);
1825
19− let path = cache.at_entry("hello", Some(false)).unwrap().path();
26+ let path = cache.at_entry("hello", Some(false), panic_on_find).unwrap().path();
2027 assert!(!path.parent().unwrap().exists(), "prefix itself is never created");
2128 assert_eq!(cache.num_mkdir_calls(), 0);
2229 }
@@ -32,7 +39,10 @@ mod create_directory { · 9 unmodified lines
3239 ("exe", Some(false)),
3340 ("link", None),
3441 ] {
35− let path = cache.at_entry(Path::new("dir").join(name), *is_dir).unwrap().path();
42+ let path = cache
43+ .at_entry(Path::new("dir").join(name), *is_dir, panic_on_find)
44+ .unwrap()
45+ .path();
3646 assert!(path.parent().unwrap().is_dir(), "dir exists");
3747 }
3848
@@ -44,7 +54,7 @@ mod create_directory { · 5 unmodified lines
4454 let (mut cache, tmp) = new_cache();
4555 std::fs::create_dir(tmp.path().join("dir")).unwrap();
4656
47− let path = cache.at_entry("dir/file", Some(false)).unwrap().path();
57+ let path = cache.at_entry("dir/file", Some(false), panic_on_find).unwrap().path();
4858 assert!(path.parent().unwrap().is_dir(), "directory is still present");
4959 assert!(!path.exists(), "it won't create the file");
5060 assert_eq!(cache.num_mkdir_calls(), 1);
@@ -62,7 +72,10 @@ mod create_directory { · 11 unmodified lines
6272 cache.unlink_on_collision(false);
6373 let relative_path = format!("{}/file", dirname);
6474 assert_eq!(
65− cache.at_entry(&relative_path, Some(false)).unwrap_err().kind(),
75+ cache
76+ .at_entry(&relative_path, Some(false), panic_on_find)
77+ .unwrap_err()
78+ .kind(),
6679 std::io::ErrorKind::AlreadyExists
6780 );
6881 }
@@ -75,7 +88,10 @@ mod create_directory { · 6 unmodified lines
7588 for dirname in &["link-to-dir", "file-in-dir"] {
7689 cache.unlink_on_collision(true);
7790 let relative_path = format!("{}/file", dirname);
78− let path = cache.at_entry(&relative_path, Some(false)).unwrap().path();
91+ let path = cache
92+ .at_entry(&relative_path, Some(false), panic_on_find)
93+ .unwrap()
94+ .path();
7995 assert!(path.parent().unwrap().is_dir(), "directory was forcefully created");
8096 assert!(!path.exists());
8197 }
@@ -105,6 +121,8 @@ mod ignore_and_attributes { · 23 unmodified lines
105121 use std::path::Path;
106122
107123 use git_index::entry::Mode;
124+ use git_odb::pack::bundle::write::Options;
125+ use git_odb::FindExt;
108126 use git_worktree::fs;
109127 use tempfile::{tempdir, TempDir};
110128
@@ -134,7 +152,6 @@ mod ignore_and_attributes { · 23 unmodified lines
134152 }
135153
136154 #[test]
137− #[ignore]
138155 fn check_against_baseline() {
139156 let dir = git_testtools::scripted_fixture_repo_read_only("make_ignore_and_attributes_setup.sh").unwrap();
140157 let worktree_dir = dir.join("repo");
@@ -144,20 +161,21 @@ mod ignore_and_attributes { · 3 unmodified lines
144161 let user_exclude_path = dir.join("user.exclude");
145162 assert!(user_exclude_path.is_file());
146163
147− let mut cache = fs::Cache::new(
148− &worktree_dir,
149− git_worktree::fs::cache::State::for_add(
150− Default::default(),
151− git_worktree::fs::cache::state::Ignore::new(
152− git_attributes::MatchGroup::from_overrides(vec!["!force-include"]),
153− git_attributes::MatchGroup::from_git_dir(&git_dir, Some(user_exclude_path), &mut buf).unwrap(),
154− None,
155− ),
164+ let mut index = git_index::File::at(git_dir.join("index"), Default::default()).unwrap();
165+ let odb = git_odb::at(git_dir.join("objects")).unwrap();
166+ let state = git_worktree::fs::cache::State::for_add(
167+ Default::default(), // TODO: attribute tests
168+ git_worktree::fs::cache::state::Ignore::new(
169+ git_attributes::MatchGroup::from_overrides(vec!["!force-include"]),
170+ git_attributes::MatchGroup::from_git_dir(&git_dir, Some(user_exclude_path), &mut buf).unwrap(),
171+ None,
156172 ),
157− Default::default(),
158− buf,
159− Default::default(), // TODO: get the index, use it to ask state to get the attributes files LUT
160173 );
174+ let case = git_glob::pattern::Case::Sensitive;
175+ let paths_storage = index.take_path_backing();
176+ let attribute_files_in_index = state.build_attribute_list(&index.state, &paths_storage, case);
177+ assert_eq!(attribute_files_in_index, vec![]);
178+ let mut cache = fs::Cache::new(&worktree_dir, state, case, buf, attribute_files_in_index);
161179
162180 for (relative_path, source_and_line) in (IgnoreExpectations {
163181 lines: baseline.lines(),
@@ -168,7 +186,9 @@ mod ignore_and_attributes { · 4 unmodified lines
168186 // TODO: ignore file in index only
169187 // TODO: dir-excludes
170188 // TODO: a sibling dir to exercise pop() impl.
171− let platform = cache.at_entry(relative_path, is_dir).unwrap();
189+ let platform = cache
190+ .at_entry(relative_path, is_dir, |oid, buf| odb.find_blob(oid, buf))
191+ .unwrap();
172192
173193 let match_ = platform.matching_exclude_pattern();
174194 let is_excluded = platform.is_excluded();