config: show unset config items with --debug

Summary: Previously there was no way to use the "config" command to see a config entry was %unset. Now, the --debug flag will give positive indication a config is <%unset> (and tell you where it was unset).

Reviewed By: zzl0

Differential Revision: D47012143

fbshipit-source-id: 611eba126fbdd13593aa64dff23ff7e53eca726b
This commit is contained in:
Muir Manders 2023-06-28 18:39:53 -07:00 committed by Facebook GitHub Bot
parent 6f760b9ec5
commit f3a51f0cb0
3 changed files with 51 additions and 18 deletions

View File

@ -225,7 +225,7 @@ pub struct ValueLocation {
}
impl ValueSource {
/// Return the actual value stored in this config value, or `None` if uset.
/// Return the actual value stored in this config value, or `None` if unset.
pub fn value(&self) -> &Option<Text> {
&self.value
}

View File

@ -89,8 +89,7 @@ pub fn run(ctx: ReqCtx<ConfigOpts>, repo: &mut OptionalRepo) -> Result<u8> {
ctx.maybe_start_pager(repo.config())?;
formatter.begin_list()?;
let verbose = ctx.global_opts().verbose;
let exit_code = show_configs(ctx.opts.args, config, formatter.as_mut(), verbose)?;
let exit_code = show_configs(ctx, config, formatter.as_mut())?;
formatter.end_list()?;
Ok(exit_code)
@ -100,7 +99,7 @@ struct ConfigItem<'a> {
source: String,
section: &'a str,
key: &'a str,
value: String,
value: Option<String>,
single_item: bool,
builtin: bool,
}
@ -114,7 +113,9 @@ impl<'a> Serialize for ConfigItem<'a> {
let name = format!("{}.{}", self.section, self.key);
item.serialize_field("name", name.as_str())?;
item.serialize_field("source", &self.source)?;
item.serialize_field("value", &self.value)?;
item.end()
}
}
@ -125,6 +126,12 @@ impl<'a> Formattable for ConfigItem<'a> {
options: &FormatOptions,
writer: &mut dyn formatter::StyleWrite,
) -> std::result::Result<(), anyhow::Error> {
let value: &str = match &self.value {
Some(value) => value.as_ref(),
None if options.debug => "<%unset>",
_ => return Ok(()),
};
let source_section = if options.debug {
format!("{}: ", self.source)
} else {
@ -140,7 +147,7 @@ impl<'a> Formattable for ConfigItem<'a> {
"{}{}{}\n",
source_section,
kv_section,
self.value.replace('\n', "\\n")
value.replace('\n', "\\n")
)?;
Ok(())
}
@ -151,6 +158,7 @@ fn get_config_item<'a>(
section: &'a str,
key: &'a str,
single_item: bool,
debug: bool,
) -> Option<ConfigItem<'a>> {
let sources_list = config.get_sources(section, key);
let config_value_source = match sources_list.last() {
@ -159,12 +167,13 @@ fn get_config_item<'a>(
}
Some(s) => s,
};
let value = match config_value_source.value() {
None => {
return None;
}
Some(v) => v.to_string(),
};
let value = config_value_source.value();
// Don't expose %unset unless --debug was specified.
if value.is_none() && !debug {
return None;
}
let builtin = config_value_source.source().starts_with("builtin:");
let source = config_value_source
@ -190,24 +199,30 @@ fn get_config_item<'a>(
source,
section,
key,
value,
value: value.as_ref().map(|v| v.to_string()),
single_item,
builtin,
})
}
fn show_configs(
requested_configs: Vec<String>,
ctx: ReqCtx<ConfigOpts>,
config: &ConfigSet,
formatter: &mut dyn ListFormatter,
verbose: bool,
) -> Result<u8> {
let requested_items: Vec<_> = requested_configs
let verbose = ctx.global_opts().verbose;
let debug = ctx.global_opts().debug;
let requested_items: Vec<_> = ctx
.opts
.args
.iter()
.filter(|a| a.contains('.'))
.cloned()
.collect();
let requested_sections: BTreeSet<_> = requested_configs
let requested_sections: BTreeSet<_> = ctx
.opts
.args
.into_iter()
.filter_map(|a| {
if !a.contains('.') {
@ -228,7 +243,7 @@ fn show_configs(
let item = &requested_items[0];
let parts: Vec<_> = item.splitn(2, '.').collect();
if let Some(item) = get_config_item(config, parts[0], parts[1], true) {
if let Some(item) = get_config_item(config, parts[0], parts[1], true, debug) {
formatter.format_item(&item)?;
return Ok(0);
}
@ -253,7 +268,7 @@ fn show_configs(
let mut keys = config.keys(section);
keys.sort();
for key in keys {
if let Some(item) = get_config_item(config, section, &key, false) {
if let Some(item) = get_config_item(config, section, &key, false, debug) {
if empty_selection && item.builtin && !verbose {
continue;
}

View File

@ -136,6 +136,24 @@ Test "%unset"
$ hg showconfig unsettest
unsettest.set-after-unset=should be set (.hg/hgrc)
$ hg showconfig unsettest.both
[1]
$ hg showconfig unsettest.both --debug
*: <%unset> (glob)
$ hg showconfig unsettest.both -Tjson
[
]
[1]
$ hg showconfig unsettest.both -Tjson --debug
[
{
"name": "unsettest.both",
"source": "*", (glob)
"value": null
}
]
Test exit code when no config matches
$ hg config Section.idontexist