##// END OF EJS Templates
Get add and locate to use new repo and dirstate walk code....
Bryan O'Sullivan -
r724:1c0c413c default
parent child Browse files
Show More
@@ -33,7 +33,8 b' COMMAND ELEMENTS'
33 ----------------
33 ----------------
34
34
35 files ...::
35 files ...::
36 indicates one or more filename or relative path filenames
36 indicates one or more filename or relative path filenames; see
37 "FILE NAME PATTERNS" for information on pattern matching
37
38
38 path::
39 path::
39 indicates a path on the local machine
40 indicates a path on the local machine
@@ -51,11 +52,14 b' repository path::'
51 COMMANDS
52 COMMANDS
52 --------
53 --------
53
54
54 add [files ...]::
55 add [options] [files ...]::
55 Schedule files to be version controlled and added to the repository.
56 Schedule files to be version controlled and added to the repository.
56
57
57 The files will be added to the repository at the next commit.
58 The files will be added to the repository at the next commit.
58
59
60 If no names are given, add all files in the current directory and
61 its subdirectory.
62
59 addremove::
63 addremove::
60 Add all new files and remove all missing files from the repository.
64 Add all new files and remove all missing files from the repository.
61
65
@@ -183,14 +187,10 b' import [-p <n> -b <base> -q] <patches>::'
183 init::
187 init::
184 Initialize a new repository in the current directory.
188 Initialize a new repository in the current directory.
185
189
186 locate [options] [patterns]::
190 locate [options] [files]::
187 Print all files under Mercurial control whose basenames match the
191 Print all files under Mercurial control whose names match the
188 given patterns.
192 given patterns.
189
193
190 Patterns are shell-style globs. To restrict searches to specific
191 directories, use the "-i <pat>" option. To eliminate particular
192 directories from searching, use the "-x <pat>" option.
193
194 This command searches the current directory and its
194 This command searches the current directory and its
195 subdirectories. To search an entire repository, move to the root
195 subdirectories. To search an entire repository, move to the root
196 of the repository.
196 of the repository.
@@ -207,9 +207,9 b' locate [options] [patterns]::'
207
207
208 -0, --print0 end filenames with NUL, for use with xargs
208 -0, --print0 end filenames with NUL, for use with xargs
209 -f, --fullpath print complete paths from the filesystem root
209 -f, --fullpath print complete paths from the filesystem root
210 -i, --include <pat> include directories matching the given globs
210 -I, --include <pat> include directories matching the given patterns
211 -r, --rev <rev> search the repository as it stood at rev
211 -r, --rev <rev> search the repository as it stood at rev
212 -x, --exclude <pat> exclude directories matching the given globs
212 -X, --exclude <pat> exclude directories matching the given patterns
213
213
214 log [-r revision ...] [-p] [file]::
214 log [-r revision ...] [-p] [file]::
215 Print the revision history of the specified file or the entire project.
215 Print the revision history of the specified file or the entire project.
@@ -398,6 +398,52 b' verify::'
398 the changelog, manifest, and tracked files, as well as the
398 the changelog, manifest, and tracked files, as well as the
399 integrity of their crosslinks and indices.
399 integrity of their crosslinks and indices.
400
400
401 FILE NAME PATTERNS
402 ------------------
403
404 Mercurial accepts several notations for identifying one or more
405 file at a time.
406
407 By default, Mercurial treats file names as shell-style extended
408 glob patterns.
409
410 Alternate pattern notations must be specified explicitly.
411
412 To use a plain path name without any pattern matching, start a
413 name with "path:". These path names must match completely, from
414 the root of the current repository.
415
416 To use an extended glob, start a name with "glob:". Globs are
417 rooted at the current directory; a glob such as "*.c" will match
418 files ending in ".c" in the current directory only.
419
420 The supported glob syntax extensions are "**" to match any string
421 across path separators, and "{a,b}" to mean "a or b".
422
423 To use a Perl/Python regular expression, start a name with "re:".
424 Regexp pattern matching is anchored at the root of the repository.
425
426 Plain examples:
427
428 path:foo/bar a name bar in a directory named foo in the root of
429 the repository
430 path:path:name a file or directory named "path:name"
431
432 Glob examples:
433
434 glob:*.c any name ending in ".c" in the current directory
435 *.c any name ending in ".c" in the current directory
436 **.c any name ending in ".c" in the current directory, or
437 any subdirectory
438 foo/*.c any name ending in ".c" in the directory foo
439 foo/**.c any name ending in ".c" in the directory foo, or any
440 subdirectory
441
442 Regexp examples:
443
444 re:.*\.c$ any name ending in ".c", anywhere in the repsitory
445
446
401 SPECIFYING SINGLE REVISIONS
447 SPECIFYING SINGLE REVISIONS
402 ---------------------------
448 ---------------------------
403
449
@@ -36,6 +36,39 b' def relpath(repo, args):'
36 for x in args]
36 for x in args]
37 return args
37 return args
38
38
39 def matchpats(ui, cwd, pats = [], opts = {}):
40 head = ''
41 if opts.get('rootless'): head = '(?:.*/|)'
42 def reify(name, tail):
43 if name.startswith('re:'):
44 return name[3:]
45 elif name.startswith('glob:'):
46 return head + util.globre(name[5:], '', tail)
47 elif name.startswith('path:'):
48 return '^' + re.escape(name[5:]) + '$'
49 return head + util.globre(name, '', tail)
50 cwdsep = cwd + os.sep
51 def under(fn):
52 if not cwd or fn.startswith(cwdsep): return True
53 def matchfn(pats, tail, ifempty = util.always):
54 if not pats: return ifempty
55 pat = '(?:%s)' % '|'.join([reify(p, tail) for p in pats])
56 if cwd: pat = re.escape(cwd + os.sep) + pat
57 ui.debug('regexp: %s\n' % pat)
58 return re.compile(pat).match
59 patmatch = matchfn(pats, '$')
60 incmatch = matchfn(opts.get('include'), '(?:/|$)', under)
61 excmatch = matchfn(opts.get('exclude'), '(?:/|$)', util.never)
62 return lambda fn: (incmatch(fn) and not excmatch(fn) and
63 (fn.endswith('/') or patmatch(fn)))
64
65 def walk(repo, pats, opts):
66 cwd = repo.getcwd()
67 if cwd: c = len(cwd) + 1
68 for fn in repo.walk(match = matchpats(repo.ui, cwd, pats, opts)):
69 if cwd: yield fn, fn[c:]
70 else: yield fn, fn
71
39 revrangesep = ':'
72 revrangesep = ':'
40
73
41 def revrange(ui, repo, revs, revlog=None):
74 def revrange(ui, repo, revs, revlog=None):
@@ -288,9 +321,17 b' def help_(ui, cmd=None):'
288
321
289 # Commands start here, listed alphabetically
322 # Commands start here, listed alphabetically
290
323
291 def add(ui, repo, file1, *files):
324 def add(ui, repo, *pats, **opts):
292 '''add the specified files on the next commit'''
325 '''add the specified files on the next commit'''
293 repo.add(relpath(repo, (file1,) + files))
326 names = []
327 q = dict(zip(pats, pats))
328 for abs, rel in walk(repo, pats, opts):
329 if rel in q or abs in q:
330 names.append(abs)
331 elif repo.dirstate.state(abs) == '?':
332 ui.status('adding %s\n' % rel)
333 names.append(abs)
334 repo.add(names)
294
335
295 def addremove(ui, repo, *files):
336 def addremove(ui, repo, *files):
296 """add all new files, delete all missing files"""
337 """add all new files, delete all missing files"""
@@ -669,46 +710,15 b' def init(ui, source=None):'
669
710
670 def locate(ui, repo, *pats, **opts):
711 def locate(ui, repo, *pats, **opts):
671 """locate files matching specific patterns"""
712 """locate files matching specific patterns"""
672 if [p for p in pats if os.sep in p]:
713 if opts['print0']: end = '\0'
673 ui.warn("error: patterns may not contain '%s'\n" % os.sep)
714 else: end = '\n'
674 ui.warn("use '-i <dir>' instead\n")
715 opts['rootless'] = True
675 sys.exit(1)
716 for abs, rel in walk(repo, pats, opts):
676 def compile(pats, head='^', tail=os.sep, on_empty=True):
717 if repo.dirstate.state(abs) == '?': continue
677 if not pats:
678 class c:
679 def match(self, x):
680 return on_empty
681 return c()
682 fnpats = [fnmatch.translate(os.path.normpath(os.path.normcase(p)))[:-1]
683 for p in pats]
684 regexp = r'%s(?:%s)%s' % (head, '|'.join(fnpats), tail)
685 return re.compile(regexp)
686 exclude = compile(opts['exclude'], on_empty=False)
687 include = compile(opts['include'])
688 pat = compile(pats, head='', tail='$')
689 end = opts['print0'] and '\0' or '\n'
690 if opts['rev']:
691 node = repo.manifest.lookup(opts['rev'])
692 else:
693 node = repo.manifest.tip()
694 manifest = repo.manifest.read(node)
695 cwd = repo.getcwd()
696 cwd_plus = cwd and (cwd + os.sep)
697 found = []
698 for f in manifest:
699 f = os.path.normcase(f)
700 if exclude.match(f) or not(include.match(f) and
701 f.startswith(cwd_plus) and
702 pat.match(os.path.basename(f))):
703 continue
704 if opts['fullpath']:
718 if opts['fullpath']:
705 f = os.path.join(repo.root, f)
719 ui.write(os.path.join(repo.root, abs), end)
706 elif cwd:
720 else:
707 f = f[len(cwd_plus):]
721 ui.write(rel, end)
708 found.append(f)
709 found.sort()
710 for f in found:
711 ui.write(f, end)
712
722
713 def log(ui, repo, f=None, **opts):
723 def log(ui, repo, f=None, **opts):
714 """show the revision history of the repository or a single file"""
724 """show the revision history of the repository or a single file"""
@@ -1087,7 +1097,10 b' def verify(ui, repo):'
1087 # Command options and aliases are listed here, alphabetically
1097 # Command options and aliases are listed here, alphabetically
1088
1098
1089 table = {
1099 table = {
1090 "^add": (add, [], "hg add [files]"),
1100 "^add": (add,
1101 [('I', 'include', [], 'include path in search'),
1102 ('X', 'exclude', [], 'exclude path from search')],
1103 "hg add [options] [files]"),
1091 "addremove": (addremove, [], "hg addremove [files]"),
1104 "addremove": (addremove, [], "hg addremove [files]"),
1092 "^annotate":
1105 "^annotate":
1093 (annotate,
1106 (annotate,
@@ -1139,9 +1152,9 b' table = {'
1139 (locate,
1152 (locate,
1140 [('0', 'print0', None, 'end records with NUL'),
1153 [('0', 'print0', None, 'end records with NUL'),
1141 ('f', 'fullpath', None, 'print complete paths'),
1154 ('f', 'fullpath', None, 'print complete paths'),
1142 ('i', 'include', [], 'include path in search'),
1155 ('I', 'include', [], 'include path in search'),
1143 ('r', 'rev', '', 'revision'),
1156 ('r', 'rev', '', 'revision'),
1144 ('x', 'exclude', [], 'exclude path from search')],
1157 ('X', 'exclude', [], 'exclude path from search')],
1145 'hg locate [options] [files]'),
1158 'hg locate [options] [files]'),
1146 "^log|history":
1159 "^log|history":
1147 (log,
1160 (log,
@@ -13,9 +13,6 b' demandload(globals(), "re lock urllib ur'
13 demandload(globals(), "tempfile httprangereader bdiff")
13 demandload(globals(), "tempfile httprangereader bdiff")
14 demandload(globals(), "bisect select")
14 demandload(globals(), "bisect select")
15
15
16 def always(fn):
17 return True
18
19 class filelog(revlog):
16 class filelog(revlog):
20 def __init__(self, opener, path):
17 def __init__(self, opener, path):
21 revlog.__init__(self, opener,
18 revlog.__init__(self, opener,
@@ -416,7 +413,7 b' class dirstate:'
416 st.write(e + f)
413 st.write(e + f)
417 self.dirty = 0
414 self.dirty = 0
418
415
419 def walk(self, files = None, match = always):
416 def walk(self, files = None, match = util.always):
420 self.read()
417 self.read()
421 dc = self.map.copy()
418 dc = self.map.copy()
422 # walk all files by default
419 # walk all files by default
@@ -454,7 +451,7 b' class dirstate:'
454 if match(fn):
451 if match(fn):
455 yield fn
452 yield fn
456
453
457 def changes(self, files = None, match = always):
454 def changes(self, files = None, match = util.always):
458 self.read()
455 self.read()
459 dc = self.map.copy()
456 dc = self.map.copy()
460 lookup, changed, added, unknown = [], [], [], []
457 lookup, changed, added, unknown = [], [], [], []
@@ -840,12 +837,16 b' class localrepository:'
840 if not self.hook("commit", node=hex(n)):
837 if not self.hook("commit", node=hex(n)):
841 return 1
838 return 1
842
839
843 def walk(self, rev = None, files = [], match = always):
840 def walk(self, node = None, files = [], match = util.always):
844 if rev is None: fns = self.dirstate.walk(files, match)
841 if node:
845 else: fns = filter(match, self.manifest.read(rev))
842 change = self.changelog.read(node)
843 fns = filter(match, self.manifest.read(change[0]))
844 else:
845 fns = self.dirstate.walk(files, match)
846 for fn in fns: yield fn
846 for fn in fns: yield fn
847
847
848 def changes(self, node1 = None, node2 = None, files = [], match = always):
848 def changes(self, node1 = None, node2 = None, files = [],
849 match = util.always):
849 mf2, u = None, []
850 mf2, u = None, []
850
851
851 def fcmp(fn, mf):
852 def fcmp(fn, mf):
@@ -922,7 +923,7 b' class localrepository:'
922 self.ui.warn("%s does not exist!\n" % f)
923 self.ui.warn("%s does not exist!\n" % f)
923 elif not os.path.isfile(p):
924 elif not os.path.isfile(p):
924 self.ui.warn("%s not added: mercurial only supports files currently\n" % f)
925 self.ui.warn("%s not added: mercurial only supports files currently\n" % f)
925 elif self.dirstate.state(f) == 'n':
926 elif self.dirstate.state(f) in 'an':
926 self.ui.warn("%s already tracked!\n" % f)
927 self.ui.warn("%s already tracked!\n" % f)
927 else:
928 else:
928 self.dirstate.update([f], "a")
929 self.dirstate.update([f], "a")
@@ -6,6 +6,8 b''
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import os, errno
8 import os, errno
9 from demandload import *
10 demandload(globals(), "re")
9
11
10 def unique(g):
12 def unique(g):
11 seen = {}
13 seen = {}
@@ -29,6 +31,54 b' def explain_exit(code):'
29 return "stopped by signal %d" % val, val
31 return "stopped by signal %d" % val, val
30 raise ValueError("invalid exit code")
32 raise ValueError("invalid exit code")
31
33
34 def always(fn): return True
35 def never(fn): return False
36
37 def globre(pat, head = '^', tail = '$'):
38 "convert a glob pattern into a regexp"
39 i, n = 0, len(pat)
40 res = ''
41 group = False
42 def peek(): return i < n and pat[i]
43 while i < n:
44 c = pat[i]
45 i = i+1
46 if c == '*':
47 if peek() == '*':
48 i += 1
49 res += '.*'
50 else:
51 res += '[^/]*'
52 elif c == '?':
53 res += '.'
54 elif c == '[':
55 j = i
56 if j < n and pat[j] in '!]':
57 j += 1
58 while j < n and pat[j] != ']':
59 j += 1
60 if j >= n:
61 res += '\\['
62 else:
63 stuff = pat[i:j].replace('\\','\\\\')
64 i = j + 1
65 if stuff[0] == '!':
66 stuff = '^' + stuff[1:]
67 elif stuff[0] == '^':
68 stuff = '\\' + stuff
69 res = '%s[%s]' % (res, stuff)
70 elif c == '{':
71 group = True
72 res += '(?:'
73 elif c == '}' and group:
74 res += ')'
75 group = False
76 elif c == ',' and group:
77 res += '|'
78 else:
79 res += re.escape(c)
80 return head + res + tail
81
32 def system(cmd, errprefix=None):
82 def system(cmd, errprefix=None):
33 """execute a shell command that must succeed"""
83 """execute a shell command that must succeed"""
34 rc = os.system(cmd)
84 rc = os.system(cmd)
General Comments 0
You need to be logged in to leave comments. Login now