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 = " |
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. |
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 }) |