From 23034b0feed35a0d573af8947c2114b3505e249b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 6 Nov 2024 15:12:24 +0100 Subject: [PATCH 1/4] move tests into new location for better readability --- gix-config/tests/Cargo.toml | 2 +- gix-config/tests/{ => config}/file/access/mod.rs | 0 gix-config/tests/{ => config}/file/access/mutate.rs | 0 gix-config/tests/{ => config}/file/access/raw/mod.rs | 0 .../tests/{ => config}/file/access/raw/raw_multi_value.rs | 0 gix-config/tests/{ => config}/file/access/raw/raw_value.rs | 0 .../{ => config}/file/access/raw/set_existing_raw_value.rs | 0 gix-config/tests/{ => config}/file/access/raw/set_raw_value.rs | 0 gix-config/tests/{ => config}/file/access/read_only.rs | 0 gix-config/tests/{ => config}/file/impls/mod.rs | 0 gix-config/tests/{ => config}/file/init/comfort.rs | 0 gix-config/tests/{ => config}/file/init/from_env.rs | 0 .../file/init/from_paths/includes/conditional/gitdir/mod.rs | 0 .../file/init/from_paths/includes/conditional/gitdir/util.rs | 0 .../file/init/from_paths/includes/conditional/mod.rs | 0 .../file/init/from_paths/includes/conditional/onbranch.rs | 0 .../{ => config}/file/init/from_paths/includes/unconditional.rs | 0 gix-config/tests/{ => config}/file/init/from_paths/mod.rs | 0 gix-config/tests/{ => config}/file/init/from_str.rs | 0 gix-config/tests/{ => config}/file/init/mod.rs | 0 gix-config/tests/{ => config}/file/mod.rs | 2 +- gix-config/tests/{ => config}/file/mutable/mod.rs | 0 gix-config/tests/{ => config}/file/mutable/multi_value.rs | 0 gix-config/tests/{ => config}/file/mutable/section.rs | 0 gix-config/tests/{ => config}/file/mutable/value.rs | 0 gix-config/tests/{ => config}/file/resolve_includes.rs | 0 gix-config/tests/{ => config}/file/write.rs | 0 gix-config/tests/{ => config}/key/mod.rs | 0 gix-config/tests/{config.rs => config/mod.rs} | 1 - gix-config/tests/{ => config}/parse/error.rs | 0 gix-config/tests/{ => config}/parse/from_bytes.rs | 2 +- gix-config/tests/{ => config}/parse/mod.rs | 0 gix-config/tests/{ => config}/parse/section.rs | 0 gix-config/tests/{ => config}/source/mod.rs | 0 gix-config/tests/{ => config}/value/mod.rs | 0 gix-config/tests/{ => config}/value/normalize.rs | 0 36 files changed, 3 insertions(+), 4 deletions(-) rename gix-config/tests/{ => config}/file/access/mod.rs (100%) rename gix-config/tests/{ => config}/file/access/mutate.rs (100%) rename gix-config/tests/{ => config}/file/access/raw/mod.rs (100%) rename gix-config/tests/{ => config}/file/access/raw/raw_multi_value.rs (100%) rename gix-config/tests/{ => config}/file/access/raw/raw_value.rs (100%) rename gix-config/tests/{ => config}/file/access/raw/set_existing_raw_value.rs (100%) rename gix-config/tests/{ => config}/file/access/raw/set_raw_value.rs (100%) rename gix-config/tests/{ => config}/file/access/read_only.rs (100%) rename gix-config/tests/{ => config}/file/impls/mod.rs (100%) rename gix-config/tests/{ => config}/file/init/comfort.rs (100%) rename gix-config/tests/{ => config}/file/init/from_env.rs (100%) rename gix-config/tests/{ => config}/file/init/from_paths/includes/conditional/gitdir/mod.rs (100%) rename gix-config/tests/{ => config}/file/init/from_paths/includes/conditional/gitdir/util.rs (100%) rename gix-config/tests/{ => config}/file/init/from_paths/includes/conditional/mod.rs (100%) rename gix-config/tests/{ => config}/file/init/from_paths/includes/conditional/onbranch.rs (100%) rename gix-config/tests/{ => config}/file/init/from_paths/includes/unconditional.rs (100%) rename gix-config/tests/{ => config}/file/init/from_paths/mod.rs (100%) rename gix-config/tests/{ => config}/file/init/from_str.rs (100%) rename gix-config/tests/{ => config}/file/init/mod.rs (100%) rename gix-config/tests/{ => config}/file/mod.rs (96%) rename gix-config/tests/{ => config}/file/mutable/mod.rs (100%) rename gix-config/tests/{ => config}/file/mutable/multi_value.rs (100%) rename gix-config/tests/{ => config}/file/mutable/section.rs (100%) rename gix-config/tests/{ => config}/file/mutable/value.rs (100%) rename gix-config/tests/{ => config}/file/resolve_includes.rs (100%) rename gix-config/tests/{ => config}/file/write.rs (100%) rename gix-config/tests/{ => config}/key/mod.rs (100%) rename gix-config/tests/{config.rs => config/mod.rs} (90%) rename gix-config/tests/{ => config}/parse/error.rs (100%) rename gix-config/tests/{ => config}/parse/from_bytes.rs (97%) rename gix-config/tests/{ => config}/parse/mod.rs (100%) rename gix-config/tests/{ => config}/parse/section.rs (100%) rename gix-config/tests/{ => config}/source/mod.rs (100%) rename gix-config/tests/{ => config}/value/mod.rs (100%) rename gix-config/tests/{ => config}/value/normalize.rs (100%) diff --git a/gix-config/tests/Cargo.toml b/gix-config/tests/Cargo.toml index 3809ff5a137..1b43a62997d 100644 --- a/gix-config/tests/Cargo.toml +++ b/gix-config/tests/Cargo.toml @@ -14,7 +14,7 @@ publish = false [[test]] name = "config" -path = "config.rs" +path = "config/mod.rs" [[test]] name = "mem" diff --git a/gix-config/tests/file/access/mod.rs b/gix-config/tests/config/file/access/mod.rs similarity index 100% rename from gix-config/tests/file/access/mod.rs rename to gix-config/tests/config/file/access/mod.rs diff --git a/gix-config/tests/file/access/mutate.rs b/gix-config/tests/config/file/access/mutate.rs similarity index 100% rename from gix-config/tests/file/access/mutate.rs rename to gix-config/tests/config/file/access/mutate.rs diff --git a/gix-config/tests/file/access/raw/mod.rs b/gix-config/tests/config/file/access/raw/mod.rs similarity index 100% rename from gix-config/tests/file/access/raw/mod.rs rename to gix-config/tests/config/file/access/raw/mod.rs diff --git a/gix-config/tests/file/access/raw/raw_multi_value.rs b/gix-config/tests/config/file/access/raw/raw_multi_value.rs similarity index 100% rename from gix-config/tests/file/access/raw/raw_multi_value.rs rename to gix-config/tests/config/file/access/raw/raw_multi_value.rs diff --git a/gix-config/tests/file/access/raw/raw_value.rs b/gix-config/tests/config/file/access/raw/raw_value.rs similarity index 100% rename from gix-config/tests/file/access/raw/raw_value.rs rename to gix-config/tests/config/file/access/raw/raw_value.rs diff --git a/gix-config/tests/file/access/raw/set_existing_raw_value.rs b/gix-config/tests/config/file/access/raw/set_existing_raw_value.rs similarity index 100% rename from gix-config/tests/file/access/raw/set_existing_raw_value.rs rename to gix-config/tests/config/file/access/raw/set_existing_raw_value.rs diff --git a/gix-config/tests/file/access/raw/set_raw_value.rs b/gix-config/tests/config/file/access/raw/set_raw_value.rs similarity index 100% rename from gix-config/tests/file/access/raw/set_raw_value.rs rename to gix-config/tests/config/file/access/raw/set_raw_value.rs diff --git a/gix-config/tests/file/access/read_only.rs b/gix-config/tests/config/file/access/read_only.rs similarity index 100% rename from gix-config/tests/file/access/read_only.rs rename to gix-config/tests/config/file/access/read_only.rs diff --git a/gix-config/tests/file/impls/mod.rs b/gix-config/tests/config/file/impls/mod.rs similarity index 100% rename from gix-config/tests/file/impls/mod.rs rename to gix-config/tests/config/file/impls/mod.rs diff --git a/gix-config/tests/file/init/comfort.rs b/gix-config/tests/config/file/init/comfort.rs similarity index 100% rename from gix-config/tests/file/init/comfort.rs rename to gix-config/tests/config/file/init/comfort.rs diff --git a/gix-config/tests/file/init/from_env.rs b/gix-config/tests/config/file/init/from_env.rs similarity index 100% rename from gix-config/tests/file/init/from_env.rs rename to gix-config/tests/config/file/init/from_env.rs diff --git a/gix-config/tests/file/init/from_paths/includes/conditional/gitdir/mod.rs b/gix-config/tests/config/file/init/from_paths/includes/conditional/gitdir/mod.rs similarity index 100% rename from gix-config/tests/file/init/from_paths/includes/conditional/gitdir/mod.rs rename to gix-config/tests/config/file/init/from_paths/includes/conditional/gitdir/mod.rs diff --git a/gix-config/tests/file/init/from_paths/includes/conditional/gitdir/util.rs b/gix-config/tests/config/file/init/from_paths/includes/conditional/gitdir/util.rs similarity index 100% rename from gix-config/tests/file/init/from_paths/includes/conditional/gitdir/util.rs rename to gix-config/tests/config/file/init/from_paths/includes/conditional/gitdir/util.rs diff --git a/gix-config/tests/file/init/from_paths/includes/conditional/mod.rs b/gix-config/tests/config/file/init/from_paths/includes/conditional/mod.rs similarity index 100% rename from gix-config/tests/file/init/from_paths/includes/conditional/mod.rs rename to gix-config/tests/config/file/init/from_paths/includes/conditional/mod.rs diff --git a/gix-config/tests/file/init/from_paths/includes/conditional/onbranch.rs b/gix-config/tests/config/file/init/from_paths/includes/conditional/onbranch.rs similarity index 100% rename from gix-config/tests/file/init/from_paths/includes/conditional/onbranch.rs rename to gix-config/tests/config/file/init/from_paths/includes/conditional/onbranch.rs diff --git a/gix-config/tests/file/init/from_paths/includes/unconditional.rs b/gix-config/tests/config/file/init/from_paths/includes/unconditional.rs similarity index 100% rename from gix-config/tests/file/init/from_paths/includes/unconditional.rs rename to gix-config/tests/config/file/init/from_paths/includes/unconditional.rs diff --git a/gix-config/tests/file/init/from_paths/mod.rs b/gix-config/tests/config/file/init/from_paths/mod.rs similarity index 100% rename from gix-config/tests/file/init/from_paths/mod.rs rename to gix-config/tests/config/file/init/from_paths/mod.rs diff --git a/gix-config/tests/file/init/from_str.rs b/gix-config/tests/config/file/init/from_str.rs similarity index 100% rename from gix-config/tests/file/init/from_str.rs rename to gix-config/tests/config/file/init/from_str.rs diff --git a/gix-config/tests/file/init/mod.rs b/gix-config/tests/config/file/init/mod.rs similarity index 100% rename from gix-config/tests/file/init/mod.rs rename to gix-config/tests/config/file/init/mod.rs diff --git a/gix-config/tests/file/mod.rs b/gix-config/tests/config/file/mod.rs similarity index 96% rename from gix-config/tests/file/mod.rs rename to gix-config/tests/config/file/mod.rs index e09f4480e85..1022f6286cc 100644 --- a/gix-config/tests/file/mod.rs +++ b/gix-config/tests/config/file/mod.rs @@ -30,7 +30,7 @@ mod open { #[test] fn fuzzed_stackoverflow() { let file = File::from_bytes_no_includes( - include_bytes!("../fixtures/fuzzed/stackoverflow-01.config"), + include_bytes!("../../fixtures/fuzzed/stackoverflow-01.config"), gix_config::file::Metadata::default(), Default::default(), ) diff --git a/gix-config/tests/file/mutable/mod.rs b/gix-config/tests/config/file/mutable/mod.rs similarity index 100% rename from gix-config/tests/file/mutable/mod.rs rename to gix-config/tests/config/file/mutable/mod.rs diff --git a/gix-config/tests/file/mutable/multi_value.rs b/gix-config/tests/config/file/mutable/multi_value.rs similarity index 100% rename from gix-config/tests/file/mutable/multi_value.rs rename to gix-config/tests/config/file/mutable/multi_value.rs diff --git a/gix-config/tests/file/mutable/section.rs b/gix-config/tests/config/file/mutable/section.rs similarity index 100% rename from gix-config/tests/file/mutable/section.rs rename to gix-config/tests/config/file/mutable/section.rs diff --git a/gix-config/tests/file/mutable/value.rs b/gix-config/tests/config/file/mutable/value.rs similarity index 100% rename from gix-config/tests/file/mutable/value.rs rename to gix-config/tests/config/file/mutable/value.rs diff --git a/gix-config/tests/file/resolve_includes.rs b/gix-config/tests/config/file/resolve_includes.rs similarity index 100% rename from gix-config/tests/file/resolve_includes.rs rename to gix-config/tests/config/file/resolve_includes.rs diff --git a/gix-config/tests/file/write.rs b/gix-config/tests/config/file/write.rs similarity index 100% rename from gix-config/tests/file/write.rs rename to gix-config/tests/config/file/write.rs diff --git a/gix-config/tests/key/mod.rs b/gix-config/tests/config/key/mod.rs similarity index 100% rename from gix-config/tests/key/mod.rs rename to gix-config/tests/config/key/mod.rs diff --git a/gix-config/tests/config.rs b/gix-config/tests/config/mod.rs similarity index 90% rename from gix-config/tests/config.rs rename to gix-config/tests/config/mod.rs index 3efeb7c63c9..2782af4095a 100644 --- a/gix-config/tests/config.rs +++ b/gix-config/tests/config/mod.rs @@ -2,7 +2,6 @@ pub use gix_testtools::Result; mod file; mod key; -mod mem; mod parse; mod source; mod value; diff --git a/gix-config/tests/parse/error.rs b/gix-config/tests/config/parse/error.rs similarity index 100% rename from gix-config/tests/parse/error.rs rename to gix-config/tests/config/parse/error.rs diff --git a/gix-config/tests/parse/from_bytes.rs b/gix-config/tests/config/parse/from_bytes.rs similarity index 97% rename from gix-config/tests/parse/from_bytes.rs rename to gix-config/tests/config/parse/from_bytes.rs index 736ddfedca0..fd25f84d0e4 100644 --- a/gix-config/tests/parse/from_bytes.rs +++ b/gix-config/tests/config/parse/from_bytes.rs @@ -8,7 +8,7 @@ fn fuzz() { ); assert!( Events::from_str(include_str!( - "../fixtures/clusterfuzz-testcase-minimized-gix-config-parse-6431708583690240" + "../../fixtures/clusterfuzz-testcase-minimized-gix-config-parse-6431708583690240" )) .is_err(), "works without hanging - these 400kb take 10s in debug mode right now, but just as long in release mode. With nom all tests ran in below 1s in debug mode" diff --git a/gix-config/tests/parse/mod.rs b/gix-config/tests/config/parse/mod.rs similarity index 100% rename from gix-config/tests/parse/mod.rs rename to gix-config/tests/config/parse/mod.rs diff --git a/gix-config/tests/parse/section.rs b/gix-config/tests/config/parse/section.rs similarity index 100% rename from gix-config/tests/parse/section.rs rename to gix-config/tests/config/parse/section.rs diff --git a/gix-config/tests/source/mod.rs b/gix-config/tests/config/source/mod.rs similarity index 100% rename from gix-config/tests/source/mod.rs rename to gix-config/tests/config/source/mod.rs diff --git a/gix-config/tests/value/mod.rs b/gix-config/tests/config/value/mod.rs similarity index 100% rename from gix-config/tests/value/mod.rs rename to gix-config/tests/config/value/mod.rs diff --git a/gix-config/tests/value/normalize.rs b/gix-config/tests/config/value/normalize.rs similarity index 100% rename from gix-config/tests/value/normalize.rs rename to gix-config/tests/config/value/normalize.rs From 581ef672862b20b1d272d8a0ee4a9646478f3a49 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 6 Nov 2024 16:42:26 +0100 Subject: [PATCH 2/4] remove `gix` dev-dependency. It's not really required. --- Cargo.lock | 1 - gix-config/tests/Cargo.toml | 1 - .../from_paths/includes/conditional/mod.rs | 27 +++-- .../includes/conditional/onbranch.rs | 108 ++++++++---------- 4 files changed, 64 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d8aee88db33..083a1ea1c78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1586,7 +1586,6 @@ dependencies = [ "bstr", "bytesize", "cap", - "gix", "gix-config", "gix-path 0.10.12", "gix-ref 0.48.0", diff --git a/gix-config/tests/Cargo.toml b/gix-config/tests/Cargo.toml index 1b43a62997d..36895eb9373 100644 --- a/gix-config/tests/Cargo.toml +++ b/gix-config/tests/Cargo.toml @@ -23,7 +23,6 @@ path = "mem.rs" [dev-dependencies] gix-config = { path = ".." } gix-testtools = { path = "../../tests/tools" } -gix = { path = "../../gix", default-features = false } gix-ref = { path = "../../gix-ref" } gix-path = { path = "../../gix-path" } gix-sec = { path = "../../gix-sec" } diff --git a/gix-config/tests/config/file/init/from_paths/includes/conditional/mod.rs b/gix-config/tests/config/file/init/from_paths/includes/conditional/mod.rs index 4ce070bad80..1cbbd99d90c 100644 --- a/gix-config/tests/config/file/init/from_paths/includes/conditional/mod.rs +++ b/gix-config/tests/config/file/init/from_paths/includes/conditional/mod.rs @@ -137,18 +137,21 @@ fn options_with_git_dir(git_dir: &Path) -> init::Options<'_> { } } -fn git_init(path: impl AsRef, bare: bool) -> crate::Result { - Ok(gix::ThreadSafeRepository::init_opts( - path, - if bare { - gix::create::Kind::Bare - } else { - gix::create::Kind::WithWorktree - }, - gix::create::Options::default(), - gix::open::Options::isolated().config_overrides(["user.name=gitoxide", "user.email=gitoxide@localhost"]), - )? - .to_thread_local()) +fn git_init(dir: impl AsRef, bare: bool) -> crate::Result { + let dir = dir.as_ref(); + let mut args = vec!["init"]; + if bare { + args.push("--bare"); + } + let output = std::process::Command::new(gix_path::env::exe_invocation()) + .args(args) + .arg(dir) + .env_remove("GIT_CONFIG_COUNT") + .env_remove("XDG_CONFIG_HOME") + .output()?; + + assert!(output.status.success(), "{output:?}, {dir:?}"); + Ok(()) } fn create_symlink(from: impl AsRef, to: impl AsRef) { diff --git a/gix-config/tests/config/file/init/from_paths/includes/conditional/onbranch.rs b/gix-config/tests/config/file/init/from_paths/includes/conditional/onbranch.rs index c6c2c7b2ffb..6b7e1d6042a 100644 --- a/gix-config/tests/config/file/init/from_paths/includes/conditional/onbranch.rs +++ b/gix-config/tests/config/file/init/from_paths/includes/conditional/onbranch.rs @@ -6,10 +6,7 @@ use gix_config::file::{ includes::conditional, init::{self}, }; -use gix_ref::{ - transaction::{Change, PreviousValue, RefEdit}, - FullName, Target, -}; +use gix_ref::FullName; use gix_testtools::tempfile::tempdir; use crate::file::{cow_str, init::from_paths::includes::conditional::git_init}; @@ -24,7 +21,7 @@ fn literal_branch_names_match() -> Result { branch_name: "refs/heads/literal-match", expect: Value::OverrideByInclude, }, - GitEnv::new()?, + &mut GitEnv::new()?, )?; Ok(()) } @@ -37,7 +34,7 @@ fn full_ref_names_do_not_match() -> Result { branch_name: "refs/heads/simple", expect: Value::Base, }, - GitEnv::new()?, + &mut GitEnv::new()?, )?; Ok(()) } @@ -50,7 +47,7 @@ fn non_branches_never_match() -> Result { branch_name: "refs/bisect/good", expect: Value::Base, }, - GitEnv::new()?, + &mut GitEnv::new()?, )?; Ok(()) } @@ -58,21 +55,21 @@ fn non_branches_never_match() -> Result { #[test] fn patterns_ending_with_slash_match_subdirectories_recursively() -> Result { let mut env = GitEnv::new()?; - env = assert_section_value( + assert_section_value( Options { condition: "feature/b/", branch_name: "refs/heads/feature/b/start", expect: Value::OverrideByInclude, }, - env, + &mut env, )?; - env = assert_section_value( + assert_section_value( Options { condition: "feature/", branch_name: "refs/heads/feature/b/start", expect: Value::OverrideByInclude, }, - env, + &mut env, )?; assert_section_value_msg( Options { @@ -80,7 +77,7 @@ fn patterns_ending_with_slash_match_subdirectories_recursively() -> Result { branch_name: "refs/heads/feature/b/start", expect: Value::OverrideByInclude, }, - env, + &mut env, "just for good measure, we would expect branch paths to work as well".into(), )?; Ok(()) @@ -89,38 +86,38 @@ fn patterns_ending_with_slash_match_subdirectories_recursively() -> Result { #[test] fn simple_glob_patterns() -> Result { let mut env = GitEnv::new()?; - env = assert_section_value( + assert_section_value( Options { condition: "prefix*", branch_name: "refs/heads/prefixsuffix", expect: Value::OverrideByInclude, }, - env, + &mut env, )?; - env = assert_section_value_msg( + assert_section_value_msg( Options { condition: "prefix*", branch_name: "refs/heads/prefix/suffix", expect: Value::Base, }, - env, + &mut env, "single-stars do not cross component boundaries".into(), )?; - env = assert_section_value( + assert_section_value( Options { condition: "*suffix", branch_name: "refs/heads/prefixsuffix", expect: Value::OverrideByInclude, }, - env, + &mut env, )?; - env = assert_section_value( + assert_section_value( Options { condition: "*/suffix", branch_name: "refs/heads/prefix/suffix", expect: Value::OverrideByInclude, }, - env, + &mut env, )?; assert_section_value_msg( Options { @@ -128,7 +125,7 @@ fn simple_glob_patterns() -> Result { branch_name: "refs/heads/prefix/suffix", expect: Value::Base, }, - env, + &mut env, "single-stars do not cross component boundaries".into(), )?; Ok(()) @@ -137,13 +134,13 @@ fn simple_glob_patterns() -> Result { #[test] fn simple_globs_do_not_cross_component_boundary() -> Result { let mut env = GitEnv::new()?; - env = assert_section_value( + assert_section_value( Options { condition: "feature/*/start", branch_name: "refs/heads/feature/a/start", expect: Value::OverrideByInclude, }, - env, + &mut env, )?; assert_section_value_msg( Options { @@ -151,7 +148,7 @@ fn simple_globs_do_not_cross_component_boundary() -> Result { branch_name: "refs/heads/feature/a/b/start", expect: Value::Base, }, - env, + &mut env, "path matching would never match 'a/b' as it cannot cross /".into(), )?; Ok(()) @@ -165,7 +162,7 @@ fn double_star_globs_cross_component_boundaries() -> Result { branch_name: "refs/heads/feature/a/b/start", expect: Value::OverrideByInclude, }, - GitEnv::new()?, + &mut GitEnv::new()?, )?; Ok(()) } @@ -177,15 +174,14 @@ enum Value { #[derive(Debug)] struct GitEnv { - repo: gix::Repository, dir: gix_testtools::tempfile::TempDir, } impl GitEnv { fn new() -> crate::Result { let dir = tempdir()?; - let repo = git_init(dir.path(), true)?; - Ok(GitEnv { repo, dir }) + git_init(dir.path(), true)?; + Ok(GitEnv { dir }) } } @@ -195,7 +191,7 @@ struct Options<'a> { expect: Value, } -fn assert_section_value(opts: Options, env: GitEnv) -> crate::Result { +fn assert_section_value(opts: Options, env: &mut GitEnv) -> crate::Result { assert_section_value_msg(opts, env, None) } @@ -205,9 +201,9 @@ fn assert_section_value_msg( branch_name, expect, }: Options, - GitEnv { repo, dir }: GitEnv, + GitEnv { dir }: &mut GitEnv, message: Option<&str>, -) -> crate::Result { +) -> crate::Result<()> { let root_config = dir.path().join("config"); let included_config = dir.path().join("include.config"); @@ -264,36 +260,23 @@ value = branch-override-by-include "the base value is overridden by an included file because the condition matches", }, message, - dir.into_path() + { + let dir = std::mem::replace( + dir, + gix_testtools::tempfile::TempDir::new().expect("substitute can be created"), + ); + dir.into_path() + } ); - repo.refs - .transaction() - .prepare( - Some(RefEdit { - name: "HEAD".try_into()?, - change: Change::Update { - log: Default::default(), - expected: PreviousValue::Any, - new: Target::Symbolic(branch_name), - }, - deref: false, - }), - gix::lock::acquire::Fail::Immediately, - gix::lock::acquire::Fail::Immediately, - )? - .commit(repo.committer().transpose()?)?; - - let dir = assure_git_agrees(expect, dir)?; - Ok(GitEnv { repo, dir }) + std::fs::write(dir.path().join("HEAD"), format!("ref: {}", branch_name.as_bstr()))?; + assure_git_agrees(expect, dir)?; + Ok(()) } -fn assure_git_agrees( - expected: Value, - dir: gix_testtools::tempfile::TempDir, -) -> crate::Result { +fn assure_git_agrees(expected: Value, dir: &mut gix_testtools::tempfile::TempDir) -> crate::Result { let git_dir = dir.path(); - let output = std::process::Command::new("git") + let output = std::process::Command::new(gix_path::env::exe_invocation()) .args(["config", "--get", "section.value"]) .env("GIT_DIR", git_dir) .env("HOME", git_dir) @@ -302,11 +285,18 @@ fn assure_git_agrees( .current_dir(git_dir) .output()?; + let mut keep_dir_on_disk = || { + let dir = std::mem::replace( + dir, + gix_testtools::tempfile::TempDir::new().expect("substitute can be created"), + ); + dir.into_path() + }; assert!( output.status.success(), "{:?}, {:?} for debugging", output, - dir.into_path() + keep_dir_on_disk() ); let git_output: BString = output.stdout.trim_end().into(); assert_eq!( @@ -316,7 +306,7 @@ fn assure_git_agrees( Value::OverrideByInclude => "branch-override-by-include", }, "git disagrees with gix-config, {:?} for debugging", - dir.into_path() + keep_dir_on_disk() ); - Ok(dir) + Ok(()) } From 92558a1fecae4175e599aec624b30b2be1c6db8d Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 6 Nov 2024 14:38:46 +0100 Subject: [PATCH 3/4] feat: add `hasconfig:remotes.*.url:` --- crate-status.md | 2 +- gix-config/src/file/includes/mod.rs | 84 ++++++--- .../includes/conditional/hasconfig.rs | 78 +++++++++ .../from_paths/includes/conditional/mod.rs | 1 + .../fixtures/generated-archives/hasconfig.tar | Bin 0 -> 284160 bytes gix-config/tests/fixtures/hasconfig.sh | 164 ++++++++++++++++++ 6 files changed, 302 insertions(+), 27 deletions(-) create mode 100644 gix-config/tests/config/file/init/from_paths/includes/conditional/hasconfig.rs create mode 100644 gix-config/tests/fixtures/generated-archives/hasconfig.tar create mode 100755 gix-config/tests/fixtures/hasconfig.sh diff --git a/crate-status.md b/crate-status.md index 502583127b8..24f179e2e8e 100644 --- a/crate-status.md +++ b/crate-status.md @@ -747,7 +747,7 @@ See its [README.md](https://github.com/GitoxideLabs/gitoxide/blob/main/gix-lock/ * all config values as per the `gix-config-value` crate * **includeIf** * [x] `gitdir`, `gitdir/i`, and `onbranch` - * [ ] `hasconfig` + * [x] `hasconfig:remote.*.url` * [x] access values and sections by name and sub-section * [x] edit configuration in memory, non-destructively * cross-platform newline handling diff --git a/gix-config/src/file/includes/mod.rs b/gix-config/src/file/includes/mod.rs index efb76d1f5b9..434042ea9ac 100644 --- a/gix-config/src/file/includes/mod.rs +++ b/gix-config/src/file/includes/mod.rs @@ -23,11 +23,16 @@ impl File<'static> { /// times. It's recommended use is as part of a multi-step bootstrapping which needs fine-grained control, /// and unless that's given one should prefer one of the other ways of initialization that resolve includes /// at the right time. + /// + /// # Deviation + /// /// - included values are added after the _section_ that included them, not directly after the value. This is /// a deviation from how git does it, as it technically adds new value right after the include path itself, /// technically 'splitting' the section. This can only make a difference if the `include` section also has values /// which later overwrite portions of the included file, which seems unusual as these would be related to `includes`. /// We can fix this by 'splitting' the include section if needed so the included sections are put into the right place. + /// - `hasconfig:remote.*.url` will not prevent itself to include files with `[remote "name"]\nurl = x` values, but it also + /// won't match them, i.e. one cannot include something that will cause the condition to match or to always be true. pub fn resolve_includes(&mut self, options: init::Options<'_>) -> Result<(), Error> { if options.includes.max_depth == 0 { return Ok(()); @@ -38,10 +43,11 @@ impl File<'static> { } pub(crate) fn resolve(config: &mut File<'static>, buf: &mut Vec, options: init::Options<'_>) -> Result<(), Error> { - resolve_includes_recursive(config, 0, buf, options) + resolve_includes_recursive(None, config, 0, buf, options) } fn resolve_includes_recursive( + search_config: Option<&File<'static>>, target_config: &mut File<'static>, depth: u8, buf: &mut Vec, @@ -57,30 +63,34 @@ fn resolve_includes_recursive( }; } - let mut section_ids_and_include_paths = Vec::new(); - for (id, section) in target_config - .section_order - .iter() - .map(|id| (*id, &target_config.sections[id])) - { + for id in target_config.section_order.clone().into_iter() { + let section = &target_config.sections[&id]; let header = §ion.header; let header_name = header.name.as_ref(); + let mut paths = None; if header_name == "include" && header.subsection_name.is_none() { - detach_include_paths(&mut section_ids_and_include_paths, section, id); + paths = Some(gather_paths(section, id)); } else if header_name == "includeIf" { if let Some(condition) = &header.subsection_name { let target_config_path = section.meta.path.as_deref(); - if include_condition_match(condition.as_ref(), target_config_path, options.includes)? { - detach_include_paths(&mut section_ids_and_include_paths, section, id); + if include_condition_match( + condition.as_ref(), + target_config_path, + search_config.unwrap_or(target_config), + options.includes, + )? { + paths = Some(gather_paths(section, id)); } } } + if let Some(paths) = paths { + insert_includes_recursively(paths, target_config, depth, options, buf)?; + } } - - append_followed_includes_recursively(section_ids_and_include_paths, target_config, depth, options, buf) + Ok(()) } -fn append_followed_includes_recursively( +fn insert_includes_recursively( section_ids_and_include_paths: Vec<(SectionId, crate::Path<'_>)>, target_config: &mut File<'static>, depth: u8, @@ -124,30 +134,26 @@ fn append_followed_includes_recursively( init::Error::Interpolate(err) => Error::Interpolate(err), init::Error::Includes(_) => unreachable!("BUG: {:?} not possible due to no-follow options", err), })?; - resolve_includes_recursive(&mut include_config, depth + 1, buf, options)?; + resolve_includes_recursive(Some(target_config), &mut include_config, depth + 1, buf, options)?; target_config.append_or_insert(include_config, Some(section_id)); } Ok(()) } -fn detach_include_paths( - include_paths: &mut Vec<(SectionId, crate::Path<'static>)>, - section: &file::Section<'_>, - id: SectionId, -) { - include_paths.extend( - section - .body - .values("path") - .into_iter() - .map(|path| (id, crate::Path::from(Cow::Owned(path.into_owned())))), - ); +fn gather_paths(section: &file::Section<'_>, id: SectionId) -> Vec<(SectionId, crate::Path<'static>)> { + section + .body + .values("path") + .into_iter() + .map(|path| (id, crate::Path::from(Cow::Owned(path.into_owned())))) + .collect() } fn include_condition_match( condition: &BStr, target_config_path: Option<&Path>, + search_config: &File<'static>, options: Options<'_>, ) -> Result { let mut tokens = condition.splitn(2, |b| *b == b':'); @@ -170,6 +176,32 @@ fn include_condition_match( gix_glob::wildmatch::Mode::IGNORE_CASE, ), b"onbranch" => Ok(onbranch_matches(condition, options.conditional).is_some()), + b"hasconfig" => { + let mut tokens = condition.splitn(2, |b| *b == b':'); + let (key_glob, value_glob) = match (tokens.next(), tokens.next()) { + (Some(a), Some(b)) => (a, b), + _ => return Ok(false), + }; + if key_glob.as_bstr() != "remote.*.url" { + return Ok(false); + } + let Some(sections) = search_config.sections_by_name("remote") else { + return Ok(false); + }; + for remote in sections { + for url in remote.values("url") { + let glob_matches = gix_glob::wildmatch( + value_glob.as_bstr(), + url.as_ref(), + gix_glob::wildmatch::Mode::NO_MATCH_SLASH_LITERAL, + ); + if glob_matches { + return Ok(true); + } + } + } + Ok(false) + } _ => Ok(false), } } diff --git a/gix-config/tests/config/file/init/from_paths/includes/conditional/hasconfig.rs b/gix-config/tests/config/file/init/from_paths/includes/conditional/hasconfig.rs new file mode 100644 index 00000000000..5ed6de7a030 --- /dev/null +++ b/gix-config/tests/config/file/init/from_paths/includes/conditional/hasconfig.rs @@ -0,0 +1,78 @@ +use gix_config::file::{includes, init}; +use std::path::{Path, PathBuf}; + +#[test] +fn simple() -> crate::Result { + let (config, root) = config_with_includes("basic")?; + compare_baseline(&config, "user.this", root.join("expected")); + assert_eq!(config.string("user.that"), None); + Ok(()) +} + +#[test] +fn inclusion_order() -> crate::Result { + let (config, root) = config_with_includes("inclusion-order")?; + for key in ["one", "two", "three"] { + compare_baseline(&config, format!("user.{key}"), root.join(format!("expected.{key}"))); + } + Ok(()) +} + +#[test] +fn globs() -> crate::Result { + let (config, root) = config_with_includes("globs")?; + for key in ["dss", "dse", "dsm", "ssm"] { + compare_baseline(&config, format!("user.{key}"), root.join(format!("expected.{key}"))); + } + assert_eq!(config.string("user.no"), None); + Ok(()) +} + +#[test] +fn cycle_breaker() -> crate::Result { + for name in ["cycle-breaker-direct", "cycle-breaker-indirect"] { + let (_config, _root) = config_with_includes(name)?; + } + + Ok(()) +} + +#[test] +fn no_cycle() -> crate::Result { + let (config, root) = config_with_includes("no-cycle")?; + compare_baseline(&config, "user.name", root.join("expected")); + Ok(()) +} + +fn compare_baseline(config: &gix_config::File<'static>, key: impl AsRef, expected: impl AsRef) { + let expected = expected.as_ref(); + let key = key.as_ref(); + assert_eq!( + config + .string(key) + .unwrap_or_else(|| panic!("key '{key} should be included")) + .as_ref(), + std::fs::read_to_string(expected) + .unwrap_or_else(|err| panic!("Couldn't find '{expected:?}' for reading: {err}")) + .trim(), + "baseline with git should match: '{key}' != {expected:?}" + ); +} + +fn config_with_includes(name: &str) -> crate::Result<(gix_config::File<'static>, PathBuf)> { + let root = gix_testtools::scripted_fixture_read_only_standalone("hasconfig.sh")?.join(name); + let options = init::Options { + includes: includes::Options::follow(Default::default(), Default::default()), + ..Default::default() + }; + + let config = gix_config::File::from_paths_metadata( + Some(gix_config::file::Metadata::try_from_path( + root.join("config"), + gix_config::Source::Local, + )?), + options, + )? + .expect("non-empty"); + Ok((config, root)) +} diff --git a/gix-config/tests/config/file/init/from_paths/includes/conditional/mod.rs b/gix-config/tests/config/file/init/from_paths/includes/conditional/mod.rs index 1cbbd99d90c..ea3a4efbc70 100644 --- a/gix-config/tests/config/file/init/from_paths/includes/conditional/mod.rs +++ b/gix-config/tests/config/file/init/from_paths/includes/conditional/mod.rs @@ -9,6 +9,7 @@ use gix_testtools::tempfile::tempdir; use crate::file::{cow_str, init::from_paths::escape_backslashes}; mod gitdir; +mod hasconfig; mod onbranch; #[test] diff --git a/gix-config/tests/fixtures/generated-archives/hasconfig.tar b/gix-config/tests/fixtures/generated-archives/hasconfig.tar new file mode 100644 index 0000000000000000000000000000000000000000..adfe35d3f84c6d8738e79bc1e4a6d922e7b680b5 GIT binary patch literal 284160 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 literal 0 HcmV?d00001 diff --git a/gix-config/tests/fixtures/hasconfig.sh b/gix-config/tests/fixtures/hasconfig.sh new file mode 100755 index 00000000000..39f26534c17 --- /dev/null +++ b/gix-config/tests/fixtures/hasconfig.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env bash +set -eu -o pipefail + +git init --bare basic +(cd basic + cat >include-this <<-\EOF + [user] + this = this-is-included +EOF + + cat >dont-include-that <<-\EOF + [user] + that = that-is-not-included +EOF + + cat >>config <<-EOF + [includeIf "hasconfig:remote.*.url:foourl"] + path = "include-this" + [includeIf "hasconfig:remote.*.url:barurl"] + path = "dont-include-that" + [remote "foo"] + url = foourl +EOF + + git config --get user.this >expected +) + +git init --bare inclusion-order +(cd inclusion-order + cat >include-two-three <<-\EOF + [user] + two = included-config + three = included-config +EOF + cat >include-four <<-\EOF + [user] + four = included-config +EOF + cat >include-five <<-\EOF + [user] + five = included-config +EOF + cat >indirect <<-\EOF + [includeIf "hasconfig:remote.*.url:early"] + path = "include-five" +EOF + cat >>config <<-EOF + [remote "foo"] + url = before + [remote "other"] + url = early + [user] + one = main-config + [includeIf "hasconfig:remote.*.url:before"] + path = "include-two-three" + [includeIf "hasconfig:remote.*.url:after"] + path = "include-four" + [user] + three = main-config + five = main-config + [remote "bar"] + url = after + [include] + path = "indirect" +EOF + git config --get user.one >expected.one + git config --get user.two >expected.two + git config --get user.three >expected.three + git config --get user.four >expected.four + git config --get user.five >expected.five +) + +git init --bare globs +(cd globs + printf "[user]\ndss = yes\n" >double-star-start + printf "[user]\ndse = yes\n" >double-star-end + printf "[user]\ndsm = yes\n" >double-star-middle + printf "[user]\nssm = yes\n" >single-star-middle + printf "[user]\nno = no\n" >no + + cat >>config <<-EOF + [remote "foo"] + url = https://foo/bar/baz + [includeIf "hasconfig:remote.*.url:**/baz"] + path = "double-star-start" + [includeIf "hasconfig:remote.*.url:**/nomatch"] + path = "no" + [includeIf "hasconfig:remote.*.url:https:/**"] + path = "double-star-end" + [includeIf "hasconfig:remote.*.url:nomatch:/**"] + path = "no" + [includeIf "hasconfig:remote.*.url:https:/**/baz"] + path = "double-star-middle" + [includeIf "hasconfig:remote.*.url:https:/**/nomatch"] + path = "no" + [includeIf "hasconfig:remote.*.url:https://*/bar/baz"] + path = "single-star-middle" + [includeIf "hasconfig:remote.*.url:https://*/baz"] + path = "no" +EOF + + git config --get user.dss > expected.dss + git config --get user.dse > expected.dse + git config --get user.dsm > expected.dsm + git config --get user.ssm > expected.ssm +) + + +git init --bare cycle-breaker-direct +(cd cycle-breaker-direct + cat >include-with-url <<-\EOF + [remote "bar"] + url = barurl +EOF + cat >>config <<-EOF + [include] + path = "include-with-url" + [includeIf "hasconfig:remote.*.url:foourl"] + path = "include-with-url" + [include] + path = "include-with-url" +EOF +) + +git init --bare cycle-breaker-indirect +(cd cycle-breaker-indirect + cat >include-with-url <<-\EOF + [include] + path = indirect +EOF + cat >indirect <<-\EOF + [remote "bar"] + url = barurl +EOF + cat >>config <<-EOF + [include] + path = "include-with-url" + [includeIf "hasconfig:remote.*.url:foourl"] + path = "include-with-url" + [include] + path = "include-with-url" +EOF +) + +git init --bare no-cycle +(cd no-cycle + cat >include-with-url <<-\EOF + [user] + name = "works" +EOF + cat >remote <<-\EOF + [remote "bar"] + url = barurl +EOF + cat >>config <<-EOF + [include] + path = "remote" + [includeIf "hasconfig:remote.*.url:barurl"] + path = "include-with-url" + [include] + path = "remote" +EOF + git config --get user.name > expected +) From d51aec95588fee219dee62438d26e4574d38a497 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 7 Nov 2024 07:15:22 +0100 Subject: [PATCH 4/4] add test to assure `hasconfig` is working on `gix` level as well. --- .../generated-archives/make_config_repos.tar | Bin 1157120 -> 1112064 bytes gix/tests/fixtures/make_config_repos.sh | 17 +++++ gix/tests/gix/repository/config/identity.rs | 61 ++++++++++-------- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/gix/tests/fixtures/generated-archives/make_config_repos.tar b/gix/tests/fixtures/generated-archives/make_config_repos.tar index 77529fdf5d187ad2d7f287e34ba71d82aca7dcae..426d7c022f5dd2b11babd6b73627a76509fe5a6c 100644 GIT binary patch delta 11868 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 SoN)i#dbnji-|GGEzW)a;fg2A1 delta 65784 zcmeI5eQZ?ap2zQbn>q77R9=QsriW4y43wGawDq!xytRT>aM@n$Wr;eSnbKlyd)x9V zmli0c)XIX@IRkMGmo=6c;w5eE!?LdHz1J9G%*MSjh7iKC#<0c^VqBIGmW%s+o^xjC zOsDLc82INgxq8prb6)1m^po%R_xnCw->>NUqUyMqI3Z3ZlaGrQndFBg)u|WmRF~_q zi%OUzS4w*YlD|aSEQ-O3;ht+d1^2>+mY3rT<1a02i?_D4>$8?iRciTTp}=FMkNuLg zESHW5N3@3$r^G^1_?{?=y1!aoF%a8{!SbZuDTCTIaVpW~O1Bh}e@e8t2eohU@Ai0e zEdFw&v1!59NK>Oe>yW+tNUShF91etk5e$UOgMm;WR2uk2AP@?L0>NJd1|mmd!$R33 z!V2ski*&@bh}IhEh&E_*Bh9geEp6sfd%UeN-ab#Oi`Tcb#qF~-dZxzaOE!q%|zJ!4z#^~(Q=h6#} zMw&4?y_lxPcnmvh9WAX|OFagomtl^kZE0=qXp2X1C2f)BPTcmk#*T)TEgf34rMbST zG1}3tH8$g!w8ya`7HQj|ZEIv}N@j@ivS{A2qJE5$BlOz9kxsx3|}C!S%Ii z%`F}Ca87o{rbv5-`7p7Dj!2*Ae74OTvy(npc5k@ySiC9T5sw-7UxQ1oZ)s|3*+!oi zy|%_pI4>S@T~oY0b+hepJcSlKlSuQXc*bqE#b0irpKWstXD}Dq;`GAs;392tZA&{I zQYQ|k4{QfJmOV=h9@!LWY;NyZ#6Ad(eemqlE-~*rzRnnYuK7$C;m#X3H8#(~sV3fi z9nOCDh*g!#R?f3`(vNywytOG3H7>tq?aH+pTWn})ipAU7*~c^X4KrQlu|C3bu2I$wykY>l_QfX9l@O`AJUd&O?6Z)}P`UQ`?`vfE~Bo%DQ* z(pNxVgZqP4fi@e;E451+}r61%OVZA;w#+cD=ezewXxRN36V1rI&*wbde> z>}54>GUFY@;G6K;<27ASsudN}i!Rc3?ZPM7v8Anv6aV==a?*^W=@$GrMcrN`!%x~g?1*zW?ChZH0jsHXcTVKR(DdUmg z?;8CgFNol4GX6Rn_B4)AU$U%{ar88mdpuZi0ybVLHc#x(oBC>pIlw@ z!pha_*ngi}yYA^1YSvX&+M}_t*H51TeW5mCOl`q$w4&!@jrH~PbHrG9dh}<;c!|GtZEIW$*RI(pP%i_L{Xd%c@hCk@0zLX?_Ve`hR^~ z^v&&Pi?nKwjD2(1-;}L!ygT({AIKwGW$o%3_G+YW%lIL&5B%HOh5C!%2wx=fq+(rr zR9;GA=f!`PbpLX7#hWo@majaRjVyt(P}o2gB77j#DwYL}z@6>Gzux*gY4oyKtm>Ly zUOEs91Cl-$d#yw}E6RDgHb-8n#}>J;_Dk^~&M;M7p~p&OEMF9RC8EjFElJO>k{a^^ z6`}I1vj)pbgQcmn{=N9Of_`w7l<&G1y-ivzEfj!m`Gff-5@_%pQ4vYuN%4P#!Tfhc z(MnkZ-!FYut*~9jEtOFUBf_uT(*)vM=LSIfzi}G?xnv+VT1xaE+y{g~|MzZ@_&2(( z3`;{D= z7@Ck1D?*$TIVW;X#^Nbk9*yH*h*n>u>p&_-ThX5=5;F=>4F2Bo7{&dQEXgHVmP;UhuVbnI0Q)m64+x-1~ugweAc|#Mz-EDy6tX6BZZRCJSWB92;P9#u=Ldix`5b zji1`~34=2}v590xzy?~>w!4-a(qYneaEe}7;{yM#5^?n%wmvK$qRWRU9KLVcr;r&T z8<4SZ4PATPg}s_>eYudaY(iuVab)b^$jFhABO^yfE-g}3jZ2GMTDY0a+Xlpw|OAUSZw^E+X9Zd*{!kP_={4>Ktd5*w8g*VztQ^+Ju}&=3_3 zm)c%qbckV@sJOw_hhdkyVD>Umv5uamaIG zOi6qaYxLM#UhH#w57QEjHD|0q!E#}jGEgwt7^hY$9oEn8by0bd?lT;_@j)(7d>o)C zQxBRP7*Y2L1NL%1x0|`$%q0+s)i==617DwU(}vNO}6qI{sPh=AkS3Ohu&J zlUqm(Rs>5;$8)^RJala)L&KGNWTUlWIC)_Y6AleR8j`_7=Xw|%VuukGJAA#D$%piG zdThM|Q1#s&CLkJzFby$J*d+}Vyk|hwQfZd2v?5zcEUgHZ-Bl7d3Z!qHu$3x_ql<-y zz=BTW;C@Tl@X?`8feMOP10oxxBO)@*1`bEJI6;nR+ zTf&4sw8@IMT)Tt;sr+HiikuZWD{@xktjJlBvm$53`^JiiPldTuKU_@pLx^Af!Xc&~ zPUt{~??PI3eImxX>p)|yH-sZ;2O5iA!fQ-pOgYfaLfV1u72rTaUQ9XAhXpv$kQY-9 z^cjIV&^H7)&|tXCE{|Y&5UzBF1AS949OxGXIM81UV7yuZ4z%CxV)il6ZKFUP=nX=K z5NSBjBzex!ASAj~FY$J%7FqXQlB!8vp6x@2u3eQ@>UC>`a+1_+y9M3%om6cu``Pk( zsd}Jp6r20h{eoWjkyJTQhklmC4{Fa8-G5A~((6`<*!-_*H`m&RlZrL%x3=cSuuzIjGYTY)wNui4*C;zJm1g@&$91=a%Yx~u zNuxxu*z~5|wyEH|XH(GD4d+&$StC8E*9B}iQ?L44Fy1;k@*FFcd$63PEJE>Q=Cdd^ z3PiNHrpY>L6;~S&m~rI zB%I0XIv^0#H2yec5Q5`Wg8IcN?6)grU%FPGC`=NP1 zH1CJz{m{H0dR+G??}r}S-pc!-c|Y{e-sh57WphP|TwY6NvZKTa- zSs=>iHYeC~tEC$Dv>rRoiZ|_D&=|WdD^155T{`w1Ake*RC+cC7f|AJca-{K?HgYy-CT`mDnOu29v*@vN7I2Z%zK@yPbbLLw zk@D0{TPNhpJBmSFsFWo76@RT7GMS9Yf16Y>+Z%UR6+% z$%-M76J(=k`5oKIK+8X4O$NBK-kT<8nT#i6vg>owBtd_u!~WNLv`Z}`$!e)f(x+P- zPY*<4dmp_d9dHo1^Fr>(jT}O%i-o z>PGYRE_;<8r3QJjM(P3s?xYL|HIy7(2PVvbO}%cpQX%6m8EFm(!jGdXy?LUZ_msEY z7aEs46t1WUrEvW@NfbO9f{)v2Ky|1jTvieqUKaWnG!HEtt?~+@JC!;fTCk45sdw}AP-t93cv&cr)!4J#Yc%$p^dNV9z8AUUCp9&rk$roLhiT; zlQehSE09U2TrTtiEy>IsuV%U9Ptn}*QCCLpxIZg*{Fcki9Y;B*0KGTt?m^S{8Ps61 z@Nt49$&Yi1k@v_QuP|#HxERUBNG?WlF_MdsT#V#mBo`y^vlw~VmC*$LjSEfS_lhAe z4W+fWY%wx%*>$%G9FTO?bvK5b78ttF1U@E){8N|N1g;~79F5tRUHv%qR5jHJ{;exB zi`>hy$k!l?oOaWU>jcjR#%Ike@(~w0!57gi^3yIei<}^f{4AQlhg@T*u~smez?CrW zFl~9O0mc*)9A-!MoycL7pKIE*p;R{D@_VFm7^K#Iqx9O zi0NlYa;MrL42eE**k}1xI3bIPK8uUEdM!wRr2Q?d5eM1hMX^U%;FNY>NC(tqY! zcNz^Z*o(yGSbuM{yRc&#>^SCi3-Wzv#|u^&E!wv%n2Lt>ys({Ei}qI*bZyhN7q*Jc zMdP*ZGCE(_D%PU?h6S_H&<+?j6m8M|!m=lq?M$bn$){7&WXYuXytul^)kUr@a&?ib zi|t%poZ*`HW2e+})2VXN5uHCHXWjJ_DQicVmI z`Jc1w=hAe%VyYo~zSXE#JYjiApDvmZ*-ImjrdrY9O}k|<9*Ol^MvP_|EE&Dnhb^xd z?J~w1Amky-&di1xvy)q)0ZFD+y-b-Rkf}=)Olwo{g)&CL#POFD%$Qwp5mIQuD#a8r zfuiu_Pb*ZqoJ(Pw&6wTKmYI~v>Ks2+x)oCJlrmP#B*`A-C#socL9S-VeWr(|C{^Y-2dkOH}}7}|IPjH`|E#?zU9O;G1K=t zo_;f;6ps(*36__p4At?oX^+0+oUZBxRgP6`I&G3X?EI}&_k}4Y(MfLf-Ojy}^nx{X zdoO}=5=kdbR9ue)p2&I!wjX!y#`HG3>Hc)Oo5VTi4r$QygHtA+2I_84D{?$TB2CWs zg+b3|X9nnD=4*!zaj{$qr%2DpZ@lS7eq)0jF+3kTK%D+Q4`OU=d9AeK%9h@tXQKA#Pj6uG3xB}FbNa!HX(id<5B zAd=$fO-HdzXFXh++p`V@gJly=Vw1S)fF7BzLXSjm%m+#5-?7%1#|=gCsso)em=Y0_ z*<5h^iB(KKuE%<5!QyoXgv-KS2`wrpnI!scx{P@dK~v1KE_Nc-(SMB67Uo5qR+ep7 zmsOOeFUp8=j5!TG@l(f4-QPnGyzB-eu5nUEyzRy^W5iD!2iY`<@Qa}%()qG6*R}r+ z-F{I)isGkO9vkgw^w20FJOfj2{4dEa5XTyCy0%gU0RnE1UiQ)%a9C|6Cawv1vFe(4 zd#bh)d$Cnl*(&6TAJJ42tM$S>H)<0@}$UAQOo1I=ve`C~I0;*W8WrH_s`Wuqi z>rIziVz2cMfL5Ou^WPZdmRQB+zZvq<@<_yxGeBeImgD?zbVq0L>kr;{ghZ`(l38ns z!4^|czUbYNsM zcvL3IN}?nXIVn#?7UiR6#bt_%A5&;^>v$bwj)EIwRp)Ju-eQSyOnZ^<+|{J2b`!{3(280R!P99PH)Z&3J?RUpDQ$~2i^ zvToH$FhBQYVRWy>ClcQ^G|~{vyp7C9%(gw1V18}T9H!I;&0!YpTr_u&nF&jIe+-uo zxqQgwLoOe3`H;(pTt0jt^5JNKr4VLzwWU56x&_N7jQSZZwq#C2=(Ql$5%Xai>;_eg zO+M(e96+F>W+qmN6#pNZqWA5xZQ+bk+JId4H}l z#zhmAF$TjyUdG7DkCPuKKTdv}{5bh>@_QiU2lmkjbiBX7jUACH->g$+k4L~@#h9|e zaYk`WE~K@Lm{^+TeCr|kAk;g*e4EuUf{$p&OVTO#PQrxA>^!|vC8;Zs&$7xz>_A&w z^z||fVOqJ!AT2S=hkVJbtetRKD6JtH#fu5qC|&n9s{3*vc_ zfIa__#fjqz8Fua!cPsj|D^?6rOCOO%1arzG@|+&bpg@qM z3z>C{!8Tek*c`E&rSX8FhGa0)WU-eu&|v$BiawPRk@mGrRe_zf(>hr$B772QJlLOM z=<_1DaoR2hZo+IIdX2LoG?W=VPWs*!S@!s7uQ&xvc!}Z~W5PQE^1lndwyvVeBp6U+ z40xF`;34^KA#q2Tk_DRzt29K9P6{?>IvfIV<~vN-WZ~m}2T1jlV~@d`Y*mQ1(VTUl zn2{nUR*~2l$NN|UaIzha)A-3^%v;F76RV7#nSRG!gFV?!ERVdw(Pc0wTgCFoPdHvN zFqExgjWcr`dkhj~L*2mH>l`^7XO>I^qk*zi!V-s34x=1KIgD}`^D%AT}rPIA{YvEN@*2)5j4(>7_7>UVLdau9f&BWxQbN+v7D+Y za*DD_B0n-_N=#^uJbhY&35+Kl?_(s;D?63nF>J6a8+R0dSH$oV^lGfZEohE$;pAww zk;O6@4~MCx!-7D2zI!bHEsWlD`!N%DpU0R>dx;S>l=K|HY}^S1P5MO-x@BO=BZP?N zlW+FC#w_`zBv$45n7Q$^rJT0*ba{FdfKa)h49&6=TL>D`&G$FXLy=Ml=9hzHuOfSMlj z9ATij7>zVoEcU#{On5L7re7qo~BI2(u6j8 zF!eV)`At5w#$@TB<-u^48UL2YG~?a=K_m%*_HMh8RXMYUWkD)s9~|}U2kqU-oQe_W zrorT4+@$HS|A*Bp=y}!BIz8G&CEE*DR0jAiN!7@s#A1_rz%2MQ@+fzzor3QBPO8?U zq6f)E+f@{R`qrm*|Hg_mOIGR`MSyv-T7}(COFc<+u6ow2@{Arr31_lSMU|(omJUSi z_T&}oezU|gN(oahQhRa{<}W8AOyocDD05DjoG>|Ia>C?<$qADa<^v(jM3Fj+N}QMv zoBHj^JQW#{tk^TE6p7_Qa^N%1K7rUpWvy&k(AXS{Zy)~k*564u4yB>_s=y3(9KF#B zrnIO%W?^Uajso1eZZ!;cY#&iEx|@xT5>Gu^0s}rdRi*C!Y4p-WF{?Mxm#Bz3_g$lu zMH4Cm*<1+_%#tg2s|HtIvQE=|7o=(uZBQYE`kqZ8-X&|dQQ1k5Rf$|k-#R+_a(Z=_ kt-CWTI`v4v_Lz*`8wQ&Lg76~=oL9aOjDHWb9(nP90Za4bMgRZ+ diff --git a/gix/tests/fixtures/make_config_repos.sh b/gix/tests/fixtures/make_config_repos.sh index be8b3f75706..e10354145d1 100755 --- a/gix/tests/fixtures/make_config_repos.sh +++ b/gix/tests/fixtures/make_config_repos.sh @@ -175,3 +175,20 @@ git init ssl-no-verify-enabled git config http.sslVerify true git config gitoxide.http.sslNoVerify true ) + + +git init --bare with-hasconfig +(cd with-hasconfig + cat >include-with-url <<-\EOF + [user] + name = "works" + email = "works@example.com" +EOF + cat >system.config <<-\EOF + [includeIf "hasconfig:remote.*.url:anyurl"] + path = "include-with-url" +EOF + + echo $'[remote "any"]\n\turl=anyurl' >>config + +) diff --git a/gix/tests/gix/repository/config/identity.rs b/gix/tests/gix/repository/config/identity.rs index ddbd0eb9607..4db71402619 100644 --- a/gix/tests/gix/repository/config/identity.rs +++ b/gix/tests/gix/repository/config/identity.rs @@ -1,10 +1,24 @@ -use std::path::Path; - +use crate::named_repo; +use crate::util::named_subrepo_opts; use gix_sec::Permission; use gix_testtools::Env; use serial_test::serial; +use std::path::Path; -use crate::named_repo; +#[test] +#[serial] +fn author_included_by_hasconfig() -> crate::Result { + let repo = named_subrepo_opts("make_config_repos.sh", "with-hasconfig", gix::open::Options::isolated())?; + let _env = Env::new().set( + "GIT_CONFIG_SYSTEM", + repo.git_dir().join("system.config").display().to_string(), + ); + let repo = gix::open_opts(repo.git_dir(), allow_system_options(repo.open_options().clone()))?; + let author = repo.author().expect("set in system config via include")?; + assert_eq!(author.name, "works"); + assert_eq!(author.email, "works@example.com"); + Ok(()) +} #[test] #[serial] @@ -29,17 +43,7 @@ fn author_and_committer_and_fallback() -> crate::Result { .set("GIT_CONFIG_VALUE_0", work_dir.join("c.config").display().to_string()); let repo = gix::open_opts( repo.git_dir(), - repo.open_options() - .clone() - .with(trust) - .permissions(gix::open::Permissions { - env: gix::open::permissions::Environment { - xdg_config_home: Permission::Deny, - home: Permission::Deny, - ..gix::open::permissions::Environment::all() - }, - ..Default::default() - }), + allow_system_options(repo.open_options().clone().with(trust)), )?; assert_eq!( @@ -147,18 +151,12 @@ fn author_from_different_config_sections() -> crate::Result { let repo = gix::open_opts( repo.git_dir(), - repo.open_options() - .clone() - .config_overrides(None::<&str>) - .with(gix_sec::Trust::Full) - .permissions(gix::open::Permissions { - env: gix::open::permissions::Environment { - xdg_config_home: Permission::Deny, - home: Permission::Deny, - ..gix::open::permissions::Environment::all() - }, - ..Default::default() - }), + allow_system_options( + repo.open_options() + .clone() + .config_overrides(None::<&str>) + .with(gix_sec::Trust::Full), + ), )?; assert_eq!( @@ -191,3 +189,14 @@ fn author_from_different_config_sections() -> crate::Result { ); Ok(()) } + +fn allow_system_options(opts: gix::open::Options) -> gix::open::Options { + opts.permissions(gix::open::Permissions { + env: gix::open::permissions::Environment { + xdg_config_home: Permission::Deny, + home: Permission::Deny, + ..gix::open::permissions::Environment::all() + }, + ..Default::default() + }) +}