gix/repository/config/
mod.rs

1use std::collections::BTreeSet;
2
3use crate::{bstr::ByteSlice, config};
4
5/// General Configuration
6impl crate::Repository {
7    /// Return a snapshot of the configuration as seen upon opening the repository.
8    pub fn config_snapshot(&self) -> config::Snapshot<'_> {
9        config::Snapshot { repo: self }
10    }
11
12    /// Return a mutable snapshot of the configuration as seen upon opening the repository, starting a transaction.
13    /// When the returned instance is dropped, it is applied in full, even if the reason for the drop is an error.
14    ///
15    /// Note that changes to the configuration are in-memory only and are observed only this instance
16    /// of the [`Repository`](crate::Repository).
17    pub fn config_snapshot_mut(&mut self) -> config::SnapshotMut<'_> {
18        let config = self.config.resolved.as_ref().clone();
19        config::SnapshotMut {
20            repo: Some(self),
21            config,
22        }
23    }
24
25    /// Return filesystem options as retrieved from the repository configuration.
26    ///
27    /// Note that these values have not been [probed](gix_fs::Capabilities::probe()).
28    pub fn filesystem_options(&self) -> Result<gix_fs::Capabilities, config::boolean::Error> {
29        self.config.fs_capabilities()
30    }
31
32    /// Return filesystem options on how to perform stat-checks, typically in relation to the index.
33    ///
34    /// Note that these values have not been [probed](gix_fs::Capabilities::probe()).
35    #[cfg(feature = "index")]
36    pub fn stat_options(&self) -> Result<gix_index::entry::stat::Options, config::stat_options::Error> {
37        self.config.stat_options()
38    }
39
40    /// The options used to open the repository.
41    pub fn open_options(&self) -> &crate::open::Options {
42        &self.options
43    }
44
45    /// Return the big-file threshold above which Git will not perform a diff anymore or try to delta-diff packs,
46    /// as configured by `core.bigFileThreshold`, or the default value.
47    pub fn big_file_threshold(&self) -> Result<u64, config::unsigned_integer::Error> {
48        self.config.big_file_threshold()
49    }
50
51    /// Create a low-level parser for ignore patterns, for instance for use in [`excludes()`](crate::Repository::excludes()).
52    ///
53    /// Depending on the configuration, precious-file parsing in `.gitignore-files` is supported.
54    /// This means that `$` prefixed files will be interpreted as precious, which is a backwards-incompatible change.
55    #[cfg(feature = "excludes")]
56    pub fn ignore_pattern_parser(&self) -> Result<gix_ignore::search::Ignore, config::boolean::Error> {
57        self.config.ignore_pattern_parser()
58    }
59
60    /// Obtain options for use when connecting via `ssh`.
61    #[cfg(feature = "blocking-network-client")]
62    pub fn ssh_connect_options(
63        &self,
64    ) -> Result<gix_protocol::transport::client::ssh::connect::Options, config::ssh_connect_options::Error> {
65        use crate::config::{
66            cache::util::ApplyLeniency,
67            tree::{gitoxide, Core, Ssh},
68        };
69
70        let config = &self.config.resolved;
71        let mut trusted = self.filter_config_section();
72        let mut fallback_active = false;
73        let ssh_command = config
74            .string_filter(Core::SSH_COMMAND, &mut trusted)
75            .or_else(|| {
76                fallback_active = true;
77                config.string_filter(gitoxide::Ssh::COMMAND_WITHOUT_SHELL_FALLBACK, &mut trusted)
78            })
79            .map(|cmd| gix_path::from_bstr(cmd).into_owned().into());
80        let opts = gix_protocol::transport::client::ssh::connect::Options {
81            disallow_shell: fallback_active,
82            command: ssh_command,
83            kind: config
84                .string_filter("ssh.variant", &mut trusted)
85                .and_then(|variant| Ssh::VARIANT.try_into_variant(variant).transpose())
86                .transpose()
87                .with_leniency(self.options.lenient_config)?,
88        };
89        Ok(opts)
90    }
91
92    /// Return the context to be passed to any spawned program that is supposed to interact with the repository, like
93    /// hooks or filters.
94    #[cfg(feature = "attributes")]
95    pub fn command_context(&self) -> Result<gix_command::Context, config::command_context::Error> {
96        use crate::config::{cache::util::ApplyLeniency, tree::gitoxide};
97
98        let pathspec_boolean = |key: &'static config::tree::keys::Boolean| {
99            self.config
100                .resolved
101                .boolean(key)
102                .map(|value| key.enrich_error(value))
103                .transpose()
104                .with_leniency(self.config.lenient_config)
105        };
106
107        Ok(gix_command::Context {
108            stderr: {
109                self.config
110                    .resolved
111                    .boolean(gitoxide::Core::EXTERNAL_COMMAND_STDERR)
112                    .map(|value| gitoxide::Core::EXTERNAL_COMMAND_STDERR.enrich_error(value))
113                    .transpose()
114                    .with_leniency(self.config.lenient_config)?
115                    .unwrap_or(true)
116                    .into()
117            },
118            git_dir: self.git_dir().to_owned().into(),
119            worktree_dir: self.workdir().map(ToOwned::to_owned),
120            no_replace_objects: config::shared::is_replace_refs_enabled(
121                &self.config.resolved,
122                self.config.lenient_config,
123                self.filter_config_section(),
124            )?
125            .map(|enabled| !enabled),
126            ref_namespace: self.refs.namespace.as_ref().map(|ns| ns.as_bstr().to_owned()),
127            literal_pathspecs: pathspec_boolean(&gitoxide::Pathspec::LITERAL)?,
128            glob_pathspecs: pathspec_boolean(&gitoxide::Pathspec::GLOB)?
129                .or(pathspec_boolean(&gitoxide::Pathspec::NOGLOB)?),
130            icase_pathspecs: pathspec_boolean(&gitoxide::Pathspec::ICASE)?,
131        })
132    }
133
134    /// The kind of object hash the repository is configured to use.
135    pub fn object_hash(&self) -> gix_hash::Kind {
136        self.config.object_hash
137    }
138
139    /// Return the algorithm to perform diffs or merges with.
140    ///
141    /// In case of merges, a diff is performed under the hood in order to learn which hunks need merging.
142    #[cfg(feature = "blob-diff")]
143    pub fn diff_algorithm(&self) -> Result<gix_diff::blob::Algorithm, config::diff::algorithm::Error> {
144        self.config.diff_algorithm()
145    }
146}
147
148mod branch;
149mod remote;
150#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
151mod transport;
152
153impl crate::Repository {
154    pub(crate) fn filter_config_section(&self) -> fn(&gix_config::file::Metadata) -> bool {
155        self.options
156            .filter_config_section
157            .unwrap_or(config::section::is_trusted)
158    }
159
160    fn subsection_str_names_of<'a>(&'a self, header_name: &'a str) -> BTreeSet<&'a str> {
161        self.config
162            .resolved
163            .sections_by_name(header_name)
164            .map(|it| {
165                let filter = self.filter_config_section();
166                it.filter(move |s| filter(s.meta()))
167                    .filter_map(|section| section.header().subsection_name().and_then(|b| b.to_str().ok()))
168                    .collect()
169            })
170            .unwrap_or_default()
171    }
172}