##// END OF EJS Templates
rhg: add error message for paths outside the repository when cwd != root...
Raphaël Gomès -
r50270:044e42ae stable
parent child Browse files
Show More
@@ -1,105 +1,114
1 1 use crate::error::CommandError;
2 2 use clap::Arg;
3 3 use format_bytes::format_bytes;
4 4 use hg::operations::cat;
5 5 use hg::utils::hg_path::HgPathBuf;
6 6 use micro_timer::timed;
7 7 use std::convert::TryFrom;
8 8
9 9 pub const HELP_TEXT: &str = "
10 10 Output the current or given revision of files
11 11 ";
12 12
13 13 pub fn args() -> clap::App<'static, 'static> {
14 14 clap::SubCommand::with_name("cat")
15 15 .arg(
16 16 Arg::with_name("rev")
17 17 .help("search the repository as it is in REV")
18 18 .short("-r")
19 19 .long("--rev")
20 20 .value_name("REV")
21 21 .takes_value(true),
22 22 )
23 23 .arg(
24 24 clap::Arg::with_name("files")
25 25 .required(true)
26 26 .multiple(true)
27 27 .empty_values(false)
28 28 .value_name("FILE")
29 29 .help("Files to output"),
30 30 )
31 31 .about(HELP_TEXT)
32 32 }
33 33
34 34 #[timed]
35 35 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
36 36 let cat_enabled_default = true;
37 37 let cat_enabled = invocation.config.get_option(b"rhg", b"cat")?;
38 38 if !cat_enabled.unwrap_or(cat_enabled_default) {
39 39 return Err(CommandError::unsupported(
40 40 "cat is disabled in rhg (enable it with 'rhg.cat = true' \
41 41 or enable fallback with 'rhg.on-unsupported = fallback')",
42 42 ));
43 43 }
44 44
45 45 let rev = invocation.subcommand_args.value_of("rev");
46 46 let file_args = match invocation.subcommand_args.values_of("files") {
47 47 Some(files) => files.collect(),
48 48 None => vec![],
49 49 };
50 50
51 51 let repo = invocation.repo?;
52 52 let cwd = hg::utils::current_dir()?;
53 53 let working_directory = repo.working_directory_path();
54 54 let working_directory = cwd.join(working_directory); // Make it absolute
55 55
56 56 let mut files = vec![];
57 57 for file in file_args.iter() {
58 58 if file.starts_with("set:") {
59 59 let message = "fileset";
60 60 return Err(CommandError::unsupported(message));
61 61 }
62 62
63 63 let normalized = cwd.join(&file);
64 64 // TODO: actually normalize `..` path segments etc?
65 65 let dotted = normalized.components().any(|c| c.as_os_str() == "..");
66 66 if file == &"." || dotted {
67 67 let message = "`..` or `.` path segment";
68 68 return Err(CommandError::unsupported(message));
69 69 }
70 let relative_path = working_directory
71 .strip_prefix(&cwd)
72 .unwrap_or(&working_directory);
70 73 let stripped = normalized
71 74 .strip_prefix(&working_directory)
72 // TODO: error message for path arguments outside of the repo
73 .map_err(|_| CommandError::abort(""))?;
75 .map_err(|_| {
76 CommandError::abort(format!(
77 "abort: {} not under root '{}'\n(consider using '--cwd {}')",
78 file,
79 working_directory.display(),
80 relative_path.display(),
81 ))
82 })?;
74 83 let hg_file = HgPathBuf::try_from(stripped.to_path_buf())
75 84 .map_err(|e| CommandError::abort(e.to_string()))?;
76 85 files.push(hg_file);
77 86 }
78 87 let files = files.iter().map(|file| file.as_ref()).collect();
79 88 // TODO probably move this to a util function like `repo.default_rev` or
80 89 // something when it's used somewhere else
81 90 let rev = match rev {
82 91 Some(r) => r.to_string(),
83 92 None => format!("{:x}", repo.dirstate_parents()?.p1),
84 93 };
85 94
86 95 let output = cat(&repo, &rev, files).map_err(|e| (e, rev.as_str()))?;
87 96 for (_file, contents) in output.results {
88 97 invocation.ui.write_stdout(&contents)?;
89 98 }
90 99 if !output.missing.is_empty() {
91 100 let short = format!("{:x}", output.node.short()).into_bytes();
92 101 for path in &output.missing {
93 102 invocation.ui.write_stderr(&format_bytes!(
94 103 b"{}: no such file in rev {}\n",
95 104 path.as_bytes(),
96 105 short
97 106 ))?;
98 107 }
99 108 }
100 109 if output.found_any {
101 110 Ok(())
102 111 } else {
103 112 Err(CommandError::Unsuccessful)
104 113 }
105 114 }
General Comments 0
You need to be logged in to leave comments. Login now