annotate rust/rhg/src/commands/cat.rs @ 48471:b005d07ded7d

rhg: Skip reading the contents of ambiguous files in some cases If the size of the file in the working directory does not match the length of the filelog data, we know its contents will be different and don?t need to read it. rhg still decodes the filelog revision, which is not needed in some cases. Differential Revision: https://phab.mercurial-scm.org/D11910
author Simon Sapin <simon.sapin@octobus.net>
date Tue, 14 Dec 2021 20:36:36 +0100
parents 698b70b9e8ea
children 044e42ae45d9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
46434
3e2d539d0d1a rust: remove `FooError` structs with only `kind: FooErrorKind` enum field
Simon Sapin <simon.sapin@octobus.net>
parents: 46167
diff changeset
1 use crate::error::CommandError;
46501
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
2 use clap::Arg;
46744
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46740
diff changeset
3 use format_bytes::format_bytes;
46436
252d1bdba33d rhg: replace `map_*_error` functions with `From` impls
Simon Sapin <simon.sapin@octobus.net>
parents: 46434
diff changeset
4 use hg::operations::cat;
45542
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
5 use hg::utils::hg_path::HgPathBuf;
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
6 use micro_timer::timed;
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
7 use std::convert::TryFrom;
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
8
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
9 pub const HELP_TEXT: &str = "
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
10 Output the current or given revision of files
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
11 ";
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
12
46501
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
13 pub fn args() -> clap::App<'static, 'static> {
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
14 clap::SubCommand::with_name("cat")
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
15 .arg(
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
16 Arg::with_name("rev")
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
17 .help("search the repository as it is in REV")
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
18 .short("-r")
48172
08c8cd2527bc rhg: in rhg cat cli, fix the long name of the --rev flag
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48074
diff changeset
19 .long("--rev")
46501
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
20 .value_name("REV")
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
21 .takes_value(true),
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
22 )
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
23 .arg(
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
24 clap::Arg::with_name("files")
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
25 .required(true)
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
26 .multiple(true)
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
27 .empty_values(false)
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
28 .value_name("FILE")
48172
08c8cd2527bc rhg: in rhg cat cli, fix the long name of the --rev flag
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48074
diff changeset
29 .help("Files to output"),
46501
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
30 )
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
31 .about(HELP_TEXT)
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
32 }
1ecaf09d9964 rhg: Move subcommand CLI arguments definitions to respective modules
Simon Sapin <simon.sapin@octobus.net>
parents: 46500
diff changeset
33
46500
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
34 #[timed]
46592
80840b651721 rhg: Group values passed to every sub-command into a struct
Simon Sapin <simon.sapin@octobus.net>
parents: 46503
diff changeset
35 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
48308
698b70b9e8ea rhg: make it possible to opt out of `rhg cat`
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48237
diff changeset
36 let cat_enabled_default = true;
698b70b9e8ea rhg: make it possible to opt out of `rhg cat`
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48237
diff changeset
37 let cat_enabled = invocation.config.get_option(b"rhg", b"cat")?;
698b70b9e8ea rhg: make it possible to opt out of `rhg cat`
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48237
diff changeset
38 if !cat_enabled.unwrap_or(cat_enabled_default) {
698b70b9e8ea rhg: make it possible to opt out of `rhg cat`
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48237
diff changeset
39 return Err(CommandError::unsupported(
698b70b9e8ea rhg: make it possible to opt out of `rhg cat`
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48237
diff changeset
40 "cat is disabled in rhg (enable it with 'rhg.cat = true' \
698b70b9e8ea rhg: make it possible to opt out of `rhg cat`
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48237
diff changeset
41 or enable fallback with 'rhg.on-unsupported = fallback')",
698b70b9e8ea rhg: make it possible to opt out of `rhg cat`
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48237
diff changeset
42 ));
698b70b9e8ea rhg: make it possible to opt out of `rhg cat`
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48237
diff changeset
43 }
698b70b9e8ea rhg: make it possible to opt out of `rhg cat`
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48237
diff changeset
44
46592
80840b651721 rhg: Group values passed to every sub-command into a struct
Simon Sapin <simon.sapin@octobus.net>
parents: 46503
diff changeset
45 let rev = invocation.subcommand_args.value_of("rev");
80840b651721 rhg: Group values passed to every sub-command into a struct
Simon Sapin <simon.sapin@octobus.net>
parents: 46503
diff changeset
46 let file_args = match invocation.subcommand_args.values_of("files") {
46500
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
47 Some(files) => files.collect(),
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
48 None => vec![],
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
49 };
45542
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
50
46593
5ce2aa7c2ad5 rhg: Move `Repo` object creation into `main()`
Simon Sapin <simon.sapin@octobus.net>
parents: 46592
diff changeset
51 let repo = invocation.repo?;
46500
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
52 let cwd = hg::utils::current_dir()?;
46740
97ac588b6d9e rhg: Don?t make repository path absolute too early
Simon Sapin <simon.sapin@octobus.net>
parents: 46666
diff changeset
53 let working_directory = repo.working_directory_path();
97ac588b6d9e rhg: Don?t make repository path absolute too early
Simon Sapin <simon.sapin@octobus.net>
parents: 46666
diff changeset
54 let working_directory = cwd.join(working_directory); // Make it absolute
46500
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
55
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
56 let mut files = vec![];
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
57 for file in file_args.iter() {
48074
4a6fa6b6f079 rhg-cat: fallback in presence of a fileset
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48073
diff changeset
58 if file.starts_with("set:") {
4a6fa6b6f079 rhg-cat: fallback in presence of a fileset
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48073
diff changeset
59 let message = "fileset";
4a6fa6b6f079 rhg-cat: fallback in presence of a fileset
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48073
diff changeset
60 return Err(CommandError::unsupported(message));
4a6fa6b6f079 rhg-cat: fallback in presence of a fileset
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48073
diff changeset
61 }
4a6fa6b6f079 rhg-cat: fallback in presence of a fileset
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48073
diff changeset
62
48073
1e00834491a5 rhg-cat: fallback when detecting `.` or `..` path segments
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48072
diff changeset
63 let normalized = cwd.join(&file);
46500
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
64 // TODO: actually normalize `..` path segments etc?
48073
1e00834491a5 rhg-cat: fallback when detecting `.` or `..` path segments
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48072
diff changeset
65 let dotted = normalized.components().any(|c| c.as_os_str() == "..");
1e00834491a5 rhg-cat: fallback when detecting `.` or `..` path segments
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48072
diff changeset
66 if file == &"." || dotted {
1e00834491a5 rhg-cat: fallback when detecting `.` or `..` path segments
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48072
diff changeset
67 let message = "`..` or `.` path segment";
1e00834491a5 rhg-cat: fallback when detecting `.` or `..` path segments
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48072
diff changeset
68 return Err(CommandError::unsupported(message));
1e00834491a5 rhg-cat: fallback when detecting `.` or `..` path segments
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48072
diff changeset
69 }
46500
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
70 let stripped = normalized
46740
97ac588b6d9e rhg: Don?t make repository path absolute too early
Simon Sapin <simon.sapin@octobus.net>
parents: 46666
diff changeset
71 .strip_prefix(&working_directory)
46500
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
72 // TODO: error message for path arguments outside of the repo
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
73 .map_err(|_| CommandError::abort(""))?;
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
74 let hg_file = HgPathBuf::try_from(stripped.to_path_buf())
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
75 .map_err(|e| CommandError::abort(e.to_string()))?;
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
76 files.push(hg_file);
45542
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
77 }
48237
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48224
diff changeset
78 let files = files.iter().map(|file| file.as_ref()).collect();
48072
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
79 // TODO probably move this to a util function like `repo.default_rev` or
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
80 // something when it's used somewhere else
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
81 let rev = match rev {
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
82 Some(r) => r.to_string(),
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
83 None => format!("{:x}", repo.dirstate_parents()?.p1),
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
84 };
45542
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
85
48224
6b5773f89183 rhg: faster hg cat when many files are requested
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48172
diff changeset
86 let output = cat(&repo, &rev, files).map_err(|e| (e, rev.as_str()))?;
48237
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48224
diff changeset
87 for (_file, contents) in output.results {
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48224
diff changeset
88 invocation.ui.write_stdout(&contents)?;
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48224
diff changeset
89 }
48072
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
90 if !output.missing.is_empty() {
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
91 let short = format!("{:x}", output.node.short()).into_bytes();
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
92 for path in &output.missing {
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
93 invocation.ui.write_stderr(&format_bytes!(
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
94 b"{}: no such file in rev {}\n",
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
95 path.as_bytes(),
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
96 short
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
97 ))?;
46500
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
98 }
48072
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
99 }
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
100 if output.found_any {
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
101 Ok(())
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
102 } else {
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
103 Err(CommandError::Unsuccessful)
45542
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
104 }
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
105 }