summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/config/cache/init.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix/src/config/cache/init.rs')
-rw-r--r--vendor/gix/src/config/cache/init.rs485
1 files changed, 485 insertions, 0 deletions
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(())
+}