##// END OF EJS Templates
rhg: Add support for -R and --repository command-line arguments...
Simon Sapin -
r47231:1a00a578 default draft
parent child Browse files
Show More
@@ -1,6 +1,7 b''
1 1 use crate::config::{Config, ConfigError, ConfigParseError};
2 2 use crate::errors::{HgError, IoResultExt};
3 3 use crate::requirements;
4 use crate::utils::current_dir;
4 5 use crate::utils::files::get_path_from_bytes;
5 6 use memmap::{Mmap, MmapOptions};
6 7 use std::collections::HashSet;
@@ -18,7 +19,7 b' pub struct Repo {'
18 19 #[derive(Debug, derive_more::From)]
19 20 pub enum RepoError {
20 21 NotFound {
21 current_directory: PathBuf,
22 at: PathBuf,
22 23 },
23 24 #[from]
24 25 ConfigParseError(ConfigParseError),
@@ -44,15 +45,36 b" pub(crate) struct Vfs<'a> {"
44 45 impl Repo {
45 46 /// Search the current directory and its ancestores for a repository:
46 47 /// a working directory that contains a `.hg` sub-directory.
47 pub fn find(config: &Config) -> Result<Self, RepoError> {
48 let current_directory = crate::utils::current_dir()?;
49 // ancestors() is inclusive: it first yields `current_directory` as-is.
50 for ancestor in current_directory.ancestors() {
51 if ancestor.join(".hg").is_dir() {
52 return Ok(Self::new_at_path(ancestor.to_owned(), config)?);
48 ///
49 /// `explicit_path` is for `--repository` command-line arguments.
50 pub fn find(
51 config: &Config,
52 explicit_path: Option<&Path>,
53 ) -> Result<Self, RepoError> {
54 if let Some(root) = explicit_path {
55 // Having an absolute path isn’t necessary here but can help code
56 // elsewhere
57 let root = current_dir()?.join(root);
58 if root.join(".hg").is_dir() {
59 Self::new_at_path(root, config)
60 } else {
61 Err(RepoError::NotFound {
62 at: root.to_owned(),
63 })
53 64 }
65 } else {
66 let current_directory = crate::utils::current_dir()?;
67 // ancestors() is inclusive: it first yields `current_directory`
68 // as-is.
69 for ancestor in current_directory.ancestors() {
70 if ancestor.join(".hg").is_dir() {
71 return Self::new_at_path(ancestor.to_owned(), config);
72 }
73 }
74 Err(RepoError::NotFound {
75 at: current_directory,
76 })
54 77 }
55 Err(RepoError::NotFound { current_directory })
56 78 }
57 79
58 80 /// To be called after checking that `.hg` is a sub-directory
@@ -8,6 +8,7 b' use hg::repo::Repo;'
8 8 use hg::utils::hg_path::HgPathBuf;
9 9 use micro_timer::timed;
10 10 use std::convert::TryFrom;
11 use std::path::Path;
11 12
12 13 pub const HELP_TEXT: &str = "
13 14 Output the current or given revision of files
@@ -38,6 +39,7 b" pub fn args() -> clap::App<'static, 'sta"
38 39 pub fn run(
39 40 ui: &Ui,
40 41 config: &Config,
42 repo_path: Option<&Path>,
41 43 args: &ArgMatches,
42 44 ) -> Result<(), CommandError> {
43 45 let rev = args.value_of("rev");
@@ -46,7 +48,7 b' pub fn run('
46 48 None => vec![],
47 49 };
48 50
49 let repo = Repo::find(config)?;
51 let repo = Repo::find(config, repo_path)?;
50 52 let cwd = hg::utils::current_dir()?;
51 53
52 54 let mut files = vec![];
@@ -7,6 +7,7 b' use hg::config::Config;'
7 7 use hg::operations::{debug_data, DebugDataKind};
8 8 use hg::repo::Repo;
9 9 use micro_timer::timed;
10 use std::path::Path;
10 11
11 12 pub const HELP_TEXT: &str = "
12 13 Dump the contents of a data file revision
@@ -44,6 +45,7 b" pub fn args() -> clap::App<'static, 'sta"
44 45 pub fn run(
45 46 ui: &Ui,
46 47 config: &Config,
48 repo_path: Option<&Path>,
47 49 args: &ArgMatches,
48 50 ) -> Result<(), CommandError> {
49 51 let rev = args
@@ -61,7 +63,7 b' pub fn run('
61 63 }
62 64 };
63 65
64 let repo = Repo::find(config)?;
66 let repo = Repo::find(config, repo_path)?;
65 67 let data = debug_data(&repo, rev, kind).map_err(|e| (e, rev))?;
66 68
67 69 let mut stdout = ui.stdout_buffer();
@@ -3,6 +3,7 b' use crate::ui::Ui;'
3 3 use clap::ArgMatches;
4 4 use hg::config::Config;
5 5 use hg::repo::Repo;
6 use std::path::Path;
6 7
7 8 pub const HELP_TEXT: &str = "
8 9 Print the current repo requirements.
@@ -15,9 +16,10 b" pub fn args() -> clap::App<'static, 'sta"
15 16 pub fn run(
16 17 ui: &Ui,
17 18 config: &Config,
19 repo_path: Option<&Path>,
18 20 _args: &ArgMatches,
19 21 ) -> Result<(), CommandError> {
20 let repo = Repo::find(config)?;
22 let repo = Repo::find(config, repo_path)?;
21 23 let mut output = String::new();
22 24 let mut requirements: Vec<_> = repo.requirements().iter().collect();
23 25 requirements.sort();
@@ -8,6 +8,7 b' use hg::operations::Dirstate;'
8 8 use hg::repo::Repo;
9 9 use hg::utils::files::{get_bytes_from_path, relativize_path};
10 10 use hg::utils::hg_path::{HgPath, HgPathBuf};
11 use std::path::Path;
11 12
12 13 pub const HELP_TEXT: &str = "
13 14 List tracked files.
@@ -31,11 +32,12 b" pub fn args() -> clap::App<'static, 'sta"
31 32 pub fn run(
32 33 ui: &Ui,
33 34 config: &Config,
35 repo_path: Option<&Path>,
34 36 args: &ArgMatches,
35 37 ) -> Result<(), CommandError> {
36 38 let rev = args.value_of("rev");
37 39
38 let repo = Repo::find(config)?;
40 let repo = Repo::find(config, repo_path)?;
39 41 if let Some(rev) = rev {
40 42 let files =
41 43 list_rev_tracked_files(&repo, rev).map_err(|e| (e, rev))?;
@@ -52,16 +54,15 b" fn display_files<'a>("
52 54 repo: &Repo,
53 55 files: impl IntoIterator<Item = &'a HgPath>,
54 56 ) -> Result<(), CommandError> {
55 let cwd = hg::utils::current_dir()?;
56 let rooted_cwd = cwd
57 .strip_prefix(repo.working_directory_path())
58 .expect("cwd was already checked within the repository");
59 let rooted_cwd = HgPathBuf::from(get_bytes_from_path(rooted_cwd));
57 let cwd = HgPathBuf::from(get_bytes_from_path(hg::utils::current_dir()?));
58 let working_directory =
59 HgPathBuf::from(get_bytes_from_path(repo.working_directory_path()));
60 60
61 61 let mut stdout = ui.stdout_buffer();
62 62
63 63 for file in files {
64 stdout.write_all(relativize_path(file, &rooted_cwd).as_ref())?;
64 let file = working_directory.join(file);
65 stdout.write_all(relativize_path(&file, &cwd).as_ref())?;
65 66 stdout.write_all(b"\n")?;
66 67 }
67 68 stdout.flush()?;
@@ -5,6 +5,7 b' use format_bytes::format_bytes;'
5 5 use hg::config::Config;
6 6 use hg::repo::Repo;
7 7 use hg::utils::files::get_bytes_from_path;
8 use std::path::Path;
8 9
9 10 pub const HELP_TEXT: &str = "
10 11 Print the root directory of the current repository.
@@ -19,9 +20,10 b" pub fn args() -> clap::App<'static, 'sta"
19 20 pub fn run(
20 21 ui: &Ui,
21 22 config: &Config,
23 repo_path: Option<&Path>,
22 24 _args: &ArgMatches,
23 25 ) -> Result<(), CommandError> {
24 let repo = Repo::find(config)?;
26 let repo = Repo::find(config, repo_path)?;
25 27 let bytes = get_bytes_from_path(repo.working_directory_path());
26 28 ui.write_stdout(&format_bytes!(b"{}\n", bytes.as_slice()))?;
27 29 Ok(())
@@ -54,10 +54,10 b' impl From<UiError> for CommandError {'
54 54 impl From<RepoError> for CommandError {
55 55 fn from(error: RepoError) -> Self {
56 56 match error {
57 RepoError::NotFound { current_directory } => CommandError::Abort {
57 RepoError::NotFound { at } => CommandError::Abort {
58 58 message: format_bytes!(
59 59 b"no repository found in '{}' (.hg not found)!",
60 get_bytes_from_path(current_directory)
60 get_bytes_from_path(at)
61 61 ),
62 62 },
63 63 RepoError::ConfigParseError(error) => error.into(),
@@ -1,14 +1,27 b''
1 1 extern crate log;
2 2 use clap::App;
3 3 use clap::AppSettings;
4 use clap::Arg;
4 5 use clap::ArgMatches;
5 6 use format_bytes::format_bytes;
7 use std::path::Path;
6 8
7 9 mod error;
8 10 mod exitcode;
9 11 mod ui;
10 12 use error::CommandError;
11 13
14 fn add_global_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
15 app.arg(
16 Arg::with_name("repository")
17 .help("repository root directory")
18 .short("-R")
19 .long("--repository")
20 .value_name("REPO")
21 .takes_value(true),
22 )
23 }
24
12 25 fn main() {
13 26 env_logger::init();
14 27 let app = App::new("rhg")
@@ -16,6 +29,7 b' fn main() {'
16 29 .setting(AppSettings::SubcommandRequired)
17 30 .setting(AppSettings::VersionlessSubcommands)
18 31 .version("0.0.1");
32 let app = add_global_args(app);
19 33 let app = add_subcommand_args(app);
20 34
21 35 let ui = ui::Ui::new();
@@ -24,15 +38,22 b' fn main() {'
24 38 let _ = ui.writeln_stderr_str(&err.message);
25 39 std::process::exit(exitcode::UNIMPLEMENTED)
26 40 });
41
27 42 let (subcommand_name, subcommand_matches) = matches.subcommand();
28 43 let run = subcommand_run_fn(subcommand_name)
29 44 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired");
30 45 let args = subcommand_matches
31 46 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired");
32 47
48 // Global arguments can be in either based on e.g. `hg -R ./foo log` v.s.
49 // `hg log -R ./foo`
50 let global_arg =
51 |name| args.value_of_os(name).or_else(|| matches.value_of_os(name));
52
53 let repo_path = global_arg("repository").map(Path::new);
33 54 let result = (|| -> Result<(), CommandError> {
34 55 let config = hg::config::Config::load()?;
35 run(&ui, &config, args)
56 run(&ui, &config, repo_path, args)
36 57 })();
37 58
38 59 let exit_code = match result {
@@ -66,13 +87,14 b' macro_rules! subcommands {'
66 87 fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
67 88 app
68 89 $(
69 .subcommand(commands::$command::args())
90 .subcommand(add_global_args(commands::$command::args()))
70 91 )+
71 92 }
72 93
73 94 fn subcommand_run_fn(name: &str) -> Option<fn(
74 95 &ui::Ui,
75 96 &hg::config::Config,
97 Option<&Path>,
76 98 &ArgMatches,
77 99 ) -> Result<(), CommandError>> {
78 100 match name {
@@ -15,7 +15,7 b' Unimplemented command'
15 15 error: Found argument 'unimplemented-command' which wasn't expected, or isn't valid in this context
16 16
17 17 USAGE:
18 rhg <SUBCOMMAND>
18 rhg [OPTIONS] <SUBCOMMAND>
19 19
20 20 For more information try --help
21 21 [252]
@@ -204,35 +204,30 b' Crate a shared repository'
204 204
205 205 $ cd $TESTTMP
206 206 $ hg init repo1
207 $ cd repo1
208 $ echo a > a
209 $ hg commit -A -m'init'
207 $ echo a > repo1/a
208 $ hg -R repo1 commit -A -m'init'
210 209 adding a
211 210
212 $ cd ..
213 211 $ hg share repo1 repo2
214 212 updating working directory
215 213 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
216 214
217 215 And check that basic rhg commands work with sharing
218 216
219 $ cd repo2
220 $ rhg files
221 a
222 $ rhg cat -r 0 a
217 $ rhg files -R repo2
218 repo2/a
219 $ rhg -R repo2 cat -r 0 repo2/a
223 220 a
224 221
225 222 Same with relative sharing
226 223
227 $ cd ..
228 224 $ hg share repo2 repo3 --relative
229 225 updating working directory
230 226 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 227
232 $ cd repo3
233 $ rhg files
234 a
235 $ rhg cat -r 0 a
228 $ rhg files -R repo3
229 repo3/a
230 $ rhg -R repo3 cat -r 0 repo3/a
236 231 a
237 232
238 233 Same with share-safe
General Comments 0
You need to be logged in to leave comments. Login now