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: |
|
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