Skip to content

Commit 580bee9

Browse files
committed
feat: respect the :(optional) prefix when interpolating paths via ConfigSnapshot::trusted_path().
Optional, but non-existing paths are now returned as `None`.
1 parent c2bc941 commit 580bee9

File tree

4 files changed

+62
-1
lines changed

4 files changed

+62
-1
lines changed

gix/src/config/cache/access.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,19 @@ pub(crate) fn trusted_file_path<'config>(
544544
let install_dir = crate::path::install_dir().ok();
545545
let home = home_dir(environment);
546546
let ctx = config::cache::interpolate_context(install_dir.as_deref(), home.as_deref());
547-
Some(path.interpolate(ctx))
547+
548+
let is_optional = path.is_optional;
549+
let res = path.interpolate(ctx);
550+
if is_optional {
551+
if let Ok(path) = &res {
552+
// As opposed to Git, for a lack of the right error variant, we ignore everything that can't
553+
// be stat'ed, instead of just checking if it doesn't exist via error code.
554+
if path.metadata().is_err() {
555+
return None;
556+
}
557+
}
558+
}
559+
Some(res)
548560
}
549561

550562
pub(crate) fn home_dir(environment: crate::open::permissions::Environment) -> Option<PathBuf> {

gix/src/config/snapshot/access.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ impl<'repo> Snapshot<'repo> {
5454
/// Return the trusted and fully interpolated path at `key`, or `None` if there is no such value
5555
/// or if no value was found in a trusted file.
5656
/// An error occurs if the path could not be interpolated to its final value.
57+
///
58+
/// ### Optional paths
59+
///
60+
/// The path can be prefixed with `:(optional)` which means it won't be returned if the interpolated
61+
/// path couldn't be accessed. Note also that this is different from Git, which ignores it only if
62+
/// it doesn't exist.
5763
pub fn trusted_path(
5864
&self,
5965
key: impl gix_config::AsKey,

gix/tests/gix/repository/config/config_snapshot/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,33 @@ fn commit_auto_rollback() -> crate::Result {
3333
Ok(())
3434
}
3535

36+
mod trusted_path {
37+
use crate::util::named_repo;
38+
39+
#[test]
40+
fn optional_is_respected() -> crate::Result {
41+
let mut repo: gix::Repository = named_repo("make_basic_repo.sh")?;
42+
repo.config_snapshot_mut().set_raw_value(&"my.path", "does-not-exist")?;
43+
44+
let actual = repo
45+
.config_snapshot()
46+
.trusted_path("my.path")
47+
.transpose()?
48+
.expect("is set");
49+
assert_eq!(
50+
actual.as_ref(),
51+
"does-not-exist",
52+
"the path isn't evaluated by default, and may not exist"
53+
);
54+
55+
repo.config_snapshot_mut()
56+
.set_raw_value(&"my.path", ":(optional)does-not-exist")?;
57+
let actual = repo.config_snapshot().trusted_path("my.path").transpose()?;
58+
assert_eq!(actual, None, "non-existing paths aren't returned to the caller");
59+
Ok(())
60+
}
61+
}
62+
3663
#[test]
3764
fn snapshot_mut_commit_and_forget() -> crate::Result {
3865
let mut repo: gix::Repository = named_repo("make_basic_repo.sh")?;

gix/tests/gix/repository/excludes.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,19 @@ fn empty_core_excludes() -> crate::Result {
2727
.expect("empty paths are now just skipped");
2828
Ok(())
2929
}
30+
31+
#[test]
32+
fn missing_core_excludes_is_ignored() -> crate::Result {
33+
let mut repo = named_subrepo_opts(
34+
"make_basic_repo.sh",
35+
"empty-core-excludes",
36+
gix::open::Options::default().strict_config(true),
37+
)?;
38+
repo.config_snapshot_mut()
39+
.set_value(&gix::config::tree::Core::EXCLUDES_FILE, "definitely-missing")?;
40+
41+
let index = repo.index_or_empty()?;
42+
repo.excludes(&index, None, Source::WorktreeThenIdMappingIfNotSkipped)
43+
.expect("the call works as missing excludes files are ignored");
44+
Ok(())
45+
}

0 commit comments

Comments
 (0)