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