##// END OF EJS Templates
rhg: support rhg files [FILE]...
Spencer Baugh -
r51760:788113f0 default
parent child Browse files
Show More
@@ -1,116 +1,149 b''
1 use crate::error::CommandError;
1 use crate::error::CommandError;
2 use crate::ui::{
2 use crate::ui::{
3 print_narrow_sparse_warnings, relative_paths, RelativePaths, Ui,
3 print_narrow_sparse_warnings, relative_paths, RelativePaths, Ui,
4 };
4 };
5 use crate::utils::path_utils::RelativizePaths;
5 use crate::utils::path_utils::RelativizePaths;
6 use clap::Arg;
6 use clap::Arg;
7 use hg::filepatterns::parse_pattern_args;
8 use hg::matchers::IntersectionMatcher;
7 use hg::narrow;
9 use hg::narrow;
8 use hg::operations::list_rev_tracked_files;
10 use hg::operations::list_rev_tracked_files;
9 use hg::repo::Repo;
11 use hg::repo::Repo;
12 use hg::utils::files::get_bytes_from_os_str;
10 use hg::utils::filter_map_results;
13 use hg::utils::filter_map_results;
11 use hg::utils::hg_path::HgPath;
14 use hg::utils::hg_path::HgPath;
12 use rayon::prelude::*;
15 use rayon::prelude::*;
13
16
14 pub const HELP_TEXT: &str = "
17 pub const HELP_TEXT: &str = "
15 List tracked files.
18 List tracked files.
16
19
17 Returns 0 on success.
20 Returns 0 on success.
18 ";
21 ";
19
22
20 pub fn args() -> clap::Command {
23 pub fn args() -> clap::Command {
21 clap::command!("files")
24 clap::command!("files")
22 .arg(
25 .arg(
23 Arg::new("rev")
26 Arg::new("rev")
24 .help("search the repository as it is in REV")
27 .help("search the repository as it is in REV")
25 .short('r')
28 .short('r')
26 .long("revision")
29 .long("revision")
27 .value_name("REV"),
30 .value_name("REV"),
28 )
31 )
32 .arg(
33 Arg::new("file")
34 .value_parser(clap::value_parser!(std::ffi::OsString))
35 .help("show only these files")
36 .action(clap::ArgAction::Append),
37 )
29 .about(HELP_TEXT)
38 .about(HELP_TEXT)
30 }
39 }
31
40
32 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
41 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
33 let relative_paths = match relative_paths(invocation.config)? {
42 let relative_paths = match relative_paths(invocation.config)? {
34 RelativePaths::Legacy => true,
43 RelativePaths::Legacy => true,
35 RelativePaths::Bool(v) => v,
44 RelativePaths::Bool(v) => v,
36 };
45 };
37
46
38 let rev = invocation.subcommand_args.get_one::<String>("rev");
47 let args = invocation.subcommand_args;
48 let rev = args.get_one::<String>("rev");
39
49
40 let repo = invocation.repo?;
50 let repo = invocation.repo?;
41
51
42 // It seems better if this check is removed: this would correspond to
52 // It seems better if this check is removed: this would correspond to
43 // automatically enabling the extension if the repo requires it.
53 // automatically enabling the extension if the repo requires it.
44 // However we need this check to be in sync with vanilla hg so hg tests
54 // However we need this check to be in sync with vanilla hg so hg tests
45 // pass.
55 // pass.
46 if repo.has_sparse()
56 if repo.has_sparse()
47 && invocation.config.get(b"extensions", b"sparse").is_none()
57 && invocation.config.get(b"extensions", b"sparse").is_none()
48 {
58 {
49 return Err(CommandError::unsupported(
59 return Err(CommandError::unsupported(
50 "repo is using sparse, but sparse extension is not enabled",
60 "repo is using sparse, but sparse extension is not enabled",
51 ));
61 ));
52 }
62 }
53
63
54 let (narrow_matcher, narrow_warnings) = narrow::matcher(repo)?;
64 let (matcher, narrow_warnings) = narrow::matcher(repo)?;
55 print_narrow_sparse_warnings(&narrow_warnings, &[], invocation.ui, repo)?;
65 print_narrow_sparse_warnings(&narrow_warnings, &[], invocation.ui, repo)?;
66 let matcher = match args.get_many::<std::ffi::OsString>("file") {
67 None => matcher,
68 Some(files) => {
69 let patterns: Vec<Vec<u8>> = files
70 .filter(|s| !s.is_empty())
71 .map(get_bytes_from_os_str)
72 .collect();
73 for file in &patterns {
74 if file.starts_with(b"set:") {
75 return Err(CommandError::unsupported("fileset"));
76 }
77 }
78 let cwd = hg::utils::current_dir()?;
79 let root = repo.working_directory_path();
80 let ignore_patterns = parse_pattern_args(patterns, &cwd, root)?;
81 let files_matcher =
82 hg::matchers::PatternMatcher::new(ignore_patterns)?;
83 Box::new(IntersectionMatcher::new(
84 Box::new(files_matcher),
85 matcher,
86 ))
87 }
88 };
56
89
57 if let Some(rev) = rev {
90 if let Some(rev) = rev {
58 let files = list_rev_tracked_files(repo, rev, narrow_matcher)
91 let files = list_rev_tracked_files(repo, rev, matcher)
59 .map_err(|e| (e, rev.as_ref()))?;
92 .map_err(|e| (e, rev.as_ref()))?;
60 display_files(invocation.ui, repo, relative_paths, files.iter())
93 display_files(invocation.ui, repo, relative_paths, files.iter())
61 } else {
94 } else {
62 // The dirstate always reflects the sparse narrowspec.
95 // The dirstate always reflects the sparse narrowspec.
63 let dirstate = repo.dirstate_map()?;
96 let dirstate = repo.dirstate_map()?;
64 let files_res: Result<Vec<_>, _> =
97 let files_res: Result<Vec<_>, _> =
65 filter_map_results(dirstate.iter(), |(path, entry)| {
98 filter_map_results(dirstate.iter(), |(path, entry)| {
66 Ok(if entry.tracked() && narrow_matcher.matches(path) {
99 Ok(if entry.tracked() && matcher.matches(path) {
67 Some(path)
100 Some(path)
68 } else {
101 } else {
69 None
102 None
70 })
103 })
71 })
104 })
72 .collect();
105 .collect();
73
106
74 let mut files = files_res?;
107 let mut files = files_res?;
75 files.par_sort_unstable();
108 files.par_sort_unstable();
76
109
77 display_files(
110 display_files(
78 invocation.ui,
111 invocation.ui,
79 repo,
112 repo,
80 relative_paths,
113 relative_paths,
81 files.into_iter().map::<Result<_, CommandError>, _>(Ok),
114 files.into_iter().map::<Result<_, CommandError>, _>(Ok),
82 )
115 )
83 }
116 }
84 }
117 }
85
118
86 fn display_files<'a, E>(
119 fn display_files<'a, E>(
87 ui: &Ui,
120 ui: &Ui,
88 repo: &Repo,
121 repo: &Repo,
89 relative_paths: bool,
122 relative_paths: bool,
90 files: impl IntoIterator<Item = Result<&'a HgPath, E>>,
123 files: impl IntoIterator<Item = Result<&'a HgPath, E>>,
91 ) -> Result<(), CommandError>
124 ) -> Result<(), CommandError>
92 where
125 where
93 CommandError: From<E>,
126 CommandError: From<E>,
94 {
127 {
95 let mut stdout = ui.stdout_buffer();
128 let mut stdout = ui.stdout_buffer();
96 let mut any = false;
129 let mut any = false;
97
130
98 let relativize = RelativizePaths::new(repo)?;
131 let relativize = RelativizePaths::new(repo)?;
99 for result in files {
132 for result in files {
100 let path = result?;
133 let path = result?;
101 if relative_paths {
134 if relative_paths {
102 stdout.write_all(&relativize.relativize(path))?;
135 stdout.write_all(&relativize.relativize(path))?;
103 } else {
136 } else {
104 stdout.write_all(path.as_bytes())?;
137 stdout.write_all(path.as_bytes())?;
105 }
138 }
106 stdout.write_all(b"\n")?;
139 stdout.write_all(b"\n")?;
107 any = true;
140 any = true;
108 }
141 }
109
142
110 stdout.flush()?;
143 stdout.flush()?;
111 if any {
144 if any {
112 Ok(())
145 Ok(())
113 } else {
146 } else {
114 Err(CommandError::Unsuccessful)
147 Err(CommandError::Unsuccessful)
115 }
148 }
116 }
149 }
General Comments 0
You need to be logged in to leave comments. Login now