Show More
@@ -1,113 +1,113 | |||
|
1 | 1 | use std::path::Path; |
|
2 | 2 | |
|
3 | 3 | use crate::{ |
|
4 | 4 | errors::HgError, |
|
5 | 5 | exit_codes, |
|
6 | 6 | filepatterns::parse_pattern_file_contents, |
|
7 | 7 | matchers::{ |
|
8 | 8 | AlwaysMatcher, DifferenceMatcher, IncludeMatcher, Matcher, |
|
9 | 9 | NeverMatcher, |
|
10 | 10 | }, |
|
11 | 11 | repo::Repo, |
|
12 | 12 | requirements::NARROW_REQUIREMENT, |
|
13 | 13 | sparse::{self, SparseConfigError, SparseWarning}, |
|
14 | 14 | }; |
|
15 | 15 | |
|
16 | 16 | /// The file in .hg/store/ that indicates which paths exit in the store |
|
17 | 17 | const FILENAME: &str = "narrowspec"; |
|
18 | 18 | /// The file in .hg/ that indicates which paths exit in the dirstate |
|
19 | 19 | const DIRSTATE_FILENAME: &str = "narrowspec.dirstate"; |
|
20 | 20 | |
|
21 | 21 | /// Pattern prefixes that are allowed in narrow patterns. This list MUST |
|
22 | 22 | /// only contain patterns that are fast and safe to evaluate. Keep in mind |
|
23 | 23 | /// that patterns are supplied by clients and executed on remote servers |
|
24 | 24 | /// as part of wire protocol commands. That means that changes to this |
|
25 | 25 | /// data structure influence the wire protocol and should not be taken |
|
26 | 26 | /// lightly - especially removals. |
|
27 | 27 | const VALID_PREFIXES: [&str; 2] = ["path:", "rootfilesin:"]; |
|
28 | 28 | |
|
29 | 29 | /// Return the matcher for the current narrow spec, and all configuration |
|
30 | 30 | /// warnings to display. |
|
31 | 31 | pub fn matcher( |
|
32 | 32 | repo: &Repo, |
|
33 | 33 | ) -> Result<(Box<dyn Matcher + Sync>, Vec<SparseWarning>), SparseConfigError> { |
|
34 | 34 | let mut warnings = vec![]; |
|
35 | 35 | if !repo.requirements().contains(NARROW_REQUIREMENT) { |
|
36 | 36 | return Ok((Box::new(AlwaysMatcher), warnings)); |
|
37 | 37 | } |
|
38 | 38 | // Treat "narrowspec does not exist" the same as "narrowspec file exists |
|
39 | 39 | // and is empty". |
|
40 | 40 | let store_spec = repo.store_vfs().try_read(FILENAME)?.unwrap_or_default(); |
|
41 | 41 | let working_copy_spec = repo |
|
42 | 42 | .hg_vfs() |
|
43 | 43 | .try_read(DIRSTATE_FILENAME)? |
|
44 | 44 | .unwrap_or_default(); |
|
45 | 45 | if store_spec != working_copy_spec { |
|
46 | 46 | return Err(HgError::abort( |
|
47 | "working copy's narrowspec is stale", | |
|
47 | "abort: working copy's narrowspec is stale", | |
|
48 | 48 | exit_codes::STATE_ERROR, |
|
49 | 49 | Some("run 'hg tracked --update-working-copy'".into()), |
|
50 | 50 | ) |
|
51 | 51 | .into()); |
|
52 | 52 | } |
|
53 | 53 | |
|
54 | 54 | let config = sparse::parse_config( |
|
55 | 55 | &store_spec, |
|
56 | 56 | sparse::SparseConfigContext::Narrow, |
|
57 | 57 | )?; |
|
58 | 58 | |
|
59 | 59 | warnings.extend(config.warnings); |
|
60 | 60 | |
|
61 | 61 | if !config.profiles.is_empty() { |
|
62 | 62 | // TODO (from Python impl) maybe do something with profiles? |
|
63 | 63 | return Err(SparseConfigError::IncludesInNarrow); |
|
64 | 64 | } |
|
65 | 65 | validate_patterns(&config.includes)?; |
|
66 | 66 | validate_patterns(&config.excludes)?; |
|
67 | 67 | |
|
68 | 68 | if config.includes.is_empty() { |
|
69 | 69 | return Ok((Box::new(NeverMatcher), warnings)); |
|
70 | 70 | } |
|
71 | 71 | |
|
72 | 72 | let (patterns, subwarnings) = parse_pattern_file_contents( |
|
73 | 73 | &config.includes, |
|
74 | 74 | Path::new(""), |
|
75 | 75 | None, |
|
76 | 76 | false, |
|
77 | 77 | )?; |
|
78 | 78 | warnings.extend(subwarnings.into_iter().map(From::from)); |
|
79 | 79 | |
|
80 | 80 | let mut m: Box<dyn Matcher + Sync> = |
|
81 | 81 | Box::new(IncludeMatcher::new(patterns)?); |
|
82 | 82 | |
|
83 | 83 | let (patterns, subwarnings) = parse_pattern_file_contents( |
|
84 | 84 | &config.excludes, |
|
85 | 85 | Path::new(""), |
|
86 | 86 | None, |
|
87 | 87 | false, |
|
88 | 88 | )?; |
|
89 | 89 | if !patterns.is_empty() { |
|
90 | 90 | warnings.extend(subwarnings.into_iter().map(From::from)); |
|
91 | 91 | let exclude_matcher = Box::new(IncludeMatcher::new(patterns)?); |
|
92 | 92 | m = Box::new(DifferenceMatcher::new(m, exclude_matcher)); |
|
93 | 93 | } |
|
94 | 94 | |
|
95 | 95 | Ok((m, warnings)) |
|
96 | 96 | } |
|
97 | 97 | |
|
98 | 98 | fn validate_patterns(patterns: &[u8]) -> Result<(), SparseConfigError> { |
|
99 | 99 | for pattern in patterns.split(|c| *c == b'\n') { |
|
100 | 100 | if pattern.is_empty() { |
|
101 | 101 | continue; |
|
102 | 102 | } |
|
103 | 103 | for prefix in VALID_PREFIXES.iter() { |
|
104 | 104 | if pattern.starts_with(prefix.as_bytes()) { |
|
105 | 105 | return Ok(()); |
|
106 | 106 | } |
|
107 | 107 | } |
|
108 | 108 | return Err(SparseConfigError::InvalidNarrowPrefix( |
|
109 | 109 | pattern.to_owned(), |
|
110 | 110 | )); |
|
111 | 111 | } |
|
112 | 112 | Ok(()) |
|
113 | 113 | } |
General Comments 0
You need to be logged in to leave comments.
Login now