diff options
Diffstat (limited to 'vendor/gix-config/src/file/init/comfort.rs')
-rw-r--r-- | vendor/gix-config/src/file/init/comfort.rs | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/vendor/gix-config/src/file/init/comfort.rs b/vendor/gix-config/src/file/init/comfort.rs new file mode 100644 index 000000000..ffe859a1a --- /dev/null +++ b/vendor/gix-config/src/file/init/comfort.rs @@ -0,0 +1,159 @@ +use std::path::PathBuf; + +use crate::{ + file::{init, Metadata}, + path, source, File, Source, +}; + +/// Easy-instantiation of typical non-repository git configuration files with all configuration defaulting to typical values. +/// +/// ### Limitations +/// +/// Note that `includeIf` conditions in global files will cause failure as the required information +/// to resolve them isn't present without a repository. +/// +/// Also note that relevant information to interpolate paths will be obtained from the environment or other +/// source on unix. +impl File<'static> { + /// Open all global configuration files which involves the following sources: + /// + /// * [system][crate::Source::System] + /// * [git][crate::Source::Git] + /// * [user][crate::Source::User] + /// + /// which excludes repository local configuration, as well as override-configuration from environment variables. + /// + /// Note that the file might [be empty][File::is_void()] in case no configuration file was found. + pub fn from_globals() -> Result<File<'static>, init::from_paths::Error> { + let metas = [source::Kind::System, source::Kind::Global] + .iter() + .flat_map(|kind| kind.sources()) + .filter_map(|source| { + let path = source + .storage_location(&mut |name| std::env::var_os(name)) + .and_then(|p| p.is_file().then_some(p)) + .map(|p| p.into_owned()); + + Metadata { + path, + source: *source, + level: 0, + trust: gix_sec::Trust::Full, + } + .into() + }); + + let home = std::env::var("HOME").ok().map(PathBuf::from); + let options = init::Options { + includes: init::includes::Options::follow_without_conditional(home.as_deref()), + ..Default::default() + }; + File::from_paths_metadata(metas, options).map(Option::unwrap_or_default) + } + + /// Generates a config from `GIT_CONFIG_*` environment variables and return a possibly empty `File`. + /// A typical use of this is to [`append`][File::append()] this configuration to another one with lower + /// precedence to obtain overrides. + /// + /// See [`gix-config`'s documentation] for more information on the environment variables in question. + /// + /// [`gix-config`'s documentation]: https://git-scm.com/docs/gix-config#Documentation/gix-config.txt-GITCONFIGCOUNT + pub fn from_environment_overrides() -> Result<File<'static>, init::from_env::Error> { + let home = std::env::var("HOME").ok().map(PathBuf::from); + let options = init::Options { + includes: init::includes::Options::follow_without_conditional(home.as_deref()), + ..Default::default() + }; + + File::from_env(options).map(Option::unwrap_or_default) + } +} + +/// An easy way to provide complete configuration for a repository. +impl File<'static> { + /// This configuration type includes the following sources, in order of precedence: + /// + /// - globals + /// - repository-local by loading `dir`/config + /// - worktree by loading `dir`/config.worktree + /// - environment + /// + /// Note that `dir` is the `.git` dir to load the configuration from, not the configuration file. + /// + /// Includes will be resolved within limits as some information like the git installation directory is missing to interpolate + /// paths with as well as git repository information like the branch name. + pub fn from_git_dir(dir: impl Into<std::path::PathBuf>) -> Result<File<'static>, from_git_dir::Error> { + let (mut local, git_dir) = { + let source = Source::Local; + let mut path = dir.into(); + path.push( + source + .storage_location(&mut |n| std::env::var_os(n)) + .expect("location available for local"), + ); + let local = Self::from_path_no_includes(&path, source)?; + path.pop(); + (local, path) + }; + + let worktree = match local.boolean("extensions", None, "worktreeConfig") { + Some(Ok(worktree_config)) => worktree_config.then(|| { + let source = Source::Worktree; + let path = git_dir.join( + source + .storage_location(&mut |n| std::env::var_os(n)) + .expect("location available for worktree"), + ); + Self::from_path_no_includes(path, source) + }), + _ => None, + } + .transpose()?; + + let home = std::env::var("HOME").ok().map(PathBuf::from); + let options = init::Options { + includes: init::includes::Options::follow( + path::interpolate::Context { + home_dir: home.as_deref(), + ..Default::default() + }, + init::includes::conditional::Context { + git_dir: Some(git_dir.as_ref()), + branch_name: None, + }, + ), + lossy: false, + }; + + let mut globals = Self::from_globals()?; + globals.resolve_includes(options)?; + local.resolve_includes(options)?; + + globals.append(local); + if let Some(mut worktree) = worktree { + worktree.resolve_includes(options)?; + globals.append(worktree); + } + globals.append(Self::from_environment_overrides()?); + + Ok(globals) + } +} + +/// +pub mod from_git_dir { + use crate::file::init; + + /// The error returned by [`File::from_git_dir()`][crate::File::from_git_dir()]. + #[derive(Debug, thiserror::Error)] + pub enum Error { + #[error(transparent)] + FromPaths(#[from] init::from_paths::Error), + #[error(transparent)] + FromEnv(#[from] init::from_env::Error), + #[error(transparent)] + Init(#[from] init::Error), + #[error(transparent)] + Includes(#[from] init::includes::Error), + } +} |