##// END OF EJS Templates
rhg: fix user-facing error message so it matches Python implementation
Raphaël Gomès -
r50877:7faedeb2 default
parent child Browse files
Show More
@@ -1,113 +1,113 b''
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