]>
Commit | Line | Data |
---|---|---|
0a29b90c FG |
1 | #![allow(clippy::result_large_err)] |
2 | use std::path::Path; | |
3 | ||
4 | pub use gix_discover::*; | |
781aab86 | 5 | use gix_macros::momo; |
0a29b90c FG |
6 | |
7 | use crate::{bstr::BString, ThreadSafeRepository}; | |
8 | ||
9 | /// The error returned by [`crate::discover()`]. | |
10 | #[derive(Debug, thiserror::Error)] | |
11 | #[allow(missing_docs)] | |
12 | pub enum Error { | |
13 | #[error(transparent)] | |
14 | Discover(#[from] upwards::Error), | |
15 | #[error(transparent)] | |
16 | Open(#[from] crate::open::Error), | |
17 | } | |
18 | ||
19 | impl ThreadSafeRepository { | |
20 | /// Try to open a git repository in `directory` and search upwards through its parents until one is found, | |
21 | /// using default trust options which matters in case the found repository isn't owned by the current user. | |
22 | pub fn discover(directory: impl AsRef<Path>) -> Result<Self, Error> { | |
23 | Self::discover_opts(directory, Default::default(), Default::default()) | |
24 | } | |
25 | ||
26 | /// Try to open a git repository in `directory` and search upwards through its parents until one is found, | |
27 | /// while applying `options`. Then use the `trust_map` to determine which of our own repository options to use | |
28 | /// for instantiations. | |
29 | /// | |
30 | /// Note that [trust overrides](crate::open::Options::with()) in the `trust_map` are not effective here and we will | |
31 | /// always override it with the determined trust value. This is a precaution as the API user is unable to actually know | |
32 | /// if the directory that is discovered can indeed be trusted (or else they'd have to implement the discovery themselves | |
33 | /// and be sure that no attacker ever gets access to a directory structure. The cost of this is a permission check, which | |
34 | /// seems acceptable). | |
781aab86 | 35 | #[momo] |
0a29b90c FG |
36 | pub fn discover_opts( |
37 | directory: impl AsRef<Path>, | |
38 | options: upwards::Options<'_>, | |
39 | trust_map: gix_sec::trust::Mapping<crate::open::Options>, | |
40 | ) -> Result<Self, Error> { | |
781aab86 FG |
41 | let _span = gix_trace::coarse!("ThreadSafeRepository::discover()"); |
42 | let (path, trust) = upwards_opts(directory.as_ref(), options)?; | |
0a29b90c FG |
43 | let (git_dir, worktree_dir) = path.into_repository_and_work_tree_directories(); |
44 | let mut options = trust_map.into_value_by_level(trust); | |
45 | options.git_dir_trust = trust.into(); | |
46 | options.current_dir = Some(std::env::current_dir().map_err(upwards::Error::CurrentDir)?); | |
47 | Self::open_from_paths(git_dir, worktree_dir, options).map_err(Into::into) | |
48 | } | |
49 | ||
50 | /// Try to open a git repository directly from the environment. | |
51 | /// If that fails, discover upwards from `directory` until one is found, | |
52 | /// while applying discovery options from the environment. | |
53 | pub fn discover_with_environment_overrides(directory: impl AsRef<Path>) -> Result<Self, Error> { | |
54 | Self::discover_with_environment_overrides_opts(directory, Default::default(), Default::default()) | |
55 | } | |
56 | ||
57 | /// Try to open a git repository directly from the environment, which reads `GIT_DIR` | |
58 | /// if it is set. If unset, discover upwards from `directory` until one is found, | |
59 | /// while applying `options` with overrides from the environment which includes: | |
60 | /// | |
61 | /// - `GIT_DISCOVERY_ACROSS_FILESYSTEM` | |
62 | /// - `GIT_CEILING_DIRECTORIES` | |
63 | /// | |
64 | /// Finally, use the `trust_map` to determine which of our own repository options to use | |
65 | /// based on the trust level of the effective repository directory. | |
781aab86 | 66 | #[momo] |
0a29b90c FG |
67 | pub fn discover_with_environment_overrides_opts( |
68 | directory: impl AsRef<Path>, | |
69 | mut options: upwards::Options<'_>, | |
70 | trust_map: gix_sec::trust::Mapping<crate::open::Options>, | |
71 | ) -> Result<Self, Error> { | |
72 | fn apply_additional_environment(mut opts: upwards::Options<'_>) -> upwards::Options<'_> { | |
73 | use crate::bstr::ByteVec; | |
74 | ||
75 | if let Some(cross_fs) = std::env::var_os("GIT_DISCOVERY_ACROSS_FILESYSTEM") | |
76 | .and_then(|v| Vec::from_os_string(v).ok().map(BString::from)) | |
77 | { | |
78 | if let Ok(b) = gix_config::Boolean::try_from(cross_fs.as_ref()) { | |
79 | opts.cross_fs = b.into(); | |
80 | } | |
81 | } | |
82 | opts | |
83 | } | |
84 | ||
85 | if std::env::var_os("GIT_DIR").is_some() { | |
86 | return Self::open_with_environment_overrides(directory.as_ref(), trust_map).map_err(Error::Open); | |
87 | } | |
88 | ||
89 | options = apply_additional_environment(options.apply_environment()); | |
90 | Self::discover_opts(directory, options, trust_map) | |
91 | } | |
92 | } |