##// END OF EJS Templates
rhg: add limited support for the `config` sub-command...
Simon Sapin -
r47233:fb0ad038 default draft
parent child Browse files
Show More
@@ -58,8 +58,8 impl ConfigLayer {
58 fn parse_one(arg: &[u8]) -> Option<(Vec<u8>, Vec<u8>, Vec<u8>)> {
58 fn parse_one(arg: &[u8]) -> Option<(Vec<u8>, Vec<u8>, Vec<u8>)> {
59 use crate::utils::SliceExt;
59 use crate::utils::SliceExt;
60
60
61 let (section_and_item, value) = split_2(arg, b'=')?;
61 let (section_and_item, value) = arg.split_2(b'=')?;
62 let (section, item) = split_2(section_and_item.trim(), b'.')?;
62 let (section, item) = section_and_item.trim().split_2(b'.')?;
63 Some((
63 Some((
64 section.to_owned(),
64 section.to_owned(),
65 item.to_owned(),
65 item.to_owned(),
@@ -67,13 +67,6 impl ConfigLayer {
67 ))
67 ))
68 }
68 }
69
69
70 fn split_2(bytes: &[u8], separator: u8) -> Option<(&[u8], &[u8])> {
71 let mut iter = bytes.splitn(2, |&byte| byte == separator);
72 let a = iter.next()?;
73 let b = iter.next()?;
74 Some((a, b))
75 }
76
77 let mut layer = Self::new(ConfigOrigin::CommandLine);
70 let mut layer = Self::new(ConfigOrigin::CommandLine);
78 for arg in cli_config_args {
71 for arg in cli_config_args {
79 let arg = arg.as_ref();
72 let arg = arg.as_ref();
@@ -43,10 +43,14 pub(crate) struct Vfs<'a> {
43 }
43 }
44
44
45 impl Repo {
45 impl Repo {
46 /// Search the current directory and its ancestores for a repository:
46 /// Find a repository, either at the given path (which must contain a `.hg`
47 /// a working directory that contains a `.hg` sub-directory.
47 /// sub-directory) or by searching the current directory and its
48 /// ancestors.
48 ///
49 ///
49 /// `explicit_path` is for `--repository` command-line arguments.
50 /// A method with two very different "modes" like this usually a code smell
51 /// to make two methods instead, but in this case an `Option` is what rhg
52 /// sub-commands get from Clap for the `-R` / `--repository` CLI argument.
53 /// Having two methods would just move that `if` to almost all callers.
50 pub fn find(
54 pub fn find(
51 config: &Config,
55 config: &Config,
52 explicit_path: Option<&Path>,
56 explicit_path: Option<&Path>,
@@ -77,6 +81,28 impl Repo {
77 }
81 }
78 }
82 }
79
83
84 /// Like `Repo::find`, but not finding a repository is not an error if no
85 /// explicit path is given. `Ok(None)` is returned in that case.
86 ///
87 /// If an explicit path *is* given, not finding a repository there is still
88 /// an error.
89 ///
90 /// For sub-commands that don’t need a repository, configuration should
91 /// still be affected by a repository’s `.hg/hgrc` file. This is the
92 /// constructor to use.
93 pub fn find_optional(
94 config: &Config,
95 explicit_path: Option<&Path>,
96 ) -> Result<Option<Self>, RepoError> {
97 match Self::find(config, explicit_path) {
98 Ok(repo) => Ok(Some(repo)),
99 Err(RepoError::NotFound { .. }) if explicit_path.is_none() => {
100 Ok(None)
101 }
102 Err(error) => Err(error),
103 }
104 }
105
80 /// To be called after checking that `.hg` is a sub-directory
106 /// To be called after checking that `.hg` is a sub-directory
81 fn new_at_path(
107 fn new_at_path(
82 working_directory: PathBuf,
108 working_directory: PathBuf,
@@ -67,6 +67,7 pub trait SliceExt {
67 fn trim_start(&self) -> &Self;
67 fn trim_start(&self) -> &Self;
68 fn trim(&self) -> &Self;
68 fn trim(&self) -> &Self;
69 fn drop_prefix(&self, needle: &Self) -> Option<&Self>;
69 fn drop_prefix(&self, needle: &Self) -> Option<&Self>;
70 fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])>;
70 }
71 }
71
72
72 #[allow(clippy::trivially_copy_pass_by_ref)]
73 #[allow(clippy::trivially_copy_pass_by_ref)]
@@ -116,6 +117,13 impl SliceExt for [u8] {
116 None
117 None
117 }
118 }
118 }
119 }
120
121 fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])> {
122 let mut iter = self.splitn(2, |&byte| byte == separator);
123 let a = iter.next()?;
124 let b = iter.next()?;
125 Some((a, b))
126 }
119 }
127 }
120
128
121 pub trait Escaped {
129 pub trait Escaped {
@@ -1,30 +1,52
1 use crate::error::CommandError;
1 use crate::error::CommandError;
2 use crate::ui::Ui;
2 use crate::ui::Ui;
3 use clap::Arg;
3 use clap::ArgMatches;
4 use clap::ArgMatches;
4 use format_bytes::format_bytes;
5 use format_bytes::format_bytes;
5 use hg::config::Config;
6 use hg::config::Config;
7 use hg::errors::HgError;
6 use hg::repo::Repo;
8 use hg::repo::Repo;
7 use hg::utils::files::get_bytes_from_path;
9 use hg::utils::SliceExt;
8 use std::path::Path;
10 use std::path::Path;
9
11
10 pub const HELP_TEXT: &str = "
12 pub const HELP_TEXT: &str = "
11 Print the root directory of the current repository.
13 With one argument of the form section.name, print just the value of that config item.
12
13 Returns 0 on success.
14 ";
14 ";
15
15
16 pub fn args() -> clap::App<'static, 'static> {
16 pub fn args() -> clap::App<'static, 'static> {
17 clap::SubCommand::with_name("root").about(HELP_TEXT)
17 clap::SubCommand::with_name("config")
18 .arg(
19 Arg::with_name("name")
20 .help("the section.name to print")
21 .value_name("NAME")
22 .required(true)
23 .takes_value(true),
24 )
25 .about(HELP_TEXT)
18 }
26 }
19
27
20 pub fn run(
28 pub fn run(
21 ui: &Ui,
29 ui: &Ui,
22 config: &Config,
30 config: &Config,
23 repo_path: Option<&Path>,
31 repo_path: Option<&Path>,
24 _args: &ArgMatches,
32 args: &ArgMatches,
25 ) -> Result<(), CommandError> {
33 ) -> Result<(), CommandError> {
26 let repo = Repo::find(config, repo_path)?;
34 let opt_repo = Repo::find_optional(config, repo_path)?;
27 let bytes = get_bytes_from_path(repo.working_directory_path());
35 let config = if let Some(repo) = &opt_repo {
28 ui.write_stdout(&format_bytes!(b"{}\n", bytes.as_slice()))?;
36 repo.config()
37 } else {
38 config
39 };
40
41 let (section, name) = args
42 .value_of("name")
43 .expect("missing required CLI argument")
44 .as_bytes()
45 .split_2(b'.')
46 .ok_or_else(|| HgError::abort(""))?;
47
48 let value = config.get(section, name).unwrap_or(b"");
49
50 ui.write_stdout(&format_bytes!(b"{}\n", value))?;
29 Ok(())
51 Ok(())
30 }
52 }
@@ -134,4 +134,5 subcommands! {
134 debugrequirements
134 debugrequirements
135 files
135 files
136 root
136 root
137 config
137 }
138 }
@@ -30,6 +30,18 Finding root
30 $ rhg root
30 $ rhg root
31 $TESTTMP/repository
31 $TESTTMP/repository
32
32
33 Reading and setting configuration
34 $ echo "[ui]" >> $HGRCPATH
35 $ echo "username = user1" >> $HGRCPATH
36 $ rhg config ui.username
37 user1
38 $ echo "[ui]" >> .hg/hgrc
39 $ echo "username = user2" >> .hg/hgrc
40 $ rhg config ui.username
41 user2
42 $ rhg --config ui.username=user3 config ui.username
43 user3
44
33 Unwritable file descriptor
45 Unwritable file descriptor
34 $ rhg root > /dev/full
46 $ rhg root > /dev/full
35 abort: No space left on device (os error 28)
47 abort: No space left on device (os error 28)
General Comments 0
You need to be logged in to leave comments. Login now