From c23a457e72abe608715ac76f076f47dc42af07a5 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 20:31:44 +0200 Subject: Merging upstream version 1.74.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/gix/src/config/cache/access.rs | 200 ++++++++++++----- vendor/gix/src/config/cache/incubate.rs | 4 +- vendor/gix/src/config/cache/init.rs | 58 ++++- vendor/gix/src/config/cache/util.rs | 36 ++- vendor/gix/src/config/mod.rs | 60 ++++- vendor/gix/src/config/overrides.rs | 12 +- vendor/gix/src/config/snapshot/access.rs | 54 ++++- .../gix/src/config/snapshot/credential_helpers.rs | 4 +- vendor/gix/src/config/snapshot/mod.rs | 1 + vendor/gix/src/config/tree/keys.rs | 2 +- vendor/gix/src/config/tree/mod.rs | 8 +- vendor/gix/src/config/tree/sections/core.rs | 249 +++++++++++++++++++-- vendor/gix/src/config/tree/sections/diff.rs | 21 +- vendor/gix/src/config/tree/sections/fetch.rs | 81 +++++-- vendor/gix/src/config/tree/sections/gitoxide.rs | 62 ++++- vendor/gix/src/config/tree/sections/index.rs | 5 +- vendor/gix/src/config/tree/sections/mod.rs | 2 + vendor/gix/src/config/tree/sections/protocol.rs | 2 +- 18 files changed, 725 insertions(+), 136 deletions(-) (limited to 'vendor/gix/src/config') diff --git a/vendor/gix/src/config/cache/access.rs b/vendor/gix/src/config/cache/access.rs index cea56f973..352bc9712 100644 --- a/vendor/gix/src/config/cache/access.rs +++ b/vendor/gix/src/config/cache/access.rs @@ -1,16 +1,15 @@ #![allow(clippy::result_large_err)] use std::{borrow::Cow, path::PathBuf, time::Duration}; -use gix_attributes::Source; use gix_lock::acquire::Fail; use crate::{ bstr::BStr, config, config::{ - cache::util::{ApplyLeniency, ApplyLeniencyDefault}, - checkout_options, - tree::{gitoxide, Checkout, Core, Key}, + boolean, + cache::util::{ApplyLeniency, ApplyLeniencyDefaultValue}, + tree::{Core, Key}, Cache, }, remote, @@ -19,7 +18,9 @@ use crate::{ /// Access impl Cache { + #[cfg(feature = "blob-diff")] pub(crate) fn diff_algorithm(&self) -> Result { + use crate::config::cache::util::ApplyLeniencyDefault; use crate::config::diff::algorithm::Error; self.diff_algorithm .get_or_try_init(|| { @@ -69,6 +70,18 @@ impl Cache { .get_or_try_init(|| remote::url::SchemePermission::from_config(&self.resolved, self.filter_config_section)) } + pub(crate) fn may_use_commit_graph(&self) -> Result { + const DEFAULT: bool = true; + self.resolved + .boolean_by_key("core.commitGraph") + .map_or(Ok(DEFAULT), |res| { + Core::COMMIT_GRAPH + .enrich_error(res) + .with_lenient_default_value(self.lenient_config, DEFAULT) + }) + } + + #[cfg(feature = "blob-diff")] pub(crate) fn diff_renames( &self, ) -> Result, crate::object::tree::diff::rewrites::Error> { @@ -100,9 +113,10 @@ impl Cache { } /// The path to the user-level excludes file to ignore certain files in the worktree. + #[cfg(feature = "excludes")] pub(crate) fn excludes_file(&self) -> Option> { self.trusted_file_path("core", None, Core::EXCLUDES_FILE.name)? - .map(|p| p.into_owned()) + .map(std::borrow::Cow::into_owned) .into() } @@ -123,7 +137,7 @@ impl Cache { 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()); + let ctx = config::cache::interpolate_context(install_dir.as_deref(), home.as_deref()); Some(path.interpolate(ctx)) } @@ -131,80 +145,108 @@ impl Cache { res.transpose().with_leniency(self.lenient_config) } + pub(crate) fn fs_capabilities(&self) -> Result { + Ok(gix_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)?, + }) + } + + #[cfg(feature = "index")] + pub(crate) fn stat_options(&self) -> Result { + use crate::config::tree::gitoxide; + Ok(gix_index::entry::stat::Options { + trust_ctime: boolean( + self, + "core.trustCTime", + &Core::TRUST_C_TIME, + // For now, on MacOS it's known to not be trust-worthy at least with the Rust STDlib, being 2s off + !cfg!(target_os = "macos"), + )?, + use_nsec: boolean(self, "gitoxide.core.useNsec", &gitoxide::Core::USE_NSEC, false)?, + use_stdev: boolean(self, "gitoxide.core.useStdev", &gitoxide::Core::USE_STDEV, false)?, + check_stat: self + .apply_leniency( + self.resolved + .string("core", None, "checkStat") + .map(|v| Core::CHECK_STAT.try_into_checkstat(v)), + )? + .unwrap_or(true), + }) + } + /// 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. + #[cfg(feature = "worktree-mutation")] pub(crate) fn checkout_options( &self, - git_dir: &std::path::Path, - ) -> Result { - fn boolean( - me: &Cache, - full_key: &str, - key: &'static config::tree::keys::Boolean, - default: bool, - ) -> Result { - 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)) - } - + repo: &crate::Repository, + attributes_source: gix_worktree::stack::state::attributes::Source, + ) -> Result { + use crate::config::tree::gitoxide; + let git_dir = repo.git_dir(); 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)), + .map(|value| crate::config::tree::Checkout::WORKERS.try_from_workers(value)), )?; - let capabilities = gix_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)?, + let capabilities = self.fs_capabilities()?; + let filters = { + let collection = Default::default(); + let mut filters = gix_filter::Pipeline::new(&collection, crate::filter::Pipeline::options(repo)?); + if let Ok(mut head) = repo.head() { + let ctx = filters.driver_context_mut(); + ctx.ref_name = head.referent_name().map(|name| name.as_bstr().to_owned()); + ctx.treeish = head.peel_to_commit_in_place().ok().map(|commit| commit.id); + } + filters + }; + let filter_process_delay = if boolean( + self, + "gitoxide.core.filterProcessDelay", + &gitoxide::Core::FILTER_PROCESS_DELAY, + true, + )? { + gix_filter::driver::apply::Delay::Allow + } else { + gix_filter::driver::apply::Delay::Forbid }; - Ok(gix_worktree::checkout::Options { + Ok(gix_worktree_state::checkout::Options { + filter_process_delay, + filters, attributes: self - .assemble_attribute_globals( - git_dir, - gix_worktree::cache::state::attributes::Source::IdMappingThenWorktree, - self.attributes, - )? + .assemble_attribute_globals(git_dir, attributes_source, self.attributes)? .0, fs: capabilities, thread_limit, destination_is_initially_empty: false, overwrite_existing: false, keep_going: false, - stat_options: gix_index::entry::stat::Options { - trust_ctime: boolean(self, "core.trustCTime", &Core::TRUST_C_TIME, true)?, - use_nsec: boolean(self, "gitoxide.core.useNsec", &gitoxide::Core::USE_NSEC, false)?, - use_stdev: boolean(self, "gitoxide.core.useStdev", &gitoxide::Core::USE_STDEV, false)?, - check_stat: self - .apply_leniency( - self.resolved - .string("core", None, "checkStat") - .map(|v| Core::CHECK_STAT.try_into_checkstat(v)), - )? - .unwrap_or(true), - }, + stat_options: self.stat_options().map_err(|err| match err { + config::stat_options::Error::ConfigCheckStat(err) => { + config::checkout_options::Error::ConfigCheckStat(err) + } + config::stat_options::Error::ConfigBoolean(err) => config::checkout_options::Error::ConfigBoolean(err), + })?, }) } + #[cfg(feature = "excludes")] pub(crate) fn assemble_exclude_globals( &self, git_dir: &std::path::Path, overrides: Option, - source: gix_worktree::cache::state::ignore::Source, + source: gix_worktree::stack::state::ignore::Source, buf: &mut Vec, - ) -> Result { + ) -> Result { let excludes_file = match self.excludes_file().transpose()? { Some(user_path) => Some(user_path), None => self.xdg_config_path("ignore")?, }; - Ok(gix_worktree::cache::state::Ignore::new( + Ok(gix_worktree::stack::state::Ignore::new( overrides.unwrap_or_default(), gix_ignore::Search::from_git_dir(git_dir, excludes_file, buf)?, None, @@ -212,12 +254,14 @@ impl Cache { )) } // TODO: at least one test, maybe related to core.attributesFile configuration. + #[cfg(feature = "attributes")] pub(crate) fn assemble_attribute_globals( &self, git_dir: &std::path::Path, - source: gix_worktree::cache::state::attributes::Source, + source: gix_worktree::stack::state::attributes::Source, attributes: crate::open::permissions::Attributes, - ) -> Result<(gix_worktree::cache::state::Attributes, Vec), config::attribute_stack::Error> { + ) -> Result<(gix_worktree::stack::state::Attributes, Vec), config::attribute_stack::Error> { + use gix_attributes::Source; let configured_or_user_attributes = match self .trusted_file_path("core", None, Core::ATTRIBUTES_FILE.name) .transpose()? @@ -243,15 +287,45 @@ impl Cache { let info_attributes_path = git_dir.join("info").join("attributes"); let mut buf = Vec::new(); let mut collection = gix_attributes::search::MetadataCollection::default(); - let res = gix_worktree::cache::state::Attributes::new( + let state = gix_worktree::stack::state::Attributes::new( gix_attributes::Search::new_globals(attribute_files, &mut buf, &mut collection)?, Some(info_attributes_path), source, collection, ); - Ok((res, buf)) + Ok((state, buf)) } + #[cfg(feature = "attributes")] + pub(crate) fn pathspec_defaults( + &self, + ) -> Result { + use crate::config::tree::gitoxide; + let res = gix_pathspec::Defaults::from_environment(&mut |name| { + let key = [ + &gitoxide::Pathspec::ICASE, + &gitoxide::Pathspec::GLOB, + &gitoxide::Pathspec::NOGLOB, + &gitoxide::Pathspec::LITERAL, + ] + .iter() + .find_map(|key| (key.environment_override().expect("set") == name).then_some(key)) + .expect("we must know all possible input variable names"); + + let val = self + .resolved + .string("gitoxide", Some("pathspec".into()), key.name()) + .map(gix_path::from_bstr)?; + Some(val.into_owned().into()) + }); + if res.is_err() && self.lenient_config { + Ok(gix_pathspec::Defaults::default()) + } else { + res + } + } + + #[cfg(any(feature = "attributes", feature = "excludes"))] pub(crate) fn xdg_config_path( &self, resource_file_name: &str, @@ -284,3 +358,19 @@ impl Cache { gix_path::env::home_dir().and_then(|path| self.environment.home.check_opt(path)) } } + +fn boolean( + me: &Cache, + full_key: &str, + key: &'static config::tree::keys::Boolean, + default: bool, +) -> Result { + 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)) +} diff --git a/vendor/gix/src/config/cache/incubate.rs b/vendor/gix/src/config/cache/incubate.rs index 44c537b50..cf7c5dcdf 100644 --- a/vendor/gix/src/config/cache/incubate.rs +++ b/vendor/gix/src/config/cache/incubate.rs @@ -102,7 +102,7 @@ fn load_config( path: config_path, }; if lenient { - log::warn!("ignoring: {err:#?}"); + gix_trace::warn!("ignoring: {err:#?}"); return Ok(gix_config::File::new(metadata)); } else { return Err(err); @@ -117,7 +117,7 @@ fn load_config( path: config_path, }; if lenient { - log::warn!("ignoring: {err:#?}"); + gix_trace::warn!("ignoring: {err:#?}"); buf.clear(); } else { return Err(err); diff --git a/vendor/gix/src/config/cache/init.rs b/vendor/gix/src/config/cache/init.rs index 6fcbcc4ec..3c482b154 100644 --- a/vendor/gix/src/config/cache/init.rs +++ b/vendor/gix/src/config/cache/init.rs @@ -13,6 +13,7 @@ use crate::{ Cache, }, open, + repository::init::setup_objects, }; /// Initialization @@ -71,7 +72,7 @@ impl Cache { let config = { let git_prefix = &git_prefix; - let metas = [ + let mut metas = [ gix_config::source::Kind::GitInstallation, gix_config::source::Kind::System, gix_config::source::Kind::Global, @@ -99,7 +100,7 @@ impl Cache { let err_on_nonexisting_paths = false; let mut globals = gix_config::File::from_paths_metadata_buf( - metas, + &mut metas, &mut buf, err_on_nonexisting_paths, gix_config::file::init::Options { @@ -150,6 +151,7 @@ impl Cache { true, lenient_config, )?; + #[cfg(feature = "revision")] let object_kind_hint = util::disambiguate_hint(&config, lenient_config)?; let (static_pack_cache_limit_bytes, pack_cache_bytes, object_cache_bytes) = util::parse_object_caches(&config, lenient_config, filter_config_section)?; @@ -158,6 +160,7 @@ impl Cache { resolved: config.into(), use_multi_pack_index, object_hash, + #[cfg(feature = "revision")] object_kind_hint, static_pack_cache_limit_bytes, pack_cache_bytes, @@ -173,9 +176,11 @@ impl Cache { user_agent: Default::default(), personas: Default::default(), url_rewrite: Default::default(), + #[cfg(feature = "blob-diff")] diff_renames: Default::default(), #[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))] url_scheme: Default::default(), + #[cfg(feature = "blob-diff")] diff_algorithm: Default::default(), }) } @@ -210,19 +215,26 @@ impl Cache { false, self.lenient_config, )?; - let object_kind_hint = util::disambiguate_hint(config, self.lenient_config)?; + + #[cfg(feature = "revision")] + { + let object_kind_hint = util::disambiguate_hint(config, self.lenient_config)?; + self.object_kind_hint = object_kind_hint; + } 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(); + #[cfg(feature = "blob-diff")] + { + self.diff_renames = Default::default(); + self.diff_algorithm = Default::default(); + } ( self.static_pack_cache_limit_bytes, self.pack_cache_bytes, @@ -268,8 +280,19 @@ impl crate::Repository { &mut self, config: crate::Config, ) -> Result<(), Error> { + let (a, b, c) = ( + self.config.static_pack_cache_limit_bytes, + self.config.pack_cache_bytes, + self.config.object_cache_bytes, + ); self.config.reread_values_and_clear_caches_replacing_config(config)?; self.apply_changed_values(); + if a != self.config.static_pack_cache_limit_bytes + || b != self.config.pack_cache_bytes + || c != self.config.object_cache_bytes + { + setup_objects(&mut self.objects, &self.config); + } Ok(()) } @@ -445,6 +468,29 @@ fn apply_environment_overrides( (env(key), key.name) }], ), + ( + "gitoxide", + Some(Cow::Borrowed("pathspec".into())), + git_prefix, + &[ + { + let key = &gitoxide::Pathspec::LITERAL; + (env(key), key.name) + }, + { + let key = &gitoxide::Pathspec::GLOB; + (env(key), key.name) + }, + { + let key = &gitoxide::Pathspec::NOGLOB; + (env(key), key.name) + }, + { + let key = &gitoxide::Pathspec::ICASE; + (env(key), key.name) + }, + ], + ), ( "ssh", None, diff --git a/vendor/gix/src/config/cache/util.rs b/vendor/gix/src/config/cache/util.rs index 7c478fcf9..4032b2cb1 100644 --- a/vendor/gix/src/config/cache/util.rs +++ b/vendor/gix/src/config/cache/util.rs @@ -3,7 +3,6 @@ use super::Error; use crate::{ config, config::tree::{gitoxide, Core}, - revision::spec::parse::ObjectKindHint, }; pub(crate) fn interpolate_context<'a>( @@ -51,7 +50,7 @@ pub(crate) fn query_refupdates( ) -> Result, Error> { let key = "core.logAllRefUpdates"; Core::LOG_ALL_REF_UPDATES - .try_into_ref_updates(config.boolean_by_key(key), || config.string_by_key(key)) + .try_into_ref_updates(config.boolean_by_key(key)) .with_leniency(lenient_config) .map_err(Into::into) } @@ -74,7 +73,7 @@ pub(crate) fn parse_object_caches( mut filter_config_section: fn(&gix_config::file::Metadata) -> bool, ) -> Result<(Option, Option, usize), Error> { let static_pack_cache_limit = config - .integer_filter_by_key("core.deltaBaseCacheLimit", &mut filter_config_section) + .integer_filter_by_key("gitoxide.core.deltaBaseCacheLimit", &mut filter_config_section) .map(|res| gitoxide::Core::DEFAULT_PACK_CACHE_MEMORY_LIMIT.try_into_usize(res)) .transpose() .with_leniency(lenient)?; @@ -103,10 +102,11 @@ pub(crate) fn parse_core_abbrev( .flatten()) } +#[cfg(feature = "revision")] pub(crate) fn disambiguate_hint( config: &gix_config::File<'static>, lenient_config: bool, -) -> Result, config::key::GenericErrorWithValue> { +) -> Result, config::key::GenericErrorWithValue> { match config.string_by_key("core.disambiguate") { None => Ok(None), Some(value) => Core::DISAMBIGUATE @@ -120,10 +120,18 @@ pub trait ApplyLeniency { fn with_leniency(self, is_lenient: bool) -> Self; } +pub trait IgnoreEmptyPath { + fn ignore_empty(self) -> Self; +} + pub trait ApplyLeniencyDefault { fn with_lenient_default(self, is_lenient: bool) -> Self; } +pub trait ApplyLeniencyDefaultValue { + fn with_lenient_default_value(self, is_lenient: bool, default: T) -> Self; +} + impl ApplyLeniency for Result, E> { fn with_leniency(self, is_lenient: bool) -> Self { match self { @@ -134,6 +142,16 @@ impl ApplyLeniency for Result, E> { } } +impl IgnoreEmptyPath for Result>, gix_config::path::interpolate::Error> { + fn ignore_empty(self) -> Self { + match self { + Ok(maybe_path) => Ok(maybe_path), + Err(gix_config::path::interpolate::Error::Missing { .. }) => Ok(None), + Err(err) => Err(err), + } + } +} + impl ApplyLeniencyDefault for Result where T: Default, @@ -146,3 +164,13 @@ where } } } + +impl ApplyLeniencyDefaultValue for Result { + fn with_lenient_default_value(self, is_lenient: bool, default: T) -> Self { + match self { + Ok(v) => Ok(v), + Err(_) if is_lenient => Ok(default), + Err(err) => Err(err), + } + } +} diff --git a/vendor/gix/src/config/mod.rs b/vendor/gix/src/config/mod.rs index 3353806f8..102c7a482 100644 --- a/vendor/gix/src/config/mod.rs +++ b/vendor/gix/src/config/mod.rs @@ -1,10 +1,11 @@ pub use gix_config::*; use gix_features::threading::OnceCell; -use crate::{bstr::BString, repository::identity, revision::spec, Repository}; +use crate::{bstr::BString, repository::identity, Repository}; pub(crate) mod cache; mod snapshot; +#[cfg(feature = "credentials")] pub use snapshot::credential_helpers; /// @@ -46,6 +47,23 @@ pub(crate) mod section { } } +/// +pub mod set_value { + /// The error produced when calling [`SnapshotMut::set(_subsection)?_value()`][crate::config::SnapshotMut::set_value()] + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error(transparent)] + SetRaw(#[from] gix_config::file::set_raw_value::Error), + #[error(transparent)] + Validate(#[from] crate::config::tree::key::validate::Error), + #[error("The key needs a subsection parameter to be valid.")] + SubSectionRequired, + #[error("The key must not be used with a subsection")] + SubSectionForbidden, + } +} + /// The error returned when failing to initialize the repository configuration. /// /// This configuration is on the critical path when opening a repository. @@ -102,6 +120,20 @@ pub mod diff { } /// +pub mod stat_options { + /// The error produced when collecting stat information, and returned by [Repository::stat_options()](crate::Repository::stat_options()). + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error(transparent)] + ConfigCheckStat(#[from] super::key::GenericErrorWithValue), + #[error(transparent)] + ConfigBoolean(#[from] super::boolean::Error), + } +} + +/// +#[cfg(feature = "attributes")] pub mod checkout_options { /// The error produced when collecting all information needed for checking out files into a worktree. #[derive(Debug, thiserror::Error)] @@ -115,6 +147,8 @@ pub mod checkout_options { CheckoutWorkers(#[from] super::checkout::workers::Error), #[error(transparent)] Attributes(#[from] super::attribute_stack::Error), + #[error(transparent)] + FilterPipelineOptions(#[from] crate::filter::pipeline::options::Error), } } @@ -274,6 +308,23 @@ pub mod key { pub type GenericErrorWithValue = Error; } +/// +pub mod encoding { + use crate::bstr::BString; + + /// The error produced when failing to parse the `core.checkRoundTripEncoding` key. + #[derive(Debug, thiserror::Error)] + #[error("The encoding named '{encoding}' seen in key '{key}={value}' is unsupported")] + pub struct Error { + /// The configuration key that contained the value. + pub key: BString, + /// The value that was assigned to `key`. + pub value: BString, + /// The encoding that failed. + pub encoding: BString, + } +} + /// pub mod checkout { /// @@ -424,6 +475,7 @@ pub mod transport { key: Cow<'static, BStr>, }, #[error("Could not configure the credential helpers for the authenticated proxy url")] + #[cfg(feature = "credentials")] ConfigureProxyAuthenticate(#[from] crate::config::snapshot::credential_helpers::Error), #[error(transparent)] InvalidSslVersion(#[from] crate::config::ssl_version::Error), @@ -459,11 +511,13 @@ pub(crate) struct Cache { /// A lazily loaded rewrite list for remote urls pub(crate) url_rewrite: OnceCell, /// The lazy-loaded rename information for diffs. + #[cfg(feature = "blob-diff")] pub(crate) diff_renames: OnceCell>, /// 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, /// The algorithm to use when diffing blobs + #[cfg(feature = "blob-diff")] pub(crate) diff_algorithm: OnceCell, /// 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. @@ -475,12 +529,14 @@ pub(crate) struct Cache { /// 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, + #[cfg(feature = "revision")] + pub object_kind_hint: Option, /// 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, + #[cfg_attr(not(feature = "worktree-mutation"), allow(dead_code))] attributes: crate::open::permissions::Attributes, environment: crate::open::permissions::Environment, // TODO: make core.precomposeUnicode available as well. diff --git a/vendor/gix/src/config/overrides.rs b/vendor/gix/src/config/overrides.rs index 4bdf4a13f..6b3fc728c 100644 --- a/vendor/gix/src/config/overrides.rs +++ b/vendor/gix/src/config/overrides.rs @@ -26,11 +26,15 @@ pub(crate) fn append( 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 mut tokens = key_value.splitn(2, |b| *b == b'=').map(ByteSlice::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 key = gix_config::parse::key( + key.to_str() + .map_err(|_| Error::InvalidKey { input: key.into() })? + .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 { @@ -38,7 +42,7 @@ pub(crate) fn append( key: key.value_name.into(), })?; let comment = make_comment(key_value); - let value = value.map(|v| v.as_bstr()); + let value = value.map(ByteSlice::as_bstr); match comment { Some(comment) => section.push_with_comment(key, value, &**comment), None => section.push(key, value), diff --git a/vendor/gix/src/config/snapshot/access.rs b/vendor/gix/src/config/snapshot/access.rs index 1710348a9..7dc593880 100644 --- a/vendor/gix/src/config/snapshot/access.rs +++ b/vendor/gix/src/config/snapshot/access.rs @@ -2,9 +2,11 @@ use std::borrow::Cow; use gix_features::threading::OwnShared; +use gix_macros::momo; +use crate::bstr::ByteSlice; use crate::{ - bstr::BStr, + bstr::{BStr, BString}, config::{CommitAutoRollback, Snapshot, SnapshotMut}, }; @@ -25,6 +27,7 @@ impl<'repo> Snapshot<'repo> { } /// Like [`boolean()`][Self::boolean()], but it will report an error if the value couldn't be interpreted as boolean. + #[momo] pub fn try_boolean<'a>(&self, key: impl Into<&'a BStr>) -> Option> { self.repo.config.resolved.boolean_by_key(key) } @@ -40,6 +43,7 @@ impl<'repo> Snapshot<'repo> { } /// Like [`integer()`][Self::integer()], but it will report an error if the value couldn't be interpreted as boolean. + #[momo] pub fn try_integer<'a>(&self, key: impl Into<&'a BStr>) -> Option> { self.repo.config.resolved.integer_by_key(key) } @@ -47,6 +51,7 @@ impl<'repo> Snapshot<'repo> { /// 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. + #[momo] pub fn string<'a>(&self, key: impl Into<&'a BStr>) -> Option> { self.repo.config.resolved.string_by_key(key) } @@ -54,11 +59,12 @@ impl<'repo> Snapshot<'repo> { /// 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. + #[momo] pub fn trusted_path<'a>( &self, key: impl Into<&'a BStr>, ) -> Option, gix_config::path::interpolate::Error>> { - let key = gix_config::parse::key(key)?; + let key = gix_config::parse::key(key.into())?; self.repo .config .trusted_file_path(key.section_name, key.subsection_name, key.value_name) @@ -99,6 +105,50 @@ impl<'repo> SnapshotMut<'repo> { self.commit_inner(repo) } + /// Set the value at `key` to `new_value`, possibly creating the section if it doesn't exist yet, or overriding the most recent existing + /// value, which will be returned. + #[momo] + pub fn set_value<'b>( + &mut self, + key: &'static dyn crate::config::tree::Key, + new_value: impl Into<&'b BStr>, + ) -> Result, crate::config::set_value::Error> { + if let Some(crate::config::tree::SubSectionRequirement::Parameter(_)) = key.subsection_requirement() { + return Err(crate::config::set_value::Error::SubSectionRequired); + } + let value = new_value.into(); + key.validate(value)?; + let current = self + .config + .set_raw_value(key.section().name(), None, key.name(), value)?; + Ok(current.map(std::borrow::Cow::into_owned)) + } + + /// Set the value at `key` to `new_value` in the given `subsection`, possibly creating the section and sub-section if it doesn't exist yet, + /// or overriding the most recent existing value, which will be returned. + #[momo] + pub fn set_subsection_value<'a, 'b>( + &mut self, + key: &'static dyn crate::config::tree::Key, + subsection: impl Into<&'a BStr>, + new_value: impl Into<&'b BStr>, + ) -> Result, crate::config::set_value::Error> { + if let Some(crate::config::tree::SubSectionRequirement::Never) = key.subsection_requirement() { + return Err(crate::config::set_value::Error::SubSectionForbidden); + } + let value = new_value.into(); + key.validate(value)?; + + let name = key + .full_name(Some(subsection.into())) + .expect("we know it needs a subsection"); + let key = gix_config::parse::key((**name).as_bstr()).expect("statically known keys can always be parsed"); + let current = + self.config + .set_raw_value(key.section_name, key.subsection_name, key.value_name.to_owned(), value)?; + Ok(current.map(std::borrow::Cow::into_owned)) + } + pub(crate) fn commit_inner( &mut self, repo: &'repo mut crate::Repository, diff --git a/vendor/gix/src/config/snapshot/credential_helpers.rs b/vendor/gix/src/config/snapshot/credential_helpers.rs index c4eef35d6..189e74471 100644 --- a/vendor/gix/src/config/snapshot/credential_helpers.rs +++ b/vendor/gix/src/config/snapshot/credential_helpers.rs @@ -2,6 +2,7 @@ use std::{borrow::Cow, convert::TryFrom}; pub use error::Error; +use crate::config::cache::util::IgnoreEmptyPath; use crate::{ bstr::{ByteSlice, ByteVec}, config::{ @@ -140,7 +141,8 @@ impl Snapshot<'_> { let prompt_options = gix_prompt::Options { askpass: self .trusted_path(Core::ASKPASS.logical_name().as_str()) - .transpose()? + .transpose() + .ignore_empty()? .map(|c| Cow::Owned(c.into_owned())), ..Default::default() } diff --git a/vendor/gix/src/config/snapshot/mod.rs b/vendor/gix/src/config/snapshot/mod.rs index 80ec6f948..de143ea1f 100644 --- a/vendor/gix/src/config/snapshot/mod.rs +++ b/vendor/gix/src/config/snapshot/mod.rs @@ -2,4 +2,5 @@ mod _impls; mod access; /// +#[cfg(feature = "credentials")] pub mod credential_helpers; diff --git a/vendor/gix/src/config/tree/keys.rs b/vendor/gix/src/config/tree/keys.rs index b03fa49c6..5a5257af5 100644 --- a/vendor/gix/src/config/tree/keys.rs +++ b/vendor/gix/src/config/tree/keys.rs @@ -464,7 +464,7 @@ mod remote_name { } } -/// Provide a way to validate a value, or decode a value from `gix-config`. +/// Provide a way to validate a value, or decode a value from `git-config`. pub trait Validate { /// Validate `value` or return an error. fn validate(&self, value: &BStr) -> Result<(), Box>; diff --git a/vendor/gix/src/config/tree/mod.rs b/vendor/gix/src/config/tree/mod.rs index 3f69ccb97..d8415154f 100644 --- a/vendor/gix/src/config/tree/mod.rs +++ b/vendor/gix/src/config/tree/mod.rs @@ -31,6 +31,7 @@ pub(crate) mod root { /// The `credential` section. pub const CREDENTIAL: sections::Credential = sections::Credential; /// The `diff` section. + #[cfg(feature = "blob-diff")] pub const DIFF: sections::Diff = sections::Diff; /// The `extensions` section. pub const EXTENSIONS: sections::Extensions = sections::Extensions; @@ -69,6 +70,7 @@ pub(crate) mod root { &Self::COMMITTER, &Self::CORE, &Self::CREDENTIAL, + #[cfg(feature = "blob-diff")] &Self::DIFF, &Self::EXTENSIONS, &Self::FETCH, @@ -90,10 +92,12 @@ pub(crate) mod root { mod sections; pub use sections::{ - branch, checkout, core, credential, diff, extensions, fetch, gitoxide, http, index, protocol, remote, ssh, Author, - Branch, Checkout, Clone, Committer, Core, Credential, Diff, Extensions, Fetch, Gitoxide, Http, Index, Init, Pack, + branch, checkout, core, credential, extensions, fetch, gitoxide, http, index, protocol, remote, ssh, Author, + Branch, Checkout, Clone, Committer, Core, Credential, Extensions, Fetch, Gitoxide, Http, Index, Init, Pack, Protocol, Remote, Safe, Ssh, Url, User, }; +#[cfg(feature = "blob-diff")] +pub use sections::{diff, Diff}; /// Generic value implementations for static instantiation. pub mod keys; diff --git a/vendor/gix/src/config/tree/sections/core.rs b/vendor/gix/src/config/tree/sections/core.rs index 93d2fcd01..ab3e2bab9 100644 --- a/vendor/gix/src/config/tree/sections/core.rs +++ b/vendor/gix/src/config/tree/sections/core.rs @@ -45,7 +45,8 @@ impl 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); + pub const TRUST_C_TIME: keys::Boolean = keys::Boolean::new_boolean("trustCTime", &config::Tree::CORE) + .with_deviation("Currently the default is false, instead of true, as it seems to be 2s off in tests"); /// The `core.worktree` key. pub const WORKTREE: keys::Any = keys::Any::new("worktree", &config::Tree::CORE) .with_environment_override("GIT_WORK_TREE") @@ -66,6 +67,24 @@ impl Core { /// The `core.useReplaceRefs` key. pub const USE_REPLACE_REFS: keys::Boolean = keys::Boolean::new_boolean("useReplaceRefs", &config::Tree::CORE) .with_environment_override("GIT_NO_REPLACE_OBJECTS"); + /// The `core.commitGraph` key. + pub const COMMIT_GRAPH: keys::Boolean = keys::Boolean::new_boolean("commitGraph", &config::Tree::CORE); + /// The `core.safecrlf` key. + #[cfg(feature = "attributes")] + pub const SAFE_CRLF: SafeCrlf = SafeCrlf::new_with_validate("safecrlf", &config::Tree::CORE, validate::SafeCrlf); + /// The `core.autocrlf` key. + #[cfg(feature = "attributes")] + pub const AUTO_CRLF: AutoCrlf = AutoCrlf::new_with_validate("autocrlf", &config::Tree::CORE, validate::AutoCrlf); + /// The `core.eol` key. + #[cfg(feature = "attributes")] + pub const EOL: Eol = Eol::new_with_validate("eol", &config::Tree::CORE, validate::Eol); + /// The `core.checkRoundTripEncoding` key. + #[cfg(feature = "attributes")] + pub const CHECK_ROUND_TRIP_ENCODING: CheckRoundTripEncoding = CheckRoundTripEncoding::new_with_validate( + "checkRoundTripEncoding", + &config::Tree::CORE, + validate::CheckRoundTripEncoding, + ); } impl Section for Core { @@ -96,6 +115,15 @@ impl Section for Core { &Self::ATTRIBUTES_FILE, &Self::SSH_COMMAND, &Self::USE_REPLACE_REFS, + &Self::COMMIT_GRAPH, + #[cfg(feature = "attributes")] + &Self::SAFE_CRLF, + #[cfg(feature = "attributes")] + &Self::AUTO_CRLF, + #[cfg(feature = "attributes")] + &Self::EOL, + #[cfg(feature = "attributes")] + &Self::CHECK_ROUND_TRIP_ENCODING, ] } } @@ -112,6 +140,154 @@ pub type LogAllRefUpdates = keys::Any; /// The `core.disambiguate` key. pub type Disambiguate = keys::Any; +#[cfg(feature = "attributes")] +mod filter { + use super::validate; + use crate::config::tree::keys; + + /// The `core.safecrlf` key. + pub type SafeCrlf = keys::Any; + + /// The `core.autocrlf` key. + pub type AutoCrlf = keys::Any; + + /// The `core.eol` key. + pub type Eol = keys::Any; + + /// The `core.checkRoundTripEncoding` key. + pub type CheckRoundTripEncoding = keys::Any; + + mod check_round_trip_encoding { + use std::borrow::Cow; + + use crate::{ + bstr::{BStr, ByteSlice}, + config, + config::tree::{core::CheckRoundTripEncoding, Key}, + }; + + impl CheckRoundTripEncoding { + /// Convert `value` into a list of encodings, which are either space or coma separated. Fail if an encoding is unknown. + /// If `None`, the default is returned. + pub fn try_into_encodings( + &'static self, + value: Option>, + ) -> Result, config::encoding::Error> { + Ok(match value { + None => vec![gix_filter::encoding::SHIFT_JIS], + Some(value) => { + let mut out = Vec::new(); + for encoding in value + .as_ref() + .split(|b| *b == b',' || *b == b' ') + .filter(|e| !e.trim().is_empty()) + { + out.push( + gix_filter::encoding::Encoding::for_label(encoding.trim()).ok_or_else(|| { + config::encoding::Error { + key: self.logical_name().into(), + value: value.as_ref().to_owned(), + encoding: encoding.into(), + } + })?, + ); + } + out + } + }) + } + } + } + + mod eol { + use std::borrow::Cow; + + use crate::{ + bstr::{BStr, ByteSlice}, + config, + config::tree::core::Eol, + }; + + impl Eol { + /// Convert `value` into the default end-of-line mode. + /// + /// ### Deviation + /// + /// git will allow any value and silently leaves it unset, we will fail if the value is not known. + pub fn try_into_eol( + &'static self, + value: Cow<'_, BStr>, + ) -> Result { + Ok(match value.to_str_lossy().as_ref() { + "lf" => gix_filter::eol::Mode::Lf, + "crlf" => gix_filter::eol::Mode::CrLf, + "native" => gix_filter::eol::Mode::default(), + _ => return Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned())), + }) + } + } + } + + mod safecrlf { + use std::borrow::Cow; + + use gix_filter::pipeline::CrlfRoundTripCheck; + + use crate::{bstr::BStr, config, config::tree::core::SafeCrlf}; + + impl SafeCrlf { + /// Convert `value` into the safe-crlf enumeration, if possible. + pub fn try_into_safecrlf( + &'static self, + value: Cow<'_, BStr>, + ) -> Result { + if value.as_ref() == "warn" { + return Ok(CrlfRoundTripCheck::Warn); + } + let value = gix_config::Boolean::try_from(value.as_ref()).map_err(|err| { + config::key::GenericErrorWithValue::from_value(self, value.into_owned()).with_source(err) + })?; + Ok(if value.into() { + CrlfRoundTripCheck::Fail + } else { + CrlfRoundTripCheck::Skip + }) + } + } + } + + mod autocrlf { + use std::borrow::Cow; + + use gix_filter::eol; + + use crate::{bstr::BStr, config, config::tree::core::AutoCrlf}; + + impl AutoCrlf { + /// Convert `value` into the safe-crlf enumeration, if possible. + pub fn try_into_autocrlf( + &'static self, + value: Cow<'_, BStr>, + ) -> Result { + if value.as_ref() == "input" { + return Ok(eol::AutoCrlf::Input); + } + let value = gix_config::Boolean::try_from(value.as_ref()).map_err(|err| { + config::key::GenericErrorWithValue::from_value(self, value.into_owned()).with_source(err) + })?; + Ok(if value.into() { + eol::AutoCrlf::Enabled + } else { + eol::AutoCrlf::Disabled + }) + } + } + } +} +#[cfg(feature = "attributes")] +pub use filter::*; + +#[cfg(feature = "revision")] mod disambiguate { use std::borrow::Cow; @@ -143,30 +319,27 @@ mod disambiguate { } mod log_all_ref_updates { - use std::borrow::Cow; - - use crate::{bstr::BStr, config, config::tree::core::LogAllRefUpdates}; + use crate::{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>( + /// Returns the mode for ref-updates as parsed from `value`. If `value` is not a boolean, we try + /// to interpret the string value instead. For correctness, this two step process is necessary as + /// the interpretation of booleans in special in `git-config`, i.e. we can't just treat it as string. + pub fn try_into_ref_updates( &'static self, value: Option>, - string_on_failure: impl FnOnce() -> Option>, ) -> Result, config::key::GenericErrorWithValue> { - match value.transpose().ok().flatten() { - Some(bool) => Ok(Some(if bool { + match value { + Some(Ok(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), + Some(Err(err)) => match err.input { + val if val.eq_ignore_ascii_case(b"always") => Ok(Some(gix_ref::store::WriteReflog::Always)), + val => Err(config::key::GenericErrorWithValue::from_value(self, val)), }, + None => Ok(None), } } } @@ -270,7 +443,9 @@ mod validate { pub struct Disambiguate; impl keys::Validate for Disambiguate { + #[cfg_attr(not(feature = "revision"), allow(unused_variables))] fn validate(&self, value: &BStr) -> Result<(), Box> { + #[cfg(feature = "revision")] super::Core::DISAMBIGUATE.try_into_object_kind_hint(value.into())?; Ok(()) } @@ -280,9 +455,7 @@ mod validate { impl keys::Validate for LogAllRefUpdates { fn validate(&self, value: &BStr) -> Result<(), Box> { super::Core::LOG_ALL_REF_UPDATES - .try_into_ref_updates(Some(gix_config::Boolean::try_from(value).map(|b| b.0)), || { - Some(value.into()) - })?; + .try_into_ref_updates(Some(gix_config::Boolean::try_from(value).map(|b| b.0)))?; Ok(()) } } @@ -303,4 +476,44 @@ mod validate { Ok(()) } } + + pub struct SafeCrlf; + impl keys::Validate for SafeCrlf { + #[cfg_attr(not(feature = "attributes"), allow(unused_variables))] + fn validate(&self, value: &BStr) -> Result<(), Box> { + #[cfg(feature = "attributes")] + super::Core::SAFE_CRLF.try_into_safecrlf(value.into())?; + Ok(()) + } + } + + pub struct AutoCrlf; + impl keys::Validate for AutoCrlf { + #[cfg_attr(not(feature = "attributes"), allow(unused_variables))] + fn validate(&self, value: &BStr) -> Result<(), Box> { + #[cfg(feature = "attributes")] + super::Core::AUTO_CRLF.try_into_autocrlf(value.into())?; + Ok(()) + } + } + + pub struct Eol; + impl keys::Validate for Eol { + #[cfg_attr(not(feature = "attributes"), allow(unused_variables))] + fn validate(&self, value: &BStr) -> Result<(), Box> { + #[cfg(feature = "attributes")] + super::Core::EOL.try_into_eol(value.into())?; + Ok(()) + } + } + + pub struct CheckRoundTripEncoding; + impl keys::Validate for CheckRoundTripEncoding { + #[cfg_attr(not(feature = "attributes"), allow(unused_variables))] + fn validate(&self, value: &BStr) -> Result<(), Box> { + #[cfg(feature = "attributes")] + super::Core::CHECK_ROUND_TRIP_ENCODING.try_into_encodings(Some(value.into()))?; + Ok(()) + } + } } diff --git a/vendor/gix/src/config/tree/sections/diff.rs b/vendor/gix/src/config/tree/sections/diff.rs index 103bb7001..7c467b8f5 100644 --- a/vendor/gix/src/config/tree/sections/diff.rs +++ b/vendor/gix/src/config/tree/sections/diff.rs @@ -68,10 +68,8 @@ mod algorithm { } mod renames { - use std::borrow::Cow; - use crate::{ - bstr::{BStr, ByteSlice}, + bstr::ByteSlice, config::{ key::GenericError, tree::{keys, sections::diff::Renames, Section}, @@ -84,21 +82,20 @@ mod renames { 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>( + /// Try to convert the configuration into a valid rename tracking variant. Use `value` and if it's an error, interpret + /// the boolean as string + pub fn try_into_renames( &'static self, value: Result, - value_string: impl FnOnce() -> Option>, ) -> Result { 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() { + let value = &err.input; + match value.as_bytes() { b"copy" | b"copies" => Tracking::RenamesAndCopies, - _ => return Err(GenericError::from_value(self, value.into_owned()).with_source(err)), + _ => return Err(GenericError::from_value(self, value.clone()).with_source(err)), } } }) @@ -107,8 +104,6 @@ mod renames { } mod validate { - use std::borrow::Cow; - use crate::{ bstr::BStr, config::tree::{keys, Diff}, @@ -126,7 +121,7 @@ mod validate { impl keys::Validate for Renames { fn validate(&self, value: &BStr) -> Result<(), Box> { let boolean = gix_config::Boolean::try_from(value).map(|b| b.0); - Diff::RENAMES.try_into_renames(boolean, || Some(Cow::Borrowed(value)))?; + Diff::RENAMES.try_into_renames(boolean)?; Ok(()) } } diff --git a/vendor/gix/src/config/tree/sections/fetch.rs b/vendor/gix/src/config/tree/sections/fetch.rs index 117cabfd2..32db7be5f 100644 --- a/vendor/gix/src/config/tree/sections/fetch.rs +++ b/vendor/gix/src/config/tree/sections/fetch.rs @@ -10,6 +10,10 @@ impl Fetch { &config::Tree::FETCH, validate::NegotiationAlgorithm, ); + /// The `fetch.recurseSubmodules` key. + #[cfg(feature = "attributes")] + pub const RECURSE_SUBMODULES: RecurseSubmodules = + RecurseSubmodules::new_with_validate("recurseSubmodules", &config::Tree::FETCH, validate::RecurseSubmodules); } impl Section for Fetch { @@ -18,50 +22,81 @@ impl Section for Fetch { } fn keys(&self) -> &[&dyn Key] { - &[&Self::NEGOTIATION_ALGORITHM] + &[ + &Self::NEGOTIATION_ALGORITHM, + #[cfg(feature = "attributes")] + &Self::RECURSE_SUBMODULES, + ] } } /// The `fetch.negotiationAlgorithm` key. pub type NegotiationAlgorithm = keys::Any; -mod algorithm { - use std::borrow::Cow; - - use gix_object::bstr::ByteSlice; +/// The `fetch.recurseSubmodules` key. +#[cfg(feature = "attributes")] +pub type RecurseSubmodules = keys::Any; - use crate::{ - bstr::BStr, - config::{key::GenericErrorWithValue, tree::sections::fetch::NegotiationAlgorithm}, - remote::fetch::negotiate, - }; - - impl NegotiationAlgorithm { +mod algorithm { + #[cfg(feature = "credentials")] + impl crate::config::tree::sections::fetch::NegotiationAlgorithm { /// Derive the negotiation algorithm identified by `name`, case-sensitively. pub fn try_into_negotiation_algorithm( &'static self, - name: Cow<'_, BStr>, - ) -> Result { + name: std::borrow::Cow<'_, crate::bstr::BStr>, + ) -> Result { + use crate::bstr::ByteSlice; + use crate::remote::fetch::negotiate::Algorithm; + Ok(match name.as_ref().as_bytes() { - b"noop" => negotiate::Algorithm::Noop, - b"consecutive" | b"default" => negotiate::Algorithm::Consecutive, - b"skipping" => negotiate::Algorithm::Skipping, - _ => return Err(GenericErrorWithValue::from_value(self, name.into_owned())), + b"noop" => Algorithm::Noop, + b"consecutive" | b"default" => Algorithm::Consecutive, + b"skipping" => Algorithm::Skipping, + _ => { + return Err(crate::config::key::GenericErrorWithValue::from_value( + self, + name.into_owned(), + )) + } }) } } + + #[cfg(feature = "attributes")] + impl crate::config::tree::sections::fetch::RecurseSubmodules { + /// Obtain the way submodules should be updated. + pub fn try_into_recurse_submodules( + &'static self, + value: Result, + ) -> Result { + gix_submodule::config::FetchRecurse::new(value) + .map_err(|err| crate::config::key::GenericErrorWithValue::from_value(self, err)) + } + } } mod validate { - use crate::{ - bstr::BStr, - config::tree::{keys, Fetch}, - }; + use crate::{bstr::BStr, config::tree::keys}; pub struct NegotiationAlgorithm; impl keys::Validate for NegotiationAlgorithm { + #[cfg_attr(not(feature = "credentials"), allow(unused_variables))] + fn validate(&self, value: &BStr) -> Result<(), Box> { + #[cfg(feature = "credentials")] + crate::config::tree::Fetch::NEGOTIATION_ALGORITHM.try_into_negotiation_algorithm(value.into())?; + Ok(()) + } + } + + pub struct RecurseSubmodules; + impl keys::Validate for RecurseSubmodules { + #[cfg_attr(not(feature = "attributes"), allow(unused_variables))] fn validate(&self, value: &BStr) -> Result<(), Box> { - Fetch::NEGOTIATION_ALGORITHM.try_into_negotiation_algorithm(value.into())?; + #[cfg(feature = "attributes")] + { + let boolean = gix_config::Boolean::try_from(value).map(|b| b.0); + crate::config::tree::Fetch::RECURSE_SUBMODULES.try_into_recurse_submodules(boolean)?; + } Ok(()) } } diff --git a/vendor/gix/src/config/tree/sections/gitoxide.rs b/vendor/gix/src/config/tree/sections/gitoxide.rs index f07d494fb..966d5af7c 100644 --- a/vendor/gix/src/config/tree/sections/gitoxide.rs +++ b/vendor/gix/src/config/tree/sections/gitoxide.rs @@ -24,6 +24,8 @@ impl Gitoxide { pub const SSH: Ssh = Ssh; /// The `gitoxide.user` section. pub const USER: User = User; + /// The `gitoxide.pathspec` section. + pub const PATHSPEC: Pathspec = Pathspec; /// The `gitoxide.userAgent` Key. pub const USER_AGENT: keys::Any = keys::Any::new("userAgent", &config::Tree::GITOXIDE).with_note( @@ -52,6 +54,7 @@ impl Section for Gitoxide { &Self::OBJECTS, &Self::SSH, &Self::USER, + &Self::PATHSPEC, ] } } @@ -86,6 +89,12 @@ mod subsections { .with_deviation( "relative file paths will always be made relative to the git-common-dir, whereas `git` keeps them as is.", ); + + /// The `gitoxide.core.filterProcessDelay` key (default `true`). + /// + /// It controls whether or not long running filter driver processes can use the 'delay' capability. + pub const FILTER_PROCESS_DELAY: keys::Boolean = + keys::Boolean::new_boolean("filterProcessDelay", &Gitoxide::CORE); } impl Section for Core { @@ -99,6 +108,7 @@ mod subsections { &Self::USE_NSEC, &Self::USE_STDEV, &Self::SHALLOW_FILE, + &Self::FILTER_PROCESS_DELAY, ] } @@ -306,6 +316,56 @@ mod subsections { } } + /// The `pathspec` sub-section. + #[derive(Copy, Clone, Default)] + pub struct Pathspec; + + impl Pathspec { + /// The `gitoxide.pathspec.glob` key. + pub const GLOB: keys::Boolean = keys::Boolean::new_boolean("glob", &Gitoxide::PATHSPEC) + .with_environment_override("GIT_GLOB_PATHSPECS") + .with_note("pathspec wildcards don't match the slash character, then needing '**' to get past them"); + /// The `gitoxide.pathspec.noglob` key. + pub const NOGLOB: keys::Boolean = keys::Boolean::new_boolean("noglob", &Gitoxide::PATHSPEC) + .with_environment_override("GIT_NOGLOB_PATHSPECS") + .with_note("Enable literal matching for glob patterns, effectively disabling globbing"); + /// The `gitoxide.pathspec.literal` key. + pub const LITERAL: keys::Boolean = keys::Boolean::new_boolean("literal", &Gitoxide::PATHSPEC) + .with_environment_override("GIT_LITERAL_PATHSPECS") + .with_note("Make the entire spec used verbatim, the only way to get ':()name' verbatim for instance"); + /// The `gitoxide.pathspec.icase` key. + pub const ICASE: keys::Boolean = keys::Boolean::new_boolean("icase", &Gitoxide::PATHSPEC) + .with_environment_override("GIT_ICASE_PATHSPECS") + .with_note("Compare string in a case-insensitive manner"); + /// The `gitoxide.pathspec.inheritIgnoreCase` key, defaulting to `true` if unspecified. + /// If set, pathspecs will automatically be match case-insensitively if the underlying filesystem is configured that way. + pub const INHERIT_IGNORE_CASE: keys::Boolean = + keys::Boolean::new_boolean("inheritIgnoreCase", &Gitoxide::PATHSPEC) + .with_note("Inherit `core.ignoreCase` for defaults in pathspecs"); + /// The default value for `gitoxide.pathspec.inheritIgnoreCase`. + pub const INHERIT_IGNORE_CASE_DEFAULT: bool = true; + } + + impl Section for Pathspec { + fn name(&self) -> &str { + "pathspec" + } + + fn keys(&self) -> &[&dyn Key] { + &[ + &Self::GLOB, + &Self::NOGLOB, + &Self::LITERAL, + &Self::ICASE, + &Self::INHERIT_IGNORE_CASE, + ] + } + + fn parent(&self) -> Option<&dyn Section> { + Some(&Tree::GITOXIDE) + } + } + /// The `objects` sub-section. #[derive(Copy, Clone, Default)] pub struct Objects; @@ -391,7 +451,7 @@ mod subsections { } } } -pub use subsections::{Allow, Author, Commit, Committer, Core, Http, Https, Objects, Ssh, User}; +pub use subsections::{Allow, Author, Commit, Committer, Core, Http, Https, Objects, Pathspec, Ssh, User}; pub mod validate { use std::error::Error; diff --git a/vendor/gix/src/config/tree/sections/index.rs b/vendor/gix/src/config/tree/sections/index.rs index 08f7ec1bd..026f35b6d 100644 --- a/vendor/gix/src/config/tree/sections/index.rs +++ b/vendor/gix/src/config/tree/sections/index.rs @@ -7,6 +7,9 @@ impl Index { /// The `index.threads` key. pub const THREADS: IndexThreads = IndexThreads::new_with_validate("threads", &config::Tree::INDEX, validate::IndexThreads); + /// The `index.skipHash` key. + pub const SKIP_HASH: keys::Boolean = keys::Boolean::new_boolean("skipHash", &config::Tree::INDEX) + .with_deviation("also used to skip the hash when reading, even if a hash exists in the index file"); } /// The `index.threads` key. @@ -47,7 +50,7 @@ impl Section for Index { } fn keys(&self) -> &[&dyn Key] { - &[&Self::THREADS] + &[&Self::THREADS, &Self::SKIP_HASH] } } diff --git a/vendor/gix/src/config/tree/sections/mod.rs b/vendor/gix/src/config/tree/sections/mod.rs index ebf24a8b7..34929c5d1 100644 --- a/vendor/gix/src/config/tree/sections/mod.rs +++ b/vendor/gix/src/config/tree/sections/mod.rs @@ -37,7 +37,9 @@ pub mod credential; /// The `diff` top-level section. #[derive(Copy, Clone, Default)] +#[cfg(feature = "blob-diff")] pub struct Diff; +#[cfg(feature = "blob-diff")] pub mod diff; /// The `extension` top-level section. diff --git a/vendor/gix/src/config/tree/sections/protocol.rs b/vendor/gix/src/config/tree/sections/protocol.rs index a0510f2b8..7ef2cc8cb 100644 --- a/vendor/gix/src/config/tree/sections/protocol.rs +++ b/vendor/gix/src/config/tree/sections/protocol.rs @@ -127,7 +127,7 @@ mod validate { .to_decimal() .ok_or_else(|| format!("integer {value} cannot be represented as integer"))?; match value { - 0 | 1 | 2 => Ok(()), + 0..=2 => Ok(()), _ => Err(format!("protocol version {value} is unknown").into()), } } -- cgit v1.2.3