##// END OF EJS Templates
rhg: add resolve_file_args to path_utils.rs...
Mitchell Kember -
r53438:f33f37ac tip default
parent child Browse files
Show More
@@ -1,10 +1,9
1 use crate::error::CommandError;
1 use crate::error::CommandError;
2 use crate::utils::path_utils::resolve_file_args;
2 use clap::Arg;
3 use clap::Arg;
3 use format_bytes::format_bytes;
4 use format_bytes::format_bytes;
4 use hg::operations::cat;
5 use hg::operations::cat;
5 use hg::utils::hg_path::HgPathBuf;
6 use std::ffi::OsString;
6 use std::ffi::OsString;
7 use std::os::unix::prelude::OsStrExt;
8
7
9 pub const HELP_TEXT: &str = "
8 pub const HELP_TEXT: &str = "
10 Output the current or given revision of files
9 Output the current or given revision of files
@@ -40,52 +39,15 pub fn run(invocation: &crate::CliInvoca
40 ));
39 ));
41 }
40 }
42
41
43 let rev = invocation.subcommand_args.get_one::<String>("rev");
44 let file_args =
45 match invocation.subcommand_args.get_many::<OsString>("files") {
46 Some(files) => files
47 .filter(|s| !s.is_empty())
48 .map(|s| s.as_os_str())
49 .collect(),
50 None => vec![],
51 };
52
53 let repo = invocation.repo?;
42 let repo = invocation.repo?;
54 let cwd = hg::utils::current_dir()?;
55 let working_directory = repo.working_directory_path();
56 let working_directory = cwd.join(working_directory); // Make it absolute
57
58 let mut files = vec![];
59 for file in file_args {
60 if file.as_bytes().starts_with(b"set:") {
61 let message = "fileset";
62 return Err(CommandError::unsupported(message));
63 }
64
43
65 let normalized = cwd.join(file);
44 let rev = invocation.subcommand_args.get_one::<String>("rev");
66 // TODO: actually normalize `..` path segments etc?
45 let files = match invocation.subcommand_args.get_many::<OsString>("files")
67 let dotted = normalized.components().any(|c| c.as_os_str() == "..");
46 {
68 if file.as_bytes() == b"." || dotted {
47 None => vec![],
69 let message = "`..` or `.` path segment";
48 Some(files) => resolve_file_args(repo, files)?,
70 return Err(CommandError::unsupported(message));
49 };
71 }
50
72 let relative_path = working_directory
73 .strip_prefix(&cwd)
74 .unwrap_or(&working_directory);
75 let stripped = normalized
76 .strip_prefix(&working_directory)
77 .map_err(|_| {
78 CommandError::abort(format!(
79 "abort: {} not under root '{}'\n(consider using '--cwd {}')",
80 String::from_utf8_lossy(file.as_bytes()),
81 working_directory.display(),
82 relative_path.display(),
83 ))
84 })?;
85 let hg_file = HgPathBuf::try_from(stripped.to_path_buf())
86 .map_err(|e| CommandError::abort(e.to_string()))?;
87 files.push(hg_file);
88 }
89 let files = files.iter().map(|file| file.as_ref()).collect();
51 let files = files.iter().map(|file| file.as_ref()).collect();
90 // TODO probably move this to a util function like `repo.default_rev` or
52 // TODO probably move this to a util function like `repo.default_rev` or
91 // something when it's used somewhere else
53 // something when it's used somewhere else
@@ -10,6 +10,9 use hg::utils::files::{get_bytes_from_pa
10 use hg::utils::hg_path::HgPath;
10 use hg::utils::hg_path::HgPath;
11 use hg::utils::hg_path::HgPathBuf;
11 use hg::utils::hg_path::HgPathBuf;
12 use std::borrow::Cow;
12 use std::borrow::Cow;
13 use std::ffi::OsString;
14
15 use crate::error::CommandError;
13
16
14 pub struct RelativizePaths {
17 pub struct RelativizePaths {
15 repo_root: HgPathBuf,
18 repo_root: HgPathBuf,
@@ -53,3 +56,41 impl RelativizePaths {
53 }
56 }
54 }
57 }
55 }
58 }
59
60 /// Resolves `FILE ...` arguments to a list of paths in the repository.
61 pub fn resolve_file_args<'a>(
62 repo: &Repo,
63 file_args: impl Iterator<Item = &'a OsString>,
64 ) -> Result<Vec<HgPathBuf>, CommandError> {
65 let cwd = hg::utils::current_dir()?;
66 let root = cwd.join(repo.working_directory_path());
67 let mut result = Vec::new();
68 for pattern in file_args {
69 // TODO: Support all the formats in `hg help patterns`.
70 if pattern.as_encoded_bytes().contains(&b':') {
71 return Err(CommandError::unsupported(
72 "rhg does not support file patterns",
73 ));
74 }
75 // TODO: use hg::utils::files::canonical_path (currently doesn't work).
76 let path = cwd.join(pattern);
77 let dotted = path.components().any(|c| c.as_os_str() == "..");
78 if pattern.as_encoded_bytes() == b"." || dotted {
79 let message = "`..` or `.` path segment";
80 return Err(CommandError::unsupported(message));
81 }
82 let relative_path = root.strip_prefix(&cwd).unwrap_or(&root);
83 let stripped = path.strip_prefix(&root).map_err(|_| {
84 CommandError::abort(format!(
85 "abort: {} not under root '{}'\n(consider using '--cwd {}')",
86 String::from_utf8_lossy(pattern.as_encoded_bytes()),
87 root.display(),
88 relative_path.display(),
89 ))
90 })?;
91 let hg_file = HgPathBuf::try_from(stripped.to_path_buf())
92 .map_err(|e| CommandError::abort(e.to_string()))?;
93 result.push(hg_file);
94 }
95 Ok(result)
96 }
@@ -251,7 +251,7 Fallback with shell path segments
251
251
252 Fallback with filesets
252 Fallback with filesets
253 $ $NO_FALLBACK rhg cat "set:c or b"
253 $ $NO_FALLBACK rhg cat "set:c or b"
254 unsupported feature: fileset
254 unsupported feature: rhg does not support file patterns
255 [252]
255 [252]
256
256
257 Fallback with generic hooks
257 Fallback with generic hooks
General Comments 0
You need to be logged in to leave comments. Login now