##// END OF EJS Templates
match: drop unnecessary wrapping of regex in group...
Martin von Zweigbergk -
r40818:3984409e default
parent child Browse files
Show More
@@ -1,1412 +1,1411 b''
1 # match.py - filename matching
1 # match.py - filename matching
2 #
2 #
3 # Copyright 2008, 2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2008, 2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import, print_function
8 from __future__ import absolute_import, print_function
9
9
10 import copy
10 import copy
11 import itertools
11 import itertools
12 import os
12 import os
13 import re
13 import re
14
14
15 from .i18n import _
15 from .i18n import _
16 from . import (
16 from . import (
17 encoding,
17 encoding,
18 error,
18 error,
19 pathutil,
19 pathutil,
20 pycompat,
20 pycompat,
21 util,
21 util,
22 )
22 )
23 from .utils import (
23 from .utils import (
24 stringutil,
24 stringutil,
25 )
25 )
26
26
27 allpatternkinds = ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
27 allpatternkinds = ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
28 'listfile', 'listfile0', 'set', 'include', 'subinclude',
28 'listfile', 'listfile0', 'set', 'include', 'subinclude',
29 'rootfilesin')
29 'rootfilesin')
30 cwdrelativepatternkinds = ('relpath', 'glob')
30 cwdrelativepatternkinds = ('relpath', 'glob')
31
31
32 propertycache = util.propertycache
32 propertycache = util.propertycache
33
33
34 def _rematcher(regex):
34 def _rematcher(regex):
35 '''compile the regexp with the best available regexp engine and return a
35 '''compile the regexp with the best available regexp engine and return a
36 matcher function'''
36 matcher function'''
37 m = util.re.compile(regex)
37 m = util.re.compile(regex)
38 try:
38 try:
39 # slightly faster, provided by facebook's re2 bindings
39 # slightly faster, provided by facebook's re2 bindings
40 return m.test_match
40 return m.test_match
41 except AttributeError:
41 except AttributeError:
42 return m.match
42 return m.match
43
43
44 def _expandsets(root, cwd, kindpats, ctx, listsubrepos, badfn):
44 def _expandsets(root, cwd, kindpats, ctx, listsubrepos, badfn):
45 '''Returns the kindpats list with the 'set' patterns expanded to matchers'''
45 '''Returns the kindpats list with the 'set' patterns expanded to matchers'''
46 matchers = []
46 matchers = []
47 other = []
47 other = []
48
48
49 for kind, pat, source in kindpats:
49 for kind, pat, source in kindpats:
50 if kind == 'set':
50 if kind == 'set':
51 if not ctx:
51 if not ctx:
52 raise error.ProgrammingError("fileset expression with no "
52 raise error.ProgrammingError("fileset expression with no "
53 "context")
53 "context")
54 matchers.append(ctx.matchfileset(pat, badfn=badfn))
54 matchers.append(ctx.matchfileset(pat, badfn=badfn))
55
55
56 if listsubrepos:
56 if listsubrepos:
57 for subpath in ctx.substate:
57 for subpath in ctx.substate:
58 sm = ctx.sub(subpath).matchfileset(pat, badfn=badfn)
58 sm = ctx.sub(subpath).matchfileset(pat, badfn=badfn)
59 pm = prefixdirmatcher(root, cwd, subpath, sm, badfn=badfn)
59 pm = prefixdirmatcher(root, cwd, subpath, sm, badfn=badfn)
60 matchers.append(pm)
60 matchers.append(pm)
61
61
62 continue
62 continue
63 other.append((kind, pat, source))
63 other.append((kind, pat, source))
64 return matchers, other
64 return matchers, other
65
65
66 def _expandsubinclude(kindpats, root):
66 def _expandsubinclude(kindpats, root):
67 '''Returns the list of subinclude matcher args and the kindpats without the
67 '''Returns the list of subinclude matcher args and the kindpats without the
68 subincludes in it.'''
68 subincludes in it.'''
69 relmatchers = []
69 relmatchers = []
70 other = []
70 other = []
71
71
72 for kind, pat, source in kindpats:
72 for kind, pat, source in kindpats:
73 if kind == 'subinclude':
73 if kind == 'subinclude':
74 sourceroot = pathutil.dirname(util.normpath(source))
74 sourceroot = pathutil.dirname(util.normpath(source))
75 pat = util.pconvert(pat)
75 pat = util.pconvert(pat)
76 path = pathutil.join(sourceroot, pat)
76 path = pathutil.join(sourceroot, pat)
77
77
78 newroot = pathutil.dirname(path)
78 newroot = pathutil.dirname(path)
79 matcherargs = (newroot, '', [], ['include:%s' % path])
79 matcherargs = (newroot, '', [], ['include:%s' % path])
80
80
81 prefix = pathutil.canonpath(root, root, newroot)
81 prefix = pathutil.canonpath(root, root, newroot)
82 if prefix:
82 if prefix:
83 prefix += '/'
83 prefix += '/'
84 relmatchers.append((prefix, matcherargs))
84 relmatchers.append((prefix, matcherargs))
85 else:
85 else:
86 other.append((kind, pat, source))
86 other.append((kind, pat, source))
87
87
88 return relmatchers, other
88 return relmatchers, other
89
89
90 def _kindpatsalwaysmatch(kindpats):
90 def _kindpatsalwaysmatch(kindpats):
91 """"Checks whether the kindspats match everything, as e.g.
91 """"Checks whether the kindspats match everything, as e.g.
92 'relpath:.' does.
92 'relpath:.' does.
93 """
93 """
94 for kind, pat, source in kindpats:
94 for kind, pat, source in kindpats:
95 if pat != '' or kind not in ['relpath', 'glob']:
95 if pat != '' or kind not in ['relpath', 'glob']:
96 return False
96 return False
97 return True
97 return True
98
98
99 def _buildkindpatsmatcher(matchercls, root, cwd, kindpats, ctx=None,
99 def _buildkindpatsmatcher(matchercls, root, cwd, kindpats, ctx=None,
100 listsubrepos=False, badfn=None):
100 listsubrepos=False, badfn=None):
101 matchers = []
101 matchers = []
102 fms, kindpats = _expandsets(root, cwd, kindpats, ctx=ctx,
102 fms, kindpats = _expandsets(root, cwd, kindpats, ctx=ctx,
103 listsubrepos=listsubrepos, badfn=badfn)
103 listsubrepos=listsubrepos, badfn=badfn)
104 if kindpats:
104 if kindpats:
105 m = matchercls(root, cwd, kindpats, listsubrepos=listsubrepos,
105 m = matchercls(root, cwd, kindpats, listsubrepos=listsubrepos,
106 badfn=badfn)
106 badfn=badfn)
107 matchers.append(m)
107 matchers.append(m)
108 if fms:
108 if fms:
109 matchers.extend(fms)
109 matchers.extend(fms)
110 if not matchers:
110 if not matchers:
111 return nevermatcher(root, cwd, badfn=badfn)
111 return nevermatcher(root, cwd, badfn=badfn)
112 if len(matchers) == 1:
112 if len(matchers) == 1:
113 return matchers[0]
113 return matchers[0]
114 return unionmatcher(matchers)
114 return unionmatcher(matchers)
115
115
116 def match(root, cwd, patterns=None, include=None, exclude=None, default='glob',
116 def match(root, cwd, patterns=None, include=None, exclude=None, default='glob',
117 exact=False, auditor=None, ctx=None, listsubrepos=False, warn=None,
117 exact=False, auditor=None, ctx=None, listsubrepos=False, warn=None,
118 badfn=None, icasefs=False):
118 badfn=None, icasefs=False):
119 """build an object to match a set of file patterns
119 """build an object to match a set of file patterns
120
120
121 arguments:
121 arguments:
122 root - the canonical root of the tree you're matching against
122 root - the canonical root of the tree you're matching against
123 cwd - the current working directory, if relevant
123 cwd - the current working directory, if relevant
124 patterns - patterns to find
124 patterns - patterns to find
125 include - patterns to include (unless they are excluded)
125 include - patterns to include (unless they are excluded)
126 exclude - patterns to exclude (even if they are included)
126 exclude - patterns to exclude (even if they are included)
127 default - if a pattern in patterns has no explicit type, assume this one
127 default - if a pattern in patterns has no explicit type, assume this one
128 exact - patterns are actually filenames (include/exclude still apply)
128 exact - patterns are actually filenames (include/exclude still apply)
129 warn - optional function used for printing warnings
129 warn - optional function used for printing warnings
130 badfn - optional bad() callback for this matcher instead of the default
130 badfn - optional bad() callback for this matcher instead of the default
131 icasefs - make a matcher for wdir on case insensitive filesystems, which
131 icasefs - make a matcher for wdir on case insensitive filesystems, which
132 normalizes the given patterns to the case in the filesystem
132 normalizes the given patterns to the case in the filesystem
133
133
134 a pattern is one of:
134 a pattern is one of:
135 'glob:<glob>' - a glob relative to cwd
135 'glob:<glob>' - a glob relative to cwd
136 're:<regexp>' - a regular expression
136 're:<regexp>' - a regular expression
137 'path:<path>' - a path relative to repository root, which is matched
137 'path:<path>' - a path relative to repository root, which is matched
138 recursively
138 recursively
139 'rootfilesin:<path>' - a path relative to repository root, which is
139 'rootfilesin:<path>' - a path relative to repository root, which is
140 matched non-recursively (will not match subdirectories)
140 matched non-recursively (will not match subdirectories)
141 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
141 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
142 'relpath:<path>' - a path relative to cwd
142 'relpath:<path>' - a path relative to cwd
143 'relre:<regexp>' - a regexp that needn't match the start of a name
143 'relre:<regexp>' - a regexp that needn't match the start of a name
144 'set:<fileset>' - a fileset expression
144 'set:<fileset>' - a fileset expression
145 'include:<path>' - a file of patterns to read and include
145 'include:<path>' - a file of patterns to read and include
146 'subinclude:<path>' - a file of patterns to match against files under
146 'subinclude:<path>' - a file of patterns to match against files under
147 the same directory
147 the same directory
148 '<something>' - a pattern of the specified default type
148 '<something>' - a pattern of the specified default type
149 """
149 """
150 normalize = _donormalize
150 normalize = _donormalize
151 if icasefs:
151 if icasefs:
152 if exact:
152 if exact:
153 raise error.ProgrammingError("a case-insensitive exact matcher "
153 raise error.ProgrammingError("a case-insensitive exact matcher "
154 "doesn't make sense")
154 "doesn't make sense")
155 dirstate = ctx.repo().dirstate
155 dirstate = ctx.repo().dirstate
156 dsnormalize = dirstate.normalize
156 dsnormalize = dirstate.normalize
157
157
158 def normalize(patterns, default, root, cwd, auditor, warn):
158 def normalize(patterns, default, root, cwd, auditor, warn):
159 kp = _donormalize(patterns, default, root, cwd, auditor, warn)
159 kp = _donormalize(patterns, default, root, cwd, auditor, warn)
160 kindpats = []
160 kindpats = []
161 for kind, pats, source in kp:
161 for kind, pats, source in kp:
162 if kind not in ('re', 'relre'): # regex can't be normalized
162 if kind not in ('re', 'relre'): # regex can't be normalized
163 p = pats
163 p = pats
164 pats = dsnormalize(pats)
164 pats = dsnormalize(pats)
165
165
166 # Preserve the original to handle a case only rename.
166 # Preserve the original to handle a case only rename.
167 if p != pats and p in dirstate:
167 if p != pats and p in dirstate:
168 kindpats.append((kind, p, source))
168 kindpats.append((kind, p, source))
169
169
170 kindpats.append((kind, pats, source))
170 kindpats.append((kind, pats, source))
171 return kindpats
171 return kindpats
172
172
173 if exact:
173 if exact:
174 m = exactmatcher(root, cwd, patterns, badfn)
174 m = exactmatcher(root, cwd, patterns, badfn)
175 elif patterns:
175 elif patterns:
176 kindpats = normalize(patterns, default, root, cwd, auditor, warn)
176 kindpats = normalize(patterns, default, root, cwd, auditor, warn)
177 if _kindpatsalwaysmatch(kindpats):
177 if _kindpatsalwaysmatch(kindpats):
178 m = alwaysmatcher(root, cwd, badfn, relativeuipath=True)
178 m = alwaysmatcher(root, cwd, badfn, relativeuipath=True)
179 else:
179 else:
180 m = _buildkindpatsmatcher(patternmatcher, root, cwd, kindpats,
180 m = _buildkindpatsmatcher(patternmatcher, root, cwd, kindpats,
181 ctx=ctx, listsubrepos=listsubrepos,
181 ctx=ctx, listsubrepos=listsubrepos,
182 badfn=badfn)
182 badfn=badfn)
183 else:
183 else:
184 # It's a little strange that no patterns means to match everything.
184 # It's a little strange that no patterns means to match everything.
185 # Consider changing this to match nothing (probably using nevermatcher).
185 # Consider changing this to match nothing (probably using nevermatcher).
186 m = alwaysmatcher(root, cwd, badfn)
186 m = alwaysmatcher(root, cwd, badfn)
187
187
188 if include:
188 if include:
189 kindpats = normalize(include, 'glob', root, cwd, auditor, warn)
189 kindpats = normalize(include, 'glob', root, cwd, auditor, warn)
190 im = _buildkindpatsmatcher(includematcher, root, cwd, kindpats, ctx=ctx,
190 im = _buildkindpatsmatcher(includematcher, root, cwd, kindpats, ctx=ctx,
191 listsubrepos=listsubrepos, badfn=None)
191 listsubrepos=listsubrepos, badfn=None)
192 m = intersectmatchers(m, im)
192 m = intersectmatchers(m, im)
193 if exclude:
193 if exclude:
194 kindpats = normalize(exclude, 'glob', root, cwd, auditor, warn)
194 kindpats = normalize(exclude, 'glob', root, cwd, auditor, warn)
195 em = _buildkindpatsmatcher(includematcher, root, cwd, kindpats, ctx=ctx,
195 em = _buildkindpatsmatcher(includematcher, root, cwd, kindpats, ctx=ctx,
196 listsubrepos=listsubrepos, badfn=None)
196 listsubrepos=listsubrepos, badfn=None)
197 m = differencematcher(m, em)
197 m = differencematcher(m, em)
198 return m
198 return m
199
199
200 def exact(root, cwd, files, badfn=None):
200 def exact(root, cwd, files, badfn=None):
201 return exactmatcher(root, cwd, files, badfn=badfn)
201 return exactmatcher(root, cwd, files, badfn=badfn)
202
202
203 def always(root, cwd):
203 def always(root, cwd):
204 return alwaysmatcher(root, cwd)
204 return alwaysmatcher(root, cwd)
205
205
206 def never(root, cwd):
206 def never(root, cwd):
207 return nevermatcher(root, cwd)
207 return nevermatcher(root, cwd)
208
208
209 def badmatch(match, badfn):
209 def badmatch(match, badfn):
210 """Make a copy of the given matcher, replacing its bad method with the given
210 """Make a copy of the given matcher, replacing its bad method with the given
211 one.
211 one.
212 """
212 """
213 m = copy.copy(match)
213 m = copy.copy(match)
214 m.bad = badfn
214 m.bad = badfn
215 return m
215 return m
216
216
217 def _donormalize(patterns, default, root, cwd, auditor, warn):
217 def _donormalize(patterns, default, root, cwd, auditor, warn):
218 '''Convert 'kind:pat' from the patterns list to tuples with kind and
218 '''Convert 'kind:pat' from the patterns list to tuples with kind and
219 normalized and rooted patterns and with listfiles expanded.'''
219 normalized and rooted patterns and with listfiles expanded.'''
220 kindpats = []
220 kindpats = []
221 for kind, pat in [_patsplit(p, default) for p in patterns]:
221 for kind, pat in [_patsplit(p, default) for p in patterns]:
222 if kind in cwdrelativepatternkinds:
222 if kind in cwdrelativepatternkinds:
223 pat = pathutil.canonpath(root, cwd, pat, auditor)
223 pat = pathutil.canonpath(root, cwd, pat, auditor)
224 elif kind in ('relglob', 'path', 'rootfilesin'):
224 elif kind in ('relglob', 'path', 'rootfilesin'):
225 pat = util.normpath(pat)
225 pat = util.normpath(pat)
226 elif kind in ('listfile', 'listfile0'):
226 elif kind in ('listfile', 'listfile0'):
227 try:
227 try:
228 files = util.readfile(pat)
228 files = util.readfile(pat)
229 if kind == 'listfile0':
229 if kind == 'listfile0':
230 files = files.split('\0')
230 files = files.split('\0')
231 else:
231 else:
232 files = files.splitlines()
232 files = files.splitlines()
233 files = [f for f in files if f]
233 files = [f for f in files if f]
234 except EnvironmentError:
234 except EnvironmentError:
235 raise error.Abort(_("unable to read file list (%s)") % pat)
235 raise error.Abort(_("unable to read file list (%s)") % pat)
236 for k, p, source in _donormalize(files, default, root, cwd,
236 for k, p, source in _donormalize(files, default, root, cwd,
237 auditor, warn):
237 auditor, warn):
238 kindpats.append((k, p, pat))
238 kindpats.append((k, p, pat))
239 continue
239 continue
240 elif kind == 'include':
240 elif kind == 'include':
241 try:
241 try:
242 fullpath = os.path.join(root, util.localpath(pat))
242 fullpath = os.path.join(root, util.localpath(pat))
243 includepats = readpatternfile(fullpath, warn)
243 includepats = readpatternfile(fullpath, warn)
244 for k, p, source in _donormalize(includepats, default,
244 for k, p, source in _donormalize(includepats, default,
245 root, cwd, auditor, warn):
245 root, cwd, auditor, warn):
246 kindpats.append((k, p, source or pat))
246 kindpats.append((k, p, source or pat))
247 except error.Abort as inst:
247 except error.Abort as inst:
248 raise error.Abort('%s: %s' % (pat, inst[0]))
248 raise error.Abort('%s: %s' % (pat, inst[0]))
249 except IOError as inst:
249 except IOError as inst:
250 if warn:
250 if warn:
251 warn(_("skipping unreadable pattern file '%s': %s\n") %
251 warn(_("skipping unreadable pattern file '%s': %s\n") %
252 (pat, stringutil.forcebytestr(inst.strerror)))
252 (pat, stringutil.forcebytestr(inst.strerror)))
253 continue
253 continue
254 # else: re or relre - which cannot be normalized
254 # else: re or relre - which cannot be normalized
255 kindpats.append((kind, pat, ''))
255 kindpats.append((kind, pat, ''))
256 return kindpats
256 return kindpats
257
257
258 class basematcher(object):
258 class basematcher(object):
259
259
260 def __init__(self, root, cwd, badfn=None, relativeuipath=True):
260 def __init__(self, root, cwd, badfn=None, relativeuipath=True):
261 self._root = root
261 self._root = root
262 self._cwd = cwd
262 self._cwd = cwd
263 if badfn is not None:
263 if badfn is not None:
264 self.bad = badfn
264 self.bad = badfn
265 self._relativeuipath = relativeuipath
265 self._relativeuipath = relativeuipath
266
266
267 def __call__(self, fn):
267 def __call__(self, fn):
268 return self.matchfn(fn)
268 return self.matchfn(fn)
269 def __iter__(self):
269 def __iter__(self):
270 for f in self._files:
270 for f in self._files:
271 yield f
271 yield f
272 # Callbacks related to how the matcher is used by dirstate.walk.
272 # Callbacks related to how the matcher is used by dirstate.walk.
273 # Subscribers to these events must monkeypatch the matcher object.
273 # Subscribers to these events must monkeypatch the matcher object.
274 def bad(self, f, msg):
274 def bad(self, f, msg):
275 '''Callback from dirstate.walk for each explicit file that can't be
275 '''Callback from dirstate.walk for each explicit file that can't be
276 found/accessed, with an error message.'''
276 found/accessed, with an error message.'''
277
277
278 # If an explicitdir is set, it will be called when an explicitly listed
278 # If an explicitdir is set, it will be called when an explicitly listed
279 # directory is visited.
279 # directory is visited.
280 explicitdir = None
280 explicitdir = None
281
281
282 # If an traversedir is set, it will be called when a directory discovered
282 # If an traversedir is set, it will be called when a directory discovered
283 # by recursive traversal is visited.
283 # by recursive traversal is visited.
284 traversedir = None
284 traversedir = None
285
285
286 def abs(self, f):
286 def abs(self, f):
287 '''Convert a repo path back to path that is relative to the root of the
287 '''Convert a repo path back to path that is relative to the root of the
288 matcher.'''
288 matcher.'''
289 return f
289 return f
290
290
291 def rel(self, f):
291 def rel(self, f):
292 '''Convert repo path back to path that is relative to cwd of matcher.'''
292 '''Convert repo path back to path that is relative to cwd of matcher.'''
293 return util.pathto(self._root, self._cwd, f)
293 return util.pathto(self._root, self._cwd, f)
294
294
295 def uipath(self, f):
295 def uipath(self, f):
296 '''Convert repo path to a display path. If patterns or -I/-X were used
296 '''Convert repo path to a display path. If patterns or -I/-X were used
297 to create this matcher, the display path will be relative to cwd.
297 to create this matcher, the display path will be relative to cwd.
298 Otherwise it is relative to the root of the repo.'''
298 Otherwise it is relative to the root of the repo.'''
299 return (self._relativeuipath and self.rel(f)) or self.abs(f)
299 return (self._relativeuipath and self.rel(f)) or self.abs(f)
300
300
301 @propertycache
301 @propertycache
302 def _files(self):
302 def _files(self):
303 return []
303 return []
304
304
305 def files(self):
305 def files(self):
306 '''Explicitly listed files or patterns or roots:
306 '''Explicitly listed files or patterns or roots:
307 if no patterns or .always(): empty list,
307 if no patterns or .always(): empty list,
308 if exact: list exact files,
308 if exact: list exact files,
309 if not .anypats(): list all files and dirs,
309 if not .anypats(): list all files and dirs,
310 else: optimal roots'''
310 else: optimal roots'''
311 return self._files
311 return self._files
312
312
313 @propertycache
313 @propertycache
314 def _fileset(self):
314 def _fileset(self):
315 return set(self._files)
315 return set(self._files)
316
316
317 def exact(self, f):
317 def exact(self, f):
318 '''Returns True if f is in .files().'''
318 '''Returns True if f is in .files().'''
319 return f in self._fileset
319 return f in self._fileset
320
320
321 def matchfn(self, f):
321 def matchfn(self, f):
322 return False
322 return False
323
323
324 def visitdir(self, dir):
324 def visitdir(self, dir):
325 '''Decides whether a directory should be visited based on whether it
325 '''Decides whether a directory should be visited based on whether it
326 has potential matches in it or one of its subdirectories. This is
326 has potential matches in it or one of its subdirectories. This is
327 based on the match's primary, included, and excluded patterns.
327 based on the match's primary, included, and excluded patterns.
328
328
329 Returns the string 'all' if the given directory and all subdirectories
329 Returns the string 'all' if the given directory and all subdirectories
330 should be visited. Otherwise returns True or False indicating whether
330 should be visited. Otherwise returns True or False indicating whether
331 the given directory should be visited.
331 the given directory should be visited.
332 '''
332 '''
333 return True
333 return True
334
334
335 def visitchildrenset(self, dir):
335 def visitchildrenset(self, dir):
336 '''Decides whether a directory should be visited based on whether it
336 '''Decides whether a directory should be visited based on whether it
337 has potential matches in it or one of its subdirectories, and
337 has potential matches in it or one of its subdirectories, and
338 potentially lists which subdirectories of that directory should be
338 potentially lists which subdirectories of that directory should be
339 visited. This is based on the match's primary, included, and excluded
339 visited. This is based on the match's primary, included, and excluded
340 patterns.
340 patterns.
341
341
342 This function is very similar to 'visitdir', and the following mapping
342 This function is very similar to 'visitdir', and the following mapping
343 can be applied:
343 can be applied:
344
344
345 visitdir | visitchildrenlist
345 visitdir | visitchildrenlist
346 ----------+-------------------
346 ----------+-------------------
347 False | set()
347 False | set()
348 'all' | 'all'
348 'all' | 'all'
349 True | 'this' OR non-empty set of subdirs -or files- to visit
349 True | 'this' OR non-empty set of subdirs -or files- to visit
350
350
351 Example:
351 Example:
352 Assume matchers ['path:foo/bar', 'rootfilesin:qux'], we would return
352 Assume matchers ['path:foo/bar', 'rootfilesin:qux'], we would return
353 the following values (assuming the implementation of visitchildrenset
353 the following values (assuming the implementation of visitchildrenset
354 is capable of recognizing this; some implementations are not).
354 is capable of recognizing this; some implementations are not).
355
355
356 '.' -> {'foo', 'qux'}
356 '.' -> {'foo', 'qux'}
357 'baz' -> set()
357 'baz' -> set()
358 'foo' -> {'bar'}
358 'foo' -> {'bar'}
359 # Ideally this would be 'all', but since the prefix nature of matchers
359 # Ideally this would be 'all', but since the prefix nature of matchers
360 # is applied to the entire matcher, we have to downgrade this to
360 # is applied to the entire matcher, we have to downgrade this to
361 # 'this' due to the non-prefix 'rootfilesin'-kind matcher being mixed
361 # 'this' due to the non-prefix 'rootfilesin'-kind matcher being mixed
362 # in.
362 # in.
363 'foo/bar' -> 'this'
363 'foo/bar' -> 'this'
364 'qux' -> 'this'
364 'qux' -> 'this'
365
365
366 Important:
366 Important:
367 Most matchers do not know if they're representing files or
367 Most matchers do not know if they're representing files or
368 directories. They see ['path:dir/f'] and don't know whether 'f' is a
368 directories. They see ['path:dir/f'] and don't know whether 'f' is a
369 file or a directory, so visitchildrenset('dir') for most matchers will
369 file or a directory, so visitchildrenset('dir') for most matchers will
370 return {'f'}, but if the matcher knows it's a file (like exactmatcher
370 return {'f'}, but if the matcher knows it's a file (like exactmatcher
371 does), it may return 'this'. Do not rely on the return being a set
371 does), it may return 'this'. Do not rely on the return being a set
372 indicating that there are no files in this dir to investigate (or
372 indicating that there are no files in this dir to investigate (or
373 equivalently that if there are files to investigate in 'dir' that it
373 equivalently that if there are files to investigate in 'dir' that it
374 will always return 'this').
374 will always return 'this').
375 '''
375 '''
376 return 'this'
376 return 'this'
377
377
378 def always(self):
378 def always(self):
379 '''Matcher will match everything and .files() will be empty --
379 '''Matcher will match everything and .files() will be empty --
380 optimization might be possible.'''
380 optimization might be possible.'''
381 return False
381 return False
382
382
383 def isexact(self):
383 def isexact(self):
384 '''Matcher will match exactly the list of files in .files() --
384 '''Matcher will match exactly the list of files in .files() --
385 optimization might be possible.'''
385 optimization might be possible.'''
386 return False
386 return False
387
387
388 def prefix(self):
388 def prefix(self):
389 '''Matcher will match the paths in .files() recursively --
389 '''Matcher will match the paths in .files() recursively --
390 optimization might be possible.'''
390 optimization might be possible.'''
391 return False
391 return False
392
392
393 def anypats(self):
393 def anypats(self):
394 '''None of .always(), .isexact(), and .prefix() is true --
394 '''None of .always(), .isexact(), and .prefix() is true --
395 optimizations will be difficult.'''
395 optimizations will be difficult.'''
396 return not self.always() and not self.isexact() and not self.prefix()
396 return not self.always() and not self.isexact() and not self.prefix()
397
397
398 class alwaysmatcher(basematcher):
398 class alwaysmatcher(basematcher):
399 '''Matches everything.'''
399 '''Matches everything.'''
400
400
401 def __init__(self, root, cwd, badfn=None, relativeuipath=False):
401 def __init__(self, root, cwd, badfn=None, relativeuipath=False):
402 super(alwaysmatcher, self).__init__(root, cwd, badfn,
402 super(alwaysmatcher, self).__init__(root, cwd, badfn,
403 relativeuipath=relativeuipath)
403 relativeuipath=relativeuipath)
404
404
405 def always(self):
405 def always(self):
406 return True
406 return True
407
407
408 def matchfn(self, f):
408 def matchfn(self, f):
409 return True
409 return True
410
410
411 def visitdir(self, dir):
411 def visitdir(self, dir):
412 return 'all'
412 return 'all'
413
413
414 def visitchildrenset(self, dir):
414 def visitchildrenset(self, dir):
415 return 'all'
415 return 'all'
416
416
417 def __repr__(self):
417 def __repr__(self):
418 return r'<alwaysmatcher>'
418 return r'<alwaysmatcher>'
419
419
420 class nevermatcher(basematcher):
420 class nevermatcher(basematcher):
421 '''Matches nothing.'''
421 '''Matches nothing.'''
422
422
423 def __init__(self, root, cwd, badfn=None):
423 def __init__(self, root, cwd, badfn=None):
424 super(nevermatcher, self).__init__(root, cwd, badfn)
424 super(nevermatcher, self).__init__(root, cwd, badfn)
425
425
426 # It's a little weird to say that the nevermatcher is an exact matcher
426 # It's a little weird to say that the nevermatcher is an exact matcher
427 # or a prefix matcher, but it seems to make sense to let callers take
427 # or a prefix matcher, but it seems to make sense to let callers take
428 # fast paths based on either. There will be no exact matches, nor any
428 # fast paths based on either. There will be no exact matches, nor any
429 # prefixes (files() returns []), so fast paths iterating over them should
429 # prefixes (files() returns []), so fast paths iterating over them should
430 # be efficient (and correct).
430 # be efficient (and correct).
431 def isexact(self):
431 def isexact(self):
432 return True
432 return True
433
433
434 def prefix(self):
434 def prefix(self):
435 return True
435 return True
436
436
437 def visitdir(self, dir):
437 def visitdir(self, dir):
438 return False
438 return False
439
439
440 def visitchildrenset(self, dir):
440 def visitchildrenset(self, dir):
441 return set()
441 return set()
442
442
443 def __repr__(self):
443 def __repr__(self):
444 return r'<nevermatcher>'
444 return r'<nevermatcher>'
445
445
446 class predicatematcher(basematcher):
446 class predicatematcher(basematcher):
447 """A matcher adapter for a simple boolean function"""
447 """A matcher adapter for a simple boolean function"""
448
448
449 def __init__(self, root, cwd, predfn, predrepr=None, badfn=None):
449 def __init__(self, root, cwd, predfn, predrepr=None, badfn=None):
450 super(predicatematcher, self).__init__(root, cwd, badfn)
450 super(predicatematcher, self).__init__(root, cwd, badfn)
451 self.matchfn = predfn
451 self.matchfn = predfn
452 self._predrepr = predrepr
452 self._predrepr = predrepr
453
453
454 @encoding.strmethod
454 @encoding.strmethod
455 def __repr__(self):
455 def __repr__(self):
456 s = (stringutil.buildrepr(self._predrepr)
456 s = (stringutil.buildrepr(self._predrepr)
457 or pycompat.byterepr(self.matchfn))
457 or pycompat.byterepr(self.matchfn))
458 return '<predicatenmatcher pred=%s>' % s
458 return '<predicatenmatcher pred=%s>' % s
459
459
460 class patternmatcher(basematcher):
460 class patternmatcher(basematcher):
461
461
462 def __init__(self, root, cwd, kindpats, listsubrepos=False, badfn=None):
462 def __init__(self, root, cwd, kindpats, listsubrepos=False, badfn=None):
463 super(patternmatcher, self).__init__(root, cwd, badfn)
463 super(patternmatcher, self).__init__(root, cwd, badfn)
464
464
465 self._files = _explicitfiles(kindpats)
465 self._files = _explicitfiles(kindpats)
466 self._prefix = _prefix(kindpats)
466 self._prefix = _prefix(kindpats)
467 self._pats, self.matchfn = _buildmatch(kindpats, '$', listsubrepos,
467 self._pats, self.matchfn = _buildmatch(kindpats, '$', listsubrepos,
468 root)
468 root)
469
469
470 @propertycache
470 @propertycache
471 def _dirs(self):
471 def _dirs(self):
472 return set(util.dirs(self._fileset)) | {'.'}
472 return set(util.dirs(self._fileset)) | {'.'}
473
473
474 def visitdir(self, dir):
474 def visitdir(self, dir):
475 if self._prefix and dir in self._fileset:
475 if self._prefix and dir in self._fileset:
476 return 'all'
476 return 'all'
477 return ('.' in self._fileset or
477 return ('.' in self._fileset or
478 dir in self._fileset or
478 dir in self._fileset or
479 dir in self._dirs or
479 dir in self._dirs or
480 any(parentdir in self._fileset
480 any(parentdir in self._fileset
481 for parentdir in util.finddirs(dir)))
481 for parentdir in util.finddirs(dir)))
482
482
483 def visitchildrenset(self, dir):
483 def visitchildrenset(self, dir):
484 ret = self.visitdir(dir)
484 ret = self.visitdir(dir)
485 if ret is True:
485 if ret is True:
486 return 'this'
486 return 'this'
487 elif not ret:
487 elif not ret:
488 return set()
488 return set()
489 assert ret == 'all'
489 assert ret == 'all'
490 return 'all'
490 return 'all'
491
491
492 def prefix(self):
492 def prefix(self):
493 return self._prefix
493 return self._prefix
494
494
495 @encoding.strmethod
495 @encoding.strmethod
496 def __repr__(self):
496 def __repr__(self):
497 return ('<patternmatcher patterns=%r>' % pycompat.bytestr(self._pats))
497 return ('<patternmatcher patterns=%r>' % pycompat.bytestr(self._pats))
498
498
499 # This is basically a reimplementation of util.dirs that stores the children
499 # This is basically a reimplementation of util.dirs that stores the children
500 # instead of just a count of them, plus a small optional optimization to avoid
500 # instead of just a count of them, plus a small optional optimization to avoid
501 # some directories we don't need.
501 # some directories we don't need.
502 class _dirchildren(object):
502 class _dirchildren(object):
503 def __init__(self, paths, onlyinclude=None):
503 def __init__(self, paths, onlyinclude=None):
504 self._dirs = {}
504 self._dirs = {}
505 self._onlyinclude = onlyinclude or []
505 self._onlyinclude = onlyinclude or []
506 addpath = self.addpath
506 addpath = self.addpath
507 for f in paths:
507 for f in paths:
508 addpath(f)
508 addpath(f)
509
509
510 def addpath(self, path):
510 def addpath(self, path):
511 if path == '.':
511 if path == '.':
512 return
512 return
513 dirs = self._dirs
513 dirs = self._dirs
514 findsplitdirs = _dirchildren._findsplitdirs
514 findsplitdirs = _dirchildren._findsplitdirs
515 for d, b in findsplitdirs(path):
515 for d, b in findsplitdirs(path):
516 if d not in self._onlyinclude:
516 if d not in self._onlyinclude:
517 continue
517 continue
518 dirs.setdefault(d, set()).add(b)
518 dirs.setdefault(d, set()).add(b)
519
519
520 @staticmethod
520 @staticmethod
521 def _findsplitdirs(path):
521 def _findsplitdirs(path):
522 # yields (dirname, basename) tuples, walking back to the root. This is
522 # yields (dirname, basename) tuples, walking back to the root. This is
523 # very similar to util.finddirs, except:
523 # very similar to util.finddirs, except:
524 # - produces a (dirname, basename) tuple, not just 'dirname'
524 # - produces a (dirname, basename) tuple, not just 'dirname'
525 # - includes root dir
525 # - includes root dir
526 # Unlike manifest._splittopdir, this does not suffix `dirname` with a
526 # Unlike manifest._splittopdir, this does not suffix `dirname` with a
527 # slash, and produces '.' for the root instead of ''.
527 # slash, and produces '.' for the root instead of ''.
528 oldpos = len(path)
528 oldpos = len(path)
529 pos = path.rfind('/')
529 pos = path.rfind('/')
530 while pos != -1:
530 while pos != -1:
531 yield path[:pos], path[pos + 1:oldpos]
531 yield path[:pos], path[pos + 1:oldpos]
532 oldpos = pos
532 oldpos = pos
533 pos = path.rfind('/', 0, pos)
533 pos = path.rfind('/', 0, pos)
534 yield '.', path[:oldpos]
534 yield '.', path[:oldpos]
535
535
536 def get(self, path):
536 def get(self, path):
537 return self._dirs.get(path, set())
537 return self._dirs.get(path, set())
538
538
539 class includematcher(basematcher):
539 class includematcher(basematcher):
540
540
541 def __init__(self, root, cwd, kindpats, listsubrepos=False, badfn=None):
541 def __init__(self, root, cwd, kindpats, listsubrepos=False, badfn=None):
542 super(includematcher, self).__init__(root, cwd, badfn)
542 super(includematcher, self).__init__(root, cwd, badfn)
543
543
544 self._pats, self.matchfn = _buildmatch(kindpats, '(?:/|$)',
544 self._pats, self.matchfn = _buildmatch(kindpats, '(?:/|$)',
545 listsubrepos, root)
545 listsubrepos, root)
546 self._prefix = _prefix(kindpats)
546 self._prefix = _prefix(kindpats)
547 roots, dirs, parents = _rootsdirsandparents(kindpats)
547 roots, dirs, parents = _rootsdirsandparents(kindpats)
548 # roots are directories which are recursively included.
548 # roots are directories which are recursively included.
549 self._roots = set(roots)
549 self._roots = set(roots)
550 # dirs are directories which are non-recursively included.
550 # dirs are directories which are non-recursively included.
551 self._dirs = set(dirs)
551 self._dirs = set(dirs)
552 # parents are directories which are non-recursively included because
552 # parents are directories which are non-recursively included because
553 # they are needed to get to items in _dirs or _roots.
553 # they are needed to get to items in _dirs or _roots.
554 self._parents = set(parents)
554 self._parents = set(parents)
555
555
556 def visitdir(self, dir):
556 def visitdir(self, dir):
557 if self._prefix and dir in self._roots:
557 if self._prefix and dir in self._roots:
558 return 'all'
558 return 'all'
559 return ('.' in self._roots or
559 return ('.' in self._roots or
560 dir in self._roots or
560 dir in self._roots or
561 dir in self._dirs or
561 dir in self._dirs or
562 dir in self._parents or
562 dir in self._parents or
563 any(parentdir in self._roots
563 any(parentdir in self._roots
564 for parentdir in util.finddirs(dir)))
564 for parentdir in util.finddirs(dir)))
565
565
566 @propertycache
566 @propertycache
567 def _allparentschildren(self):
567 def _allparentschildren(self):
568 # It may seem odd that we add dirs, roots, and parents, and then
568 # It may seem odd that we add dirs, roots, and parents, and then
569 # restrict to only parents. This is to catch the case of:
569 # restrict to only parents. This is to catch the case of:
570 # dirs = ['foo/bar']
570 # dirs = ['foo/bar']
571 # parents = ['foo']
571 # parents = ['foo']
572 # if we asked for the children of 'foo', but had only added
572 # if we asked for the children of 'foo', but had only added
573 # self._parents, we wouldn't be able to respond ['bar'].
573 # self._parents, we wouldn't be able to respond ['bar'].
574 return _dirchildren(
574 return _dirchildren(
575 itertools.chain(self._dirs, self._roots, self._parents),
575 itertools.chain(self._dirs, self._roots, self._parents),
576 onlyinclude=self._parents)
576 onlyinclude=self._parents)
577
577
578 def visitchildrenset(self, dir):
578 def visitchildrenset(self, dir):
579 if self._prefix and dir in self._roots:
579 if self._prefix and dir in self._roots:
580 return 'all'
580 return 'all'
581 # Note: this does *not* include the 'dir in self._parents' case from
581 # Note: this does *not* include the 'dir in self._parents' case from
582 # visitdir, that's handled below.
582 # visitdir, that's handled below.
583 if ('.' in self._roots or
583 if ('.' in self._roots or
584 dir in self._roots or
584 dir in self._roots or
585 dir in self._dirs or
585 dir in self._dirs or
586 any(parentdir in self._roots
586 any(parentdir in self._roots
587 for parentdir in util.finddirs(dir))):
587 for parentdir in util.finddirs(dir))):
588 return 'this'
588 return 'this'
589
589
590 if dir in self._parents:
590 if dir in self._parents:
591 return self._allparentschildren.get(dir) or set()
591 return self._allparentschildren.get(dir) or set()
592 return set()
592 return set()
593
593
594 @encoding.strmethod
594 @encoding.strmethod
595 def __repr__(self):
595 def __repr__(self):
596 return ('<includematcher includes=%r>' % pycompat.bytestr(self._pats))
596 return ('<includematcher includes=%r>' % pycompat.bytestr(self._pats))
597
597
598 class exactmatcher(basematcher):
598 class exactmatcher(basematcher):
599 '''Matches the input files exactly. They are interpreted as paths, not
599 '''Matches the input files exactly. They are interpreted as paths, not
600 patterns (so no kind-prefixes).
600 patterns (so no kind-prefixes).
601 '''
601 '''
602
602
603 def __init__(self, root, cwd, files, badfn=None):
603 def __init__(self, root, cwd, files, badfn=None):
604 super(exactmatcher, self).__init__(root, cwd, badfn)
604 super(exactmatcher, self).__init__(root, cwd, badfn)
605
605
606 if isinstance(files, list):
606 if isinstance(files, list):
607 self._files = files
607 self._files = files
608 else:
608 else:
609 self._files = list(files)
609 self._files = list(files)
610
610
611 matchfn = basematcher.exact
611 matchfn = basematcher.exact
612
612
613 @propertycache
613 @propertycache
614 def _dirs(self):
614 def _dirs(self):
615 return set(util.dirs(self._fileset)) | {'.'}
615 return set(util.dirs(self._fileset)) | {'.'}
616
616
617 def visitdir(self, dir):
617 def visitdir(self, dir):
618 return dir in self._dirs
618 return dir in self._dirs
619
619
620 def visitchildrenset(self, dir):
620 def visitchildrenset(self, dir):
621 if not self._fileset or dir not in self._dirs:
621 if not self._fileset or dir not in self._dirs:
622 return set()
622 return set()
623
623
624 candidates = self._fileset | self._dirs - {'.'}
624 candidates = self._fileset | self._dirs - {'.'}
625 if dir != '.':
625 if dir != '.':
626 d = dir + '/'
626 d = dir + '/'
627 candidates = set(c[len(d):] for c in candidates if
627 candidates = set(c[len(d):] for c in candidates if
628 c.startswith(d))
628 c.startswith(d))
629 # self._dirs includes all of the directories, recursively, so if
629 # self._dirs includes all of the directories, recursively, so if
630 # we're attempting to match foo/bar/baz.txt, it'll have '.', 'foo',
630 # we're attempting to match foo/bar/baz.txt, it'll have '.', 'foo',
631 # 'foo/bar' in it. Thus we can safely ignore a candidate that has a
631 # 'foo/bar' in it. Thus we can safely ignore a candidate that has a
632 # '/' in it, indicating a it's for a subdir-of-a-subdir; the
632 # '/' in it, indicating a it's for a subdir-of-a-subdir; the
633 # immediate subdir will be in there without a slash.
633 # immediate subdir will be in there without a slash.
634 ret = {c for c in candidates if '/' not in c}
634 ret = {c for c in candidates if '/' not in c}
635 # We really do not expect ret to be empty, since that would imply that
635 # We really do not expect ret to be empty, since that would imply that
636 # there's something in _dirs that didn't have a file in _fileset.
636 # there's something in _dirs that didn't have a file in _fileset.
637 assert ret
637 assert ret
638 return ret
638 return ret
639
639
640 def isexact(self):
640 def isexact(self):
641 return True
641 return True
642
642
643 @encoding.strmethod
643 @encoding.strmethod
644 def __repr__(self):
644 def __repr__(self):
645 return ('<exactmatcher files=%r>' % self._files)
645 return ('<exactmatcher files=%r>' % self._files)
646
646
647 class differencematcher(basematcher):
647 class differencematcher(basematcher):
648 '''Composes two matchers by matching if the first matches and the second
648 '''Composes two matchers by matching if the first matches and the second
649 does not.
649 does not.
650
650
651 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir,
651 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir,
652 traversedir) are ignored.
652 traversedir) are ignored.
653 '''
653 '''
654 def __init__(self, m1, m2):
654 def __init__(self, m1, m2):
655 super(differencematcher, self).__init__(m1._root, m1._cwd)
655 super(differencematcher, self).__init__(m1._root, m1._cwd)
656 self._m1 = m1
656 self._m1 = m1
657 self._m2 = m2
657 self._m2 = m2
658 self.bad = m1.bad
658 self.bad = m1.bad
659 self.explicitdir = m1.explicitdir
659 self.explicitdir = m1.explicitdir
660 self.traversedir = m1.traversedir
660 self.traversedir = m1.traversedir
661
661
662 def matchfn(self, f):
662 def matchfn(self, f):
663 return self._m1(f) and not self._m2(f)
663 return self._m1(f) and not self._m2(f)
664
664
665 @propertycache
665 @propertycache
666 def _files(self):
666 def _files(self):
667 if self.isexact():
667 if self.isexact():
668 return [f for f in self._m1.files() if self(f)]
668 return [f for f in self._m1.files() if self(f)]
669 # If m1 is not an exact matcher, we can't easily figure out the set of
669 # If m1 is not an exact matcher, we can't easily figure out the set of
670 # files, because its files() are not always files. For example, if
670 # files, because its files() are not always files. For example, if
671 # m1 is "path:dir" and m2 is "rootfileins:.", we don't
671 # m1 is "path:dir" and m2 is "rootfileins:.", we don't
672 # want to remove "dir" from the set even though it would match m2,
672 # want to remove "dir" from the set even though it would match m2,
673 # because the "dir" in m1 may not be a file.
673 # because the "dir" in m1 may not be a file.
674 return self._m1.files()
674 return self._m1.files()
675
675
676 def visitdir(self, dir):
676 def visitdir(self, dir):
677 if self._m2.visitdir(dir) == 'all':
677 if self._m2.visitdir(dir) == 'all':
678 return False
678 return False
679 return bool(self._m1.visitdir(dir))
679 return bool(self._m1.visitdir(dir))
680
680
681 def visitchildrenset(self, dir):
681 def visitchildrenset(self, dir):
682 m2_set = self._m2.visitchildrenset(dir)
682 m2_set = self._m2.visitchildrenset(dir)
683 if m2_set == 'all':
683 if m2_set == 'all':
684 return set()
684 return set()
685 m1_set = self._m1.visitchildrenset(dir)
685 m1_set = self._m1.visitchildrenset(dir)
686 # Possible values for m1: 'all', 'this', set(...), set()
686 # Possible values for m1: 'all', 'this', set(...), set()
687 # Possible values for m2: 'this', set(...), set()
687 # Possible values for m2: 'this', set(...), set()
688 # If m2 has nothing under here that we care about, return m1, even if
688 # If m2 has nothing under here that we care about, return m1, even if
689 # it's 'all'. This is a change in behavior from visitdir, which would
689 # it's 'all'. This is a change in behavior from visitdir, which would
690 # return True, not 'all', for some reason.
690 # return True, not 'all', for some reason.
691 if not m2_set:
691 if not m2_set:
692 return m1_set
692 return m1_set
693 if m1_set in ['all', 'this']:
693 if m1_set in ['all', 'this']:
694 # Never return 'all' here if m2_set is any kind of non-empty (either
694 # Never return 'all' here if m2_set is any kind of non-empty (either
695 # 'this' or set(foo)), since m2 might return set() for a
695 # 'this' or set(foo)), since m2 might return set() for a
696 # subdirectory.
696 # subdirectory.
697 return 'this'
697 return 'this'
698 # Possible values for m1: set(...), set()
698 # Possible values for m1: set(...), set()
699 # Possible values for m2: 'this', set(...)
699 # Possible values for m2: 'this', set(...)
700 # We ignore m2's set results. They're possibly incorrect:
700 # We ignore m2's set results. They're possibly incorrect:
701 # m1 = path:dir/subdir, m2=rootfilesin:dir, visitchildrenset('.'):
701 # m1 = path:dir/subdir, m2=rootfilesin:dir, visitchildrenset('.'):
702 # m1 returns {'dir'}, m2 returns {'dir'}, if we subtracted we'd
702 # m1 returns {'dir'}, m2 returns {'dir'}, if we subtracted we'd
703 # return set(), which is *not* correct, we still need to visit 'dir'!
703 # return set(), which is *not* correct, we still need to visit 'dir'!
704 return m1_set
704 return m1_set
705
705
706 def isexact(self):
706 def isexact(self):
707 return self._m1.isexact()
707 return self._m1.isexact()
708
708
709 @encoding.strmethod
709 @encoding.strmethod
710 def __repr__(self):
710 def __repr__(self):
711 return ('<differencematcher m1=%r, m2=%r>' % (self._m1, self._m2))
711 return ('<differencematcher m1=%r, m2=%r>' % (self._m1, self._m2))
712
712
713 def intersectmatchers(m1, m2):
713 def intersectmatchers(m1, m2):
714 '''Composes two matchers by matching if both of them match.
714 '''Composes two matchers by matching if both of them match.
715
715
716 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir,
716 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir,
717 traversedir) are ignored.
717 traversedir) are ignored.
718 '''
718 '''
719 if m1 is None or m2 is None:
719 if m1 is None or m2 is None:
720 return m1 or m2
720 return m1 or m2
721 if m1.always():
721 if m1.always():
722 m = copy.copy(m2)
722 m = copy.copy(m2)
723 # TODO: Consider encapsulating these things in a class so there's only
723 # TODO: Consider encapsulating these things in a class so there's only
724 # one thing to copy from m1.
724 # one thing to copy from m1.
725 m.bad = m1.bad
725 m.bad = m1.bad
726 m.explicitdir = m1.explicitdir
726 m.explicitdir = m1.explicitdir
727 m.traversedir = m1.traversedir
727 m.traversedir = m1.traversedir
728 m.abs = m1.abs
728 m.abs = m1.abs
729 m.rel = m1.rel
729 m.rel = m1.rel
730 m._relativeuipath |= m1._relativeuipath
730 m._relativeuipath |= m1._relativeuipath
731 return m
731 return m
732 if m2.always():
732 if m2.always():
733 m = copy.copy(m1)
733 m = copy.copy(m1)
734 m._relativeuipath |= m2._relativeuipath
734 m._relativeuipath |= m2._relativeuipath
735 return m
735 return m
736 return intersectionmatcher(m1, m2)
736 return intersectionmatcher(m1, m2)
737
737
738 class intersectionmatcher(basematcher):
738 class intersectionmatcher(basematcher):
739 def __init__(self, m1, m2):
739 def __init__(self, m1, m2):
740 super(intersectionmatcher, self).__init__(m1._root, m1._cwd)
740 super(intersectionmatcher, self).__init__(m1._root, m1._cwd)
741 self._m1 = m1
741 self._m1 = m1
742 self._m2 = m2
742 self._m2 = m2
743 self.bad = m1.bad
743 self.bad = m1.bad
744 self.explicitdir = m1.explicitdir
744 self.explicitdir = m1.explicitdir
745 self.traversedir = m1.traversedir
745 self.traversedir = m1.traversedir
746
746
747 @propertycache
747 @propertycache
748 def _files(self):
748 def _files(self):
749 if self.isexact():
749 if self.isexact():
750 m1, m2 = self._m1, self._m2
750 m1, m2 = self._m1, self._m2
751 if not m1.isexact():
751 if not m1.isexact():
752 m1, m2 = m2, m1
752 m1, m2 = m2, m1
753 return [f for f in m1.files() if m2(f)]
753 return [f for f in m1.files() if m2(f)]
754 # It neither m1 nor m2 is an exact matcher, we can't easily intersect
754 # It neither m1 nor m2 is an exact matcher, we can't easily intersect
755 # the set of files, because their files() are not always files. For
755 # the set of files, because their files() are not always files. For
756 # example, if intersecting a matcher "-I glob:foo.txt" with matcher of
756 # example, if intersecting a matcher "-I glob:foo.txt" with matcher of
757 # "path:dir2", we don't want to remove "dir2" from the set.
757 # "path:dir2", we don't want to remove "dir2" from the set.
758 return self._m1.files() + self._m2.files()
758 return self._m1.files() + self._m2.files()
759
759
760 def matchfn(self, f):
760 def matchfn(self, f):
761 return self._m1(f) and self._m2(f)
761 return self._m1(f) and self._m2(f)
762
762
763 def visitdir(self, dir):
763 def visitdir(self, dir):
764 visit1 = self._m1.visitdir(dir)
764 visit1 = self._m1.visitdir(dir)
765 if visit1 == 'all':
765 if visit1 == 'all':
766 return self._m2.visitdir(dir)
766 return self._m2.visitdir(dir)
767 # bool() because visit1=True + visit2='all' should not be 'all'
767 # bool() because visit1=True + visit2='all' should not be 'all'
768 return bool(visit1 and self._m2.visitdir(dir))
768 return bool(visit1 and self._m2.visitdir(dir))
769
769
770 def visitchildrenset(self, dir):
770 def visitchildrenset(self, dir):
771 m1_set = self._m1.visitchildrenset(dir)
771 m1_set = self._m1.visitchildrenset(dir)
772 if not m1_set:
772 if not m1_set:
773 return set()
773 return set()
774 m2_set = self._m2.visitchildrenset(dir)
774 m2_set = self._m2.visitchildrenset(dir)
775 if not m2_set:
775 if not m2_set:
776 return set()
776 return set()
777
777
778 if m1_set == 'all':
778 if m1_set == 'all':
779 return m2_set
779 return m2_set
780 elif m2_set == 'all':
780 elif m2_set == 'all':
781 return m1_set
781 return m1_set
782
782
783 if m1_set == 'this' or m2_set == 'this':
783 if m1_set == 'this' or m2_set == 'this':
784 return 'this'
784 return 'this'
785
785
786 assert isinstance(m1_set, set) and isinstance(m2_set, set)
786 assert isinstance(m1_set, set) and isinstance(m2_set, set)
787 return m1_set.intersection(m2_set)
787 return m1_set.intersection(m2_set)
788
788
789 def always(self):
789 def always(self):
790 return self._m1.always() and self._m2.always()
790 return self._m1.always() and self._m2.always()
791
791
792 def isexact(self):
792 def isexact(self):
793 return self._m1.isexact() or self._m2.isexact()
793 return self._m1.isexact() or self._m2.isexact()
794
794
795 @encoding.strmethod
795 @encoding.strmethod
796 def __repr__(self):
796 def __repr__(self):
797 return ('<intersectionmatcher m1=%r, m2=%r>' % (self._m1, self._m2))
797 return ('<intersectionmatcher m1=%r, m2=%r>' % (self._m1, self._m2))
798
798
799 class subdirmatcher(basematcher):
799 class subdirmatcher(basematcher):
800 """Adapt a matcher to work on a subdirectory only.
800 """Adapt a matcher to work on a subdirectory only.
801
801
802 The paths are remapped to remove/insert the path as needed:
802 The paths are remapped to remove/insert the path as needed:
803
803
804 >>> from . import pycompat
804 >>> from . import pycompat
805 >>> m1 = match(b'root', b'', [b'a.txt', b'sub/b.txt'])
805 >>> m1 = match(b'root', b'', [b'a.txt', b'sub/b.txt'])
806 >>> m2 = subdirmatcher(b'sub', m1)
806 >>> m2 = subdirmatcher(b'sub', m1)
807 >>> bool(m2(b'a.txt'))
807 >>> bool(m2(b'a.txt'))
808 False
808 False
809 >>> bool(m2(b'b.txt'))
809 >>> bool(m2(b'b.txt'))
810 True
810 True
811 >>> bool(m2.matchfn(b'a.txt'))
811 >>> bool(m2.matchfn(b'a.txt'))
812 False
812 False
813 >>> bool(m2.matchfn(b'b.txt'))
813 >>> bool(m2.matchfn(b'b.txt'))
814 True
814 True
815 >>> m2.files()
815 >>> m2.files()
816 ['b.txt']
816 ['b.txt']
817 >>> m2.exact(b'b.txt')
817 >>> m2.exact(b'b.txt')
818 True
818 True
819 >>> util.pconvert(m2.rel(b'b.txt'))
819 >>> util.pconvert(m2.rel(b'b.txt'))
820 'sub/b.txt'
820 'sub/b.txt'
821 >>> def bad(f, msg):
821 >>> def bad(f, msg):
822 ... print(pycompat.sysstr(b"%s: %s" % (f, msg)))
822 ... print(pycompat.sysstr(b"%s: %s" % (f, msg)))
823 >>> m1.bad = bad
823 >>> m1.bad = bad
824 >>> m2.bad(b'x.txt', b'No such file')
824 >>> m2.bad(b'x.txt', b'No such file')
825 sub/x.txt: No such file
825 sub/x.txt: No such file
826 >>> m2.abs(b'c.txt')
826 >>> m2.abs(b'c.txt')
827 'sub/c.txt'
827 'sub/c.txt'
828 """
828 """
829
829
830 def __init__(self, path, matcher):
830 def __init__(self, path, matcher):
831 super(subdirmatcher, self).__init__(matcher._root, matcher._cwd)
831 super(subdirmatcher, self).__init__(matcher._root, matcher._cwd)
832 self._path = path
832 self._path = path
833 self._matcher = matcher
833 self._matcher = matcher
834 self._always = matcher.always()
834 self._always = matcher.always()
835
835
836 self._files = [f[len(path) + 1:] for f in matcher._files
836 self._files = [f[len(path) + 1:] for f in matcher._files
837 if f.startswith(path + "/")]
837 if f.startswith(path + "/")]
838
838
839 # If the parent repo had a path to this subrepo and the matcher is
839 # If the parent repo had a path to this subrepo and the matcher is
840 # a prefix matcher, this submatcher always matches.
840 # a prefix matcher, this submatcher always matches.
841 if matcher.prefix():
841 if matcher.prefix():
842 self._always = any(f == path for f in matcher._files)
842 self._always = any(f == path for f in matcher._files)
843
843
844 def bad(self, f, msg):
844 def bad(self, f, msg):
845 self._matcher.bad(self._path + "/" + f, msg)
845 self._matcher.bad(self._path + "/" + f, msg)
846
846
847 def abs(self, f):
847 def abs(self, f):
848 return self._matcher.abs(self._path + "/" + f)
848 return self._matcher.abs(self._path + "/" + f)
849
849
850 def rel(self, f):
850 def rel(self, f):
851 return self._matcher.rel(self._path + "/" + f)
851 return self._matcher.rel(self._path + "/" + f)
852
852
853 def uipath(self, f):
853 def uipath(self, f):
854 return self._matcher.uipath(self._path + "/" + f)
854 return self._matcher.uipath(self._path + "/" + f)
855
855
856 def matchfn(self, f):
856 def matchfn(self, f):
857 # Some information is lost in the superclass's constructor, so we
857 # Some information is lost in the superclass's constructor, so we
858 # can not accurately create the matching function for the subdirectory
858 # can not accurately create the matching function for the subdirectory
859 # from the inputs. Instead, we override matchfn() and visitdir() to
859 # from the inputs. Instead, we override matchfn() and visitdir() to
860 # call the original matcher with the subdirectory path prepended.
860 # call the original matcher with the subdirectory path prepended.
861 return self._matcher.matchfn(self._path + "/" + f)
861 return self._matcher.matchfn(self._path + "/" + f)
862
862
863 def visitdir(self, dir):
863 def visitdir(self, dir):
864 if dir == '.':
864 if dir == '.':
865 dir = self._path
865 dir = self._path
866 else:
866 else:
867 dir = self._path + "/" + dir
867 dir = self._path + "/" + dir
868 return self._matcher.visitdir(dir)
868 return self._matcher.visitdir(dir)
869
869
870 def visitchildrenset(self, dir):
870 def visitchildrenset(self, dir):
871 if dir == '.':
871 if dir == '.':
872 dir = self._path
872 dir = self._path
873 else:
873 else:
874 dir = self._path + "/" + dir
874 dir = self._path + "/" + dir
875 return self._matcher.visitchildrenset(dir)
875 return self._matcher.visitchildrenset(dir)
876
876
877 def always(self):
877 def always(self):
878 return self._always
878 return self._always
879
879
880 def prefix(self):
880 def prefix(self):
881 return self._matcher.prefix() and not self._always
881 return self._matcher.prefix() and not self._always
882
882
883 @encoding.strmethod
883 @encoding.strmethod
884 def __repr__(self):
884 def __repr__(self):
885 return ('<subdirmatcher path=%r, matcher=%r>' %
885 return ('<subdirmatcher path=%r, matcher=%r>' %
886 (self._path, self._matcher))
886 (self._path, self._matcher))
887
887
888 class prefixdirmatcher(basematcher):
888 class prefixdirmatcher(basematcher):
889 """Adapt a matcher to work on a parent directory.
889 """Adapt a matcher to work on a parent directory.
890
890
891 The matcher's non-matching-attributes (root, cwd, bad, explicitdir,
891 The matcher's non-matching-attributes (root, cwd, bad, explicitdir,
892 traversedir) are ignored.
892 traversedir) are ignored.
893
893
894 The prefix path should usually be the relative path from the root of
894 The prefix path should usually be the relative path from the root of
895 this matcher to the root of the wrapped matcher.
895 this matcher to the root of the wrapped matcher.
896
896
897 >>> m1 = match(util.localpath(b'root/d/e'), b'f', [b'../a.txt', b'b.txt'])
897 >>> m1 = match(util.localpath(b'root/d/e'), b'f', [b'../a.txt', b'b.txt'])
898 >>> m2 = prefixdirmatcher(b'root', b'd/e/f', b'd/e', m1)
898 >>> m2 = prefixdirmatcher(b'root', b'd/e/f', b'd/e', m1)
899 >>> bool(m2(b'a.txt'),)
899 >>> bool(m2(b'a.txt'),)
900 False
900 False
901 >>> bool(m2(b'd/e/a.txt'))
901 >>> bool(m2(b'd/e/a.txt'))
902 True
902 True
903 >>> bool(m2(b'd/e/b.txt'))
903 >>> bool(m2(b'd/e/b.txt'))
904 False
904 False
905 >>> m2.files()
905 >>> m2.files()
906 ['d/e/a.txt', 'd/e/f/b.txt']
906 ['d/e/a.txt', 'd/e/f/b.txt']
907 >>> m2.exact(b'd/e/a.txt')
907 >>> m2.exact(b'd/e/a.txt')
908 True
908 True
909 >>> m2.visitdir(b'd')
909 >>> m2.visitdir(b'd')
910 True
910 True
911 >>> m2.visitdir(b'd/e')
911 >>> m2.visitdir(b'd/e')
912 True
912 True
913 >>> m2.visitdir(b'd/e/f')
913 >>> m2.visitdir(b'd/e/f')
914 True
914 True
915 >>> m2.visitdir(b'd/e/g')
915 >>> m2.visitdir(b'd/e/g')
916 False
916 False
917 >>> m2.visitdir(b'd/ef')
917 >>> m2.visitdir(b'd/ef')
918 False
918 False
919 """
919 """
920
920
921 def __init__(self, root, cwd, path, matcher, badfn=None):
921 def __init__(self, root, cwd, path, matcher, badfn=None):
922 super(prefixdirmatcher, self).__init__(root, cwd, badfn)
922 super(prefixdirmatcher, self).__init__(root, cwd, badfn)
923 if not path:
923 if not path:
924 raise error.ProgrammingError('prefix path must not be empty')
924 raise error.ProgrammingError('prefix path must not be empty')
925 self._path = path
925 self._path = path
926 self._pathprefix = path + '/'
926 self._pathprefix = path + '/'
927 self._matcher = matcher
927 self._matcher = matcher
928
928
929 @propertycache
929 @propertycache
930 def _files(self):
930 def _files(self):
931 return [self._pathprefix + f for f in self._matcher._files]
931 return [self._pathprefix + f for f in self._matcher._files]
932
932
933 def matchfn(self, f):
933 def matchfn(self, f):
934 if not f.startswith(self._pathprefix):
934 if not f.startswith(self._pathprefix):
935 return False
935 return False
936 return self._matcher.matchfn(f[len(self._pathprefix):])
936 return self._matcher.matchfn(f[len(self._pathprefix):])
937
937
938 @propertycache
938 @propertycache
939 def _pathdirs(self):
939 def _pathdirs(self):
940 return set(util.finddirs(self._path)) | {'.'}
940 return set(util.finddirs(self._path)) | {'.'}
941
941
942 def visitdir(self, dir):
942 def visitdir(self, dir):
943 if dir == self._path:
943 if dir == self._path:
944 return self._matcher.visitdir('.')
944 return self._matcher.visitdir('.')
945 if dir.startswith(self._pathprefix):
945 if dir.startswith(self._pathprefix):
946 return self._matcher.visitdir(dir[len(self._pathprefix):])
946 return self._matcher.visitdir(dir[len(self._pathprefix):])
947 return dir in self._pathdirs
947 return dir in self._pathdirs
948
948
949 def visitchildrenset(self, dir):
949 def visitchildrenset(self, dir):
950 if dir == self._path:
950 if dir == self._path:
951 return self._matcher.visitchildrenset('.')
951 return self._matcher.visitchildrenset('.')
952 if dir.startswith(self._pathprefix):
952 if dir.startswith(self._pathprefix):
953 return self._matcher.visitchildrenset(dir[len(self._pathprefix):])
953 return self._matcher.visitchildrenset(dir[len(self._pathprefix):])
954 if dir in self._pathdirs:
954 if dir in self._pathdirs:
955 return 'this'
955 return 'this'
956 return set()
956 return set()
957
957
958 def isexact(self):
958 def isexact(self):
959 return self._matcher.isexact()
959 return self._matcher.isexact()
960
960
961 def prefix(self):
961 def prefix(self):
962 return self._matcher.prefix()
962 return self._matcher.prefix()
963
963
964 @encoding.strmethod
964 @encoding.strmethod
965 def __repr__(self):
965 def __repr__(self):
966 return ('<prefixdirmatcher path=%r, matcher=%r>'
966 return ('<prefixdirmatcher path=%r, matcher=%r>'
967 % (pycompat.bytestr(self._path), self._matcher))
967 % (pycompat.bytestr(self._path), self._matcher))
968
968
969 class unionmatcher(basematcher):
969 class unionmatcher(basematcher):
970 """A matcher that is the union of several matchers.
970 """A matcher that is the union of several matchers.
971
971
972 The non-matching-attributes (root, cwd, bad, explicitdir, traversedir) are
972 The non-matching-attributes (root, cwd, bad, explicitdir, traversedir) are
973 taken from the first matcher.
973 taken from the first matcher.
974 """
974 """
975
975
976 def __init__(self, matchers):
976 def __init__(self, matchers):
977 m1 = matchers[0]
977 m1 = matchers[0]
978 super(unionmatcher, self).__init__(m1._root, m1._cwd)
978 super(unionmatcher, self).__init__(m1._root, m1._cwd)
979 self.explicitdir = m1.explicitdir
979 self.explicitdir = m1.explicitdir
980 self.traversedir = m1.traversedir
980 self.traversedir = m1.traversedir
981 self._matchers = matchers
981 self._matchers = matchers
982
982
983 def matchfn(self, f):
983 def matchfn(self, f):
984 for match in self._matchers:
984 for match in self._matchers:
985 if match(f):
985 if match(f):
986 return True
986 return True
987 return False
987 return False
988
988
989 def visitdir(self, dir):
989 def visitdir(self, dir):
990 r = False
990 r = False
991 for m in self._matchers:
991 for m in self._matchers:
992 v = m.visitdir(dir)
992 v = m.visitdir(dir)
993 if v == 'all':
993 if v == 'all':
994 return v
994 return v
995 r |= v
995 r |= v
996 return r
996 return r
997
997
998 def visitchildrenset(self, dir):
998 def visitchildrenset(self, dir):
999 r = set()
999 r = set()
1000 this = False
1000 this = False
1001 for m in self._matchers:
1001 for m in self._matchers:
1002 v = m.visitchildrenset(dir)
1002 v = m.visitchildrenset(dir)
1003 if not v:
1003 if not v:
1004 continue
1004 continue
1005 if v == 'all':
1005 if v == 'all':
1006 return v
1006 return v
1007 if this or v == 'this':
1007 if this or v == 'this':
1008 this = True
1008 this = True
1009 # don't break, we might have an 'all' in here.
1009 # don't break, we might have an 'all' in here.
1010 continue
1010 continue
1011 assert isinstance(v, set)
1011 assert isinstance(v, set)
1012 r = r.union(v)
1012 r = r.union(v)
1013 if this:
1013 if this:
1014 return 'this'
1014 return 'this'
1015 return r
1015 return r
1016
1016
1017 @encoding.strmethod
1017 @encoding.strmethod
1018 def __repr__(self):
1018 def __repr__(self):
1019 return ('<unionmatcher matchers=%r>' % self._matchers)
1019 return ('<unionmatcher matchers=%r>' % self._matchers)
1020
1020
1021 def patkind(pattern, default=None):
1021 def patkind(pattern, default=None):
1022 '''If pattern is 'kind:pat' with a known kind, return kind.'''
1022 '''If pattern is 'kind:pat' with a known kind, return kind.'''
1023 return _patsplit(pattern, default)[0]
1023 return _patsplit(pattern, default)[0]
1024
1024
1025 def _patsplit(pattern, default):
1025 def _patsplit(pattern, default):
1026 """Split a string into the optional pattern kind prefix and the actual
1026 """Split a string into the optional pattern kind prefix and the actual
1027 pattern."""
1027 pattern."""
1028 if ':' in pattern:
1028 if ':' in pattern:
1029 kind, pat = pattern.split(':', 1)
1029 kind, pat = pattern.split(':', 1)
1030 if kind in allpatternkinds:
1030 if kind in allpatternkinds:
1031 return kind, pat
1031 return kind, pat
1032 return default, pattern
1032 return default, pattern
1033
1033
1034 def _globre(pat):
1034 def _globre(pat):
1035 r'''Convert an extended glob string to a regexp string.
1035 r'''Convert an extended glob string to a regexp string.
1036
1036
1037 >>> from . import pycompat
1037 >>> from . import pycompat
1038 >>> def bprint(s):
1038 >>> def bprint(s):
1039 ... print(pycompat.sysstr(s))
1039 ... print(pycompat.sysstr(s))
1040 >>> bprint(_globre(br'?'))
1040 >>> bprint(_globre(br'?'))
1041 .
1041 .
1042 >>> bprint(_globre(br'*'))
1042 >>> bprint(_globre(br'*'))
1043 [^/]*
1043 [^/]*
1044 >>> bprint(_globre(br'**'))
1044 >>> bprint(_globre(br'**'))
1045 .*
1045 .*
1046 >>> bprint(_globre(br'**/a'))
1046 >>> bprint(_globre(br'**/a'))
1047 (?:.*/)?a
1047 (?:.*/)?a
1048 >>> bprint(_globre(br'a/**/b'))
1048 >>> bprint(_globre(br'a/**/b'))
1049 a/(?:.*/)?b
1049 a/(?:.*/)?b
1050 >>> bprint(_globre(br'[a*?!^][^b][!c]'))
1050 >>> bprint(_globre(br'[a*?!^][^b][!c]'))
1051 [a*?!^][\^b][^c]
1051 [a*?!^][\^b][^c]
1052 >>> bprint(_globre(br'{a,b}'))
1052 >>> bprint(_globre(br'{a,b}'))
1053 (?:a|b)
1053 (?:a|b)
1054 >>> bprint(_globre(br'.\*\?'))
1054 >>> bprint(_globre(br'.\*\?'))
1055 \.\*\?
1055 \.\*\?
1056 '''
1056 '''
1057 i, n = 0, len(pat)
1057 i, n = 0, len(pat)
1058 res = ''
1058 res = ''
1059 group = 0
1059 group = 0
1060 escape = util.stringutil.regexbytesescapemap.get
1060 escape = util.stringutil.regexbytesescapemap.get
1061 def peek():
1061 def peek():
1062 return i < n and pat[i:i + 1]
1062 return i < n and pat[i:i + 1]
1063 while i < n:
1063 while i < n:
1064 c = pat[i:i + 1]
1064 c = pat[i:i + 1]
1065 i += 1
1065 i += 1
1066 if c not in '*?[{},\\':
1066 if c not in '*?[{},\\':
1067 res += escape(c, c)
1067 res += escape(c, c)
1068 elif c == '*':
1068 elif c == '*':
1069 if peek() == '*':
1069 if peek() == '*':
1070 i += 1
1070 i += 1
1071 if peek() == '/':
1071 if peek() == '/':
1072 i += 1
1072 i += 1
1073 res += '(?:.*/)?'
1073 res += '(?:.*/)?'
1074 else:
1074 else:
1075 res += '.*'
1075 res += '.*'
1076 else:
1076 else:
1077 res += '[^/]*'
1077 res += '[^/]*'
1078 elif c == '?':
1078 elif c == '?':
1079 res += '.'
1079 res += '.'
1080 elif c == '[':
1080 elif c == '[':
1081 j = i
1081 j = i
1082 if j < n and pat[j:j + 1] in '!]':
1082 if j < n and pat[j:j + 1] in '!]':
1083 j += 1
1083 j += 1
1084 while j < n and pat[j:j + 1] != ']':
1084 while j < n and pat[j:j + 1] != ']':
1085 j += 1
1085 j += 1
1086 if j >= n:
1086 if j >= n:
1087 res += '\\['
1087 res += '\\['
1088 else:
1088 else:
1089 stuff = pat[i:j].replace('\\','\\\\')
1089 stuff = pat[i:j].replace('\\','\\\\')
1090 i = j + 1
1090 i = j + 1
1091 if stuff[0:1] == '!':
1091 if stuff[0:1] == '!':
1092 stuff = '^' + stuff[1:]
1092 stuff = '^' + stuff[1:]
1093 elif stuff[0:1] == '^':
1093 elif stuff[0:1] == '^':
1094 stuff = '\\' + stuff
1094 stuff = '\\' + stuff
1095 res = '%s[%s]' % (res, stuff)
1095 res = '%s[%s]' % (res, stuff)
1096 elif c == '{':
1096 elif c == '{':
1097 group += 1
1097 group += 1
1098 res += '(?:'
1098 res += '(?:'
1099 elif c == '}' and group:
1099 elif c == '}' and group:
1100 res += ')'
1100 res += ')'
1101 group -= 1
1101 group -= 1
1102 elif c == ',' and group:
1102 elif c == ',' and group:
1103 res += '|'
1103 res += '|'
1104 elif c == '\\':
1104 elif c == '\\':
1105 p = peek()
1105 p = peek()
1106 if p:
1106 if p:
1107 i += 1
1107 i += 1
1108 res += escape(p, p)
1108 res += escape(p, p)
1109 else:
1109 else:
1110 res += escape(c, c)
1110 res += escape(c, c)
1111 else:
1111 else:
1112 res += escape(c, c)
1112 res += escape(c, c)
1113 return res
1113 return res
1114
1114
1115 def _regex(kind, pat, globsuffix):
1115 def _regex(kind, pat, globsuffix):
1116 '''Convert a (normalized) pattern of any kind into a regular expression.
1116 '''Convert a (normalized) pattern of any kind into a regular expression.
1117 globsuffix is appended to the regexp of globs.'''
1117 globsuffix is appended to the regexp of globs.'''
1118 if not pat:
1118 if not pat:
1119 return ''
1119 return ''
1120 if kind == 're':
1120 if kind == 're':
1121 return pat
1121 return pat
1122 if kind in ('path', 'relpath'):
1122 if kind in ('path', 'relpath'):
1123 if pat == '.':
1123 if pat == '.':
1124 return ''
1124 return ''
1125 return util.stringutil.reescape(pat) + '(?:/|$)'
1125 return util.stringutil.reescape(pat) + '(?:/|$)'
1126 if kind == 'rootfilesin':
1126 if kind == 'rootfilesin':
1127 if pat == '.':
1127 if pat == '.':
1128 escaped = ''
1128 escaped = ''
1129 else:
1129 else:
1130 # Pattern is a directory name.
1130 # Pattern is a directory name.
1131 escaped = util.stringutil.reescape(pat) + '/'
1131 escaped = util.stringutil.reescape(pat) + '/'
1132 # Anything after the pattern must be a non-directory.
1132 # Anything after the pattern must be a non-directory.
1133 return escaped + '[^/]+$'
1133 return escaped + '[^/]+$'
1134 if kind == 'relglob':
1134 if kind == 'relglob':
1135 return '(?:|.*/)' + _globre(pat) + globsuffix
1135 return '(?:|.*/)' + _globre(pat) + globsuffix
1136 if kind == 'relre':
1136 if kind == 'relre':
1137 if pat.startswith('^'):
1137 if pat.startswith('^'):
1138 return pat
1138 return pat
1139 return '.*' + pat
1139 return '.*' + pat
1140 if kind == 'glob':
1140 if kind == 'glob':
1141 return _globre(pat) + globsuffix
1141 return _globre(pat) + globsuffix
1142 raise error.ProgrammingError('not a regex pattern: %s:%s' % (kind, pat))
1142 raise error.ProgrammingError('not a regex pattern: %s:%s' % (kind, pat))
1143
1143
1144 def _buildmatch(kindpats, globsuffix, listsubrepos, root):
1144 def _buildmatch(kindpats, globsuffix, listsubrepos, root):
1145 '''Return regexp string and a matcher function for kindpats.
1145 '''Return regexp string and a matcher function for kindpats.
1146 globsuffix is appended to the regexp of globs.'''
1146 globsuffix is appended to the regexp of globs.'''
1147 matchfuncs = []
1147 matchfuncs = []
1148
1148
1149 subincludes, kindpats = _expandsubinclude(kindpats, root)
1149 subincludes, kindpats = _expandsubinclude(kindpats, root)
1150 if subincludes:
1150 if subincludes:
1151 submatchers = {}
1151 submatchers = {}
1152 def matchsubinclude(f):
1152 def matchsubinclude(f):
1153 for prefix, matcherargs in subincludes:
1153 for prefix, matcherargs in subincludes:
1154 if f.startswith(prefix):
1154 if f.startswith(prefix):
1155 mf = submatchers.get(prefix)
1155 mf = submatchers.get(prefix)
1156 if mf is None:
1156 if mf is None:
1157 mf = match(*matcherargs)
1157 mf = match(*matcherargs)
1158 submatchers[prefix] = mf
1158 submatchers[prefix] = mf
1159
1159
1160 if mf(f[len(prefix):]):
1160 if mf(f[len(prefix):]):
1161 return True
1161 return True
1162 return False
1162 return False
1163 matchfuncs.append(matchsubinclude)
1163 matchfuncs.append(matchsubinclude)
1164
1164
1165 regex = ''
1165 regex = ''
1166 if kindpats:
1166 if kindpats:
1167 if all(k == 'rootfilesin' for k, p, s in kindpats):
1167 if all(k == 'rootfilesin' for k, p, s in kindpats):
1168 dirs = {p for k, p, s in kindpats}
1168 dirs = {p for k, p, s in kindpats}
1169 def mf(f):
1169 def mf(f):
1170 i = f.rfind('/')
1170 i = f.rfind('/')
1171 if i >= 0:
1171 if i >= 0:
1172 dir = f[:i]
1172 dir = f[:i]
1173 else:
1173 else:
1174 dir = '.'
1174 dir = '.'
1175 return dir in dirs
1175 return dir in dirs
1176 regex = b'rootfilesin: %s' % stringutil.pprint(list(sorted(dirs)))
1176 regex = b'rootfilesin: %s' % stringutil.pprint(list(sorted(dirs)))
1177 matchfuncs.append(mf)
1177 matchfuncs.append(mf)
1178 else:
1178 else:
1179 regex, mf = _buildregexmatch(kindpats, globsuffix)
1179 regex, mf = _buildregexmatch(kindpats, globsuffix)
1180 matchfuncs.append(mf)
1180 matchfuncs.append(mf)
1181
1181
1182 if len(matchfuncs) == 1:
1182 if len(matchfuncs) == 1:
1183 return regex, matchfuncs[0]
1183 return regex, matchfuncs[0]
1184 else:
1184 else:
1185 return regex, lambda f: any(mf(f) for mf in matchfuncs)
1185 return regex, lambda f: any(mf(f) for mf in matchfuncs)
1186
1186
1187 MAX_RE_SIZE = 20000
1187 MAX_RE_SIZE = 20000
1188 _BASE_SIZE = len('(?:)')
1189
1188
1190 def _joinregexes(regexps):
1189 def _joinregexes(regexps):
1191 """gather multiple regular expressions into a single one"""
1190 """gather multiple regular expressions into a single one"""
1192 return '(?:%s)' % '|'.join(regexps)
1191 return '|'.join(regexps)
1193
1192
1194 def _buildregexmatch(kindpats, globsuffix):
1193 def _buildregexmatch(kindpats, globsuffix):
1195 """Build a match function from a list of kinds and kindpats,
1194 """Build a match function from a list of kinds and kindpats,
1196 return regexp string and a matcher function.
1195 return regexp string and a matcher function.
1197
1196
1198 Test too large input
1197 Test too large input
1199 >>> _buildregexmatch([
1198 >>> _buildregexmatch([
1200 ... ('relglob', '?' * MAX_RE_SIZE, '')
1199 ... ('relglob', '?' * MAX_RE_SIZE, '')
1201 ... ], '$')
1200 ... ], '$')
1202 Traceback (most recent call last):
1201 Traceback (most recent call last):
1203 ...
1202 ...
1204 Abort: matcher pattern is too long (20009 bytes)
1203 Abort: matcher pattern is too long (20009 bytes)
1205 """
1204 """
1206 try:
1205 try:
1207 allgroups = []
1206 allgroups = []
1208 regexps = [_regex(k, p, globsuffix) for (k, p, s) in kindpats]
1207 regexps = [_regex(k, p, globsuffix) for (k, p, s) in kindpats]
1209 fullregexp = _joinregexes(regexps)
1208 fullregexp = _joinregexes(regexps)
1210
1209
1211 startidx = 0
1210 startidx = 0
1212 groupsize = _BASE_SIZE
1211 groupsize = 0
1213 for idx, r in enumerate(regexps):
1212 for idx, r in enumerate(regexps):
1214 piecesize = len(r)
1213 piecesize = len(r)
1215 if (piecesize + _BASE_SIZE) > MAX_RE_SIZE:
1214 if piecesize > MAX_RE_SIZE:
1216 msg = _("matcher pattern is too long (%d bytes)") % piecesize
1215 msg = _("matcher pattern is too long (%d bytes)") % piecesize
1217 raise error.Abort(msg)
1216 raise error.Abort(msg)
1218 elif (groupsize + piecesize) > MAX_RE_SIZE:
1217 elif (groupsize + piecesize) > MAX_RE_SIZE:
1219 group = regexps[startidx:idx]
1218 group = regexps[startidx:idx]
1220 allgroups.append(_joinregexes(group))
1219 allgroups.append(_joinregexes(group))
1221 startidx = idx
1220 startidx = idx
1222 groupsize = _BASE_SIZE
1221 groupsize = 0
1223 groupsize += piecesize + 1
1222 groupsize += piecesize + 1
1224
1223
1225 if startidx == 0:
1224 if startidx == 0:
1226 func = _rematcher(fullregexp)
1225 func = _rematcher(fullregexp)
1227 else:
1226 else:
1228 group = regexps[startidx:]
1227 group = regexps[startidx:]
1229 allgroups.append(_joinregexes(group))
1228 allgroups.append(_joinregexes(group))
1230 allmatchers = [_rematcher(g) for g in allgroups]
1229 allmatchers = [_rematcher(g) for g in allgroups]
1231 func = lambda s: any(m(s) for m in allmatchers)
1230 func = lambda s: any(m(s) for m in allmatchers)
1232 return fullregexp, func
1231 return fullregexp, func
1233 except re.error:
1232 except re.error:
1234 for k, p, s in kindpats:
1233 for k, p, s in kindpats:
1235 try:
1234 try:
1236 _rematcher('(?:%s)' % _regex(k, p, globsuffix))
1235 _rematcher(_regex(k, p, globsuffix))
1237 except re.error:
1236 except re.error:
1238 if s:
1237 if s:
1239 raise error.Abort(_("%s: invalid pattern (%s): %s") %
1238 raise error.Abort(_("%s: invalid pattern (%s): %s") %
1240 (s, k, p))
1239 (s, k, p))
1241 else:
1240 else:
1242 raise error.Abort(_("invalid pattern (%s): %s") % (k, p))
1241 raise error.Abort(_("invalid pattern (%s): %s") % (k, p))
1243 raise error.Abort(_("invalid pattern"))
1242 raise error.Abort(_("invalid pattern"))
1244
1243
1245 def _patternrootsanddirs(kindpats):
1244 def _patternrootsanddirs(kindpats):
1246 '''Returns roots and directories corresponding to each pattern.
1245 '''Returns roots and directories corresponding to each pattern.
1247
1246
1248 This calculates the roots and directories exactly matching the patterns and
1247 This calculates the roots and directories exactly matching the patterns and
1249 returns a tuple of (roots, dirs) for each. It does not return other
1248 returns a tuple of (roots, dirs) for each. It does not return other
1250 directories which may also need to be considered, like the parent
1249 directories which may also need to be considered, like the parent
1251 directories.
1250 directories.
1252 '''
1251 '''
1253 r = []
1252 r = []
1254 d = []
1253 d = []
1255 for kind, pat, source in kindpats:
1254 for kind, pat, source in kindpats:
1256 if kind == 'glob': # find the non-glob prefix
1255 if kind == 'glob': # find the non-glob prefix
1257 root = []
1256 root = []
1258 for p in pat.split('/'):
1257 for p in pat.split('/'):
1259 if '[' in p or '{' in p or '*' in p or '?' in p:
1258 if '[' in p or '{' in p or '*' in p or '?' in p:
1260 break
1259 break
1261 root.append(p)
1260 root.append(p)
1262 r.append('/'.join(root) or '.')
1261 r.append('/'.join(root) or '.')
1263 elif kind in ('relpath', 'path'):
1262 elif kind in ('relpath', 'path'):
1264 r.append(pat or '.')
1263 r.append(pat or '.')
1265 elif kind in ('rootfilesin',):
1264 elif kind in ('rootfilesin',):
1266 d.append(pat or '.')
1265 d.append(pat or '.')
1267 else: # relglob, re, relre
1266 else: # relglob, re, relre
1268 r.append('.')
1267 r.append('.')
1269 return r, d
1268 return r, d
1270
1269
1271 def _roots(kindpats):
1270 def _roots(kindpats):
1272 '''Returns root directories to match recursively from the given patterns.'''
1271 '''Returns root directories to match recursively from the given patterns.'''
1273 roots, dirs = _patternrootsanddirs(kindpats)
1272 roots, dirs = _patternrootsanddirs(kindpats)
1274 return roots
1273 return roots
1275
1274
1276 def _rootsdirsandparents(kindpats):
1275 def _rootsdirsandparents(kindpats):
1277 '''Returns roots and exact directories from patterns.
1276 '''Returns roots and exact directories from patterns.
1278
1277
1279 `roots` are directories to match recursively, `dirs` should
1278 `roots` are directories to match recursively, `dirs` should
1280 be matched non-recursively, and `parents` are the implicitly required
1279 be matched non-recursively, and `parents` are the implicitly required
1281 directories to walk to items in either roots or dirs.
1280 directories to walk to items in either roots or dirs.
1282
1281
1283 Returns a tuple of (roots, dirs, parents).
1282 Returns a tuple of (roots, dirs, parents).
1284
1283
1285 >>> _rootsdirsandparents(
1284 >>> _rootsdirsandparents(
1286 ... [(b'glob', b'g/h/*', b''), (b'glob', b'g/h', b''),
1285 ... [(b'glob', b'g/h/*', b''), (b'glob', b'g/h', b''),
1287 ... (b'glob', b'g*', b'')])
1286 ... (b'glob', b'g*', b'')])
1288 (['g/h', 'g/h', '.'], [], ['g', '.'])
1287 (['g/h', 'g/h', '.'], [], ['g', '.'])
1289 >>> _rootsdirsandparents(
1288 >>> _rootsdirsandparents(
1290 ... [(b'rootfilesin', b'g/h', b''), (b'rootfilesin', b'', b'')])
1289 ... [(b'rootfilesin', b'g/h', b''), (b'rootfilesin', b'', b'')])
1291 ([], ['g/h', '.'], ['g', '.'])
1290 ([], ['g/h', '.'], ['g', '.'])
1292 >>> _rootsdirsandparents(
1291 >>> _rootsdirsandparents(
1293 ... [(b'relpath', b'r', b''), (b'path', b'p/p', b''),
1292 ... [(b'relpath', b'r', b''), (b'path', b'p/p', b''),
1294 ... (b'path', b'', b'')])
1293 ... (b'path', b'', b'')])
1295 (['r', 'p/p', '.'], [], ['p', '.'])
1294 (['r', 'p/p', '.'], [], ['p', '.'])
1296 >>> _rootsdirsandparents(
1295 >>> _rootsdirsandparents(
1297 ... [(b'relglob', b'rg*', b''), (b're', b're/', b''),
1296 ... [(b'relglob', b'rg*', b''), (b're', b're/', b''),
1298 ... (b'relre', b'rr', b'')])
1297 ... (b'relre', b'rr', b'')])
1299 (['.', '.', '.'], [], ['.'])
1298 (['.', '.', '.'], [], ['.'])
1300 '''
1299 '''
1301 r, d = _patternrootsanddirs(kindpats)
1300 r, d = _patternrootsanddirs(kindpats)
1302
1301
1303 p = []
1302 p = []
1304 # Append the parents as non-recursive/exact directories, since they must be
1303 # Append the parents as non-recursive/exact directories, since they must be
1305 # scanned to get to either the roots or the other exact directories.
1304 # scanned to get to either the roots or the other exact directories.
1306 p.extend(util.dirs(d))
1305 p.extend(util.dirs(d))
1307 p.extend(util.dirs(r))
1306 p.extend(util.dirs(r))
1308 # util.dirs() does not include the root directory, so add it manually
1307 # util.dirs() does not include the root directory, so add it manually
1309 p.append('.')
1308 p.append('.')
1310
1309
1311 # FIXME: all uses of this function convert these to sets, do so before
1310 # FIXME: all uses of this function convert these to sets, do so before
1312 # returning.
1311 # returning.
1313 # FIXME: all uses of this function do not need anything in 'roots' and
1312 # FIXME: all uses of this function do not need anything in 'roots' and
1314 # 'dirs' to also be in 'parents', consider removing them before returning.
1313 # 'dirs' to also be in 'parents', consider removing them before returning.
1315 return r, d, p
1314 return r, d, p
1316
1315
1317 def _explicitfiles(kindpats):
1316 def _explicitfiles(kindpats):
1318 '''Returns the potential explicit filenames from the patterns.
1317 '''Returns the potential explicit filenames from the patterns.
1319
1318
1320 >>> _explicitfiles([(b'path', b'foo/bar', b'')])
1319 >>> _explicitfiles([(b'path', b'foo/bar', b'')])
1321 ['foo/bar']
1320 ['foo/bar']
1322 >>> _explicitfiles([(b'rootfilesin', b'foo/bar', b'')])
1321 >>> _explicitfiles([(b'rootfilesin', b'foo/bar', b'')])
1323 []
1322 []
1324 '''
1323 '''
1325 # Keep only the pattern kinds where one can specify filenames (vs only
1324 # Keep only the pattern kinds where one can specify filenames (vs only
1326 # directory names).
1325 # directory names).
1327 filable = [kp for kp in kindpats if kp[0] not in ('rootfilesin',)]
1326 filable = [kp for kp in kindpats if kp[0] not in ('rootfilesin',)]
1328 return _roots(filable)
1327 return _roots(filable)
1329
1328
1330 def _prefix(kindpats):
1329 def _prefix(kindpats):
1331 '''Whether all the patterns match a prefix (i.e. recursively)'''
1330 '''Whether all the patterns match a prefix (i.e. recursively)'''
1332 for kind, pat, source in kindpats:
1331 for kind, pat, source in kindpats:
1333 if kind not in ('path', 'relpath'):
1332 if kind not in ('path', 'relpath'):
1334 return False
1333 return False
1335 return True
1334 return True
1336
1335
1337 _commentre = None
1336 _commentre = None
1338
1337
1339 def readpatternfile(filepath, warn, sourceinfo=False):
1338 def readpatternfile(filepath, warn, sourceinfo=False):
1340 '''parse a pattern file, returning a list of
1339 '''parse a pattern file, returning a list of
1341 patterns. These patterns should be given to compile()
1340 patterns. These patterns should be given to compile()
1342 to be validated and converted into a match function.
1341 to be validated and converted into a match function.
1343
1342
1344 trailing white space is dropped.
1343 trailing white space is dropped.
1345 the escape character is backslash.
1344 the escape character is backslash.
1346 comments start with #.
1345 comments start with #.
1347 empty lines are skipped.
1346 empty lines are skipped.
1348
1347
1349 lines can be of the following formats:
1348 lines can be of the following formats:
1350
1349
1351 syntax: regexp # defaults following lines to non-rooted regexps
1350 syntax: regexp # defaults following lines to non-rooted regexps
1352 syntax: glob # defaults following lines to non-rooted globs
1351 syntax: glob # defaults following lines to non-rooted globs
1353 re:pattern # non-rooted regular expression
1352 re:pattern # non-rooted regular expression
1354 glob:pattern # non-rooted glob
1353 glob:pattern # non-rooted glob
1355 pattern # pattern of the current default type
1354 pattern # pattern of the current default type
1356
1355
1357 if sourceinfo is set, returns a list of tuples:
1356 if sourceinfo is set, returns a list of tuples:
1358 (pattern, lineno, originalline). This is useful to debug ignore patterns.
1357 (pattern, lineno, originalline). This is useful to debug ignore patterns.
1359 '''
1358 '''
1360
1359
1361 syntaxes = {
1360 syntaxes = {
1362 're': 'relre:',
1361 're': 'relre:',
1363 'regexp': 'relre:',
1362 'regexp': 'relre:',
1364 'glob': 'relglob:',
1363 'glob': 'relglob:',
1365 'include': 'include',
1364 'include': 'include',
1366 'subinclude': 'subinclude',
1365 'subinclude': 'subinclude',
1367 }
1366 }
1368 syntax = 'relre:'
1367 syntax = 'relre:'
1369 patterns = []
1368 patterns = []
1370
1369
1371 fp = open(filepath, 'rb')
1370 fp = open(filepath, 'rb')
1372 for lineno, line in enumerate(util.iterfile(fp), start=1):
1371 for lineno, line in enumerate(util.iterfile(fp), start=1):
1373 if "#" in line:
1372 if "#" in line:
1374 global _commentre
1373 global _commentre
1375 if not _commentre:
1374 if not _commentre:
1376 _commentre = util.re.compile(br'((?:^|[^\\])(?:\\\\)*)#.*')
1375 _commentre = util.re.compile(br'((?:^|[^\\])(?:\\\\)*)#.*')
1377 # remove comments prefixed by an even number of escapes
1376 # remove comments prefixed by an even number of escapes
1378 m = _commentre.search(line)
1377 m = _commentre.search(line)
1379 if m:
1378 if m:
1380 line = line[:m.end(1)]
1379 line = line[:m.end(1)]
1381 # fixup properly escaped comments that survived the above
1380 # fixup properly escaped comments that survived the above
1382 line = line.replace("\\#", "#")
1381 line = line.replace("\\#", "#")
1383 line = line.rstrip()
1382 line = line.rstrip()
1384 if not line:
1383 if not line:
1385 continue
1384 continue
1386
1385
1387 if line.startswith('syntax:'):
1386 if line.startswith('syntax:'):
1388 s = line[7:].strip()
1387 s = line[7:].strip()
1389 try:
1388 try:
1390 syntax = syntaxes[s]
1389 syntax = syntaxes[s]
1391 except KeyError:
1390 except KeyError:
1392 if warn:
1391 if warn:
1393 warn(_("%s: ignoring invalid syntax '%s'\n") %
1392 warn(_("%s: ignoring invalid syntax '%s'\n") %
1394 (filepath, s))
1393 (filepath, s))
1395 continue
1394 continue
1396
1395
1397 linesyntax = syntax
1396 linesyntax = syntax
1398 for s, rels in syntaxes.iteritems():
1397 for s, rels in syntaxes.iteritems():
1399 if line.startswith(rels):
1398 if line.startswith(rels):
1400 linesyntax = rels
1399 linesyntax = rels
1401 line = line[len(rels):]
1400 line = line[len(rels):]
1402 break
1401 break
1403 elif line.startswith(s+':'):
1402 elif line.startswith(s+':'):
1404 linesyntax = rels
1403 linesyntax = rels
1405 line = line[len(s) + 1:]
1404 line = line[len(s) + 1:]
1406 break
1405 break
1407 if sourceinfo:
1406 if sourceinfo:
1408 patterns.append((linesyntax + line, lineno, line))
1407 patterns.append((linesyntax + line, lineno, line))
1409 else:
1408 else:
1410 patterns.append(linesyntax + line)
1409 patterns.append(linesyntax + line)
1411 fp.close()
1410 fp.close()
1412 return patterns
1411 return patterns
@@ -1,1037 +1,1037 b''
1 $ fileset() {
1 $ fileset() {
2 > hg debugfileset --all-files "$@"
2 > hg debugfileset --all-files "$@"
3 > }
3 > }
4
4
5 $ hg init repo
5 $ hg init repo
6 $ cd repo
6 $ cd repo
7 $ echo a > a1
7 $ echo a > a1
8 $ echo a > a2
8 $ echo a > a2
9 $ echo b > b1
9 $ echo b > b1
10 $ echo b > b2
10 $ echo b > b2
11 $ hg ci -Am addfiles
11 $ hg ci -Am addfiles
12 adding a1
12 adding a1
13 adding a2
13 adding a2
14 adding b1
14 adding b1
15 adding b2
15 adding b2
16
16
17 Test operators and basic patterns
17 Test operators and basic patterns
18
18
19 $ fileset -v a1
19 $ fileset -v a1
20 (symbol 'a1')
20 (symbol 'a1')
21 * matcher:
21 * matcher:
22 <patternmatcher patterns='(?:a1$)'>
22 <patternmatcher patterns='a1$'>
23 a1
23 a1
24 $ fileset -v 'a*'
24 $ fileset -v 'a*'
25 (symbol 'a*')
25 (symbol 'a*')
26 * matcher:
26 * matcher:
27 <patternmatcher patterns='(?:a[^/]*$)'>
27 <patternmatcher patterns='a[^/]*$'>
28 a1
28 a1
29 a2
29 a2
30 $ fileset -v '"re:a\d"'
30 $ fileset -v '"re:a\d"'
31 (string 're:a\\d')
31 (string 're:a\\d')
32 * matcher:
32 * matcher:
33 <patternmatcher patterns='(?:a\\d)'>
33 <patternmatcher patterns='a\\d'>
34 a1
34 a1
35 a2
35 a2
36 $ fileset -v '!re:"a\d"'
36 $ fileset -v '!re:"a\d"'
37 (not
37 (not
38 (kindpat
38 (kindpat
39 (symbol 're')
39 (symbol 're')
40 (string 'a\\d')))
40 (string 'a\\d')))
41 * matcher:
41 * matcher:
42 <predicatenmatcher
42 <predicatenmatcher
43 pred=<not
43 pred=<not
44 <patternmatcher patterns='(?:a\\d)'>>>
44 <patternmatcher patterns='a\\d'>>>
45 b1
45 b1
46 b2
46 b2
47 $ fileset -v 'path:a1 or glob:b?'
47 $ fileset -v 'path:a1 or glob:b?'
48 (or
48 (or
49 (kindpat
49 (kindpat
50 (symbol 'path')
50 (symbol 'path')
51 (symbol 'a1'))
51 (symbol 'a1'))
52 (kindpat
52 (kindpat
53 (symbol 'glob')
53 (symbol 'glob')
54 (symbol 'b?')))
54 (symbol 'b?')))
55 * matcher:
55 * matcher:
56 <patternmatcher patterns='(?:a1(?:/|$)|b.$)'>
56 <patternmatcher patterns='a1(?:/|$)|b.$'>
57 a1
57 a1
58 b1
58 b1
59 b2
59 b2
60 $ fileset -v --no-show-matcher 'a1 or a2'
60 $ fileset -v --no-show-matcher 'a1 or a2'
61 (or
61 (or
62 (symbol 'a1')
62 (symbol 'a1')
63 (symbol 'a2'))
63 (symbol 'a2'))
64 a1
64 a1
65 a2
65 a2
66 $ fileset 'a1 | a2'
66 $ fileset 'a1 | a2'
67 a1
67 a1
68 a2
68 a2
69 $ fileset 'a* and "*1"'
69 $ fileset 'a* and "*1"'
70 a1
70 a1
71 $ fileset 'a* & "*1"'
71 $ fileset 'a* & "*1"'
72 a1
72 a1
73 $ fileset 'not (r"a*")'
73 $ fileset 'not (r"a*")'
74 b1
74 b1
75 b2
75 b2
76 $ fileset '! ("a*")'
76 $ fileset '! ("a*")'
77 b1
77 b1
78 b2
78 b2
79 $ fileset 'a* - a1'
79 $ fileset 'a* - a1'
80 a2
80 a2
81 $ fileset 'a_b'
81 $ fileset 'a_b'
82 $ fileset '"\xy"'
82 $ fileset '"\xy"'
83 hg: parse error: invalid \x escape* (glob)
83 hg: parse error: invalid \x escape* (glob)
84 [255]
84 [255]
85
85
86 Test invalid syntax
86 Test invalid syntax
87
87
88 $ fileset -v '"added"()'
88 $ fileset -v '"added"()'
89 (func
89 (func
90 (string 'added')
90 (string 'added')
91 None)
91 None)
92 hg: parse error: not a symbol
92 hg: parse error: not a symbol
93 [255]
93 [255]
94 $ fileset -v '()()'
94 $ fileset -v '()()'
95 (func
95 (func
96 (group
96 (group
97 None)
97 None)
98 None)
98 None)
99 hg: parse error: not a symbol
99 hg: parse error: not a symbol
100 [255]
100 [255]
101 $ fileset -v -- '-x'
101 $ fileset -v -- '-x'
102 (negate
102 (negate
103 (symbol 'x'))
103 (symbol 'x'))
104 hg: parse error: can't use negate operator in this context
104 hg: parse error: can't use negate operator in this context
105 [255]
105 [255]
106 $ fileset -v -- '-()'
106 $ fileset -v -- '-()'
107 (negate
107 (negate
108 (group
108 (group
109 None))
109 None))
110 hg: parse error: can't use negate operator in this context
110 hg: parse error: can't use negate operator in this context
111 [255]
111 [255]
112 $ fileset -p parsed 'a, b, c'
112 $ fileset -p parsed 'a, b, c'
113 * parsed:
113 * parsed:
114 (list
114 (list
115 (symbol 'a')
115 (symbol 'a')
116 (symbol 'b')
116 (symbol 'b')
117 (symbol 'c'))
117 (symbol 'c'))
118 hg: parse error: can't use a list in this context
118 hg: parse error: can't use a list in this context
119 (see 'hg help "filesets.x or y"')
119 (see 'hg help "filesets.x or y"')
120 [255]
120 [255]
121
121
122 $ fileset '"path":.'
122 $ fileset '"path":.'
123 hg: parse error: not a symbol
123 hg: parse error: not a symbol
124 [255]
124 [255]
125 $ fileset 'path:foo bar'
125 $ fileset 'path:foo bar'
126 hg: parse error at 9: invalid token
126 hg: parse error at 9: invalid token
127 [255]
127 [255]
128 $ fileset 'foo:bar:baz'
128 $ fileset 'foo:bar:baz'
129 hg: parse error: not a symbol
129 hg: parse error: not a symbol
130 [255]
130 [255]
131 $ fileset 'foo:bar()'
131 $ fileset 'foo:bar()'
132 hg: parse error: pattern must be a string
132 hg: parse error: pattern must be a string
133 [255]
133 [255]
134 $ fileset 'foo:bar'
134 $ fileset 'foo:bar'
135 hg: parse error: invalid pattern kind: foo
135 hg: parse error: invalid pattern kind: foo
136 [255]
136 [255]
137
137
138 Show parsed tree at stages:
138 Show parsed tree at stages:
139
139
140 $ fileset -p unknown a
140 $ fileset -p unknown a
141 abort: invalid stage name: unknown
141 abort: invalid stage name: unknown
142 [255]
142 [255]
143
143
144 $ fileset -p parsed 'path:a1 or glob:b?'
144 $ fileset -p parsed 'path:a1 or glob:b?'
145 * parsed:
145 * parsed:
146 (or
146 (or
147 (kindpat
147 (kindpat
148 (symbol 'path')
148 (symbol 'path')
149 (symbol 'a1'))
149 (symbol 'a1'))
150 (kindpat
150 (kindpat
151 (symbol 'glob')
151 (symbol 'glob')
152 (symbol 'b?')))
152 (symbol 'b?')))
153 a1
153 a1
154 b1
154 b1
155 b2
155 b2
156
156
157 $ fileset -p all -s 'a1 or a2 or (grep("b") & clean())'
157 $ fileset -p all -s 'a1 or a2 or (grep("b") & clean())'
158 * parsed:
158 * parsed:
159 (or
159 (or
160 (symbol 'a1')
160 (symbol 'a1')
161 (symbol 'a2')
161 (symbol 'a2')
162 (group
162 (group
163 (and
163 (and
164 (func
164 (func
165 (symbol 'grep')
165 (symbol 'grep')
166 (string 'b'))
166 (string 'b'))
167 (func
167 (func
168 (symbol 'clean')
168 (symbol 'clean')
169 None))))
169 None))))
170 * analyzed:
170 * analyzed:
171 (or
171 (or
172 (symbol 'a1')
172 (symbol 'a1')
173 (symbol 'a2')
173 (symbol 'a2')
174 (and
174 (and
175 (func
175 (func
176 (symbol 'grep')
176 (symbol 'grep')
177 (string 'b'))
177 (string 'b'))
178 (withstatus
178 (withstatus
179 (func
179 (func
180 (symbol 'clean')
180 (symbol 'clean')
181 None)
181 None)
182 (string 'clean'))))
182 (string 'clean'))))
183 * optimized:
183 * optimized:
184 (or
184 (or
185 (patterns
185 (patterns
186 (symbol 'a1')
186 (symbol 'a1')
187 (symbol 'a2'))
187 (symbol 'a2'))
188 (and
188 (and
189 (withstatus
189 (withstatus
190 (func
190 (func
191 (symbol 'clean')
191 (symbol 'clean')
192 None)
192 None)
193 (string 'clean'))
193 (string 'clean'))
194 (func
194 (func
195 (symbol 'grep')
195 (symbol 'grep')
196 (string 'b'))))
196 (string 'b'))))
197 * matcher:
197 * matcher:
198 <unionmatcher matchers=[
198 <unionmatcher matchers=[
199 <patternmatcher patterns='(?:a1$|a2$)'>,
199 <patternmatcher patterns='a1$|a2$'>,
200 <intersectionmatcher
200 <intersectionmatcher
201 m1=<predicatenmatcher pred=clean>,
201 m1=<predicatenmatcher pred=clean>,
202 m2=<predicatenmatcher pred=grep('b')>>]>
202 m2=<predicatenmatcher pred=grep('b')>>]>
203 a1
203 a1
204 a2
204 a2
205 b1
205 b1
206 b2
206 b2
207
207
208 Union of basic patterns:
208 Union of basic patterns:
209
209
210 $ fileset -p optimized -s -r. 'a1 or a2 or path:b1'
210 $ fileset -p optimized -s -r. 'a1 or a2 or path:b1'
211 * optimized:
211 * optimized:
212 (patterns
212 (patterns
213 (symbol 'a1')
213 (symbol 'a1')
214 (symbol 'a2')
214 (symbol 'a2')
215 (kindpat
215 (kindpat
216 (symbol 'path')
216 (symbol 'path')
217 (symbol 'b1')))
217 (symbol 'b1')))
218 * matcher:
218 * matcher:
219 <patternmatcher patterns='(?:a1$|a2$|b1(?:/|$))'>
219 <patternmatcher patterns='a1$|a2$|b1(?:/|$)'>
220 a1
220 a1
221 a2
221 a2
222 b1
222 b1
223
223
224 OR expression should be reordered by weight:
224 OR expression should be reordered by weight:
225
225
226 $ fileset -p optimized -s -r. 'grep("a") or a1 or grep("b") or b2'
226 $ fileset -p optimized -s -r. 'grep("a") or a1 or grep("b") or b2'
227 * optimized:
227 * optimized:
228 (or
228 (or
229 (patterns
229 (patterns
230 (symbol 'a1')
230 (symbol 'a1')
231 (symbol 'b2'))
231 (symbol 'b2'))
232 (func
232 (func
233 (symbol 'grep')
233 (symbol 'grep')
234 (string 'a'))
234 (string 'a'))
235 (func
235 (func
236 (symbol 'grep')
236 (symbol 'grep')
237 (string 'b')))
237 (string 'b')))
238 * matcher:
238 * matcher:
239 <unionmatcher matchers=[
239 <unionmatcher matchers=[
240 <patternmatcher patterns='(?:a1$|b2$)'>,
240 <patternmatcher patterns='a1$|b2$'>,
241 <predicatenmatcher pred=grep('a')>,
241 <predicatenmatcher pred=grep('a')>,
242 <predicatenmatcher pred=grep('b')>]>
242 <predicatenmatcher pred=grep('b')>]>
243 a1
243 a1
244 a2
244 a2
245 b1
245 b1
246 b2
246 b2
247
247
248 Use differencematcher for 'x and not y':
248 Use differencematcher for 'x and not y':
249
249
250 $ fileset -p optimized -s 'a* and not a1'
250 $ fileset -p optimized -s 'a* and not a1'
251 * optimized:
251 * optimized:
252 (minus
252 (minus
253 (symbol 'a*')
253 (symbol 'a*')
254 (symbol 'a1'))
254 (symbol 'a1'))
255 * matcher:
255 * matcher:
256 <differencematcher
256 <differencematcher
257 m1=<patternmatcher patterns='(?:a[^/]*$)'>,
257 m1=<patternmatcher patterns='a[^/]*$'>,
258 m2=<patternmatcher patterns='(?:a1$)'>>
258 m2=<patternmatcher patterns='a1$'>>
259 a2
259 a2
260
260
261 $ fileset -p optimized -s '!binary() and a*'
261 $ fileset -p optimized -s '!binary() and a*'
262 * optimized:
262 * optimized:
263 (minus
263 (minus
264 (symbol 'a*')
264 (symbol 'a*')
265 (func
265 (func
266 (symbol 'binary')
266 (symbol 'binary')
267 None))
267 None))
268 * matcher:
268 * matcher:
269 <differencematcher
269 <differencematcher
270 m1=<patternmatcher patterns='(?:a[^/]*$)'>,
270 m1=<patternmatcher patterns='a[^/]*$'>,
271 m2=<predicatenmatcher pred=binary>>
271 m2=<predicatenmatcher pred=binary>>
272 a1
272 a1
273 a2
273 a2
274
274
275 'x - y' is rewritten to 'x and not y' first so the operands can be reordered:
275 'x - y' is rewritten to 'x and not y' first so the operands can be reordered:
276
276
277 $ fileset -p analyzed -p optimized -s 'a* - a1'
277 $ fileset -p analyzed -p optimized -s 'a* - a1'
278 * analyzed:
278 * analyzed:
279 (and
279 (and
280 (symbol 'a*')
280 (symbol 'a*')
281 (not
281 (not
282 (symbol 'a1')))
282 (symbol 'a1')))
283 * optimized:
283 * optimized:
284 (minus
284 (minus
285 (symbol 'a*')
285 (symbol 'a*')
286 (symbol 'a1'))
286 (symbol 'a1'))
287 * matcher:
287 * matcher:
288 <differencematcher
288 <differencematcher
289 m1=<patternmatcher patterns='(?:a[^/]*$)'>,
289 m1=<patternmatcher patterns='a[^/]*$'>,
290 m2=<patternmatcher patterns='(?:a1$)'>>
290 m2=<patternmatcher patterns='a1$'>>
291 a2
291 a2
292
292
293 $ fileset -p analyzed -p optimized -s 'binary() - a*'
293 $ fileset -p analyzed -p optimized -s 'binary() - a*'
294 * analyzed:
294 * analyzed:
295 (and
295 (and
296 (func
296 (func
297 (symbol 'binary')
297 (symbol 'binary')
298 None)
298 None)
299 (not
299 (not
300 (symbol 'a*')))
300 (symbol 'a*')))
301 * optimized:
301 * optimized:
302 (and
302 (and
303 (not
303 (not
304 (symbol 'a*'))
304 (symbol 'a*'))
305 (func
305 (func
306 (symbol 'binary')
306 (symbol 'binary')
307 None))
307 None))
308 * matcher:
308 * matcher:
309 <intersectionmatcher
309 <intersectionmatcher
310 m1=<predicatenmatcher
310 m1=<predicatenmatcher
311 pred=<not
311 pred=<not
312 <patternmatcher patterns='(?:a[^/]*$)'>>>,
312 <patternmatcher patterns='a[^/]*$'>>>,
313 m2=<predicatenmatcher pred=binary>>
313 m2=<predicatenmatcher pred=binary>>
314
314
315 Test files status
315 Test files status
316
316
317 $ rm a1
317 $ rm a1
318 $ hg rm a2
318 $ hg rm a2
319 $ echo b >> b2
319 $ echo b >> b2
320 $ hg cp b1 c1
320 $ hg cp b1 c1
321 $ echo c > c2
321 $ echo c > c2
322 $ echo c > c3
322 $ echo c > c3
323 $ cat > .hgignore <<EOF
323 $ cat > .hgignore <<EOF
324 > \.hgignore
324 > \.hgignore
325 > 2$
325 > 2$
326 > EOF
326 > EOF
327 $ fileset 'modified()'
327 $ fileset 'modified()'
328 b2
328 b2
329 $ fileset 'added()'
329 $ fileset 'added()'
330 c1
330 c1
331 $ fileset 'removed()'
331 $ fileset 'removed()'
332 a2
332 a2
333 $ fileset 'deleted()'
333 $ fileset 'deleted()'
334 a1
334 a1
335 $ fileset 'missing()'
335 $ fileset 'missing()'
336 a1
336 a1
337 $ fileset 'unknown()'
337 $ fileset 'unknown()'
338 c3
338 c3
339 $ fileset 'ignored()'
339 $ fileset 'ignored()'
340 .hgignore
340 .hgignore
341 c2
341 c2
342 $ fileset 'hgignore()'
342 $ fileset 'hgignore()'
343 .hgignore
343 .hgignore
344 a2
344 a2
345 b2
345 b2
346 c2
346 c2
347 $ fileset 'clean()'
347 $ fileset 'clean()'
348 b1
348 b1
349 $ fileset 'copied()'
349 $ fileset 'copied()'
350 c1
350 c1
351
351
352 Test files status in different revisions
352 Test files status in different revisions
353
353
354 $ hg status -m
354 $ hg status -m
355 M b2
355 M b2
356 $ fileset -r0 'revs("wdir()", modified())' --traceback
356 $ fileset -r0 'revs("wdir()", modified())' --traceback
357 b2
357 b2
358 $ hg status -a
358 $ hg status -a
359 A c1
359 A c1
360 $ fileset -r0 'revs("wdir()", added())'
360 $ fileset -r0 'revs("wdir()", added())'
361 c1
361 c1
362 $ hg status --change 0 -a
362 $ hg status --change 0 -a
363 A a1
363 A a1
364 A a2
364 A a2
365 A b1
365 A b1
366 A b2
366 A b2
367 $ hg status -mru
367 $ hg status -mru
368 M b2
368 M b2
369 R a2
369 R a2
370 ? c3
370 ? c3
371 $ fileset -r0 'added() and revs("wdir()", modified() or removed() or unknown())'
371 $ fileset -r0 'added() and revs("wdir()", modified() or removed() or unknown())'
372 a2
372 a2
373 b2
373 b2
374 $ fileset -r0 'added() or revs("wdir()", added())'
374 $ fileset -r0 'added() or revs("wdir()", added())'
375 a1
375 a1
376 a2
376 a2
377 b1
377 b1
378 b2
378 b2
379 c1
379 c1
380
380
381 Test insertion of status hints
381 Test insertion of status hints
382
382
383 $ fileset -p optimized 'added()'
383 $ fileset -p optimized 'added()'
384 * optimized:
384 * optimized:
385 (withstatus
385 (withstatus
386 (func
386 (func
387 (symbol 'added')
387 (symbol 'added')
388 None)
388 None)
389 (string 'added'))
389 (string 'added'))
390 c1
390 c1
391
391
392 $ fileset -p optimized 'a* & removed()'
392 $ fileset -p optimized 'a* & removed()'
393 * optimized:
393 * optimized:
394 (and
394 (and
395 (symbol 'a*')
395 (symbol 'a*')
396 (withstatus
396 (withstatus
397 (func
397 (func
398 (symbol 'removed')
398 (symbol 'removed')
399 None)
399 None)
400 (string 'removed')))
400 (string 'removed')))
401 a2
401 a2
402
402
403 $ fileset -p optimized 'a* - removed()'
403 $ fileset -p optimized 'a* - removed()'
404 * optimized:
404 * optimized:
405 (minus
405 (minus
406 (symbol 'a*')
406 (symbol 'a*')
407 (withstatus
407 (withstatus
408 (func
408 (func
409 (symbol 'removed')
409 (symbol 'removed')
410 None)
410 None)
411 (string 'removed')))
411 (string 'removed')))
412 a1
412 a1
413
413
414 $ fileset -p analyzed -p optimized '(added() + removed()) - a*'
414 $ fileset -p analyzed -p optimized '(added() + removed()) - a*'
415 * analyzed:
415 * analyzed:
416 (and
416 (and
417 (withstatus
417 (withstatus
418 (or
418 (or
419 (func
419 (func
420 (symbol 'added')
420 (symbol 'added')
421 None)
421 None)
422 (func
422 (func
423 (symbol 'removed')
423 (symbol 'removed')
424 None))
424 None))
425 (string 'added removed'))
425 (string 'added removed'))
426 (not
426 (not
427 (symbol 'a*')))
427 (symbol 'a*')))
428 * optimized:
428 * optimized:
429 (and
429 (and
430 (not
430 (not
431 (symbol 'a*'))
431 (symbol 'a*'))
432 (withstatus
432 (withstatus
433 (or
433 (or
434 (func
434 (func
435 (symbol 'added')
435 (symbol 'added')
436 None)
436 None)
437 (func
437 (func
438 (symbol 'removed')
438 (symbol 'removed')
439 None))
439 None))
440 (string 'added removed')))
440 (string 'added removed')))
441 c1
441 c1
442
442
443 $ fileset -p optimized 'a* + b* + added() + unknown()'
443 $ fileset -p optimized 'a* + b* + added() + unknown()'
444 * optimized:
444 * optimized:
445 (withstatus
445 (withstatus
446 (or
446 (or
447 (patterns
447 (patterns
448 (symbol 'a*')
448 (symbol 'a*')
449 (symbol 'b*'))
449 (symbol 'b*'))
450 (func
450 (func
451 (symbol 'added')
451 (symbol 'added')
452 None)
452 None)
453 (func
453 (func
454 (symbol 'unknown')
454 (symbol 'unknown')
455 None))
455 None))
456 (string 'added unknown'))
456 (string 'added unknown'))
457 a1
457 a1
458 a2
458 a2
459 b1
459 b1
460 b2
460 b2
461 c1
461 c1
462 c3
462 c3
463
463
464 $ fileset -p analyzed -p optimized 'removed() & missing() & a*'
464 $ fileset -p analyzed -p optimized 'removed() & missing() & a*'
465 * analyzed:
465 * analyzed:
466 (and
466 (and
467 (withstatus
467 (withstatus
468 (and
468 (and
469 (func
469 (func
470 (symbol 'removed')
470 (symbol 'removed')
471 None)
471 None)
472 (func
472 (func
473 (symbol 'missing')
473 (symbol 'missing')
474 None))
474 None))
475 (string 'removed missing'))
475 (string 'removed missing'))
476 (symbol 'a*'))
476 (symbol 'a*'))
477 * optimized:
477 * optimized:
478 (and
478 (and
479 (symbol 'a*')
479 (symbol 'a*')
480 (withstatus
480 (withstatus
481 (and
481 (and
482 (func
482 (func
483 (symbol 'removed')
483 (symbol 'removed')
484 None)
484 None)
485 (func
485 (func
486 (symbol 'missing')
486 (symbol 'missing')
487 None))
487 None))
488 (string 'removed missing')))
488 (string 'removed missing')))
489
489
490 $ fileset -p optimized 'clean() & revs(0, added())'
490 $ fileset -p optimized 'clean() & revs(0, added())'
491 * optimized:
491 * optimized:
492 (and
492 (and
493 (withstatus
493 (withstatus
494 (func
494 (func
495 (symbol 'clean')
495 (symbol 'clean')
496 None)
496 None)
497 (string 'clean'))
497 (string 'clean'))
498 (func
498 (func
499 (symbol 'revs')
499 (symbol 'revs')
500 (list
500 (list
501 (symbol '0')
501 (symbol '0')
502 (withstatus
502 (withstatus
503 (func
503 (func
504 (symbol 'added')
504 (symbol 'added')
505 None)
505 None)
506 (string 'added')))))
506 (string 'added')))))
507 b1
507 b1
508
508
509 $ fileset -p optimized 'clean() & status(null, 0, b* & added())'
509 $ fileset -p optimized 'clean() & status(null, 0, b* & added())'
510 * optimized:
510 * optimized:
511 (and
511 (and
512 (withstatus
512 (withstatus
513 (func
513 (func
514 (symbol 'clean')
514 (symbol 'clean')
515 None)
515 None)
516 (string 'clean'))
516 (string 'clean'))
517 (func
517 (func
518 (symbol 'status')
518 (symbol 'status')
519 (list
519 (list
520 (symbol 'null')
520 (symbol 'null')
521 (symbol '0')
521 (symbol '0')
522 (and
522 (and
523 (symbol 'b*')
523 (symbol 'b*')
524 (withstatus
524 (withstatus
525 (func
525 (func
526 (symbol 'added')
526 (symbol 'added')
527 None)
527 None)
528 (string 'added'))))))
528 (string 'added'))))))
529 b1
529 b1
530
530
531 Test files properties
531 Test files properties
532
532
533 >>> open('bin', 'wb').write(b'\0a') and None
533 >>> open('bin', 'wb').write(b'\0a') and None
534 $ fileset 'binary()'
534 $ fileset 'binary()'
535 bin
535 bin
536 $ fileset 'binary() and unknown()'
536 $ fileset 'binary() and unknown()'
537 bin
537 bin
538 $ echo '^bin$' >> .hgignore
538 $ echo '^bin$' >> .hgignore
539 $ fileset 'binary() and ignored()'
539 $ fileset 'binary() and ignored()'
540 bin
540 bin
541 $ hg add bin
541 $ hg add bin
542 $ fileset 'binary()'
542 $ fileset 'binary()'
543 bin
543 bin
544
544
545 $ fileset -p optimized -s 'binary() and b*'
545 $ fileset -p optimized -s 'binary() and b*'
546 * optimized:
546 * optimized:
547 (and
547 (and
548 (symbol 'b*')
548 (symbol 'b*')
549 (func
549 (func
550 (symbol 'binary')
550 (symbol 'binary')
551 None))
551 None))
552 * matcher:
552 * matcher:
553 <intersectionmatcher
553 <intersectionmatcher
554 m1=<patternmatcher patterns='(?:b[^/]*$)'>,
554 m1=<patternmatcher patterns='b[^/]*$'>,
555 m2=<predicatenmatcher pred=binary>>
555 m2=<predicatenmatcher pred=binary>>
556 bin
556 bin
557
557
558 $ fileset 'grep("b{1}")'
558 $ fileset 'grep("b{1}")'
559 .hgignore
559 .hgignore
560 b1
560 b1
561 b2
561 b2
562 c1
562 c1
563 $ fileset 'grep("missingparens(")'
563 $ fileset 'grep("missingparens(")'
564 hg: parse error: invalid match pattern: (unbalanced parenthesis|missing \)).* (re)
564 hg: parse error: invalid match pattern: (unbalanced parenthesis|missing \)).* (re)
565 [255]
565 [255]
566
566
567 #if execbit
567 #if execbit
568 $ chmod +x b2
568 $ chmod +x b2
569 $ fileset 'exec()'
569 $ fileset 'exec()'
570 b2
570 b2
571 #endif
571 #endif
572
572
573 #if symlink
573 #if symlink
574 $ ln -s b2 b2link
574 $ ln -s b2 b2link
575 $ fileset 'symlink() and unknown()'
575 $ fileset 'symlink() and unknown()'
576 b2link
576 b2link
577 $ hg add b2link
577 $ hg add b2link
578 #endif
578 #endif
579
579
580 #if no-windows
580 #if no-windows
581 $ echo foo > con.xml
581 $ echo foo > con.xml
582 $ fileset 'not portable()'
582 $ fileset 'not portable()'
583 con.xml
583 con.xml
584 $ hg --config ui.portablefilenames=ignore add con.xml
584 $ hg --config ui.portablefilenames=ignore add con.xml
585 #endif
585 #endif
586
586
587 >>> open('1k', 'wb').write(b' '*1024) and None
587 >>> open('1k', 'wb').write(b' '*1024) and None
588 >>> open('2k', 'wb').write(b' '*2048) and None
588 >>> open('2k', 'wb').write(b' '*2048) and None
589 $ hg add 1k 2k
589 $ hg add 1k 2k
590 $ fileset 'size("bar")'
590 $ fileset 'size("bar")'
591 hg: parse error: couldn't parse size: bar
591 hg: parse error: couldn't parse size: bar
592 [255]
592 [255]
593 $ fileset '(1k, 2k)'
593 $ fileset '(1k, 2k)'
594 hg: parse error: can't use a list in this context
594 hg: parse error: can't use a list in this context
595 (see 'hg help "filesets.x or y"')
595 (see 'hg help "filesets.x or y"')
596 [255]
596 [255]
597 $ fileset 'size(1k)'
597 $ fileset 'size(1k)'
598 1k
598 1k
599 $ fileset '(1k or 2k) and size("< 2k")'
599 $ fileset '(1k or 2k) and size("< 2k")'
600 1k
600 1k
601 $ fileset '(1k or 2k) and size("<=2k")'
601 $ fileset '(1k or 2k) and size("<=2k")'
602 1k
602 1k
603 2k
603 2k
604 $ fileset '(1k or 2k) and size("> 1k")'
604 $ fileset '(1k or 2k) and size("> 1k")'
605 2k
605 2k
606 $ fileset '(1k or 2k) and size(">=1K")'
606 $ fileset '(1k or 2k) and size(">=1K")'
607 1k
607 1k
608 2k
608 2k
609 $ fileset '(1k or 2k) and size(".5KB - 1.5kB")'
609 $ fileset '(1k or 2k) and size(".5KB - 1.5kB")'
610 1k
610 1k
611 $ fileset 'size("1M")'
611 $ fileset 'size("1M")'
612 $ fileset 'size("1 GB")'
612 $ fileset 'size("1 GB")'
613
613
614 Test merge states
614 Test merge states
615
615
616 $ hg ci -m manychanges
616 $ hg ci -m manychanges
617 $ hg file -r . 'set:copied() & modified()'
617 $ hg file -r . 'set:copied() & modified()'
618 [1]
618 [1]
619 $ hg up -C 0
619 $ hg up -C 0
620 * files updated, 0 files merged, * files removed, 0 files unresolved (glob)
620 * files updated, 0 files merged, * files removed, 0 files unresolved (glob)
621 $ echo c >> b2
621 $ echo c >> b2
622 $ hg ci -m diverging b2
622 $ hg ci -m diverging b2
623 created new head
623 created new head
624 $ fileset 'resolved()'
624 $ fileset 'resolved()'
625 $ fileset 'unresolved()'
625 $ fileset 'unresolved()'
626 $ hg merge
626 $ hg merge
627 merging b2
627 merging b2
628 warning: conflicts while merging b2! (edit, then use 'hg resolve --mark')
628 warning: conflicts while merging b2! (edit, then use 'hg resolve --mark')
629 * files updated, 0 files merged, 1 files removed, 1 files unresolved (glob)
629 * files updated, 0 files merged, 1 files removed, 1 files unresolved (glob)
630 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
630 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
631 [1]
631 [1]
632 $ fileset 'resolved()'
632 $ fileset 'resolved()'
633 $ fileset 'unresolved()'
633 $ fileset 'unresolved()'
634 b2
634 b2
635 $ echo e > b2
635 $ echo e > b2
636 $ hg resolve -m b2
636 $ hg resolve -m b2
637 (no more unresolved files)
637 (no more unresolved files)
638 $ fileset 'resolved()'
638 $ fileset 'resolved()'
639 b2
639 b2
640 $ fileset 'unresolved()'
640 $ fileset 'unresolved()'
641 $ hg ci -m merge
641 $ hg ci -m merge
642
642
643 Test subrepo predicate
643 Test subrepo predicate
644
644
645 $ hg init sub
645 $ hg init sub
646 $ echo a > sub/suba
646 $ echo a > sub/suba
647 $ hg -R sub add sub/suba
647 $ hg -R sub add sub/suba
648 $ hg -R sub ci -m sub
648 $ hg -R sub ci -m sub
649 $ echo 'sub = sub' > .hgsub
649 $ echo 'sub = sub' > .hgsub
650 $ hg init sub2
650 $ hg init sub2
651 $ echo b > sub2/b
651 $ echo b > sub2/b
652 $ hg -R sub2 ci -Am sub2
652 $ hg -R sub2 ci -Am sub2
653 adding b
653 adding b
654 $ echo 'sub2 = sub2' >> .hgsub
654 $ echo 'sub2 = sub2' >> .hgsub
655 $ fileset 'subrepo()'
655 $ fileset 'subrepo()'
656 $ hg add .hgsub
656 $ hg add .hgsub
657 $ fileset 'subrepo()'
657 $ fileset 'subrepo()'
658 sub
658 sub
659 sub2
659 sub2
660 $ fileset 'subrepo("sub")'
660 $ fileset 'subrepo("sub")'
661 sub
661 sub
662 $ fileset 'subrepo("glob:*")'
662 $ fileset 'subrepo("glob:*")'
663 sub
663 sub
664 sub2
664 sub2
665 $ hg ci -m subrepo
665 $ hg ci -m subrepo
666
666
667 Test that .hgsubstate is updated as appropriate during a conversion. The
667 Test that .hgsubstate is updated as appropriate during a conversion. The
668 saverev property is enough to alter the hashes of the subrepo.
668 saverev property is enough to alter the hashes of the subrepo.
669
669
670 $ hg init ../converted
670 $ hg init ../converted
671 $ hg --config extensions.convert= convert --config convert.hg.saverev=True \
671 $ hg --config extensions.convert= convert --config convert.hg.saverev=True \
672 > sub ../converted/sub
672 > sub ../converted/sub
673 initializing destination ../converted/sub repository
673 initializing destination ../converted/sub repository
674 scanning source...
674 scanning source...
675 sorting...
675 sorting...
676 converting...
676 converting...
677 0 sub
677 0 sub
678 $ hg clone -U sub2 ../converted/sub2
678 $ hg clone -U sub2 ../converted/sub2
679 $ hg --config extensions.convert= convert --config convert.hg.saverev=True \
679 $ hg --config extensions.convert= convert --config convert.hg.saverev=True \
680 > . ../converted
680 > . ../converted
681 scanning source...
681 scanning source...
682 sorting...
682 sorting...
683 converting...
683 converting...
684 4 addfiles
684 4 addfiles
685 3 manychanges
685 3 manychanges
686 2 diverging
686 2 diverging
687 1 merge
687 1 merge
688 0 subrepo
688 0 subrepo
689 no ".hgsubstate" updates will be made for "sub2"
689 no ".hgsubstate" updates will be made for "sub2"
690 $ hg up -q -R ../converted -r tip
690 $ hg up -q -R ../converted -r tip
691 $ hg --cwd ../converted cat sub/suba sub2/b -r tip
691 $ hg --cwd ../converted cat sub/suba sub2/b -r tip
692 a
692 a
693 b
693 b
694 $ oldnode=`hg log -r tip -T "{node}\n"`
694 $ oldnode=`hg log -r tip -T "{node}\n"`
695 $ newnode=`hg log -R ../converted -r tip -T "{node}\n"`
695 $ newnode=`hg log -R ../converted -r tip -T "{node}\n"`
696 $ [ "$oldnode" != "$newnode" ] || echo "nothing changed"
696 $ [ "$oldnode" != "$newnode" ] || echo "nothing changed"
697
697
698 Test with a revision
698 Test with a revision
699
699
700 $ hg log -G --template '{rev} {desc}\n'
700 $ hg log -G --template '{rev} {desc}\n'
701 @ 4 subrepo
701 @ 4 subrepo
702 |
702 |
703 o 3 merge
703 o 3 merge
704 |\
704 |\
705 | o 2 diverging
705 | o 2 diverging
706 | |
706 | |
707 o | 1 manychanges
707 o | 1 manychanges
708 |/
708 |/
709 o 0 addfiles
709 o 0 addfiles
710
710
711 $ echo unknown > unknown
711 $ echo unknown > unknown
712 $ fileset -r1 'modified()'
712 $ fileset -r1 'modified()'
713 b2
713 b2
714 $ fileset -r1 'added() and c1'
714 $ fileset -r1 'added() and c1'
715 c1
715 c1
716 $ fileset -r1 'removed()'
716 $ fileset -r1 'removed()'
717 a2
717 a2
718 $ fileset -r1 'deleted()'
718 $ fileset -r1 'deleted()'
719 $ fileset -r1 'unknown()'
719 $ fileset -r1 'unknown()'
720 $ fileset -r1 'ignored()'
720 $ fileset -r1 'ignored()'
721 $ fileset -r1 'hgignore()'
721 $ fileset -r1 'hgignore()'
722 .hgignore
722 .hgignore
723 a2
723 a2
724 b2
724 b2
725 bin
725 bin
726 c2
726 c2
727 sub2
727 sub2
728 $ fileset -r1 'binary()'
728 $ fileset -r1 'binary()'
729 bin
729 bin
730 $ fileset -r1 'size(1k)'
730 $ fileset -r1 'size(1k)'
731 1k
731 1k
732 $ fileset -r3 'resolved()'
732 $ fileset -r3 'resolved()'
733 $ fileset -r3 'unresolved()'
733 $ fileset -r3 'unresolved()'
734
734
735 #if execbit
735 #if execbit
736 $ fileset -r1 'exec()'
736 $ fileset -r1 'exec()'
737 b2
737 b2
738 #endif
738 #endif
739
739
740 #if symlink
740 #if symlink
741 $ fileset -r1 'symlink()'
741 $ fileset -r1 'symlink()'
742 b2link
742 b2link
743 #endif
743 #endif
744
744
745 #if no-windows
745 #if no-windows
746 $ fileset -r1 'not portable()'
746 $ fileset -r1 'not portable()'
747 con.xml
747 con.xml
748 $ hg forget 'con.xml'
748 $ hg forget 'con.xml'
749 #endif
749 #endif
750
750
751 $ fileset -r4 'subrepo("re:su.*")'
751 $ fileset -r4 'subrepo("re:su.*")'
752 sub
752 sub
753 sub2
753 sub2
754 $ fileset -r4 'subrepo(re:su.*)'
754 $ fileset -r4 'subrepo(re:su.*)'
755 sub
755 sub
756 sub2
756 sub2
757 $ fileset -r4 'subrepo("sub")'
757 $ fileset -r4 'subrepo("sub")'
758 sub
758 sub
759 $ fileset -r4 'b2 or c1'
759 $ fileset -r4 'b2 or c1'
760 b2
760 b2
761 c1
761 c1
762
762
763 >>> open('dos', 'wb').write(b"dos\r\n") and None
763 >>> open('dos', 'wb').write(b"dos\r\n") and None
764 >>> open('mixed', 'wb').write(b"dos\r\nunix\n") and None
764 >>> open('mixed', 'wb').write(b"dos\r\nunix\n") and None
765 >>> open('mac', 'wb').write(b"mac\r") and None
765 >>> open('mac', 'wb').write(b"mac\r") and None
766 $ hg add dos mixed mac
766 $ hg add dos mixed mac
767
767
768 (remove a1, to examine safety of 'eol' on removed files)
768 (remove a1, to examine safety of 'eol' on removed files)
769 $ rm a1
769 $ rm a1
770
770
771 $ fileset 'eol(dos)'
771 $ fileset 'eol(dos)'
772 dos
772 dos
773 mixed
773 mixed
774 $ fileset 'eol(unix)'
774 $ fileset 'eol(unix)'
775 .hgignore
775 .hgignore
776 .hgsub
776 .hgsub
777 .hgsubstate
777 .hgsubstate
778 b1
778 b1
779 b2
779 b2
780 b2.orig
780 b2.orig
781 c1
781 c1
782 c2
782 c2
783 c3
783 c3
784 con.xml (no-windows !)
784 con.xml (no-windows !)
785 mixed
785 mixed
786 unknown
786 unknown
787 $ fileset 'eol(mac)'
787 $ fileset 'eol(mac)'
788 mac
788 mac
789
789
790 Test safety of 'encoding' on removed files
790 Test safety of 'encoding' on removed files
791
791
792 $ fileset 'encoding("ascii")'
792 $ fileset 'encoding("ascii")'
793 .hgignore
793 .hgignore
794 .hgsub
794 .hgsub
795 .hgsubstate
795 .hgsubstate
796 1k
796 1k
797 2k
797 2k
798 b1
798 b1
799 b2
799 b2
800 b2.orig
800 b2.orig
801 b2link (symlink !)
801 b2link (symlink !)
802 bin
802 bin
803 c1
803 c1
804 c2
804 c2
805 c3
805 c3
806 con.xml (no-windows !)
806 con.xml (no-windows !)
807 dos
807 dos
808 mac
808 mac
809 mixed
809 mixed
810 unknown
810 unknown
811
811
812 Test 'revs(...)'
812 Test 'revs(...)'
813 ================
813 ================
814
814
815 small reminder of the repository state
815 small reminder of the repository state
816
816
817 $ hg log -G
817 $ hg log -G
818 @ changeset: 4:* (glob)
818 @ changeset: 4:* (glob)
819 | tag: tip
819 | tag: tip
820 | user: test
820 | user: test
821 | date: Thu Jan 01 00:00:00 1970 +0000
821 | date: Thu Jan 01 00:00:00 1970 +0000
822 | summary: subrepo
822 | summary: subrepo
823 |
823 |
824 o changeset: 3:* (glob)
824 o changeset: 3:* (glob)
825 |\ parent: 2:55b05bdebf36
825 |\ parent: 2:55b05bdebf36
826 | | parent: 1:* (glob)
826 | | parent: 1:* (glob)
827 | | user: test
827 | | user: test
828 | | date: Thu Jan 01 00:00:00 1970 +0000
828 | | date: Thu Jan 01 00:00:00 1970 +0000
829 | | summary: merge
829 | | summary: merge
830 | |
830 | |
831 | o changeset: 2:55b05bdebf36
831 | o changeset: 2:55b05bdebf36
832 | | parent: 0:8a9576c51c1f
832 | | parent: 0:8a9576c51c1f
833 | | user: test
833 | | user: test
834 | | date: Thu Jan 01 00:00:00 1970 +0000
834 | | date: Thu Jan 01 00:00:00 1970 +0000
835 | | summary: diverging
835 | | summary: diverging
836 | |
836 | |
837 o | changeset: 1:* (glob)
837 o | changeset: 1:* (glob)
838 |/ user: test
838 |/ user: test
839 | date: Thu Jan 01 00:00:00 1970 +0000
839 | date: Thu Jan 01 00:00:00 1970 +0000
840 | summary: manychanges
840 | summary: manychanges
841 |
841 |
842 o changeset: 0:8a9576c51c1f
842 o changeset: 0:8a9576c51c1f
843 user: test
843 user: test
844 date: Thu Jan 01 00:00:00 1970 +0000
844 date: Thu Jan 01 00:00:00 1970 +0000
845 summary: addfiles
845 summary: addfiles
846
846
847 $ hg status --change 0
847 $ hg status --change 0
848 A a1
848 A a1
849 A a2
849 A a2
850 A b1
850 A b1
851 A b2
851 A b2
852 $ hg status --change 1
852 $ hg status --change 1
853 M b2
853 M b2
854 A 1k
854 A 1k
855 A 2k
855 A 2k
856 A b2link (no-windows !)
856 A b2link (no-windows !)
857 A bin
857 A bin
858 A c1
858 A c1
859 A con.xml (no-windows !)
859 A con.xml (no-windows !)
860 R a2
860 R a2
861 $ hg status --change 2
861 $ hg status --change 2
862 M b2
862 M b2
863 $ hg status --change 3
863 $ hg status --change 3
864 M b2
864 M b2
865 A 1k
865 A 1k
866 A 2k
866 A 2k
867 A b2link (no-windows !)
867 A b2link (no-windows !)
868 A bin
868 A bin
869 A c1
869 A c1
870 A con.xml (no-windows !)
870 A con.xml (no-windows !)
871 R a2
871 R a2
872 $ hg status --change 4
872 $ hg status --change 4
873 A .hgsub
873 A .hgsub
874 A .hgsubstate
874 A .hgsubstate
875 $ hg status
875 $ hg status
876 A dos
876 A dos
877 A mac
877 A mac
878 A mixed
878 A mixed
879 R con.xml (no-windows !)
879 R con.xml (no-windows !)
880 ! a1
880 ! a1
881 ? b2.orig
881 ? b2.orig
882 ? c3
882 ? c3
883 ? unknown
883 ? unknown
884
884
885 Test files at -r0 should be filtered by files at wdir
885 Test files at -r0 should be filtered by files at wdir
886 -----------------------------------------------------
886 -----------------------------------------------------
887
887
888 $ fileset -r0 'tracked() and revs("wdir()", tracked())'
888 $ fileset -r0 'tracked() and revs("wdir()", tracked())'
889 a1
889 a1
890 b1
890 b1
891 b2
891 b2
892
892
893 Test that "revs()" work at all
893 Test that "revs()" work at all
894 ------------------------------
894 ------------------------------
895
895
896 $ fileset "revs('2', modified())"
896 $ fileset "revs('2', modified())"
897 b2
897 b2
898
898
899 Test that "revs()" work for file missing in the working copy/current context
899 Test that "revs()" work for file missing in the working copy/current context
900 ----------------------------------------------------------------------------
900 ----------------------------------------------------------------------------
901
901
902 (a2 not in working copy)
902 (a2 not in working copy)
903
903
904 $ fileset "revs('0', added())"
904 $ fileset "revs('0', added())"
905 a1
905 a1
906 a2
906 a2
907 b1
907 b1
908 b2
908 b2
909
909
910 (none of the file exist in "0")
910 (none of the file exist in "0")
911
911
912 $ fileset -r 0 "revs('4', added())"
912 $ fileset -r 0 "revs('4', added())"
913 .hgsub
913 .hgsub
914 .hgsubstate
914 .hgsubstate
915
915
916 Call with empty revset
916 Call with empty revset
917 --------------------------
917 --------------------------
918
918
919 $ fileset "revs('2-2', modified())"
919 $ fileset "revs('2-2', modified())"
920
920
921 Call with revset matching multiple revs
921 Call with revset matching multiple revs
922 ---------------------------------------
922 ---------------------------------------
923
923
924 $ fileset "revs('0+4', added())"
924 $ fileset "revs('0+4', added())"
925 .hgsub
925 .hgsub
926 .hgsubstate
926 .hgsubstate
927 a1
927 a1
928 a2
928 a2
929 b1
929 b1
930 b2
930 b2
931
931
932 overlapping set
932 overlapping set
933
933
934 $ fileset "revs('1+2', modified())"
934 $ fileset "revs('1+2', modified())"
935 b2
935 b2
936
936
937 test 'status(...)'
937 test 'status(...)'
938 =================
938 =================
939
939
940 Simple case
940 Simple case
941 -----------
941 -----------
942
942
943 $ fileset "status(3, 4, added())"
943 $ fileset "status(3, 4, added())"
944 .hgsub
944 .hgsub
945 .hgsubstate
945 .hgsubstate
946
946
947 use rev to restrict matched file
947 use rev to restrict matched file
948 -----------------------------------------
948 -----------------------------------------
949
949
950 $ hg status --removed --rev 0 --rev 1
950 $ hg status --removed --rev 0 --rev 1
951 R a2
951 R a2
952 $ fileset "status(0, 1, removed())"
952 $ fileset "status(0, 1, removed())"
953 a2
953 a2
954 $ fileset "tracked() and status(0, 1, removed())"
954 $ fileset "tracked() and status(0, 1, removed())"
955 $ fileset -r 4 "status(0, 1, removed())"
955 $ fileset -r 4 "status(0, 1, removed())"
956 a2
956 a2
957 $ fileset -r 4 "tracked() and status(0, 1, removed())"
957 $ fileset -r 4 "tracked() and status(0, 1, removed())"
958 $ fileset "revs('4', tracked() and status(0, 1, removed()))"
958 $ fileset "revs('4', tracked() and status(0, 1, removed()))"
959 $ fileset "revs('0', tracked() and status(0, 1, removed()))"
959 $ fileset "revs('0', tracked() and status(0, 1, removed()))"
960 a2
960 a2
961
961
962 check wdir()
962 check wdir()
963 ------------
963 ------------
964
964
965 $ hg status --removed --rev 4
965 $ hg status --removed --rev 4
966 R con.xml (no-windows !)
966 R con.xml (no-windows !)
967 $ fileset "status(4, 'wdir()', removed())"
967 $ fileset "status(4, 'wdir()', removed())"
968 con.xml (no-windows !)
968 con.xml (no-windows !)
969
969
970 $ hg status --removed --rev 2
970 $ hg status --removed --rev 2
971 R a2
971 R a2
972 $ fileset "status('2', 'wdir()', removed())"
972 $ fileset "status('2', 'wdir()', removed())"
973 a2
973 a2
974
974
975 test backward status
975 test backward status
976 --------------------
976 --------------------
977
977
978 $ hg status --removed --rev 0 --rev 4
978 $ hg status --removed --rev 0 --rev 4
979 R a2
979 R a2
980 $ hg status --added --rev 4 --rev 0
980 $ hg status --added --rev 4 --rev 0
981 A a2
981 A a2
982 $ fileset "status(4, 0, added())"
982 $ fileset "status(4, 0, added())"
983 a2
983 a2
984
984
985 test cross branch status
985 test cross branch status
986 ------------------------
986 ------------------------
987
987
988 $ hg status --added --rev 1 --rev 2
988 $ hg status --added --rev 1 --rev 2
989 A a2
989 A a2
990 $ fileset "status(1, 2, added())"
990 $ fileset "status(1, 2, added())"
991 a2
991 a2
992
992
993 test with multi revs revset
993 test with multi revs revset
994 ---------------------------
994 ---------------------------
995 $ hg status --added --rev 0:1 --rev 3:4
995 $ hg status --added --rev 0:1 --rev 3:4
996 A .hgsub
996 A .hgsub
997 A .hgsubstate
997 A .hgsubstate
998 A 1k
998 A 1k
999 A 2k
999 A 2k
1000 A b2link (no-windows !)
1000 A b2link (no-windows !)
1001 A bin
1001 A bin
1002 A c1
1002 A c1
1003 A con.xml (no-windows !)
1003 A con.xml (no-windows !)
1004 $ fileset "status('0:1', '3:4', added())"
1004 $ fileset "status('0:1', '3:4', added())"
1005 .hgsub
1005 .hgsub
1006 .hgsubstate
1006 .hgsubstate
1007 1k
1007 1k
1008 2k
1008 2k
1009 b2link (no-windows !)
1009 b2link (no-windows !)
1010 bin
1010 bin
1011 c1
1011 c1
1012 con.xml (no-windows !)
1012 con.xml (no-windows !)
1013
1013
1014 tests with empty value
1014 tests with empty value
1015 ----------------------
1015 ----------------------
1016
1016
1017 Fully empty revset
1017 Fully empty revset
1018
1018
1019 $ fileset "status('', '4', added())"
1019 $ fileset "status('', '4', added())"
1020 hg: parse error: first argument to status must be a revision
1020 hg: parse error: first argument to status must be a revision
1021 [255]
1021 [255]
1022 $ fileset "status('2', '', added())"
1022 $ fileset "status('2', '', added())"
1023 hg: parse error: second argument to status must be a revision
1023 hg: parse error: second argument to status must be a revision
1024 [255]
1024 [255]
1025
1025
1026 Empty revset will error at the revset layer
1026 Empty revset will error at the revset layer
1027
1027
1028 $ fileset "status(' ', '4', added())"
1028 $ fileset "status(' ', '4', added())"
1029 hg: parse error at 1: not a prefix: end
1029 hg: parse error at 1: not a prefix: end
1030 (
1030 (
1031 ^ here)
1031 ^ here)
1032 [255]
1032 [255]
1033 $ fileset "status('2', ' ', added())"
1033 $ fileset "status('2', ' ', added())"
1034 hg: parse error at 1: not a prefix: end
1034 hg: parse error at 1: not a prefix: end
1035 (
1035 (
1036 ^ here)
1036 ^ here)
1037 [255]
1037 [255]
@@ -1,339 +1,339 b''
1 $ hg init ignorerepo
1 $ hg init ignorerepo
2 $ cd ignorerepo
2 $ cd ignorerepo
3
3
4 debugignore with no hgignore should be deterministic:
4 debugignore with no hgignore should be deterministic:
5 $ hg debugignore
5 $ hg debugignore
6 <nevermatcher>
6 <nevermatcher>
7
7
8 Issue562: .hgignore requires newline at end:
8 Issue562: .hgignore requires newline at end:
9
9
10 $ touch foo
10 $ touch foo
11 $ touch bar
11 $ touch bar
12 $ touch baz
12 $ touch baz
13 $ cat > makeignore.py <<EOF
13 $ cat > makeignore.py <<EOF
14 > f = open(".hgignore", "w")
14 > f = open(".hgignore", "w")
15 > f.write("ignore\n")
15 > f.write("ignore\n")
16 > f.write("foo\n")
16 > f.write("foo\n")
17 > # No EOL here
17 > # No EOL here
18 > f.write("bar")
18 > f.write("bar")
19 > f.close()
19 > f.close()
20 > EOF
20 > EOF
21
21
22 $ "$PYTHON" makeignore.py
22 $ "$PYTHON" makeignore.py
23
23
24 Should display baz only:
24 Should display baz only:
25
25
26 $ hg status
26 $ hg status
27 ? baz
27 ? baz
28
28
29 $ rm foo bar baz .hgignore makeignore.py
29 $ rm foo bar baz .hgignore makeignore.py
30
30
31 $ touch a.o
31 $ touch a.o
32 $ touch a.c
32 $ touch a.c
33 $ touch syntax
33 $ touch syntax
34 $ mkdir dir
34 $ mkdir dir
35 $ touch dir/a.o
35 $ touch dir/a.o
36 $ touch dir/b.o
36 $ touch dir/b.o
37 $ touch dir/c.o
37 $ touch dir/c.o
38
38
39 $ hg add dir/a.o
39 $ hg add dir/a.o
40 $ hg commit -m 0
40 $ hg commit -m 0
41 $ hg add dir/b.o
41 $ hg add dir/b.o
42
42
43 $ hg status
43 $ hg status
44 A dir/b.o
44 A dir/b.o
45 ? a.c
45 ? a.c
46 ? a.o
46 ? a.o
47 ? dir/c.o
47 ? dir/c.o
48 ? syntax
48 ? syntax
49
49
50 $ echo "*.o" > .hgignore
50 $ echo "*.o" > .hgignore
51 $ hg status
51 $ hg status
52 abort: $TESTTMP/ignorerepo/.hgignore: invalid pattern (relre): *.o (glob)
52 abort: $TESTTMP/ignorerepo/.hgignore: invalid pattern (relre): *.o (glob)
53 [255]
53 [255]
54
54
55 Ensure given files are relative to cwd
55 Ensure given files are relative to cwd
56
56
57 $ echo "dir/.*\.o" > .hgignore
57 $ echo "dir/.*\.o" > .hgignore
58 $ hg status -i
58 $ hg status -i
59 I dir/c.o
59 I dir/c.o
60
60
61 $ hg debugignore dir/c.o dir/missing.o
61 $ hg debugignore dir/c.o dir/missing.o
62 dir/c.o is ignored
62 dir/c.o is ignored
63 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
63 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
64 dir/missing.o is ignored
64 dir/missing.o is ignored
65 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
65 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
66 $ cd dir
66 $ cd dir
67 $ hg debugignore c.o missing.o
67 $ hg debugignore c.o missing.o
68 c.o is ignored
68 c.o is ignored
69 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
69 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
70 missing.o is ignored
70 missing.o is ignored
71 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
71 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
72
72
73 For icasefs, inexact matches also work, except for missing files
73 For icasefs, inexact matches also work, except for missing files
74
74
75 #if icasefs
75 #if icasefs
76 $ hg debugignore c.O missing.O
76 $ hg debugignore c.O missing.O
77 c.o is ignored
77 c.o is ignored
78 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
78 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: 'dir/.*\.o') (glob)
79 missing.O is not ignored
79 missing.O is not ignored
80 #endif
80 #endif
81
81
82 $ cd ..
82 $ cd ..
83
83
84 $ echo ".*\.o" > .hgignore
84 $ echo ".*\.o" > .hgignore
85 $ hg status
85 $ hg status
86 A dir/b.o
86 A dir/b.o
87 ? .hgignore
87 ? .hgignore
88 ? a.c
88 ? a.c
89 ? syntax
89 ? syntax
90
90
91 Ensure that comments work:
91 Ensure that comments work:
92
92
93 $ touch 'foo#bar' 'quux#'
93 $ touch 'foo#bar' 'quux#'
94 #if no-windows
94 #if no-windows
95 $ touch 'baz\#wat'
95 $ touch 'baz\#wat'
96 #endif
96 #endif
97 $ cat <<'EOF' >> .hgignore
97 $ cat <<'EOF' >> .hgignore
98 > # full-line comment
98 > # full-line comment
99 > # whitespace-only comment line
99 > # whitespace-only comment line
100 > syntax# pattern, no whitespace, then comment
100 > syntax# pattern, no whitespace, then comment
101 > a.c # pattern, then whitespace, then comment
101 > a.c # pattern, then whitespace, then comment
102 > baz\\# # escaped comment character
102 > baz\\# # escaped comment character
103 > foo\#b # escaped comment character
103 > foo\#b # escaped comment character
104 > quux\## escaped comment character at end of name
104 > quux\## escaped comment character at end of name
105 > EOF
105 > EOF
106 $ hg status
106 $ hg status
107 A dir/b.o
107 A dir/b.o
108 ? .hgignore
108 ? .hgignore
109 $ rm 'foo#bar' 'quux#'
109 $ rm 'foo#bar' 'quux#'
110 #if no-windows
110 #if no-windows
111 $ rm 'baz\#wat'
111 $ rm 'baz\#wat'
112 #endif
112 #endif
113
113
114 Check that '^\.' does not ignore the root directory:
114 Check that '^\.' does not ignore the root directory:
115
115
116 $ echo "^\." > .hgignore
116 $ echo "^\." > .hgignore
117 $ hg status
117 $ hg status
118 A dir/b.o
118 A dir/b.o
119 ? a.c
119 ? a.c
120 ? a.o
120 ? a.o
121 ? dir/c.o
121 ? dir/c.o
122 ? syntax
122 ? syntax
123
123
124 Test that patterns from ui.ignore options are read:
124 Test that patterns from ui.ignore options are read:
125
125
126 $ echo > .hgignore
126 $ echo > .hgignore
127 $ cat >> $HGRCPATH << EOF
127 $ cat >> $HGRCPATH << EOF
128 > [ui]
128 > [ui]
129 > ignore.other = $TESTTMP/ignorerepo/.hg/testhgignore
129 > ignore.other = $TESTTMP/ignorerepo/.hg/testhgignore
130 > EOF
130 > EOF
131 $ echo "glob:**.o" > .hg/testhgignore
131 $ echo "glob:**.o" > .hg/testhgignore
132 $ hg status
132 $ hg status
133 A dir/b.o
133 A dir/b.o
134 ? .hgignore
134 ? .hgignore
135 ? a.c
135 ? a.c
136 ? syntax
136 ? syntax
137
137
138 empty out testhgignore
138 empty out testhgignore
139 $ echo > .hg/testhgignore
139 $ echo > .hg/testhgignore
140
140
141 Test relative ignore path (issue4473):
141 Test relative ignore path (issue4473):
142
142
143 $ cat >> $HGRCPATH << EOF
143 $ cat >> $HGRCPATH << EOF
144 > [ui]
144 > [ui]
145 > ignore.relative = .hg/testhgignorerel
145 > ignore.relative = .hg/testhgignorerel
146 > EOF
146 > EOF
147 $ echo "glob:*.o" > .hg/testhgignorerel
147 $ echo "glob:*.o" > .hg/testhgignorerel
148 $ cd dir
148 $ cd dir
149 $ hg status
149 $ hg status
150 A dir/b.o
150 A dir/b.o
151 ? .hgignore
151 ? .hgignore
152 ? a.c
152 ? a.c
153 ? syntax
153 ? syntax
154
154
155 $ cd ..
155 $ cd ..
156 $ echo > .hg/testhgignorerel
156 $ echo > .hg/testhgignorerel
157 $ echo "syntax: glob" > .hgignore
157 $ echo "syntax: glob" > .hgignore
158 $ echo "re:.*\.o" >> .hgignore
158 $ echo "re:.*\.o" >> .hgignore
159 $ hg status
159 $ hg status
160 A dir/b.o
160 A dir/b.o
161 ? .hgignore
161 ? .hgignore
162 ? a.c
162 ? a.c
163 ? syntax
163 ? syntax
164
164
165 $ echo "syntax: invalid" > .hgignore
165 $ echo "syntax: invalid" > .hgignore
166 $ hg status
166 $ hg status
167 $TESTTMP/ignorerepo/.hgignore: ignoring invalid syntax 'invalid'
167 $TESTTMP/ignorerepo/.hgignore: ignoring invalid syntax 'invalid'
168 A dir/b.o
168 A dir/b.o
169 ? .hgignore
169 ? .hgignore
170 ? a.c
170 ? a.c
171 ? a.o
171 ? a.o
172 ? dir/c.o
172 ? dir/c.o
173 ? syntax
173 ? syntax
174
174
175 $ echo "syntax: glob" > .hgignore
175 $ echo "syntax: glob" > .hgignore
176 $ echo "*.o" >> .hgignore
176 $ echo "*.o" >> .hgignore
177 $ hg status
177 $ hg status
178 A dir/b.o
178 A dir/b.o
179 ? .hgignore
179 ? .hgignore
180 ? a.c
180 ? a.c
181 ? syntax
181 ? syntax
182
182
183 $ echo "relglob:syntax*" > .hgignore
183 $ echo "relglob:syntax*" > .hgignore
184 $ hg status
184 $ hg status
185 A dir/b.o
185 A dir/b.o
186 ? .hgignore
186 ? .hgignore
187 ? a.c
187 ? a.c
188 ? a.o
188 ? a.o
189 ? dir/c.o
189 ? dir/c.o
190
190
191 $ echo "relglob:*" > .hgignore
191 $ echo "relglob:*" > .hgignore
192 $ hg status
192 $ hg status
193 A dir/b.o
193 A dir/b.o
194
194
195 $ cd dir
195 $ cd dir
196 $ hg status .
196 $ hg status .
197 A b.o
197 A b.o
198
198
199 $ hg debugignore
199 $ hg debugignore
200 <includematcher includes='(?:(?:|.*/)[^/]*(?:/|$))'>
200 <includematcher includes='(?:|.*/)[^/]*(?:/|$)'>
201
201
202 $ hg debugignore b.o
202 $ hg debugignore b.o
203 b.o is ignored
203 b.o is ignored
204 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: '*') (glob)
204 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 1: '*') (glob)
205
205
206 $ cd ..
206 $ cd ..
207
207
208 Check patterns that match only the directory
208 Check patterns that match only the directory
209
209
210 "(fsmonitor !)" below assumes that fsmonitor is enabled with
210 "(fsmonitor !)" below assumes that fsmonitor is enabled with
211 "walk_on_invalidate = false" (default), which doesn't involve
211 "walk_on_invalidate = false" (default), which doesn't involve
212 re-walking whole repository at detection of .hgignore change.
212 re-walking whole repository at detection of .hgignore change.
213
213
214 $ echo "^dir\$" > .hgignore
214 $ echo "^dir\$" > .hgignore
215 $ hg status
215 $ hg status
216 A dir/b.o
216 A dir/b.o
217 ? .hgignore
217 ? .hgignore
218 ? a.c
218 ? a.c
219 ? a.o
219 ? a.o
220 ? dir/c.o (fsmonitor !)
220 ? dir/c.o (fsmonitor !)
221 ? syntax
221 ? syntax
222
222
223 Check recursive glob pattern matches no directories (dir/**/c.o matches dir/c.o)
223 Check recursive glob pattern matches no directories (dir/**/c.o matches dir/c.o)
224
224
225 $ echo "syntax: glob" > .hgignore
225 $ echo "syntax: glob" > .hgignore
226 $ echo "dir/**/c.o" >> .hgignore
226 $ echo "dir/**/c.o" >> .hgignore
227 $ touch dir/c.o
227 $ touch dir/c.o
228 $ mkdir dir/subdir
228 $ mkdir dir/subdir
229 $ touch dir/subdir/c.o
229 $ touch dir/subdir/c.o
230 $ hg status
230 $ hg status
231 A dir/b.o
231 A dir/b.o
232 ? .hgignore
232 ? .hgignore
233 ? a.c
233 ? a.c
234 ? a.o
234 ? a.o
235 ? syntax
235 ? syntax
236 $ hg debugignore a.c
236 $ hg debugignore a.c
237 a.c is not ignored
237 a.c is not ignored
238 $ hg debugignore dir/c.o
238 $ hg debugignore dir/c.o
239 dir/c.o is ignored
239 dir/c.o is ignored
240 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 2: 'dir/**/c.o') (glob)
240 (ignore rule in $TESTTMP/ignorerepo/.hgignore, line 2: 'dir/**/c.o') (glob)
241
241
242 Check using 'include:' in ignore file
242 Check using 'include:' in ignore file
243
243
244 $ hg purge --all --config extensions.purge=
244 $ hg purge --all --config extensions.purge=
245 $ touch foo.included
245 $ touch foo.included
246
246
247 $ echo ".*.included" > otherignore
247 $ echo ".*.included" > otherignore
248 $ hg status -I "include:otherignore"
248 $ hg status -I "include:otherignore"
249 ? foo.included
249 ? foo.included
250
250
251 $ echo "include:otherignore" >> .hgignore
251 $ echo "include:otherignore" >> .hgignore
252 $ hg status
252 $ hg status
253 A dir/b.o
253 A dir/b.o
254 ? .hgignore
254 ? .hgignore
255 ? otherignore
255 ? otherignore
256
256
257 Check recursive uses of 'include:'
257 Check recursive uses of 'include:'
258
258
259 $ echo "include:nested/ignore" >> otherignore
259 $ echo "include:nested/ignore" >> otherignore
260 $ mkdir nested
260 $ mkdir nested
261 $ echo "glob:*ignore" > nested/ignore
261 $ echo "glob:*ignore" > nested/ignore
262 $ hg status
262 $ hg status
263 A dir/b.o
263 A dir/b.o
264
264
265 $ cp otherignore goodignore
265 $ cp otherignore goodignore
266 $ echo "include:badignore" >> otherignore
266 $ echo "include:badignore" >> otherignore
267 $ hg status
267 $ hg status
268 skipping unreadable pattern file 'badignore': $ENOENT$
268 skipping unreadable pattern file 'badignore': $ENOENT$
269 A dir/b.o
269 A dir/b.o
270
270
271 $ mv goodignore otherignore
271 $ mv goodignore otherignore
272
272
273 Check using 'include:' while in a non-root directory
273 Check using 'include:' while in a non-root directory
274
274
275 $ cd ..
275 $ cd ..
276 $ hg -R ignorerepo status
276 $ hg -R ignorerepo status
277 A dir/b.o
277 A dir/b.o
278 $ cd ignorerepo
278 $ cd ignorerepo
279
279
280 Check including subincludes
280 Check including subincludes
281
281
282 $ hg revert -q --all
282 $ hg revert -q --all
283 $ hg purge --all --config extensions.purge=
283 $ hg purge --all --config extensions.purge=
284 $ echo ".hgignore" > .hgignore
284 $ echo ".hgignore" > .hgignore
285 $ mkdir dir1 dir2
285 $ mkdir dir1 dir2
286 $ touch dir1/file1 dir1/file2 dir2/file1 dir2/file2
286 $ touch dir1/file1 dir1/file2 dir2/file1 dir2/file2
287 $ echo "subinclude:dir2/.hgignore" >> .hgignore
287 $ echo "subinclude:dir2/.hgignore" >> .hgignore
288 $ echo "glob:file*2" > dir2/.hgignore
288 $ echo "glob:file*2" > dir2/.hgignore
289 $ hg status
289 $ hg status
290 ? dir1/file1
290 ? dir1/file1
291 ? dir1/file2
291 ? dir1/file2
292 ? dir2/file1
292 ? dir2/file1
293
293
294 Check including subincludes with regexs
294 Check including subincludes with regexs
295
295
296 $ echo "subinclude:dir1/.hgignore" >> .hgignore
296 $ echo "subinclude:dir1/.hgignore" >> .hgignore
297 $ echo "regexp:f.le1" > dir1/.hgignore
297 $ echo "regexp:f.le1" > dir1/.hgignore
298
298
299 $ hg status
299 $ hg status
300 ? dir1/file2
300 ? dir1/file2
301 ? dir2/file1
301 ? dir2/file1
302
302
303 Check multiple levels of sub-ignores
303 Check multiple levels of sub-ignores
304
304
305 $ mkdir dir1/subdir
305 $ mkdir dir1/subdir
306 $ touch dir1/subdir/subfile1 dir1/subdir/subfile3 dir1/subdir/subfile4
306 $ touch dir1/subdir/subfile1 dir1/subdir/subfile3 dir1/subdir/subfile4
307 $ echo "subinclude:subdir/.hgignore" >> dir1/.hgignore
307 $ echo "subinclude:subdir/.hgignore" >> dir1/.hgignore
308 $ echo "glob:subfil*3" >> dir1/subdir/.hgignore
308 $ echo "glob:subfil*3" >> dir1/subdir/.hgignore
309
309
310 $ hg status
310 $ hg status
311 ? dir1/file2
311 ? dir1/file2
312 ? dir1/subdir/subfile4
312 ? dir1/subdir/subfile4
313 ? dir2/file1
313 ? dir2/file1
314
314
315 Check include subignore at the same level
315 Check include subignore at the same level
316
316
317 $ mv dir1/subdir/.hgignore dir1/.hgignoretwo
317 $ mv dir1/subdir/.hgignore dir1/.hgignoretwo
318 $ echo "regexp:f.le1" > dir1/.hgignore
318 $ echo "regexp:f.le1" > dir1/.hgignore
319 $ echo "subinclude:.hgignoretwo" >> dir1/.hgignore
319 $ echo "subinclude:.hgignoretwo" >> dir1/.hgignore
320 $ echo "glob:file*2" > dir1/.hgignoretwo
320 $ echo "glob:file*2" > dir1/.hgignoretwo
321
321
322 $ hg status | grep file2
322 $ hg status | grep file2
323 [1]
323 [1]
324 $ hg debugignore dir1/file2
324 $ hg debugignore dir1/file2
325 dir1/file2 is ignored
325 dir1/file2 is ignored
326 (ignore rule in dir2/.hgignore, line 1: 'file*2')
326 (ignore rule in dir2/.hgignore, line 1: 'file*2')
327
327
328 #if windows
328 #if windows
329
329
330 Windows paths are accepted on input
330 Windows paths are accepted on input
331
331
332 $ rm dir1/.hgignore
332 $ rm dir1/.hgignore
333 $ echo "dir1/file*" >> .hgignore
333 $ echo "dir1/file*" >> .hgignore
334 $ hg debugignore "dir1\file2"
334 $ hg debugignore "dir1\file2"
335 dir1\file2 is ignored
335 dir1\file2 is ignored
336 (ignore rule in $TESTTMP\ignorerepo\.hgignore, line 4: 'dir1/file*')
336 (ignore rule in $TESTTMP\ignorerepo\.hgignore, line 4: 'dir1/file*')
337 $ hg up -qC .
337 $ hg up -qC .
338
338
339 #endif
339 #endif
@@ -1,106 +1,106 b''
1 #testcases flat tree
1 #testcases flat tree
2
2
3 $ . "$TESTDIR/narrow-library.sh"
3 $ . "$TESTDIR/narrow-library.sh"
4
4
5 #if tree
5 #if tree
6 $ cat << EOF >> $HGRCPATH
6 $ cat << EOF >> $HGRCPATH
7 > [experimental]
7 > [experimental]
8 > treemanifest = 1
8 > treemanifest = 1
9 > EOF
9 > EOF
10 #endif
10 #endif
11
11
12 create full repo
12 create full repo
13
13
14 $ hg init master
14 $ hg init master
15 $ cd master
15 $ cd master
16
16
17 $ mkdir inside
17 $ mkdir inside
18 $ echo inside > inside/f1
18 $ echo inside > inside/f1
19 $ mkdir outside
19 $ mkdir outside
20 $ echo outside > outside/f1
20 $ echo outside > outside/f1
21 $ hg ci -Aqm 'initial'
21 $ hg ci -Aqm 'initial'
22
22
23 $ echo modified > inside/f1
23 $ echo modified > inside/f1
24 $ hg ci -qm 'modify inside'
24 $ hg ci -qm 'modify inside'
25
25
26 $ echo modified > outside/f1
26 $ echo modified > outside/f1
27 $ hg ci -qm 'modify outside'
27 $ hg ci -qm 'modify outside'
28
28
29 $ cd ..
29 $ cd ..
30
30
31 (The lfs extension does nothing here, but this test ensures that its hook that
31 (The lfs extension does nothing here, but this test ensures that its hook that
32 determines whether to add the lfs requirement, respects the narrow boundaries.)
32 determines whether to add the lfs requirement, respects the narrow boundaries.)
33
33
34 $ hg --config extensions.lfs= clone --narrow ssh://user@dummy/master narrow \
34 $ hg --config extensions.lfs= clone --narrow ssh://user@dummy/master narrow \
35 > --include inside
35 > --include inside
36 requesting all changes
36 requesting all changes
37 adding changesets
37 adding changesets
38 adding manifests
38 adding manifests
39 adding file changes
39 adding file changes
40 added 3 changesets with 2 changes to 1 files
40 added 3 changesets with 2 changes to 1 files
41 new changesets *:* (glob)
41 new changesets *:* (glob)
42 updating to branch default
42 updating to branch default
43 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 $ cd narrow
44 $ cd narrow
45
45
46 $ hg update -q 0
46 $ hg update -q 0
47
47
48 Can not modify dirstate outside
48 Can not modify dirstate outside
49
49
50 $ mkdir outside
50 $ mkdir outside
51 $ touch outside/f1
51 $ touch outside/f1
52 $ hg debugwalk -v -I 'relglob:f1'
52 $ hg debugwalk -v -I 'relglob:f1'
53 * matcher:
53 * matcher:
54 <includematcher includes='(?:(?:|.*/)f1(?:/|$))'>
54 <includematcher includes='(?:|.*/)f1(?:/|$)'>
55 f inside/f1 inside/f1
55 f inside/f1 inside/f1
56 $ hg add .
56 $ hg add .
57 $ hg add outside/f1
57 $ hg add outside/f1
58 abort: cannot track 'outside/f1' - it is outside the narrow clone
58 abort: cannot track 'outside/f1' - it is outside the narrow clone
59 [255]
59 [255]
60 $ touch outside/f3
60 $ touch outside/f3
61 $ hg add outside/f3
61 $ hg add outside/f3
62 abort: cannot track 'outside/f3' - it is outside the narrow clone
62 abort: cannot track 'outside/f3' - it is outside the narrow clone
63 [255]
63 [255]
64
64
65 But adding a truly excluded file shouldn't count
65 But adding a truly excluded file shouldn't count
66
66
67 $ hg add outside/f3 -X outside/f3
67 $ hg add outside/f3 -X outside/f3
68
68
69 $ rm -r outside
69 $ rm -r outside
70
70
71 Can modify dirstate inside
71 Can modify dirstate inside
72
72
73 $ echo modified > inside/f1
73 $ echo modified > inside/f1
74 $ touch inside/f3
74 $ touch inside/f3
75 $ hg add inside/f3
75 $ hg add inside/f3
76 $ hg status
76 $ hg status
77 M inside/f1
77 M inside/f1
78 A inside/f3
78 A inside/f3
79 $ hg revert -qC .
79 $ hg revert -qC .
80 $ rm inside/f3
80 $ rm inside/f3
81
81
82 Can commit changes inside. Leaves outside unchanged.
82 Can commit changes inside. Leaves outside unchanged.
83
83
84 $ hg update -q 'desc("initial")'
84 $ hg update -q 'desc("initial")'
85 $ echo modified2 > inside/f1
85 $ echo modified2 > inside/f1
86 $ hg manifest --debug
86 $ hg manifest --debug
87 4d6a634d5ba06331a60c29ee0db8412490a54fcd 644 inside/f1
87 4d6a634d5ba06331a60c29ee0db8412490a54fcd 644 inside/f1
88 7fb3bb6356d28d4dc352c5ba52d7350a81b6bd46 644 outside/f1 (flat !)
88 7fb3bb6356d28d4dc352c5ba52d7350a81b6bd46 644 outside/f1 (flat !)
89 d0f2f706468ab0e8bec7af87446835fb1b13511b 755 d outside/ (tree !)
89 d0f2f706468ab0e8bec7af87446835fb1b13511b 755 d outside/ (tree !)
90 $ hg commit -m 'modify inside/f1'
90 $ hg commit -m 'modify inside/f1'
91 created new head
91 created new head
92 $ hg files -r .
92 $ hg files -r .
93 inside/f1
93 inside/f1
94 $ hg manifest --debug
94 $ hg manifest --debug
95 3f4197b4a11b9016e77ebc47fe566944885fd11b 644 inside/f1
95 3f4197b4a11b9016e77ebc47fe566944885fd11b 644 inside/f1
96 7fb3bb6356d28d4dc352c5ba52d7350a81b6bd46 644 outside/f1 (flat !)
96 7fb3bb6356d28d4dc352c5ba52d7350a81b6bd46 644 outside/f1 (flat !)
97 d0f2f706468ab0e8bec7af87446835fb1b13511b 755 d outside/ (tree !)
97 d0f2f706468ab0e8bec7af87446835fb1b13511b 755 d outside/ (tree !)
98 Some filesystems (notably FAT/exFAT only store timestamps with 2
98 Some filesystems (notably FAT/exFAT only store timestamps with 2
99 seconds of precision, so by sleeping for 3 seconds, we can ensure that
99 seconds of precision, so by sleeping for 3 seconds, we can ensure that
100 the timestamps of files stored by dirstate will appear older than the
100 the timestamps of files stored by dirstate will appear older than the
101 dirstate file, and therefore we'll be able to get stable output from
101 dirstate file, and therefore we'll be able to get stable output from
102 debugdirstate. If we don't do this, the test can be slightly flaky.
102 debugdirstate. If we don't do this, the test can be slightly flaky.
103 $ sleep 3
103 $ sleep 3
104 $ hg status
104 $ hg status
105 $ hg debugdirstate --no-dates
105 $ hg debugdirstate --no-dates
106 n 644 10 set inside/f1
106 n 644 10 set inside/f1
@@ -1,652 +1,652 b''
1 $ hg init t
1 $ hg init t
2 $ cd t
2 $ cd t
3 $ mkdir -p beans
3 $ mkdir -p beans
4 $ for b in kidney navy turtle borlotti black pinto; do
4 $ for b in kidney navy turtle borlotti black pinto; do
5 > echo $b > beans/$b
5 > echo $b > beans/$b
6 > done
6 > done
7 $ mkdir -p mammals/Procyonidae
7 $ mkdir -p mammals/Procyonidae
8 $ for m in cacomistle coatimundi raccoon; do
8 $ for m in cacomistle coatimundi raccoon; do
9 > echo $m > mammals/Procyonidae/$m
9 > echo $m > mammals/Procyonidae/$m
10 > done
10 > done
11 $ echo skunk > mammals/skunk
11 $ echo skunk > mammals/skunk
12 $ echo fennel > fennel
12 $ echo fennel > fennel
13 $ echo fenugreek > fenugreek
13 $ echo fenugreek > fenugreek
14 $ echo fiddlehead > fiddlehead
14 $ echo fiddlehead > fiddlehead
15 $ hg addremove
15 $ hg addremove
16 adding beans/black
16 adding beans/black
17 adding beans/borlotti
17 adding beans/borlotti
18 adding beans/kidney
18 adding beans/kidney
19 adding beans/navy
19 adding beans/navy
20 adding beans/pinto
20 adding beans/pinto
21 adding beans/turtle
21 adding beans/turtle
22 adding fennel
22 adding fennel
23 adding fenugreek
23 adding fenugreek
24 adding fiddlehead
24 adding fiddlehead
25 adding mammals/Procyonidae/cacomistle
25 adding mammals/Procyonidae/cacomistle
26 adding mammals/Procyonidae/coatimundi
26 adding mammals/Procyonidae/coatimundi
27 adding mammals/Procyonidae/raccoon
27 adding mammals/Procyonidae/raccoon
28 adding mammals/skunk
28 adding mammals/skunk
29 $ hg commit -m "commit #0"
29 $ hg commit -m "commit #0"
30
30
31 $ hg debugwalk -v
31 $ hg debugwalk -v
32 * matcher:
32 * matcher:
33 <alwaysmatcher>
33 <alwaysmatcher>
34 f beans/black beans/black
34 f beans/black beans/black
35 f beans/borlotti beans/borlotti
35 f beans/borlotti beans/borlotti
36 f beans/kidney beans/kidney
36 f beans/kidney beans/kidney
37 f beans/navy beans/navy
37 f beans/navy beans/navy
38 f beans/pinto beans/pinto
38 f beans/pinto beans/pinto
39 f beans/turtle beans/turtle
39 f beans/turtle beans/turtle
40 f fennel fennel
40 f fennel fennel
41 f fenugreek fenugreek
41 f fenugreek fenugreek
42 f fiddlehead fiddlehead
42 f fiddlehead fiddlehead
43 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
43 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
44 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
44 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
45 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
45 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
46 f mammals/skunk mammals/skunk
46 f mammals/skunk mammals/skunk
47 $ hg debugwalk -v -I.
47 $ hg debugwalk -v -I.
48 * matcher:
48 * matcher:
49 <includematcher includes='(?:)'>
49 <includematcher includes=''>
50 f beans/black beans/black
50 f beans/black beans/black
51 f beans/borlotti beans/borlotti
51 f beans/borlotti beans/borlotti
52 f beans/kidney beans/kidney
52 f beans/kidney beans/kidney
53 f beans/navy beans/navy
53 f beans/navy beans/navy
54 f beans/pinto beans/pinto
54 f beans/pinto beans/pinto
55 f beans/turtle beans/turtle
55 f beans/turtle beans/turtle
56 f fennel fennel
56 f fennel fennel
57 f fenugreek fenugreek
57 f fenugreek fenugreek
58 f fiddlehead fiddlehead
58 f fiddlehead fiddlehead
59 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
59 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
60 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
60 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
61 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
61 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
62 f mammals/skunk mammals/skunk
62 f mammals/skunk mammals/skunk
63
63
64 $ cd mammals
64 $ cd mammals
65 $ hg debugwalk -v
65 $ hg debugwalk -v
66 * matcher:
66 * matcher:
67 <alwaysmatcher>
67 <alwaysmatcher>
68 f beans/black ../beans/black
68 f beans/black ../beans/black
69 f beans/borlotti ../beans/borlotti
69 f beans/borlotti ../beans/borlotti
70 f beans/kidney ../beans/kidney
70 f beans/kidney ../beans/kidney
71 f beans/navy ../beans/navy
71 f beans/navy ../beans/navy
72 f beans/pinto ../beans/pinto
72 f beans/pinto ../beans/pinto
73 f beans/turtle ../beans/turtle
73 f beans/turtle ../beans/turtle
74 f fennel ../fennel
74 f fennel ../fennel
75 f fenugreek ../fenugreek
75 f fenugreek ../fenugreek
76 f fiddlehead ../fiddlehead
76 f fiddlehead ../fiddlehead
77 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
77 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
78 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
78 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
79 f mammals/Procyonidae/raccoon Procyonidae/raccoon
79 f mammals/Procyonidae/raccoon Procyonidae/raccoon
80 f mammals/skunk skunk
80 f mammals/skunk skunk
81 $ hg debugwalk -v -X ../beans
81 $ hg debugwalk -v -X ../beans
82 * matcher:
82 * matcher:
83 <differencematcher
83 <differencematcher
84 m1=<alwaysmatcher>,
84 m1=<alwaysmatcher>,
85 m2=<includematcher includes='(?:beans(?:/|$))'>>
85 m2=<includematcher includes='beans(?:/|$)'>>
86 f fennel ../fennel
86 f fennel ../fennel
87 f fenugreek ../fenugreek
87 f fenugreek ../fenugreek
88 f fiddlehead ../fiddlehead
88 f fiddlehead ../fiddlehead
89 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
89 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
90 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
90 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
91 f mammals/Procyonidae/raccoon Procyonidae/raccoon
91 f mammals/Procyonidae/raccoon Procyonidae/raccoon
92 f mammals/skunk skunk
92 f mammals/skunk skunk
93 $ hg debugwalk -v -I '*k'
93 $ hg debugwalk -v -I '*k'
94 * matcher:
94 * matcher:
95 <includematcher includes='(?:mammals/[^/]*k(?:/|$))'>
95 <includematcher includes='mammals/[^/]*k(?:/|$)'>
96 f mammals/skunk skunk
96 f mammals/skunk skunk
97 $ hg debugwalk -v -I 'glob:*k'
97 $ hg debugwalk -v -I 'glob:*k'
98 * matcher:
98 * matcher:
99 <includematcher includes='(?:mammals/[^/]*k(?:/|$))'>
99 <includematcher includes='mammals/[^/]*k(?:/|$)'>
100 f mammals/skunk skunk
100 f mammals/skunk skunk
101 $ hg debugwalk -v -I 'relglob:*k'
101 $ hg debugwalk -v -I 'relglob:*k'
102 * matcher:
102 * matcher:
103 <includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>
103 <includematcher includes='(?:|.*/)[^/]*k(?:/|$)'>
104 f beans/black ../beans/black
104 f beans/black ../beans/black
105 f fenugreek ../fenugreek
105 f fenugreek ../fenugreek
106 f mammals/skunk skunk
106 f mammals/skunk skunk
107 $ hg debugwalk -v -I 'relglob:*k' .
107 $ hg debugwalk -v -I 'relglob:*k' .
108 * matcher:
108 * matcher:
109 <intersectionmatcher
109 <intersectionmatcher
110 m1=<patternmatcher patterns='(?:mammals(?:/|$))'>,
110 m1=<patternmatcher patterns='mammals(?:/|$)'>,
111 m2=<includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>>
111 m2=<includematcher includes='(?:|.*/)[^/]*k(?:/|$)'>>
112 f mammals/skunk skunk
112 f mammals/skunk skunk
113 $ hg debugwalk -v -I 're:.*k$'
113 $ hg debugwalk -v -I 're:.*k$'
114 * matcher:
114 * matcher:
115 <includematcher includes='(?:.*k$)'>
115 <includematcher includes='.*k$'>
116 f beans/black ../beans/black
116 f beans/black ../beans/black
117 f fenugreek ../fenugreek
117 f fenugreek ../fenugreek
118 f mammals/skunk skunk
118 f mammals/skunk skunk
119 $ hg debugwalk -v -I 'relre:.*k$'
119 $ hg debugwalk -v -I 'relre:.*k$'
120 * matcher:
120 * matcher:
121 <includematcher includes='(?:.*.*k$)'>
121 <includematcher includes='.*.*k$'>
122 f beans/black ../beans/black
122 f beans/black ../beans/black
123 f fenugreek ../fenugreek
123 f fenugreek ../fenugreek
124 f mammals/skunk skunk
124 f mammals/skunk skunk
125 $ hg debugwalk -v -I 'path:beans'
125 $ hg debugwalk -v -I 'path:beans'
126 * matcher:
126 * matcher:
127 <includematcher includes='(?:beans(?:/|$))'>
127 <includematcher includes='beans(?:/|$)'>
128 f beans/black ../beans/black
128 f beans/black ../beans/black
129 f beans/borlotti ../beans/borlotti
129 f beans/borlotti ../beans/borlotti
130 f beans/kidney ../beans/kidney
130 f beans/kidney ../beans/kidney
131 f beans/navy ../beans/navy
131 f beans/navy ../beans/navy
132 f beans/pinto ../beans/pinto
132 f beans/pinto ../beans/pinto
133 f beans/turtle ../beans/turtle
133 f beans/turtle ../beans/turtle
134 $ hg debugwalk -v -I 'relpath:detour/../../beans'
134 $ hg debugwalk -v -I 'relpath:detour/../../beans'
135 * matcher:
135 * matcher:
136 <includematcher includes='(?:beans(?:/|$))'>
136 <includematcher includes='beans(?:/|$)'>
137 f beans/black ../beans/black
137 f beans/black ../beans/black
138 f beans/borlotti ../beans/borlotti
138 f beans/borlotti ../beans/borlotti
139 f beans/kidney ../beans/kidney
139 f beans/kidney ../beans/kidney
140 f beans/navy ../beans/navy
140 f beans/navy ../beans/navy
141 f beans/pinto ../beans/pinto
141 f beans/pinto ../beans/pinto
142 f beans/turtle ../beans/turtle
142 f beans/turtle ../beans/turtle
143
143
144 $ hg debugwalk -v 'rootfilesin:'
144 $ hg debugwalk -v 'rootfilesin:'
145 * matcher:
145 * matcher:
146 <patternmatcher patterns="rootfilesin: ['.']">
146 <patternmatcher patterns="rootfilesin: ['.']">
147 f fennel ../fennel
147 f fennel ../fennel
148 f fenugreek ../fenugreek
148 f fenugreek ../fenugreek
149 f fiddlehead ../fiddlehead
149 f fiddlehead ../fiddlehead
150 $ hg debugwalk -v -I 'rootfilesin:'
150 $ hg debugwalk -v -I 'rootfilesin:'
151 * matcher:
151 * matcher:
152 <includematcher includes="rootfilesin: ['.']">
152 <includematcher includes="rootfilesin: ['.']">
153 f fennel ../fennel
153 f fennel ../fennel
154 f fenugreek ../fenugreek
154 f fenugreek ../fenugreek
155 f fiddlehead ../fiddlehead
155 f fiddlehead ../fiddlehead
156 $ hg debugwalk -v 'rootfilesin:.'
156 $ hg debugwalk -v 'rootfilesin:.'
157 * matcher:
157 * matcher:
158 <patternmatcher patterns="rootfilesin: ['.']">
158 <patternmatcher patterns="rootfilesin: ['.']">
159 f fennel ../fennel
159 f fennel ../fennel
160 f fenugreek ../fenugreek
160 f fenugreek ../fenugreek
161 f fiddlehead ../fiddlehead
161 f fiddlehead ../fiddlehead
162 $ hg debugwalk -v -I 'rootfilesin:.'
162 $ hg debugwalk -v -I 'rootfilesin:.'
163 * matcher:
163 * matcher:
164 <includematcher includes="rootfilesin: ['.']">
164 <includematcher includes="rootfilesin: ['.']">
165 f fennel ../fennel
165 f fennel ../fennel
166 f fenugreek ../fenugreek
166 f fenugreek ../fenugreek
167 f fiddlehead ../fiddlehead
167 f fiddlehead ../fiddlehead
168 $ hg debugwalk -v -X 'rootfilesin:'
168 $ hg debugwalk -v -X 'rootfilesin:'
169 * matcher:
169 * matcher:
170 <differencematcher
170 <differencematcher
171 m1=<alwaysmatcher>,
171 m1=<alwaysmatcher>,
172 m2=<includematcher includes="rootfilesin: ['.']">>
172 m2=<includematcher includes="rootfilesin: ['.']">>
173 f beans/black ../beans/black
173 f beans/black ../beans/black
174 f beans/borlotti ../beans/borlotti
174 f beans/borlotti ../beans/borlotti
175 f beans/kidney ../beans/kidney
175 f beans/kidney ../beans/kidney
176 f beans/navy ../beans/navy
176 f beans/navy ../beans/navy
177 f beans/pinto ../beans/pinto
177 f beans/pinto ../beans/pinto
178 f beans/turtle ../beans/turtle
178 f beans/turtle ../beans/turtle
179 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
179 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
180 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
180 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
181 f mammals/Procyonidae/raccoon Procyonidae/raccoon
181 f mammals/Procyonidae/raccoon Procyonidae/raccoon
182 f mammals/skunk skunk
182 f mammals/skunk skunk
183 $ hg debugwalk -v 'rootfilesin:fennel'
183 $ hg debugwalk -v 'rootfilesin:fennel'
184 * matcher:
184 * matcher:
185 <patternmatcher patterns="rootfilesin: ['fennel']">
185 <patternmatcher patterns="rootfilesin: ['fennel']">
186 $ hg debugwalk -v -I 'rootfilesin:fennel'
186 $ hg debugwalk -v -I 'rootfilesin:fennel'
187 * matcher:
187 * matcher:
188 <includematcher includes="rootfilesin: ['fennel']">
188 <includematcher includes="rootfilesin: ['fennel']">
189 $ hg debugwalk -v 'rootfilesin:skunk'
189 $ hg debugwalk -v 'rootfilesin:skunk'
190 * matcher:
190 * matcher:
191 <patternmatcher patterns="rootfilesin: ['skunk']">
191 <patternmatcher patterns="rootfilesin: ['skunk']">
192 $ hg debugwalk -v -I 'rootfilesin:skunk'
192 $ hg debugwalk -v -I 'rootfilesin:skunk'
193 * matcher:
193 * matcher:
194 <includematcher includes="rootfilesin: ['skunk']">
194 <includematcher includes="rootfilesin: ['skunk']">
195 $ hg debugwalk -v 'rootfilesin:beans'
195 $ hg debugwalk -v 'rootfilesin:beans'
196 * matcher:
196 * matcher:
197 <patternmatcher patterns="rootfilesin: ['beans']">
197 <patternmatcher patterns="rootfilesin: ['beans']">
198 f beans/black ../beans/black
198 f beans/black ../beans/black
199 f beans/borlotti ../beans/borlotti
199 f beans/borlotti ../beans/borlotti
200 f beans/kidney ../beans/kidney
200 f beans/kidney ../beans/kidney
201 f beans/navy ../beans/navy
201 f beans/navy ../beans/navy
202 f beans/pinto ../beans/pinto
202 f beans/pinto ../beans/pinto
203 f beans/turtle ../beans/turtle
203 f beans/turtle ../beans/turtle
204 $ hg debugwalk -v -I 'rootfilesin:beans'
204 $ hg debugwalk -v -I 'rootfilesin:beans'
205 * matcher:
205 * matcher:
206 <includematcher includes="rootfilesin: ['beans']">
206 <includematcher includes="rootfilesin: ['beans']">
207 f beans/black ../beans/black
207 f beans/black ../beans/black
208 f beans/borlotti ../beans/borlotti
208 f beans/borlotti ../beans/borlotti
209 f beans/kidney ../beans/kidney
209 f beans/kidney ../beans/kidney
210 f beans/navy ../beans/navy
210 f beans/navy ../beans/navy
211 f beans/pinto ../beans/pinto
211 f beans/pinto ../beans/pinto
212 f beans/turtle ../beans/turtle
212 f beans/turtle ../beans/turtle
213 $ hg debugwalk -v 'rootfilesin:mammals'
213 $ hg debugwalk -v 'rootfilesin:mammals'
214 * matcher:
214 * matcher:
215 <patternmatcher patterns="rootfilesin: ['mammals']">
215 <patternmatcher patterns="rootfilesin: ['mammals']">
216 f mammals/skunk skunk
216 f mammals/skunk skunk
217 $ hg debugwalk -v -I 'rootfilesin:mammals'
217 $ hg debugwalk -v -I 'rootfilesin:mammals'
218 * matcher:
218 * matcher:
219 <includematcher includes="rootfilesin: ['mammals']">
219 <includematcher includes="rootfilesin: ['mammals']">
220 f mammals/skunk skunk
220 f mammals/skunk skunk
221 $ hg debugwalk -v 'rootfilesin:mammals/'
221 $ hg debugwalk -v 'rootfilesin:mammals/'
222 * matcher:
222 * matcher:
223 <patternmatcher patterns="rootfilesin: ['mammals']">
223 <patternmatcher patterns="rootfilesin: ['mammals']">
224 f mammals/skunk skunk
224 f mammals/skunk skunk
225 $ hg debugwalk -v -I 'rootfilesin:mammals/'
225 $ hg debugwalk -v -I 'rootfilesin:mammals/'
226 * matcher:
226 * matcher:
227 <includematcher includes="rootfilesin: ['mammals']">
227 <includematcher includes="rootfilesin: ['mammals']">
228 f mammals/skunk skunk
228 f mammals/skunk skunk
229 $ hg debugwalk -v -X 'rootfilesin:mammals'
229 $ hg debugwalk -v -X 'rootfilesin:mammals'
230 * matcher:
230 * matcher:
231 <differencematcher
231 <differencematcher
232 m1=<alwaysmatcher>,
232 m1=<alwaysmatcher>,
233 m2=<includematcher includes="rootfilesin: ['mammals']">>
233 m2=<includematcher includes="rootfilesin: ['mammals']">>
234 f beans/black ../beans/black
234 f beans/black ../beans/black
235 f beans/borlotti ../beans/borlotti
235 f beans/borlotti ../beans/borlotti
236 f beans/kidney ../beans/kidney
236 f beans/kidney ../beans/kidney
237 f beans/navy ../beans/navy
237 f beans/navy ../beans/navy
238 f beans/pinto ../beans/pinto
238 f beans/pinto ../beans/pinto
239 f beans/turtle ../beans/turtle
239 f beans/turtle ../beans/turtle
240 f fennel ../fennel
240 f fennel ../fennel
241 f fenugreek ../fenugreek
241 f fenugreek ../fenugreek
242 f fiddlehead ../fiddlehead
242 f fiddlehead ../fiddlehead
243 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
243 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
244 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
244 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
245 f mammals/Procyonidae/raccoon Procyonidae/raccoon
245 f mammals/Procyonidae/raccoon Procyonidae/raccoon
246
246
247 $ hg debugwalk -v .
247 $ hg debugwalk -v .
248 * matcher:
248 * matcher:
249 <patternmatcher patterns='(?:mammals(?:/|$))'>
249 <patternmatcher patterns='mammals(?:/|$)'>
250 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
250 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
251 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
251 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
252 f mammals/Procyonidae/raccoon Procyonidae/raccoon
252 f mammals/Procyonidae/raccoon Procyonidae/raccoon
253 f mammals/skunk skunk
253 f mammals/skunk skunk
254 $ hg debugwalk -v -I.
254 $ hg debugwalk -v -I.
255 * matcher:
255 * matcher:
256 <includematcher includes='(?:mammals(?:/|$))'>
256 <includematcher includes='mammals(?:/|$)'>
257 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
257 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
258 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
258 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
259 f mammals/Procyonidae/raccoon Procyonidae/raccoon
259 f mammals/Procyonidae/raccoon Procyonidae/raccoon
260 f mammals/skunk skunk
260 f mammals/skunk skunk
261 $ hg debugwalk -v Procyonidae
261 $ hg debugwalk -v Procyonidae
262 * matcher:
262 * matcher:
263 <patternmatcher patterns='(?:mammals/Procyonidae(?:/|$))'>
263 <patternmatcher patterns='mammals/Procyonidae(?:/|$)'>
264 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
264 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
265 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
265 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
266 f mammals/Procyonidae/raccoon Procyonidae/raccoon
266 f mammals/Procyonidae/raccoon Procyonidae/raccoon
267
267
268 $ cd Procyonidae
268 $ cd Procyonidae
269 $ hg debugwalk -v .
269 $ hg debugwalk -v .
270 * matcher:
270 * matcher:
271 <patternmatcher patterns='(?:mammals/Procyonidae(?:/|$))'>
271 <patternmatcher patterns='mammals/Procyonidae(?:/|$)'>
272 f mammals/Procyonidae/cacomistle cacomistle
272 f mammals/Procyonidae/cacomistle cacomistle
273 f mammals/Procyonidae/coatimundi coatimundi
273 f mammals/Procyonidae/coatimundi coatimundi
274 f mammals/Procyonidae/raccoon raccoon
274 f mammals/Procyonidae/raccoon raccoon
275 $ hg debugwalk -v ..
275 $ hg debugwalk -v ..
276 * matcher:
276 * matcher:
277 <patternmatcher patterns='(?:mammals(?:/|$))'>
277 <patternmatcher patterns='mammals(?:/|$)'>
278 f mammals/Procyonidae/cacomistle cacomistle
278 f mammals/Procyonidae/cacomistle cacomistle
279 f mammals/Procyonidae/coatimundi coatimundi
279 f mammals/Procyonidae/coatimundi coatimundi
280 f mammals/Procyonidae/raccoon raccoon
280 f mammals/Procyonidae/raccoon raccoon
281 f mammals/skunk ../skunk
281 f mammals/skunk ../skunk
282 $ cd ..
282 $ cd ..
283
283
284 $ hg debugwalk -v ../beans
284 $ hg debugwalk -v ../beans
285 * matcher:
285 * matcher:
286 <patternmatcher patterns='(?:beans(?:/|$))'>
286 <patternmatcher patterns='beans(?:/|$)'>
287 f beans/black ../beans/black
287 f beans/black ../beans/black
288 f beans/borlotti ../beans/borlotti
288 f beans/borlotti ../beans/borlotti
289 f beans/kidney ../beans/kidney
289 f beans/kidney ../beans/kidney
290 f beans/navy ../beans/navy
290 f beans/navy ../beans/navy
291 f beans/pinto ../beans/pinto
291 f beans/pinto ../beans/pinto
292 f beans/turtle ../beans/turtle
292 f beans/turtle ../beans/turtle
293 $ hg debugwalk -v .
293 $ hg debugwalk -v .
294 * matcher:
294 * matcher:
295 <patternmatcher patterns='(?:mammals(?:/|$))'>
295 <patternmatcher patterns='mammals(?:/|$)'>
296 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
296 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
297 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
297 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
298 f mammals/Procyonidae/raccoon Procyonidae/raccoon
298 f mammals/Procyonidae/raccoon Procyonidae/raccoon
299 f mammals/skunk skunk
299 f mammals/skunk skunk
300 $ hg debugwalk -v .hg
300 $ hg debugwalk -v .hg
301 abort: path 'mammals/.hg' is inside nested repo 'mammals'
301 abort: path 'mammals/.hg' is inside nested repo 'mammals'
302 [255]
302 [255]
303 $ hg debugwalk -v ../.hg
303 $ hg debugwalk -v ../.hg
304 abort: path contains illegal component: .hg
304 abort: path contains illegal component: .hg
305 [255]
305 [255]
306 $ cd ..
306 $ cd ..
307
307
308 $ hg debugwalk -v -Ibeans
308 $ hg debugwalk -v -Ibeans
309 * matcher:
309 * matcher:
310 <includematcher includes='(?:beans(?:/|$))'>
310 <includematcher includes='beans(?:/|$)'>
311 f beans/black beans/black
311 f beans/black beans/black
312 f beans/borlotti beans/borlotti
312 f beans/borlotti beans/borlotti
313 f beans/kidney beans/kidney
313 f beans/kidney beans/kidney
314 f beans/navy beans/navy
314 f beans/navy beans/navy
315 f beans/pinto beans/pinto
315 f beans/pinto beans/pinto
316 f beans/turtle beans/turtle
316 f beans/turtle beans/turtle
317 $ hg debugwalk -v -I '{*,{b,m}*/*}k'
317 $ hg debugwalk -v -I '{*,{b,m}*/*}k'
318 * matcher:
318 * matcher:
319 <includematcher includes='(?:(?:[^/]*|(?:b|m)[^/]*/[^/]*)k(?:/|$))'>
319 <includematcher includes='(?:[^/]*|(?:b|m)[^/]*/[^/]*)k(?:/|$)'>
320 f beans/black beans/black
320 f beans/black beans/black
321 f fenugreek fenugreek
321 f fenugreek fenugreek
322 f mammals/skunk mammals/skunk
322 f mammals/skunk mammals/skunk
323 $ hg debugwalk -v -Ibeans mammals
323 $ hg debugwalk -v -Ibeans mammals
324 * matcher:
324 * matcher:
325 <intersectionmatcher
325 <intersectionmatcher
326 m1=<patternmatcher patterns='(?:mammals(?:/|$))'>,
326 m1=<patternmatcher patterns='mammals(?:/|$)'>,
327 m2=<includematcher includes='(?:beans(?:/|$))'>>
327 m2=<includematcher includes='beans(?:/|$)'>>
328 $ hg debugwalk -v -Inon-existent
328 $ hg debugwalk -v -Inon-existent
329 * matcher:
329 * matcher:
330 <includematcher includes='(?:non\\-existent(?:/|$))'>
330 <includematcher includes='non\\-existent(?:/|$)'>
331 $ hg debugwalk -v -Inon-existent -Ibeans/black
331 $ hg debugwalk -v -Inon-existent -Ibeans/black
332 * matcher:
332 * matcher:
333 <includematcher includes='(?:non\\-existent(?:/|$)|beans/black(?:/|$))'>
333 <includematcher includes='non\\-existent(?:/|$)|beans/black(?:/|$)'>
334 f beans/black beans/black
334 f beans/black beans/black
335 $ hg debugwalk -v -Ibeans beans/black
335 $ hg debugwalk -v -Ibeans beans/black
336 * matcher:
336 * matcher:
337 <intersectionmatcher
337 <intersectionmatcher
338 m1=<patternmatcher patterns='(?:beans/black(?:/|$))'>,
338 m1=<patternmatcher patterns='beans/black(?:/|$)'>,
339 m2=<includematcher includes='(?:beans(?:/|$))'>>
339 m2=<includematcher includes='beans(?:/|$)'>>
340 f beans/black beans/black exact
340 f beans/black beans/black exact
341 $ hg debugwalk -v -Ibeans/black beans
341 $ hg debugwalk -v -Ibeans/black beans
342 * matcher:
342 * matcher:
343 <intersectionmatcher
343 <intersectionmatcher
344 m1=<patternmatcher patterns='(?:beans(?:/|$))'>,
344 m1=<patternmatcher patterns='beans(?:/|$)'>,
345 m2=<includematcher includes='(?:beans/black(?:/|$))'>>
345 m2=<includematcher includes='beans/black(?:/|$)'>>
346 f beans/black beans/black
346 f beans/black beans/black
347 $ hg debugwalk -v -Xbeans/black beans
347 $ hg debugwalk -v -Xbeans/black beans
348 * matcher:
348 * matcher:
349 <differencematcher
349 <differencematcher
350 m1=<patternmatcher patterns='(?:beans(?:/|$))'>,
350 m1=<patternmatcher patterns='beans(?:/|$)'>,
351 m2=<includematcher includes='(?:beans/black(?:/|$))'>>
351 m2=<includematcher includes='beans/black(?:/|$)'>>
352 f beans/borlotti beans/borlotti
352 f beans/borlotti beans/borlotti
353 f beans/kidney beans/kidney
353 f beans/kidney beans/kidney
354 f beans/navy beans/navy
354 f beans/navy beans/navy
355 f beans/pinto beans/pinto
355 f beans/pinto beans/pinto
356 f beans/turtle beans/turtle
356 f beans/turtle beans/turtle
357 $ hg debugwalk -v -Xbeans/black -Ibeans
357 $ hg debugwalk -v -Xbeans/black -Ibeans
358 * matcher:
358 * matcher:
359 <differencematcher
359 <differencematcher
360 m1=<includematcher includes='(?:beans(?:/|$))'>,
360 m1=<includematcher includes='beans(?:/|$)'>,
361 m2=<includematcher includes='(?:beans/black(?:/|$))'>>
361 m2=<includematcher includes='beans/black(?:/|$)'>>
362 f beans/borlotti beans/borlotti
362 f beans/borlotti beans/borlotti
363 f beans/kidney beans/kidney
363 f beans/kidney beans/kidney
364 f beans/navy beans/navy
364 f beans/navy beans/navy
365 f beans/pinto beans/pinto
365 f beans/pinto beans/pinto
366 f beans/turtle beans/turtle
366 f beans/turtle beans/turtle
367 $ hg debugwalk -v -Xbeans/black beans/black
367 $ hg debugwalk -v -Xbeans/black beans/black
368 * matcher:
368 * matcher:
369 <differencematcher
369 <differencematcher
370 m1=<patternmatcher patterns='(?:beans/black(?:/|$))'>,
370 m1=<patternmatcher patterns='beans/black(?:/|$)'>,
371 m2=<includematcher includes='(?:beans/black(?:/|$))'>>
371 m2=<includematcher includes='beans/black(?:/|$)'>>
372 $ hg debugwalk -v -Xbeans/black -Ibeans/black
372 $ hg debugwalk -v -Xbeans/black -Ibeans/black
373 * matcher:
373 * matcher:
374 <differencematcher
374 <differencematcher
375 m1=<includematcher includes='(?:beans/black(?:/|$))'>,
375 m1=<includematcher includes='beans/black(?:/|$)'>,
376 m2=<includematcher includes='(?:beans/black(?:/|$))'>>
376 m2=<includematcher includes='beans/black(?:/|$)'>>
377 $ hg debugwalk -v -Xbeans beans/black
377 $ hg debugwalk -v -Xbeans beans/black
378 * matcher:
378 * matcher:
379 <differencematcher
379 <differencematcher
380 m1=<patternmatcher patterns='(?:beans/black(?:/|$))'>,
380 m1=<patternmatcher patterns='beans/black(?:/|$)'>,
381 m2=<includematcher includes='(?:beans(?:/|$))'>>
381 m2=<includematcher includes='beans(?:/|$)'>>
382 $ hg debugwalk -v -Xbeans -Ibeans/black
382 $ hg debugwalk -v -Xbeans -Ibeans/black
383 * matcher:
383 * matcher:
384 <differencematcher
384 <differencematcher
385 m1=<includematcher includes='(?:beans/black(?:/|$))'>,
385 m1=<includematcher includes='beans/black(?:/|$)'>,
386 m2=<includematcher includes='(?:beans(?:/|$))'>>
386 m2=<includematcher includes='beans(?:/|$)'>>
387 $ hg debugwalk -v 'glob:mammals/../beans/b*'
387 $ hg debugwalk -v 'glob:mammals/../beans/b*'
388 * matcher:
388 * matcher:
389 <patternmatcher patterns='(?:beans/b[^/]*$)'>
389 <patternmatcher patterns='beans/b[^/]*$'>
390 f beans/black beans/black
390 f beans/black beans/black
391 f beans/borlotti beans/borlotti
391 f beans/borlotti beans/borlotti
392 $ hg debugwalk -v '-X*/Procyonidae' mammals
392 $ hg debugwalk -v '-X*/Procyonidae' mammals
393 * matcher:
393 * matcher:
394 <differencematcher
394 <differencematcher
395 m1=<patternmatcher patterns='(?:mammals(?:/|$))'>,
395 m1=<patternmatcher patterns='mammals(?:/|$)'>,
396 m2=<includematcher includes='(?:[^/]*/Procyonidae(?:/|$))'>>
396 m2=<includematcher includes='[^/]*/Procyonidae(?:/|$)'>>
397 f mammals/skunk mammals/skunk
397 f mammals/skunk mammals/skunk
398 $ hg debugwalk -v path:mammals
398 $ hg debugwalk -v path:mammals
399 * matcher:
399 * matcher:
400 <patternmatcher patterns='(?:mammals(?:/|$))'>
400 <patternmatcher patterns='mammals(?:/|$)'>
401 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
401 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
402 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
402 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
403 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
403 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
404 f mammals/skunk mammals/skunk
404 f mammals/skunk mammals/skunk
405 $ hg debugwalk -v ..
405 $ hg debugwalk -v ..
406 abort: .. not under root '$TESTTMP/t'
406 abort: .. not under root '$TESTTMP/t'
407 [255]
407 [255]
408 $ hg debugwalk -v beans/../..
408 $ hg debugwalk -v beans/../..
409 abort: beans/../.. not under root '$TESTTMP/t'
409 abort: beans/../.. not under root '$TESTTMP/t'
410 [255]
410 [255]
411 $ hg debugwalk -v .hg
411 $ hg debugwalk -v .hg
412 abort: path contains illegal component: .hg
412 abort: path contains illegal component: .hg
413 [255]
413 [255]
414 $ hg debugwalk -v beans/../.hg
414 $ hg debugwalk -v beans/../.hg
415 abort: path contains illegal component: .hg
415 abort: path contains illegal component: .hg
416 [255]
416 [255]
417 $ hg debugwalk -v beans/../.hg/data
417 $ hg debugwalk -v beans/../.hg/data
418 abort: path contains illegal component: .hg/data
418 abort: path contains illegal component: .hg/data
419 [255]
419 [255]
420 $ hg debugwalk -v beans/.hg
420 $ hg debugwalk -v beans/.hg
421 abort: path 'beans/.hg' is inside nested repo 'beans'
421 abort: path 'beans/.hg' is inside nested repo 'beans'
422 [255]
422 [255]
423
423
424 Test explicit paths and excludes:
424 Test explicit paths and excludes:
425
425
426 $ hg debugwalk -v fennel -X fennel
426 $ hg debugwalk -v fennel -X fennel
427 * matcher:
427 * matcher:
428 <differencematcher
428 <differencematcher
429 m1=<patternmatcher patterns='(?:fennel(?:/|$))'>,
429 m1=<patternmatcher patterns='fennel(?:/|$)'>,
430 m2=<includematcher includes='(?:fennel(?:/|$))'>>
430 m2=<includematcher includes='fennel(?:/|$)'>>
431 $ hg debugwalk -v fennel -X 'f*'
431 $ hg debugwalk -v fennel -X 'f*'
432 * matcher:
432 * matcher:
433 <differencematcher
433 <differencematcher
434 m1=<patternmatcher patterns='(?:fennel(?:/|$))'>,
434 m1=<patternmatcher patterns='fennel(?:/|$)'>,
435 m2=<includematcher includes='(?:f[^/]*(?:/|$))'>>
435 m2=<includematcher includes='f[^/]*(?:/|$)'>>
436 $ hg debugwalk -v beans/black -X 'path:beans'
436 $ hg debugwalk -v beans/black -X 'path:beans'
437 * matcher:
437 * matcher:
438 <differencematcher
438 <differencematcher
439 m1=<patternmatcher patterns='(?:beans/black(?:/|$))'>,
439 m1=<patternmatcher patterns='beans/black(?:/|$)'>,
440 m2=<includematcher includes='(?:beans(?:/|$))'>>
440 m2=<includematcher includes='beans(?:/|$)'>>
441 $ hg debugwalk -v -I 'path:beans/black' -X 'path:beans'
441 $ hg debugwalk -v -I 'path:beans/black' -X 'path:beans'
442 * matcher:
442 * matcher:
443 <differencematcher
443 <differencematcher
444 m1=<includematcher includes='(?:beans/black(?:/|$))'>,
444 m1=<includematcher includes='beans/black(?:/|$)'>,
445 m2=<includematcher includes='(?:beans(?:/|$))'>>
445 m2=<includematcher includes='beans(?:/|$)'>>
446
446
447 Test absolute paths:
447 Test absolute paths:
448
448
449 $ hg debugwalk -v `pwd`/beans
449 $ hg debugwalk -v `pwd`/beans
450 * matcher:
450 * matcher:
451 <patternmatcher patterns='(?:beans(?:/|$))'>
451 <patternmatcher patterns='beans(?:/|$)'>
452 f beans/black beans/black
452 f beans/black beans/black
453 f beans/borlotti beans/borlotti
453 f beans/borlotti beans/borlotti
454 f beans/kidney beans/kidney
454 f beans/kidney beans/kidney
455 f beans/navy beans/navy
455 f beans/navy beans/navy
456 f beans/pinto beans/pinto
456 f beans/pinto beans/pinto
457 f beans/turtle beans/turtle
457 f beans/turtle beans/turtle
458 $ hg debugwalk -v `pwd`/..
458 $ hg debugwalk -v `pwd`/..
459 abort: $TESTTMP/t/.. not under root '$TESTTMP/t'
459 abort: $TESTTMP/t/.. not under root '$TESTTMP/t'
460 [255]
460 [255]
461
461
462 Test patterns:
462 Test patterns:
463
463
464 $ hg debugwalk -v glob:\*
464 $ hg debugwalk -v glob:\*
465 * matcher:
465 * matcher:
466 <patternmatcher patterns='(?:[^/]*$)'>
466 <patternmatcher patterns='[^/]*$'>
467 f fennel fennel
467 f fennel fennel
468 f fenugreek fenugreek
468 f fenugreek fenugreek
469 f fiddlehead fiddlehead
469 f fiddlehead fiddlehead
470 #if eol-in-paths
470 #if eol-in-paths
471 $ echo glob:glob > glob:glob
471 $ echo glob:glob > glob:glob
472 $ hg addremove
472 $ hg addremove
473 adding glob:glob
473 adding glob:glob
474 warning: filename contains ':', which is reserved on Windows: 'glob:glob'
474 warning: filename contains ':', which is reserved on Windows: 'glob:glob'
475 $ hg debugwalk -v glob:\*
475 $ hg debugwalk -v glob:\*
476 * matcher:
476 * matcher:
477 <patternmatcher patterns='(?:[^/]*$)'>
477 <patternmatcher patterns='[^/]*$'>
478 f fennel fennel
478 f fennel fennel
479 f fenugreek fenugreek
479 f fenugreek fenugreek
480 f fiddlehead fiddlehead
480 f fiddlehead fiddlehead
481 f glob:glob glob:glob
481 f glob:glob glob:glob
482 $ hg debugwalk -v glob:glob
482 $ hg debugwalk -v glob:glob
483 * matcher:
483 * matcher:
484 <patternmatcher patterns='(?:glob$)'>
484 <patternmatcher patterns='glob$'>
485 glob: $ENOENT$
485 glob: $ENOENT$
486 $ hg debugwalk -v glob:glob:glob
486 $ hg debugwalk -v glob:glob:glob
487 * matcher:
487 * matcher:
488 <patternmatcher patterns='(?:glob:glob$)'>
488 <patternmatcher patterns='glob:glob$'>
489 f glob:glob glob:glob exact
489 f glob:glob glob:glob exact
490 $ hg debugwalk -v path:glob:glob
490 $ hg debugwalk -v path:glob:glob
491 * matcher:
491 * matcher:
492 <patternmatcher patterns='(?:glob:glob(?:/|$))'>
492 <patternmatcher patterns='glob:glob(?:/|$)'>
493 f glob:glob glob:glob exact
493 f glob:glob glob:glob exact
494 $ rm glob:glob
494 $ rm glob:glob
495 $ hg addremove
495 $ hg addremove
496 removing glob:glob
496 removing glob:glob
497 #endif
497 #endif
498
498
499 $ hg debugwalk -v 'glob:**e'
499 $ hg debugwalk -v 'glob:**e'
500 * matcher:
500 * matcher:
501 <patternmatcher patterns='(?:.*e$)'>
501 <patternmatcher patterns='.*e$'>
502 f beans/turtle beans/turtle
502 f beans/turtle beans/turtle
503 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
503 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
504
504
505 $ hg debugwalk -v 're:.*[kb]$'
505 $ hg debugwalk -v 're:.*[kb]$'
506 * matcher:
506 * matcher:
507 <patternmatcher patterns='(?:.*[kb]$)'>
507 <patternmatcher patterns='.*[kb]$'>
508 f beans/black beans/black
508 f beans/black beans/black
509 f fenugreek fenugreek
509 f fenugreek fenugreek
510 f mammals/skunk mammals/skunk
510 f mammals/skunk mammals/skunk
511
511
512 $ hg debugwalk -v path:beans/black
512 $ hg debugwalk -v path:beans/black
513 * matcher:
513 * matcher:
514 <patternmatcher patterns='(?:beans/black(?:/|$))'>
514 <patternmatcher patterns='beans/black(?:/|$)'>
515 f beans/black beans/black exact
515 f beans/black beans/black exact
516 $ hg debugwalk -v path:beans//black
516 $ hg debugwalk -v path:beans//black
517 * matcher:
517 * matcher:
518 <patternmatcher patterns='(?:beans/black(?:/|$))'>
518 <patternmatcher patterns='beans/black(?:/|$)'>
519 f beans/black beans/black exact
519 f beans/black beans/black exact
520
520
521 $ hg debugwalk -v relglob:Procyonidae
521 $ hg debugwalk -v relglob:Procyonidae
522 * matcher:
522 * matcher:
523 <patternmatcher patterns='(?:(?:|.*/)Procyonidae$)'>
523 <patternmatcher patterns='(?:|.*/)Procyonidae$'>
524 $ hg debugwalk -v 'relglob:Procyonidae/**'
524 $ hg debugwalk -v 'relglob:Procyonidae/**'
525 * matcher:
525 * matcher:
526 <patternmatcher patterns='(?:(?:|.*/)Procyonidae/.*$)'>
526 <patternmatcher patterns='(?:|.*/)Procyonidae/.*$'>
527 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
527 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
528 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
528 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
529 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
529 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
530 $ hg debugwalk -v 'relglob:Procyonidae/**' fennel
530 $ hg debugwalk -v 'relglob:Procyonidae/**' fennel
531 * matcher:
531 * matcher:
532 <patternmatcher patterns='(?:(?:|.*/)Procyonidae/.*$|fennel(?:/|$))'>
532 <patternmatcher patterns='(?:|.*/)Procyonidae/.*$|fennel(?:/|$)'>
533 f fennel fennel exact
533 f fennel fennel exact
534 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
534 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
535 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
535 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
536 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
536 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
537 $ hg debugwalk -v beans 'glob:beans/*'
537 $ hg debugwalk -v beans 'glob:beans/*'
538 * matcher:
538 * matcher:
539 <patternmatcher patterns='(?:beans(?:/|$)|beans/[^/]*$)'>
539 <patternmatcher patterns='beans(?:/|$)|beans/[^/]*$'>
540 f beans/black beans/black
540 f beans/black beans/black
541 f beans/borlotti beans/borlotti
541 f beans/borlotti beans/borlotti
542 f beans/kidney beans/kidney
542 f beans/kidney beans/kidney
543 f beans/navy beans/navy
543 f beans/navy beans/navy
544 f beans/pinto beans/pinto
544 f beans/pinto beans/pinto
545 f beans/turtle beans/turtle
545 f beans/turtle beans/turtle
546 $ hg debugwalk -v 'glob:mamm**'
546 $ hg debugwalk -v 'glob:mamm**'
547 * matcher:
547 * matcher:
548 <patternmatcher patterns='(?:mamm.*$)'>
548 <patternmatcher patterns='mamm.*$'>
549 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
549 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
550 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
550 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
551 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
551 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
552 f mammals/skunk mammals/skunk
552 f mammals/skunk mammals/skunk
553 $ hg debugwalk -v 'glob:mamm**' fennel
553 $ hg debugwalk -v 'glob:mamm**' fennel
554 * matcher:
554 * matcher:
555 <patternmatcher patterns='(?:mamm.*$|fennel(?:/|$))'>
555 <patternmatcher patterns='mamm.*$|fennel(?:/|$)'>
556 f fennel fennel exact
556 f fennel fennel exact
557 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
557 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
558 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
558 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
559 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
559 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
560 f mammals/skunk mammals/skunk
560 f mammals/skunk mammals/skunk
561 $ hg debugwalk -v 'glob:j*'
561 $ hg debugwalk -v 'glob:j*'
562 * matcher:
562 * matcher:
563 <patternmatcher patterns='(?:j[^/]*$)'>
563 <patternmatcher patterns='j[^/]*$'>
564 $ hg debugwalk -v NOEXIST
564 $ hg debugwalk -v NOEXIST
565 * matcher:
565 * matcher:
566 <patternmatcher patterns='(?:NOEXIST(?:/|$))'>
566 <patternmatcher patterns='NOEXIST(?:/|$)'>
567 NOEXIST: * (glob)
567 NOEXIST: * (glob)
568
568
569 #if fifo
569 #if fifo
570 $ mkfifo fifo
570 $ mkfifo fifo
571 $ hg debugwalk -v fifo
571 $ hg debugwalk -v fifo
572 * matcher:
572 * matcher:
573 <patternmatcher patterns='(?:fifo(?:/|$))'>
573 <patternmatcher patterns='fifo(?:/|$)'>
574 fifo: unsupported file type (type is fifo)
574 fifo: unsupported file type (type is fifo)
575 #endif
575 #endif
576
576
577 $ rm fenugreek
577 $ rm fenugreek
578 $ hg debugwalk -v fenugreek
578 $ hg debugwalk -v fenugreek
579 * matcher:
579 * matcher:
580 <patternmatcher patterns='(?:fenugreek(?:/|$))'>
580 <patternmatcher patterns='fenugreek(?:/|$)'>
581 f fenugreek fenugreek exact
581 f fenugreek fenugreek exact
582 $ hg rm fenugreek
582 $ hg rm fenugreek
583 $ hg debugwalk -v fenugreek
583 $ hg debugwalk -v fenugreek
584 * matcher:
584 * matcher:
585 <patternmatcher patterns='(?:fenugreek(?:/|$))'>
585 <patternmatcher patterns='fenugreek(?:/|$)'>
586 f fenugreek fenugreek exact
586 f fenugreek fenugreek exact
587 $ touch new
587 $ touch new
588 $ hg debugwalk -v new
588 $ hg debugwalk -v new
589 * matcher:
589 * matcher:
590 <patternmatcher patterns='(?:new(?:/|$))'>
590 <patternmatcher patterns='new(?:/|$)'>
591 f new new exact
591 f new new exact
592
592
593 $ mkdir ignored
593 $ mkdir ignored
594 $ touch ignored/file
594 $ touch ignored/file
595 $ echo '^ignored$' > .hgignore
595 $ echo '^ignored$' > .hgignore
596 $ hg debugwalk -v ignored
596 $ hg debugwalk -v ignored
597 * matcher:
597 * matcher:
598 <patternmatcher patterns='(?:ignored(?:/|$))'>
598 <patternmatcher patterns='ignored(?:/|$)'>
599 $ hg debugwalk -v ignored/file
599 $ hg debugwalk -v ignored/file
600 * matcher:
600 * matcher:
601 <patternmatcher patterns='(?:ignored/file(?:/|$))'>
601 <patternmatcher patterns='ignored/file(?:/|$)'>
602 f ignored/file ignored/file exact
602 f ignored/file ignored/file exact
603
603
604 Test listfile and listfile0
604 Test listfile and listfile0
605
605
606 $ "$PYTHON" -c "open('listfile0', 'wb').write(b'fenugreek\0new\0')"
606 $ "$PYTHON" -c "open('listfile0', 'wb').write(b'fenugreek\0new\0')"
607 $ hg debugwalk -v -I 'listfile0:listfile0'
607 $ hg debugwalk -v -I 'listfile0:listfile0'
608 * matcher:
608 * matcher:
609 <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$))'>
609 <includematcher includes='fenugreek(?:/|$)|new(?:/|$)'>
610 f fenugreek fenugreek
610 f fenugreek fenugreek
611 f new new
611 f new new
612 $ "$PYTHON" -c "open('listfile', 'wb').write(b'fenugreek\nnew\r\nmammals/skunk\n')"
612 $ "$PYTHON" -c "open('listfile', 'wb').write(b'fenugreek\nnew\r\nmammals/skunk\n')"
613 $ hg debugwalk -v -I 'listfile:listfile'
613 $ hg debugwalk -v -I 'listfile:listfile'
614 * matcher:
614 * matcher:
615 <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$)|mammals/skunk(?:/|$))'>
615 <includematcher includes='fenugreek(?:/|$)|new(?:/|$)|mammals/skunk(?:/|$)'>
616 f fenugreek fenugreek
616 f fenugreek fenugreek
617 f mammals/skunk mammals/skunk
617 f mammals/skunk mammals/skunk
618 f new new
618 f new new
619
619
620 $ cd ..
620 $ cd ..
621 $ hg debugwalk -v -R t t/mammals/skunk
621 $ hg debugwalk -v -R t t/mammals/skunk
622 * matcher:
622 * matcher:
623 <patternmatcher patterns='(?:mammals/skunk(?:/|$))'>
623 <patternmatcher patterns='mammals/skunk(?:/|$)'>
624 f mammals/skunk t/mammals/skunk exact
624 f mammals/skunk t/mammals/skunk exact
625 $ mkdir t2
625 $ mkdir t2
626 $ cd t2
626 $ cd t2
627 $ hg debugwalk -v -R ../t ../t/mammals/skunk
627 $ hg debugwalk -v -R ../t ../t/mammals/skunk
628 * matcher:
628 * matcher:
629 <patternmatcher patterns='(?:mammals/skunk(?:/|$))'>
629 <patternmatcher patterns='mammals/skunk(?:/|$)'>
630 f mammals/skunk ../t/mammals/skunk exact
630 f mammals/skunk ../t/mammals/skunk exact
631 $ hg debugwalk -v --cwd ../t mammals/skunk
631 $ hg debugwalk -v --cwd ../t mammals/skunk
632 * matcher:
632 * matcher:
633 <patternmatcher patterns='(?:mammals/skunk(?:/|$))'>
633 <patternmatcher patterns='mammals/skunk(?:/|$)'>
634 f mammals/skunk mammals/skunk exact
634 f mammals/skunk mammals/skunk exact
635
635
636 $ cd ..
636 $ cd ..
637
637
638 Test split patterns on overflow
638 Test split patterns on overflow
639
639
640 $ cd t
640 $ cd t
641 $ echo fennel > overflow.list
641 $ echo fennel > overflow.list
642 $ cat >> printnum.py <<EOF
642 $ cat >> printnum.py <<EOF
643 > from __future__ import print_function
643 > from __future__ import print_function
644 > for i in range(20000 // 100):
644 > for i in range(20000 // 100):
645 > print('x' * 100)
645 > print('x' * 100)
646 > EOF
646 > EOF
647 $ "$PYTHON" printnum.py >> overflow.list
647 $ "$PYTHON" printnum.py >> overflow.list
648 $ echo fenugreek >> overflow.list
648 $ echo fenugreek >> overflow.list
649 $ hg debugwalk 'listfile:overflow.list' 2>&1 | egrep -v '^xxx'
649 $ hg debugwalk 'listfile:overflow.list' 2>&1 | egrep -v '^xxx'
650 f fennel fennel exact
650 f fennel fennel exact
651 f fenugreek fenugreek exact
651 f fenugreek fenugreek exact
652 $ cd ..
652 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now