use crate::{
config,
config::tree::{Gitoxide, Key, Section, keys},
};
impl Gitoxide {
pub const ALLOW: Allow = Allow;
pub const AUTHOR: Author = Author;
pub const CORE: Core = Core;
pub const COMMIT: Commit = Commit;
pub const COMMITTER: Committer = Committer;
pub const CREDENTIALS: Credentials = Credentials;
pub const HTTP: Http = Http;
pub const HTTPS: Https = Https;
pub const OBJECTS: Objects = Objects;
pub const SSH: Ssh = Ssh;
pub const USER: User = User;
pub const PATHSPEC: Pathspec = Pathspec;
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",
);
pub const TRACE_PACKET: keys::Boolean = keys::Boolean::new_boolean("tracePacket", &config::Tree::GITOXIDE)
.with_environment_override("GIT_TRACE_PACKET");
pub const PARSE_PRECIOUS: keys::Boolean = keys::Boolean::new_boolean("parsePrecious", &config::Tree::GITOXIDE)
.with_environment_override("GIX_PARSE_PRECIOUS");
}
impl Section for Gitoxide {
fn name(&self) -> &str {
"gitoxide"
}
fn keys(&self) -> &[&dyn Key] {
&[&Self::USER_AGENT, &Self::TRACE_PACKET, &Self::PARSE_PRECIOUS]
}
fn sub_sections(&self) -> &[&dyn Section] {
&[
&Self::ALLOW,
&Self::AUTHOR,
&Self::CORE,
&Self::COMMIT,
&Self::COMMITTER,
&Self::CREDENTIALS,
&Self::HTTP,
&Self::HTTPS,
&Self::OBJECTS,
&Self::SSH,
&Self::USER,
&Self::PATHSPEC,
]
}
}
mod subsections {
use crate::{
bstr::ByteSlice,
config::{
Tree,
tree::{Gitoxide, Key, Section, http, keys},
},
};
#[derive(Copy, Clone, Default)]
pub struct Core;
pub type RefsNamespace = keys::Any<super::validate::RefsNamespace>;
pub type IndexFile = keys::Any<super::validate::NonEmptyPath>;
impl RefsNamespace {
pub fn try_into_refs_namespace(
&'static self,
name: impl gix_utils::AsBStr,
) -> Result<gix_ref::Namespace, crate::config::refs_namespace::Error> {
let name = name.as_bstr();
gix_ref::namespace::expand(name.as_bstr())
.map_err(|err| crate::config::key::Error::from_value(self, name.into()).with_source(err))
}
}
impl Core {
pub const DEFAULT_PACK_CACHE_MEMORY_LIMIT: keys::UnsignedInteger =
keys::UnsignedInteger::new_unsigned_integer("defaultPackCacheMemoryLimit", &Gitoxide::CORE).with_note(
"If unset, we default to 96MB memory cap for the default 64 slot LRU cache for object deltas.",
);
pub const USE_NSEC: keys::Boolean = keys::Boolean::new_boolean("useNsec", &Gitoxide::CORE)
.with_note("A runtime version of the USE_NSEC build flag.");
pub const USE_STDEV: keys::Boolean = keys::Boolean::new_boolean("useStdev", &Gitoxide::CORE)
.with_note("A runtime version of the USE_STDEV build flag.");
pub const PROTECT_WINDOWS: keys::Boolean = keys::Boolean::new_boolean("protectWindows", &Gitoxide::CORE)
.with_note("enable protections that are enabled by default on Windows");
pub const SHALLOW_FILE: keys::Path = keys::Path::new_path("shallowFile", &Gitoxide::CORE)
.with_default(b"shallow")
.with_environment_override("GIT_SHALLOW_FILE")
.with_deviation(
"relative file paths will always be made relative to the git-common-dir, whereas `git` keeps them as is.",
);
pub const INDEX_FILE: IndexFile =
keys::Any::new_with_validate("indexFile", &Gitoxide::CORE, super::validate::NonEmptyPath)
.with_environment_override("GIT_INDEX_FILE")
.with_deviation(
"relative file paths are resolved against the current working directory captured when the repository was opened, whereas Git retains them and thus resolves them against the process's current directory on each use.",
);
pub const FILTER_PROCESS_DELAY: keys::Boolean =
keys::Boolean::new_boolean("filterProcessDelay", &Gitoxide::CORE);
pub const EXTERNAL_COMMAND_STDERR: keys::Boolean =
keys::Boolean::new_boolean("externalCommandStderr", &Gitoxide::CORE)
.with_environment_override("GIX_EXTERNAL_COMMAND_STDERR");
pub const REFS_NAMESPACE: RefsNamespace =
keys::Any::new_with_validate("refsNamespace", &Gitoxide::CORE, super::validate::RefsNamespace)
.with_environment_override("GIT_NAMESPACE");
}
impl Section for Core {
fn name(&self) -> &str {
"core"
}
fn keys(&self) -> &[&dyn Key] {
&[
&Self::DEFAULT_PACK_CACHE_MEMORY_LIMIT,
&Self::USE_NSEC,
&Self::USE_STDEV,
&Self::SHALLOW_FILE,
&Self::INDEX_FILE,
&Self::PROTECT_WINDOWS,
&Self::FILTER_PROCESS_DELAY,
&Self::EXTERNAL_COMMAND_STDERR,
&Self::REFS_NAMESPACE,
]
}
fn parent(&self) -> Option<&dyn Section> {
Some(&Tree::GITOXIDE)
}
}
#[derive(Copy, Clone, Default)]
pub struct Http;
impl Http {
pub const PROXY: keys::String =
keys::String::new_string("proxy", &Gitoxide::HTTP).with_environment_override("http_proxy");
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`");
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");
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`");
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",
);
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.",
);
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.",
);
pub const SSL_NO_VERIFY: keys::Boolean = keys::Boolean::new_boolean("sslNoVerify", &Gitoxide::HTTP)
.with_environment_override("GIT_SSL_NO_VERIFY")
.with_note("used to disable SSL verification. When this is enabled it takes priority over http.sslVerify");
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::SSL_NO_VERIFY,
&Self::PROXY_AUTH_METHOD,
]
}
fn parent(&self) -> Option<&dyn Section> {
Some(&Tree::GITOXIDE)
}
}
#[derive(Copy, Clone, Default)]
pub struct Https;
impl Https {
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)
}
}
#[derive(Copy, Clone, Default)]
pub struct Allow;
pub type ProtocolFromUser = keys::Boolean;
impl Allow {
pub const PROTOCOL: keys::Any =
keys::Any::new("protocol", &Gitoxide::ALLOW).with_environment_override("GIT_ALLOW_PROTOCOL");
pub const PROTOCOL_FROM_USER: ProtocolFromUser =
ProtocolFromUser::new_boolean("protocolFromUser", &Gitoxide::ALLOW)
.with_environment_override("GIT_PROTOCOL_FROM_USER");
}
impl Section for Allow {
fn name(&self) -> &str {
"allow"
}
fn keys(&self) -> &[&dyn Key] {
&[&Self::PROTOCOL, &Self::PROTOCOL_FROM_USER]
}
fn parent(&self) -> Option<&dyn Section> {
Some(&Tree::GITOXIDE)
}
}
#[derive(Copy, Clone, Default)]
pub struct Author;
impl Author {
pub const NAME_FALLBACK: keys::Any =
keys::Any::new("nameFallback", &Gitoxide::AUTHOR).with_environment_override("GIT_AUTHOR_NAME");
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)
}
}
#[derive(Copy, Clone, Default)]
pub struct User;
impl User {
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)
}
}
#[derive(Copy, Clone, Default)]
pub struct Ssh;
impl Ssh {
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)
}
}
#[derive(Copy, Clone, Default)]
pub struct Pathspec;
impl Pathspec {
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");
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");
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");
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");
pub const INHERIT_IGNORE_CASE: keys::Boolean =
keys::Boolean::new_boolean("inheritIgnoreCase", &Gitoxide::PATHSPEC)
.with_note("Inherit `core.ignoreCase` for defaults in pathspecs");
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)
}
}
#[derive(Copy, Clone, Default)]
pub struct Objects;
impl Objects {
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("GIX_OBJECT_CACHE_MEMORY");
pub const ALLOC_LIMIT: keys::UnsignedInteger =
keys::UnsignedInteger::new_unsigned_integer("allocLimit", &Gitoxide::OBJECTS)
.with_environment_override("GIT_ALLOC_LIMIT")
.with_note("The maximum size of a single allocation caused by user-controlled on-disk object data. In fact, it's used for all untrusted data that causes allocations.");
pub const ALLOC_LIMIT_IF_REDUCED_TRUST_DEFAULT: usize = 16 * 1024 * 1024;
pub const ALLOC_LIMIT_IF_REDUCED_TRUST: keys::UnsignedInteger =
keys::UnsignedInteger::new_unsigned_integer("allocLimitIfReducedTrust", &Gitoxide::OBJECTS).with_note(
"The default allocation limit used for reduced-trust repositories when no explicit allocLimit is configured; set to 0 to disable it",
);
pub const NO_REPLACE: keys::Boolean = keys::Boolean::new_boolean("noReplace", &Gitoxide::OBJECTS);
pub const REPLACE_REF_BASE: keys::Any = keys::Any::new("replaceRefBase", &Gitoxide::OBJECTS)
.with_default(b"refs/replace/")
.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::ALLOC_LIMIT,
&Self::ALLOC_LIMIT_IF_REDUCED_TRUST,
&Self::REPLACE_REF_BASE,
]
}
fn parent(&self) -> Option<&dyn Section> {
Some(&Tree::GITOXIDE)
}
}
#[derive(Copy, Clone, Default)]
pub struct Committer;
impl Committer {
pub const NAME_FALLBACK: keys::Any =
keys::Any::new("nameFallback", &Gitoxide::COMMITTER).with_environment_override("GIT_COMMITTER_NAME");
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)
}
}
#[derive(Copy, Clone, Default)]
pub struct Credentials;
impl Credentials {
pub const TERMINAL_PROMPT: keys::Boolean = keys::Boolean::new_boolean("terminalPrompt", &Gitoxide::CREDENTIALS)
.with_note("This is a custom addition to provide an alternative to the respective environment variable.")
.with_environment_override("GIT_TERMINAL_PROMPT");
pub const HELPER_STDERR: keys::Boolean = keys::Boolean::new_boolean("helperStderr", &Gitoxide::CREDENTIALS)
.with_environment_override("GIX_CREDENTIALS_HELPER_STDERR");
}
impl Section for Credentials {
fn name(&self) -> &str {
"credentials"
}
fn keys(&self) -> &[&dyn Key] {
&[&Self::TERMINAL_PROMPT, &Self::HELPER_STDERR]
}
fn parent(&self) -> Option<&dyn Section> {
Some(&Tree::GITOXIDE)
}
}
#[derive(Copy, Clone, Default)]
pub struct Commit;
impl Commit {
pub const AUTHOR_DATE: keys::Any =
keys::Any::new("authorDate", &Gitoxide::COMMIT).with_environment_override("GIT_AUTHOR_DATE");
pub const COMMITTER_DATE: keys::Any =
keys::Any::new("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 use subsections::{Allow, Author, Commit, Committer, Core, Credentials, Http, Https, Objects, Pathspec, Ssh, User};
pub mod validate {
use gix_error::ValidationError;
use std::error::Error;
use crate::{bstr::BStr, config::tree::keys::Validate};
#[derive(Clone, Copy)]
pub struct RefsNamespace;
impl Validate for RefsNamespace {
fn validate(&self, value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
super::Core::REFS_NAMESPACE.try_into_refs_namespace(value)?;
Ok(())
}
}
#[derive(Clone, Copy)]
pub struct NonEmptyPath;
impl Validate for NonEmptyPath {
fn validate(&self, value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
if value.is_empty() {
return Err(ValidationError::new("index file path must not be empty").into());
}
Ok(())
}
}
}