Mercurial > hg
annotate rust/hg-core/src/sparse.rs @ 52314:33d8cb64e9da
rust: fix darwin build
author | Dan Villiom Podlaski Christiansen <danchr@gmail.com> |
---|---|
date | Mon, 18 Nov 2024 15:42:09 +0100 |
parents | 22d24f6d6411 |
children |
rev | line source |
---|---|
52043
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
1 use std::{collections::HashSet, fmt::Display, path::Path}; |
49485 | 2 |
52043
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
3 use format_bytes::{format_bytes, write_bytes, DisplayBytes}; |
49485 | 4 |
5 use crate::{ | |
6 errors::HgError, | |
52043
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
7 exit_codes::STATE_ERROR, |
52307
22d24f6d6411
rust-lib: remove exports for not too common pattern-related types
Raphaël Gomès <rgomes@octobus.net>
parents:
52306
diff
changeset
|
8 filepatterns::{ |
22d24f6d6411
rust-lib: remove exports for not too common pattern-related types
Raphaël Gomès <rgomes@octobus.net>
parents:
52306
diff
changeset
|
9 parse_pattern_file_contents, IgnorePattern, PatternError, |
22d24f6d6411
rust-lib: remove exports for not too common pattern-related types
Raphaël Gomès <rgomes@octobus.net>
parents:
52306
diff
changeset
|
10 PatternFileWarning, PatternSyntax, |
22d24f6d6411
rust-lib: remove exports for not too common pattern-related types
Raphaël Gomès <rgomes@octobus.net>
parents:
52306
diff
changeset
|
11 }, |
49485 | 12 matchers::{ |
13 AlwaysMatcher, DifferenceMatcher, IncludeMatcher, Matcher, | |
14 UnionMatcher, | |
15 }, | |
52043
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
16 narrow::VALID_PREFIXES, |
49485 | 17 operations::cat, |
18 repo::Repo, | |
19 requirements::SPARSE_REQUIREMENT, | |
20 utils::{hg_path::HgPath, SliceExt}, | |
52307
22d24f6d6411
rust-lib: remove exports for not too common pattern-related types
Raphaël Gomès <rgomes@octobus.net>
parents:
52306
diff
changeset
|
21 Revision, NULL_REVISION, |
49485 | 22 }; |
23 | |
24 /// Command which is triggering the config read | |
25 #[derive(Copy, Clone, Debug)] | |
26 pub enum SparseConfigContext { | |
27 Sparse, | |
28 Narrow, | |
29 } | |
30 | |
31 impl DisplayBytes for SparseConfigContext { | |
32 fn display_bytes( | |
33 &self, | |
34 output: &mut dyn std::io::Write, | |
35 ) -> std::io::Result<()> { | |
36 match self { | |
37 SparseConfigContext::Sparse => write_bytes!(output, b"sparse"), | |
38 SparseConfigContext::Narrow => write_bytes!(output, b"narrow"), | |
39 } | |
40 } | |
41 } | |
42 | |
52043
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
43 impl Display for SparseConfigContext { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
45 match self { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
46 SparseConfigContext::Sparse => write!(f, "sparse"), |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
47 SparseConfigContext::Narrow => write!(f, "narrow"), |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
48 } |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
49 } |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
50 } |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
51 |
49485 | 52 /// Possible warnings when reading sparse configuration |
53 #[derive(Debug, derive_more::From)] | |
54 pub enum SparseWarning { | |
55 /// Warns about improper paths that start with "/" | |
56 RootWarning { | |
57 context: SparseConfigContext, | |
58 line: Vec<u8>, | |
59 }, | |
60 /// Warns about a profile missing from the given changelog revision | |
61 ProfileNotFound { profile: Vec<u8>, rev: Revision }, | |
62 #[from] | |
63 Pattern(PatternFileWarning), | |
64 } | |
65 | |
66 /// Parsed sparse config | |
67 #[derive(Debug, Default)] | |
68 pub struct SparseConfig { | |
69 // Line-separated | |
49489
7c93e38a0bbd
rhg-status: add support for narrow clones
Raphaël Gomès <rgomes@octobus.net>
parents:
49485
diff
changeset
|
70 pub(crate) includes: Vec<u8>, |
49485 | 71 // Line-separated |
49489
7c93e38a0bbd
rhg-status: add support for narrow clones
Raphaël Gomès <rgomes@octobus.net>
parents:
49485
diff
changeset
|
72 pub(crate) excludes: Vec<u8>, |
7c93e38a0bbd
rhg-status: add support for narrow clones
Raphaël Gomès <rgomes@octobus.net>
parents:
49485
diff
changeset
|
73 pub(crate) profiles: HashSet<Vec<u8>>, |
7c93e38a0bbd
rhg-status: add support for narrow clones
Raphaël Gomès <rgomes@octobus.net>
parents:
49485
diff
changeset
|
74 pub(crate) warnings: Vec<SparseWarning>, |
49485 | 75 } |
76 | |
49489
7c93e38a0bbd
rhg-status: add support for narrow clones
Raphaël Gomès <rgomes@octobus.net>
parents:
49485
diff
changeset
|
77 /// All possible errors when reading sparse/narrow config |
49485 | 78 #[derive(Debug, derive_more::From)] |
79 pub enum SparseConfigError { | |
80 IncludesAfterExcludes { | |
81 context: SparseConfigContext, | |
82 }, | |
83 EntryOutsideSection { | |
84 context: SparseConfigContext, | |
85 line: Vec<u8>, | |
86 }, | |
49489
7c93e38a0bbd
rhg-status: add support for narrow clones
Raphaël Gomès <rgomes@octobus.net>
parents:
49485
diff
changeset
|
87 /// Narrow config does not support '%include' directives |
7c93e38a0bbd
rhg-status: add support for narrow clones
Raphaël Gomès <rgomes@octobus.net>
parents:
49485
diff
changeset
|
88 IncludesInNarrow, |
7c93e38a0bbd
rhg-status: add support for narrow clones
Raphaël Gomès <rgomes@octobus.net>
parents:
49485
diff
changeset
|
89 /// An invalid pattern prefix was given to the narrow spec. Includes the |
7c93e38a0bbd
rhg-status: add support for narrow clones
Raphaël Gomès <rgomes@octobus.net>
parents:
49485
diff
changeset
|
90 /// entire pattern for context. |
7c93e38a0bbd
rhg-status: add support for narrow clones
Raphaël Gomès <rgomes@octobus.net>
parents:
49485
diff
changeset
|
91 InvalidNarrowPrefix(Vec<u8>), |
49485 | 92 #[from] |
93 HgError(HgError), | |
94 #[from] | |
95 PatternError(PatternError), | |
96 } | |
97 | |
52043
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
98 impl From<SparseConfigError> for HgError { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
99 fn from(value: SparseConfigError) -> Self { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
100 match value { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
101 SparseConfigError::IncludesAfterExcludes { context } => { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
102 HgError::Abort { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
103 message: format!( |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
104 "{} config cannot have includes after excludes", |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
105 context, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
106 ), |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
107 detailed_exit_code: STATE_ERROR, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
108 hint: None, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
109 } |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
110 } |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
111 SparseConfigError::EntryOutsideSection { context, line } => { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
112 HgError::Abort { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
113 message: format!( |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
114 "{} config entry outside of section: {}", |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
115 context, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
116 String::from_utf8_lossy(&line) |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
117 ), |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
118 detailed_exit_code: STATE_ERROR, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
119 hint: None, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
120 } |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
121 } |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
122 SparseConfigError::IncludesInNarrow => HgError::Abort { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
123 message: "including other spec files using '%include' is not \ |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
124 supported in narrowspec" |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
125 .to_string(), |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
126 detailed_exit_code: STATE_ERROR, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
127 hint: None, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
128 }, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
129 SparseConfigError::InvalidNarrowPrefix(vec) => HgError::Abort { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
130 message: String::from_utf8_lossy(&format_bytes!( |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
131 b"invalid prefix on narrow pattern: {}", |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
132 vec |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
133 )) |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
134 .to_string(), |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
135 detailed_exit_code: STATE_ERROR, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
136 hint: Some(format!( |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
137 "narrow patterns must begin with one of the following: {}", |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
138 VALID_PREFIXES.join(", ") |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
139 )), |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
140 }, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
141 SparseConfigError::HgError(hg_error) => hg_error, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
142 SparseConfigError::PatternError(pattern_error) => HgError::Abort { |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
143 message: pattern_error.to_string(), |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
144 detailed_exit_code: STATE_ERROR, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
145 hint: None, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
146 }, |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
147 } |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
148 } |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
149 } |
ae1ab6d71f4a
rust: implement `From<SparseConfigWarning>` for `HgError`
Raphaël Gomès <rgomes@octobus.net>
parents:
50857
diff
changeset
|
150 |
49485 | 151 /// Parse sparse config file content. |
49489
7c93e38a0bbd
rhg-status: add support for narrow clones
Raphaël Gomès <rgomes@octobus.net>
parents:
49485
diff
changeset
|
152 pub(crate) fn parse_config( |
49485 | 153 raw: &[u8], |
154 context: SparseConfigContext, | |
155 ) -> Result<SparseConfig, SparseConfigError> { | |
156 let mut includes = vec![]; | |
157 let mut excludes = vec![]; | |
158 let mut profiles = HashSet::new(); | |
159 let mut warnings = vec![]; | |
160 | |
161 #[derive(PartialEq, Eq)] | |
162 enum Current { | |
163 Includes, | |
164 Excludes, | |
165 None, | |
49517
52464a20add0
rhg: parallellize computation of [unsure_is_modified]
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
49489
diff
changeset
|
166 } |
49485 | 167 |
168 let mut current = Current::None; | |
169 let mut in_section = false; | |
170 | |
171 for line in raw.split(|c| *c == b'\n') { | |
172 let line = line.trim(); | |
173 if line.is_empty() || line[0] == b'#' { | |
174 // empty or comment line, skip | |
175 continue; | |
176 } | |
177 if line.starts_with(b"%include ") { | |
178 let profile = line[b"%include ".len()..].trim(); | |
179 if !profile.is_empty() { | |
180 profiles.insert(profile.into()); | |
181 } | |
182 } else if line == b"[include]" { | |
183 if in_section && current == Current::Includes { | |
184 return Err(SparseConfigError::IncludesAfterExcludes { | |
185 context, | |
186 }); | |
187 } | |
188 in_section = true; | |
189 current = Current::Includes; | |
190 continue; | |
191 } else if line == b"[exclude]" { | |
192 in_section = true; | |
193 current = Current::Excludes; | |
194 } else { | |
195 if current == Current::None { | |
196 return Err(SparseConfigError::EntryOutsideSection { | |
197 context, | |
198 line: line.into(), | |
199 }); | |
200 } | |
201 if line.trim().starts_with(b"/") { | |
202 warnings.push(SparseWarning::RootWarning { | |
203 context, | |
204 line: line.into(), | |
205 }); | |
206 continue; | |
207 } | |
208 match current { | |
209 Current::Includes => { | |
210 includes.push(b'\n'); | |
211 includes.extend(line.iter()); | |
212 } | |
213 Current::Excludes => { | |
214 excludes.push(b'\n'); | |
215 excludes.extend(line.iter()); | |
216 } | |
217 Current::None => unreachable!(), | |
218 } | |
219 } | |
220 } | |
221 | |
222 Ok(SparseConfig { | |
223 includes, | |
224 excludes, | |
225 profiles, | |
226 warnings, | |
227 }) | |
228 } | |
229 | |
230 fn read_temporary_includes( | |
231 repo: &Repo, | |
232 ) -> Result<Vec<Vec<u8>>, SparseConfigError> { | |
49930
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
233 let raw = repo.hg_vfs().try_read("tempsparse")?.unwrap_or_default(); |
49485 | 234 if raw.is_empty() { |
235 return Ok(vec![]); | |
236 } | |
237 Ok(raw.split(|c| *c == b'\n').map(ToOwned::to_owned).collect()) | |
238 } | |
239 | |
240 /// Obtain sparse checkout patterns for the given revision | |
241 fn patterns_for_rev( | |
242 repo: &Repo, | |
243 rev: Revision, | |
244 ) -> Result<Option<SparseConfig>, SparseConfigError> { | |
245 if !repo.has_sparse() { | |
246 return Ok(None); | |
247 } | |
49930
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
248 let raw = repo.hg_vfs().try_read("sparse")?.unwrap_or_default(); |
49485 | 249 |
250 if raw.is_empty() { | |
251 return Ok(None); | |
252 } | |
253 | |
254 let mut config = parse_config(&raw, SparseConfigContext::Sparse)?; | |
255 | |
256 if !config.profiles.is_empty() { | |
257 let mut profiles: Vec<Vec<u8>> = config.profiles.into_iter().collect(); | |
258 let mut visited = HashSet::new(); | |
259 | |
260 while let Some(profile) = profiles.pop() { | |
261 if visited.contains(&profile) { | |
262 continue; | |
263 } | |
264 visited.insert(profile.to_owned()); | |
265 | |
266 let output = | |
267 cat(repo, &rev.to_string(), vec![HgPath::new(&profile)]) | |
268 .map_err(|_| { | |
49930
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
269 HgError::corrupted( |
49485 | 270 "dirstate points to non-existent parent node" |
49930
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
271 .to_string(), |
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
272 ) |
49485 | 273 })?; |
274 if output.results.is_empty() { | |
275 config.warnings.push(SparseWarning::ProfileNotFound { | |
276 profile: profile.to_owned(), | |
277 rev, | |
278 }) | |
279 } | |
280 | |
281 let subconfig = parse_config( | |
282 &output.results[0].1, | |
283 SparseConfigContext::Sparse, | |
284 )?; | |
285 if !subconfig.includes.is_empty() { | |
286 config.includes.push(b'\n'); | |
287 config.includes.extend(&subconfig.includes); | |
288 } | |
289 if !subconfig.includes.is_empty() { | |
290 config.includes.push(b'\n'); | |
291 config.excludes.extend(&subconfig.excludes); | |
292 } | |
293 config.warnings.extend(subconfig.warnings.into_iter()); | |
294 profiles.extend(subconfig.profiles.into_iter()); | |
295 } | |
296 | |
297 config.profiles = visited; | |
298 } | |
299 | |
300 if !config.includes.is_empty() { | |
301 config.includes.extend(b"\n.hg*"); | |
302 } | |
303 | |
304 Ok(Some(config)) | |
305 } | |
306 | |
307 /// Obtain a matcher for sparse working directories. | |
308 pub fn matcher( | |
309 repo: &Repo, | |
310 ) -> Result<(Box<dyn Matcher + Sync>, Vec<SparseWarning>), SparseConfigError> { | |
311 let mut warnings = vec![]; | |
312 if !repo.requirements().contains(SPARSE_REQUIREMENT) { | |
313 return Ok((Box::new(AlwaysMatcher), warnings)); | |
314 } | |
315 | |
316 let parents = repo.dirstate_parents()?; | |
317 let mut revs = vec![]; | |
318 let p1_rev = | |
319 repo.changelog()? | |
320 .rev_from_node(parents.p1.into()) | |
321 .map_err(|_| { | |
49930
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
322 HgError::corrupted( |
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
323 "dirstate points to non-existent parent node".to_string(), |
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
324 ) |
49485 | 325 })?; |
326 if p1_rev != NULL_REVISION { | |
327 revs.push(p1_rev) | |
328 } | |
329 let p2_rev = | |
330 repo.changelog()? | |
331 .rev_from_node(parents.p2.into()) | |
332 .map_err(|_| { | |
49930
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
333 HgError::corrupted( |
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
334 "dirstate points to non-existent parent node".to_string(), |
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
335 ) |
49485 | 336 })?; |
337 if p2_rev != NULL_REVISION { | |
338 revs.push(p2_rev) | |
339 } | |
340 let mut matchers = vec![]; | |
341 | |
342 for rev in revs.iter() { | |
343 let config = patterns_for_rev(repo, *rev); | |
344 if let Ok(Some(config)) = config { | |
345 warnings.extend(config.warnings); | |
346 let mut m: Box<dyn Matcher + Sync> = Box::new(AlwaysMatcher); | |
347 if !config.includes.is_empty() { | |
348 let (patterns, subwarnings) = parse_pattern_file_contents( | |
349 &config.includes, | |
350 Path::new(""), | |
50857
796b5d6693a4
rust: simplify pattern file parsing
Spencer Baugh <sbaugh@janestreet.com>
parents:
50821
diff
changeset
|
351 Some(PatternSyntax::Glob), |
796b5d6693a4
rust: simplify pattern file parsing
Spencer Baugh <sbaugh@janestreet.com>
parents:
50821
diff
changeset
|
352 false, |
49485 | 353 false, |
354 )?; | |
355 warnings.extend(subwarnings.into_iter().map(From::from)); | |
356 m = Box::new(IncludeMatcher::new(patterns)?); | |
357 } | |
358 if !config.excludes.is_empty() { | |
359 let (patterns, subwarnings) = parse_pattern_file_contents( | |
360 &config.excludes, | |
361 Path::new(""), | |
50857
796b5d6693a4
rust: simplify pattern file parsing
Spencer Baugh <sbaugh@janestreet.com>
parents:
50821
diff
changeset
|
362 Some(PatternSyntax::Glob), |
796b5d6693a4
rust: simplify pattern file parsing
Spencer Baugh <sbaugh@janestreet.com>
parents:
50821
diff
changeset
|
363 false, |
49485 | 364 false, |
365 )?; | |
366 warnings.extend(subwarnings.into_iter().map(From::from)); | |
367 m = Box::new(DifferenceMatcher::new( | |
368 m, | |
369 Box::new(IncludeMatcher::new(patterns)?), | |
370 )); | |
371 } | |
372 matchers.push(m); | |
373 } | |
374 } | |
375 let result: Box<dyn Matcher + Sync> = match matchers.len() { | |
376 0 => Box::new(AlwaysMatcher), | |
377 1 => matchers.pop().expect("1 is equal to 0"), | |
378 _ => Box::new(UnionMatcher::new(matchers)), | |
379 }; | |
380 | |
381 let matcher = | |
382 force_include_matcher(result, &read_temporary_includes(repo)?)?; | |
383 Ok((matcher, warnings)) | |
384 } | |
385 | |
386 /// Returns a matcher that returns true for any of the forced includes before | |
387 /// testing against the actual matcher | |
388 fn force_include_matcher( | |
389 result: Box<dyn Matcher + Sync>, | |
390 temp_includes: &[Vec<u8>], | |
391 ) -> Result<Box<dyn Matcher + Sync>, PatternError> { | |
392 if temp_includes.is_empty() { | |
393 return Ok(result); | |
394 } | |
395 let forced_include_matcher = IncludeMatcher::new( | |
396 temp_includes | |
49930
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49517
diff
changeset
|
397 .iter() |
49485 | 398 .map(|include| { |
399 IgnorePattern::new(PatternSyntax::Path, include, Path::new("")) | |
400 }) | |
401 .collect(), | |
402 )?; | |
403 Ok(Box::new(UnionMatcher::new(vec![ | |
404 Box::new(forced_include_matcher), | |
405 result, | |
406 ]))) | |
407 } |