annotate rust/rhg/src/commands/cat.rs @ 50215:ae61851e6fe2 stable

dirstate: add a way to test races happening during status We add the `devel.sync.status.pre-dirstate-write-file` config option to easily test what happens when other operations happen during the window where `hg status` is done working but has not updated the cache on disk yet. We introduce the framework for testing such races too, actual tests will be added in the next changesets. For now the test is only checking dirstate-v1. We will extend the test coverage later too. Check test documentation for details. Code change from Rapha?l Gom?s <rgomes@octobus.net> Test change from Pierre-Yves David <pierre-yves.david@octobus.net>
author Rapha?l Gom?s <rgomes@octobus.net>, Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 28 Feb 2023 15:25:47 +0100
parents 044e42ae45d9
children c7fb9b74e753
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 }
49375
044e42ae45d9 rhg: add error message for paths outside the repository when cwd != root
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48308
diff changeset
70 let relative_path = working_directory
044e42ae45d9 rhg: add error message for paths outside the repository when cwd != root
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48308
diff changeset
71 .strip_prefix(&cwd)
044e42ae45d9 rhg: add error message for paths outside the repository when cwd != root
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48308
diff changeset
72 .unwrap_or(&working_directory);
46500
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
73 let stripped = normalized
46740
97ac588b6d9e rhg: Don?t make repository path absolute too early
Simon Sapin <simon.sapin@octobus.net>
parents: 46666
diff changeset
74 .strip_prefix(&working_directory)
49375
044e42ae45d9 rhg: add error message for paths outside the repository when cwd != root
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48308
diff changeset
75 .map_err(|_| {
044e42ae45d9 rhg: add error message for paths outside the repository when cwd != root
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48308
diff changeset
76 CommandError::abort(format!(
044e42ae45d9 rhg: add error message for paths outside the repository when cwd != root
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48308
diff changeset
77 "abort: {} not under root '{}'\n(consider using '--cwd {}')",
044e42ae45d9 rhg: add error message for paths outside the repository when cwd != root
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48308
diff changeset
78 file,
044e42ae45d9 rhg: add error message for paths outside the repository when cwd != root
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48308
diff changeset
79 working_directory.display(),
044e42ae45d9 rhg: add error message for paths outside the repository when cwd != root
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48308
diff changeset
80 relative_path.display(),
044e42ae45d9 rhg: add error message for paths outside the repository when cwd != root
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48308
diff changeset
81 ))
044e42ae45d9 rhg: add error message for paths outside the repository when cwd != root
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48308
diff changeset
82 })?;
46500
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
83 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
84 .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
85 files.push(hg_file);
45542
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
86 }
48237
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48224
diff changeset
87 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
88 // 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
89 // 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
90 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
91 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
92 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
93 };
45542
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
94
48224
6b5773f89183 rhg: faster hg cat when many files are requested
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48172
diff changeset
95 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
96 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
97 invocation.ui.write_stdout(&contents)?;
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48224
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 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
100 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
101 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
102 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
103 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
104 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
105 short
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
106 ))?;
46500
184e46550dc8 rhg: replace command structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
107 }
48072
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
108 }
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
109 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
110 Ok(())
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
111 } else {
d919b0ca8449 rhg: add support for calling `rhg cat` without a revision
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46744
diff changeset
112 Err(CommandError::Unsuccessful)
45542
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
113 }
33ded2d3f4fc rhg: add a limited `rhg cat -r` subcommand
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
114 }