History

alternate now handles cycles

Sebastian Thiel committed 6 years ago

Commit 71167e41 parent 73721183 files · +24 −5Browse files

Unified · Split

3 files
  1. git-odb/src/alternate.rs +7 −0
  2. git-odb/tests/alternate/mod.rs +14 −3
  3. tasks.md +3 −2
git-odb/src/alternate.rs+7−0
@@ -10,12 +10,19 @@ pub enum Error { · 9 unmodified lines
1010 PathConversion(Vec<u8>),
1111 #[error(transparent)]
1212 Init(#[from] compound::init::Error),
13+ #[error("Alternates form a cycle: {} -> {}", .0.iter().map(|p| format!("'{}'", p.display())).collect::<Vec<_>>().join(" -> "), .0.first().expect("more than one directories").display())]
14+ Cycle(Vec<PathBuf>),
1315 }
1416
1517 pub fn resolve(objects_directory: impl Into<PathBuf>) -> Result<Option<compound::Db>, Error> {
1618 let mut dir = objects_directory.into();
1719 let mut count = 0;
20+ let mut seen = Vec::new();
1821 loop {
22+ if seen.contains(&dir) {
23+ break Err(Error::Cycle(seen));
24+ }
25+ seen.push(dir.clone());
1926 let content = match fs::read(dir.join("info").join("alternates")) {
2027 Ok(d) => d,
2128 Err(err) if err.kind() == io::ErrorKind::NotFound => {
git-odb/tests/alternate/mod.rs+14−3
@@ -6,18 +6,29 @@ fn alternate(objects_at: impl Into<PathBuf>, objects_to: impl Into<PathBuf>) -> · 5 unmodified lines
66 let to = objects_to.into();
77 let at_info = at.join("info");
88 fs::create_dir_all(&at_info)?;
9− fs::create_dir(&to)?;
9+ fs::create_dir_all(&to)?;
1010 fs::write(at_info.join("alternates"), to.to_string_lossy().as_bytes())?;
1111 Ok((at, to))
1212 }
1313
1414 #[test]
15−#[ignore]
1615 fn circular_alternates_are_detected() -> crate::Result {
1716 let tmp = tempdir::TempDir::new("alternates")?;
18− alternate(tmp.path().join("a"), tmp.path().join("b"))?;
17+ let (from, _) = alternate(tmp.path().join("a"), tmp.path().join("b"))?;
1918 alternate(tmp.path().join("b"), tmp.path().join("a"))?;
2019
20+ match alternate::resolve(&from) {
21+ Err(alternate::Error::Cycle(chain)) => {
22+ assert_eq!(
23+ chain
24+ .into_iter()
25+ .map(|p| p.file_name().expect("non-root").to_str().expect("utf8").to_owned())
26+ .collect::<Vec<_>>(),
27+ vec!["a", "b"]
28+ );
29+ }
30+ _ => unreachable!("should be a specific kind of error"),
31+ }
2132 Ok(())
2233 }
2334
tasks.md+3−2
@@ -9,9 +9,10 @@ · 8 unmodified lines
99 * [x] Add #![deny(rust_2018_idioms)] everywhere
1010 * [x] Where 'thiserror' is available, use it for all Errors. It is more powerful, and if we paid for it already, let's use it.
1111 * [x] alternate DB (location - it's really must following the chain until a compound DB can be created)
12− * [ ] circular dependencies test
13− * [ ] basic test
12+ * [x] circular dependencies test
13+ * [x] basic test
1414 * [ ] loose upgrade: jwalk powered iteration behind a feature flag
15+ * [ ] full docs
1516 * **git-config**
1617 * A complete implementation, writing a the git remote configuration is needed for finalizing the clone
1718 * **git-ref**