D9972: rhg: add limited support for the `config` sub-command
SimonSapin
phabricator at mercurial-scm.org
Mon Feb 8 22:45:38 UTC 2021
SimonSapin created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.
REVISION SUMMARY
Only with one argument and no flag. This is mostly for testing.
REPOSITORY
rHG Mercurial
BRANCH
default
REVISION DETAIL
https://phab.mercurial-scm.org/D9972
AFFECTED FILES
rust/hg-core/src/config/layer.rs
rust/hg-core/src/repo.rs
rust/hg-core/src/utils.rs
rust/rhg/src/commands/config.rs
rust/rhg/src/commands/root.rs
rust/rhg/src/main.rs
tests/test-rhg.t
CHANGE DETAILS
diff --git a/tests/test-rhg.t b/tests/test-rhg.t
--- a/tests/test-rhg.t
+++ b/tests/test-rhg.t
@@ -30,6 +30,18 @@
$ rhg root
$TESTTMP/repository
+Reading and setting configuration
+ $ echo "[ui]" >> $HGRCPATH
+ $ echo "username = user1" >> $HGRCPATH
+ $ rhg config ui.username
+ user1
+ $ echo "[ui]" >> .hg/hgrc
+ $ echo "username = user2" >> .hg/hgrc
+ $ rhg config ui.username
+ user2
+ $ rhg --config ui.username=user3 config ui.username
+ user3
+
Unwritable file descriptor
$ rhg root > /dev/full
abort: No space left on device (os error 28)
diff --git a/rust/rhg/src/main.rs b/rust/rhg/src/main.rs
--- a/rust/rhg/src/main.rs
+++ b/rust/rhg/src/main.rs
@@ -134,4 +134,5 @@
debugrequirements
files
root
+ config
}
diff --git a/rust/rhg/src/commands/root.rs b/rust/rhg/src/commands/config.rs
copy from rust/rhg/src/commands/root.rs
copy to rust/rhg/src/commands/config.rs
--- a/rust/rhg/src/commands/root.rs
+++ b/rust/rhg/src/commands/config.rs
@@ -1,30 +1,52 @@
use crate::error::CommandError;
use crate::ui::Ui;
+use clap::Arg;
use clap::ArgMatches;
use format_bytes::format_bytes;
use hg::config::Config;
+use hg::errors::HgError;
use hg::repo::Repo;
-use hg::utils::files::get_bytes_from_path;
+use hg::utils::SliceExt;
use std::path::Path;
pub const HELP_TEXT: &str = "
-Print the root directory of the current repository.
-
-Returns 0 on success.
+With one argument of the form section.name, print just the value of that config item.
";
pub fn args() -> clap::App<'static, 'static> {
- clap::SubCommand::with_name("root").about(HELP_TEXT)
+ clap::SubCommand::with_name("config")
+ .arg(
+ Arg::with_name("name")
+ .help("the section.name to print")
+ .value_name("NAME")
+ .required(true)
+ .takes_value(true),
+ )
+ .about(HELP_TEXT)
}
pub fn run(
ui: &Ui,
config: &Config,
repo_path: Option<&Path>,
- _args: &ArgMatches,
+ args: &ArgMatches,
) -> Result<(), CommandError> {
- let repo = Repo::find(config, repo_path)?;
- let bytes = get_bytes_from_path(repo.working_directory_path());
- ui.write_stdout(&format_bytes!(b"{}\n", bytes.as_slice()))?;
+ let opt_repo = Repo::find_optional(config, repo_path)?;
+ let config = if let Some(repo) = &opt_repo {
+ repo.config()
+ } else {
+ config
+ };
+
+ let (section, name) = args
+ .value_of("name")
+ .expect("missing required CLI argument")
+ .as_bytes()
+ .split_2(b'.')
+ .ok_or_else(|| HgError::abort(""))?;
+
+ let value = config.get(section, name).unwrap_or(b"");
+
+ ui.write_stdout(&format_bytes!(b"{}\n", value))?;
Ok(())
}
diff --git a/rust/hg-core/src/utils.rs b/rust/hg-core/src/utils.rs
--- a/rust/hg-core/src/utils.rs
+++ b/rust/hg-core/src/utils.rs
@@ -67,6 +67,7 @@
fn trim_start(&self) -> &Self;
fn trim(&self) -> &Self;
fn drop_prefix(&self, needle: &Self) -> Option<&Self>;
+ fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])>;
}
#[allow(clippy::trivially_copy_pass_by_ref)]
@@ -116,6 +117,13 @@
None
}
}
+
+ fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])> {
+ let mut iter = self.splitn(2, |&byte| byte == separator);
+ let a = iter.next()?;
+ let b = iter.next()?;
+ Some((a, b))
+ }
}
pub trait Escaped {
diff --git a/rust/hg-core/src/repo.rs b/rust/hg-core/src/repo.rs
--- a/rust/hg-core/src/repo.rs
+++ b/rust/hg-core/src/repo.rs
@@ -43,10 +43,14 @@
}
impl Repo {
- /// Search the current directory and its ancestores for a repository:
- /// a working directory that contains a `.hg` sub-directory.
+ /// Find a repository, either at the given path (which must contain a `.hg`
+ /// sub-directory) or by searching the current directory and its
+ /// ancestors.
///
- /// `explicit_path` is for `--repository` command-line arguments.
+ /// A method with two very different "modes" like this usually a code smell
+ /// to make two methods instead, but in this case an `Option` is what rhg
+ /// sub-commands get from Clap for the `-R` / `--repository` CLI argument.
+ /// Having two methods would just move that `if` to almost all callers.
pub fn find(
config: &Config,
explicit_path: Option<&Path>,
@@ -77,6 +81,28 @@
}
}
+ /// Like `Repo::find`, but not finding a repository is not an error if no
+ /// explicit path is given. `Ok(None)` is returned in that case.
+ ///
+ /// If an explicit path *is* given, not finding a repository there is still
+ /// an error.
+ ///
+ /// For sub-commands that donât need a repository, configuration should
+ /// still be affected by a repositoryâs `.hg/hgrc` file. This is the
+ /// constructor to use.
+ pub fn find_optional(
+ config: &Config,
+ explicit_path: Option<&Path>,
+ ) -> Result<Option<Self>, RepoError> {
+ match Self::find(config, explicit_path) {
+ Ok(repo) => Ok(Some(repo)),
+ Err(RepoError::NotFound { .. }) if explicit_path.is_none() => {
+ Ok(None)
+ }
+ Err(error) => Err(error),
+ }
+ }
+
/// To be called after checking that `.hg` is a sub-directory
fn new_at_path(
working_directory: PathBuf,
diff --git a/rust/hg-core/src/config/layer.rs b/rust/hg-core/src/config/layer.rs
--- a/rust/hg-core/src/config/layer.rs
+++ b/rust/hg-core/src/config/layer.rs
@@ -58,8 +58,8 @@
fn parse_one(arg: &[u8]) -> Option<(Vec<u8>, Vec<u8>, Vec<u8>)> {
use crate::utils::SliceExt;
- let (section_and_item, value) = split_2(arg, b'=')?;
- let (section, item) = split_2(section_and_item.trim(), b'.')?;
+ let (section_and_item, value) = arg.split_2(b'=')?;
+ let (section, item) = section_and_item.trim().split_2(b'.')?;
Some((
section.to_owned(),
item.to_owned(),
@@ -67,13 +67,6 @@
))
}
- fn split_2(bytes: &[u8], separator: u8) -> Option<(&[u8], &[u8])> {
- let mut iter = bytes.splitn(2, |&byte| byte == separator);
- let a = iter.next()?;
- let b = iter.next()?;
- Some((a, b))
- }
-
let mut layer = Self::new(ConfigOrigin::CommandLine);
for arg in cli_config_args {
let arg = arg.as_ref();
To: SimonSapin, #hg-reviewers
Cc: mercurial-patches, mercurial-devel
More information about the Mercurial-devel
mailing list