Show More
@@ -58,8 +58,8 b' 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( |
|
61 | let (section_and_item, value) = arg.split_2(b'=')?; | |
62 |
let (section, item) = |
|
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 b' 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 b" 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 b' 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 b' 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 b' 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 b'' | |||||
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(" |
|
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 |
|
|
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 b' subcommands! {' | |||||
134 | debugrequirements |
|
134 | debugrequirements | |
135 | files |
|
135 | files | |
136 | root |
|
136 | root | |
|
137 | config | |||
137 | } |
|
138 | } |
@@ -30,6 +30,18 b' 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