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