##// END OF EJS Templates
rhg: fallback to slow path on invalid patterns in hgignore
Arseniy Alekseyev -
r50434:8076298b stable
parent child Browse files
Show More
@@ -1,290 +1,295 b''
1 1 use crate::ui::utf8_to_local;
2 2 use crate::ui::UiError;
3 3 use crate::NoRepoInCwdError;
4 4 use format_bytes::format_bytes;
5 5 use hg::config::{ConfigError, ConfigParseError, ConfigValueParseError};
6 6 use hg::dirstate_tree::on_disk::DirstateV2ParseError;
7 7 use hg::errors::HgError;
8 8 use hg::exit_codes;
9 9 use hg::repo::RepoError;
10 10 use hg::revlog::revlog::RevlogError;
11 11 use hg::sparse::SparseConfigError;
12 12 use hg::utils::files::get_bytes_from_path;
13 13 use hg::{DirstateError, DirstateMapError, StatusError};
14 14 use std::convert::From;
15 15
16 16 /// The kind of command error
17 17 #[derive(Debug)]
18 18 pub enum CommandError {
19 19 /// Exit with an error message and "standard" failure exit code.
20 20 Abort {
21 21 message: Vec<u8>,
22 22 detailed_exit_code: exit_codes::ExitCode,
23 23 hint: Option<Vec<u8>>,
24 24 },
25 25
26 26 /// Exit with a failure exit code but no message.
27 27 Unsuccessful,
28 28
29 29 /// Encountered something (such as a CLI argument, repository layout, …)
30 30 /// not supported by this version of `rhg`. Depending on configuration
31 31 /// `rhg` may attempt to silently fall back to Python-based `hg`, which
32 32 /// may or may not support this feature.
33 33 UnsupportedFeature { message: Vec<u8> },
34 34 /// The fallback executable does not exist (or has some other problem if
35 35 /// we end up being more precise about broken fallbacks).
36 36 InvalidFallback { path: Vec<u8>, err: String },
37 37 }
38 38
39 39 impl CommandError {
40 40 pub fn abort(message: impl AsRef<str>) -> Self {
41 41 CommandError::abort_with_exit_code(message, exit_codes::ABORT)
42 42 }
43 43
44 44 pub fn abort_with_exit_code(
45 45 message: impl AsRef<str>,
46 46 detailed_exit_code: exit_codes::ExitCode,
47 47 ) -> Self {
48 48 CommandError::Abort {
49 49 // TODO: bytes-based (instead of Unicode-based) formatting
50 50 // of error messages to handle non-UTF-8 filenames etc:
51 51 // https://www.mercurial-scm.org/wiki/EncodingStrategy#Mixing_output
52 52 message: utf8_to_local(message.as_ref()).into(),
53 53 detailed_exit_code: detailed_exit_code,
54 54 hint: None,
55 55 }
56 56 }
57 57
58 58 pub fn abort_with_exit_code_and_hint(
59 59 message: impl AsRef<str>,
60 60 detailed_exit_code: exit_codes::ExitCode,
61 61 hint: Option<impl AsRef<str>>,
62 62 ) -> Self {
63 63 CommandError::Abort {
64 64 message: utf8_to_local(message.as_ref()).into(),
65 65 detailed_exit_code,
66 66 hint: hint.map(|h| utf8_to_local(h.as_ref()).into()),
67 67 }
68 68 }
69 69
70 70 pub fn abort_with_exit_code_bytes(
71 71 message: impl AsRef<[u8]>,
72 72 detailed_exit_code: exit_codes::ExitCode,
73 73 ) -> Self {
74 74 // TODO: use this everywhere it makes sense instead of the string
75 75 // version.
76 76 CommandError::Abort {
77 77 message: message.as_ref().into(),
78 78 detailed_exit_code,
79 79 hint: None,
80 80 }
81 81 }
82 82
83 83 pub fn unsupported(message: impl AsRef<str>) -> Self {
84 84 CommandError::UnsupportedFeature {
85 85 message: utf8_to_local(message.as_ref()).into(),
86 86 }
87 87 }
88 88 }
89 89
90 90 /// For now we don’t differenciate between invalid CLI args and valid for `hg`
91 91 /// but not supported yet by `rhg`.
92 92 impl From<clap::Error> for CommandError {
93 93 fn from(error: clap::Error) -> Self {
94 94 CommandError::unsupported(error.to_string())
95 95 }
96 96 }
97 97
98 98 impl From<HgError> for CommandError {
99 99 fn from(error: HgError) -> Self {
100 100 match error {
101 101 HgError::UnsupportedFeature(message) => {
102 102 CommandError::unsupported(message)
103 103 }
104 104 HgError::CensoredNodeError => {
105 105 CommandError::unsupported("Encountered a censored node")
106 106 }
107 107 HgError::Abort {
108 108 message,
109 109 detailed_exit_code,
110 110 hint,
111 111 } => CommandError::abort_with_exit_code_and_hint(
112 112 message,
113 113 detailed_exit_code,
114 114 hint,
115 115 ),
116 116 _ => CommandError::abort(error.to_string()),
117 117 }
118 118 }
119 119 }
120 120
121 121 impl From<ConfigValueParseError> for CommandError {
122 122 fn from(error: ConfigValueParseError) -> Self {
123 123 CommandError::abort_with_exit_code(
124 124 error.to_string(),
125 125 exit_codes::CONFIG_ERROR_ABORT,
126 126 )
127 127 }
128 128 }
129 129
130 130 impl From<UiError> for CommandError {
131 131 fn from(_error: UiError) -> Self {
132 132 // If we already failed writing to stdout or stderr,
133 133 // writing an error message to stderr about it would be likely to fail
134 134 // too.
135 135 CommandError::abort("")
136 136 }
137 137 }
138 138
139 139 impl From<RepoError> for CommandError {
140 140 fn from(error: RepoError) -> Self {
141 141 match error {
142 142 RepoError::NotFound { at } => {
143 143 CommandError::abort_with_exit_code_bytes(
144 144 format_bytes!(
145 145 b"abort: repository {} not found",
146 146 get_bytes_from_path(at)
147 147 ),
148 148 exit_codes::ABORT,
149 149 )
150 150 }
151 151 RepoError::ConfigParseError(error) => error.into(),
152 152 RepoError::Other(error) => error.into(),
153 153 }
154 154 }
155 155 }
156 156
157 157 impl<'a> From<&'a NoRepoInCwdError> for CommandError {
158 158 fn from(error: &'a NoRepoInCwdError) -> Self {
159 159 let NoRepoInCwdError { cwd } = error;
160 160 CommandError::abort_with_exit_code_bytes(
161 161 format_bytes!(
162 162 b"abort: no repository found in '{}' (.hg not found)!",
163 163 get_bytes_from_path(cwd)
164 164 ),
165 165 exit_codes::ABORT,
166 166 )
167 167 }
168 168 }
169 169
170 170 impl From<ConfigError> for CommandError {
171 171 fn from(error: ConfigError) -> Self {
172 172 match error {
173 173 ConfigError::Parse(error) => error.into(),
174 174 ConfigError::Other(error) => error.into(),
175 175 }
176 176 }
177 177 }
178 178
179 179 impl From<ConfigParseError> for CommandError {
180 180 fn from(error: ConfigParseError) -> Self {
181 181 let ConfigParseError {
182 182 origin,
183 183 line,
184 184 message,
185 185 } = error;
186 186 let line_message = if let Some(line_number) = line {
187 187 format_bytes!(b":{}", line_number.to_string().into_bytes())
188 188 } else {
189 189 Vec::new()
190 190 };
191 191 CommandError::abort_with_exit_code_bytes(
192 192 format_bytes!(
193 193 b"config error at {}{}: {}",
194 194 origin,
195 195 line_message,
196 196 message
197 197 ),
198 198 exit_codes::CONFIG_ERROR_ABORT,
199 199 )
200 200 }
201 201 }
202 202
203 203 impl From<(RevlogError, &str)> for CommandError {
204 204 fn from((err, rev): (RevlogError, &str)) -> CommandError {
205 205 match err {
206 206 RevlogError::WDirUnsupported => CommandError::abort(
207 207 "abort: working directory revision cannot be specified",
208 208 ),
209 209 RevlogError::InvalidRevision => CommandError::abort(format!(
210 210 "abort: invalid revision identifier: {}",
211 211 rev
212 212 )),
213 213 RevlogError::AmbiguousPrefix => CommandError::abort(format!(
214 214 "abort: ambiguous revision identifier: {}",
215 215 rev
216 216 )),
217 217 RevlogError::Other(error) => error.into(),
218 218 }
219 219 }
220 220 }
221 221
222 222 impl From<StatusError> for CommandError {
223 223 fn from(error: StatusError) -> Self {
224 CommandError::abort(format!("{}", error))
224 match error {
225 StatusError::Pattern(_) => {
226 CommandError::unsupported(format!("{}", error))
227 }
228 _ => CommandError::abort(format!("{}", error)),
229 }
225 230 }
226 231 }
227 232
228 233 impl From<DirstateMapError> for CommandError {
229 234 fn from(error: DirstateMapError) -> Self {
230 235 CommandError::abort(format!("{}", error))
231 236 }
232 237 }
233 238
234 239 impl From<DirstateError> for CommandError {
235 240 fn from(error: DirstateError) -> Self {
236 241 match error {
237 242 DirstateError::Common(error) => error.into(),
238 243 DirstateError::Map(error) => error.into(),
239 244 }
240 245 }
241 246 }
242 247
243 248 impl From<DirstateV2ParseError> for CommandError {
244 249 fn from(error: DirstateV2ParseError) -> Self {
245 250 HgError::from(error).into()
246 251 }
247 252 }
248 253
249 254 impl From<SparseConfigError> for CommandError {
250 255 fn from(e: SparseConfigError) -> Self {
251 256 match e {
252 257 SparseConfigError::IncludesAfterExcludes { context } => {
253 258 Self::abort_with_exit_code_bytes(
254 259 format_bytes!(
255 260 b"{} config cannot have includes after excludes",
256 261 context
257 262 ),
258 263 exit_codes::CONFIG_PARSE_ERROR_ABORT,
259 264 )
260 265 }
261 266 SparseConfigError::EntryOutsideSection { context, line } => {
262 267 Self::abort_with_exit_code_bytes(
263 268 format_bytes!(
264 269 b"{} config entry outside of section: {}",
265 270 context,
266 271 &line,
267 272 ),
268 273 exit_codes::CONFIG_PARSE_ERROR_ABORT,
269 274 )
270 275 }
271 276 SparseConfigError::InvalidNarrowPrefix(prefix) => {
272 277 Self::abort_with_exit_code_bytes(
273 278 format_bytes!(
274 279 b"invalid prefix on narrow pattern: {}",
275 280 &prefix
276 281 ),
277 282 exit_codes::ABORT,
278 283 )
279 284 }
280 285 SparseConfigError::IncludesInNarrow => Self::abort(
281 286 "including other spec files using '%include' \
282 287 is not supported in narrowspec",
283 288 ),
284 289 SparseConfigError::HgError(e) => Self::from(e),
285 290 SparseConfigError::PatternError(e) => {
286 291 Self::unsupported(format!("{}", e))
287 292 }
288 293 }
289 294 }
290 295 }
@@ -1,449 +1,437 b''
1 1 #testcases dirstate-v1 dirstate-v2
2 2
3 3 #if dirstate-v2
4 4 $ cat >> $HGRCPATH << EOF
5 5 > [format]
6 6 > use-dirstate-v2=1
7 7 > [storage]
8 8 > dirstate-v2.slow-path=allow
9 9 > EOF
10 10 #endif
11 11
12 12 $ hg init ignorerepo
13 13 $ cd ignorerepo
14 14
15 15 debugignore with no hgignore should be deterministic:
16 16 $ hg debugignore
17 17 <nevermatcher>
18 18
19 19 Issue562: .hgignore requires newline at end:
20 20
21 21 $ touch foo
22 22 $ touch bar
23 23 $ touch baz
24 24 $ cat > makeignore.py <<EOF
25 25 > f = open(".hgignore", "w")
26 26 > f.write("ignore\n")
27 27 > f.write("foo\n")
28 28 > # No EOL here
29 29 > f.write("bar")
30 30 > f.close()
31 31 > EOF
32 32
33 33 $ "$PYTHON" makeignore.py
34 34
35 35 Should display baz only:
36 36
37 37 $ hg status
38 38 ? baz
39 39
40 40 $ rm foo bar baz .hgignore makeignore.py
41 41
42 42 $ touch a.o
43 43 $ touch a.c
44 44 $ touch syntax
45 45 $ mkdir dir
46 46 $ touch dir/a.o
47 47 $ touch dir/b.o
48 48 $ touch dir/c.o
49 49
50 50 $ hg add dir/a.o
51 51 $ hg commit -m 0
52 52 $ hg add dir/b.o
53 53
54 54 $ hg status
55 55 A dir/b.o
56 56 ? a.c
57 57 ? a.o
58 58 ? dir/c.o
59 59 ? syntax
60 60
61 61 $ echo "*.o" > .hgignore
62 #if no-rhg
63 62 $ hg status
64 63 abort: $TESTTMP/ignorerepo/.hgignore: invalid pattern (relre): *.o (glob)
65 64 [255]
66 #endif
67 #if rhg
68 $ hg status
69 Unsupported syntax regex parse error:
70 ^(?:*.o)
71 ^
72 error: repetition operator missing expression
73 [255]
74 #endif
75 65
76 66 $ echo 're:^(?!a).*\.o$' > .hgignore
77 #if no-rhg
78 67 $ hg status
79 68 A dir/b.o
80 69 ? .hgignore
81 70 ? a.c
82 71 ? a.o
83 72 ? syntax
84 #endif
85 73 #if rhg
86 $ hg status
87 Unsupported syntax regex parse error:
74 $ hg status --config rhg.on-unsupported=abort
75 unsupported feature: Unsupported syntax regex parse error:
88 76 ^(?:^(?!a).*\.o$)
89 77 ^^^
90 78 error: look-around, including look-ahead and look-behind, is not supported
91 [255]
79 [252]
92 80 #endif
93 81
94 82 Ensure given files are relative to cwd
95 83
96 84 $ echo "dir/.*\.o" > .hgignore
97 85 $ hg status -i
98 86 I dir/c.o
99 87
100 88 $ hg debugignore dir/c.o dir/missing.o
101 89 dir/c.o is ignored
102 90 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
103 91 dir/missing.o is ignored
104 92 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
105 93 $ cd dir
106 94 $ hg debugignore c.o missing.o
107 95 c.o is ignored
108 96 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
109 97 missing.o is ignored
110 98 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
111 99
112 100 For icasefs, inexact matches also work, except for missing files
113 101
114 102 #if icasefs
115 103 $ hg debugignore c.O missing.O
116 104 c.o is ignored
117 105 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
118 106 missing.O is not ignored
119 107 #endif
120 108
121 109 $ cd ..
122 110
123 111 $ echo ".*\.o" > .hgignore
124 112 $ hg status
125 113 A dir/b.o
126 114 ? .hgignore
127 115 ? a.c
128 116 ? syntax
129 117
130 118 Ensure that comments work:
131 119
132 120 $ touch 'foo#bar' 'quux#' 'quu0#'
133 121 #if no-windows
134 122 $ touch 'baz\' 'baz\wat' 'ba0\#wat' 'ba1\\' 'ba1\\wat' 'quu0\'
135 123 #endif
136 124
137 125 $ cat <<'EOF' >> .hgignore
138 126 > # full-line comment
139 127 > # whitespace-only comment line
140 128 > syntax# pattern, no whitespace, then comment
141 129 > a.c # pattern, then whitespace, then comment
142 130 > baz\\# # (escaped) backslash, then comment
143 131 > ba0\\\#w # (escaped) backslash, escaped comment character, then comment
144 132 > ba1\\\\# # (escaped) backslashes, then comment
145 133 > foo\#b # escaped comment character
146 134 > quux\## escaped comment character at end of name
147 135 > EOF
148 136 $ hg status
149 137 A dir/b.o
150 138 ? .hgignore
151 139 ? quu0#
152 140 ? quu0\ (no-windows !)
153 141
154 142 $ cat <<'EOF' > .hgignore
155 143 > .*\.o
156 144 > syntax: glob
157 145 > syntax# pattern, no whitespace, then comment
158 146 > a.c # pattern, then whitespace, then comment
159 147 > baz\\#* # (escaped) backslash, then comment
160 148 > ba0\\\#w* # (escaped) backslash, escaped comment character, then comment
161 149 > ba1\\\\#* # (escaped) backslashes, then comment
162 150 > foo\#b* # escaped comment character
163 151 > quux\## escaped comment character at end of name
164 152 > quu0[\#]# escaped comment character inside [...]
165 153 > EOF
166 154 $ hg status
167 155 A dir/b.o
168 156 ? .hgignore
169 157 ? ba1\\wat (no-windows !)
170 158 ? baz\wat (no-windows !)
171 159 ? quu0\ (no-windows !)
172 160
173 161 $ rm 'foo#bar' 'quux#' 'quu0#'
174 162 #if no-windows
175 163 $ rm 'baz\' 'baz\wat' 'ba0\#wat' 'ba1\\' 'ba1\\wat' 'quu0\'
176 164 #endif
177 165
178 166 Check that '^\.' does not ignore the root directory:
179 167
180 168 $ echo "^\." > .hgignore
181 169 $ hg status
182 170 A dir/b.o
183 171 ? a.c
184 172 ? a.o
185 173 ? dir/c.o
186 174 ? syntax
187 175
188 176 Test that patterns from ui.ignore options are read:
189 177
190 178 $ echo > .hgignore
191 179 $ cat >> $HGRCPATH << EOF
192 180 > [ui]
193 181 > ignore.other = $TESTTMP/ignorerepo/.hg/testhgignore
194 182 > EOF
195 183 $ echo "glob:**.o" > .hg/testhgignore
196 184 $ hg status
197 185 A dir/b.o
198 186 ? .hgignore
199 187 ? a.c
200 188 ? syntax
201 189
202 190 empty out testhgignore
203 191 $ echo > .hg/testhgignore
204 192
205 193 Test relative ignore path (issue4473):
206 194
207 195 $ cat >> $HGRCPATH << EOF
208 196 > [ui]
209 197 > ignore.relative = .hg/testhgignorerel
210 198 > EOF
211 199 $ echo "glob:*.o" > .hg/testhgignorerel
212 200 $ cd dir
213 201 $ hg status
214 202 A dir/b.o
215 203 ? .hgignore
216 204 ? a.c
217 205 ? syntax
218 206 $ hg debugignore
219 207 <includematcher includes='.*\\.o(?:/|$)'>
220 208
221 209 $ cd ..
222 210 $ echo > .hg/testhgignorerel
223 211 $ echo "syntax: glob" > .hgignore
224 212 $ echo "re:.*\.o" >> .hgignore
225 213 $ hg status
226 214 A dir/b.o
227 215 ? .hgignore
228 216 ? a.c
229 217 ? syntax
230 218
231 219 $ echo "syntax: invalid" > .hgignore
232 220 $ hg status
233 221 $TESTTMP/ignorerepo/.hgignore: ignoring invalid syntax 'invalid'
234 222 A dir/b.o
235 223 ? .hgignore
236 224 ? a.c
237 225 ? a.o
238 226 ? dir/c.o
239 227 ? syntax
240 228
241 229 $ echo "syntax: glob" > .hgignore
242 230 $ echo "*.o" >> .hgignore
243 231 $ hg status
244 232 A dir/b.o
245 233 ? .hgignore
246 234 ? a.c
247 235 ? syntax
248 236
249 237 $ echo "relglob:syntax*" > .hgignore
250 238 $ hg status
251 239 A dir/b.o
252 240 ? .hgignore
253 241 ? a.c
254 242 ? a.o
255 243 ? dir/c.o
256 244
257 245 $ echo "relglob:*" > .hgignore
258 246 $ hg status
259 247 A dir/b.o
260 248
261 249 $ cd dir
262 250 $ hg status .
263 251 A b.o
264 252
265 253 $ hg debugignore
266 254 <includematcher includes='.*(?:/|$)'>
267 255
268 256 $ hg debugignore b.o
269 257 b.o is ignored
270 258 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: '*') (glob)
271 259
272 260 $ cd ..
273 261
274 262 Check patterns that match only the directory
275 263
276 264 "(fsmonitor !)" below assumes that fsmonitor is enabled with
277 265 "walk_on_invalidate = false" (default), which doesn't involve
278 266 re-walking whole repository at detection of .hgignore change.
279 267
280 268 $ echo "^dir\$" > .hgignore
281 269 $ hg status
282 270 A dir/b.o
283 271 ? .hgignore
284 272 ? a.c
285 273 ? a.o
286 274 ? dir/c.o (fsmonitor !)
287 275 ? syntax
288 276
289 277 Check recursive glob pattern matches no directories (dir/**/c.o matches dir/c.o)
290 278
291 279 $ echo "syntax: glob" > .hgignore
292 280 $ echo "dir/**/c.o" >> .hgignore
293 281 $ touch dir/c.o
294 282 $ mkdir dir/subdir
295 283 $ touch dir/subdir/c.o
296 284 $ hg status
297 285 A dir/b.o
298 286 ? .hgignore
299 287 ? a.c
300 288 ? a.o
301 289 ? syntax
302 290 $ hg debugignore a.c
303 291 a.c is not ignored
304 292 $ hg debugignore dir/c.o
305 293 dir/c.o is ignored
306 294 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 2: 'dir/**/c.o') (glob)
307 295
308 296 Check rooted globs
309 297
310 298 $ hg purge --all --config extensions.purge=
311 299 $ echo "syntax: rootglob" > .hgignore
312 300 $ echo "a/*.ext" >> .hgignore
313 301 $ for p in a b/a aa; do mkdir -p $p; touch $p/b.ext; done
314 302 $ hg status -A 'set:**.ext'
315 303 ? aa/b.ext
316 304 ? b/a/b.ext
317 305 I a/b.ext
318 306
319 307 Check using 'include:' in ignore file
320 308
321 309 $ hg purge --all --config extensions.purge=
322 310 $ touch foo.included
323 311
324 312 $ echo ".*.included" > otherignore
325 313 $ hg status -I "include:otherignore"
326 314 ? foo.included
327 315
328 316 $ echo "include:otherignore" >> .hgignore
329 317 $ hg status
330 318 A dir/b.o
331 319 ? .hgignore
332 320 ? otherignore
333 321
334 322 Check recursive uses of 'include:'
335 323
336 324 $ echo "include:nested/ignore" >> otherignore
337 325 $ mkdir nested nested/more
338 326 $ echo "glob:*ignore" > nested/ignore
339 327 $ echo "rootglob:a" >> nested/ignore
340 328 $ touch a nested/a nested/more/a
341 329 $ hg status
342 330 A dir/b.o
343 331 ? nested/a
344 332 ? nested/more/a
345 333 $ rm a nested/a nested/more/a
346 334
347 335 $ cp otherignore goodignore
348 336 $ echo "include:badignore" >> otherignore
349 337 $ hg status
350 338 skipping unreadable pattern file 'badignore': $ENOENT$
351 339 A dir/b.o
352 340
353 341 $ mv goodignore otherignore
354 342
355 343 Check using 'include:' while in a non-root directory
356 344
357 345 $ cd ..
358 346 $ hg -R ignorerepo status
359 347 A dir/b.o
360 348 $ cd ignorerepo
361 349
362 350 Check including subincludes
363 351
364 352 $ hg revert -q --all
365 353 $ hg purge --all --config extensions.purge=
366 354 $ echo ".hgignore" > .hgignore
367 355 $ mkdir dir1 dir2
368 356 $ touch dir1/file1 dir1/file2 dir2/file1 dir2/file2
369 357 $ echo "subinclude:dir2/.hgignore" >> .hgignore
370 358 $ echo "glob:file*2" > dir2/.hgignore
371 359 $ hg status
372 360 ? dir1/file1
373 361 ? dir1/file2
374 362 ? dir2/file1
375 363
376 364 Check including subincludes with other patterns
377 365
378 366 $ echo "subinclude:dir1/.hgignore" >> .hgignore
379 367
380 368 $ mkdir dir1/subdir
381 369 $ touch dir1/subdir/file1
382 370 $ echo "rootglob:f?le1" > dir1/.hgignore
383 371 $ hg status
384 372 ? dir1/file2
385 373 ? dir1/subdir/file1
386 374 ? dir2/file1
387 375 $ rm dir1/subdir/file1
388 376
389 377 $ echo "regexp:f.le1" > dir1/.hgignore
390 378 $ hg status
391 379 ? dir1/file2
392 380 ? dir2/file1
393 381
394 382 Check multiple levels of sub-ignores
395 383
396 384 $ touch dir1/subdir/subfile1 dir1/subdir/subfile3 dir1/subdir/subfile4
397 385 $ echo "subinclude:subdir/.hgignore" >> dir1/.hgignore
398 386 $ echo "glob:subfil*3" >> dir1/subdir/.hgignore
399 387
400 388 $ hg status
401 389 ? dir1/file2
402 390 ? dir1/subdir/subfile4
403 391 ? dir2/file1
404 392
405 393 Check include subignore at the same level
406 394
407 395 $ mv dir1/subdir/.hgignore dir1/.hgignoretwo
408 396 $ echo "regexp:f.le1" > dir1/.hgignore
409 397 $ echo "subinclude:.hgignoretwo" >> dir1/.hgignore
410 398 $ echo "glob:file*2" > dir1/.hgignoretwo
411 399
412 400 $ hg status | grep file2
413 401 [1]
414 402 $ hg debugignore dir1/file2
415 403 dir1/file2 is ignored
416 404 (ignore rule in dir2/.hgignore, line 1: 'file*2')
417 405
418 406 #if windows
419 407
420 408 Windows paths are accepted on input
421 409
422 410 $ rm dir1/.hgignore
423 411 $ echo "dir1/file*" >> .hgignore
424 412 $ hg debugignore "dir1\file2"
425 413 dir1/file2 is ignored
426 414 (ignore rule in $TESTTMP\ignorerepo\.hgignore, line 4: 'dir1/file*')
427 415 $ hg up -qC .
428 416
429 417 #endif
430 418
431 419 #if dirstate-v2 rust
432 420
433 421 Check the hash of ignore patterns written in the dirstate
434 422 This is an optimization that is only relevant when using the Rust extensions
435 423
436 424 $ hg status > /dev/null
437 425 $ cat .hg/testhgignore .hg/testhgignorerel .hgignore dir2/.hgignore dir1/.hgignore dir1/.hgignoretwo | $TESTDIR/f --sha1
438 426 sha1=6e315b60f15fb5dfa02be00f3e2c8f923051f5ff
439 427 $ hg debugstate --docket | grep ignore
440 428 ignore pattern hash: 6e315b60f15fb5dfa02be00f3e2c8f923051f5ff
441 429
442 430 $ echo rel > .hg/testhgignorerel
443 431 $ hg status > /dev/null
444 432 $ cat .hg/testhgignore .hg/testhgignorerel .hgignore dir2/.hgignore dir1/.hgignore dir1/.hgignoretwo | $TESTDIR/f --sha1
445 433 sha1=dea19cc7119213f24b6b582a4bae7b0cb063e34e
446 434 $ hg debugstate --docket | grep ignore
447 435 ignore pattern hash: dea19cc7119213f24b6b582a4bae7b0cb063e34e
448 436
449 437 #endif
General Comments 0
You need to be logged in to leave comments. Login now