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