summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/config
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
commit10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch)
treebdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/gix/src/config
parentReleasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff)
downloadrustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz
rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix/src/config')
-rw-r--r--vendor/gix/src/config/cache/access.rs233
-rw-r--r--vendor/gix/src/config/cache/incubate.rs111
-rw-r--r--vendor/gix/src/config/cache/init.rs485
-rw-r--r--vendor/gix/src/config/cache/mod.rs18
-rw-r--r--vendor/gix/src/config/cache/util.rs143
-rw-r--r--vendor/gix/src/config/mod.rs454
-rw-r--r--vendor/gix/src/config/overrides.rs49
-rw-r--r--vendor/gix/src/config/snapshot/_impls.rs76
-rw-r--r--vendor/gix/src/config/snapshot/access.rs143
-rw-r--r--vendor/gix/src/config/snapshot/credential_helpers.rs183
-rw-r--r--vendor/gix/src/config/snapshot/mod.rs5
-rw-r--r--vendor/gix/src/config/tree/keys.rs629
-rw-r--r--vendor/gix/src/config/tree/mod.rs123
-rw-r--r--vendor/gix/src/config/tree/sections/author.rs23
-rw-r--r--vendor/gix/src/config/tree/sections/branch.rs65
-rw-r--r--vendor/gix/src/config/tree/sections/checkout.rs58
-rw-r--r--vendor/gix/src/config/tree/sections/clone.rs20
-rw-r--r--vendor/gix/src/config/tree/sections/committer.rs23
-rw-r--r--vendor/gix/src/config/tree/sections/core.rs302
-rw-r--r--vendor/gix/src/config/tree/sections/credential.rs56
-rw-r--r--vendor/gix/src/config/tree/sections/diff.rs133
-rw-r--r--vendor/gix/src/config/tree/sections/extensions.rs59
-rw-r--r--vendor/gix/src/config/tree/sections/gitoxide.rs363
-rw-r--r--vendor/gix/src/config/tree/sections/http.rs317
-rw-r--r--vendor/gix/src/config/tree/sections/init.rs20
-rw-r--r--vendor/gix/src/config/tree/sections/mod.rs96
-rw-r--r--vendor/gix/src/config/tree/sections/pack.rs64
-rw-r--r--vendor/gix/src/config/tree/sections/protocol.rs85
-rw-r--r--vendor/gix/src/config/tree/sections/remote.rs101
-rw-r--r--vendor/gix/src/config/tree/sections/safe.rs27
-rw-r--r--vendor/gix/src/config/tree/sections/ssh.rs65
-rw-r--r--vendor/gix/src/config/tree/sections/url.rs25
-rw-r--r--vendor/gix/src/config/tree/sections/user.rs22
-rw-r--r--vendor/gix/src/config/tree/traits.rs199
34 files changed, 4775 insertions, 0 deletions
diff --git a/vendor/gix/src/config/cache/access.rs b/vendor/gix/src/config/cache/access.rs
new file mode 100644
index 000000000..8244eaf27
--- /dev/null
+++ b/vendor/gix/src/config/cache/access.rs
@@ -0,0 +1,233 @@
+#![allow(clippy::result_large_err)]
+use std::{borrow::Cow, path::PathBuf, time::Duration};
+
+use gix_lock::acquire::Fail;
+
+use crate::{
+ bstr::BStr,
+ config,
+ config::{
+ cache::util::{ApplyLeniency, ApplyLeniencyDefault},
+ checkout_options,
+ tree::{Checkout, Core, Key},
+ Cache,
+ },
+ remote,
+ repository::identity,
+};
+
+/// Access
+impl Cache {
+ pub(crate) fn diff_algorithm(&self) -> Result<gix_diff::blob::Algorithm, config::diff::algorithm::Error> {
+ use crate::config::diff::algorithm::Error;
+ self.diff_algorithm
+ .get_or_try_init(|| {
+ let name = self
+ .resolved
+ .string("diff", None, "algorithm")
+ .unwrap_or_else(|| Cow::Borrowed("myers".into()));
+ config::tree::Diff::ALGORITHM
+ .try_into_algorithm(name)
+ .or_else(|err| match err {
+ Error::Unimplemented { .. } if self.lenient_config => Ok(gix_diff::blob::Algorithm::Histogram),
+ err => Err(err),
+ })
+ .with_lenient_default(self.lenient_config)
+ })
+ .copied()
+ }
+
+ /// Returns a user agent for use with servers.
+ #[cfg(any(feature = "async-network-client", feature = "blocking-network-client"))]
+ pub(crate) fn user_agent_tuple(&self) -> (&'static str, Option<Cow<'static, str>>) {
+ use config::tree::Gitoxide;
+ let agent = self
+ .user_agent
+ .get_or_init(|| {
+ self.resolved
+ .string_by_key(Gitoxide::USER_AGENT.logical_name().as_str())
+ .map(|s| s.to_string())
+ .unwrap_or_else(|| crate::env::agent().into())
+ })
+ .to_owned();
+ ("agent", Some(gix_protocol::agent(agent).into()))
+ }
+
+ pub(crate) fn personas(&self) -> &identity::Personas {
+ self.personas
+ .get_or_init(|| identity::Personas::from_config_and_env(&self.resolved))
+ }
+
+ pub(crate) fn url_rewrite(&self) -> &remote::url::Rewrite {
+ self.url_rewrite
+ .get_or_init(|| remote::url::Rewrite::from_config(&self.resolved, self.filter_config_section))
+ }
+
+ #[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
+ pub(crate) fn url_scheme(&self) -> Result<&remote::url::SchemePermission, config::protocol::allow::Error> {
+ self.url_scheme
+ .get_or_try_init(|| remote::url::SchemePermission::from_config(&self.resolved, self.filter_config_section))
+ }
+
+ pub(crate) fn diff_renames(
+ &self,
+ ) -> Result<Option<crate::object::tree::diff::Rewrites>, crate::object::tree::diff::rewrites::Error> {
+ self.diff_renames
+ .get_or_try_init(|| {
+ crate::object::tree::diff::Rewrites::try_from_config(&self.resolved, self.lenient_config)
+ })
+ .copied()
+ }
+
+ /// Returns (file-timeout, pack-refs timeout)
+ pub(crate) fn lock_timeout(
+ &self,
+ ) -> Result<(gix_lock::acquire::Fail, gix_lock::acquire::Fail), config::lock_timeout::Error> {
+ let mut out: [gix_lock::acquire::Fail; 2] = Default::default();
+ for (idx, (key, default_ms)) in [(&Core::FILES_REF_LOCK_TIMEOUT, 100), (&Core::PACKED_REFS_TIMEOUT, 1000)]
+ .into_iter()
+ .enumerate()
+ {
+ out[idx] = self
+ .resolved
+ .integer_filter("core", None, key.name, &mut self.filter_config_section.clone())
+ .map(|res| key.try_into_lock_timeout(res))
+ .transpose()
+ .with_leniency(self.lenient_config)?
+ .unwrap_or_else(|| Fail::AfterDurationWithBackoff(Duration::from_millis(default_ms)));
+ }
+ Ok((out[0], out[1]))
+ }
+
+ /// The path to the user-level excludes file to ignore certain files in the worktree.
+ pub(crate) fn excludes_file(&self) -> Option<Result<PathBuf, gix_config::path::interpolate::Error>> {
+ self.trusted_file_path("core", None, Core::EXCLUDES_FILE.name)?
+ .map(|p| p.into_owned())
+ .into()
+ }
+
+ /// A helper to obtain a file from trusted configuration at `section_name`, `subsection_name`, and `key`, which is interpolated
+ /// if present.
+ pub(crate) fn trusted_file_path(
+ &self,
+ section_name: impl AsRef<str>,
+ subsection_name: Option<&BStr>,
+ key: impl AsRef<str>,
+ ) -> Option<Result<Cow<'_, std::path::Path>, gix_config::path::interpolate::Error>> {
+ let path = self.resolved.path_filter(
+ section_name,
+ subsection_name,
+ key,
+ &mut self.filter_config_section.clone(),
+ )?;
+
+ let install_dir = crate::path::install_dir().ok();
+ let home = self.home_dir();
+ let ctx = crate::config::cache::interpolate_context(install_dir.as_deref(), home.as_deref());
+ Some(path.interpolate(ctx))
+ }
+
+ pub(crate) fn apply_leniency<T, E>(&self, res: Option<Result<T, E>>) -> Result<Option<T>, E> {
+ res.transpose().with_leniency(self.lenient_config)
+ }
+
+ /// Collect everything needed to checkout files into a worktree.
+ /// Note that some of the options being returned will be defaulted so safe settings, the caller might have to override them
+ /// depending on the use-case.
+ pub(crate) fn checkout_options(
+ &self,
+ git_dir: &std::path::Path,
+ ) -> Result<gix_worktree::index::checkout::Options, checkout_options::Error> {
+ fn boolean(
+ me: &Cache,
+ full_key: &str,
+ key: &'static config::tree::keys::Boolean,
+ default: bool,
+ ) -> Result<bool, checkout_options::Error> {
+ debug_assert_eq!(
+ full_key,
+ key.logical_name(),
+ "BUG: key name and hardcoded name must match"
+ );
+ Ok(me
+ .apply_leniency(me.resolved.boolean_by_key(full_key).map(|v| key.enrich_error(v)))?
+ .unwrap_or(default))
+ }
+
+ fn assemble_attribute_globals(
+ me: &Cache,
+ _git_dir: &std::path::Path,
+ ) -> Result<gix_attributes::MatchGroup, checkout_options::Error> {
+ let _attributes_file = match me
+ .trusted_file_path("core", None, Core::ATTRIBUTES_FILE.name)
+ .transpose()?
+ {
+ Some(attributes) => Some(attributes.into_owned()),
+ None => me.xdg_config_path("attributes").ok().flatten(),
+ };
+ // TODO: implement gix_attributes::MatchGroup::<gix_attributes::Attributes>::from_git_dir(), similar to what's done for `Ignore`.
+ Ok(Default::default())
+ }
+
+ let thread_limit = self.apply_leniency(
+ self.resolved
+ .integer_filter_by_key("checkout.workers", &mut self.filter_config_section.clone())
+ .map(|value| Checkout::WORKERS.try_from_workers(value)),
+ )?;
+ Ok(gix_worktree::index::checkout::Options {
+ fs: gix_worktree::fs::Capabilities {
+ precompose_unicode: boolean(self, "core.precomposeUnicode", &Core::PRECOMPOSE_UNICODE, false)?,
+ ignore_case: boolean(self, "core.ignoreCase", &Core::IGNORE_CASE, false)?,
+ executable_bit: boolean(self, "core.fileMode", &Core::FILE_MODE, true)?,
+ symlink: boolean(self, "core.symlinks", &Core::SYMLINKS, true)?,
+ },
+ thread_limit,
+ destination_is_initially_empty: false,
+ overwrite_existing: false,
+ keep_going: false,
+ trust_ctime: boolean(self, "core.trustCTime", &Core::TRUST_C_TIME, true)?,
+ check_stat: self
+ .apply_leniency(
+ self.resolved
+ .string("core", None, "checkStat")
+ .map(|v| Core::CHECK_STAT.try_into_checkstat(v)),
+ )?
+ .unwrap_or(true),
+ attribute_globals: assemble_attribute_globals(self, git_dir)?,
+ })
+ }
+ pub(crate) fn xdg_config_path(
+ &self,
+ resource_file_name: &str,
+ ) -> Result<Option<PathBuf>, gix_sec::permission::Error<PathBuf>> {
+ std::env::var_os("XDG_CONFIG_HOME")
+ .map(|path| (PathBuf::from(path), &self.xdg_config_home_env))
+ .or_else(|| {
+ std::env::var_os("HOME").map(|path| {
+ (
+ {
+ let mut p = PathBuf::from(path);
+ p.push(".config");
+ p
+ },
+ &self.home_env,
+ )
+ })
+ })
+ .and_then(|(base, permission)| {
+ let resource = base.join("git").join(resource_file_name);
+ permission.check(resource).transpose()
+ })
+ .transpose()
+ }
+
+ /// Return the home directory if we are allowed to read it and if it is set in the environment.
+ ///
+ /// We never fail for here even if the permission is set to deny as we `gix-config` will fail later
+ /// if it actually wants to use the home directory - we don't want to fail prematurely.
+ pub(crate) fn home_dir(&self) -> Option<PathBuf> {
+ std::env::var_os("HOME")
+ .map(PathBuf::from)
+ .and_then(|path| self.home_env.check_opt(path))
+ }
+}
diff --git a/vendor/gix/src/config/cache/incubate.rs b/vendor/gix/src/config/cache/incubate.rs
new file mode 100644
index 000000000..047f2132b
--- /dev/null
+++ b/vendor/gix/src/config/cache/incubate.rs
@@ -0,0 +1,111 @@
+#![allow(clippy::result_large_err)]
+use super::{util, Error};
+use crate::config::tree::{Core, Extensions};
+
+/// A utility to deal with the cyclic dependency between the ref store and the configuration. The ref-store needs the
+/// object hash kind, and the configuration needs the current branch name to resolve conditional includes with `onbranch`.
+pub(crate) struct StageOne {
+ pub git_dir_config: gix_config::File<'static>,
+ pub buf: Vec<u8>,
+
+ pub is_bare: bool,
+ pub lossy: Option<bool>,
+ pub object_hash: gix_hash::Kind,
+ pub reflog: Option<gix_ref::store::WriteReflog>,
+}
+
+/// Initialization
+impl StageOne {
+ pub fn new(
+ common_dir: &std::path::Path,
+ git_dir: &std::path::Path,
+ git_dir_trust: gix_sec::Trust,
+ lossy: Option<bool>,
+ lenient: bool,
+ ) -> Result<Self, Error> {
+ let mut buf = Vec::with_capacity(512);
+ let mut config = load_config(
+ common_dir.join("config"),
+ &mut buf,
+ gix_config::Source::Local,
+ git_dir_trust,
+ lossy,
+ )?;
+
+ // Note that we assume the repo is bare by default unless we are told otherwise. This is relevant if
+ // the repo doesn't have a configuration file.
+ let is_bare = util::config_bool(&config, &Core::BARE, "core.bare", true, lenient)?;
+ let repo_format_version = config
+ .integer_by_key("core.repositoryFormatVersion")
+ .map(|version| Core::REPOSITORY_FORMAT_VERSION.try_into_usize(version))
+ .transpose()?
+ .unwrap_or_default();
+ let object_hash = (repo_format_version != 1)
+ .then_some(Ok(gix_hash::Kind::Sha1))
+ .or_else(|| {
+ config
+ .string("extensions", None, "objectFormat")
+ .map(|format| Extensions::OBJECT_FORMAT.try_into_object_format(format))
+ })
+ .transpose()?
+ .unwrap_or(gix_hash::Kind::Sha1);
+
+ let extension_worktree = util::config_bool(
+ &config,
+ &Extensions::WORKTREE_CONFIG,
+ "extensions.worktreeConfig",
+ false,
+ lenient,
+ )?;
+ if extension_worktree {
+ let worktree_config = load_config(
+ git_dir.join("config.worktree"),
+ &mut buf,
+ gix_config::Source::Worktree,
+ git_dir_trust,
+ lossy,
+ )?;
+ config.append(worktree_config);
+ };
+
+ let reflog = util::query_refupdates(&config, lenient)?;
+ Ok(StageOne {
+ git_dir_config: config,
+ buf,
+ is_bare,
+ lossy,
+ object_hash,
+ reflog,
+ })
+ }
+}
+
+fn load_config(
+ config_path: std::path::PathBuf,
+ buf: &mut Vec<u8>,
+ source: gix_config::Source,
+ git_dir_trust: gix_sec::Trust,
+ lossy: Option<bool>,
+) -> Result<gix_config::File<'static>, Error> {
+ buf.clear();
+ let metadata = gix_config::file::Metadata::from(source)
+ .at(&config_path)
+ .with(git_dir_trust);
+ let mut file = match std::fs::File::open(&config_path) {
+ Ok(f) => f,
+ Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(gix_config::File::new(metadata)),
+ Err(err) => return Err(err.into()),
+ };
+ std::io::copy(&mut file, buf)?;
+
+ let config = gix_config::File::from_bytes_owned(
+ buf,
+ metadata,
+ gix_config::file::init::Options {
+ includes: gix_config::file::includes::Options::no_follow(),
+ ..util::base_options(lossy)
+ },
+ )?;
+
+ Ok(config)
+}
diff --git a/vendor/gix/src/config/cache/init.rs b/vendor/gix/src/config/cache/init.rs
new file mode 100644
index 000000000..dc76f78bb
--- /dev/null
+++ b/vendor/gix/src/config/cache/init.rs
@@ -0,0 +1,485 @@
+#![allow(clippy::result_large_err)]
+use std::borrow::Cow;
+
+use gix_sec::Permission;
+
+use super::{interpolate_context, util, Error, StageOne};
+use crate::{
+ bstr::BString,
+ config,
+ config::{
+ cache::util::ApplyLeniency,
+ tree::{gitoxide, Core, Http},
+ Cache,
+ },
+ repository,
+};
+
+/// Initialization
+impl Cache {
+ #[allow(clippy::too_many_arguments)]
+ pub fn from_stage_one(
+ StageOne {
+ git_dir_config,
+ mut buf,
+ lossy,
+ is_bare,
+ object_hash,
+ reflog: _,
+ }: StageOne,
+ git_dir: &std::path::Path,
+ branch_name: Option<&gix_ref::FullNameRef>,
+ filter_config_section: fn(&gix_config::file::Metadata) -> bool,
+ git_install_dir: Option<&std::path::Path>,
+ home: Option<&std::path::Path>,
+ repository::permissions::Environment {
+ git_prefix,
+ home: home_env,
+ xdg_config_home: xdg_config_home_env,
+ ssh_prefix: _,
+ http_transport,
+ identity,
+ objects,
+ }: repository::permissions::Environment,
+ repository::permissions::Config {
+ git_binary: use_installation,
+ system: use_system,
+ git: use_git,
+ user: use_user,
+ env: use_env,
+ includes: use_includes,
+ }: repository::permissions::Config,
+ lenient_config: bool,
+ api_config_overrides: &[BString],
+ cli_config_overrides: &[BString],
+ ) -> Result<Self, Error> {
+ let options = gix_config::file::init::Options {
+ includes: if use_includes {
+ gix_config::file::includes::Options::follow(
+ interpolate_context(git_install_dir, home),
+ gix_config::file::includes::conditional::Context {
+ git_dir: git_dir.into(),
+ branch_name,
+ },
+ )
+ } else {
+ gix_config::file::includes::Options::no_follow()
+ },
+ ..util::base_options(lossy)
+ };
+
+ let config = {
+ let home_env = &home_env;
+ let xdg_config_home_env = &xdg_config_home_env;
+ let git_prefix = &git_prefix;
+ let metas = [
+ gix_config::source::Kind::GitInstallation,
+ gix_config::source::Kind::System,
+ gix_config::source::Kind::Global,
+ ]
+ .iter()
+ .flat_map(|kind| kind.sources())
+ .filter_map(|source| {
+ match source {
+ gix_config::Source::GitInstallation if !use_installation => return None,
+ gix_config::Source::System if !use_system => return None,
+ gix_config::Source::Git if !use_git => return None,
+ gix_config::Source::User if !use_user => return None,
+ _ => {}
+ }
+ source
+ .storage_location(&mut |name| {
+ match name {
+ git_ if git_.starts_with("GIT_") => Some(git_prefix),
+ "XDG_CONFIG_HOME" => Some(xdg_config_home_env),
+ "HOME" => Some(home_env),
+ _ => None,
+ }
+ .and_then(|perm| perm.check_opt(name).and_then(std::env::var_os))
+ })
+ .map(|p| (source, p.into_owned()))
+ })
+ .map(|(source, path)| gix_config::file::Metadata {
+ path: Some(path),
+ source: *source,
+ level: 0,
+ trust: gix_sec::Trust::Full,
+ });
+
+ let err_on_nonexisting_paths = false;
+ let mut globals = gix_config::File::from_paths_metadata_buf(
+ metas,
+ &mut buf,
+ err_on_nonexisting_paths,
+ gix_config::file::init::Options {
+ includes: gix_config::file::includes::Options::no_follow(),
+ ..options
+ },
+ )
+ .map_err(|err| match err {
+ gix_config::file::init::from_paths::Error::Init(err) => Error::from(err),
+ gix_config::file::init::from_paths::Error::Io(err) => err.into(),
+ })?
+ .unwrap_or_default();
+
+ let local_meta = git_dir_config.meta_owned();
+ globals.append(git_dir_config);
+ globals.resolve_includes(options)?;
+ if use_env {
+ globals.append(gix_config::File::from_env(options)?.unwrap_or_default());
+ }
+ if !cli_config_overrides.is_empty() {
+ config::overrides::append(&mut globals, cli_config_overrides, gix_config::Source::Cli, |_| None)
+ .map_err(|err| Error::ConfigOverrides {
+ err,
+ source: gix_config::Source::Cli,
+ })?;
+ }
+ if !api_config_overrides.is_empty() {
+ config::overrides::append(&mut globals, api_config_overrides, gix_config::Source::Api, |_| None)
+ .map_err(|err| Error::ConfigOverrides {
+ err,
+ source: gix_config::Source::Api,
+ })?;
+ }
+ apply_environment_overrides(&mut globals, *git_prefix, http_transport, identity, objects)?;
+ globals.set_meta(local_meta);
+ globals
+ };
+
+ let hex_len = util::parse_core_abbrev(&config, object_hash).with_leniency(lenient_config)?;
+
+ use util::config_bool;
+ let reflog = util::query_refupdates(&config, lenient_config)?;
+ let ignore_case = config_bool(&config, &Core::IGNORE_CASE, "core.ignoreCase", false, lenient_config)?;
+ let use_multi_pack_index = config_bool(
+ &config,
+ &Core::MULTIPACK_INDEX,
+ "core.multiPackIndex",
+ true,
+ lenient_config,
+ )?;
+ let object_kind_hint = util::disambiguate_hint(&config, lenient_config)?;
+ let (pack_cache_bytes, object_cache_bytes) =
+ util::parse_object_caches(&config, lenient_config, filter_config_section)?;
+ // NOTE: When adding a new initial cache, consider adjusting `reread_values_and_clear_caches()` as well.
+ Ok(Cache {
+ resolved: config.into(),
+ use_multi_pack_index,
+ object_hash,
+ object_kind_hint,
+ pack_cache_bytes,
+ object_cache_bytes,
+ reflog,
+ is_bare,
+ ignore_case,
+ hex_len,
+ filter_config_section,
+ xdg_config_home_env,
+ home_env,
+ lenient_config,
+ user_agent: Default::default(),
+ personas: Default::default(),
+ url_rewrite: Default::default(),
+ diff_renames: Default::default(),
+ #[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
+ url_scheme: Default::default(),
+ diff_algorithm: Default::default(),
+ })
+ }
+
+ /// Call this with new `config` to update values and clear caches. Note that none of the values will be applied if a single
+ /// one is invalid.
+ /// However, those that are lazily read won't be re-evaluated right away and might thus pass now but fail later.
+ ///
+ /// Note that we unconditionally re-read all values.
+ pub fn reread_values_and_clear_caches_replacing_config(&mut self, config: crate::Config) -> Result<(), Error> {
+ let prev = std::mem::replace(&mut self.resolved, config);
+ match self.reread_values_and_clear_caches() {
+ Err(err) => {
+ drop(std::mem::replace(&mut self.resolved, prev));
+ Err(err)
+ }
+ Ok(()) => Ok(()),
+ }
+ }
+
+ /// Similar to `reread_values_and_clear_caches_replacing_config()`, but works on the existing configuration instead of a passed
+ /// in one that it them makes the default.
+ pub fn reread_values_and_clear_caches(&mut self) -> Result<(), Error> {
+ let config = &self.resolved;
+ let hex_len = util::parse_core_abbrev(config, self.object_hash).with_leniency(self.lenient_config)?;
+
+ use util::config_bool;
+ let ignore_case = config_bool(
+ config,
+ &Core::IGNORE_CASE,
+ "core.ignoreCase",
+ false,
+ self.lenient_config,
+ )?;
+ let object_kind_hint = util::disambiguate_hint(config, self.lenient_config)?;
+ let reflog = util::query_refupdates(config, self.lenient_config)?;
+
+ self.hex_len = hex_len;
+ self.ignore_case = ignore_case;
+ self.object_kind_hint = object_kind_hint;
+ self.reflog = reflog;
+
+ self.user_agent = Default::default();
+ self.personas = Default::default();
+ self.url_rewrite = Default::default();
+ self.diff_renames = Default::default();
+ self.diff_algorithm = Default::default();
+ (self.pack_cache_bytes, self.object_cache_bytes) =
+ util::parse_object_caches(config, self.lenient_config, self.filter_config_section)?;
+ #[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
+ {
+ self.url_scheme = Default::default();
+ }
+
+ Ok(())
+ }
+}
+
+impl crate::Repository {
+ /// Replace our own configuration with `config` and re-read all cached values, and apply them to select in-memory instances.
+ pub(crate) fn reread_values_and_clear_caches_replacing_config(
+ &mut self,
+ config: crate::Config,
+ ) -> Result<(), Error> {
+ self.config.reread_values_and_clear_caches_replacing_config(config)?;
+ self.apply_changed_values();
+ Ok(())
+ }
+
+ fn apply_changed_values(&mut self) {
+ self.refs.write_reflog = util::reflog_or_default(self.config.reflog, self.work_dir().is_some());
+ }
+}
+
+fn apply_environment_overrides(
+ config: &mut gix_config::File<'static>,
+ git_prefix: Permission,
+ http_transport: Permission,
+ identity: Permission,
+ objects: Permission,
+) -> Result<(), Error> {
+ fn env(key: &'static dyn config::tree::Key) -> &'static str {
+ key.the_environment_override()
+ }
+ fn var_as_bstring(var: &str, perm: Permission) -> Option<BString> {
+ perm.check_opt(var)
+ .and_then(std::env::var_os)
+ .and_then(|val| gix_path::os_string_into_bstring(val).ok())
+ }
+
+ let mut env_override = gix_config::File::new(gix_config::file::Metadata::from(gix_config::Source::EnvOverride));
+ for (section_name, subsection_name, permission, data) in [
+ (
+ "http",
+ None,
+ http_transport,
+ &[
+ ("GIT_HTTP_LOW_SPEED_LIMIT", "lowSpeedLimit"),
+ ("GIT_HTTP_LOW_SPEED_TIME", "lowSpeedTime"),
+ ("GIT_HTTP_USER_AGENT", "userAgent"),
+ {
+ let key = &Http::SSL_CA_INFO;
+ (env(key), key.name)
+ },
+ {
+ let key = &Http::SSL_VERSION;
+ (env(key), key.name)
+ },
+ ][..],
+ ),
+ (
+ "gitoxide",
+ Some(Cow::Borrowed("https".into())),
+ http_transport,
+ &[
+ ("HTTPS_PROXY", gitoxide::Https::PROXY.name),
+ ("https_proxy", gitoxide::Https::PROXY.name),
+ ],
+ ),
+ (
+ "gitoxide",
+ Some(Cow::Borrowed("http".into())),
+ http_transport,
+ &[
+ ("ALL_PROXY", "allProxy"),
+ {
+ let key = &gitoxide::Http::ALL_PROXY;
+ (env(key), key.name)
+ },
+ ("NO_PROXY", "noProxy"),
+ {
+ let key = &gitoxide::Http::NO_PROXY;
+ (env(key), key.name)
+ },
+ {
+ let key = &gitoxide::Http::PROXY;
+ (env(key), key.name)
+ },
+ {
+ let key = &gitoxide::Http::VERBOSE;
+ (env(key), key.name)
+ },
+ {
+ let key = &gitoxide::Http::PROXY_AUTH_METHOD;
+ (env(key), key.name)
+ },
+ ],
+ ),
+ (
+ "gitoxide",
+ Some(Cow::Borrowed("committer".into())),
+ identity,
+ &[
+ {
+ let key = &gitoxide::Committer::NAME_FALLBACK;
+ (env(key), key.name)
+ },
+ {
+ let key = &gitoxide::Committer::EMAIL_FALLBACK;
+ (env(key), key.name)
+ },
+ ],
+ ),
+ (
+ "gitoxide",
+ Some(Cow::Borrowed("author".into())),
+ identity,
+ &[
+ {
+ let key = &gitoxide::Author::NAME_FALLBACK;
+ (env(key), key.name)
+ },
+ {
+ let key = &gitoxide::Author::EMAIL_FALLBACK;
+ (env(key), key.name)
+ },
+ ],
+ ),
+ (
+ "gitoxide",
+ Some(Cow::Borrowed("commit".into())),
+ git_prefix,
+ &[
+ {
+ let key = &gitoxide::Commit::COMMITTER_DATE;
+ (env(key), key.name)
+ },
+ {
+ let key = &gitoxide::Commit::AUTHOR_DATE;
+ (env(key), key.name)
+ },
+ ],
+ ),
+ (
+ "gitoxide",
+ Some(Cow::Borrowed("allow".into())),
+ http_transport,
+ &[("GIT_PROTOCOL_FROM_USER", "protocolFromUser")],
+ ),
+ (
+ "gitoxide",
+ Some(Cow::Borrowed("user".into())),
+ identity,
+ &[{
+ let key = &gitoxide::User::EMAIL_FALLBACK;
+ (env(key), key.name)
+ }],
+ ),
+ (
+ "gitoxide",
+ Some(Cow::Borrowed("objects".into())),
+ objects,
+ &[
+ {
+ let key = &gitoxide::Objects::NO_REPLACE;
+ (env(key), key.name)
+ },
+ {
+ let key = &gitoxide::Objects::REPLACE_REF_BASE;
+ (env(key), key.name)
+ },
+ {
+ let key = &gitoxide::Objects::CACHE_LIMIT;
+ (env(key), key.name)
+ },
+ ],
+ ),
+ (
+ "gitoxide",
+ Some(Cow::Borrowed("ssh".into())),
+ git_prefix,
+ &[{
+ let key = &gitoxide::Ssh::COMMAND_WITHOUT_SHELL_FALLBACK;
+ (env(key), key.name)
+ }],
+ ),
+ (
+ "ssh",
+ None,
+ git_prefix,
+ &[{
+ let key = &config::tree::Ssh::VARIANT;
+ (env(key), key.name)
+ }],
+ ),
+ ] {
+ let mut section = env_override
+ .new_section(section_name, subsection_name)
+ .expect("statically known valid section name");
+ for (var, key) in data {
+ if let Some(value) = var_as_bstring(var, permission) {
+ section.push_with_comment(
+ (*key).try_into().expect("statically known to be valid"),
+ Some(value.as_ref()),
+ format!("from {var}").as_str(),
+ );
+ }
+ }
+ if section.num_values() == 0 {
+ let id = section.id();
+ env_override.remove_section_by_id(id);
+ }
+ }
+
+ {
+ let mut section = env_override
+ .new_section("core", None)
+ .expect("statically known valid section name");
+
+ for (var, key, permission) in [
+ {
+ let key = &Core::DELTA_BASE_CACHE_LIMIT;
+ (env(key), key.name, objects)
+ },
+ {
+ let key = &Core::SSH_COMMAND;
+ (env(key), key.name, git_prefix)
+ },
+ ] {
+ if let Some(value) = var_as_bstring(var, permission) {
+ section.push_with_comment(
+ key.try_into().expect("statically known to be valid"),
+ Some(value.as_ref()),
+ format!("from {var}").as_str(),
+ );
+ }
+ }
+
+ if section.num_values() == 0 {
+ let id = section.id();
+ env_override.remove_section_by_id(id);
+ }
+ }
+
+ if !env_override.is_void() {
+ config.append(env_override);
+ }
+ Ok(())
+}
diff --git a/vendor/gix/src/config/cache/mod.rs b/vendor/gix/src/config/cache/mod.rs
new file mode 100644
index 000000000..1904c5ea9
--- /dev/null
+++ b/vendor/gix/src/config/cache/mod.rs
@@ -0,0 +1,18 @@
+use super::{Cache, Error};
+
+mod incubate;
+pub(crate) use incubate::StageOne;
+
+mod init;
+
+impl std::fmt::Debug for Cache {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("Cache").finish_non_exhaustive()
+ }
+}
+
+mod access;
+
+pub(crate) mod util;
+
+pub(crate) use util::interpolate_context;
diff --git a/vendor/gix/src/config/cache/util.rs b/vendor/gix/src/config/cache/util.rs
new file mode 100644
index 000000000..c12f850e6
--- /dev/null
+++ b/vendor/gix/src/config/cache/util.rs
@@ -0,0 +1,143 @@
+#![allow(clippy::result_large_err)]
+use super::Error;
+use crate::{
+ config,
+ config::tree::{gitoxide, Core},
+ revision::spec::parse::ObjectKindHint,
+};
+
+pub(crate) fn interpolate_context<'a>(
+ git_install_dir: Option<&'a std::path::Path>,
+ home_dir: Option<&'a std::path::Path>,
+) -> gix_config::path::interpolate::Context<'a> {
+ gix_config::path::interpolate::Context {
+ git_install_dir,
+ home_dir,
+ home_for_user: Some(gix_config::path::interpolate::home_for_user), // TODO: figure out how to configure this
+ }
+}
+
+pub(crate) fn base_options(lossy: Option<bool>) -> gix_config::file::init::Options<'static> {
+ gix_config::file::init::Options {
+ lossy: lossy.unwrap_or(!cfg!(debug_assertions)),
+ ..Default::default()
+ }
+}
+
+pub(crate) fn config_bool(
+ config: &gix_config::File<'_>,
+ key: &'static config::tree::keys::Boolean,
+ key_str: &str,
+ default: bool,
+ lenient: bool,
+) -> Result<bool, Error> {
+ use config::tree::Key;
+ debug_assert_eq!(
+ key_str,
+ key.logical_name(),
+ "BUG: key name and hardcoded name must match"
+ );
+ config
+ .boolean_by_key(key_str)
+ .map(|res| key.enrich_error(res))
+ .unwrap_or(Ok(default))
+ .map_err(Error::from)
+ .with_lenient_default(lenient)
+}
+
+pub(crate) fn query_refupdates(
+ config: &gix_config::File<'static>,
+ lenient_config: bool,
+) -> Result<Option<gix_ref::store::WriteReflog>, Error> {
+ let key = "core.logAllRefUpdates";
+ Core::LOG_ALL_REF_UPDATES
+ .try_into_ref_updates(config.boolean_by_key(key), || config.string_by_key(key))
+ .with_leniency(lenient_config)
+ .map_err(Into::into)
+}
+
+pub(crate) fn reflog_or_default(
+ config_reflog: Option<gix_ref::store::WriteReflog>,
+ has_worktree: bool,
+) -> gix_ref::store::WriteReflog {
+ config_reflog.unwrap_or(if has_worktree {
+ gix_ref::store::WriteReflog::Normal
+ } else {
+ gix_ref::store::WriteReflog::Disable
+ })
+}
+
+/// Return `(pack_cache_bytes, object_cache_bytes)` as parsed from gix-config
+pub(crate) fn parse_object_caches(
+ config: &gix_config::File<'static>,
+ lenient: bool,
+ mut filter_config_section: fn(&gix_config::file::Metadata) -> bool,
+) -> Result<(Option<usize>, usize), Error> {
+ let pack_cache_bytes = config
+ .integer_filter_by_key("core.deltaBaseCacheLimit", &mut filter_config_section)
+ .map(|res| Core::DELTA_BASE_CACHE_LIMIT.try_into_usize(res))
+ .transpose()
+ .with_leniency(lenient)?;
+ let object_cache_bytes = config
+ .integer_filter_by_key("gitoxide.objects.cacheLimit", &mut filter_config_section)
+ .map(|res| gitoxide::Objects::CACHE_LIMIT.try_into_usize(res))
+ .transpose()
+ .with_leniency(lenient)?
+ .unwrap_or_default();
+ Ok((pack_cache_bytes, object_cache_bytes))
+}
+
+pub(crate) fn parse_core_abbrev(
+ config: &gix_config::File<'static>,
+ object_hash: gix_hash::Kind,
+) -> Result<Option<usize>, Error> {
+ Ok(config
+ .string_by_key("core.abbrev")
+ .map(|abbrev| Core::ABBREV.try_into_abbreviation(abbrev, object_hash))
+ .transpose()?
+ .flatten())
+}
+
+pub(crate) fn disambiguate_hint(
+ config: &gix_config::File<'static>,
+ lenient_config: bool,
+) -> Result<Option<ObjectKindHint>, config::key::GenericErrorWithValue> {
+ match config.string_by_key("core.disambiguate") {
+ None => Ok(None),
+ Some(value) => Core::DISAMBIGUATE
+ .try_into_object_kind_hint(value)
+ .with_leniency(lenient_config),
+ }
+}
+
+// TODO: Use a specialization here once trait specialization is stabilized. Would be perfect here for `T: Default`.
+pub trait ApplyLeniency {
+ fn with_leniency(self, is_lenient: bool) -> Self;
+}
+
+pub trait ApplyLeniencyDefault {
+ fn with_lenient_default(self, is_lenient: bool) -> Self;
+}
+
+impl<T, E> ApplyLeniency for Result<Option<T>, E> {
+ fn with_leniency(self, is_lenient: bool) -> Self {
+ match self {
+ Ok(v) => Ok(v),
+ Err(_) if is_lenient => Ok(None),
+ Err(err) => Err(err),
+ }
+ }
+}
+
+impl<T, E> ApplyLeniencyDefault for Result<T, E>
+where
+ T: Default,
+{
+ fn with_lenient_default(self, is_lenient: bool) -> Self {
+ match self {
+ Ok(v) => Ok(v),
+ Err(_) if is_lenient => Ok(T::default()),
+ Err(err) => Err(err),
+ }
+ }
+}
diff --git a/vendor/gix/src/config/mod.rs b/vendor/gix/src/config/mod.rs
new file mode 100644
index 000000000..1e2566777
--- /dev/null
+++ b/vendor/gix/src/config/mod.rs
@@ -0,0 +1,454 @@
+pub use gix_config::*;
+use gix_features::threading::OnceCell;
+
+use crate::{bstr::BString, repository::identity, revision::spec, Repository};
+
+pub(crate) mod cache;
+mod snapshot;
+pub use snapshot::credential_helpers;
+
+///
+pub mod overrides;
+
+pub mod tree;
+pub use tree::root::Tree;
+
+/// A platform to access configuration values as read from disk.
+///
+/// Note that these values won't update even if the underlying file(s) change.
+pub struct Snapshot<'repo> {
+ pub(crate) repo: &'repo Repository,
+}
+
+/// A platform to access configuration values and modify them in memory, while making them available when this platform is dropped
+/// as form of auto-commit.
+/// Note that the values will only affect this instance of the parent repository, and not other clones that may exist.
+///
+/// Note that these values won't update even if the underlying file(s) change.
+///
+/// Use [`forget()`][Self::forget()] to not apply any of the changes.
+// TODO: make it possible to load snapshots with reloading via .config() and write mutated snapshots back to disk which should be the way
+// to affect all instances of a repo, probably via `config_mut()` and `config_mut_at()`.
+pub struct SnapshotMut<'repo> {
+ pub(crate) repo: Option<&'repo mut Repository>,
+ pub(crate) config: gix_config::File<'static>,
+}
+
+/// A utility structure created by [`SnapshotMut::commit_auto_rollback()`] that restores the previous configuration on drop.
+pub struct CommitAutoRollback<'repo> {
+ pub(crate) repo: Option<&'repo mut Repository>,
+ pub(crate) prev_config: crate::Config,
+}
+
+pub(crate) mod section {
+ pub fn is_trusted(meta: &gix_config::file::Metadata) -> bool {
+ meta.trust == gix_sec::Trust::Full || meta.source.kind() != gix_config::source::Kind::Repository
+ }
+}
+
+/// The error returned when failing to initialize the repository configuration.
+///
+/// This configuration is on the critical path when opening a repository.
+#[derive(Debug, thiserror::Error)]
+#[allow(missing_docs)]
+pub enum Error {
+ #[error(transparent)]
+ ConfigBoolean(#[from] boolean::Error),
+ #[error(transparent)]
+ ConfigUnsigned(#[from] unsigned_integer::Error),
+ #[error(transparent)]
+ ConfigTypedString(#[from] key::GenericErrorWithValue),
+ #[error("Cannot handle objects formatted as {:?}", .name)]
+ UnsupportedObjectFormat { name: BString },
+ #[error(transparent)]
+ CoreAbbrev(#[from] abbrev::Error),
+ #[error("Could not read configuration file")]
+ Io(#[from] std::io::Error),
+ #[error(transparent)]
+ Init(#[from] gix_config::file::init::Error),
+ #[error(transparent)]
+ ResolveIncludes(#[from] gix_config::file::includes::Error),
+ #[error(transparent)]
+ FromEnv(#[from] gix_config::file::init::from_env::Error),
+ #[error(transparent)]
+ PathInterpolation(#[from] gix_config::path::interpolate::Error),
+ #[error("{source:?} configuration overrides at open or init time could not be applied.")]
+ ConfigOverrides {
+ #[source]
+ err: overrides::Error,
+ source: gix_config::Source,
+ },
+}
+
+///
+pub mod diff {
+ ///
+ pub mod algorithm {
+ use crate::bstr::BString;
+
+ /// The error produced when obtaining `diff.algorithm`.
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("Unknown diff algorithm named '{name}'")]
+ Unknown { name: BString },
+ #[error("The '{name}' algorithm is not yet implemented")]
+ Unimplemented { name: BString },
+ }
+ }
+}
+
+///
+pub mod checkout_options {
+ /// The error produced when collecting all information needed for checking out files into a worktree.
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error(transparent)]
+ ConfigCheckStat(#[from] super::key::GenericErrorWithValue),
+ #[error(transparent)]
+ ConfigBoolean(#[from] super::boolean::Error),
+ #[error(transparent)]
+ CheckoutWorkers(#[from] super::checkout::workers::Error),
+ #[error("Failed to interpolate the attribute file configured at `core.attributesFile`")]
+ AttributesFileInterpolation(#[from] gix_config::path::interpolate::Error),
+ }
+}
+
+///
+pub mod protocol {
+ ///
+ pub mod allow {
+ use crate::bstr::BString;
+
+ /// The error returned when obtaining the permission for a particular scheme.
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ #[error("The value {value:?} must be allow|deny|user in configuration key protocol{0}.allow", scheme.as_ref().map(|s| format!(".{s}")).unwrap_or_default())]
+ pub struct Error {
+ pub scheme: Option<String>,
+ pub value: BString,
+ }
+ }
+}
+
+///
+pub mod ssh_connect_options {
+ /// The error produced when obtaining ssh connection configuration.
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ #[error(transparent)]
+ pub struct Error(#[from] super::key::GenericErrorWithValue);
+}
+
+///
+pub mod key {
+ use crate::bstr::BString;
+
+ const fn prefix(kind: char) -> &'static str {
+ match kind {
+ 'n' => "", // nothing
+ 'k' => "The value of key", // generic key
+ 't' => "The date format at key", // time
+ 'i' => "The timeout at key", // timeout
+ 'd' => "The duration [ms] at key", // duration
+ 'b' => "The boolean at key", // boolean
+ 'v' => "The key", // generic key with value
+ 'r' => "The refspec at", // refspec
+ 's' => "The ssl version at", // ssl-version
+ 'u' => "The url at", // url
+ 'w' => "The utf-8 string at", // string
+ _ => panic!("BUG: invalid prefix kind - add a case for it here"),
+ }
+ }
+ const fn suffix(kind: char) -> &'static str {
+ match kind {
+ 'd' => "could not be decoded", // decoding
+ 'i' => "was invalid", // invalid
+ 'u' => "could not be parsed as unsigned integer", // unsigned integer
+ 'p' => "could not be parsed", // parsing
+ _ => panic!("BUG: invalid suffix kind - add a case for it here"),
+ }
+ }
+ /// A generic error suitable to produce decent messages for all kinds of configuration errors with config-key granularity.
+ ///
+ /// This error is meant to be reusable and help produce uniform error messages related to parsing any configuration key.
+ #[derive(Debug, thiserror::Error)]
+ #[error("{} \"{key}{}\"{} {}", prefix(PREFIX), value.as_ref().map(|v| format!("={v}")).unwrap_or_default(), environment_override.as_deref().map(|var| format!(" (possibly from {var})")).unwrap_or_default(), suffix(SUFFIX))]
+ pub struct Error<E: std::error::Error + Send + Sync + 'static, const PREFIX: char, const SUFFIX: char> {
+ /// The configuration key that contained the value.
+ pub key: BString,
+ /// The value that was assigned to `key`.
+ pub value: Option<BString>,
+ /// The associated environment variable that would override this value.
+ pub environment_override: Option<&'static str>,
+ /// The source of the error if there was one.
+ pub source: Option<E>,
+ }
+
+ /// Initialization
+ /// Instantiate a new error from the given `key`.
+ ///
+ /// Note that specifics of the error message are defined by the `PREFIX` and `SUFFIX` which is usually defined by a typedef.
+ impl<T, E, const PREFIX: char, const SUFFIX: char> From<&'static T> for Error<E, PREFIX, SUFFIX>
+ where
+ E: std::error::Error + Send + Sync + 'static,
+ T: super::tree::Key,
+ {
+ fn from(key: &'static T) -> Self {
+ Error {
+ key: key.logical_name().into(),
+ value: None,
+ environment_override: key.environment_override(),
+ source: None,
+ }
+ }
+ }
+
+ /// Initialization
+ impl<E, const PREFIX: char, const SUFFIX: char> Error<E, PREFIX, SUFFIX>
+ where
+ E: std::error::Error + Send + Sync + 'static,
+ {
+ /// Instantiate an error with all data from `key` along with the `value` of the key.
+ pub fn from_value(key: &'static impl super::tree::Key, value: BString) -> Self {
+ Error::from(key).with_value(value)
+ }
+ }
+
+ /// Builder
+ impl<E, const PREFIX: char, const SUFFIX: char> Error<E, PREFIX, SUFFIX>
+ where
+ E: std::error::Error + Send + Sync + 'static,
+ {
+ /// Attach the given `err` as source.
+ pub fn with_source(mut self, err: E) -> Self {
+ self.source = Some(err);
+ self
+ }
+
+ /// Attach the given `value` as value we observed when the error was produced.
+ pub fn with_value(mut self, value: BString) -> Self {
+ self.value = Some(value);
+ self
+ }
+ }
+
+ /// A generic key error for use when it doesn't seem worth it say more than 'key is invalid' along with meta-data.
+ pub type GenericError<E = gix_config::value::Error> = Error<E, 'k', 'i'>;
+
+ /// A generic key error which will also contain a value.
+ pub type GenericErrorWithValue<E = gix_config::value::Error> = Error<E, 'v', 'i'>;
+}
+
+///
+pub mod checkout {
+ ///
+ pub mod workers {
+ use crate::config;
+
+ /// The error produced when failing to parse the the `checkout.workers` key.
+ pub type Error = config::key::Error<gix_config::value::Error, 'n', 'd'>;
+ }
+}
+
+///
+pub mod abbrev {
+ use crate::bstr::BString;
+
+ /// The error describing an incorrect `core.abbrev` value.
+ #[derive(Debug, thiserror::Error)]
+ #[error("Invalid value for 'core.abbrev' = '{}'. It must be between 4 and {}", .value, .max)]
+ pub struct Error {
+ /// The value found in the git configuration
+ pub value: BString,
+ /// The maximum abbreviation length, the length of an object hash.
+ pub max: u8,
+ }
+}
+
+///
+pub mod remote {
+ ///
+ pub mod symbolic_name {
+ /// The error produced when failing to produce a symbolic remote name from configuration.
+ pub type Error = super::super::key::Error<crate::remote::name::Error, 'v', 'i'>;
+ }
+}
+
+///
+pub mod time {
+ /// The error produced when failing to parse time from configuration.
+ pub type Error = super::key::Error<gix_date::parse::Error, 't', 'i'>;
+}
+
+///
+pub mod lock_timeout {
+ /// The error produced when failing to parse timeout for locks.
+ pub type Error = super::key::Error<gix_config::value::Error, 'i', 'i'>;
+}
+
+///
+pub mod duration {
+ /// The error produced when failing to parse durations (in milliseconds).
+ pub type Error = super::key::Error<gix_config::value::Error, 'd', 'i'>;
+}
+
+///
+pub mod boolean {
+ /// The error produced when failing to parse time from configuration.
+ pub type Error = super::key::Error<gix_config::value::Error, 'b', 'i'>;
+}
+
+///
+pub mod unsigned_integer {
+ /// The error produced when failing to parse a signed integer from configuration.
+ pub type Error = super::key::Error<gix_config::value::Error, 'k', 'u'>;
+}
+
+///
+pub mod url {
+ /// The error produced when failing to parse a url from the configuration.
+ pub type Error = super::key::Error<gix_url::parse::Error, 'u', 'p'>;
+}
+
+///
+pub mod string {
+ /// The error produced when failing to interpret configuration as UTF-8 encoded string.
+ pub type Error = super::key::Error<crate::bstr::Utf8Error, 'w', 'd'>;
+}
+
+///
+pub mod refspec {
+ /// The error produced when failing to parse a refspec from the configuration.
+ pub type Error = super::key::Error<gix_refspec::parse::Error, 'r', 'p'>;
+}
+
+///
+pub mod ssl_version {
+ /// The error produced when failing to parse a refspec from the configuration.
+ pub type Error = super::key::Error<std::convert::Infallible, 's', 'i'>;
+}
+
+///
+pub mod transport {
+ use std::borrow::Cow;
+
+ use crate::bstr::BStr;
+
+ /// The error produced when configuring a transport for a particular protocol.
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error(
+ "Could not interpret configuration key {key:?} as {kind} integer of desired range with value: {actual}"
+ )]
+ InvalidInteger {
+ key: &'static str,
+ kind: &'static str,
+ actual: i64,
+ },
+ #[error("Could not interpret configuration key {key:?}")]
+ ConfigValue {
+ source: gix_config::value::Error,
+ key: &'static str,
+ },
+ #[error("Could not interpolate path at key {key:?}")]
+ InterpolatePath {
+ source: gix_config::path::interpolate::Error,
+ key: &'static str,
+ },
+ #[error("Could not decode value at key {key:?} as UTF-8 string")]
+ IllformedUtf8 {
+ key: Cow<'static, BStr>,
+ source: crate::config::string::Error,
+ },
+ #[error("Invalid URL passed for configuration")]
+ ParseUrl(#[from] gix_url::parse::Error),
+ #[error("Could obtain configuration for an HTTP url")]
+ Http(#[from] http::Error),
+ }
+
+ ///
+ pub mod http {
+ use std::borrow::Cow;
+
+ use crate::bstr::BStr;
+
+ /// The error produced when configuring a HTTP transport.
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error(transparent)]
+ Boolean(#[from] crate::config::boolean::Error),
+ #[error(transparent)]
+ UnsignedInteger(#[from] crate::config::unsigned_integer::Error),
+ #[error(transparent)]
+ ConnectTimeout(#[from] crate::config::duration::Error),
+ #[error("The proxy authentication at key `{key}` is invalid")]
+ InvalidProxyAuthMethod {
+ source: crate::config::key::GenericErrorWithValue,
+ key: Cow<'static, BStr>,
+ },
+ #[error("Could not configure the credential helpers for the authenticated proxy url")]
+ ConfigureProxyAuthenticate(#[from] crate::config::snapshot::credential_helpers::Error),
+ #[error(transparent)]
+ InvalidSslVersion(#[from] crate::config::ssl_version::Error),
+ #[error("The HTTP version must be 'HTTP/2' or 'HTTP/1.1'")]
+ InvalidHttpVersion(#[from] crate::config::key::GenericErrorWithValue),
+ #[error("The follow redirects value 'initial', or boolean true or false")]
+ InvalidFollowRedirects(#[source] crate::config::key::GenericErrorWithValue),
+ }
+ }
+}
+
+/// Utility type to keep pre-obtained configuration values, only for those required during initial setup
+/// and other basic operations that are common enough to warrant a permanent cache.
+///
+/// All other values are obtained lazily using OnceCell.
+#[derive(Clone)]
+pub(crate) struct Cache {
+ pub resolved: crate::Config,
+ /// The hex-length to assume when shortening object ids. If `None`, it should be computed based on the approximate object count.
+ pub hex_len: Option<usize>,
+ /// true if the repository is designated as 'bare', without work tree.
+ pub is_bare: bool,
+ /// The type of hash to use.
+ pub object_hash: gix_hash::Kind,
+ /// If true, multi-pack indices, whether present or not, may be used by the object database.
+ pub use_multi_pack_index: bool,
+ /// The representation of `core.logallrefupdates`, or `None` if the variable wasn't set.
+ pub reflog: Option<gix_ref::store::WriteReflog>,
+ /// The configured user agent for presentation to servers.
+ pub(crate) user_agent: OnceCell<String>,
+ /// identities for later use, lazy initialization.
+ pub(crate) personas: OnceCell<identity::Personas>,
+ /// A lazily loaded rewrite list for remote urls
+ pub(crate) url_rewrite: OnceCell<crate::remote::url::Rewrite>,
+ /// The lazy-loaded rename information for diffs.
+ pub(crate) diff_renames: OnceCell<Option<crate::object::tree::diff::Rewrites>>,
+ /// A lazily loaded mapping to know which url schemes to allow
+ #[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
+ pub(crate) url_scheme: OnceCell<crate::remote::url::SchemePermission>,
+ /// The algorithm to use when diffing blobs
+ pub(crate) diff_algorithm: OnceCell<gix_diff::blob::Algorithm>,
+ /// The amount of bytes to use for a memory backed delta pack cache. If `Some(0)`, no cache is used, if `None`
+ /// a standard cache is used which costs near to nothing and always pays for itself.
+ pub(crate) pack_cache_bytes: Option<usize>,
+ /// The amount of bytes to use for caching whole objects, or 0 to turn it off entirely.
+ pub(crate) object_cache_bytes: usize,
+ /// The config section filter from the options used to initialize this instance. Keep these in sync!
+ filter_config_section: fn(&gix_config::file::Metadata) -> bool,
+ /// The object kind to pick if a prefix is ambiguous.
+ pub object_kind_hint: Option<spec::parse::ObjectKindHint>,
+ /// If true, we are on a case-insensitive file system.
+ pub ignore_case: bool,
+ /// If true, we should default what's possible if something is misconfigured, on case by case basis, to be more resilient.
+ /// Also available in options! Keep in sync!
+ pub lenient_config: bool,
+ /// Define how we can use values obtained with `xdg_config(…)` and its `XDG_CONFIG_HOME` variable.
+ xdg_config_home_env: gix_sec::Permission,
+ /// Define how we can use values obtained with `xdg_config(…)`. and its `HOME` variable.
+ home_env: gix_sec::Permission,
+ // TODO: make core.precomposeUnicode available as well.
+}
diff --git a/vendor/gix/src/config/overrides.rs b/vendor/gix/src/config/overrides.rs
new file mode 100644
index 000000000..f43e8471b
--- /dev/null
+++ b/vendor/gix/src/config/overrides.rs
@@ -0,0 +1,49 @@
+use std::convert::TryFrom;
+
+use crate::bstr::{BStr, BString, ByteSlice};
+
+/// The error returned by [SnapshotMut::apply_cli_overrides()][crate::config::SnapshotMut::append_config()].
+#[derive(Debug, thiserror::Error)]
+#[allow(missing_docs)]
+pub enum Error {
+ #[error("{input:?} is not a valid configuration key. Examples are 'core.abbrev' or 'remote.origin.url'")]
+ InvalidKey { input: BString },
+ #[error("Key {key:?} could not be parsed")]
+ SectionKey {
+ key: BString,
+ source: gix_config::parse::section::key::Error,
+ },
+ #[error(transparent)]
+ SectionHeader(#[from] gix_config::parse::section::header::Error),
+}
+
+pub(crate) fn append(
+ config: &mut gix_config::File<'static>,
+ values: impl IntoIterator<Item = impl AsRef<BStr>>,
+ source: gix_config::Source,
+ mut make_comment: impl FnMut(&BStr) -> Option<BString>,
+) -> Result<(), Error> {
+ let mut file = gix_config::File::new(gix_config::file::Metadata::from(source));
+ for key_value in values {
+ let key_value = key_value.as_ref();
+ let mut tokens = key_value.splitn(2, |b| *b == b'=').map(|v| v.trim());
+ let key = tokens.next().expect("always one value").as_bstr();
+ let value = tokens.next();
+ let key = gix_config::parse::key(key.to_str().map_err(|_| Error::InvalidKey { input: key.into() })?)
+ .ok_or_else(|| Error::InvalidKey { input: key.into() })?;
+ let mut section = file.section_mut_or_create_new(key.section_name, key.subsection_name)?;
+ let key =
+ gix_config::parse::section::Key::try_from(key.value_name.to_owned()).map_err(|err| Error::SectionKey {
+ source: err,
+ key: key.value_name.into(),
+ })?;
+ let comment = make_comment(key_value);
+ let value = value.map(|v| v.as_bstr());
+ match comment {
+ Some(comment) => section.push_with_comment(key, value, &**comment),
+ None => section.push(key, value),
+ };
+ }
+ config.append(file);
+ Ok(())
+}
diff --git a/vendor/gix/src/config/snapshot/_impls.rs b/vendor/gix/src/config/snapshot/_impls.rs
new file mode 100644
index 000000000..ec22cb640
--- /dev/null
+++ b/vendor/gix/src/config/snapshot/_impls.rs
@@ -0,0 +1,76 @@
+use std::{
+ fmt::{Debug, Formatter},
+ ops::{Deref, DerefMut},
+};
+
+use crate::config::{CommitAutoRollback, Snapshot, SnapshotMut};
+
+impl Debug for Snapshot<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&self.repo.config.resolved.to_string())
+ }
+}
+
+impl Debug for CommitAutoRollback<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&self.repo.as_ref().expect("still present").config.resolved.to_string())
+ }
+}
+
+impl Debug for SnapshotMut<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&self.config.to_string())
+ }
+}
+
+impl Drop for SnapshotMut<'_> {
+ fn drop(&mut self) {
+ if let Some(repo) = self.repo.take() {
+ self.commit_inner(repo).ok();
+ };
+ }
+}
+
+impl Drop for CommitAutoRollback<'_> {
+ fn drop(&mut self) {
+ if let Some(repo) = self.repo.take() {
+ self.rollback_inner(repo).ok();
+ }
+ }
+}
+
+impl Deref for SnapshotMut<'_> {
+ type Target = gix_config::File<'static>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.config
+ }
+}
+
+impl Deref for Snapshot<'_> {
+ type Target = gix_config::File<'static>;
+
+ fn deref(&self) -> &Self::Target {
+ self.plumbing()
+ }
+}
+
+impl Deref for CommitAutoRollback<'_> {
+ type Target = crate::Repository;
+
+ fn deref(&self) -> &Self::Target {
+ self.repo.as_ref().expect("always present")
+ }
+}
+
+impl DerefMut for CommitAutoRollback<'_> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.repo.as_mut().expect("always present")
+ }
+}
+
+impl DerefMut for SnapshotMut<'_> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.config
+ }
+}
diff --git a/vendor/gix/src/config/snapshot/access.rs b/vendor/gix/src/config/snapshot/access.rs
new file mode 100644
index 000000000..1710348a9
--- /dev/null
+++ b/vendor/gix/src/config/snapshot/access.rs
@@ -0,0 +1,143 @@
+#![allow(clippy::result_large_err)]
+use std::borrow::Cow;
+
+use gix_features::threading::OwnShared;
+
+use crate::{
+ bstr::BStr,
+ config::{CommitAutoRollback, Snapshot, SnapshotMut},
+};
+
+/// Access configuration values, frozen in time, using a `key` which is a `.` separated string of up to
+/// three tokens, namely `section_name.[subsection_name.]value_name`, like `core.bare` or `remote.origin.url`.
+///
+/// Note that single-value methods always return the last value found, which is the one set most recently in the
+/// hierarchy of configuration files, aka 'last one wins'.
+impl<'repo> Snapshot<'repo> {
+ /// Return the boolean at `key`, or `None` if there is no such value or if the value can't be interpreted as
+ /// boolean.
+ ///
+ /// For a non-degenerating version, use [`try_boolean(…)`][Self::try_boolean()].
+ ///
+ /// Note that this method takes the most recent value at `key` even if it is from a file with reduced trust.
+ pub fn boolean<'a>(&self, key: impl Into<&'a BStr>) -> Option<bool> {
+ self.try_boolean(key).and_then(Result::ok)
+ }
+
+ /// Like [`boolean()`][Self::boolean()], but it will report an error if the value couldn't be interpreted as boolean.
+ pub fn try_boolean<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<bool, gix_config::value::Error>> {
+ self.repo.config.resolved.boolean_by_key(key)
+ }
+
+ /// Return the resolved integer at `key`, or `None` if there is no such value or if the value can't be interpreted as
+ /// integer or exceeded the value range.
+ ///
+ /// For a non-degenerating version, use [`try_integer(…)`][Self::try_integer()].
+ ///
+ /// Note that this method takes the most recent value at `key` even if it is from a file with reduced trust.
+ pub fn integer<'a>(&self, key: impl Into<&'a BStr>) -> Option<i64> {
+ self.try_integer(key).and_then(Result::ok)
+ }
+
+ /// Like [`integer()`][Self::integer()], but it will report an error if the value couldn't be interpreted as boolean.
+ pub fn try_integer<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<i64, gix_config::value::Error>> {
+ self.repo.config.resolved.integer_by_key(key)
+ }
+
+ /// Return the string at `key`, or `None` if there is no such value.
+ ///
+ /// Note that this method takes the most recent value at `key` even if it is from a file with reduced trust.
+ pub fn string<'a>(&self, key: impl Into<&'a BStr>) -> Option<Cow<'_, BStr>> {
+ self.repo.config.resolved.string_by_key(key)
+ }
+
+ /// Return the trusted and fully interpolated path at `key`, or `None` if there is no such value
+ /// or if no value was found in a trusted file.
+ /// An error occurs if the path could not be interpolated to its final value.
+ pub fn trusted_path<'a>(
+ &self,
+ key: impl Into<&'a BStr>,
+ ) -> Option<Result<Cow<'_, std::path::Path>, gix_config::path::interpolate::Error>> {
+ let key = gix_config::parse::key(key)?;
+ self.repo
+ .config
+ .trusted_file_path(key.section_name, key.subsection_name, key.value_name)
+ }
+}
+
+/// Utilities and additional access
+impl<'repo> Snapshot<'repo> {
+ /// Returns the underlying configuration implementation for a complete API, despite being a little less convenient.
+ ///
+ /// It's expected that more functionality will move up depending on demand.
+ pub fn plumbing(&self) -> &gix_config::File<'static> {
+ &self.repo.config.resolved
+ }
+}
+
+/// Utilities
+impl<'repo> SnapshotMut<'repo> {
+ /// Append configuration values of the form `core.abbrev=5` or `remote.origin.url = foo` or `core.bool-implicit-true`
+ /// to the end of the repository configuration, with each section marked with the given `source`.
+ ///
+ /// Note that doing so applies the configuration at the very end, so it will always override what came before it
+ /// even though the `source` is of lower priority as what's there.
+ pub fn append_config(
+ &mut self,
+ values: impl IntoIterator<Item = impl AsRef<BStr>>,
+ source: gix_config::Source,
+ ) -> Result<&mut Self, crate::config::overrides::Error> {
+ crate::config::overrides::append(&mut self.config, values, source, |v| Some(format!("-c {v}").into()))?;
+ Ok(self)
+ }
+ /// Apply all changes made to this instance.
+ ///
+ /// Note that this would also happen once this instance is dropped, but using this method may be more intuitive and won't squelch errors
+ /// in case the new configuration is partially invalid.
+ pub fn commit(mut self) -> Result<&'repo mut crate::Repository, crate::config::Error> {
+ let repo = self.repo.take().expect("always present here");
+ self.commit_inner(repo)
+ }
+
+ pub(crate) fn commit_inner(
+ &mut self,
+ repo: &'repo mut crate::Repository,
+ ) -> Result<&'repo mut crate::Repository, crate::config::Error> {
+ repo.reread_values_and_clear_caches_replacing_config(std::mem::take(&mut self.config).into())?;
+ Ok(repo)
+ }
+
+ /// Create a structure the temporarily commits the changes, but rolls them back when dropped.
+ pub fn commit_auto_rollback(mut self) -> Result<CommitAutoRollback<'repo>, crate::config::Error> {
+ let repo = self.repo.take().expect("this only runs once on consumption");
+ let prev_config = OwnShared::clone(&repo.config.resolved);
+
+ Ok(CommitAutoRollback {
+ repo: self.commit_inner(repo)?.into(),
+ prev_config,
+ })
+ }
+
+ /// Don't apply any of the changes after consuming this instance, effectively forgetting them, returning the changed configuration.
+ pub fn forget(mut self) -> gix_config::File<'static> {
+ self.repo.take();
+ std::mem::take(&mut self.config)
+ }
+}
+
+/// Utilities
+impl<'repo> CommitAutoRollback<'repo> {
+ /// Rollback the changes previously applied and all values before the change.
+ pub fn rollback(mut self) -> Result<&'repo mut crate::Repository, crate::config::Error> {
+ let repo = self.repo.take().expect("still present, consumed only once");
+ self.rollback_inner(repo)
+ }
+
+ pub(crate) fn rollback_inner(
+ &mut self,
+ repo: &'repo mut crate::Repository,
+ ) -> Result<&'repo mut crate::Repository, crate::config::Error> {
+ repo.reread_values_and_clear_caches_replacing_config(OwnShared::clone(&self.prev_config))?;
+ Ok(repo)
+ }
+}
diff --git a/vendor/gix/src/config/snapshot/credential_helpers.rs b/vendor/gix/src/config/snapshot/credential_helpers.rs
new file mode 100644
index 000000000..5a07e9fe2
--- /dev/null
+++ b/vendor/gix/src/config/snapshot/credential_helpers.rs
@@ -0,0 +1,183 @@
+use std::{borrow::Cow, convert::TryFrom};
+
+pub use error::Error;
+
+use crate::{
+ bstr::{ByteSlice, ByteVec},
+ config::{
+ tree::{credential, Core, Credential, Key},
+ Snapshot,
+ },
+};
+
+mod error {
+ use crate::bstr::BString;
+
+ /// The error returned by [Snapshot::credential_helpers()][super::Snapshot::credential_helpers()].
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("Could not parse 'useHttpPath' key in section {section}")]
+ InvalidUseHttpPath {
+ section: BString,
+ source: gix_config::value::Error,
+ },
+ #[error("core.askpass could not be read")]
+ CoreAskpass(#[from] gix_config::path::interpolate::Error),
+ }
+}
+
+impl Snapshot<'_> {
+ /// Returns the configuration for all git-credential helpers from trusted configuration that apply
+ /// to the given `url` along with an action preconfigured to invoke the cascade with.
+ /// This includes `url` which may be altered to contain a user-name as configured.
+ ///
+ /// These can be invoked to obtain credentials. Note that the `url` is expected to be the one used
+ /// to connect to a remote, and thus should already have passed the url-rewrite engine.
+ ///
+ /// # Deviation
+ ///
+ /// - Invalid urls can't be used to obtain credential helpers as they are rejected early when creating a valid `url` here.
+ /// - Parsed urls will automatically drop the port if it's the default, i.e. `http://host:80` becomes `http://host` when parsed.
+ /// This affects the prompt provided to the user, so that git will use the verbatim url, whereas we use `http://host`.
+ /// - Upper-case scheme and host will be lower-cased automatically when parsing into a url, so prompts differ compared to git.
+ /// - A **difference in prompt might affect the matching of getting existing stored credentials**, and it's a question of this being
+ /// a feature or a bug.
+ // TODO: when dealing with `http.*.*` configuration, generalize this algorithm as needed and support precedence.
+ pub fn credential_helpers(
+ &self,
+ mut url: gix_url::Url,
+ ) -> Result<
+ (
+ gix_credentials::helper::Cascade,
+ gix_credentials::helper::Action,
+ gix_prompt::Options<'static>,
+ ),
+ Error,
+ > {
+ let mut programs = Vec::new();
+ let mut use_http_path = false;
+ let url_had_user_initially = url.user().is_some();
+ normalize(&mut url);
+
+ if let Some(credential_sections) = self
+ .repo
+ .config
+ .resolved
+ .sections_by_name_and_filter("credential", &mut self.repo.filter_config_section())
+ {
+ for section in credential_sections {
+ let section = match section.header().subsection_name() {
+ Some(pattern) => gix_url::parse(pattern).ok().and_then(|mut pattern| {
+ normalize(&mut pattern);
+ let is_http = matches!(pattern.scheme, gix_url::Scheme::Https | gix_url::Scheme::Http);
+ let scheme = &pattern.scheme;
+ let host = pattern.host();
+ let ports = is_http
+ .then(|| (pattern.port_or_default(), url.port_or_default()))
+ .unwrap_or((pattern.port, url.port));
+ let path = (!(is_http && pattern.path_is_root())).then_some(&pattern.path);
+
+ if !path.map_or(true, |path| path == &url.path) {
+ return None;
+ }
+ if pattern.user().is_some() && pattern.user() != url.user() {
+ return None;
+ }
+ (scheme == &url.scheme && host_matches(host, url.host()) && ports.0 == ports.1).then_some((
+ section,
+ &credential::UrlParameter::HELPER,
+ &credential::UrlParameter::USERNAME,
+ &credential::UrlParameter::USE_HTTP_PATH,
+ ))
+ }),
+ None => Some((
+ section,
+ &Credential::HELPER,
+ &Credential::USERNAME,
+ &Credential::USE_HTTP_PATH,
+ )),
+ };
+ if let Some((section, helper_key, username_key, use_http_path_key)) = section {
+ for value in section.values(helper_key.name) {
+ if value.trim().is_empty() {
+ programs.clear();
+ } else {
+ programs.push(gix_credentials::Program::from_custom_definition(value.into_owned()));
+ }
+ }
+ if let Some(Some(user)) = (!url_had_user_initially).then(|| {
+ section
+ .value(username_key.name)
+ .filter(|n| !n.trim().is_empty())
+ .and_then(|n| {
+ let n: Vec<_> = Cow::into_owned(n).into();
+ n.into_string().ok()
+ })
+ }) {
+ url.set_user(Some(user));
+ }
+ if let Some(toggle) = section
+ .value(use_http_path_key.name)
+ .map(|val| {
+ gix_config::Boolean::try_from(val)
+ .map_err(|err| Error::InvalidUseHttpPath {
+ source: err,
+ section: section.header().to_bstring(),
+ })
+ .map(|b| b.0)
+ })
+ .transpose()?
+ {
+ use_http_path = toggle;
+ }
+ }
+ }
+ }
+
+ let allow_git_env = self.repo.options.permissions.env.git_prefix.is_allowed();
+ let allow_ssh_env = self.repo.options.permissions.env.ssh_prefix.is_allowed();
+ let prompt_options = gix_prompt::Options {
+ askpass: self
+ .trusted_path(Core::ASKPASS.logical_name().as_str())
+ .transpose()?
+ .map(|c| Cow::Owned(c.into_owned())),
+ ..Default::default()
+ }
+ .apply_environment(allow_git_env, allow_ssh_env, allow_git_env);
+ Ok((
+ gix_credentials::helper::Cascade {
+ programs,
+ use_http_path,
+ // The default ssh implementation uses binaries that do their own auth, so our passwords aren't used.
+ query_user_only: url.scheme == gix_url::Scheme::Ssh,
+ ..Default::default()
+ },
+ gix_credentials::helper::Action::get_for_url(url.to_bstring()),
+ prompt_options,
+ ))
+ }
+}
+
+fn host_matches(pattern: Option<&str>, host: Option<&str>) -> bool {
+ match (pattern, host) {
+ (Some(pattern), Some(host)) => {
+ let lfields = pattern.split('.');
+ let rfields = host.split('.');
+ if lfields.clone().count() != rfields.clone().count() {
+ return false;
+ }
+ lfields
+ .zip(rfields)
+ .all(|(pat, value)| gix_glob::wildmatch(pat.into(), value.into(), gix_glob::wildmatch::Mode::empty()))
+ }
+ (None, None) => true,
+ (Some(_), None) | (None, Some(_)) => false,
+ }
+}
+
+fn normalize(url: &mut gix_url::Url) {
+ if !url.path_is_root() && url.path.ends_with(b"/") {
+ url.path.pop();
+ }
+}
diff --git a/vendor/gix/src/config/snapshot/mod.rs b/vendor/gix/src/config/snapshot/mod.rs
new file mode 100644
index 000000000..80ec6f948
--- /dev/null
+++ b/vendor/gix/src/config/snapshot/mod.rs
@@ -0,0 +1,5 @@
+mod _impls;
+mod access;
+
+///
+pub mod credential_helpers;
diff --git a/vendor/gix/src/config/tree/keys.rs b/vendor/gix/src/config/tree/keys.rs
new file mode 100644
index 000000000..1cdd187d0
--- /dev/null
+++ b/vendor/gix/src/config/tree/keys.rs
@@ -0,0 +1,629 @@
+#![allow(clippy::result_large_err)]
+use std::{
+ borrow::Cow,
+ error::Error,
+ fmt::{Debug, Formatter},
+};
+
+use crate::{
+ bstr::BStr,
+ config,
+ config::tree::{Key, Link, Note, Section, SubSectionRequirement},
+};
+
+/// Implements a value without any constraints, i.e. a any value.
+pub struct Any<T: Validate = validate::All> {
+ /// The key of the value in the git configuration.
+ pub name: &'static str,
+ /// The parent section of the key.
+ pub section: &'static dyn Section,
+ /// The subsection requirement to use.
+ pub subsection_requirement: Option<SubSectionRequirement>,
+ /// A link to other resources that might be eligible as value.
+ pub link: Option<Link>,
+ /// A note about this key.
+ pub note: Option<Note>,
+ /// The way validation and transformation should happen.
+ validate: T,
+}
+
+/// Init
+impl Any<validate::All> {
+ /// Create a new instance from `name` and `section`
+ pub const fn new(name: &'static str, section: &'static dyn Section) -> Self {
+ Any::new_with_validate(name, section, validate::All)
+ }
+}
+
+/// Init other validate implementations
+impl<T: Validate> Any<T> {
+ /// Create a new instance from `name` and `section`
+ pub const fn new_with_validate(name: &'static str, section: &'static dyn Section, validate: T) -> Self {
+ Any {
+ name,
+ section,
+ subsection_requirement: Some(SubSectionRequirement::Never),
+ link: None,
+ note: None,
+ validate,
+ }
+ }
+}
+
+/// Builder
+impl<T: Validate> Any<T> {
+ /// Set the subsection requirement to non-default values.
+ pub const fn with_subsection_requirement(mut self, requirement: Option<SubSectionRequirement>) -> Self {
+ self.subsection_requirement = requirement;
+ self
+ }
+
+ /// Associate an environment variable with this key.
+ ///
+ /// This is mainly useful for enriching error messages.
+ pub const fn with_environment_override(mut self, var: &'static str) -> Self {
+ self.link = Some(Link::EnvironmentOverride(var));
+ self
+ }
+
+ /// Set a link to another key which serves as fallback to provide a value if this key is not set.
+ pub const fn with_fallback(mut self, key: &'static dyn Key) -> Self {
+ self.link = Some(Link::FallbackKey(key));
+ self
+ }
+
+ /// Attach an informative message to this key.
+ pub const fn with_note(mut self, message: &'static str) -> Self {
+ self.note = Some(Note::Informative(message));
+ self
+ }
+
+ /// Inform about a deviation in how this key is interpreted.
+ pub const fn with_deviation(mut self, message: &'static str) -> Self {
+ self.note = Some(Note::Deviation(message));
+ self
+ }
+}
+
+/// Conversion
+impl<T: Validate> Any<T> {
+ /// Try to convert `value` into a refspec suitable for the `op` operation.
+ pub fn try_into_refspec(
+ &'static self,
+ value: std::borrow::Cow<'_, BStr>,
+ op: gix_refspec::parse::Operation,
+ ) -> Result<gix_refspec::RefSpec, config::refspec::Error> {
+ gix_refspec::parse(value.as_ref(), op)
+ .map(|spec| spec.to_owned())
+ .map_err(|err| config::refspec::Error::from_value(self, value.into_owned()).with_source(err))
+ }
+
+ /// Try to interpret `value` as UTF-8 encoded string.
+ pub fn try_into_string(&'static self, value: Cow<'_, BStr>) -> Result<std::string::String, config::string::Error> {
+ use crate::bstr::ByteVec;
+ Vec::from(value.into_owned()).into_string().map_err(|err| {
+ let utf8_err = err.utf8_error().clone();
+ config::string::Error::from_value(self, err.into_vec().into()).with_source(utf8_err)
+ })
+ }
+}
+
+impl<T: Validate> Debug for Any<T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ self.logical_name().fmt(f)
+ }
+}
+
+impl<T: Validate> std::fmt::Display for Any<T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&self.logical_name())
+ }
+}
+
+impl<T: Validate> Key for Any<T> {
+ fn name(&self) -> &str {
+ self.name
+ }
+
+ fn validate(&self, value: &BStr) -> Result<(), config::tree::key::validate::Error> {
+ Ok(self.validate.validate(value)?)
+ }
+
+ fn section(&self) -> &dyn Section {
+ self.section
+ }
+
+ fn subsection_requirement(&self) -> Option<&SubSectionRequirement> {
+ self.subsection_requirement.as_ref()
+ }
+
+ fn link(&self) -> Option<&Link> {
+ self.link.as_ref()
+ }
+
+ fn note(&self) -> Option<&Note> {
+ self.note.as_ref()
+ }
+}
+
+/// A key which represents a date.
+pub type Time = Any<validate::Time>;
+
+/// The `core.(filesRefLockTimeout|packedRefsTimeout)` keys, or any other lock timeout for that matter.
+pub type LockTimeout = Any<validate::LockTimeout>;
+
+/// Keys specifying durations in milliseconds.
+pub type DurationInMilliseconds = Any<validate::DurationInMilliseconds>;
+
+/// A key which represents any unsigned integer.
+pub type UnsignedInteger = Any<validate::UnsignedInteger>;
+
+/// A key that represents a remote name, either as url or symbolic name.
+pub type RemoteName = Any<validate::RemoteName>;
+
+/// A key that represents a boolean value.
+pub type Boolean = Any<validate::Boolean>;
+
+/// A key that represents an executable program, shell script or shell commands.
+pub type Program = Any<validate::Program>;
+
+/// A key that represents an executable program as identified by name or path.
+pub type Executable = Any<validate::Executable>;
+
+/// A key that represents a path (to a resource).
+pub type Path = Any<validate::Path>;
+
+/// A key that represents a URL.
+pub type Url = Any<validate::Url>;
+
+/// A key that represents a UTF-8 string.
+pub type String = Any<validate::String>;
+
+/// A key that represents a RefSpec for pushing.
+pub type PushRefSpec = Any<validate::PushRefSpec>;
+
+/// A key that represents a RefSpec for fetching.
+pub type FetchRefSpec = Any<validate::FetchRefSpec>;
+
+mod duration {
+ use std::time::Duration;
+
+ use crate::{
+ config,
+ config::tree::{keys::DurationInMilliseconds, Section},
+ };
+
+ impl DurationInMilliseconds {
+ /// Create a new instance.
+ pub const fn new_duration(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, super::validate::DurationInMilliseconds)
+ }
+
+ /// Return a valid duration as parsed from an integer that is interpreted as milliseconds.
+ pub fn try_into_duration(
+ &'static self,
+ value: Result<i64, gix_config::value::Error>,
+ ) -> Result<std::time::Duration, config::duration::Error> {
+ let value = value.map_err(|err| config::duration::Error::from(self).with_source(err))?;
+ Ok(match value {
+ val if val < 0 => Duration::from_secs(u64::MAX),
+ val => Duration::from_millis(val.try_into().expect("i64 to u64 always works if positive")),
+ })
+ }
+ }
+}
+
+mod lock_timeout {
+ use std::time::Duration;
+
+ use gix_lock::acquire::Fail;
+
+ use crate::{
+ config,
+ config::tree::{keys::LockTimeout, Section},
+ };
+
+ impl LockTimeout {
+ /// Create a new instance.
+ pub const fn new_lock_timeout(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, super::validate::LockTimeout)
+ }
+
+ /// Return information on how long to wait for locked files.
+ pub fn try_into_lock_timeout(
+ &'static self,
+ value: Result<i64, gix_config::value::Error>,
+ ) -> Result<gix_lock::acquire::Fail, config::lock_timeout::Error> {
+ let value = value.map_err(|err| config::lock_timeout::Error::from(self).with_source(err))?;
+ Ok(match value {
+ val if val < 0 => Fail::AfterDurationWithBackoff(Duration::from_secs(u64::MAX)),
+ val if val == 0 => Fail::Immediately,
+ val => Fail::AfterDurationWithBackoff(Duration::from_millis(
+ val.try_into().expect("i64 to u64 always works if positive"),
+ )),
+ })
+ }
+ }
+}
+
+mod refspecs {
+ use crate::config::tree::{
+ keys::{validate, FetchRefSpec, PushRefSpec},
+ Section,
+ };
+
+ impl PushRefSpec {
+ /// Create a new instance.
+ pub const fn new_push_refspec(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, validate::PushRefSpec)
+ }
+ }
+
+ impl FetchRefSpec {
+ /// Create a new instance.
+ pub const fn new_fetch_refspec(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, validate::FetchRefSpec)
+ }
+ }
+}
+
+mod url {
+ use std::borrow::Cow;
+
+ use crate::{
+ bstr::BStr,
+ config,
+ config::tree::{
+ keys::{validate, Url},
+ Section,
+ },
+ };
+
+ impl Url {
+ /// Create a new instance.
+ pub const fn new_url(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, validate::Url)
+ }
+
+ /// Try to parse `value` as URL.
+ pub fn try_into_url(&'static self, value: Cow<'_, BStr>) -> Result<gix_url::Url, config::url::Error> {
+ gix_url::parse(value.as_ref())
+ .map_err(|err| config::url::Error::from_value(self, value.into_owned()).with_source(err))
+ }
+ }
+}
+
+impl String {
+ /// Create a new instance.
+ pub const fn new_string(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, validate::String)
+ }
+}
+
+impl Program {
+ /// Create a new instance.
+ pub const fn new_program(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, validate::Program)
+ }
+}
+
+impl Executable {
+ /// Create a new instance.
+ pub const fn new_executable(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, validate::Executable)
+ }
+}
+
+impl Path {
+ /// Create a new instance.
+ pub const fn new_path(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, validate::Path)
+ }
+}
+
+mod workers {
+ use crate::config::tree::{keys::UnsignedInteger, Section};
+
+ impl UnsignedInteger {
+ /// Create a new instance.
+ pub const fn new_unsigned_integer(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, super::validate::UnsignedInteger)
+ }
+
+ /// Convert `value` into a `usize` or wrap it into a specialized error.
+ pub fn try_into_usize(
+ &'static self,
+ value: Result<i64, gix_config::value::Error>,
+ ) -> Result<usize, crate::config::unsigned_integer::Error> {
+ value
+ .map_err(|err| crate::config::unsigned_integer::Error::from(self).with_source(err))
+ .and_then(|value| {
+ value
+ .try_into()
+ .map_err(|_| crate::config::unsigned_integer::Error::from(self))
+ })
+ }
+
+ /// Convert `value` into a `u64` or wrap it into a specialized error.
+ pub fn try_into_u64(
+ &'static self,
+ value: Result<i64, gix_config::value::Error>,
+ ) -> Result<u64, crate::config::unsigned_integer::Error> {
+ value
+ .map_err(|err| crate::config::unsigned_integer::Error::from(self).with_source(err))
+ .and_then(|value| {
+ value
+ .try_into()
+ .map_err(|_| crate::config::unsigned_integer::Error::from(self))
+ })
+ }
+
+ /// Convert `value` into a `u32` or wrap it into a specialized error.
+ pub fn try_into_u32(
+ &'static self,
+ value: Result<i64, gix_config::value::Error>,
+ ) -> Result<u32, crate::config::unsigned_integer::Error> {
+ value
+ .map_err(|err| crate::config::unsigned_integer::Error::from(self).with_source(err))
+ .and_then(|value| {
+ value
+ .try_into()
+ .map_err(|_| crate::config::unsigned_integer::Error::from(self))
+ })
+ }
+ }
+}
+
+mod time {
+ use std::borrow::Cow;
+
+ use crate::{
+ bstr::{BStr, ByteSlice},
+ config::tree::{
+ keys::{validate, Time},
+ Section,
+ },
+ };
+
+ impl Time {
+ /// Create a new instance.
+ pub const fn new_time(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, validate::Time)
+ }
+
+ /// Convert the `value` into a date if possible, with `now` as reference time for relative dates.
+ pub fn try_into_time(
+ &self,
+ value: Cow<'_, BStr>,
+ now: Option<std::time::SystemTime>,
+ ) -> Result<gix_date::Time, gix_date::parse::Error> {
+ gix_date::parse(
+ value
+ .as_ref()
+ .to_str()
+ .map_err(|_| gix_date::parse::Error::InvalidDateString {
+ input: value.to_string(),
+ })?,
+ now,
+ )
+ }
+ }
+}
+
+mod boolean {
+ use crate::{
+ config,
+ config::tree::{
+ keys::{validate, Boolean},
+ Section,
+ },
+ };
+
+ impl Boolean {
+ /// Create a new instance.
+ pub const fn new_boolean(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, validate::Boolean)
+ }
+
+ /// Process the `value` into a result with an improved error message.
+ ///
+ /// `value` is expected to be provided by [`gix_config::File::boolean()`].
+ pub fn enrich_error(
+ &'static self,
+ value: Result<bool, gix_config::value::Error>,
+ ) -> Result<bool, config::boolean::Error> {
+ value.map_err(|err| config::boolean::Error::from(self).with_source(err))
+ }
+ }
+}
+
+mod remote_name {
+ use std::borrow::Cow;
+
+ use crate::{
+ bstr::{BStr, BString},
+ config,
+ config::tree::{keys::RemoteName, Section},
+ };
+
+ impl RemoteName {
+ /// Create a new instance.
+ pub const fn new_remote_name(name: &'static str, section: &'static dyn Section) -> Self {
+ Self::new_with_validate(name, section, super::validate::RemoteName)
+ }
+
+ /// Try to validate `name` as symbolic remote name and return it.
+ #[allow(clippy::result_large_err)]
+ pub fn try_into_symbolic_name(
+ &'static self,
+ name: Cow<'_, BStr>,
+ ) -> Result<BString, config::remote::symbolic_name::Error> {
+ crate::remote::name::validated(name.into_owned())
+ .map_err(|err| config::remote::symbolic_name::Error::from(self).with_source(err))
+ }
+ }
+}
+
+/// Provide a way to validate a value, or decode a value from `gix-config`.
+pub trait Validate {
+ /// Validate `value` or return an error.
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>>;
+}
+
+/// various implementations of the `Validate` trait.
+pub mod validate {
+ use std::{borrow::Cow, error::Error};
+
+ use crate::{
+ bstr::{BStr, ByteSlice},
+ config::tree::keys::Validate,
+ remote,
+ };
+
+ /// Everything is valid.
+ #[derive(Default)]
+ pub struct All;
+
+ impl Validate for All {
+ fn validate(&self, _value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ Ok(())
+ }
+ }
+
+ /// Assure that values that parse as git dates are valid.
+ #[derive(Default)]
+ pub struct Time;
+
+ impl Validate for Time {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ gix_date::parse(value.to_str()?, std::time::SystemTime::now().into())?;
+ Ok(())
+ }
+ }
+
+ /// Assure that values that parse as unsigned integers are valid.
+ #[derive(Default)]
+ pub struct UnsignedInteger;
+
+ impl Validate for UnsignedInteger {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ usize::try_from(
+ gix_config::Integer::try_from(value)?
+ .to_decimal()
+ .ok_or_else(|| format!("integer {value} cannot be represented as `usize`"))?,
+ )?;
+ Ok(())
+ }
+ }
+
+ /// Assure that values that parse as git booleans are valid.
+ #[derive(Default)]
+ pub struct Boolean;
+
+ impl Validate for Boolean {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ gix_config::Boolean::try_from(value)?;
+ Ok(())
+ }
+ }
+
+ /// Values that are git remotes, symbolic or urls
+ #[derive(Default)]
+ pub struct RemoteName;
+ impl Validate for RemoteName {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ remote::Name::try_from(Cow::Borrowed(value))
+ .map_err(|_| format!("Illformed UTF-8 in remote name: \"{}\"", value.to_str_lossy()))?;
+ Ok(())
+ }
+ }
+
+ /// Values that are programs - everything is allowed.
+ #[derive(Default)]
+ pub struct Program;
+ impl Validate for Program {
+ fn validate(&self, _value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ Ok(())
+ }
+ }
+
+ /// Values that are programs executables, everything is allowed.
+ #[derive(Default)]
+ pub struct Executable;
+ impl Validate for Executable {
+ fn validate(&self, _value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ Ok(())
+ }
+ }
+
+ /// Values that parse as URLs.
+ #[derive(Default)]
+ pub struct Url;
+ impl Validate for Url {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ gix_url::parse(value)?;
+ Ok(())
+ }
+ }
+
+ /// Values that parse as ref-specs for pushing.
+ #[derive(Default)]
+ pub struct PushRefSpec;
+ impl Validate for PushRefSpec {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ gix_refspec::parse(value, gix_refspec::parse::Operation::Push)?;
+ Ok(())
+ }
+ }
+
+ /// Values that parse as ref-specs for pushing.
+ #[derive(Default)]
+ pub struct FetchRefSpec;
+ impl Validate for FetchRefSpec {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ gix_refspec::parse(value, gix_refspec::parse::Operation::Fetch)?;
+ Ok(())
+ }
+ }
+
+ /// Timeouts used for file locks.
+ pub struct LockTimeout;
+ impl Validate for LockTimeout {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ let value = gix_config::Integer::try_from(value)?
+ .to_decimal()
+ .ok_or_else(|| format!("integer {value} cannot be represented as integer"));
+ super::super::Core::FILES_REF_LOCK_TIMEOUT.try_into_lock_timeout(Ok(value?))?;
+ Ok(())
+ }
+ }
+
+ /// Durations in milliseconds.
+ pub struct DurationInMilliseconds;
+ impl Validate for DurationInMilliseconds {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ let value = gix_config::Integer::try_from(value)?
+ .to_decimal()
+ .ok_or_else(|| format!("integer {value} cannot be represented as integer"));
+ super::super::gitoxide::Http::CONNECT_TIMEOUT.try_into_duration(Ok(value?))?;
+ Ok(())
+ }
+ }
+
+ /// A UTF-8 string.
+ pub struct String;
+ impl Validate for String {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ value.to_str()?;
+ Ok(())
+ }
+ }
+
+ /// Any path - everything is allowed.
+ pub struct Path;
+ impl Validate for Path {
+ fn validate(&self, _value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ Ok(())
+ }
+ }
+}
diff --git a/vendor/gix/src/config/tree/mod.rs b/vendor/gix/src/config/tree/mod.rs
new file mode 100644
index 000000000..fd769f3ed
--- /dev/null
+++ b/vendor/gix/src/config/tree/mod.rs
@@ -0,0 +1,123 @@
+//! The tree of supported configuration values for use in [`config_overrides`][crate::open::Options::config_overrides()]
+//! or for validating and transforming well-known configuration values.
+//!
+//! It can also be used to traverse all implemented keys and to validate values before usage as configuration overrides.
+//!
+//! ### Leniency
+//!
+//! When validating values, we don't apply leniency here which is left to the caller. Leniency is an application defined configuration
+//! to ignore errors on non-security related values, which might make applications more resilient towards misconfiguration.
+pub(crate) mod root {
+ use super::sections;
+ use crate::config::tree::Section;
+
+ /// The root of the configuration tree, suitable to discover all sub-sections at runtime or compile time.
+ #[derive(Copy, Clone, Default)]
+ pub struct Tree;
+
+ impl Tree {
+ /// The `author` section.
+ pub const AUTHOR: sections::Author = sections::Author;
+ /// The `branch` section.
+ pub const BRANCH: sections::Branch = sections::Branch;
+ /// The `checkout` section.
+ pub const CHECKOUT: sections::Checkout = sections::Checkout;
+ /// The `clone` section.
+ pub const CLONE: sections::Clone = sections::Clone;
+ /// The `committer` section.
+ pub const COMMITTER: sections::Committer = sections::Committer;
+ /// The `core` section.
+ pub const CORE: sections::Core = sections::Core;
+ /// The `credential` section.
+ pub const CREDENTIAL: sections::Credential = sections::Credential;
+ /// The `diff` section.
+ pub const DIFF: sections::Diff = sections::Diff;
+ /// The `extensions` section.
+ pub const EXTENSIONS: sections::Extensions = sections::Extensions;
+ /// The `gitoxide` section.
+ pub const GITOXIDE: sections::Gitoxide = sections::Gitoxide;
+ /// The `http` section.
+ pub const HTTP: sections::Http = sections::Http;
+ /// The `init` section.
+ pub const INIT: sections::Init = sections::Init;
+ /// The `pack` section.
+ pub const PACK: sections::Pack = sections::Pack;
+ /// The `protocol` section.
+ pub const PROTOCOL: sections::Protocol = sections::Protocol;
+ /// The `remote` section.
+ pub const REMOTE: sections::Remote = sections::Remote;
+ /// The `safe` section.
+ pub const SAFE: sections::Safe = sections::Safe;
+ /// The `ssh` section.
+ pub const SSH: sections::Ssh = sections::Ssh;
+ /// The `user` section.
+ pub const USER: sections::User = sections::User;
+ /// The `url` section.
+ pub const URL: sections::Url = sections::Url;
+
+ /// List all available sections.
+ pub fn sections(&self) -> &[&dyn Section] {
+ &[
+ &Self::AUTHOR,
+ &Self::BRANCH,
+ &Self::CHECKOUT,
+ &Self::CLONE,
+ &Self::COMMITTER,
+ &Self::CORE,
+ &Self::CREDENTIAL,
+ &Self::DIFF,
+ &Self::EXTENSIONS,
+ &Self::GITOXIDE,
+ &Self::HTTP,
+ &Self::INIT,
+ &Self::PACK,
+ &Self::PROTOCOL,
+ &Self::REMOTE,
+ &Self::SAFE,
+ &Self::SSH,
+ &Self::USER,
+ &Self::URL,
+ ]
+ }
+ }
+}
+
+mod sections;
+pub use sections::{
+ branch, checkout, core, credential, diff, extensions, gitoxide, http, protocol, remote, ssh, Author, Branch,
+ Checkout, Clone, Committer, Core, Credential, Diff, Extensions, Gitoxide, Http, Init, Pack, Protocol, Remote, Safe,
+ Ssh, Url, User,
+};
+
+/// Generic value implementations for static instantiation.
+pub mod keys;
+
+///
+pub mod key {
+ ///
+ pub mod validate {
+ /// The error returned by [Key::validate()][crate::config::tree::Key::validate()].
+ #[derive(Debug, thiserror::Error)]
+ #[error(transparent)]
+ #[allow(missing_docs)]
+ pub struct Error {
+ #[from]
+ source: Box<dyn std::error::Error + Send + Sync + 'static>,
+ }
+ }
+ ///
+ pub mod validate_assignment {
+ /// The error returned by [Key::validated_assignment*()][crate::config::tree::Key::validated_assignment_fmt()].
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("Failed to validate the value to be assigned to this key")]
+ Validate(#[from] super::validate::Error),
+ #[error("{message}")]
+ Name { message: String },
+ }
+ }
+}
+
+mod traits;
+pub use traits::{Key, Link, Note, Section, SubSectionRequirement};
diff --git a/vendor/gix/src/config/tree/sections/author.rs b/vendor/gix/src/config/tree/sections/author.rs
new file mode 100644
index 000000000..4101e3817
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/author.rs
@@ -0,0 +1,23 @@
+use crate::{
+ config,
+ config::tree::{gitoxide, keys, Author, Key, Section},
+};
+
+impl Author {
+ /// The `author.name` key.
+ pub const NAME: keys::Any =
+ keys::Any::new("name", &config::Tree::AUTHOR).with_fallback(&gitoxide::Author::NAME_FALLBACK);
+ /// The `author.email` key.
+ pub const EMAIL: keys::Any =
+ keys::Any::new("email", &config::Tree::AUTHOR).with_fallback(&gitoxide::Author::EMAIL_FALLBACK);
+}
+
+impl Section for Author {
+ fn name(&self) -> &str {
+ "author"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::NAME, &Self::EMAIL]
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/branch.rs b/vendor/gix/src/config/tree/sections/branch.rs
new file mode 100644
index 000000000..8e1e0a4b8
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/branch.rs
@@ -0,0 +1,65 @@
+use crate::config::tree::{keys, traits::SubSectionRequirement, Branch, Key, Section};
+
+const NAME_PARAMETER: Option<SubSectionRequirement> = Some(SubSectionRequirement::Parameter("name"));
+
+impl Branch {
+ /// The `branch.<name>.merge` key.
+ pub const MERGE: Merge = Merge::new_with_validate("merge", &crate::config::Tree::BRANCH, validate::FullNameRef)
+ .with_subsection_requirement(NAME_PARAMETER);
+ /// The `branch.<name>.pushRemote` key.
+ pub const PUSH_REMOTE: keys::RemoteName =
+ keys::RemoteName::new_remote_name("pushRemote", &crate::config::Tree::BRANCH)
+ .with_subsection_requirement(NAME_PARAMETER);
+ /// The `branch.<name>.remote` key.
+ pub const REMOTE: keys::RemoteName = keys::RemoteName::new_remote_name("remote", &crate::config::Tree::BRANCH)
+ .with_subsection_requirement(NAME_PARAMETER);
+}
+
+impl Section for Branch {
+ fn name(&self) -> &str {
+ "branch"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::MERGE, &Self::PUSH_REMOTE, &Self::REMOTE]
+ }
+}
+
+/// The `branch.<name>.merge` key.
+pub type Merge = keys::Any<validate::FullNameRef>;
+
+mod merge {
+ use std::borrow::Cow;
+
+ use gix_ref::FullNameRef;
+
+ use crate::{bstr::BStr, config::tree::branch::Merge};
+
+ impl Merge {
+ /// Return the validated full ref name from `value` if it is valid.
+ pub fn try_into_fullrefname(
+ value: Cow<'_, BStr>,
+ ) -> Result<Cow<'_, FullNameRef>, gix_validate::reference::name::Error> {
+ match value {
+ Cow::Borrowed(v) => v.try_into().map(Cow::Borrowed),
+ Cow::Owned(v) => v.try_into().map(Cow::Owned),
+ }
+ }
+ }
+}
+
+///
+pub mod validate {
+ use crate::{
+ bstr::BStr,
+ config::tree::{branch::Merge, keys},
+ };
+
+ pub struct FullNameRef;
+ impl keys::Validate for FullNameRef {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ Merge::try_into_fullrefname(value.into())?;
+ Ok(())
+ }
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/checkout.rs b/vendor/gix/src/config/tree/sections/checkout.rs
new file mode 100644
index 000000000..27f31ee84
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/checkout.rs
@@ -0,0 +1,58 @@
+use crate::{
+ config,
+ config::tree::{keys, Checkout, Key, Section},
+};
+
+impl Checkout {
+ /// The `checkout.workers` key.
+ pub const WORKERS: Workers = Workers::new_with_validate("workers", &config::Tree::CHECKOUT, validate::Workers)
+ .with_deviation("if unset, uses all cores instead of just one");
+}
+
+/// The `checkout.workers` key.
+pub type Workers = keys::Any<validate::Workers>;
+
+impl Section for Checkout {
+ fn name(&self) -> &str {
+ "checkout"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::WORKERS]
+ }
+}
+
+mod workers {
+ use crate::config::tree::checkout::Workers;
+
+ impl Workers {
+ /// Return the amount of threads to use for checkout, with `0` meaning all available ones, after decoding our integer value from `config`,
+ /// or `None` if the value isn't set which is typically interpreted as "as many threads as available"
+ pub fn try_from_workers(
+ &'static self,
+ value: Result<i64, gix_config::value::Error>,
+ ) -> Result<usize, crate::config::checkout::workers::Error> {
+ match value {
+ Ok(v) if v < 0 => Ok(0),
+ Ok(v) => Ok(v.try_into().expect("positive i64 can always be usize on 64 bit")),
+ Err(err) => Err(crate::config::key::Error::from(&super::Checkout::WORKERS).with_source(err)),
+ }
+ }
+ }
+}
+
+///
+pub mod validate {
+ use crate::{bstr::BStr, config::tree::keys};
+
+ pub struct Workers;
+ impl keys::Validate for Workers {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ super::Checkout::WORKERS.try_from_workers(gix_config::Integer::try_from(value).and_then(|i| {
+ i.to_decimal()
+ .ok_or_else(|| gix_config::value::Error::new("Integer overflow", value.to_owned()))
+ }))?;
+ Ok(())
+ }
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/clone.rs b/vendor/gix/src/config/tree/sections/clone.rs
new file mode 100644
index 000000000..616185a0b
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/clone.rs
@@ -0,0 +1,20 @@
+use crate::{
+ config,
+ config::tree::{keys, Clone, Key, Section},
+};
+
+impl Clone {
+ /// The `clone.defaultRemoteName` key.
+ pub const DEFAULT_REMOTE_NAME: keys::RemoteName =
+ keys::RemoteName::new_remote_name("defaultRemoteName", &config::Tree::CLONE);
+}
+
+impl Section for Clone {
+ fn name(&self) -> &str {
+ "clone"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::DEFAULT_REMOTE_NAME]
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/committer.rs b/vendor/gix/src/config/tree/sections/committer.rs
new file mode 100644
index 000000000..acc25c930
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/committer.rs
@@ -0,0 +1,23 @@
+use crate::{
+ config,
+ config::tree::{gitoxide, keys, Committer, Key, Section},
+};
+
+impl Committer {
+ /// The `committer.name` key.
+ pub const NAME: keys::Any =
+ keys::Any::new("name", &config::Tree::COMMITTER).with_fallback(&gitoxide::Committer::NAME_FALLBACK);
+ /// The `committer.email` key.
+ pub const EMAIL: keys::Any =
+ keys::Any::new("email", &config::Tree::COMMITTER).with_fallback(&gitoxide::Committer::EMAIL_FALLBACK);
+}
+
+impl Section for Committer {
+ fn name(&self) -> &str {
+ "committer"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::NAME, &Self::EMAIL]
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/core.rs b/vendor/gix/src/config/tree/sections/core.rs
new file mode 100644
index 000000000..6ea0580e1
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/core.rs
@@ -0,0 +1,302 @@
+use crate::{
+ config,
+ config::tree::{keys, Core, Key, Section},
+};
+
+impl Core {
+ /// The `core.abbrev` key.
+ pub const ABBREV: Abbrev = Abbrev::new_with_validate("abbrev", &config::Tree::CORE, validate::Abbrev);
+ /// The `core.bare` key.
+ pub const BARE: keys::Boolean = keys::Boolean::new_boolean("bare", &config::Tree::CORE);
+ /// The `core.checkStat` key.
+ pub const CHECK_STAT: CheckStat =
+ CheckStat::new_with_validate("checkStat", &config::Tree::CORE, validate::CheckStat);
+ /// The `core.deltaBaseCacheLimit` key.
+ pub const DELTA_BASE_CACHE_LIMIT: keys::UnsignedInteger =
+ keys::UnsignedInteger::new_unsigned_integer("deltaBaseCacheLimit", &config::Tree::CORE)
+ .with_environment_override("GITOXIDE_PACK_CACHE_MEMORY")
+ .with_note("if unset, we default to a small 64 slot fixed-size cache that holds at most 64 full delta base objects of any size. Set to 0 to deactivate it entirely");
+ /// The `core.disambiguate` key.
+ pub const DISAMBIGUATE: Disambiguate =
+ Disambiguate::new_with_validate("disambiguate", &config::Tree::CORE, validate::Disambiguate);
+ /// The `core.fileMode` key.
+ pub const FILE_MODE: keys::Boolean = keys::Boolean::new_boolean("fileMode", &config::Tree::CORE);
+ /// The `core.ignoreCase` key.
+ pub const IGNORE_CASE: keys::Boolean = keys::Boolean::new_boolean("ignoreCase", &config::Tree::CORE);
+ /// The `core.filesRefLockTimeout` key.
+ pub const FILES_REF_LOCK_TIMEOUT: keys::LockTimeout =
+ keys::LockTimeout::new_lock_timeout("filesRefLockTimeout", &config::Tree::CORE);
+ /// The `core.packedRefsTimeout` key.
+ pub const PACKED_REFS_TIMEOUT: keys::LockTimeout =
+ keys::LockTimeout::new_lock_timeout("packedRefsTimeout", &config::Tree::CORE);
+ /// The `core.multiPackIndex` key.
+ pub const MULTIPACK_INDEX: keys::Boolean = keys::Boolean::new_boolean("multiPackIndex", &config::Tree::CORE);
+ /// The `core.logAllRefUpdates` key.
+ pub const LOG_ALL_REF_UPDATES: LogAllRefUpdates =
+ LogAllRefUpdates::new_with_validate("logAllRefUpdates", &config::Tree::CORE, validate::LogAllRefUpdates);
+ /// The `core.precomposeUnicode` key.
+ ///
+ /// Needs application to use [env::args_os][crate::env::args_os()] to conform all input paths before they are used.
+ pub const PRECOMPOSE_UNICODE: keys::Boolean = keys::Boolean::new_boolean("precomposeUnicode", &config::Tree::CORE)
+ .with_note("application needs to conform all program input by using gix::env::args_os()");
+ /// The `core.repositoryFormatVersion` key.
+ pub const REPOSITORY_FORMAT_VERSION: keys::UnsignedInteger =
+ keys::UnsignedInteger::new_unsigned_integer("repositoryFormatVersion", &config::Tree::CORE);
+ /// The `core.symlinks` key.
+ pub const SYMLINKS: keys::Boolean = keys::Boolean::new_boolean("symlinks", &config::Tree::CORE);
+ /// The `core.trustCTime` key.
+ pub const TRUST_C_TIME: keys::Boolean = keys::Boolean::new_boolean("trustCTime", &config::Tree::CORE);
+ /// The `core.worktree` key.
+ pub const WORKTREE: keys::Any = keys::Any::new("worktree", &config::Tree::CORE)
+ .with_environment_override("GIT_WORK_TREE")
+ .with_deviation("Overriding the worktree with environment variables is supported using `ThreadSafeRepository::open_with_environment_overrides()");
+ /// The `core.askPass` key.
+ pub const ASKPASS: keys::Executable = keys::Executable::new_executable("askPass", &config::Tree::CORE)
+ .with_environment_override("GIT_ASKPASS")
+ .with_note("fallback is 'SSH_ASKPASS'");
+ /// The `core.excludesFile` key.
+ pub const EXCLUDES_FILE: keys::Executable = keys::Executable::new_executable("excludesFile", &config::Tree::CORE);
+ /// The `core.attributesFile` key.
+ pub const ATTRIBUTES_FILE: keys::Executable =
+ keys::Executable::new_executable("attributesFile", &config::Tree::CORE)
+ .with_deviation("for checkout - it's already queried but needs building of attributes group, and of course support during checkout");
+ /// The `core.sshCommand` key.
+ pub const SSH_COMMAND: keys::Executable = keys::Executable::new_executable("sshCommand", &config::Tree::CORE)
+ .with_environment_override("GIT_SSH_COMMAND");
+}
+
+impl Section for Core {
+ fn name(&self) -> &str {
+ "core"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[
+ &Self::ABBREV,
+ &Self::BARE,
+ &Self::CHECK_STAT,
+ &Self::DELTA_BASE_CACHE_LIMIT,
+ &Self::DISAMBIGUATE,
+ &Self::FILE_MODE,
+ &Self::IGNORE_CASE,
+ &Self::FILES_REF_LOCK_TIMEOUT,
+ &Self::PACKED_REFS_TIMEOUT,
+ &Self::MULTIPACK_INDEX,
+ &Self::LOG_ALL_REF_UPDATES,
+ &Self::PRECOMPOSE_UNICODE,
+ &Self::REPOSITORY_FORMAT_VERSION,
+ &Self::SYMLINKS,
+ &Self::TRUST_C_TIME,
+ &Self::WORKTREE,
+ &Self::ASKPASS,
+ &Self::EXCLUDES_FILE,
+ &Self::ATTRIBUTES_FILE,
+ &Self::SSH_COMMAND,
+ ]
+ }
+}
+
+/// The `core.checkStat` key.
+pub type CheckStat = keys::Any<validate::CheckStat>;
+
+/// The `core.abbrev` key.
+pub type Abbrev = keys::Any<validate::Abbrev>;
+
+/// The `core.logAllRefUpdates` key.
+pub type LogAllRefUpdates = keys::Any<validate::LogAllRefUpdates>;
+
+/// The `core.disambiguate` key.
+pub type Disambiguate = keys::Any<validate::Disambiguate>;
+
+mod disambiguate {
+ use std::borrow::Cow;
+
+ use crate::{
+ bstr::{BStr, ByteSlice},
+ config,
+ config::tree::core::Disambiguate,
+ revision::spec::parse::ObjectKindHint,
+ };
+
+ impl Disambiguate {
+ /// Convert a disambiguation marker into the respective enum.
+ pub fn try_into_object_kind_hint(
+ &'static self,
+ value: Cow<'_, BStr>,
+ ) -> Result<Option<ObjectKindHint>, config::key::GenericErrorWithValue> {
+ let hint = match value.as_ref().as_bytes() {
+ b"none" => return Ok(None),
+ b"commit" => ObjectKindHint::Commit,
+ b"committish" => ObjectKindHint::Committish,
+ b"tree" => ObjectKindHint::Tree,
+ b"treeish" => ObjectKindHint::Treeish,
+ b"blob" => ObjectKindHint::Blob,
+ _ => return Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned())),
+ };
+ Ok(Some(hint))
+ }
+ }
+}
+
+mod log_all_ref_updates {
+ use std::borrow::Cow;
+
+ use crate::{bstr::BStr, config, config::tree::core::LogAllRefUpdates};
+
+ impl LogAllRefUpdates {
+ /// Returns the mode for ref-updates as parsed from `value`. If `value` is not a boolean, `string_on_failure` will be called
+ /// to obtain the key `core.logAllRefUpdates` as string instead. For correctness, this two step process is necessary as
+ /// the interpretation of booleans in special in `gix-config`, i.e. we can't just treat it as string.
+ pub fn try_into_ref_updates<'a>(
+ &'static self,
+ value: Option<Result<bool, gix_config::value::Error>>,
+ string_on_failure: impl FnOnce() -> Option<Cow<'a, BStr>>,
+ ) -> Result<Option<gix_ref::store::WriteReflog>, config::key::GenericErrorWithValue> {
+ match value.transpose().ok().flatten() {
+ Some(bool) => Ok(Some(if bool {
+ gix_ref::store::WriteReflog::Normal
+ } else {
+ gix_ref::store::WriteReflog::Disable
+ })),
+ None => match string_on_failure() {
+ Some(val) if val.eq_ignore_ascii_case(b"always") => Ok(Some(gix_ref::store::WriteReflog::Always)),
+ Some(val) => Err(config::key::GenericErrorWithValue::from_value(self, val.into_owned())),
+ None => Ok(None),
+ },
+ }
+ }
+ }
+}
+
+mod check_stat {
+ use std::borrow::Cow;
+
+ use crate::{
+ bstr::{BStr, ByteSlice},
+ config,
+ config::tree::core::CheckStat,
+ };
+
+ impl CheckStat {
+ /// Returns true if the full set of stat entries should be checked, and it's just as lenient as git.
+ pub fn try_into_checkstat(
+ &'static self,
+ value: Cow<'_, BStr>,
+ ) -> Result<bool, config::key::GenericErrorWithValue> {
+ Ok(match value.as_ref().as_bytes() {
+ b"minimal" => false,
+ b"default" => true,
+ _ => {
+ return Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned()));
+ }
+ })
+ }
+ }
+}
+
+mod abbrev {
+ use std::borrow::Cow;
+
+ use config::abbrev::Error;
+
+ use crate::{
+ bstr::{BStr, ByteSlice},
+ config,
+ config::tree::core::Abbrev,
+ };
+
+ impl Abbrev {
+ /// Convert the given `hex_len_str` into the amount of characters that a short hash should have.
+ /// If `None` is returned, the correct value can be determined based on the amount of objects in the repo.
+ pub fn try_into_abbreviation(
+ &'static self,
+ hex_len_str: Cow<'_, BStr>,
+ object_hash: gix_hash::Kind,
+ ) -> Result<Option<usize>, Error> {
+ let max = object_hash.len_in_hex() as u8;
+ if hex_len_str.trim().is_empty() {
+ return Err(Error {
+ value: hex_len_str.into_owned(),
+ max,
+ });
+ }
+ if hex_len_str.trim().eq_ignore_ascii_case(b"auto") {
+ Ok(None)
+ } else {
+ let value_bytes = hex_len_str.as_ref();
+ if let Ok(false) = gix_config::Boolean::try_from(value_bytes).map(Into::into) {
+ Ok(object_hash.len_in_hex().into())
+ } else {
+ let value = gix_config::Integer::try_from(value_bytes)
+ .map_err(|_| Error {
+ value: hex_len_str.clone().into_owned(),
+ max,
+ })?
+ .to_decimal()
+ .ok_or_else(|| Error {
+ value: hex_len_str.clone().into_owned(),
+ max,
+ })?;
+ if value < 4 || value as usize > object_hash.len_in_hex() {
+ return Err(Error {
+ value: hex_len_str.clone().into_owned(),
+ max,
+ });
+ }
+ Ok(Some(value as usize))
+ }
+ }
+ }
+ }
+}
+
+mod validate {
+ use crate::{bstr::BStr, config::tree::keys};
+
+ pub struct LockTimeout;
+ impl keys::Validate for LockTimeout {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ let value = gix_config::Integer::try_from(value)?
+ .to_decimal()
+ .ok_or_else(|| format!("integer {value} cannot be represented as integer"));
+ super::Core::FILES_REF_LOCK_TIMEOUT.try_into_lock_timeout(Ok(value?))?;
+ Ok(())
+ }
+ }
+
+ pub struct Disambiguate;
+ impl keys::Validate for Disambiguate {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ super::Core::DISAMBIGUATE.try_into_object_kind_hint(value.into())?;
+ Ok(())
+ }
+ }
+
+ pub struct LogAllRefUpdates;
+ impl keys::Validate for LogAllRefUpdates {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ super::Core::LOG_ALL_REF_UPDATES
+ .try_into_ref_updates(Some(gix_config::Boolean::try_from(value).map(|b| b.0)), || {
+ Some(value.into())
+ })?;
+ Ok(())
+ }
+ }
+
+ pub struct CheckStat;
+ impl keys::Validate for CheckStat {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ super::Core::CHECK_STAT.try_into_checkstat(value.into())?;
+ Ok(())
+ }
+ }
+
+ pub struct Abbrev;
+ impl keys::Validate for Abbrev {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ // TODO: when there is options, validate against all hashes and assure all fail to trigger a validation failure.
+ super::Core::ABBREV.try_into_abbreviation(value.into(), gix_hash::Kind::Sha1)?;
+ Ok(())
+ }
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/credential.rs b/vendor/gix/src/config/tree/sections/credential.rs
new file mode 100644
index 000000000..d370db0c5
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/credential.rs
@@ -0,0 +1,56 @@
+use crate::{
+ config,
+ config::tree::{keys, Credential, Key, Section},
+};
+
+impl Credential {
+ /// The `credential.helper` key.
+ pub const HELPER: keys::Program = keys::Program::new_program("helper", &config::Tree::CREDENTIAL);
+ /// The `credential.username` key.
+ pub const USERNAME: keys::Any = keys::Any::new("username", &config::Tree::CREDENTIAL);
+ /// The `credential.useHttpPath` key.
+ pub const USE_HTTP_PATH: keys::Boolean = keys::Boolean::new_boolean("useHttpPath", &config::Tree::CREDENTIAL);
+
+ /// The `credential.<url>` subsection
+ pub const URL_PARAMETER: UrlParameter = UrlParameter;
+}
+
+/// The `credential.<url>` parameter section.
+pub struct UrlParameter;
+
+impl UrlParameter {
+ /// The `credential.<url>.helper` key.
+ pub const HELPER: keys::Program = keys::Program::new_program("helper", &Credential::URL_PARAMETER);
+ /// The `credential.<url>.username` key.
+ pub const USERNAME: keys::Any = keys::Any::new("username", &Credential::URL_PARAMETER);
+ /// The `credential.<url>.useHttpPath` key.
+ pub const USE_HTTP_PATH: keys::Boolean = keys::Boolean::new_boolean("useHttpPath", &Credential::URL_PARAMETER);
+}
+
+impl Section for UrlParameter {
+ fn name(&self) -> &str {
+ "<url>"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::HELPER, &Self::USERNAME, &Self::USE_HTTP_PATH]
+ }
+
+ fn parent(&self) -> Option<&dyn Section> {
+ Some(&config::Tree::CREDENTIAL)
+ }
+}
+
+impl Section for Credential {
+ fn name(&self) -> &str {
+ "credential"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::HELPER, &Self::USERNAME, &Self::USE_HTTP_PATH]
+ }
+
+ fn sub_sections(&self) -> &[&dyn Section] {
+ &[&Self::URL_PARAMETER]
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/diff.rs b/vendor/gix/src/config/tree/sections/diff.rs
new file mode 100644
index 000000000..103bb7001
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/diff.rs
@@ -0,0 +1,133 @@
+use crate::{
+ config,
+ config::tree::{keys, Diff, Key, Section},
+};
+
+impl Diff {
+ /// The `diff.algorithm` key.
+ pub const ALGORITHM: Algorithm = Algorithm::new_with_validate("algorithm", &config::Tree::DIFF, validate::Algorithm)
+ .with_deviation("'patience' diff is not implemented and can default to 'histogram' if lenient config is used, and defaults to histogram if unset for fastest and best results");
+ /// The `diff.renameLimit` key.
+ pub const RENAME_LIMIT: keys::UnsignedInteger = keys::UnsignedInteger::new_unsigned_integer(
+ "renameLimit",
+ &config::Tree::DIFF,
+ )
+ .with_note(
+ "The limit is actually squared, so 1000 stands for up to 1 million diffs if fuzzy rename tracking is enabled",
+ );
+ /// The `diff.renames` key.
+ pub const RENAMES: Renames = Renames::new_renames("renames", &config::Tree::DIFF);
+}
+
+impl Section for Diff {
+ fn name(&self) -> &str {
+ "diff"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::ALGORITHM, &Self::RENAME_LIMIT, &Self::RENAMES]
+ }
+}
+
+/// The `diff.algorithm` key.
+pub type Algorithm = keys::Any<validate::Algorithm>;
+
+/// The `diff.renames` key.
+pub type Renames = keys::Any<validate::Renames>;
+
+mod algorithm {
+ use std::borrow::Cow;
+
+ use crate::{
+ bstr::BStr,
+ config,
+ config::{diff::algorithm::Error, tree::sections::diff::Algorithm},
+ };
+
+ impl Algorithm {
+ /// Derive the diff algorithm identified by `name`, case-insensitively.
+ pub fn try_into_algorithm(&self, name: Cow<'_, BStr>) -> Result<gix_diff::blob::Algorithm, Error> {
+ let algo = if name.eq_ignore_ascii_case(b"myers") || name.eq_ignore_ascii_case(b"default") {
+ gix_diff::blob::Algorithm::Myers
+ } else if name.eq_ignore_ascii_case(b"minimal") {
+ gix_diff::blob::Algorithm::MyersMinimal
+ } else if name.eq_ignore_ascii_case(b"histogram") {
+ gix_diff::blob::Algorithm::Histogram
+ } else if name.eq_ignore_ascii_case(b"patience") {
+ return Err(config::diff::algorithm::Error::Unimplemented {
+ name: name.into_owned(),
+ });
+ } else {
+ return Err(Error::Unknown {
+ name: name.into_owned(),
+ });
+ };
+ Ok(algo)
+ }
+ }
+}
+
+mod renames {
+ use std::borrow::Cow;
+
+ use crate::{
+ bstr::{BStr, ByteSlice},
+ config::{
+ key::GenericError,
+ tree::{keys, sections::diff::Renames, Section},
+ },
+ diff::rename::Tracking,
+ };
+
+ impl Renames {
+ /// Create a new instance.
+ pub const fn new_renames(name: &'static str, section: &'static dyn Section) -> Self {
+ keys::Any::new_with_validate(name, section, super::validate::Renames)
+ }
+ /// Try to convert the configuration into a valid rename tracking variant. Use `value` and if it's an error, call `value_string`
+ /// to try and interpret the key as string.
+ pub fn try_into_renames<'a>(
+ &'static self,
+ value: Result<bool, gix_config::value::Error>,
+ value_string: impl FnOnce() -> Option<Cow<'a, BStr>>,
+ ) -> Result<Tracking, GenericError> {
+ Ok(match value {
+ Ok(true) => Tracking::Renames,
+ Ok(false) => Tracking::Disabled,
+ Err(err) => {
+ let value = value_string().ok_or_else(|| GenericError::from(self))?;
+ match value.as_ref().as_bytes() {
+ b"copy" | b"copies" => Tracking::RenamesAndCopies,
+ _ => return Err(GenericError::from_value(self, value.into_owned()).with_source(err)),
+ }
+ }
+ })
+ }
+ }
+}
+
+mod validate {
+ use std::borrow::Cow;
+
+ use crate::{
+ bstr::BStr,
+ config::tree::{keys, Diff},
+ };
+
+ pub struct Algorithm;
+ impl keys::Validate for Algorithm {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ Diff::ALGORITHM.try_into_algorithm(value.into())?;
+ Ok(())
+ }
+ }
+
+ pub struct Renames;
+ impl keys::Validate for Renames {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ let boolean = gix_config::Boolean::try_from(value).map(|b| b.0);
+ Diff::RENAMES.try_into_renames(boolean, || Some(Cow::Borrowed(value)))?;
+ Ok(())
+ }
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/extensions.rs b/vendor/gix/src/config/tree/sections/extensions.rs
new file mode 100644
index 000000000..77130f804
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/extensions.rs
@@ -0,0 +1,59 @@
+use crate::{
+ config,
+ config::tree::{keys, Extensions, Key, Section},
+};
+
+impl Extensions {
+ /// The `extensions.worktreeConfig` key.
+ pub const WORKTREE_CONFIG: keys::Boolean = keys::Boolean::new_boolean("worktreeConfig", &config::Tree::EXTENSIONS);
+ /// The `extensions.objectFormat` key.
+ pub const OBJECT_FORMAT: ObjectFormat =
+ ObjectFormat::new_with_validate("objectFormat", &config::Tree::EXTENSIONS, validate::ObjectFormat).with_note(
+ "Support for SHA256 is prepared but not fully implemented yet. For now we abort when encountered",
+ );
+}
+
+/// The `core.checkStat` key.
+pub type ObjectFormat = keys::Any<validate::ObjectFormat>;
+
+mod object_format {
+ use std::borrow::Cow;
+
+ use crate::{bstr::BStr, config, config::tree::sections::extensions::ObjectFormat};
+
+ impl ObjectFormat {
+ pub fn try_into_object_format(
+ &'static self,
+ value: Cow<'_, BStr>,
+ ) -> Result<gix_hash::Kind, config::key::GenericErrorWithValue> {
+ if value.as_ref().eq_ignore_ascii_case(b"sha1") {
+ Ok(gix_hash::Kind::Sha1)
+ } else {
+ Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned()))
+ }
+ }
+ }
+}
+
+impl Section for Extensions {
+ fn name(&self) -> &str {
+ "extensions"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::OBJECT_FORMAT, &Self::WORKTREE_CONFIG]
+ }
+}
+
+mod validate {
+ use crate::{bstr::BStr, config::tree::keys};
+
+ pub struct ObjectFormat;
+
+ impl keys::Validate for ObjectFormat {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ super::Extensions::OBJECT_FORMAT.try_into_object_format(value.into())?;
+ Ok(())
+ }
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/gitoxide.rs b/vendor/gix/src/config/tree/sections/gitoxide.rs
new file mode 100644
index 000000000..8c3defd0b
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/gitoxide.rs
@@ -0,0 +1,363 @@
+use crate::config::tree::{keys, Gitoxide, Key, Section};
+
+impl Gitoxide {
+ /// The `gitoxide.allow` section.
+ pub const ALLOW: Allow = Allow;
+ /// The `gitoxide.author` section.
+ pub const AUTHOR: Author = Author;
+ /// The `gitoxide.commit` section.
+ pub const COMMIT: Commit = Commit;
+ /// The `gitoxide.committer` section.
+ pub const COMMITTER: Committer = Committer;
+ /// The `gitoxide.http` section.
+ pub const HTTP: Http = Http;
+ /// The `gitoxide.https` section.
+ pub const HTTPS: Https = Https;
+ /// The `gitoxide.objects` section.
+ pub const OBJECTS: Objects = Objects;
+ /// The `gitoxide.ssh` section.
+ pub const SSH: Ssh = Ssh;
+ /// The `gitoxide.user` section.
+ pub const USER: User = User;
+
+ /// The `gitoxide.userAgent` Key.
+ pub const USER_AGENT: keys::Any = keys::Any::new("userAgent", &config::Tree::GITOXIDE).with_note(
+ "The user agent presented on the git protocol layer, serving as fallback for when no `http.userAgent` is set",
+ );
+}
+
+impl Section for Gitoxide {
+ fn name(&self) -> &str {
+ "gitoxide"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::USER_AGENT]
+ }
+
+ fn sub_sections(&self) -> &[&dyn Section] {
+ &[
+ &Self::ALLOW,
+ &Self::AUTHOR,
+ &Self::COMMIT,
+ &Self::COMMITTER,
+ &Self::HTTP,
+ &Self::HTTPS,
+ &Self::OBJECTS,
+ &Self::SSH,
+ &Self::USER,
+ ]
+ }
+}
+
+mod subsections {
+ use crate::config::{
+ tree::{http, keys, Gitoxide, Key, Section},
+ Tree,
+ };
+
+ /// The `Http` sub-section.
+ #[derive(Copy, Clone, Default)]
+ pub struct Http;
+
+ impl Http {
+ /// The `gitoxide.http.proxy` key.
+ pub const PROXY: keys::String =
+ keys::String::new_string("proxy", &Gitoxide::HTTP).with_environment_override("http_proxy");
+ /// The `gitoxide.http.allProxy` key.
+ pub const ALL_PROXY: keys::String = keys::String::new_string("allProxy", &Gitoxide::HTTP)
+ .with_environment_override("all_proxy")
+ .with_note("fallback environment is `ALL_PROXY`");
+ /// The `gitoxide.http.verbose` key.
+ ///
+ /// If set, curl will be configured to log verbosely.
+ pub const VERBOSE: keys::Boolean = keys::Boolean::new_boolean("verbose", &Gitoxide::HTTP)
+ .with_environment_override("GIT_CURL_VERBOSE")
+ .with_deviation("we parse it as boolean for convenience (infallible) but git only checks the presence");
+ /// The `gitoxide.http.noProxy` key.
+ pub const NO_PROXY: keys::String = keys::String::new_string("noProxy", &Gitoxide::HTTP)
+ .with_environment_override("no_proxy")
+ .with_note("fallback environment is `NO_PROXY`");
+ /// The `gitoxide.http.connectTimeout` key.
+ pub const CONNECT_TIMEOUT: keys::DurationInMilliseconds =
+ keys::DurationInMilliseconds::new_duration("connectTimeout", &Gitoxide::HTTP).with_note(
+ "entirely new, and in milliseconds, to describe how long to wait until a connection attempt is aborted",
+ );
+ /// The `gitoxide.http.sslVersionMin` key.
+ pub const SSL_VERSION_MIN: http::SslVersion =
+ http::SslVersion::new_ssl_version("sslVersionMin", &Gitoxide::HTTP).with_note(
+ "entirely new to set the lower bound for the allowed ssl version range. Overwrites the min bound of `http.sslVersion` if set. Min and Max must be set to become effective.",
+ );
+ /// The `gitoxide.http.sslVersionMax` key.
+ pub const SSL_VERSION_MAX: http::SslVersion =
+ http::SslVersion::new_ssl_version("sslVersionMax", &Gitoxide::HTTP).with_note(
+ "entirely new to set the upper bound for the allowed ssl version range. Overwrites the max bound of `http.sslVersion` if set. Min and Max must be set to become effective.",
+ );
+ /// The `gitoxide.http.proxyAuthMethod` key.
+ pub const PROXY_AUTH_METHOD: http::ProxyAuthMethod =
+ http::ProxyAuthMethod::new_proxy_auth_method("proxyAuthMethod", &Gitoxide::HTTP)
+ .with_environment_override("GIT_HTTP_PROXY_AUTHMETHOD");
+ }
+
+ impl Section for Http {
+ fn name(&self) -> &str {
+ "http"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[
+ &Self::PROXY,
+ &Self::ALL_PROXY,
+ &Self::VERBOSE,
+ &Self::NO_PROXY,
+ &Self::CONNECT_TIMEOUT,
+ &Self::SSL_VERSION_MIN,
+ &Self::SSL_VERSION_MAX,
+ &Self::PROXY_AUTH_METHOD,
+ ]
+ }
+
+ fn parent(&self) -> Option<&dyn Section> {
+ Some(&Tree::GITOXIDE)
+ }
+ }
+
+ /// The `Https` sub-section.
+ #[derive(Copy, Clone, Default)]
+ pub struct Https;
+
+ impl Https {
+ /// The `gitoxide.https.proxy` key.
+ pub const PROXY: keys::String = keys::String::new_string("proxy", &Gitoxide::HTTPS)
+ .with_environment_override("HTTPS_PROXY")
+ .with_note("fallback environment variable is `https_proxy`");
+ }
+
+ impl Section for Https {
+ fn name(&self) -> &str {
+ "https"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::PROXY]
+ }
+
+ fn parent(&self) -> Option<&dyn Section> {
+ Some(&Tree::GITOXIDE)
+ }
+ }
+
+ /// The `allow` sub-section.
+ #[derive(Copy, Clone, Default)]
+ pub struct Allow;
+
+ /// The `gitoxide.allow.protocolFromUser` key.
+ pub type ProtocolFromUser = keys::Any<super::validate::ProtocolFromUser>;
+
+ impl Allow {
+ /// The `gitoxide.allow.protocolFromUser` key.
+ pub const PROTOCOL_FROM_USER: ProtocolFromUser = ProtocolFromUser::new_with_validate(
+ "protocolFromUser",
+ &Gitoxide::ALLOW,
+ super::validate::ProtocolFromUser,
+ )
+ .with_environment_override("GIT_PROTOCOL_FROM_USER");
+ }
+
+ impl Section for Allow {
+ fn name(&self) -> &str {
+ "allow"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::PROTOCOL_FROM_USER]
+ }
+
+ fn parent(&self) -> Option<&dyn Section> {
+ Some(&Tree::GITOXIDE)
+ }
+ }
+
+ /// The `author` sub-section.
+ #[derive(Copy, Clone, Default)]
+ pub struct Author;
+
+ impl Author {
+ /// The `gitoxide.author.nameFallback` key.
+ pub const NAME_FALLBACK: keys::Any =
+ keys::Any::new("nameFallback", &Gitoxide::AUTHOR).with_environment_override("GIT_AUTHOR_NAME");
+ /// The `gitoxide.author.emailFallback` key.
+ pub const EMAIL_FALLBACK: keys::Any =
+ keys::Any::new("emailFallback", &Gitoxide::AUTHOR).with_environment_override("GIT_AUTHOR_EMAIL");
+ }
+
+ impl Section for Author {
+ fn name(&self) -> &str {
+ "author"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::NAME_FALLBACK, &Self::EMAIL_FALLBACK]
+ }
+
+ fn parent(&self) -> Option<&dyn Section> {
+ Some(&Tree::GITOXIDE)
+ }
+ }
+
+ /// The `user` sub-section.
+ #[derive(Copy, Clone, Default)]
+ pub struct User;
+
+ impl User {
+ /// The `gitoxide.user.emailFallback` key.
+ pub const EMAIL_FALLBACK: keys::Any =
+ keys::Any::new("emailFallback", &Gitoxide::USER).with_environment_override("EMAIL");
+ }
+
+ impl Section for User {
+ fn name(&self) -> &str {
+ "user"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::EMAIL_FALLBACK]
+ }
+
+ fn parent(&self) -> Option<&dyn Section> {
+ Some(&Tree::GITOXIDE)
+ }
+ }
+
+ /// The `ssh` sub-section.
+ #[derive(Copy, Clone, Default)]
+ pub struct Ssh;
+
+ impl Ssh {
+ /// The `gitoxide.ssh.commandWithoutShellFallback` key.
+ pub const COMMAND_WITHOUT_SHELL_FALLBACK: keys::Executable =
+ keys::Executable::new_executable("commandWithoutShellFallback", &Gitoxide::SSH)
+ .with_environment_override("GIT_SSH")
+ .with_note("is always executed without shell and treated as fallback");
+ }
+
+ impl Section for Ssh {
+ fn name(&self) -> &str {
+ "ssh"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::COMMAND_WITHOUT_SHELL_FALLBACK]
+ }
+
+ fn parent(&self) -> Option<&dyn Section> {
+ Some(&Tree::GITOXIDE)
+ }
+ }
+
+ /// The `objects` sub-section.
+ #[derive(Copy, Clone, Default)]
+ pub struct Objects;
+
+ impl Objects {
+ /// The `gitoxide.objects.cacheLimit` key.
+ pub const CACHE_LIMIT: keys::UnsignedInteger =
+ keys::UnsignedInteger::new_unsigned_integer("cacheLimit", &Gitoxide::OBJECTS)
+ .with_note("If unset or 0, there is no object cache")
+ .with_environment_override("GITOXIDE_OBJECT_CACHE_MEMORY");
+ /// The `gitoxide.objects.noReplace` key.
+ pub const NO_REPLACE: keys::Boolean = keys::Boolean::new_boolean("noReplace", &Gitoxide::OBJECTS)
+ .with_environment_override("GIT_NO_REPLACE_OBJECTS");
+ /// The `gitoxide.objects.replaceRefBase` key.
+ pub const REPLACE_REF_BASE: keys::Any =
+ keys::Any::new("replaceRefBase", &Gitoxide::OBJECTS).with_environment_override("GIT_REPLACE_REF_BASE");
+ }
+
+ impl Section for Objects {
+ fn name(&self) -> &str {
+ "objects"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::CACHE_LIMIT, &Self::NO_REPLACE, &Self::REPLACE_REF_BASE]
+ }
+
+ fn parent(&self) -> Option<&dyn Section> {
+ Some(&Tree::GITOXIDE)
+ }
+ }
+
+ /// The `committer` sub-section.
+ #[derive(Copy, Clone, Default)]
+ pub struct Committer;
+
+ impl Committer {
+ /// The `gitoxide.committer.nameFallback` key.
+ pub const NAME_FALLBACK: keys::Any =
+ keys::Any::new("nameFallback", &Gitoxide::COMMITTER).with_environment_override("GIT_COMMITTER_NAME");
+ /// The `gitoxide.committer.emailFallback` key.
+ pub const EMAIL_FALLBACK: keys::Any =
+ keys::Any::new("emailFallback", &Gitoxide::COMMITTER).with_environment_override("GIT_COMMITTER_EMAIL");
+ }
+
+ impl Section for Committer {
+ fn name(&self) -> &str {
+ "committer"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::NAME_FALLBACK, &Self::EMAIL_FALLBACK]
+ }
+
+ fn parent(&self) -> Option<&dyn Section> {
+ Some(&Tree::GITOXIDE)
+ }
+ }
+
+ /// The `commit` sub-section.
+ #[derive(Copy, Clone, Default)]
+ pub struct Commit;
+
+ impl Commit {
+ /// The `gitoxide.commit.authorDate` key.
+ pub const AUTHOR_DATE: keys::Time =
+ keys::Time::new_time("authorDate", &Gitoxide::COMMIT).with_environment_override("GIT_AUTHOR_DATE");
+ /// The `gitoxide.commit.committerDate` key.
+ pub const COMMITTER_DATE: keys::Time =
+ keys::Time::new_time("committerDate", &Gitoxide::COMMIT).with_environment_override("GIT_COMMITTER_DATE");
+ }
+
+ impl Section for Commit {
+ fn name(&self) -> &str {
+ "commit"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[]
+ }
+
+ fn parent(&self) -> Option<&dyn Section> {
+ Some(&Tree::GITOXIDE)
+ }
+ }
+}
+
+pub mod validate {
+ use std::error::Error;
+
+ use crate::{bstr::BStr, config::tree::keys::Validate};
+
+ pub struct ProtocolFromUser;
+ impl Validate for ProtocolFromUser {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ if value != "1" {
+ return Err("GIT_PROTOCOL_FROM_USER is either unset or as the value '1'".into());
+ }
+ Ok(())
+ }
+ }
+}
+
+pub use subsections::{Allow, Author, Commit, Committer, Http, Https, Objects, Ssh, User};
+
+use crate::config;
diff --git a/vendor/gix/src/config/tree/sections/http.rs b/vendor/gix/src/config/tree/sections/http.rs
new file mode 100644
index 000000000..f45c37076
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/http.rs
@@ -0,0 +1,317 @@
+use crate::{
+ config,
+ config::tree::{keys, Http, Key, Section},
+};
+
+impl Http {
+ /// The `http.sslVersion` key.
+ pub const SSL_VERSION: SslVersion = SslVersion::new_ssl_version("sslVersion", &config::Tree::HTTP)
+ .with_environment_override("GIT_SSL_VERSION")
+ .with_deviation(
+ "accepts the new 'default' value which means to use the curl default just like the empty string does",
+ );
+ /// The `http.proxy` key.
+ pub const PROXY: keys::String =
+ keys::String::new_string("proxy", &config::Tree::HTTP).with_deviation("fails on strings with illformed UTF-8");
+ /// The `http.proxyAuthMethod` key.
+ pub const PROXY_AUTH_METHOD: ProxyAuthMethod =
+ ProxyAuthMethod::new_proxy_auth_method("proxyAuthMethod", &config::Tree::HTTP)
+ .with_deviation("implemented like git, but never actually tried");
+ /// The `http.version` key.
+ pub const VERSION: Version = Version::new_with_validate("version", &config::Tree::HTTP, validate::Version)
+ .with_deviation("fails on illformed UTF-8");
+ /// The `http.userAgent` key.
+ pub const USER_AGENT: keys::String =
+ keys::String::new_string("userAgent", &config::Tree::HTTP).with_deviation("fails on illformed UTF-8");
+ /// The `http.extraHeader` key.
+ pub const EXTRA_HEADER: ExtraHeader =
+ ExtraHeader::new_with_validate("extraHeader", &config::Tree::HTTP, validate::ExtraHeader)
+ .with_deviation("fails on illformed UTF-8, without leniency");
+ /// The `http.followRedirects` key.
+ pub const FOLLOW_REDIRECTS: FollowRedirects =
+ FollowRedirects::new_with_validate("followRedirects", &config::Tree::HTTP, validate::FollowRedirects);
+ /// The `http.lowSpeedTime` key.
+ pub const LOW_SPEED_TIME: keys::UnsignedInteger =
+ keys::UnsignedInteger::new_unsigned_integer("lowSpeedTime", &config::Tree::HTTP)
+ .with_deviation("fails on negative values");
+ /// The `http.lowSpeedLimit` key.
+ pub const LOW_SPEED_LIMIT: keys::UnsignedInteger =
+ keys::UnsignedInteger::new_unsigned_integer("lowSpeedLimit", &config::Tree::HTTP)
+ .with_deviation("fails on negative values");
+ /// The `http.schannelUseSSLCAInfo` key.
+ pub const SCHANNEL_USE_SSL_CA_INFO: keys::Boolean =
+ keys::Boolean::new_boolean("schannelUseSSLCAInfo", &config::Tree::HTTP)
+ .with_deviation("only used as switch internally to turn off using the sslCAInfo, unconditionally. If unset, it has no effect, whereas in `git` it defaults to false.");
+ /// The `http.sslCAInfo` key.
+ pub const SSL_CA_INFO: keys::Path =
+ keys::Path::new_path("sslCAInfo", &config::Tree::HTTP).with_environment_override("GIT_SSL_CAINFO");
+ /// The `http.schannelCheckRevoke` key.
+ pub const SCHANNEL_CHECK_REVOKE: keys::Boolean =
+ keys::Boolean::new_boolean("schannelCheckRevoke", &config::Tree::HTTP);
+}
+
+impl Section for Http {
+ fn name(&self) -> &str {
+ "http"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[
+ &Self::SSL_VERSION,
+ &Self::PROXY,
+ &Self::PROXY_AUTH_METHOD,
+ &Self::VERSION,
+ &Self::USER_AGENT,
+ &Self::EXTRA_HEADER,
+ &Self::FOLLOW_REDIRECTS,
+ &Self::LOW_SPEED_TIME,
+ &Self::LOW_SPEED_LIMIT,
+ &Self::SCHANNEL_USE_SSL_CA_INFO,
+ &Self::SSL_CA_INFO,
+ &Self::SCHANNEL_CHECK_REVOKE,
+ ]
+ }
+}
+
+/// The `http.followRedirects` key.
+pub type FollowRedirects = keys::Any<validate::FollowRedirects>;
+
+/// The `http.extraHeader` key.
+pub type ExtraHeader = keys::Any<validate::ExtraHeader>;
+
+/// The `http.sslVersion` key, as well as others of the same type.
+pub type SslVersion = keys::Any<validate::SslVersion>;
+
+/// The `http.proxyAuthMethod` key, as well as others of the same type.
+pub type ProxyAuthMethod = keys::Any<validate::ProxyAuthMethod>;
+
+/// The `http.version` key.
+pub type Version = keys::Any<validate::Version>;
+
+mod key_impls {
+ use crate::config::tree::{
+ http::{ProxyAuthMethod, SslVersion},
+ keys, Section,
+ };
+
+ impl SslVersion {
+ pub const fn new_ssl_version(name: &'static str, section: &'static dyn Section) -> Self {
+ keys::Any::new_with_validate(name, section, super::validate::SslVersion)
+ }
+ }
+
+ impl ProxyAuthMethod {
+ pub const fn new_proxy_auth_method(name: &'static str, section: &'static dyn Section) -> Self {
+ keys::Any::new_with_validate(name, section, super::validate::ProxyAuthMethod)
+ }
+ }
+
+ #[cfg(any(
+ feature = "blocking-http-transport-reqwest",
+ feature = "blocking-http-transport-curl"
+ ))]
+ impl crate::config::tree::http::FollowRedirects {
+ /// Convert `value` into the redirect specification, or query the same value as `boolean`
+ /// for additional possible input values.
+ ///
+ /// Note that `boolean` only queries the underlying key as boolean, which is a necessity to handle
+ /// empty booleans correctly, that is those without a value separator.
+ pub fn try_into_follow_redirects(
+ &'static self,
+ value: std::borrow::Cow<'_, crate::bstr::BStr>,
+ boolean: impl FnOnce() -> Result<Option<bool>, gix_config::value::Error>,
+ ) -> Result<
+ crate::protocol::transport::client::http::options::FollowRedirects,
+ crate::config::key::GenericErrorWithValue,
+ > {
+ use crate::{bstr::ByteSlice, protocol::transport::client::http::options::FollowRedirects};
+ Ok(if value.as_ref().as_bytes() == b"initial" {
+ FollowRedirects::Initial
+ } else if let Some(value) = boolean().map_err(|err| {
+ crate::config::key::GenericErrorWithValue::from_value(self, value.into_owned()).with_source(err)
+ })? {
+ if value {
+ FollowRedirects::All
+ } else {
+ FollowRedirects::None
+ }
+ } else {
+ FollowRedirects::Initial
+ })
+ }
+ }
+
+ impl super::ExtraHeader {
+ /// Convert a list of values into extra-headers, while failing entirely on illformed UTF-8.
+ pub fn try_into_extra_header(
+ &'static self,
+ values: Vec<std::borrow::Cow<'_, crate::bstr::BStr>>,
+ ) -> Result<Vec<String>, crate::config::string::Error> {
+ let mut out = Vec::with_capacity(values.len());
+ for value in values {
+ if value.is_empty() {
+ out.clear();
+ } else {
+ out.push(self.try_into_string(value)?);
+ }
+ }
+ Ok(out)
+ }
+ }
+
+ #[cfg(any(
+ feature = "blocking-http-transport-reqwest",
+ feature = "blocking-http-transport-curl"
+ ))]
+ impl super::Version {
+ pub fn try_into_http_version(
+ &'static self,
+ value: std::borrow::Cow<'_, crate::bstr::BStr>,
+ ) -> Result<
+ gix_protocol::transport::client::http::options::HttpVersion,
+ crate::config::key::GenericErrorWithValue,
+ > {
+ use gix_protocol::transport::client::http::options::HttpVersion;
+
+ use crate::bstr::ByteSlice;
+ Ok(match value.as_ref().as_bytes() {
+ b"HTTP/1.1" => HttpVersion::V1_1,
+ b"HTTP/2" => HttpVersion::V2,
+ _ => {
+ return Err(crate::config::key::GenericErrorWithValue::from_value(
+ self,
+ value.into_owned(),
+ ))
+ }
+ })
+ }
+ }
+
+ #[cfg(any(
+ feature = "blocking-http-transport-reqwest",
+ feature = "blocking-http-transport-curl"
+ ))]
+ impl ProxyAuthMethod {
+ pub fn try_into_proxy_auth_method(
+ &'static self,
+ value: std::borrow::Cow<'_, crate::bstr::BStr>,
+ ) -> Result<
+ gix_protocol::transport::client::http::options::ProxyAuthMethod,
+ crate::config::key::GenericErrorWithValue,
+ > {
+ use gix_protocol::transport::client::http::options::ProxyAuthMethod;
+
+ use crate::bstr::ByteSlice;
+ Ok(match value.as_ref().as_bytes() {
+ b"anyauth" => ProxyAuthMethod::AnyAuth,
+ b"basic" => ProxyAuthMethod::Basic,
+ b"digest" => ProxyAuthMethod::Digest,
+ b"negotiate" => ProxyAuthMethod::Negotiate,
+ b"ntlm" => ProxyAuthMethod::Ntlm,
+ _ => {
+ return Err(crate::config::key::GenericErrorWithValue::from_value(
+ self,
+ value.into_owned(),
+ ))
+ }
+ })
+ }
+ }
+
+ #[cfg(any(
+ feature = "blocking-http-transport-reqwest",
+ feature = "blocking-http-transport-curl"
+ ))]
+ impl SslVersion {
+ pub fn try_into_ssl_version(
+ &'static self,
+ value: std::borrow::Cow<'_, crate::bstr::BStr>,
+ ) -> Result<gix_protocol::transport::client::http::options::SslVersion, crate::config::ssl_version::Error>
+ {
+ use gix_protocol::transport::client::http::options::SslVersion::*;
+
+ use crate::bstr::ByteSlice;
+ Ok(match value.as_ref().as_bytes() {
+ b"default" | b"" => Default,
+ b"tlsv1" => TlsV1,
+ b"sslv2" => SslV2,
+ b"sslv3" => SslV3,
+ b"tlsv1.0" => TlsV1_0,
+ b"tlsv1.1" => TlsV1_1,
+ b"tlsv1.2" => TlsV1_2,
+ b"tlsv1.3" => TlsV1_3,
+ _ => return Err(crate::config::ssl_version::Error::from_value(self, value.into_owned())),
+ })
+ }
+ }
+}
+
+pub mod validate {
+ use std::error::Error;
+
+ use crate::{
+ bstr::{BStr, ByteSlice},
+ config::tree::keys::Validate,
+ };
+
+ pub struct SslVersion;
+ impl Validate for SslVersion {
+ fn validate(&self, _value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ #[cfg(any(
+ feature = "blocking-http-transport-reqwest",
+ feature = "blocking-http-transport-curl"
+ ))]
+ super::Http::SSL_VERSION.try_into_ssl_version(std::borrow::Cow::Borrowed(_value))?;
+
+ Ok(())
+ }
+ }
+
+ pub struct ProxyAuthMethod;
+ impl Validate for ProxyAuthMethod {
+ fn validate(&self, _value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ #[cfg(any(
+ feature = "blocking-http-transport-reqwest",
+ feature = "blocking-http-transport-curl"
+ ))]
+ super::Http::PROXY_AUTH_METHOD.try_into_proxy_auth_method(std::borrow::Cow::Borrowed(_value))?;
+
+ Ok(())
+ }
+ }
+
+ pub struct Version;
+ impl Validate for Version {
+ fn validate(&self, _value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ #[cfg(any(
+ feature = "blocking-http-transport-reqwest",
+ feature = "blocking-http-transport-curl"
+ ))]
+ super::Http::VERSION.try_into_http_version(std::borrow::Cow::Borrowed(_value))?;
+
+ Ok(())
+ }
+ }
+
+ pub struct ExtraHeader;
+ impl Validate for ExtraHeader {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ value.to_str()?;
+ Ok(())
+ }
+ }
+
+ pub struct FollowRedirects;
+ impl Validate for FollowRedirects {
+ fn validate(&self, _value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ #[cfg(any(
+ feature = "blocking-http-transport-reqwest",
+ feature = "blocking-http-transport-curl"
+ ))]
+ super::Http::FOLLOW_REDIRECTS.try_into_follow_redirects(std::borrow::Cow::Borrowed(_value), || {
+ gix_config::Boolean::try_from(_value).map(|b| Some(b.0))
+ })?;
+ Ok(())
+ }
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/init.rs b/vendor/gix/src/config/tree/sections/init.rs
new file mode 100644
index 000000000..de42d3b62
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/init.rs
@@ -0,0 +1,20 @@
+use crate::{
+ config,
+ config::tree::{keys, Init, Key, Section},
+};
+
+impl Init {
+ /// The `init.defaultBranch` key.
+ pub const DEFAULT_BRANCH: keys::Any = keys::Any::new("defaultBranch", &config::Tree::INIT)
+ .with_deviation("If not set, we use `main` instead of `master`");
+}
+
+impl Section for Init {
+ fn name(&self) -> &str {
+ "init"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::DEFAULT_BRANCH]
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/mod.rs b/vendor/gix/src/config/tree/sections/mod.rs
new file mode 100644
index 000000000..fb9b50786
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/mod.rs
@@ -0,0 +1,96 @@
+#![allow(missing_docs)]
+
+/// The `author` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Author;
+mod author;
+
+/// The `branch` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Branch;
+pub mod branch;
+
+/// The `checkout` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Checkout;
+pub mod checkout;
+
+/// The `clone` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Clone;
+mod clone;
+
+/// The `committer` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Committer;
+mod committer;
+
+/// The `core` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Core;
+pub mod core;
+
+/// The `credential` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Credential;
+pub mod credential;
+
+/// The `diff` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Diff;
+pub mod diff;
+
+/// The `extension` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Extensions;
+pub mod extensions;
+
+/// The `gitoxide` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Gitoxide;
+pub mod gitoxide;
+
+/// The `http` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Http;
+pub mod http;
+
+/// The `init` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Init;
+mod init;
+
+/// The `pack` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Pack;
+pub mod pack;
+
+/// The `protocol` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Protocol;
+pub mod protocol;
+
+/// The `remote` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Remote;
+pub mod remote;
+
+/// The `safe` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Safe;
+mod safe;
+
+/// The `ssh` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Ssh;
+pub mod ssh;
+
+/// The `user` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct User;
+mod user;
+
+/// The `url` top-level section.
+#[derive(Copy, Clone, Default)]
+pub struct Url;
+mod url;
diff --git a/vendor/gix/src/config/tree/sections/pack.rs b/vendor/gix/src/config/tree/sections/pack.rs
new file mode 100644
index 000000000..941817e5b
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/pack.rs
@@ -0,0 +1,64 @@
+use crate::{
+ config,
+ config::tree::{keys, Key, Pack, Section},
+};
+
+impl Pack {
+ /// The `pack.threads` key.
+ pub const THREADS: keys::UnsignedInteger =
+ keys::UnsignedInteger::new_unsigned_integer("threads", &config::Tree::PACK)
+ .with_deviation("Leaving this key unspecified uses all available cores, instead of 1");
+
+ /// The `pack.indexVersion` key.
+ pub const INDEX_VERSION: IndexVersion =
+ IndexVersion::new_with_validate("indexVersion", &config::Tree::PACK, validate::IndexVersion);
+}
+
+/// The `pack.indexVersion` key.
+pub type IndexVersion = keys::Any<validate::IndexVersion>;
+
+mod index_version {
+ use crate::{config, config::tree::sections::pack::IndexVersion};
+
+ impl IndexVersion {
+ /// Try to interpret an integer value as index version.
+ pub fn try_into_index_version(
+ &'static self,
+ value: Result<i64, gix_config::value::Error>,
+ ) -> Result<gix_pack::index::Version, config::key::GenericError> {
+ let value = value.map_err(|err| config::key::GenericError::from(self).with_source(err))?;
+ Ok(match value {
+ 1 => gix_pack::index::Version::V1,
+ 2 => gix_pack::index::Version::V2,
+ _ => return Err(config::key::GenericError::from(self)),
+ })
+ }
+ }
+}
+
+impl Section for Pack {
+ fn name(&self) -> &str {
+ "pack"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::THREADS, &Self::INDEX_VERSION]
+ }
+}
+
+mod validate {
+ use crate::{bstr::BStr, config::tree::keys};
+
+ pub struct IndexVersion;
+ impl keys::Validate for IndexVersion {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ super::Pack::INDEX_VERSION.try_into_index_version(gix_config::Integer::try_from(value).and_then(
+ |int| {
+ int.to_decimal()
+ .ok_or_else(|| gix_config::value::Error::new("integer out of range", value))
+ },
+ ))?;
+ Ok(())
+ }
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/protocol.rs b/vendor/gix/src/config/tree/sections/protocol.rs
new file mode 100644
index 000000000..58e907b0f
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/protocol.rs
@@ -0,0 +1,85 @@
+use crate::{
+ config,
+ config::tree::{keys, Key, Protocol, Section},
+};
+
+impl Protocol {
+ /// The `protocol.allow` key.
+ pub const ALLOW: Allow = Allow::new_with_validate("allow", &config::Tree::PROTOCOL, validate::Allow);
+
+ /// The `protocol.<name>` subsection
+ pub const NAME_PARAMETER: NameParameter = NameParameter;
+}
+
+/// The `protocol.allow` key type.
+pub type Allow = keys::Any<validate::Allow>;
+
+#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
+mod allow {
+ use std::borrow::Cow;
+
+ use crate::{bstr::BStr, config, config::tree::protocol::Allow, remote::url::scheme_permission};
+
+ impl Allow {
+ /// Convert `value` into its respective `Allow` variant, possibly informing about the `scheme` we are looking at in the error.
+ pub fn try_into_allow(
+ &'static self,
+ value: Cow<'_, BStr>,
+ scheme: Option<&str>,
+ ) -> Result<scheme_permission::Allow, config::protocol::allow::Error> {
+ scheme_permission::Allow::try_from(value).map_err(|value| config::protocol::allow::Error {
+ value,
+ scheme: scheme.map(ToOwned::to_owned),
+ })
+ }
+ }
+}
+
+/// The `protocol.<name>` parameter section.
+pub struct NameParameter;
+
+impl NameParameter {
+ /// The `credential.<url>.helper` key.
+ pub const ALLOW: Allow = Allow::new_with_validate("allow", &Protocol::NAME_PARAMETER, validate::Allow);
+}
+
+impl Section for NameParameter {
+ fn name(&self) -> &str {
+ "<name>"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::ALLOW]
+ }
+
+ fn parent(&self) -> Option<&dyn Section> {
+ Some(&config::Tree::PROTOCOL)
+ }
+}
+
+impl Section for Protocol {
+ fn name(&self) -> &str {
+ "protocol"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::ALLOW]
+ }
+
+ fn sub_sections(&self) -> &[&dyn Section] {
+ &[&Self::NAME_PARAMETER]
+ }
+}
+
+mod validate {
+ use crate::{bstr::BStr, config::tree::keys};
+
+ pub struct Allow;
+ impl keys::Validate for Allow {
+ fn validate(&self, _value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ #[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
+ super::Protocol::ALLOW.try_into_allow(std::borrow::Cow::Borrowed(_value), None)?;
+ Ok(())
+ }
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/remote.rs b/vendor/gix/src/config/tree/sections/remote.rs
new file mode 100644
index 000000000..b242c9c14
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/remote.rs
@@ -0,0 +1,101 @@
+use crate::{
+ config,
+ config::tree::{http, keys, Key, Remote, Section, SubSectionRequirement},
+};
+
+const NAME_PARAMETER: Option<SubSectionRequirement> = Some(SubSectionRequirement::Parameter("name"));
+
+impl Remote {
+ /// The `remote.pushDefault` key
+ pub const PUSH_DEFAULT: keys::RemoteName = keys::RemoteName::new_remote_name("pushDefault", &config::Tree::REMOTE);
+ /// The `remote.<name>.tagOpt` key
+ pub const TAG_OPT: TagOpt = TagOpt::new_with_validate("tagOpt", &config::Tree::REMOTE, validate::TagOpt)
+ .with_subsection_requirement(Some(SubSectionRequirement::Parameter("name")));
+ /// The `remote.<name>.url` key
+ pub const URL: keys::Url =
+ keys::Url::new_url("url", &config::Tree::REMOTE).with_subsection_requirement(NAME_PARAMETER);
+ /// The `remote.<name>.pushUrl` key
+ pub const PUSH_URL: keys::Url =
+ keys::Url::new_url("pushUrl", &config::Tree::REMOTE).with_subsection_requirement(NAME_PARAMETER);
+ /// The `remote.<name>.fetch` key
+ pub const FETCH: keys::FetchRefSpec = keys::FetchRefSpec::new_fetch_refspec("fetch", &config::Tree::REMOTE)
+ .with_subsection_requirement(NAME_PARAMETER);
+ /// The `remote.<name>.push` key
+ pub const PUSH: keys::PushRefSpec =
+ keys::PushRefSpec::new_push_refspec("push", &config::Tree::REMOTE).with_subsection_requirement(NAME_PARAMETER);
+ /// The `remote.<name>.proxy` key
+ pub const PROXY: keys::String =
+ keys::String::new_string("proxy", &config::Tree::REMOTE).with_subsection_requirement(NAME_PARAMETER);
+ /// The `remote.<name>.proxyAuthMethod` key.
+ pub const PROXY_AUTH_METHOD: http::ProxyAuthMethod =
+ http::ProxyAuthMethod::new_proxy_auth_method("proxyAuthMethod", &config::Tree::REMOTE)
+ .with_subsection_requirement(NAME_PARAMETER)
+ .with_deviation("implemented like git, but never actually tried");
+}
+
+impl Section for Remote {
+ fn name(&self) -> &str {
+ "remote"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[
+ &Self::PUSH_DEFAULT,
+ &Self::TAG_OPT,
+ &Self::URL,
+ &Self::PUSH_URL,
+ &Self::FETCH,
+ &Self::PUSH,
+ &Self::PROXY,
+ &Self::PROXY_AUTH_METHOD,
+ ]
+ }
+}
+
+/// The `remote.<name>.tagOpt` key type.
+pub type TagOpt = keys::Any<validate::TagOpt>;
+
+mod tag_opts {
+ use std::borrow::Cow;
+
+ use crate::{
+ bstr::{BStr, ByteSlice},
+ config,
+ config::tree::remote::TagOpt,
+ remote,
+ };
+
+ impl TagOpt {
+ /// Try to interpret `value` as tag option.
+ ///
+ /// # Note
+ ///
+ /// It's heavily biased towards the git command-line unfortunately, and the only
+ /// value of its kind. Maybe in future more values will be supported which are less
+ /// about passing them to a sub-process.
+ pub fn try_into_tag_opt(
+ &'static self,
+ value: Cow<'_, BStr>,
+ ) -> Result<remote::fetch::Tags, config::key::GenericErrorWithValue> {
+ Ok(match value.as_ref().as_bytes() {
+ b"--tags" => remote::fetch::Tags::All,
+ b"--no-tags" => remote::fetch::Tags::None,
+ _ => return Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned())),
+ })
+ }
+ }
+}
+
+pub mod validate {
+ use std::{borrow::Cow, error::Error};
+
+ use crate::{bstr::BStr, config::tree::keys::Validate};
+
+ pub struct TagOpt;
+ impl Validate for TagOpt {
+ fn validate(&self, value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ super::Remote::TAG_OPT.try_into_tag_opt(Cow::Borrowed(value))?;
+ Ok(())
+ }
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/safe.rs b/vendor/gix/src/config/tree/sections/safe.rs
new file mode 100644
index 000000000..e76d28888
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/safe.rs
@@ -0,0 +1,27 @@
+use crate::{
+ config,
+ config::tree::{keys, Key, Safe, Section},
+};
+
+impl Safe {
+ /// The `safe.directory` key
+ pub const DIRECTORY: keys::Any = keys::Any::new("directory", &config::Tree::SAFE);
+}
+
+impl Safe {
+ /// Implements the directory filter to trust only global and system files, for use with `safe.directory`.
+ pub fn directory_filter(meta: &gix_config::file::Metadata) -> bool {
+ let kind = meta.source.kind();
+ kind == gix_config::source::Kind::System || kind == gix_config::source::Kind::Global
+ }
+}
+
+impl Section for Safe {
+ fn name(&self) -> &str {
+ "safe"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::DIRECTORY]
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/ssh.rs b/vendor/gix/src/config/tree/sections/ssh.rs
new file mode 100644
index 000000000..600ee663b
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/ssh.rs
@@ -0,0 +1,65 @@
+use crate::{
+ config,
+ config::tree::{keys, Key, Section, Ssh},
+};
+
+impl Ssh {
+ /// The `ssh.variant` key
+ pub const VARIANT: Variant = Variant::new_with_validate("variant", &config::Tree::SSH, validate::Variant)
+ .with_environment_override("GIT_SSH_VARIANT")
+ .with_deviation("We error if a variant is chosen that we don't know, as opposed to defaulting to 'ssh'");
+}
+
+/// The `ssh.variant` key.
+pub type Variant = keys::Any<validate::Variant>;
+
+#[cfg(feature = "blocking-network-client")]
+mod variant {
+ use std::borrow::Cow;
+
+ use crate::{bstr::BStr, config, config::tree::ssh::Variant};
+
+ impl Variant {
+ pub fn try_into_variant(
+ &'static self,
+ value: Cow<'_, BStr>,
+ ) -> Result<Option<gix_protocol::transport::client::ssh::ProgramKind>, config::key::GenericErrorWithValue>
+ {
+ use gix_protocol::transport::client::ssh::ProgramKind;
+
+ use crate::bstr::ByteSlice;
+ Ok(Some(match value.as_ref().as_bytes() {
+ b"auto" => return Ok(None),
+ b"ssh" => ProgramKind::Ssh,
+ b"plink" => ProgramKind::Plink,
+ b"putty" => ProgramKind::Putty,
+ b"tortoiseplink" => ProgramKind::TortoisePlink,
+ b"simple" => ProgramKind::Simple,
+ _ => return Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned())),
+ }))
+ }
+ }
+}
+
+impl Section for Ssh {
+ fn name(&self) -> &str {
+ "ssh"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::VARIANT]
+ }
+}
+
+mod validate {
+ use crate::{bstr::BStr, config::tree::keys};
+
+ pub struct Variant;
+ impl keys::Validate for Variant {
+ fn validate(&self, _value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+ #[cfg(feature = "blocking-network-client")]
+ super::Ssh::VARIANT.try_into_variant(_value.into())?;
+ Ok(())
+ }
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/url.rs b/vendor/gix/src/config/tree/sections/url.rs
new file mode 100644
index 000000000..6a9c0bfdb
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/url.rs
@@ -0,0 +1,25 @@
+use crate::{
+ config,
+ config::tree::{keys, Key, Section, SubSectionRequirement, Url},
+};
+
+const BASE_PARAMETER: Option<SubSectionRequirement> = Some(SubSectionRequirement::Parameter("base"));
+
+impl Url {
+ /// The `url.<base>.insteadOf` key
+ pub const INSTEAD_OF: keys::Any =
+ keys::Any::new("insteadOf", &config::Tree::URL).with_subsection_requirement(BASE_PARAMETER);
+ /// The `url.<base>.pushInsteadOf` key
+ pub const PUSH_INSTEAD_OF: keys::Any =
+ keys::Any::new("pushInsteadOf", &config::Tree::URL).with_subsection_requirement(BASE_PARAMETER);
+}
+
+impl Section for Url {
+ fn name(&self) -> &str {
+ "url"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::INSTEAD_OF, &Self::PUSH_INSTEAD_OF]
+ }
+}
diff --git a/vendor/gix/src/config/tree/sections/user.rs b/vendor/gix/src/config/tree/sections/user.rs
new file mode 100644
index 000000000..d1f4f7102
--- /dev/null
+++ b/vendor/gix/src/config/tree/sections/user.rs
@@ -0,0 +1,22 @@
+use crate::{
+ config,
+ config::tree::{gitoxide, keys, Key, Section, User},
+};
+
+impl User {
+ /// The `user.name` key
+ pub const NAME: keys::Any = keys::Any::new("name", &config::Tree::USER);
+ /// The `user.email` key
+ pub const EMAIL: keys::Any =
+ keys::Any::new("email", &config::Tree::USER).with_fallback(&gitoxide::User::EMAIL_FALLBACK);
+}
+
+impl Section for User {
+ fn name(&self) -> &str {
+ "user"
+ }
+
+ fn keys(&self) -> &[&dyn Key] {
+ &[&Self::NAME, &Self::EMAIL]
+ }
+}
diff --git a/vendor/gix/src/config/tree/traits.rs b/vendor/gix/src/config/tree/traits.rs
new file mode 100644
index 000000000..7cfd7aac4
--- /dev/null
+++ b/vendor/gix/src/config/tree/traits.rs
@@ -0,0 +1,199 @@
+use crate::{
+ bstr::{BStr, BString, ByteVec},
+ config::tree::key::validate_assignment,
+};
+
+/// Provide information about a configuration section.
+pub trait Section {
+ /// The section name, like `remote` in `remote.origin.url`.
+ fn name(&self) -> &str;
+ /// The keys directly underneath it for carrying configuration values.
+ fn keys(&self) -> &[&dyn Key];
+ /// The list of sub-section names, which may be empty if there are no statically known sub-sections.
+ fn sub_sections(&self) -> &[&dyn Section] {
+ &[]
+ }
+ /// The parent section if this is a statically known sub-section.
+ fn parent(&self) -> Option<&dyn Section> {
+ None
+ }
+}
+
+/// Determine how subsections may be used with a given key, suitable for obtaining the full name for use in assignments.
+#[derive(Debug, Copy, Clone)]
+pub enum SubSectionRequirement {
+ /// Subsections must not be used, this key can only be below a section.
+ Never,
+ /// The sub-section is used as parameter with the given name.
+ Parameter(&'static str),
+}
+
+/// A way to link a key with other resources.
+#[derive(Debug, Copy, Clone)]
+pub enum Link {
+ /// The environment variable of the given name will override the value of this key.
+ EnvironmentOverride(&'static str),
+ /// This config key is used as fallback if this key isn't set.
+ FallbackKey(&'static dyn Key),
+}
+
+/// A note attached to a key.
+#[derive(Debug, Copy, Clone)]
+pub enum Note {
+ /// A piece of information related to a key to help the user.
+ Informative(&'static str),
+ /// This key works differently than is described by git, explaining the deviation further.
+ Deviation(&'static str),
+}
+
+/// A leaf-level entry in the git configuration, like `url` in `remote.origin.url`.
+pub trait Key: std::fmt::Debug {
+ /// The key's name, like `url` in `remote.origin.url`.
+ fn name(&self) -> &str;
+ /// See if `value` is allowed as value of this key, or return a descriptive error if it is not.
+ fn validate(&self, value: &BStr) -> Result<(), crate::config::tree::key::validate::Error>;
+ /// The section containing this key. Git configuration has no free-standing keys, they are always underneath a section.
+ fn section(&self) -> &dyn Section;
+ /// The return value encodes three possible states to indicate subsection requirements
+ /// * `None` = subsections may or may not be used, the most flexible setting.
+ /// * `Some([Requirement][SubSectionRequirement])` = subsections must or must not be used, depending on the value
+ fn subsection_requirement(&self) -> Option<&SubSectionRequirement> {
+ Some(&SubSectionRequirement::Never)
+ }
+ /// Return the link to other resources, if available.
+ fn link(&self) -> Option<&Link> {
+ None
+ }
+ /// Return a note about this key, if available.
+ fn note(&self) -> Option<&Note> {
+ None
+ }
+
+ /// Return the name of an environment variable that would override this value (after following links until one is found).
+ fn environment_override(&self) -> Option<&str> {
+ let mut cursor = self.link()?;
+ loop {
+ match cursor {
+ Link::EnvironmentOverride(name) => return Some(name),
+ Link::FallbackKey(next) => {
+ cursor = next.link()?;
+ }
+ }
+ }
+ }
+
+ /// Return the environment override that must be set on this key.
+ /// # Panics
+ /// If no environment variable is set
+ fn the_environment_override(&self) -> &str {
+ self.environment_override()
+ .expect("BUG: environment override must be set")
+ }
+ /// Produce a name that describes how the name is composed. This is `core.bare` for statically known keys, or `branch.<name>.key`
+ /// for complex ones.
+ fn logical_name(&self) -> String {
+ let section = self.section();
+ let mut buf = String::new();
+ let parameter = if let Some(parent) = section.parent() {
+ buf.push_str(parent.name());
+ buf.push('.');
+ None
+ } else {
+ self.subsection_requirement().and_then(|requirement| match requirement {
+ SubSectionRequirement::Parameter(name) => Some(name),
+ SubSectionRequirement::Never => None,
+ })
+ };
+ buf.push_str(section.name());
+ buf.push('.');
+ if let Some(parameter) = parameter {
+ buf.push('<');
+ buf.push_str(parameter);
+ buf.push('>');
+ buf.push('.');
+ }
+ buf.push_str(self.name());
+ buf
+ }
+
+ /// The full name of the key for use in configuration overrides, like `core.bare`, or `remote.<subsection>.url` if `subsection` is
+ /// not `None`.
+ /// May fail if this key needs a subsection, or may not have a subsection.
+ fn full_name(&self, subsection: Option<&BStr>) -> Result<BString, String> {
+ let section = self.section();
+ let mut buf = BString::default();
+ let subsection = match self.subsection_requirement() {
+ None => subsection,
+ Some(requirement) => match (requirement, subsection) {
+ (SubSectionRequirement::Never, Some(_)) => {
+ return Err(format!(
+ "The key named '{}' cannot be used with non-static subsections.",
+ self.logical_name()
+ ));
+ }
+ (SubSectionRequirement::Parameter(_), None) => {
+ return Err(format!(
+ "The key named '{}' cannot be used without subsections.",
+ self.logical_name()
+ ))
+ }
+ _ => subsection,
+ },
+ };
+
+ if let Some(parent) = section.parent() {
+ buf.push_str(parent.name());
+ buf.push(b'.');
+ }
+ buf.push_str(section.name());
+ buf.push(b'.');
+ if let Some(subsection) = subsection {
+ debug_assert!(
+ section.parent().is_none(),
+ "BUG: sections with parameterized sub-sections must be top-level sections"
+ );
+ buf.push_str(subsection);
+ buf.push(b'.');
+ }
+ buf.push_str(self.name());
+ Ok(buf)
+ }
+
+ /// Return an assignment with the keys full name to `value`, suitable for [configuration overrides][crate::open::Options::config_overrides()].
+ /// Note that this will fail if the key requires a subsection name.
+ fn validated_assignment(&self, value: &BStr) -> Result<BString, validate_assignment::Error> {
+ self.validate(value)?;
+ let mut key = self
+ .full_name(None)
+ .map_err(|message| validate_assignment::Error::Name { message })?;
+ key.push(b'=');
+ key.push_str(value);
+ Ok(key)
+ }
+
+ /// Return an assignment with the keys full name to `value`, suitable for [configuration overrides][crate::open::Options::config_overrides()].
+ /// Note that this will fail if the key requires a subsection name.
+ fn validated_assignment_fmt(
+ &self,
+ value: &dyn std::fmt::Display,
+ ) -> Result<BString, crate::config::tree::key::validate_assignment::Error> {
+ let value = value.to_string();
+ self.validated_assignment(value.as_str().into())
+ }
+
+ /// Return an assignment to `value` with the keys full name within `subsection`, suitable for [configuration overrides][crate::open::Options::config_overrides()].
+ /// Note that this is only valid if this key supports parameterized sub-sections, or else an error is returned.
+ fn validated_assignment_with_subsection(
+ &self,
+ value: &BStr,
+ subsection: &BStr,
+ ) -> Result<BString, crate::config::tree::key::validate_assignment::Error> {
+ self.validate(value)?;
+ let mut key = self
+ .full_name(Some(subsection))
+ .map_err(|message| validate_assignment::Error::Name { message })?;
+ key.push(b'=');
+ key.push_str(value);
+ Ok(key)
+ }
+}