History

fix: allow to open split worktree repositories

Sebastian Thiel committed 3 years ago

Commit 20f962e1 parent e9295dc8 files · +121 −25Browse files

Unified · Split

8 files
  1. gix/src/create.rs +1 −1
  2. gix/src/open/repository.rs +13 −3
  3. gix/src/repository/kind.rs +1 −1
  4. gix/tests/fixtures/make_worktree_repo.sh +32 −8
  5. gix/tests/repository/open.rs +54 −0
  6. gix/tests/repository/worktree.rs +9 −9
  7. gix/tests/submodule/mod.rs +5 −1
  8. gix/tests/util/mod.rs +6 −2
gix/src/create.rs+1−1
@@ -230,7 +230,7 @@ pub fn into( · 229 unmodified lines
230230 Ok(gix_discover::repository::Path::from_dot_git_dir(
231231 dot_git,
232232 if bare {
233− gix_discover::repository::Kind::Bare
233+ gix_discover::repository::Kind::PossiblyBare
234234 } else {
235235 gix_discover::repository::Kind::WorkTree { linked_git_dir: None }
236236 },
gix/src/open/repository.rs+13−3
@@ -240,10 +240,20 @@ impl ThreadSafeRepository { · 239 unmodified lines
240240 let wt_path = wt
241241 .interpolate(interpolate_context(git_install_dir.as_deref(), home.as_deref()))
242242 .map_err(config::Error::PathInterpolation)?;
243− worktree_dir = {
244− gix_path::normalize(git_dir.join(wt_path).into(), current_dir)
245− .and_then(|wt| wt.as_ref().is_dir().then(|| wt.into_owned()))
243+ worktree_dir = gix_path::normalize(git_dir.join(wt_path).into(), current_dir).map(Cow::into_owned);
244+ #[allow(unused_variables)]
245+ if let Some(worktree_path) = worktree_dir.as_deref().filter(|wtd| !wtd.is_dir()) {
246+ gix_trace::warn!("The configured worktree path '{}' is not a directory or doesn't exist - `core.worktree` may be misleading", worktree_path.display());
246247 }
248+ } else if !config.lenient_config
249+ && config
250+ .resolved
251+ .boolean_filter("core", None, Core::WORKTREE.name, &mut filter_config_section)
252+ .is_some()
253+ {
254+ return Err(Error::from(config::Error::ConfigTypedString(
255+ config::key::GenericErrorWithValue::from(&Core::WORKTREE),
256+ )));
247257 }
248258 }
249259
gix/src/repository/kind.rs+1−1
@@ -13,7 +13,7 @@ impl From<gix_discover::repository::Kind> for Kind { · 12 unmodified lines
1313 gix_discover::repository::Kind::Submodule { .. } | gix_discover::repository::Kind::SubmoduleGitDir => {
1414 Kind::WorkTree { is_linked: false }
1515 }
16− gix_discover::repository::Kind::Bare => Kind::Bare,
16+ gix_discover::repository::Kind::PossiblyBare => Kind::Bare,
1717 gix_discover::repository::Kind::WorkTreeGitDir { .. } => Kind::WorkTree { is_linked: true },
1818 gix_discover::repository::Kind::WorkTree { linked_git_dir } => Kind::WorkTree {
1919 is_linked: linked_git_dir.is_some(),
gix/tests/fixtures/make_worktree_repo.sh+32−8
@@ -17,18 +17,42 @@ mkdir repo · 16 unmodified lines
1717 git commit -q -am c2
1818 )
1919
20−if [ "$bare" == "bare" ]; then
20+(if [ "$bare" == "bare" ]; then
2121 git clone --bare --shared repo repo.git
2222 cd repo.git
2323 else
2424 cd repo
2525 fi
2626
27−git worktree add ../wt-a
28−git worktree add ../prev/wt-a HEAD~1
29−git worktree add ../wt-b HEAD~1
30−git worktree add ../wt-a/nested-wt-b HEAD~1
31−git worktree add --lock ../wt-c-locked
32−git worktree add ../wt-deleted && rm -Rf ../wt-deleted
27+ git worktree add ../wt-a
28+ git worktree add ../prev/wt-a HEAD~1
29+ git worktree add ../wt-b HEAD~1
30+ git worktree add ../wt-a/nested-wt-b HEAD~1
31+ git worktree add --lock ../wt-c-locked
32+ git worktree add ../wt-deleted && rm -Rf ../wt-deleted
3333
34−git worktree list --porcelain > ../worktree-list.baseline
34+ git worktree list --porcelain > ../worktree-list.baseline
35+)
36+
37+
38+git --git-dir=repo-with-worktree-in-config-unborn-no-worktreedir --work-tree=does-not-exist-yet init
39+worktree=repo-with-worktree-in-config-unborn-worktree
40+git --git-dir=repo-with-worktree-in-config-unborn --work-tree=$worktree init && mkdir $worktree
41+
42+repo=repo-with-worktree-in-config-unborn-empty-worktreedir
43+git --git-dir=$repo --work-tree="." init
44+git -C $repo config core.worktree ''
45+
46+repo=repo-with-worktree-in-config-unborn-worktreedir-missing-value
47+git --git-dir=$repo init
48+touch $repo/index
49+git -C $repo config core.bare false
50+echo " worktree" >> $repo/config
51+
52+worktree=repo-with-worktree-in-config-worktree
53+git --git-dir=repo-with-worktree-in-config --work-tree=$worktree init
54+mkdir $worktree && touch $worktree/file
55+(cd repo-with-worktree-in-config
56+ git add file
57+ git commit -m "make sure na index exists"
58+)
gix/tests/repository/open.rs+54−0
@@ -1,4 +1,5 @@
11 use crate::util::named_subrepo_opts;
2+use std::error::Error;
23
34 #[test]
45 fn bare_repo_with_index() -> crate::Result {
@@ -26,6 +27,59 @@ fn none_bare_repo_without_index() -> crate::Result { · 21 unmodified lines
2627 Ok(())
2728 }
2829
30+#[test]
31+fn non_bare_split_worktree() -> crate::Result {
32+ for (name, worktree_exists) in [
33+ ("repo-with-worktree-in-config-unborn-no-worktreedir", false),
34+ ("repo-with-worktree-in-config-unborn", true),
35+ ("repo-with-worktree-in-config", true),
36+ ] {
37+ let repo = named_subrepo_opts("make_worktree_repo.sh", name, gix::open::Options::isolated())?;
38+ assert!(repo.git_dir().is_dir());
39+ assert!(
40+ !repo.is_bare(),
41+ "worktree is actually configured, and it's non-bare by configuration"
42+ );
43+ assert_eq!(
44+ repo.work_dir().expect("worktree is configured").is_dir(),
45+ worktree_exists
46+ );
47+ }
48+ Ok(())
49+}
50+
51+#[test]
52+fn non_bare_split_worktree_invalid_worktree_path_boolean() -> crate::Result {
53+ let err = named_subrepo_opts(
54+ "make_worktree_repo.sh",
55+ "repo-with-worktree-in-config-unborn-worktreedir-missing-value",
56+ gix::open::Options::isolated().strict_config(true),
57+ )
58+ .unwrap_err();
59+ assert_eq!(
60+ err.source().expect("present").to_string(),
61+ "The key \"core.worktree\" (possibly from GIT_WORK_TREE) was invalid",
62+ "in strict mode, we fail just like git does"
63+ );
64+ Ok(())
65+}
66+
67+#[test]
68+fn non_bare_split_worktree_invalid_worktree_path_empty() -> crate::Result {
69+ // "repo-with-worktree-in-config-unborn-worktreedir-missing-value",
70+ let err = named_subrepo_opts(
71+ "make_worktree_repo.sh",
72+ "repo-with-worktree-in-config-unborn-empty-worktreedir",
73+ gix::open::Options::isolated(),
74+ )
75+ .unwrap_err();
76+ assert!(
77+ matches!(err, gix::open::Error::Config(gix::config::Error::PathInterpolation(_))),
78+ "DEVIATION: could not read path at core.worktree as empty is always invalid, git tries to use an empty path, even though it's better to reject it"
79+ );
80+ Ok(())
81+}
82+
2983 mod missing_config_file {
3084
3185 use crate::util::named_subrepo_opts;
gix/tests/repository/worktree.rs+9−9
@@ -91,10 +91,10 @@ mod with_core_worktree_config { · 90 unmodified lines
9191 "git can't chdir into missing worktrees, has no error handling there"
9292 );
9393
94− assert_eq!(
95− repo.work_dir(),
96− repo.git_dir().parent(),
97− "we just ignore missing configured worktree dirs and fall back to the default one"
94+ assert!(
95+ !repo.work_dir().expect("configured").exists(),
96+ "non-existing or invalid worktrees (this one is a file) are taken verbatim and \
97+ may lead to errors later - just like in `git` and we explicitly do not try to be smart about it"
9898 )
9999 }
100100
@@ -103,11 +103,11 @@ mod with_core_worktree_config { · 2 unmodified lines
103103 let repo = repo("relative-worktree-file");
104104 assert_eq!(count_deleted(repo.git_dir()), 0, "git can't chdir into a file");
105105
106− assert_eq!(
107− repo.work_dir(),
108− repo.git_dir().parent(),
109− "we just ignore missing configured worktree dirs and fall back to the default one"
110− )
106+ assert!(
107+ repo.work_dir().expect("configured").is_file(),
108+ "non-existing or invalid worktrees (this one is a file) are taken verbatim and \
109+ may lead to errors later - just like in `git` and we explicitly do not try to be smart about it"
110+ );
111111 }
112112
113113 #[test]
gix/tests/submodule/mod.rs+5−1
@@ -1,6 +1,10 @@
11 pub fn repo(name: &str) -> crate::Result<gix::Repository> {
22 use crate::util::named_subrepo_opts;
3− named_subrepo_opts("make_submodules.sh", name, gix::open::Options::isolated())
3+ Ok(named_subrepo_opts(
4+ "make_submodules.sh",
5+ name,
6+ gix::open::Options::isolated(),
7+ )?)
48 }
59
610 mod open {
gix/tests/util/mod.rs+6−2
@@ -34,8 +34,12 @@ pub fn named_repo(name: &str) -> Result<Repository> { · 33 unmodified lines
3434 Ok(ThreadSafeRepository::open_opts(repo_path, restricted())?.to_thread_local())
3535 }
3636
37−pub fn named_subrepo_opts(fixture: &str, name: &str, opts: open::Options) -> Result<Repository> {
38− let repo_path = gix_testtools::scripted_fixture_read_only(fixture)?.join(name);
37+pub fn named_subrepo_opts(
38+ fixture: &str,
39+ name: &str,
40+ opts: open::Options,
41+) -> std::result::Result<Repository, gix::open::Error> {
42+ let repo_path = gix_testtools::scripted_fixture_read_only(fixture).unwrap().join(name);
3943 Ok(ThreadSafeRepository::open_opts(repo_path, opts)?.to_thread_local())
4044 }
4145