Skip to content

Commit 8434aab

Browse files
committed
feat: add gitoxide.core.refsNamespace key and respect the GIT_NAMESPACE environment variable.
It's also provided as context value.
1 parent 0b3eb14 commit 8434aab

File tree

7 files changed

+98
-11
lines changed

7 files changed

+98
-11
lines changed

gix/src/config/cache/init.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ impl Cache {
144144

145145
use util::config_bool;
146146
let reflog = util::query_refupdates(&config, lenient_config)?;
147+
let refs_namespace = util::query_refs_namespace(&config, lenient_config)?;
147148
let ignore_case = config_bool(&config, &Core::IGNORE_CASE, "core.ignoreCase", false, lenient_config)?;
148149
let use_multi_pack_index = config_bool(
149150
&config,
@@ -167,6 +168,7 @@ impl Cache {
167168
pack_cache_bytes,
168169
object_cache_bytes,
169170
reflog,
171+
refs_namespace,
170172
is_bare,
171173
ignore_case,
172174
hex_len,
@@ -223,10 +225,12 @@ impl Cache {
223225
self.object_kind_hint = object_kind_hint;
224226
}
225227
let reflog = util::query_refupdates(config, self.lenient_config)?;
228+
let refs_namespace = util::query_refs_namespace(config, self.lenient_config)?;
226229

227230
self.hex_len = hex_len;
228231
self.ignore_case = ignore_case;
229232
self.reflog = reflog;
233+
self.refs_namespace = refs_namespace;
230234

231235
self.user_agent = Default::default();
232236
self.personas = Default::default();
@@ -299,6 +303,7 @@ impl crate::Repository {
299303

300304
fn apply_changed_values(&mut self) {
301305
self.refs.write_reflog = util::reflog_or_default(self.config.reflog, self.work_dir().is_some());
306+
self.refs.namespace = self.config.refs_namespace.clone();
302307
}
303308
}
304309

@@ -413,10 +418,16 @@ fn apply_environment_overrides(
413418
"gitoxide",
414419
Some(Cow::Borrowed("core".into())),
415420
git_prefix,
416-
&[{
417-
let key = &gitoxide::Core::SHALLOW_FILE;
418-
(env(key), key.name)
419-
}],
421+
&[
422+
{
423+
let key = &gitoxide::Core::SHALLOW_FILE;
424+
(env(key), key.name)
425+
},
426+
{
427+
let key = &gitoxide::Core::REFS_NAMESPACE;
428+
(env(key), key.name)
429+
},
430+
],
420431
),
421432
(
422433
"gitoxide",

gix/src/config/cache/util.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ pub(crate) fn query_refupdates(
5555
.map_err(Into::into)
5656
}
5757

58+
pub(crate) fn query_refs_namespace(
59+
config: &gix_config::File<'static>,
60+
lenient_config: bool,
61+
) -> Result<Option<gix_ref::Namespace>, config::refs_namespace::Error> {
62+
let key = "gitoxide.core.refsNamespace";
63+
config
64+
.string_by_key(key)
65+
.map(|ns| gitoxide::Core::REFS_NAMESPACE.try_into_refs_namespace(ns))
66+
.transpose()
67+
.with_leniency(lenient_config)
68+
}
69+
5870
pub(crate) fn reflog_or_default(
5971
config_reflog: Option<gix_ref::store::WriteReflog>,
6072
has_worktree: bool,

gix/src/config/mod.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ pub enum Error {
7676
ConfigUnsigned(#[from] unsigned_integer::Error),
7777
#[error(transparent)]
7878
ConfigTypedString(#[from] key::GenericErrorWithValue),
79+
#[error(transparent)]
80+
RefsNamespace(#[from] refs_namespace::Error),
7981
#[error("Cannot handle objects formatted as {:?}", .name)]
8082
UnsupportedObjectFormat { name: BString },
8183
#[error(transparent)]
@@ -167,10 +169,10 @@ pub mod command_context {
167169
#[derive(Debug, thiserror::Error)]
168170
#[allow(missing_docs)]
169171
pub enum Error {
170-
#[error(transparent)]
171-
PathSpec(#[from] gix_pathspec::defaults::from_environment::Error),
172172
#[error(transparent)]
173173
Boolean(#[from] config::boolean::Error),
174+
#[error(transparent)]
175+
ParseBool(#[from] gix_config::value::Error),
174176
}
175177
}
176178

@@ -430,6 +432,12 @@ pub mod refspec {
430432
pub type Error = super::key::Error<gix_refspec::parse::Error, 'r', 'p'>;
431433
}
432434

435+
///
436+
pub mod refs_namespace {
437+
/// The error produced when failing to parse a refspec from the configuration.
438+
pub type Error = super::key::Error<gix_validate::reference::name::Error, 'v', 'i'>;
439+
}
440+
433441
///
434442
pub mod ssl_version {
435443
/// The error produced when failing to parse a refspec from the configuration.
@@ -526,6 +534,8 @@ pub(crate) struct Cache {
526534
pub use_multi_pack_index: bool,
527535
/// The representation of `core.logallrefupdates`, or `None` if the variable wasn't set.
528536
pub reflog: Option<gix_ref::store::WriteReflog>,
537+
/// The representation of `gitoxide.core.refsNamespace`, or `None` if the variable wasn't set.
538+
pub refs_namespace: Option<gix_ref::Namespace>,
529539
/// The configured user agent for presentation to servers.
530540
pub(crate) user_agent: OnceCell<String>,
531541
/// identities for later use, lazy initialization.

gix/src/config/tree/sections/gitoxide.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,20 @@ mod subsections {
7474
#[derive(Copy, Clone, Default)]
7575
pub struct Core;
7676

77+
/// The `gitoxide.allow.protocolFromUser` key.
78+
pub type RefsNamespace = keys::Any<super::validate::RefsNamespace>;
79+
80+
impl RefsNamespace {
81+
/// Derive the negotiation algorithm identified by `name`, case-sensitively.
82+
pub fn try_into_refs_namespace(
83+
&'static self,
84+
name: std::borrow::Cow<'_, crate::bstr::BStr>,
85+
) -> Result<gix_ref::Namespace, crate::config::refs_namespace::Error> {
86+
gix_ref::namespace::expand(name.as_ref())
87+
.map_err(|err| crate::config::key::Error::from_value(self, name.into_owned()).with_source(err))
88+
}
89+
}
90+
7791
impl Core {
7892
/// The `gitoxide.core.defaultPackCacheMemoryLimit` key.
7993
pub const DEFAULT_PACK_CACHE_MEMORY_LIMIT: keys::UnsignedInteger =
@@ -100,6 +114,11 @@ mod subsections {
100114
/// It controls whether or not long running filter driver processes can use the 'delay' capability.
101115
pub const FILTER_PROCESS_DELAY: keys::Boolean =
102116
keys::Boolean::new_boolean("filterProcessDelay", &Gitoxide::CORE);
117+
118+
/// The `gitoxide.core.refsNamespace` key.
119+
pub const REFS_NAMESPACE: RefsNamespace =
120+
keys::Any::new_with_validate("refsNamespace", &Gitoxide::CORE, super::validate::RefsNamespace)
121+
.with_environment_override("GIT_NAMESPACE");
103122
}
104123

105124
impl Section for Core {
@@ -114,6 +133,7 @@ mod subsections {
114133
&Self::USE_STDEV,
115134
&Self::SHALLOW_FILE,
116135
&Self::FILTER_PROCESS_DELAY,
136+
&Self::REFS_NAMESPACE,
117137
]
118138
}
119139

@@ -496,4 +516,12 @@ pub mod validate {
496516
Ok(())
497517
}
498518
}
519+
520+
pub struct RefsNamespace;
521+
impl Validate for RefsNamespace {
522+
fn validate(&self, value: &BStr) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
523+
super::Core::REFS_NAMESPACE.try_into_refs_namespace(value.into())?;
524+
Ok(())
525+
}
526+
}
499527
}

gix/src/open/repository.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ impl ThreadSafeRepository {
273273
}
274274

275275
refs.write_reflog = config::cache::util::reflog_or_default(config.reflog, worktree_dir.is_some());
276+
refs.namespace = config.refs_namespace.clone();
276277
let replacements = replacement_objects_refs_prefix(&config.resolved, lenient_config, filter_config_section)?
277278
.and_then(|prefix| {
278279
let _span = gix_trace::detail!("find replacement objects");

gix/src/repository/config/mod.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@ impl crate::Repository {
8383
/// hooks or filters.
8484
#[cfg(feature = "attributes")]
8585
pub fn command_context(&self) -> Result<gix_command::Context, config::command_context::Error> {
86+
use crate::config::cache::util::ApplyLeniency;
87+
use crate::config::tree::gitoxide;
88+
use crate::config::tree::Key;
89+
90+
let boolean = |key: &dyn Key| {
91+
self.config
92+
.resolved
93+
.boolean("gitoxide", Some("pathspec".into()), key.name())
94+
.transpose()
95+
.with_leniency(self.config.lenient_config)
96+
};
97+
8698
Ok(gix_command::Context {
8799
git_dir: self.git_dir().to_owned().into(),
88100
worktree_dir: self.work_dir().map(ToOwned::to_owned),
@@ -92,10 +104,10 @@ impl crate::Repository {
92104
self.filter_config_section(),
93105
)?
94106
.map(|enabled| !enabled),
95-
ref_namespace: None,
96-
literal_pathspecs: None,
97-
glob_pathspecs: None,
98-
icase_pathspecs: None,
107+
ref_namespace: self.refs.namespace.as_ref().map(|ns| ns.as_bstr().to_owned()),
108+
literal_pathspecs: boolean(&gitoxide::Pathspec::LITERAL)?,
109+
glob_pathspecs: boolean(&gitoxide::Pathspec::GLOB)?.or(boolean(&gitoxide::Pathspec::NOGLOB)?),
110+
icase_pathspecs: boolean(&gitoxide::Pathspec::ICASE)?,
99111
})
100112
}
101113

gix/tests/gix-init.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ mod with_overrides {
4949
.set("GIT_NOGLOB_PATHSPECS", "pathspecs-noglob")
5050
.set("GIT_ICASE_PATHSPECS", "pathspecs-icase")
5151
.set("GIT_TERMINAL_PROMPT", "42")
52-
.set("GIT_SHALLOW_FILE", "shallow-file-env");
52+
.set("GIT_SHALLOW_FILE", "shallow-file-env")
53+
.set("GIT_NAMESPACE", "namespace-env");
5354
let mut opts = gix::open::Options::isolated()
5455
.cli_overrides([
5556
"http.userAgent=agent-from-cli",
@@ -62,6 +63,7 @@ mod with_overrides {
6263
"gitoxide.ssh.commandWithoutShellFallback=ssh-command-fallback-cli",
6364
"gitoxide.http.proxyAuthMethod=proxy-auth-method-cli",
6465
"gitoxide.core.shallowFile=shallow-file-cli",
66+
"gitoxide.core.refsNamespace=namespace-cli",
6567
])
6668
.config_overrides([
6769
"http.userAgent=agent-from-api",
@@ -74,6 +76,7 @@ mod with_overrides {
7476
"gitoxide.ssh.commandWithoutShellFallback=ssh-command-fallback-api",
7577
"gitoxide.http.proxyAuthMethod=proxy-auth-method-api",
7678
"gitoxide.core.shallowFile=shallow-file-api",
79+
"gitoxide.core.refsNamespace=namespace-api",
7780
]);
7881
opts.permissions.env.git_prefix = Permission::Allow;
7982
opts.permissions.env.http_transport = Permission::Allow;
@@ -96,6 +99,16 @@ mod with_overrides {
9699
cow_bstr("shallow-file-env")
97100
]
98101
);
102+
assert_eq!(
103+
config
104+
.strings_by_key("gitoxide.core.refsNamespace")
105+
.expect("at least one value"),
106+
[
107+
cow_bstr("namespace-cli"),
108+
cow_bstr("namespace-api"),
109+
cow_bstr("namespace-env")
110+
]
111+
);
99112
assert_eq!(
100113
config.strings_by_key("http.userAgent").expect("at least one value"),
101114
[

0 commit comments

Comments
 (0)