History

feat: `open::Options::open_path_as_is()` allows to avoid 'smart opening' to try the path verbatim.

The path to git repositories is well-known as they either end in `.git` or `.../.git`. If this is not the case, by default we append `/.git` to the path. With this new option enabled, no path transformations apply to open the given path as is, which is preferable if you know it's a non-standard git repository folder name.

Sebastian Thiel committed 3 years ago

Commit ca84c871 parent 68ba9a05 files · +67 −7Browse files

Unified · Split

5 files
  1. git-repository/src/open/mod.rs +1 −0
  2. git-repository/src/open/options.rs +12 −0
  3. git-repository/src/open/repository.rs +21 −7
  4. git-repository/tests/repository/open.rs +28 −0
  5. git-repository/tests/util/mod.rs +5 −0
git-repository/src/open/mod.rs+1−0
@@ -23,6 +23,7 @@ pub struct Options { · 22 unmodified lines
2323 pub(crate) bail_if_untrusted: bool,
2424 pub(crate) api_config_overrides: Vec<BString>,
2525 pub(crate) cli_config_overrides: Vec<BString>,
26+ pub(crate) open_path_as_is: bool,
2627 /// Internal to pass an already obtained CWD on to where it may also be used. This avoids the CWD being queried more than once per repo.
2728 pub(crate) current_dir: Option<PathBuf>,
2829 }
git-repository/src/open/options.rs+12−0
@@ -13,6 +13,7 @@ impl Default for Options { · 12 unmodified lines
1313 lossy_config: None,
1414 lenient_config: true,
1515 bail_if_untrusted: false,
16+ open_path_as_is: false,
1617 api_config_overrides: Vec::new(),
1718 cli_config_overrides: Vec::new(),
1819 current_dir: None,
@@ -69,6 +70,15 @@ impl Options { · 50 unmodified lines
6970 self
7071 }
7172
73+ /// If `true`, default `false`, we will not modify the incoming path to open to assure it is a `.git` directory.
74+ ///
75+ /// If `false`, we will try to open the input directory as is, even though it doesn't appear to be a `git` repository
76+ /// due to the lack of `.git` suffix or because its basename is not `.git` as in `worktree/.git`.
77+ pub fn open_path_as_is(mut self, enable: bool) -> Self {
78+ self.open_path_as_is = enable;
79+ self
80+ }
81+
7282 /// Set the trust level of the `.git` directory we are about to open.
7383 ///
7484 /// This can be set manually to force trust even though otherwise it might
@@ -146,6 +156,7 @@ impl git_sec::trust::DefaultForLevel for Options { · 71 unmodified lines
146156 lossy_config: None,
147157 bail_if_untrusted: false,
148158 lenient_config: true,
159+ open_path_as_is: false,
149160 api_config_overrides: Vec::new(),
150161 cli_config_overrides: Vec::new(),
151162 current_dir: None,
@@ -157,6 +168,7 @@ impl git_sec::trust::DefaultForLevel for Options { · 5 unmodified lines
157168 filter_config_section: Some(config::section::is_trusted),
158169 bail_if_untrusted: false,
159170 lenient_config: true,
171+ open_path_as_is: false,
160172 lossy_config: None,
161173 api_config_overrides: Vec::new(),
162174 cli_config_overrides: Vec::new(),
git-repository/src/open/repository.rs+21−7
@@ -48,13 +48,26 @@ impl ThreadSafeRepository { · 47 unmodified lines
4848 pub fn open_opts(path: impl Into<PathBuf>, mut options: Options) -> Result<Self, Error> {
4949 let (path, kind) = {
5050 let path = path.into();
51− match git_discover::is_git(&path) {
52− Ok(kind) => (path, kind),
53− Err(_err) => {
54− let git_dir = path.join(git_discover::DOT_GIT_DIR);
55− git_discover::is_git(&git_dir)
56− .map(|kind| (git_dir, kind))
57− .map_err(|err| Error::NotARepository { source: err, path })?
51+ let looks_like_git_dir =
52+ path.ends_with(git_discover::DOT_GIT_DIR) || path.extension() == Some(std::ffi::OsStr::new("git"));
53+ let candidate = if !options.open_path_as_is && !looks_like_git_dir {
54+ Cow::Owned(path.join(git_discover::DOT_GIT_DIR))
55+ } else {
56+ Cow::Borrowed(&path)
57+ };
58+ match git_discover::is_git(candidate.as_ref()) {
59+ Ok(kind) => (candidate.into_owned(), kind),
60+ Err(err) => {
61+ if options.open_path_as_is || matches!(candidate, Cow::Borrowed(_)) {
62+ return Err(Error::NotARepository {
63+ source: err,
64+ path: candidate.into_owned(),
65+ });
66+ }
67+ match git_discover::is_git(&path) {
68+ Ok(kind) => (path, kind),
69+ Err(err) => return Err(Error::NotARepository { source: err, path }),
70+ }
5871 }
5972 }
6073 };
@@ -128,6 +141,7 @@ impl ThreadSafeRepository { · 67 unmodified lines
128141 lossy_config,
129142 lenient_config,
130143 bail_if_untrusted,
144+ open_path_as_is: _,
131145 permissions: Permissions { ref env, config },
132146 ref api_config_overrides,
133147 ref cli_config_overrides,
git-repository/tests/repository/open.rs+28−0
@@ -46,6 +46,34 @@ mod not_a_repository { · 45 unmodified lines
4646 }
4747 }
4848
49+mod open_path_as_is {
50+ use crate::util::{named_subrepo_opts, repo_opts};
51+ use git_repository as git;
52+
53+ fn open_path_as_is() -> git::open::Options {
54+ git::open::Options::isolated().open_path_as_is(true)
55+ }
56+
57+ #[test]
58+ fn bare_repos_open_normally() -> crate::Result {
59+ assert!(named_subrepo_opts("make_basic_repo.sh", "bare.git", open_path_as_is())?.is_bare());
60+ Ok(())
61+ }
62+
63+ #[test]
64+ fn worktrees_cannot_be_opened() -> crate::Result {
65+ let err = repo_opts("make_basic_repo.sh", open_path_as_is()).unwrap_err();
66+ assert!(matches!(err, git::open::Error::NotARepository { .. }));
67+ Ok(())
68+ }
69+
70+ #[test]
71+ fn git_dir_within_worktrees_open_normally() -> crate::Result {
72+ assert!(!named_subrepo_opts("make_basic_repo.sh", ".git", open_path_as_is())?.is_bare());
73+ Ok(())
74+ }
75+}
76+
4977 mod submodules {
5078 use std::path::Path;
5179
git-repository/tests/util/mod.rs+5−0
@@ -18,6 +18,11 @@ pub fn repo(name: &str) -> Result<ThreadSafeRepository> { · 17 unmodified lines
1818 Ok(ThreadSafeRepository::open_opts(repo_path, restricted())?)
1919 }
2020
21+pub fn repo_opts(name: &str, opts: open::Options) -> std::result::Result<ThreadSafeRepository, open::Error> {
22+ let repo_path = git_testtools::scripted_fixture_read_only(name).unwrap();
23+ ThreadSafeRepository::open_opts(repo_path, opts)
24+}
25+
2126 pub fn named_repo(name: &str) -> Result<Repository> {
2227 let repo_path = git_testtools::scripted_fixture_read_only(name)?;
2328 Ok(ThreadSafeRepository::open_opts(repo_path, restricted())?.to_thread_local())

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t