##// END OF EJS Templates
Merge last few matcher/locate fixes.
Alexis S. L. Carvalho -
r4309:d4f0405f merge default
parent child Browse files
Show More
@@ -1,3377 +1,3380 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
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 demandimport; demandimport.enable()
8 import demandimport; demandimport.enable()
9 from node import *
9 from node import *
10 from i18n import _
10 from i18n import _
11 import bisect, os, re, sys, signal, imp, urllib, pdb, shlex, stat
11 import bisect, os, re, sys, signal, imp, urllib, pdb, shlex, stat
12 import fancyopts, ui, hg, util, lock, revlog, bundlerepo
12 import fancyopts, ui, hg, util, lock, revlog, bundlerepo
13 import difflib, patch, time, help, mdiff, tempfile
13 import difflib, patch, time, help, mdiff, tempfile
14 import traceback, errno, version, atexit, socket
14 import traceback, errno, version, atexit, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
16
16
17 class UnknownCommand(Exception):
17 class UnknownCommand(Exception):
18 """Exception raised if command is not in the command table."""
18 """Exception raised if command is not in the command table."""
19 class AmbiguousCommand(Exception):
19 class AmbiguousCommand(Exception):
20 """Exception raised if command shortcut matches more than one command."""
20 """Exception raised if command shortcut matches more than one command."""
21
21
22 def bail_if_changed(repo):
22 def bail_if_changed(repo):
23 modified, added, removed, deleted = repo.status()[:4]
23 modified, added, removed, deleted = repo.status()[:4]
24 if modified or added or removed or deleted:
24 if modified or added or removed or deleted:
25 raise util.Abort(_("outstanding uncommitted changes"))
25 raise util.Abort(_("outstanding uncommitted changes"))
26
26
27 def logmessage(opts):
27 def logmessage(opts):
28 """ get the log message according to -m and -l option """
28 """ get the log message according to -m and -l option """
29 message = opts['message']
29 message = opts['message']
30 logfile = opts['logfile']
30 logfile = opts['logfile']
31
31
32 if message and logfile:
32 if message and logfile:
33 raise util.Abort(_('options --message and --logfile are mutually '
33 raise util.Abort(_('options --message and --logfile are mutually '
34 'exclusive'))
34 'exclusive'))
35 if not message and logfile:
35 if not message and logfile:
36 try:
36 try:
37 if logfile == '-':
37 if logfile == '-':
38 message = sys.stdin.read()
38 message = sys.stdin.read()
39 else:
39 else:
40 message = open(logfile).read()
40 message = open(logfile).read()
41 except IOError, inst:
41 except IOError, inst:
42 raise util.Abort(_("can't read commit message '%s': %s") %
42 raise util.Abort(_("can't read commit message '%s': %s") %
43 (logfile, inst.strerror))
43 (logfile, inst.strerror))
44 return message
44 return message
45
45
46 def setremoteconfig(ui, opts):
46 def setremoteconfig(ui, opts):
47 "copy remote options to ui tree"
47 "copy remote options to ui tree"
48 if opts.get('ssh'):
48 if opts.get('ssh'):
49 ui.setconfig("ui", "ssh", opts['ssh'])
49 ui.setconfig("ui", "ssh", opts['ssh'])
50 if opts.get('remotecmd'):
50 if opts.get('remotecmd'):
51 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
51 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
52
52
53 # Commands start here, listed alphabetically
53 # Commands start here, listed alphabetically
54
54
55 def add(ui, repo, *pats, **opts):
55 def add(ui, repo, *pats, **opts):
56 """add the specified files on the next commit
56 """add the specified files on the next commit
57
57
58 Schedule files to be version controlled and added to the repository.
58 Schedule files to be version controlled and added to the repository.
59
59
60 The files will be added to the repository at the next commit. To
60 The files will be added to the repository at the next commit. To
61 undo an add before that, see hg revert.
61 undo an add before that, see hg revert.
62
62
63 If no names are given, add all files in the repository.
63 If no names are given, add all files in the repository.
64 """
64 """
65
65
66 names = []
66 names = []
67 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
67 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
68 if exact:
68 if exact:
69 if ui.verbose:
69 if ui.verbose:
70 ui.status(_('adding %s\n') % rel)
70 ui.status(_('adding %s\n') % rel)
71 names.append(abs)
71 names.append(abs)
72 elif repo.dirstate.state(abs) == '?':
72 elif repo.dirstate.state(abs) == '?':
73 ui.status(_('adding %s\n') % rel)
73 ui.status(_('adding %s\n') % rel)
74 names.append(abs)
74 names.append(abs)
75 if not opts.get('dry_run'):
75 if not opts.get('dry_run'):
76 repo.add(names)
76 repo.add(names)
77
77
78 def addremove(ui, repo, *pats, **opts):
78 def addremove(ui, repo, *pats, **opts):
79 """add all new files, delete all missing files
79 """add all new files, delete all missing files
80
80
81 Add all new files and remove all missing files from the repository.
81 Add all new files and remove all missing files from the repository.
82
82
83 New files are ignored if they match any of the patterns in .hgignore. As
83 New files are ignored if they match any of the patterns in .hgignore. As
84 with add, these changes take effect at the next commit.
84 with add, these changes take effect at the next commit.
85
85
86 Use the -s option to detect renamed files. With a parameter > 0,
86 Use the -s option to detect renamed files. With a parameter > 0,
87 this compares every removed file with every added file and records
87 this compares every removed file with every added file and records
88 those similar enough as renames. This option takes a percentage
88 those similar enough as renames. This option takes a percentage
89 between 0 (disabled) and 100 (files must be identical) as its
89 between 0 (disabled) and 100 (files must be identical) as its
90 parameter. Detecting renamed files this way can be expensive.
90 parameter. Detecting renamed files this way can be expensive.
91 """
91 """
92 sim = float(opts.get('similarity') or 0)
92 sim = float(opts.get('similarity') or 0)
93 if sim < 0 or sim > 100:
93 if sim < 0 or sim > 100:
94 raise util.Abort(_('similarity must be between 0 and 100'))
94 raise util.Abort(_('similarity must be between 0 and 100'))
95 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
95 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
96
96
97 def annotate(ui, repo, *pats, **opts):
97 def annotate(ui, repo, *pats, **opts):
98 """show changeset information per file line
98 """show changeset information per file line
99
99
100 List changes in files, showing the revision id responsible for each line
100 List changes in files, showing the revision id responsible for each line
101
101
102 This command is useful to discover who did a change or when a change took
102 This command is useful to discover who did a change or when a change took
103 place.
103 place.
104
104
105 Without the -a option, annotate will avoid processing files it
105 Without the -a option, annotate will avoid processing files it
106 detects as binary. With -a, annotate will generate an annotation
106 detects as binary. With -a, annotate will generate an annotation
107 anyway, probably with undesirable results.
107 anyway, probably with undesirable results.
108 """
108 """
109 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
109 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
110
110
111 if not pats:
111 if not pats:
112 raise util.Abort(_('at least one file name or pattern required'))
112 raise util.Abort(_('at least one file name or pattern required'))
113
113
114 opmap = [['user', lambda x: ui.shortuser(x.user())],
114 opmap = [['user', lambda x: ui.shortuser(x.user())],
115 ['number', lambda x: str(x.rev())],
115 ['number', lambda x: str(x.rev())],
116 ['changeset', lambda x: short(x.node())],
116 ['changeset', lambda x: short(x.node())],
117 ['date', getdate], ['follow', lambda x: x.path()]]
117 ['date', getdate], ['follow', lambda x: x.path()]]
118 if (not opts['user'] and not opts['changeset'] and not opts['date']
118 if (not opts['user'] and not opts['changeset'] and not opts['date']
119 and not opts['follow']):
119 and not opts['follow']):
120 opts['number'] = 1
120 opts['number'] = 1
121
121
122 ctx = repo.changectx(opts['rev'])
122 ctx = repo.changectx(opts['rev'])
123
123
124 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
124 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
125 node=ctx.node()):
125 node=ctx.node()):
126 fctx = ctx.filectx(abs)
126 fctx = ctx.filectx(abs)
127 if not opts['text'] and util.binary(fctx.data()):
127 if not opts['text'] and util.binary(fctx.data()):
128 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
128 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
129 continue
129 continue
130
130
131 lines = fctx.annotate(follow=opts.get('follow'))
131 lines = fctx.annotate(follow=opts.get('follow'))
132 pieces = []
132 pieces = []
133
133
134 for o, f in opmap:
134 for o, f in opmap:
135 if opts[o]:
135 if opts[o]:
136 l = [f(n) for n, dummy in lines]
136 l = [f(n) for n, dummy in lines]
137 if l:
137 if l:
138 m = max(map(len, l))
138 m = max(map(len, l))
139 pieces.append(["%*s" % (m, x) for x in l])
139 pieces.append(["%*s" % (m, x) for x in l])
140
140
141 if pieces:
141 if pieces:
142 for p, l in zip(zip(*pieces), lines):
142 for p, l in zip(zip(*pieces), lines):
143 ui.write("%s: %s" % (" ".join(p), l[1]))
143 ui.write("%s: %s" % (" ".join(p), l[1]))
144
144
145 def archive(ui, repo, dest, **opts):
145 def archive(ui, repo, dest, **opts):
146 '''create unversioned archive of a repository revision
146 '''create unversioned archive of a repository revision
147
147
148 By default, the revision used is the parent of the working
148 By default, the revision used is the parent of the working
149 directory; use "-r" to specify a different revision.
149 directory; use "-r" to specify a different revision.
150
150
151 To specify the type of archive to create, use "-t". Valid
151 To specify the type of archive to create, use "-t". Valid
152 types are:
152 types are:
153
153
154 "files" (default): a directory full of files
154 "files" (default): a directory full of files
155 "tar": tar archive, uncompressed
155 "tar": tar archive, uncompressed
156 "tbz2": tar archive, compressed using bzip2
156 "tbz2": tar archive, compressed using bzip2
157 "tgz": tar archive, compressed using gzip
157 "tgz": tar archive, compressed using gzip
158 "uzip": zip archive, uncompressed
158 "uzip": zip archive, uncompressed
159 "zip": zip archive, compressed using deflate
159 "zip": zip archive, compressed using deflate
160
160
161 The exact name of the destination archive or directory is given
161 The exact name of the destination archive or directory is given
162 using a format string; see "hg help export" for details.
162 using a format string; see "hg help export" for details.
163
163
164 Each member added to an archive file has a directory prefix
164 Each member added to an archive file has a directory prefix
165 prepended. Use "-p" to specify a format string for the prefix.
165 prepended. Use "-p" to specify a format string for the prefix.
166 The default is the basename of the archive, with suffixes removed.
166 The default is the basename of the archive, with suffixes removed.
167 '''
167 '''
168
168
169 node = repo.changectx(opts['rev']).node()
169 node = repo.changectx(opts['rev']).node()
170 dest = cmdutil.make_filename(repo, dest, node)
170 dest = cmdutil.make_filename(repo, dest, node)
171 if os.path.realpath(dest) == repo.root:
171 if os.path.realpath(dest) == repo.root:
172 raise util.Abort(_('repository root cannot be destination'))
172 raise util.Abort(_('repository root cannot be destination'))
173 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
173 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
174 kind = opts.get('type') or 'files'
174 kind = opts.get('type') or 'files'
175 prefix = opts['prefix']
175 prefix = opts['prefix']
176 if dest == '-':
176 if dest == '-':
177 if kind == 'files':
177 if kind == 'files':
178 raise util.Abort(_('cannot archive plain files to stdout'))
178 raise util.Abort(_('cannot archive plain files to stdout'))
179 dest = sys.stdout
179 dest = sys.stdout
180 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
180 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
181 prefix = cmdutil.make_filename(repo, prefix, node)
181 prefix = cmdutil.make_filename(repo, prefix, node)
182 archival.archive(repo, dest, node, kind, not opts['no_decode'],
182 archival.archive(repo, dest, node, kind, not opts['no_decode'],
183 matchfn, prefix)
183 matchfn, prefix)
184
184
185 def backout(ui, repo, rev, **opts):
185 def backout(ui, repo, rev, **opts):
186 '''reverse effect of earlier changeset
186 '''reverse effect of earlier changeset
187
187
188 Commit the backed out changes as a new changeset. The new
188 Commit the backed out changes as a new changeset. The new
189 changeset is a child of the backed out changeset.
189 changeset is a child of the backed out changeset.
190
190
191 If you back out a changeset other than the tip, a new head is
191 If you back out a changeset other than the tip, a new head is
192 created. This head is the parent of the working directory. If
192 created. This head is the parent of the working directory. If
193 you back out an old changeset, your working directory will appear
193 you back out an old changeset, your working directory will appear
194 old after the backout. You should merge the backout changeset
194 old after the backout. You should merge the backout changeset
195 with another head.
195 with another head.
196
196
197 The --merge option remembers the parent of the working directory
197 The --merge option remembers the parent of the working directory
198 before starting the backout, then merges the new head with that
198 before starting the backout, then merges the new head with that
199 changeset afterwards. This saves you from doing the merge by
199 changeset afterwards. This saves you from doing the merge by
200 hand. The result of this merge is not committed, as for a normal
200 hand. The result of this merge is not committed, as for a normal
201 merge.'''
201 merge.'''
202
202
203 bail_if_changed(repo)
203 bail_if_changed(repo)
204 op1, op2 = repo.dirstate.parents()
204 op1, op2 = repo.dirstate.parents()
205 if op2 != nullid:
205 if op2 != nullid:
206 raise util.Abort(_('outstanding uncommitted merge'))
206 raise util.Abort(_('outstanding uncommitted merge'))
207 node = repo.lookup(rev)
207 node = repo.lookup(rev)
208 p1, p2 = repo.changelog.parents(node)
208 p1, p2 = repo.changelog.parents(node)
209 if p1 == nullid:
209 if p1 == nullid:
210 raise util.Abort(_('cannot back out a change with no parents'))
210 raise util.Abort(_('cannot back out a change with no parents'))
211 if p2 != nullid:
211 if p2 != nullid:
212 if not opts['parent']:
212 if not opts['parent']:
213 raise util.Abort(_('cannot back out a merge changeset without '
213 raise util.Abort(_('cannot back out a merge changeset without '
214 '--parent'))
214 '--parent'))
215 p = repo.lookup(opts['parent'])
215 p = repo.lookup(opts['parent'])
216 if p not in (p1, p2):
216 if p not in (p1, p2):
217 raise util.Abort(_('%s is not a parent of %s') %
217 raise util.Abort(_('%s is not a parent of %s') %
218 (short(p), short(node)))
218 (short(p), short(node)))
219 parent = p
219 parent = p
220 else:
220 else:
221 if opts['parent']:
221 if opts['parent']:
222 raise util.Abort(_('cannot use --parent on non-merge changeset'))
222 raise util.Abort(_('cannot use --parent on non-merge changeset'))
223 parent = p1
223 parent = p1
224 hg.clean(repo, node, show_stats=False)
224 hg.clean(repo, node, show_stats=False)
225 revert_opts = opts.copy()
225 revert_opts = opts.copy()
226 revert_opts['date'] = None
226 revert_opts['date'] = None
227 revert_opts['all'] = True
227 revert_opts['all'] = True
228 revert_opts['rev'] = hex(parent)
228 revert_opts['rev'] = hex(parent)
229 revert(ui, repo, **revert_opts)
229 revert(ui, repo, **revert_opts)
230 commit_opts = opts.copy()
230 commit_opts = opts.copy()
231 commit_opts['addremove'] = False
231 commit_opts['addremove'] = False
232 if not commit_opts['message'] and not commit_opts['logfile']:
232 if not commit_opts['message'] and not commit_opts['logfile']:
233 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
233 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
234 commit_opts['force_editor'] = True
234 commit_opts['force_editor'] = True
235 commit(ui, repo, **commit_opts)
235 commit(ui, repo, **commit_opts)
236 def nice(node):
236 def nice(node):
237 return '%d:%s' % (repo.changelog.rev(node), short(node))
237 return '%d:%s' % (repo.changelog.rev(node), short(node))
238 ui.status(_('changeset %s backs out changeset %s\n') %
238 ui.status(_('changeset %s backs out changeset %s\n') %
239 (nice(repo.changelog.tip()), nice(node)))
239 (nice(repo.changelog.tip()), nice(node)))
240 if op1 != node:
240 if op1 != node:
241 if opts['merge']:
241 if opts['merge']:
242 ui.status(_('merging with changeset %s\n') % nice(op1))
242 ui.status(_('merging with changeset %s\n') % nice(op1))
243 hg.merge(repo, hex(op1))
243 hg.merge(repo, hex(op1))
244 else:
244 else:
245 ui.status(_('the backout changeset is a new head - '
245 ui.status(_('the backout changeset is a new head - '
246 'do not forget to merge\n'))
246 'do not forget to merge\n'))
247 ui.status(_('(use "backout --merge" '
247 ui.status(_('(use "backout --merge" '
248 'if you want to auto-merge)\n'))
248 'if you want to auto-merge)\n'))
249
249
250 def branch(ui, repo, label=None, **opts):
250 def branch(ui, repo, label=None, **opts):
251 """set or show the current branch name
251 """set or show the current branch name
252
252
253 With <name>, set the current branch name. Otherwise, show the
253 With <name>, set the current branch name. Otherwise, show the
254 current branch name.
254 current branch name.
255
255
256 Unless --force is specified, branch will not let you set a
256 Unless --force is specified, branch will not let you set a
257 branch name that shadows an existing branch.
257 branch name that shadows an existing branch.
258 """
258 """
259
259
260 if label:
260 if label:
261 if not opts.get('force') and label in repo.branchtags():
261 if not opts.get('force') and label in repo.branchtags():
262 if label not in [p.branch() for p in repo.workingctx().parents()]:
262 if label not in [p.branch() for p in repo.workingctx().parents()]:
263 raise util.Abort(_('a branch of the same name already exists'
263 raise util.Abort(_('a branch of the same name already exists'
264 ' (use --force to override)'))
264 ' (use --force to override)'))
265 repo.dirstate.setbranch(util.fromlocal(label))
265 repo.dirstate.setbranch(util.fromlocal(label))
266 else:
266 else:
267 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
267 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
268
268
269 def branches(ui, repo):
269 def branches(ui, repo):
270 """list repository named branches
270 """list repository named branches
271
271
272 List the repository's named branches.
272 List the repository's named branches.
273 """
273 """
274 b = repo.branchtags()
274 b = repo.branchtags()
275 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
275 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
276 l.sort()
276 l.sort()
277 for r, n, t in l:
277 for r, n, t in l:
278 hexfunc = ui.debugflag and hex or short
278 hexfunc = ui.debugflag and hex or short
279 if ui.quiet:
279 if ui.quiet:
280 ui.write("%s\n" % t)
280 ui.write("%s\n" % t)
281 else:
281 else:
282 spaces = " " * (30 - util.locallen(t))
282 spaces = " " * (30 - util.locallen(t))
283 ui.write("%s%s %s:%s\n" % (t, spaces, -r, hexfunc(n)))
283 ui.write("%s%s %s:%s\n" % (t, spaces, -r, hexfunc(n)))
284
284
285 def bundle(ui, repo, fname, dest=None, **opts):
285 def bundle(ui, repo, fname, dest=None, **opts):
286 """create a changegroup file
286 """create a changegroup file
287
287
288 Generate a compressed changegroup file collecting changesets not
288 Generate a compressed changegroup file collecting changesets not
289 found in the other repository.
289 found in the other repository.
290
290
291 If no destination repository is specified the destination is assumed
291 If no destination repository is specified the destination is assumed
292 to have all the nodes specified by one or more --base parameters.
292 to have all the nodes specified by one or more --base parameters.
293
293
294 The bundle file can then be transferred using conventional means and
294 The bundle file can then be transferred using conventional means and
295 applied to another repository with the unbundle or pull command.
295 applied to another repository with the unbundle or pull command.
296 This is useful when direct push and pull are not available or when
296 This is useful when direct push and pull are not available or when
297 exporting an entire repository is undesirable.
297 exporting an entire repository is undesirable.
298
298
299 Applying bundles preserves all changeset contents including
299 Applying bundles preserves all changeset contents including
300 permissions, copy/rename information, and revision history.
300 permissions, copy/rename information, and revision history.
301 """
301 """
302 revs = opts.get('rev') or None
302 revs = opts.get('rev') or None
303 if revs:
303 if revs:
304 revs = [repo.lookup(rev) for rev in revs]
304 revs = [repo.lookup(rev) for rev in revs]
305 base = opts.get('base')
305 base = opts.get('base')
306 if base:
306 if base:
307 if dest:
307 if dest:
308 raise util.Abort(_("--base is incompatible with specifiying "
308 raise util.Abort(_("--base is incompatible with specifiying "
309 "a destination"))
309 "a destination"))
310 base = [repo.lookup(rev) for rev in base]
310 base = [repo.lookup(rev) for rev in base]
311 # create the right base
311 # create the right base
312 # XXX: nodesbetween / changegroup* should be "fixed" instead
312 # XXX: nodesbetween / changegroup* should be "fixed" instead
313 o = []
313 o = []
314 has = {nullid: None}
314 has = {nullid: None}
315 for n in base:
315 for n in base:
316 has.update(repo.changelog.reachable(n))
316 has.update(repo.changelog.reachable(n))
317 if revs:
317 if revs:
318 visit = list(revs)
318 visit = list(revs)
319 else:
319 else:
320 visit = repo.changelog.heads()
320 visit = repo.changelog.heads()
321 seen = {}
321 seen = {}
322 while visit:
322 while visit:
323 n = visit.pop(0)
323 n = visit.pop(0)
324 parents = [p for p in repo.changelog.parents(n) if p not in has]
324 parents = [p for p in repo.changelog.parents(n) if p not in has]
325 if len(parents) == 0:
325 if len(parents) == 0:
326 o.insert(0, n)
326 o.insert(0, n)
327 else:
327 else:
328 for p in parents:
328 for p in parents:
329 if p not in seen:
329 if p not in seen:
330 seen[p] = 1
330 seen[p] = 1
331 visit.append(p)
331 visit.append(p)
332 else:
332 else:
333 setremoteconfig(ui, opts)
333 setremoteconfig(ui, opts)
334 dest = ui.expandpath(dest or 'default-push', dest or 'default')
334 dest = ui.expandpath(dest or 'default-push', dest or 'default')
335 other = hg.repository(ui, dest)
335 other = hg.repository(ui, dest)
336 o = repo.findoutgoing(other, force=opts['force'])
336 o = repo.findoutgoing(other, force=opts['force'])
337
337
338 if revs:
338 if revs:
339 cg = repo.changegroupsubset(o, revs, 'bundle')
339 cg = repo.changegroupsubset(o, revs, 'bundle')
340 else:
340 else:
341 cg = repo.changegroup(o, 'bundle')
341 cg = repo.changegroup(o, 'bundle')
342 changegroup.writebundle(cg, fname, "HG10BZ")
342 changegroup.writebundle(cg, fname, "HG10BZ")
343
343
344 def cat(ui, repo, file1, *pats, **opts):
344 def cat(ui, repo, file1, *pats, **opts):
345 """output the current or given revision of files
345 """output the current or given revision of files
346
346
347 Print the specified files as they were at the given revision.
347 Print the specified files as they were at the given revision.
348 If no revision is given, the parent of the working directory is used,
348 If no revision is given, the parent of the working directory is used,
349 or tip if no revision is checked out.
349 or tip if no revision is checked out.
350
350
351 Output may be to a file, in which case the name of the file is
351 Output may be to a file, in which case the name of the file is
352 given using a format string. The formatting rules are the same as
352 given using a format string. The formatting rules are the same as
353 for the export command, with the following additions:
353 for the export command, with the following additions:
354
354
355 %s basename of file being printed
355 %s basename of file being printed
356 %d dirname of file being printed, or '.' if in repo root
356 %d dirname of file being printed, or '.' if in repo root
357 %p root-relative path name of file being printed
357 %p root-relative path name of file being printed
358 """
358 """
359 ctx = repo.changectx(opts['rev'])
359 ctx = repo.changectx(opts['rev'])
360 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
360 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
361 ctx.node()):
361 ctx.node()):
362 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
362 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
363 fp.write(ctx.filectx(abs).data())
363 fp.write(ctx.filectx(abs).data())
364
364
365 def clone(ui, source, dest=None, **opts):
365 def clone(ui, source, dest=None, **opts):
366 """make a copy of an existing repository
366 """make a copy of an existing repository
367
367
368 Create a copy of an existing repository in a new directory.
368 Create a copy of an existing repository in a new directory.
369
369
370 If no destination directory name is specified, it defaults to the
370 If no destination directory name is specified, it defaults to the
371 basename of the source.
371 basename of the source.
372
372
373 The location of the source is added to the new repository's
373 The location of the source is added to the new repository's
374 .hg/hgrc file, as the default to be used for future pulls.
374 .hg/hgrc file, as the default to be used for future pulls.
375
375
376 For efficiency, hardlinks are used for cloning whenever the source
376 For efficiency, hardlinks are used for cloning whenever the source
377 and destination are on the same filesystem (note this applies only
377 and destination are on the same filesystem (note this applies only
378 to the repository data, not to the checked out files). Some
378 to the repository data, not to the checked out files). Some
379 filesystems, such as AFS, implement hardlinking incorrectly, but
379 filesystems, such as AFS, implement hardlinking incorrectly, but
380 do not report errors. In these cases, use the --pull option to
380 do not report errors. In these cases, use the --pull option to
381 avoid hardlinking.
381 avoid hardlinking.
382
382
383 You can safely clone repositories and checked out files using full
383 You can safely clone repositories and checked out files using full
384 hardlinks with
384 hardlinks with
385
385
386 $ cp -al REPO REPOCLONE
386 $ cp -al REPO REPOCLONE
387
387
388 which is the fastest way to clone. However, the operation is not
388 which is the fastest way to clone. However, the operation is not
389 atomic (making sure REPO is not modified during the operation is
389 atomic (making sure REPO is not modified during the operation is
390 up to you) and you have to make sure your editor breaks hardlinks
390 up to you) and you have to make sure your editor breaks hardlinks
391 (Emacs and most Linux Kernel tools do so).
391 (Emacs and most Linux Kernel tools do so).
392
392
393 If you use the -r option to clone up to a specific revision, no
393 If you use the -r option to clone up to a specific revision, no
394 subsequent revisions will be present in the cloned repository.
394 subsequent revisions will be present in the cloned repository.
395 This option implies --pull, even on local repositories.
395 This option implies --pull, even on local repositories.
396
396
397 See pull for valid source format details.
397 See pull for valid source format details.
398
398
399 It is possible to specify an ssh:// URL as the destination, but no
399 It is possible to specify an ssh:// URL as the destination, but no
400 .hg/hgrc and working directory will be created on the remote side.
400 .hg/hgrc and working directory will be created on the remote side.
401 Look at the help text for the pull command for important details
401 Look at the help text for the pull command for important details
402 about ssh:// URLs.
402 about ssh:// URLs.
403 """
403 """
404 setremoteconfig(ui, opts)
404 setremoteconfig(ui, opts)
405 hg.clone(ui, ui.expandpath(source), dest,
405 hg.clone(ui, ui.expandpath(source), dest,
406 pull=opts['pull'],
406 pull=opts['pull'],
407 stream=opts['uncompressed'],
407 stream=opts['uncompressed'],
408 rev=opts['rev'],
408 rev=opts['rev'],
409 update=not opts['noupdate'])
409 update=not opts['noupdate'])
410
410
411 def commit(ui, repo, *pats, **opts):
411 def commit(ui, repo, *pats, **opts):
412 """commit the specified files or all outstanding changes
412 """commit the specified files or all outstanding changes
413
413
414 Commit changes to the given files into the repository.
414 Commit changes to the given files into the repository.
415
415
416 If a list of files is omitted, all changes reported by "hg status"
416 If a list of files is omitted, all changes reported by "hg status"
417 will be committed.
417 will be committed.
418
418
419 If no commit message is specified, the editor configured in your hgrc
419 If no commit message is specified, the editor configured in your hgrc
420 or in the EDITOR environment variable is started to enter a message.
420 or in the EDITOR environment variable is started to enter a message.
421 """
421 """
422 message = logmessage(opts)
422 message = logmessage(opts)
423
423
424 if opts['addremove']:
424 if opts['addremove']:
425 cmdutil.addremove(repo, pats, opts)
425 cmdutil.addremove(repo, pats, opts)
426 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
426 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
427 if pats:
427 if pats:
428 status = repo.status(files=fns, match=match)
428 status = repo.status(files=fns, match=match)
429 modified, added, removed, deleted, unknown = status[:5]
429 modified, added, removed, deleted, unknown = status[:5]
430 files = modified + added + removed
430 files = modified + added + removed
431 slist = None
431 slist = None
432 for f in fns:
432 for f in fns:
433 if f == '.':
433 if f == '.':
434 continue
434 continue
435 if f not in files:
435 if f not in files:
436 rf = repo.wjoin(f)
436 rf = repo.wjoin(f)
437 if f in unknown:
437 if f in unknown:
438 raise util.Abort(_("file %s not tracked!") % rf)
438 raise util.Abort(_("file %s not tracked!") % rf)
439 try:
439 try:
440 mode = os.lstat(rf)[stat.ST_MODE]
440 mode = os.lstat(rf)[stat.ST_MODE]
441 except OSError:
441 except OSError:
442 raise util.Abort(_("file %s not found!") % rf)
442 raise util.Abort(_("file %s not found!") % rf)
443 if stat.S_ISDIR(mode):
443 if stat.S_ISDIR(mode):
444 name = f + '/'
444 name = f + '/'
445 if slist is None:
445 if slist is None:
446 slist = list(files)
446 slist = list(files)
447 slist.sort()
447 slist.sort()
448 i = bisect.bisect(slist, name)
448 i = bisect.bisect(slist, name)
449 if i >= len(slist) or not slist[i].startswith(name):
449 if i >= len(slist) or not slist[i].startswith(name):
450 raise util.Abort(_("no match under directory %s!")
450 raise util.Abort(_("no match under directory %s!")
451 % rf)
451 % rf)
452 elif not stat.S_ISREG(mode):
452 elif not stat.S_ISREG(mode):
453 raise util.Abort(_("can't commit %s: "
453 raise util.Abort(_("can't commit %s: "
454 "unsupported file type!") % rf)
454 "unsupported file type!") % rf)
455 else:
455 else:
456 files = []
456 files = []
457 try:
457 try:
458 repo.commit(files, message, opts['user'], opts['date'], match,
458 repo.commit(files, message, opts['user'], opts['date'], match,
459 force_editor=opts.get('force_editor'))
459 force_editor=opts.get('force_editor'))
460 except ValueError, inst:
460 except ValueError, inst:
461 raise util.Abort(str(inst))
461 raise util.Abort(str(inst))
462
462
463 def docopy(ui, repo, pats, opts, wlock):
463 def docopy(ui, repo, pats, opts, wlock):
464 # called with the repo lock held
464 # called with the repo lock held
465 #
465 #
466 # hgsep => pathname that uses "/" to separate directories
466 # hgsep => pathname that uses "/" to separate directories
467 # ossep => pathname that uses os.sep to separate directories
467 # ossep => pathname that uses os.sep to separate directories
468 cwd = repo.getcwd()
468 cwd = repo.getcwd()
469 errors = 0
469 errors = 0
470 copied = []
470 copied = []
471 targets = {}
471 targets = {}
472
472
473 # abs: hgsep
473 # abs: hgsep
474 # rel: ossep
474 # rel: ossep
475 # return: hgsep
475 # return: hgsep
476 def okaytocopy(abs, rel, exact):
476 def okaytocopy(abs, rel, exact):
477 reasons = {'?': _('is not managed'),
477 reasons = {'?': _('is not managed'),
478 'a': _('has been marked for add'),
478 'a': _('has been marked for add'),
479 'r': _('has been marked for remove')}
479 'r': _('has been marked for remove')}
480 state = repo.dirstate.state(abs)
480 state = repo.dirstate.state(abs)
481 reason = reasons.get(state)
481 reason = reasons.get(state)
482 if reason:
482 if reason:
483 if state == 'a':
483 if state == 'a':
484 origsrc = repo.dirstate.copied(abs)
484 origsrc = repo.dirstate.copied(abs)
485 if origsrc is not None:
485 if origsrc is not None:
486 return origsrc
486 return origsrc
487 if exact:
487 if exact:
488 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
488 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
489 else:
489 else:
490 return abs
490 return abs
491
491
492 # origsrc: hgsep
492 # origsrc: hgsep
493 # abssrc: hgsep
493 # abssrc: hgsep
494 # relsrc: ossep
494 # relsrc: ossep
495 # target: ossep
495 # target: ossep
496 def copy(origsrc, abssrc, relsrc, target, exact):
496 def copy(origsrc, abssrc, relsrc, target, exact):
497 abstarget = util.canonpath(repo.root, cwd, target)
497 abstarget = util.canonpath(repo.root, cwd, target)
498 reltarget = util.pathto(repo.root, cwd, abstarget)
498 reltarget = util.pathto(repo.root, cwd, abstarget)
499 prevsrc = targets.get(abstarget)
499 prevsrc = targets.get(abstarget)
500 if prevsrc is not None:
500 if prevsrc is not None:
501 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
501 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
502 (reltarget, util.localpath(abssrc),
502 (reltarget, util.localpath(abssrc),
503 util.localpath(prevsrc)))
503 util.localpath(prevsrc)))
504 return
504 return
505 if (not opts['after'] and os.path.exists(reltarget) or
505 if (not opts['after'] and os.path.exists(reltarget) or
506 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
506 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
507 if not opts['force']:
507 if not opts['force']:
508 ui.warn(_('%s: not overwriting - file exists\n') %
508 ui.warn(_('%s: not overwriting - file exists\n') %
509 reltarget)
509 reltarget)
510 return
510 return
511 if not opts['after'] and not opts.get('dry_run'):
511 if not opts['after'] and not opts.get('dry_run'):
512 os.unlink(reltarget)
512 os.unlink(reltarget)
513 if opts['after']:
513 if opts['after']:
514 if not os.path.exists(reltarget):
514 if not os.path.exists(reltarget):
515 return
515 return
516 else:
516 else:
517 targetdir = os.path.dirname(reltarget) or '.'
517 targetdir = os.path.dirname(reltarget) or '.'
518 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
518 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
519 os.makedirs(targetdir)
519 os.makedirs(targetdir)
520 try:
520 try:
521 restore = repo.dirstate.state(abstarget) == 'r'
521 restore = repo.dirstate.state(abstarget) == 'r'
522 if restore and not opts.get('dry_run'):
522 if restore and not opts.get('dry_run'):
523 repo.undelete([abstarget], wlock)
523 repo.undelete([abstarget], wlock)
524 try:
524 try:
525 if not opts.get('dry_run'):
525 if not opts.get('dry_run'):
526 util.copyfile(relsrc, reltarget)
526 util.copyfile(relsrc, reltarget)
527 restore = False
527 restore = False
528 finally:
528 finally:
529 if restore:
529 if restore:
530 repo.remove([abstarget], wlock)
530 repo.remove([abstarget], wlock)
531 except IOError, inst:
531 except IOError, inst:
532 if inst.errno == errno.ENOENT:
532 if inst.errno == errno.ENOENT:
533 ui.warn(_('%s: deleted in working copy\n') % relsrc)
533 ui.warn(_('%s: deleted in working copy\n') % relsrc)
534 else:
534 else:
535 ui.warn(_('%s: cannot copy - %s\n') %
535 ui.warn(_('%s: cannot copy - %s\n') %
536 (relsrc, inst.strerror))
536 (relsrc, inst.strerror))
537 errors += 1
537 errors += 1
538 return
538 return
539 if ui.verbose or not exact:
539 if ui.verbose or not exact:
540 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
540 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
541 targets[abstarget] = abssrc
541 targets[abstarget] = abssrc
542 if abstarget != origsrc and not opts.get('dry_run'):
542 if abstarget != origsrc and not opts.get('dry_run'):
543 repo.copy(origsrc, abstarget, wlock)
543 repo.copy(origsrc, abstarget, wlock)
544 copied.append((abssrc, relsrc, exact))
544 copied.append((abssrc, relsrc, exact))
545
545
546 # pat: ossep
546 # pat: ossep
547 # dest ossep
547 # dest ossep
548 # srcs: list of (hgsep, hgsep, ossep, bool)
548 # srcs: list of (hgsep, hgsep, ossep, bool)
549 # return: function that takes hgsep and returns ossep
549 # return: function that takes hgsep and returns ossep
550 def targetpathfn(pat, dest, srcs):
550 def targetpathfn(pat, dest, srcs):
551 if os.path.isdir(pat):
551 if os.path.isdir(pat):
552 abspfx = util.canonpath(repo.root, cwd, pat)
552 abspfx = util.canonpath(repo.root, cwd, pat)
553 abspfx = util.localpath(abspfx)
553 abspfx = util.localpath(abspfx)
554 if destdirexists:
554 if destdirexists:
555 striplen = len(os.path.split(abspfx)[0])
555 striplen = len(os.path.split(abspfx)[0])
556 else:
556 else:
557 striplen = len(abspfx)
557 striplen = len(abspfx)
558 if striplen:
558 if striplen:
559 striplen += len(os.sep)
559 striplen += len(os.sep)
560 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
560 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
561 elif destdirexists:
561 elif destdirexists:
562 res = lambda p: os.path.join(dest,
562 res = lambda p: os.path.join(dest,
563 os.path.basename(util.localpath(p)))
563 os.path.basename(util.localpath(p)))
564 else:
564 else:
565 res = lambda p: dest
565 res = lambda p: dest
566 return res
566 return res
567
567
568 # pat: ossep
568 # pat: ossep
569 # dest ossep
569 # dest ossep
570 # srcs: list of (hgsep, hgsep, ossep, bool)
570 # srcs: list of (hgsep, hgsep, ossep, bool)
571 # return: function that takes hgsep and returns ossep
571 # return: function that takes hgsep and returns ossep
572 def targetpathafterfn(pat, dest, srcs):
572 def targetpathafterfn(pat, dest, srcs):
573 if util.patkind(pat, None)[0]:
573 if util.patkind(pat, None)[0]:
574 # a mercurial pattern
574 # a mercurial pattern
575 res = lambda p: os.path.join(dest,
575 res = lambda p: os.path.join(dest,
576 os.path.basename(util.localpath(p)))
576 os.path.basename(util.localpath(p)))
577 else:
577 else:
578 abspfx = util.canonpath(repo.root, cwd, pat)
578 abspfx = util.canonpath(repo.root, cwd, pat)
579 if len(abspfx) < len(srcs[0][0]):
579 if len(abspfx) < len(srcs[0][0]):
580 # A directory. Either the target path contains the last
580 # A directory. Either the target path contains the last
581 # component of the source path or it does not.
581 # component of the source path or it does not.
582 def evalpath(striplen):
582 def evalpath(striplen):
583 score = 0
583 score = 0
584 for s in srcs:
584 for s in srcs:
585 t = os.path.join(dest, util.localpath(s[0])[striplen:])
585 t = os.path.join(dest, util.localpath(s[0])[striplen:])
586 if os.path.exists(t):
586 if os.path.exists(t):
587 score += 1
587 score += 1
588 return score
588 return score
589
589
590 abspfx = util.localpath(abspfx)
590 abspfx = util.localpath(abspfx)
591 striplen = len(abspfx)
591 striplen = len(abspfx)
592 if striplen:
592 if striplen:
593 striplen += len(os.sep)
593 striplen += len(os.sep)
594 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
594 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
595 score = evalpath(striplen)
595 score = evalpath(striplen)
596 striplen1 = len(os.path.split(abspfx)[0])
596 striplen1 = len(os.path.split(abspfx)[0])
597 if striplen1:
597 if striplen1:
598 striplen1 += len(os.sep)
598 striplen1 += len(os.sep)
599 if evalpath(striplen1) > score:
599 if evalpath(striplen1) > score:
600 striplen = striplen1
600 striplen = striplen1
601 res = lambda p: os.path.join(dest,
601 res = lambda p: os.path.join(dest,
602 util.localpath(p)[striplen:])
602 util.localpath(p)[striplen:])
603 else:
603 else:
604 # a file
604 # a file
605 if destdirexists:
605 if destdirexists:
606 res = lambda p: os.path.join(dest,
606 res = lambda p: os.path.join(dest,
607 os.path.basename(util.localpath(p)))
607 os.path.basename(util.localpath(p)))
608 else:
608 else:
609 res = lambda p: dest
609 res = lambda p: dest
610 return res
610 return res
611
611
612
612
613 pats = util.expand_glob(pats)
613 pats = util.expand_glob(pats)
614 if not pats:
614 if not pats:
615 raise util.Abort(_('no source or destination specified'))
615 raise util.Abort(_('no source or destination specified'))
616 if len(pats) == 1:
616 if len(pats) == 1:
617 raise util.Abort(_('no destination specified'))
617 raise util.Abort(_('no destination specified'))
618 dest = pats.pop()
618 dest = pats.pop()
619 destdirexists = os.path.isdir(dest)
619 destdirexists = os.path.isdir(dest)
620 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
620 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
621 raise util.Abort(_('with multiple sources, destination must be an '
621 raise util.Abort(_('with multiple sources, destination must be an '
622 'existing directory'))
622 'existing directory'))
623 if opts['after']:
623 if opts['after']:
624 tfn = targetpathafterfn
624 tfn = targetpathafterfn
625 else:
625 else:
626 tfn = targetpathfn
626 tfn = targetpathfn
627 copylist = []
627 copylist = []
628 for pat in pats:
628 for pat in pats:
629 srcs = []
629 srcs = []
630 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
630 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
631 globbed=True):
631 globbed=True):
632 origsrc = okaytocopy(abssrc, relsrc, exact)
632 origsrc = okaytocopy(abssrc, relsrc, exact)
633 if origsrc:
633 if origsrc:
634 srcs.append((origsrc, abssrc, relsrc, exact))
634 srcs.append((origsrc, abssrc, relsrc, exact))
635 if not srcs:
635 if not srcs:
636 continue
636 continue
637 copylist.append((tfn(pat, dest, srcs), srcs))
637 copylist.append((tfn(pat, dest, srcs), srcs))
638 if not copylist:
638 if not copylist:
639 raise util.Abort(_('no files to copy'))
639 raise util.Abort(_('no files to copy'))
640
640
641 for targetpath, srcs in copylist:
641 for targetpath, srcs in copylist:
642 for origsrc, abssrc, relsrc, exact in srcs:
642 for origsrc, abssrc, relsrc, exact in srcs:
643 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
643 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
644
644
645 if errors:
645 if errors:
646 ui.warn(_('(consider using --after)\n'))
646 ui.warn(_('(consider using --after)\n'))
647 return errors, copied
647 return errors, copied
648
648
649 def copy(ui, repo, *pats, **opts):
649 def copy(ui, repo, *pats, **opts):
650 """mark files as copied for the next commit
650 """mark files as copied for the next commit
651
651
652 Mark dest as having copies of source files. If dest is a
652 Mark dest as having copies of source files. If dest is a
653 directory, copies are put in that directory. If dest is a file,
653 directory, copies are put in that directory. If dest is a file,
654 there can only be one source.
654 there can only be one source.
655
655
656 By default, this command copies the contents of files as they
656 By default, this command copies the contents of files as they
657 stand in the working directory. If invoked with --after, the
657 stand in the working directory. If invoked with --after, the
658 operation is recorded, but no copying is performed.
658 operation is recorded, but no copying is performed.
659
659
660 This command takes effect in the next commit. To undo a copy
660 This command takes effect in the next commit. To undo a copy
661 before that, see hg revert.
661 before that, see hg revert.
662 """
662 """
663 wlock = repo.wlock(0)
663 wlock = repo.wlock(0)
664 errs, copied = docopy(ui, repo, pats, opts, wlock)
664 errs, copied = docopy(ui, repo, pats, opts, wlock)
665 return errs
665 return errs
666
666
667 def debugancestor(ui, index, rev1, rev2):
667 def debugancestor(ui, index, rev1, rev2):
668 """find the ancestor revision of two revisions in a given index"""
668 """find the ancestor revision of two revisions in a given index"""
669 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
669 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
670 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
670 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
671 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
671 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
672
672
673 def debugcomplete(ui, cmd='', **opts):
673 def debugcomplete(ui, cmd='', **opts):
674 """returns the completion list associated with the given command"""
674 """returns the completion list associated with the given command"""
675
675
676 if opts['options']:
676 if opts['options']:
677 options = []
677 options = []
678 otables = [globalopts]
678 otables = [globalopts]
679 if cmd:
679 if cmd:
680 aliases, entry = findcmd(ui, cmd)
680 aliases, entry = findcmd(ui, cmd)
681 otables.append(entry[1])
681 otables.append(entry[1])
682 for t in otables:
682 for t in otables:
683 for o in t:
683 for o in t:
684 if o[0]:
684 if o[0]:
685 options.append('-%s' % o[0])
685 options.append('-%s' % o[0])
686 options.append('--%s' % o[1])
686 options.append('--%s' % o[1])
687 ui.write("%s\n" % "\n".join(options))
687 ui.write("%s\n" % "\n".join(options))
688 return
688 return
689
689
690 clist = findpossible(ui, cmd).keys()
690 clist = findpossible(ui, cmd).keys()
691 clist.sort()
691 clist.sort()
692 ui.write("%s\n" % "\n".join(clist))
692 ui.write("%s\n" % "\n".join(clist))
693
693
694 def debugrebuildstate(ui, repo, rev=""):
694 def debugrebuildstate(ui, repo, rev=""):
695 """rebuild the dirstate as it would look like for the given revision"""
695 """rebuild the dirstate as it would look like for the given revision"""
696 if rev == "":
696 if rev == "":
697 rev = repo.changelog.tip()
697 rev = repo.changelog.tip()
698 ctx = repo.changectx(rev)
698 ctx = repo.changectx(rev)
699 files = ctx.manifest()
699 files = ctx.manifest()
700 wlock = repo.wlock()
700 wlock = repo.wlock()
701 repo.dirstate.rebuild(rev, files)
701 repo.dirstate.rebuild(rev, files)
702
702
703 def debugcheckstate(ui, repo):
703 def debugcheckstate(ui, repo):
704 """validate the correctness of the current dirstate"""
704 """validate the correctness of the current dirstate"""
705 parent1, parent2 = repo.dirstate.parents()
705 parent1, parent2 = repo.dirstate.parents()
706 repo.dirstate.read()
706 repo.dirstate.read()
707 dc = repo.dirstate.map
707 dc = repo.dirstate.map
708 keys = dc.keys()
708 keys = dc.keys()
709 keys.sort()
709 keys.sort()
710 m1 = repo.changectx(parent1).manifest()
710 m1 = repo.changectx(parent1).manifest()
711 m2 = repo.changectx(parent2).manifest()
711 m2 = repo.changectx(parent2).manifest()
712 errors = 0
712 errors = 0
713 for f in dc:
713 for f in dc:
714 state = repo.dirstate.state(f)
714 state = repo.dirstate.state(f)
715 if state in "nr" and f not in m1:
715 if state in "nr" and f not in m1:
716 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
716 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
717 errors += 1
717 errors += 1
718 if state in "a" and f in m1:
718 if state in "a" and f in m1:
719 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
719 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
720 errors += 1
720 errors += 1
721 if state in "m" and f not in m1 and f not in m2:
721 if state in "m" and f not in m1 and f not in m2:
722 ui.warn(_("%s in state %s, but not in either manifest\n") %
722 ui.warn(_("%s in state %s, but not in either manifest\n") %
723 (f, state))
723 (f, state))
724 errors += 1
724 errors += 1
725 for f in m1:
725 for f in m1:
726 state = repo.dirstate.state(f)
726 state = repo.dirstate.state(f)
727 if state not in "nrm":
727 if state not in "nrm":
728 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
728 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
729 errors += 1
729 errors += 1
730 if errors:
730 if errors:
731 error = _(".hg/dirstate inconsistent with current parent's manifest")
731 error = _(".hg/dirstate inconsistent with current parent's manifest")
732 raise util.Abort(error)
732 raise util.Abort(error)
733
733
734 def showconfig(ui, repo, *values, **opts):
734 def showconfig(ui, repo, *values, **opts):
735 """show combined config settings from all hgrc files
735 """show combined config settings from all hgrc files
736
736
737 With no args, print names and values of all config items.
737 With no args, print names and values of all config items.
738
738
739 With one arg of the form section.name, print just the value of
739 With one arg of the form section.name, print just the value of
740 that config item.
740 that config item.
741
741
742 With multiple args, print names and values of all config items
742 With multiple args, print names and values of all config items
743 with matching section names."""
743 with matching section names."""
744
744
745 untrusted = bool(opts.get('untrusted'))
745 untrusted = bool(opts.get('untrusted'))
746 if values:
746 if values:
747 if len([v for v in values if '.' in v]) > 1:
747 if len([v for v in values if '.' in v]) > 1:
748 raise util.Abort(_('only one config item permitted'))
748 raise util.Abort(_('only one config item permitted'))
749 for section, name, value in ui.walkconfig(untrusted=untrusted):
749 for section, name, value in ui.walkconfig(untrusted=untrusted):
750 sectname = section + '.' + name
750 sectname = section + '.' + name
751 if values:
751 if values:
752 for v in values:
752 for v in values:
753 if v == section:
753 if v == section:
754 ui.write('%s=%s\n' % (sectname, value))
754 ui.write('%s=%s\n' % (sectname, value))
755 elif v == sectname:
755 elif v == sectname:
756 ui.write(value, '\n')
756 ui.write(value, '\n')
757 else:
757 else:
758 ui.write('%s=%s\n' % (sectname, value))
758 ui.write('%s=%s\n' % (sectname, value))
759
759
760 def debugsetparents(ui, repo, rev1, rev2=None):
760 def debugsetparents(ui, repo, rev1, rev2=None):
761 """manually set the parents of the current working directory
761 """manually set the parents of the current working directory
762
762
763 This is useful for writing repository conversion tools, but should
763 This is useful for writing repository conversion tools, but should
764 be used with care.
764 be used with care.
765 """
765 """
766
766
767 if not rev2:
767 if not rev2:
768 rev2 = hex(nullid)
768 rev2 = hex(nullid)
769
769
770 wlock = repo.wlock()
770 wlock = repo.wlock()
771 try:
771 try:
772 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
772 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
773 finally:
773 finally:
774 wlock.release()
774 wlock.release()
775
775
776 def debugstate(ui, repo):
776 def debugstate(ui, repo):
777 """show the contents of the current dirstate"""
777 """show the contents of the current dirstate"""
778 repo.dirstate.read()
778 repo.dirstate.read()
779 dc = repo.dirstate.map
779 dc = repo.dirstate.map
780 keys = dc.keys()
780 keys = dc.keys()
781 keys.sort()
781 keys.sort()
782 for file_ in keys:
782 for file_ in keys:
783 if dc[file_][3] == -1:
783 if dc[file_][3] == -1:
784 # Pad or slice to locale representation
784 # Pad or slice to locale representation
785 locale_len = len(time.strftime("%x %X", time.localtime(0)))
785 locale_len = len(time.strftime("%x %X", time.localtime(0)))
786 timestr = 'unset'
786 timestr = 'unset'
787 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
787 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
788 else:
788 else:
789 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
789 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
790 ui.write("%c %3o %10d %s %s\n"
790 ui.write("%c %3o %10d %s %s\n"
791 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
791 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
792 timestr, file_))
792 timestr, file_))
793 for f in repo.dirstate.copies():
793 for f in repo.dirstate.copies():
794 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
794 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
795
795
796 def debugdata(ui, file_, rev):
796 def debugdata(ui, file_, rev):
797 """dump the contents of a data file revision"""
797 """dump the contents of a data file revision"""
798 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
798 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
799 try:
799 try:
800 ui.write(r.revision(r.lookup(rev)))
800 ui.write(r.revision(r.lookup(rev)))
801 except KeyError:
801 except KeyError:
802 raise util.Abort(_('invalid revision identifier %s') % rev)
802 raise util.Abort(_('invalid revision identifier %s') % rev)
803
803
804 def debugdate(ui, date, range=None, **opts):
804 def debugdate(ui, date, range=None, **opts):
805 """parse and display a date"""
805 """parse and display a date"""
806 if opts["extended"]:
806 if opts["extended"]:
807 d = util.parsedate(date, util.extendeddateformats)
807 d = util.parsedate(date, util.extendeddateformats)
808 else:
808 else:
809 d = util.parsedate(date)
809 d = util.parsedate(date)
810 ui.write("internal: %s %s\n" % d)
810 ui.write("internal: %s %s\n" % d)
811 ui.write("standard: %s\n" % util.datestr(d))
811 ui.write("standard: %s\n" % util.datestr(d))
812 if range:
812 if range:
813 m = util.matchdate(range)
813 m = util.matchdate(range)
814 ui.write("match: %s\n" % m(d[0]))
814 ui.write("match: %s\n" % m(d[0]))
815
815
816 def debugindex(ui, file_):
816 def debugindex(ui, file_):
817 """dump the contents of an index file"""
817 """dump the contents of an index file"""
818 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
818 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
819 ui.write(" rev offset length base linkrev" +
819 ui.write(" rev offset length base linkrev" +
820 " nodeid p1 p2\n")
820 " nodeid p1 p2\n")
821 for i in xrange(r.count()):
821 for i in xrange(r.count()):
822 node = r.node(i)
822 node = r.node(i)
823 pp = r.parents(node)
823 pp = r.parents(node)
824 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
824 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
825 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
825 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
826 short(node), short(pp[0]), short(pp[1])))
826 short(node), short(pp[0]), short(pp[1])))
827
827
828 def debugindexdot(ui, file_):
828 def debugindexdot(ui, file_):
829 """dump an index DAG as a .dot file"""
829 """dump an index DAG as a .dot file"""
830 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
830 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
831 ui.write("digraph G {\n")
831 ui.write("digraph G {\n")
832 for i in xrange(r.count()):
832 for i in xrange(r.count()):
833 node = r.node(i)
833 node = r.node(i)
834 pp = r.parents(node)
834 pp = r.parents(node)
835 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
835 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
836 if pp[1] != nullid:
836 if pp[1] != nullid:
837 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
837 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
838 ui.write("}\n")
838 ui.write("}\n")
839
839
840 def debuginstall(ui):
840 def debuginstall(ui):
841 '''test Mercurial installation'''
841 '''test Mercurial installation'''
842
842
843 def writetemp(contents):
843 def writetemp(contents):
844 (fd, name) = tempfile.mkstemp()
844 (fd, name) = tempfile.mkstemp()
845 f = os.fdopen(fd, "wb")
845 f = os.fdopen(fd, "wb")
846 f.write(contents)
846 f.write(contents)
847 f.close()
847 f.close()
848 return name
848 return name
849
849
850 problems = 0
850 problems = 0
851
851
852 # encoding
852 # encoding
853 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
853 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
854 try:
854 try:
855 util.fromlocal("test")
855 util.fromlocal("test")
856 except util.Abort, inst:
856 except util.Abort, inst:
857 ui.write(" %s\n" % inst)
857 ui.write(" %s\n" % inst)
858 ui.write(_(" (check that your locale is properly set)\n"))
858 ui.write(_(" (check that your locale is properly set)\n"))
859 problems += 1
859 problems += 1
860
860
861 # compiled modules
861 # compiled modules
862 ui.status(_("Checking extensions...\n"))
862 ui.status(_("Checking extensions...\n"))
863 try:
863 try:
864 import bdiff, mpatch, base85
864 import bdiff, mpatch, base85
865 except Exception, inst:
865 except Exception, inst:
866 ui.write(" %s\n" % inst)
866 ui.write(" %s\n" % inst)
867 ui.write(_(" One or more extensions could not be found"))
867 ui.write(_(" One or more extensions could not be found"))
868 ui.write(_(" (check that you compiled the extensions)\n"))
868 ui.write(_(" (check that you compiled the extensions)\n"))
869 problems += 1
869 problems += 1
870
870
871 # templates
871 # templates
872 ui.status(_("Checking templates...\n"))
872 ui.status(_("Checking templates...\n"))
873 try:
873 try:
874 import templater
874 import templater
875 t = templater.templater(templater.templatepath("map-cmdline.default"))
875 t = templater.templater(templater.templatepath("map-cmdline.default"))
876 except Exception, inst:
876 except Exception, inst:
877 ui.write(" %s\n" % inst)
877 ui.write(" %s\n" % inst)
878 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
878 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
879 problems += 1
879 problems += 1
880
880
881 # patch
881 # patch
882 ui.status(_("Checking patch...\n"))
882 ui.status(_("Checking patch...\n"))
883 path = os.environ.get('PATH', '')
883 path = os.environ.get('PATH', '')
884 patcher = util.find_in_path('gpatch', path,
884 patcher = util.find_in_path('gpatch', path,
885 util.find_in_path('patch', path, None))
885 util.find_in_path('patch', path, None))
886 if not patcher:
886 if not patcher:
887 ui.write(_(" Can't find patch or gpatch in PATH\n"))
887 ui.write(_(" Can't find patch or gpatch in PATH\n"))
888 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
888 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
889 problems += 1
889 problems += 1
890 else:
890 else:
891 # actually attempt a patch here
891 # actually attempt a patch here
892 a = "1\n2\n3\n4\n"
892 a = "1\n2\n3\n4\n"
893 b = "1\n2\n3\ninsert\n4\n"
893 b = "1\n2\n3\ninsert\n4\n"
894 d = mdiff.unidiff(a, None, b, None, "a")
894 d = mdiff.unidiff(a, None, b, None, "a")
895 fa = writetemp(a)
895 fa = writetemp(a)
896 fd = writetemp(d)
896 fd = writetemp(d)
897 fp = os.popen('%s %s %s' % (patcher, fa, fd))
897 fp = os.popen('%s %s %s' % (patcher, fa, fd))
898 files = []
898 files = []
899 output = ""
899 output = ""
900 for line in fp:
900 for line in fp:
901 output += line
901 output += line
902 if line.startswith('patching file '):
902 if line.startswith('patching file '):
903 pf = util.parse_patch_output(line.rstrip())
903 pf = util.parse_patch_output(line.rstrip())
904 files.append(pf)
904 files.append(pf)
905 if files != [fa]:
905 if files != [fa]:
906 ui.write(_(" unexpected patch output!"))
906 ui.write(_(" unexpected patch output!"))
907 ui.write(_(" (you may have an incompatible version of patch)\n"))
907 ui.write(_(" (you may have an incompatible version of patch)\n"))
908 ui.write(output)
908 ui.write(output)
909 problems += 1
909 problems += 1
910 a = file(fa).read()
910 a = file(fa).read()
911 if a != b:
911 if a != b:
912 ui.write(_(" patch test failed!"))
912 ui.write(_(" patch test failed!"))
913 ui.write(_(" (you may have an incompatible version of patch)\n"))
913 ui.write(_(" (you may have an incompatible version of patch)\n"))
914 problems += 1
914 problems += 1
915 os.unlink(fa)
915 os.unlink(fa)
916 os.unlink(fd)
916 os.unlink(fd)
917
917
918 # merge helper
918 # merge helper
919 ui.status(_("Checking merge helper...\n"))
919 ui.status(_("Checking merge helper...\n"))
920 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
920 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
921 or "hgmerge")
921 or "hgmerge")
922 cmdpath = util.find_in_path(cmd, path)
922 cmdpath = util.find_in_path(cmd, path)
923 if not cmdpath:
923 if not cmdpath:
924 cmdpath = util.find_in_path(cmd.split()[0], path)
924 cmdpath = util.find_in_path(cmd.split()[0], path)
925 if not cmdpath:
925 if not cmdpath:
926 if cmd == 'hgmerge':
926 if cmd == 'hgmerge':
927 ui.write(_(" No merge helper set and can't find default"
927 ui.write(_(" No merge helper set and can't find default"
928 " hgmerge script in PATH\n"))
928 " hgmerge script in PATH\n"))
929 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
929 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
930 else:
930 else:
931 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
931 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
932 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
932 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
933 problems += 1
933 problems += 1
934 else:
934 else:
935 # actually attempt a patch here
935 # actually attempt a patch here
936 fa = writetemp("1\n2\n3\n4\n")
936 fa = writetemp("1\n2\n3\n4\n")
937 fl = writetemp("1\n2\n3\ninsert\n4\n")
937 fl = writetemp("1\n2\n3\ninsert\n4\n")
938 fr = writetemp("begin\n1\n2\n3\n4\n")
938 fr = writetemp("begin\n1\n2\n3\n4\n")
939 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
939 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
940 if r:
940 if r:
941 ui.write(_(" got unexpected merge error %d!") % r)
941 ui.write(_(" got unexpected merge error %d!") % r)
942 problems += 1
942 problems += 1
943 m = file(fl).read()
943 m = file(fl).read()
944 if m != "begin\n1\n2\n3\ninsert\n4\n":
944 if m != "begin\n1\n2\n3\ninsert\n4\n":
945 ui.write(_(" got unexpected merge results!") % r)
945 ui.write(_(" got unexpected merge results!") % r)
946 ui.write(_(" (your merge helper may have the"
946 ui.write(_(" (your merge helper may have the"
947 " wrong argument order)\n"))
947 " wrong argument order)\n"))
948 ui.write(m)
948 ui.write(m)
949 os.unlink(fa)
949 os.unlink(fa)
950 os.unlink(fl)
950 os.unlink(fl)
951 os.unlink(fr)
951 os.unlink(fr)
952
952
953 # editor
953 # editor
954 ui.status(_("Checking commit editor...\n"))
954 ui.status(_("Checking commit editor...\n"))
955 editor = (os.environ.get("HGEDITOR") or
955 editor = (os.environ.get("HGEDITOR") or
956 ui.config("ui", "editor") or
956 ui.config("ui", "editor") or
957 os.environ.get("EDITOR", "vi"))
957 os.environ.get("EDITOR", "vi"))
958 cmdpath = util.find_in_path(editor, path)
958 cmdpath = util.find_in_path(editor, path)
959 if not cmdpath:
959 if not cmdpath:
960 cmdpath = util.find_in_path(editor.split()[0], path)
960 cmdpath = util.find_in_path(editor.split()[0], path)
961 if not cmdpath:
961 if not cmdpath:
962 if editor == 'vi':
962 if editor == 'vi':
963 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
963 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
964 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
964 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
965 else:
965 else:
966 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
966 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
967 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
967 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
968 problems += 1
968 problems += 1
969
969
970 # check username
970 # check username
971 ui.status(_("Checking username...\n"))
971 ui.status(_("Checking username...\n"))
972 user = os.environ.get("HGUSER")
972 user = os.environ.get("HGUSER")
973 if user is None:
973 if user is None:
974 user = ui.config("ui", "username")
974 user = ui.config("ui", "username")
975 if user is None:
975 if user is None:
976 user = os.environ.get("EMAIL")
976 user = os.environ.get("EMAIL")
977 if not user:
977 if not user:
978 ui.warn(" ")
978 ui.warn(" ")
979 ui.username()
979 ui.username()
980 ui.write(_(" (specify a username in your .hgrc file)\n"))
980 ui.write(_(" (specify a username in your .hgrc file)\n"))
981
981
982 if not problems:
982 if not problems:
983 ui.status(_("No problems detected\n"))
983 ui.status(_("No problems detected\n"))
984 else:
984 else:
985 ui.write(_("%s problems detected,"
985 ui.write(_("%s problems detected,"
986 " please check your install!\n") % problems)
986 " please check your install!\n") % problems)
987
987
988 return problems
988 return problems
989
989
990 def debugrename(ui, repo, file1, *pats, **opts):
990 def debugrename(ui, repo, file1, *pats, **opts):
991 """dump rename information"""
991 """dump rename information"""
992
992
993 ctx = repo.changectx(opts.get('rev', 'tip'))
993 ctx = repo.changectx(opts.get('rev', 'tip'))
994 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
994 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
995 ctx.node()):
995 ctx.node()):
996 m = ctx.filectx(abs).renamed()
996 m = ctx.filectx(abs).renamed()
997 if m:
997 if m:
998 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
998 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
999 else:
999 else:
1000 ui.write(_("%s not renamed\n") % rel)
1000 ui.write(_("%s not renamed\n") % rel)
1001
1001
1002 def debugwalk(ui, repo, *pats, **opts):
1002 def debugwalk(ui, repo, *pats, **opts):
1003 """show how files match on given patterns"""
1003 """show how files match on given patterns"""
1004 items = list(cmdutil.walk(repo, pats, opts))
1004 items = list(cmdutil.walk(repo, pats, opts))
1005 if not items:
1005 if not items:
1006 return
1006 return
1007 fmt = '%%s %%-%ds %%-%ds %%s' % (
1007 fmt = '%%s %%-%ds %%-%ds %%s' % (
1008 max([len(abs) for (src, abs, rel, exact) in items]),
1008 max([len(abs) for (src, abs, rel, exact) in items]),
1009 max([len(rel) for (src, abs, rel, exact) in items]))
1009 max([len(rel) for (src, abs, rel, exact) in items]))
1010 for src, abs, rel, exact in items:
1010 for src, abs, rel, exact in items:
1011 line = fmt % (src, abs, rel, exact and 'exact' or '')
1011 line = fmt % (src, abs, rel, exact and 'exact' or '')
1012 ui.write("%s\n" % line.rstrip())
1012 ui.write("%s\n" % line.rstrip())
1013
1013
1014 def diff(ui, repo, *pats, **opts):
1014 def diff(ui, repo, *pats, **opts):
1015 """diff repository (or selected files)
1015 """diff repository (or selected files)
1016
1016
1017 Show differences between revisions for the specified files.
1017 Show differences between revisions for the specified files.
1018
1018
1019 Differences between files are shown using the unified diff format.
1019 Differences between files are shown using the unified diff format.
1020
1020
1021 NOTE: diff may generate unexpected results for merges, as it will
1021 NOTE: diff may generate unexpected results for merges, as it will
1022 default to comparing against the working directory's first parent
1022 default to comparing against the working directory's first parent
1023 changeset if no revisions are specified.
1023 changeset if no revisions are specified.
1024
1024
1025 When two revision arguments are given, then changes are shown
1025 When two revision arguments are given, then changes are shown
1026 between those revisions. If only one revision is specified then
1026 between those revisions. If only one revision is specified then
1027 that revision is compared to the working directory, and, when no
1027 that revision is compared to the working directory, and, when no
1028 revisions are specified, the working directory files are compared
1028 revisions are specified, the working directory files are compared
1029 to its parent.
1029 to its parent.
1030
1030
1031 Without the -a option, diff will avoid generating diffs of files
1031 Without the -a option, diff will avoid generating diffs of files
1032 it detects as binary. With -a, diff will generate a diff anyway,
1032 it detects as binary. With -a, diff will generate a diff anyway,
1033 probably with undesirable results.
1033 probably with undesirable results.
1034 """
1034 """
1035 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1035 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1036
1036
1037 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1037 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1038
1038
1039 patch.diff(repo, node1, node2, fns, match=matchfn,
1039 patch.diff(repo, node1, node2, fns, match=matchfn,
1040 opts=patch.diffopts(ui, opts))
1040 opts=patch.diffopts(ui, opts))
1041
1041
1042 def export(ui, repo, *changesets, **opts):
1042 def export(ui, repo, *changesets, **opts):
1043 """dump the header and diffs for one or more changesets
1043 """dump the header and diffs for one or more changesets
1044
1044
1045 Print the changeset header and diffs for one or more revisions.
1045 Print the changeset header and diffs for one or more revisions.
1046
1046
1047 The information shown in the changeset header is: author,
1047 The information shown in the changeset header is: author,
1048 changeset hash, parent(s) and commit comment.
1048 changeset hash, parent(s) and commit comment.
1049
1049
1050 NOTE: export may generate unexpected diff output for merge changesets,
1050 NOTE: export may generate unexpected diff output for merge changesets,
1051 as it will compare the merge changeset against its first parent only.
1051 as it will compare the merge changeset against its first parent only.
1052
1052
1053 Output may be to a file, in which case the name of the file is
1053 Output may be to a file, in which case the name of the file is
1054 given using a format string. The formatting rules are as follows:
1054 given using a format string. The formatting rules are as follows:
1055
1055
1056 %% literal "%" character
1056 %% literal "%" character
1057 %H changeset hash (40 bytes of hexadecimal)
1057 %H changeset hash (40 bytes of hexadecimal)
1058 %N number of patches being generated
1058 %N number of patches being generated
1059 %R changeset revision number
1059 %R changeset revision number
1060 %b basename of the exporting repository
1060 %b basename of the exporting repository
1061 %h short-form changeset hash (12 bytes of hexadecimal)
1061 %h short-form changeset hash (12 bytes of hexadecimal)
1062 %n zero-padded sequence number, starting at 1
1062 %n zero-padded sequence number, starting at 1
1063 %r zero-padded changeset revision number
1063 %r zero-padded changeset revision number
1064
1064
1065 Without the -a option, export will avoid generating diffs of files
1065 Without the -a option, export will avoid generating diffs of files
1066 it detects as binary. With -a, export will generate a diff anyway,
1066 it detects as binary. With -a, export will generate a diff anyway,
1067 probably with undesirable results.
1067 probably with undesirable results.
1068
1068
1069 With the --switch-parent option, the diff will be against the second
1069 With the --switch-parent option, the diff will be against the second
1070 parent. It can be useful to review a merge.
1070 parent. It can be useful to review a merge.
1071 """
1071 """
1072 if not changesets:
1072 if not changesets:
1073 raise util.Abort(_("export requires at least one changeset"))
1073 raise util.Abort(_("export requires at least one changeset"))
1074 revs = cmdutil.revrange(repo, changesets)
1074 revs = cmdutil.revrange(repo, changesets)
1075 if len(revs) > 1:
1075 if len(revs) > 1:
1076 ui.note(_('exporting patches:\n'))
1076 ui.note(_('exporting patches:\n'))
1077 else:
1077 else:
1078 ui.note(_('exporting patch:\n'))
1078 ui.note(_('exporting patch:\n'))
1079 patch.export(repo, revs, template=opts['output'],
1079 patch.export(repo, revs, template=opts['output'],
1080 switch_parent=opts['switch_parent'],
1080 switch_parent=opts['switch_parent'],
1081 opts=patch.diffopts(ui, opts))
1081 opts=patch.diffopts(ui, opts))
1082
1082
1083 def grep(ui, repo, pattern, *pats, **opts):
1083 def grep(ui, repo, pattern, *pats, **opts):
1084 """search for a pattern in specified files and revisions
1084 """search for a pattern in specified files and revisions
1085
1085
1086 Search revisions of files for a regular expression.
1086 Search revisions of files for a regular expression.
1087
1087
1088 This command behaves differently than Unix grep. It only accepts
1088 This command behaves differently than Unix grep. It only accepts
1089 Python/Perl regexps. It searches repository history, not the
1089 Python/Perl regexps. It searches repository history, not the
1090 working directory. It always prints the revision number in which
1090 working directory. It always prints the revision number in which
1091 a match appears.
1091 a match appears.
1092
1092
1093 By default, grep only prints output for the first revision of a
1093 By default, grep only prints output for the first revision of a
1094 file in which it finds a match. To get it to print every revision
1094 file in which it finds a match. To get it to print every revision
1095 that contains a change in match status ("-" for a match that
1095 that contains a change in match status ("-" for a match that
1096 becomes a non-match, or "+" for a non-match that becomes a match),
1096 becomes a non-match, or "+" for a non-match that becomes a match),
1097 use the --all flag.
1097 use the --all flag.
1098 """
1098 """
1099 reflags = 0
1099 reflags = 0
1100 if opts['ignore_case']:
1100 if opts['ignore_case']:
1101 reflags |= re.I
1101 reflags |= re.I
1102 regexp = re.compile(pattern, reflags)
1102 regexp = re.compile(pattern, reflags)
1103 sep, eol = ':', '\n'
1103 sep, eol = ':', '\n'
1104 if opts['print0']:
1104 if opts['print0']:
1105 sep = eol = '\0'
1105 sep = eol = '\0'
1106
1106
1107 fcache = {}
1107 fcache = {}
1108 def getfile(fn):
1108 def getfile(fn):
1109 if fn not in fcache:
1109 if fn not in fcache:
1110 fcache[fn] = repo.file(fn)
1110 fcache[fn] = repo.file(fn)
1111 return fcache[fn]
1111 return fcache[fn]
1112
1112
1113 def matchlines(body):
1113 def matchlines(body):
1114 begin = 0
1114 begin = 0
1115 linenum = 0
1115 linenum = 0
1116 while True:
1116 while True:
1117 match = regexp.search(body, begin)
1117 match = regexp.search(body, begin)
1118 if not match:
1118 if not match:
1119 break
1119 break
1120 mstart, mend = match.span()
1120 mstart, mend = match.span()
1121 linenum += body.count('\n', begin, mstart) + 1
1121 linenum += body.count('\n', begin, mstart) + 1
1122 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1122 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1123 lend = body.find('\n', mend)
1123 lend = body.find('\n', mend)
1124 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1124 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1125 begin = lend + 1
1125 begin = lend + 1
1126
1126
1127 class linestate(object):
1127 class linestate(object):
1128 def __init__(self, line, linenum, colstart, colend):
1128 def __init__(self, line, linenum, colstart, colend):
1129 self.line = line
1129 self.line = line
1130 self.linenum = linenum
1130 self.linenum = linenum
1131 self.colstart = colstart
1131 self.colstart = colstart
1132 self.colend = colend
1132 self.colend = colend
1133
1133
1134 def __eq__(self, other):
1134 def __eq__(self, other):
1135 return self.line == other.line
1135 return self.line == other.line
1136
1136
1137 matches = {}
1137 matches = {}
1138 copies = {}
1138 copies = {}
1139 def grepbody(fn, rev, body):
1139 def grepbody(fn, rev, body):
1140 matches[rev].setdefault(fn, [])
1140 matches[rev].setdefault(fn, [])
1141 m = matches[rev][fn]
1141 m = matches[rev][fn]
1142 for lnum, cstart, cend, line in matchlines(body):
1142 for lnum, cstart, cend, line in matchlines(body):
1143 s = linestate(line, lnum, cstart, cend)
1143 s = linestate(line, lnum, cstart, cend)
1144 m.append(s)
1144 m.append(s)
1145
1145
1146 def difflinestates(a, b):
1146 def difflinestates(a, b):
1147 sm = difflib.SequenceMatcher(None, a, b)
1147 sm = difflib.SequenceMatcher(None, a, b)
1148 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1148 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1149 if tag == 'insert':
1149 if tag == 'insert':
1150 for i in xrange(blo, bhi):
1150 for i in xrange(blo, bhi):
1151 yield ('+', b[i])
1151 yield ('+', b[i])
1152 elif tag == 'delete':
1152 elif tag == 'delete':
1153 for i in xrange(alo, ahi):
1153 for i in xrange(alo, ahi):
1154 yield ('-', a[i])
1154 yield ('-', a[i])
1155 elif tag == 'replace':
1155 elif tag == 'replace':
1156 for i in xrange(alo, ahi):
1156 for i in xrange(alo, ahi):
1157 yield ('-', a[i])
1157 yield ('-', a[i])
1158 for i in xrange(blo, bhi):
1158 for i in xrange(blo, bhi):
1159 yield ('+', b[i])
1159 yield ('+', b[i])
1160
1160
1161 prev = {}
1161 prev = {}
1162 def display(fn, rev, states, prevstates):
1162 def display(fn, rev, states, prevstates):
1163 found = False
1163 found = False
1164 filerevmatches = {}
1164 filerevmatches = {}
1165 r = prev.get(fn, -1)
1165 r = prev.get(fn, -1)
1166 if opts['all']:
1166 if opts['all']:
1167 iter = difflinestates(states, prevstates)
1167 iter = difflinestates(states, prevstates)
1168 else:
1168 else:
1169 iter = [('', l) for l in prevstates]
1169 iter = [('', l) for l in prevstates]
1170 for change, l in iter:
1170 for change, l in iter:
1171 cols = [fn, str(r)]
1171 cols = [fn, str(r)]
1172 if opts['line_number']:
1172 if opts['line_number']:
1173 cols.append(str(l.linenum))
1173 cols.append(str(l.linenum))
1174 if opts['all']:
1174 if opts['all']:
1175 cols.append(change)
1175 cols.append(change)
1176 if opts['user']:
1176 if opts['user']:
1177 cols.append(ui.shortuser(get(r)[1]))
1177 cols.append(ui.shortuser(get(r)[1]))
1178 if opts['files_with_matches']:
1178 if opts['files_with_matches']:
1179 c = (fn, r)
1179 c = (fn, r)
1180 if c in filerevmatches:
1180 if c in filerevmatches:
1181 continue
1181 continue
1182 filerevmatches[c] = 1
1182 filerevmatches[c] = 1
1183 else:
1183 else:
1184 cols.append(l.line)
1184 cols.append(l.line)
1185 ui.write(sep.join(cols), eol)
1185 ui.write(sep.join(cols), eol)
1186 found = True
1186 found = True
1187 return found
1187 return found
1188
1188
1189 fstate = {}
1189 fstate = {}
1190 skip = {}
1190 skip = {}
1191 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1191 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1192 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1192 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1193 found = False
1193 found = False
1194 follow = opts.get('follow')
1194 follow = opts.get('follow')
1195 for st, rev, fns in changeiter:
1195 for st, rev, fns in changeiter:
1196 if st == 'window':
1196 if st == 'window':
1197 matches.clear()
1197 matches.clear()
1198 elif st == 'add':
1198 elif st == 'add':
1199 mf = repo.changectx(rev).manifest()
1199 mf = repo.changectx(rev).manifest()
1200 matches[rev] = {}
1200 matches[rev] = {}
1201 for fn in fns:
1201 for fn in fns:
1202 if fn in skip:
1202 if fn in skip:
1203 continue
1203 continue
1204 fstate.setdefault(fn, {})
1204 fstate.setdefault(fn, {})
1205 try:
1205 try:
1206 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1206 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1207 if follow:
1207 if follow:
1208 copied = getfile(fn).renamed(mf[fn])
1208 copied = getfile(fn).renamed(mf[fn])
1209 if copied:
1209 if copied:
1210 copies.setdefault(rev, {})[fn] = copied[0]
1210 copies.setdefault(rev, {})[fn] = copied[0]
1211 except KeyError:
1211 except KeyError:
1212 pass
1212 pass
1213 elif st == 'iter':
1213 elif st == 'iter':
1214 states = matches[rev].items()
1214 states = matches[rev].items()
1215 states.sort()
1215 states.sort()
1216 for fn, m in states:
1216 for fn, m in states:
1217 copy = copies.get(rev, {}).get(fn)
1217 copy = copies.get(rev, {}).get(fn)
1218 if fn in skip:
1218 if fn in skip:
1219 if copy:
1219 if copy:
1220 skip[copy] = True
1220 skip[copy] = True
1221 continue
1221 continue
1222 if fn in prev or fstate[fn]:
1222 if fn in prev or fstate[fn]:
1223 r = display(fn, rev, m, fstate[fn])
1223 r = display(fn, rev, m, fstate[fn])
1224 found = found or r
1224 found = found or r
1225 if r and not opts['all']:
1225 if r and not opts['all']:
1226 skip[fn] = True
1226 skip[fn] = True
1227 if copy:
1227 if copy:
1228 skip[copy] = True
1228 skip[copy] = True
1229 fstate[fn] = m
1229 fstate[fn] = m
1230 if copy:
1230 if copy:
1231 fstate[copy] = m
1231 fstate[copy] = m
1232 prev[fn] = rev
1232 prev[fn] = rev
1233
1233
1234 fstate = fstate.items()
1234 fstate = fstate.items()
1235 fstate.sort()
1235 fstate.sort()
1236 for fn, state in fstate:
1236 for fn, state in fstate:
1237 if fn in skip:
1237 if fn in skip:
1238 continue
1238 continue
1239 if fn not in copies.get(prev[fn], {}):
1239 if fn not in copies.get(prev[fn], {}):
1240 found = display(fn, rev, {}, state) or found
1240 found = display(fn, rev, {}, state) or found
1241 return (not found and 1) or 0
1241 return (not found and 1) or 0
1242
1242
1243 def heads(ui, repo, **opts):
1243 def heads(ui, repo, **opts):
1244 """show current repository heads
1244 """show current repository heads
1245
1245
1246 Show all repository head changesets.
1246 Show all repository head changesets.
1247
1247
1248 Repository "heads" are changesets that don't have children
1248 Repository "heads" are changesets that don't have children
1249 changesets. They are where development generally takes place and
1249 changesets. They are where development generally takes place and
1250 are the usual targets for update and merge operations.
1250 are the usual targets for update and merge operations.
1251 """
1251 """
1252 if opts['rev']:
1252 if opts['rev']:
1253 heads = repo.heads(repo.lookup(opts['rev']))
1253 heads = repo.heads(repo.lookup(opts['rev']))
1254 else:
1254 else:
1255 heads = repo.heads()
1255 heads = repo.heads()
1256 displayer = cmdutil.show_changeset(ui, repo, opts)
1256 displayer = cmdutil.show_changeset(ui, repo, opts)
1257 for n in heads:
1257 for n in heads:
1258 displayer.show(changenode=n)
1258 displayer.show(changenode=n)
1259
1259
1260 def help_(ui, name=None, with_version=False):
1260 def help_(ui, name=None, with_version=False):
1261 """show help for a command, extension, or list of commands
1261 """show help for a command, extension, or list of commands
1262
1262
1263 With no arguments, print a list of commands and short help.
1263 With no arguments, print a list of commands and short help.
1264
1264
1265 Given a command name, print help for that command.
1265 Given a command name, print help for that command.
1266
1266
1267 Given an extension name, print help for that extension, and the
1267 Given an extension name, print help for that extension, and the
1268 commands it provides."""
1268 commands it provides."""
1269 option_lists = []
1269 option_lists = []
1270
1270
1271 def helpcmd(name):
1271 def helpcmd(name):
1272 if with_version:
1272 if with_version:
1273 version_(ui)
1273 version_(ui)
1274 ui.write('\n')
1274 ui.write('\n')
1275 aliases, i = findcmd(ui, name)
1275 aliases, i = findcmd(ui, name)
1276 # synopsis
1276 # synopsis
1277 ui.write("%s\n\n" % i[2])
1277 ui.write("%s\n\n" % i[2])
1278
1278
1279 # description
1279 # description
1280 doc = i[0].__doc__
1280 doc = i[0].__doc__
1281 if not doc:
1281 if not doc:
1282 doc = _("(No help text available)")
1282 doc = _("(No help text available)")
1283 if ui.quiet:
1283 if ui.quiet:
1284 doc = doc.splitlines(0)[0]
1284 doc = doc.splitlines(0)[0]
1285 ui.write("%s\n" % doc.rstrip())
1285 ui.write("%s\n" % doc.rstrip())
1286
1286
1287 if not ui.quiet:
1287 if not ui.quiet:
1288 # aliases
1288 # aliases
1289 if len(aliases) > 1:
1289 if len(aliases) > 1:
1290 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1290 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1291
1291
1292 # options
1292 # options
1293 if i[1]:
1293 if i[1]:
1294 option_lists.append(("options", i[1]))
1294 option_lists.append(("options", i[1]))
1295
1295
1296 def helplist(select=None):
1296 def helplist(select=None):
1297 h = {}
1297 h = {}
1298 cmds = {}
1298 cmds = {}
1299 for c, e in table.items():
1299 for c, e in table.items():
1300 f = c.split("|", 1)[0]
1300 f = c.split("|", 1)[0]
1301 if select and not select(f):
1301 if select and not select(f):
1302 continue
1302 continue
1303 if name == "shortlist" and not f.startswith("^"):
1303 if name == "shortlist" and not f.startswith("^"):
1304 continue
1304 continue
1305 f = f.lstrip("^")
1305 f = f.lstrip("^")
1306 if not ui.debugflag and f.startswith("debug"):
1306 if not ui.debugflag and f.startswith("debug"):
1307 continue
1307 continue
1308 doc = e[0].__doc__
1308 doc = e[0].__doc__
1309 if not doc:
1309 if not doc:
1310 doc = _("(No help text available)")
1310 doc = _("(No help text available)")
1311 h[f] = doc.splitlines(0)[0].rstrip()
1311 h[f] = doc.splitlines(0)[0].rstrip()
1312 cmds[f] = c.lstrip("^")
1312 cmds[f] = c.lstrip("^")
1313
1313
1314 fns = h.keys()
1314 fns = h.keys()
1315 fns.sort()
1315 fns.sort()
1316 m = max(map(len, fns))
1316 m = max(map(len, fns))
1317 for f in fns:
1317 for f in fns:
1318 if ui.verbose:
1318 if ui.verbose:
1319 commands = cmds[f].replace("|",", ")
1319 commands = cmds[f].replace("|",", ")
1320 ui.write(" %s:\n %s\n"%(commands, h[f]))
1320 ui.write(" %s:\n %s\n"%(commands, h[f]))
1321 else:
1321 else:
1322 ui.write(' %-*s %s\n' % (m, f, h[f]))
1322 ui.write(' %-*s %s\n' % (m, f, h[f]))
1323
1323
1324 def helptopic(name):
1324 def helptopic(name):
1325 v = None
1325 v = None
1326 for i in help.helptable:
1326 for i in help.helptable:
1327 l = i.split('|')
1327 l = i.split('|')
1328 if name in l:
1328 if name in l:
1329 v = i
1329 v = i
1330 header = l[-1]
1330 header = l[-1]
1331 if not v:
1331 if not v:
1332 raise UnknownCommand(name)
1332 raise UnknownCommand(name)
1333
1333
1334 # description
1334 # description
1335 doc = help.helptable[v]
1335 doc = help.helptable[v]
1336 if not doc:
1336 if not doc:
1337 doc = _("(No help text available)")
1337 doc = _("(No help text available)")
1338 if callable(doc):
1338 if callable(doc):
1339 doc = doc()
1339 doc = doc()
1340
1340
1341 ui.write("%s\n" % header)
1341 ui.write("%s\n" % header)
1342 ui.write("%s\n" % doc.rstrip())
1342 ui.write("%s\n" % doc.rstrip())
1343
1343
1344 def helpext(name):
1344 def helpext(name):
1345 try:
1345 try:
1346 mod = findext(name)
1346 mod = findext(name)
1347 except KeyError:
1347 except KeyError:
1348 raise UnknownCommand(name)
1348 raise UnknownCommand(name)
1349
1349
1350 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1350 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1351 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1351 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1352 for d in doc[1:]:
1352 for d in doc[1:]:
1353 ui.write(d, '\n')
1353 ui.write(d, '\n')
1354
1354
1355 ui.status('\n')
1355 ui.status('\n')
1356
1356
1357 try:
1357 try:
1358 ct = mod.cmdtable
1358 ct = mod.cmdtable
1359 except AttributeError:
1359 except AttributeError:
1360 ui.status(_('no commands defined\n'))
1360 ui.status(_('no commands defined\n'))
1361 return
1361 return
1362
1362
1363 if ui.verbose:
1363 if ui.verbose:
1364 ui.status(_('list of commands:\n\n'))
1364 ui.status(_('list of commands:\n\n'))
1365 else:
1365 else:
1366 ui.status(_('list of commands (use "hg help -v %s" '
1366 ui.status(_('list of commands (use "hg help -v %s" '
1367 'to show aliases and global options):\n\n') % name)
1367 'to show aliases and global options):\n\n') % name)
1368
1368
1369 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1369 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1370 helplist(modcmds.has_key)
1370 helplist(modcmds.has_key)
1371
1371
1372 if name and name != 'shortlist':
1372 if name and name != 'shortlist':
1373 i = None
1373 i = None
1374 for f in (helpcmd, helptopic, helpext):
1374 for f in (helpcmd, helptopic, helpext):
1375 try:
1375 try:
1376 f(name)
1376 f(name)
1377 i = None
1377 i = None
1378 break
1378 break
1379 except UnknownCommand, inst:
1379 except UnknownCommand, inst:
1380 i = inst
1380 i = inst
1381 if i:
1381 if i:
1382 raise i
1382 raise i
1383
1383
1384 else:
1384 else:
1385 # program name
1385 # program name
1386 if ui.verbose or with_version:
1386 if ui.verbose or with_version:
1387 version_(ui)
1387 version_(ui)
1388 else:
1388 else:
1389 ui.status(_("Mercurial Distributed SCM\n"))
1389 ui.status(_("Mercurial Distributed SCM\n"))
1390 ui.status('\n')
1390 ui.status('\n')
1391
1391
1392 # list of commands
1392 # list of commands
1393 if name == "shortlist":
1393 if name == "shortlist":
1394 ui.status(_('basic commands (use "hg help" '
1394 ui.status(_('basic commands (use "hg help" '
1395 'for the full list or option "-v" for details):\n\n'))
1395 'for the full list or option "-v" for details):\n\n'))
1396 elif ui.verbose:
1396 elif ui.verbose:
1397 ui.status(_('list of commands:\n\n'))
1397 ui.status(_('list of commands:\n\n'))
1398 else:
1398 else:
1399 ui.status(_('list of commands (use "hg help -v" '
1399 ui.status(_('list of commands (use "hg help -v" '
1400 'to show aliases and global options):\n\n'))
1400 'to show aliases and global options):\n\n'))
1401
1401
1402 helplist()
1402 helplist()
1403
1403
1404 # global options
1404 # global options
1405 if ui.verbose:
1405 if ui.verbose:
1406 option_lists.append(("global options", globalopts))
1406 option_lists.append(("global options", globalopts))
1407
1407
1408 # list all option lists
1408 # list all option lists
1409 opt_output = []
1409 opt_output = []
1410 for title, options in option_lists:
1410 for title, options in option_lists:
1411 opt_output.append(("\n%s:\n" % title, None))
1411 opt_output.append(("\n%s:\n" % title, None))
1412 for shortopt, longopt, default, desc in options:
1412 for shortopt, longopt, default, desc in options:
1413 if "DEPRECATED" in desc and not ui.verbose: continue
1413 if "DEPRECATED" in desc and not ui.verbose: continue
1414 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1414 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1415 longopt and " --%s" % longopt),
1415 longopt and " --%s" % longopt),
1416 "%s%s" % (desc,
1416 "%s%s" % (desc,
1417 default
1417 default
1418 and _(" (default: %s)") % default
1418 and _(" (default: %s)") % default
1419 or "")))
1419 or "")))
1420
1420
1421 if opt_output:
1421 if opt_output:
1422 opts_len = max([len(line[0]) for line in opt_output if line[1]])
1422 opts_len = max([len(line[0]) for line in opt_output if line[1]])
1423 for first, second in opt_output:
1423 for first, second in opt_output:
1424 if second:
1424 if second:
1425 ui.write(" %-*s %s\n" % (opts_len, first, second))
1425 ui.write(" %-*s %s\n" % (opts_len, first, second))
1426 else:
1426 else:
1427 ui.write("%s\n" % first)
1427 ui.write("%s\n" % first)
1428
1428
1429 def identify(ui, repo):
1429 def identify(ui, repo):
1430 """print information about the working copy
1430 """print information about the working copy
1431
1431
1432 Print a short summary of the current state of the repo.
1432 Print a short summary of the current state of the repo.
1433
1433
1434 This summary identifies the repository state using one or two parent
1434 This summary identifies the repository state using one or two parent
1435 hash identifiers, followed by a "+" if there are uncommitted changes
1435 hash identifiers, followed by a "+" if there are uncommitted changes
1436 in the working directory, followed by a list of tags for this revision.
1436 in the working directory, followed by a list of tags for this revision.
1437 """
1437 """
1438 parents = [p for p in repo.dirstate.parents() if p != nullid]
1438 parents = [p for p in repo.dirstate.parents() if p != nullid]
1439 if not parents:
1439 if not parents:
1440 ui.write(_("unknown\n"))
1440 ui.write(_("unknown\n"))
1441 return
1441 return
1442
1442
1443 hexfunc = ui.debugflag and hex or short
1443 hexfunc = ui.debugflag and hex or short
1444 modified, added, removed, deleted = repo.status()[:4]
1444 modified, added, removed, deleted = repo.status()[:4]
1445 output = ["%s%s" %
1445 output = ["%s%s" %
1446 ('+'.join([hexfunc(parent) for parent in parents]),
1446 ('+'.join([hexfunc(parent) for parent in parents]),
1447 (modified or added or removed or deleted) and "+" or "")]
1447 (modified or added or removed or deleted) and "+" or "")]
1448
1448
1449 if not ui.quiet:
1449 if not ui.quiet:
1450
1450
1451 branch = util.tolocal(repo.workingctx().branch())
1451 branch = util.tolocal(repo.workingctx().branch())
1452 if branch != 'default':
1452 if branch != 'default':
1453 output.append("(%s)" % branch)
1453 output.append("(%s)" % branch)
1454
1454
1455 # multiple tags for a single parent separated by '/'
1455 # multiple tags for a single parent separated by '/'
1456 parenttags = ['/'.join(tags)
1456 parenttags = ['/'.join(tags)
1457 for tags in map(repo.nodetags, parents) if tags]
1457 for tags in map(repo.nodetags, parents) if tags]
1458 # tags for multiple parents separated by ' + '
1458 # tags for multiple parents separated by ' + '
1459 if parenttags:
1459 if parenttags:
1460 output.append(' + '.join(parenttags))
1460 output.append(' + '.join(parenttags))
1461
1461
1462 ui.write("%s\n" % ' '.join(output))
1462 ui.write("%s\n" % ' '.join(output))
1463
1463
1464 def import_(ui, repo, patch1, *patches, **opts):
1464 def import_(ui, repo, patch1, *patches, **opts):
1465 """import an ordered set of patches
1465 """import an ordered set of patches
1466
1466
1467 Import a list of patches and commit them individually.
1467 Import a list of patches and commit them individually.
1468
1468
1469 If there are outstanding changes in the working directory, import
1469 If there are outstanding changes in the working directory, import
1470 will abort unless given the -f flag.
1470 will abort unless given the -f flag.
1471
1471
1472 You can import a patch straight from a mail message. Even patches
1472 You can import a patch straight from a mail message. Even patches
1473 as attachments work (body part must be type text/plain or
1473 as attachments work (body part must be type text/plain or
1474 text/x-patch to be used). From and Subject headers of email
1474 text/x-patch to be used). From and Subject headers of email
1475 message are used as default committer and commit message. All
1475 message are used as default committer and commit message. All
1476 text/plain body parts before first diff are added to commit
1476 text/plain body parts before first diff are added to commit
1477 message.
1477 message.
1478
1478
1479 If the imported patch was generated by hg export, user and description
1479 If the imported patch was generated by hg export, user and description
1480 from patch override values from message headers and body. Values
1480 from patch override values from message headers and body. Values
1481 given on command line with -m and -u override these.
1481 given on command line with -m and -u override these.
1482
1482
1483 If --exact is specified, import will set the working directory
1483 If --exact is specified, import will set the working directory
1484 to the parent of each patch before applying it, and will abort
1484 to the parent of each patch before applying it, and will abort
1485 if the resulting changeset has a different ID than the one
1485 if the resulting changeset has a different ID than the one
1486 recorded in the patch. This may happen due to character set
1486 recorded in the patch. This may happen due to character set
1487 problems or other deficiencies in the text patch format.
1487 problems or other deficiencies in the text patch format.
1488
1488
1489 To read a patch from standard input, use patch name "-".
1489 To read a patch from standard input, use patch name "-".
1490 """
1490 """
1491 patches = (patch1,) + patches
1491 patches = (patch1,) + patches
1492
1492
1493 if opts.get('exact') or not opts['force']:
1493 if opts.get('exact') or not opts['force']:
1494 bail_if_changed(repo)
1494 bail_if_changed(repo)
1495
1495
1496 d = opts["base"]
1496 d = opts["base"]
1497 strip = opts["strip"]
1497 strip = opts["strip"]
1498
1498
1499 wlock = repo.wlock()
1499 wlock = repo.wlock()
1500 lock = repo.lock()
1500 lock = repo.lock()
1501
1501
1502 for p in patches:
1502 for p in patches:
1503 pf = os.path.join(d, p)
1503 pf = os.path.join(d, p)
1504
1504
1505 if pf == '-':
1505 if pf == '-':
1506 ui.status(_("applying patch from stdin\n"))
1506 ui.status(_("applying patch from stdin\n"))
1507 tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
1507 tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
1508 else:
1508 else:
1509 ui.status(_("applying %s\n") % p)
1509 ui.status(_("applying %s\n") % p)
1510 tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, file(pf))
1510 tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, file(pf))
1511
1511
1512 if tmpname is None:
1512 if tmpname is None:
1513 raise util.Abort(_('no diffs found'))
1513 raise util.Abort(_('no diffs found'))
1514
1514
1515 try:
1515 try:
1516 cmdline_message = logmessage(opts)
1516 cmdline_message = logmessage(opts)
1517 if cmdline_message:
1517 if cmdline_message:
1518 # pickup the cmdline msg
1518 # pickup the cmdline msg
1519 message = cmdline_message
1519 message = cmdline_message
1520 elif message:
1520 elif message:
1521 # pickup the patch msg
1521 # pickup the patch msg
1522 message = message.strip()
1522 message = message.strip()
1523 else:
1523 else:
1524 # launch the editor
1524 # launch the editor
1525 message = None
1525 message = None
1526 ui.debug(_('message:\n%s\n') % message)
1526 ui.debug(_('message:\n%s\n') % message)
1527
1527
1528 wp = repo.workingctx().parents()
1528 wp = repo.workingctx().parents()
1529 if opts.get('exact'):
1529 if opts.get('exact'):
1530 if not nodeid or not p1:
1530 if not nodeid or not p1:
1531 raise util.Abort(_('not a mercurial patch'))
1531 raise util.Abort(_('not a mercurial patch'))
1532 p1 = repo.lookup(p1)
1532 p1 = repo.lookup(p1)
1533 p2 = repo.lookup(p2 or hex(nullid))
1533 p2 = repo.lookup(p2 or hex(nullid))
1534
1534
1535 if p1 != wp[0].node():
1535 if p1 != wp[0].node():
1536 hg.clean(repo, p1, wlock=wlock)
1536 hg.clean(repo, p1, wlock=wlock)
1537 repo.dirstate.setparents(p1, p2)
1537 repo.dirstate.setparents(p1, p2)
1538 elif p2:
1538 elif p2:
1539 try:
1539 try:
1540 p1 = repo.lookup(p1)
1540 p1 = repo.lookup(p1)
1541 p2 = repo.lookup(p2)
1541 p2 = repo.lookup(p2)
1542 if p1 == wp[0].node():
1542 if p1 == wp[0].node():
1543 repo.dirstate.setparents(p1, p2)
1543 repo.dirstate.setparents(p1, p2)
1544 except RepoError:
1544 except RepoError:
1545 pass
1545 pass
1546
1546
1547 files = {}
1547 files = {}
1548 try:
1548 try:
1549 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1549 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1550 files=files)
1550 files=files)
1551 finally:
1551 finally:
1552 files = patch.updatedir(ui, repo, files, wlock=wlock)
1552 files = patch.updatedir(ui, repo, files, wlock=wlock)
1553 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1553 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1554 if opts.get('exact'):
1554 if opts.get('exact'):
1555 if hex(n) != nodeid:
1555 if hex(n) != nodeid:
1556 repo.rollback()
1556 repo.rollback()
1557 raise util.Abort(_('patch is damaged or loses information'))
1557 raise util.Abort(_('patch is damaged or loses information'))
1558 finally:
1558 finally:
1559 os.unlink(tmpname)
1559 os.unlink(tmpname)
1560
1560
1561 def incoming(ui, repo, source="default", **opts):
1561 def incoming(ui, repo, source="default", **opts):
1562 """show new changesets found in source
1562 """show new changesets found in source
1563
1563
1564 Show new changesets found in the specified path/URL or the default
1564 Show new changesets found in the specified path/URL or the default
1565 pull location. These are the changesets that would be pulled if a pull
1565 pull location. These are the changesets that would be pulled if a pull
1566 was requested.
1566 was requested.
1567
1567
1568 For remote repository, using --bundle avoids downloading the changesets
1568 For remote repository, using --bundle avoids downloading the changesets
1569 twice if the incoming is followed by a pull.
1569 twice if the incoming is followed by a pull.
1570
1570
1571 See pull for valid source format details.
1571 See pull for valid source format details.
1572 """
1572 """
1573 source = ui.expandpath(source)
1573 source = ui.expandpath(source)
1574 setremoteconfig(ui, opts)
1574 setremoteconfig(ui, opts)
1575
1575
1576 other = hg.repository(ui, source)
1576 other = hg.repository(ui, source)
1577 ui.status(_('comparing with %s\n') % source)
1577 ui.status(_('comparing with %s\n') % source)
1578 incoming = repo.findincoming(other, force=opts["force"])
1578 incoming = repo.findincoming(other, force=opts["force"])
1579 if not incoming:
1579 if not incoming:
1580 try:
1580 try:
1581 os.unlink(opts["bundle"])
1581 os.unlink(opts["bundle"])
1582 except:
1582 except:
1583 pass
1583 pass
1584 ui.status(_("no changes found\n"))
1584 ui.status(_("no changes found\n"))
1585 return 1
1585 return 1
1586
1586
1587 cleanup = None
1587 cleanup = None
1588 try:
1588 try:
1589 fname = opts["bundle"]
1589 fname = opts["bundle"]
1590 if fname or not other.local():
1590 if fname or not other.local():
1591 # create a bundle (uncompressed if other repo is not local)
1591 # create a bundle (uncompressed if other repo is not local)
1592 cg = other.changegroup(incoming, "incoming")
1592 cg = other.changegroup(incoming, "incoming")
1593 bundletype = other.local() and "HG10BZ" or "HG10UN"
1593 bundletype = other.local() and "HG10BZ" or "HG10UN"
1594 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1594 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1595 # keep written bundle?
1595 # keep written bundle?
1596 if opts["bundle"]:
1596 if opts["bundle"]:
1597 cleanup = None
1597 cleanup = None
1598 if not other.local():
1598 if not other.local():
1599 # use the created uncompressed bundlerepo
1599 # use the created uncompressed bundlerepo
1600 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1600 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1601
1601
1602 revs = None
1602 revs = None
1603 if opts['rev']:
1603 if opts['rev']:
1604 revs = [other.lookup(rev) for rev in opts['rev']]
1604 revs = [other.lookup(rev) for rev in opts['rev']]
1605 o = other.changelog.nodesbetween(incoming, revs)[0]
1605 o = other.changelog.nodesbetween(incoming, revs)[0]
1606 if opts['newest_first']:
1606 if opts['newest_first']:
1607 o.reverse()
1607 o.reverse()
1608 displayer = cmdutil.show_changeset(ui, other, opts)
1608 displayer = cmdutil.show_changeset(ui, other, opts)
1609 for n in o:
1609 for n in o:
1610 parents = [p for p in other.changelog.parents(n) if p != nullid]
1610 parents = [p for p in other.changelog.parents(n) if p != nullid]
1611 if opts['no_merges'] and len(parents) == 2:
1611 if opts['no_merges'] and len(parents) == 2:
1612 continue
1612 continue
1613 displayer.show(changenode=n)
1613 displayer.show(changenode=n)
1614 finally:
1614 finally:
1615 if hasattr(other, 'close'):
1615 if hasattr(other, 'close'):
1616 other.close()
1616 other.close()
1617 if cleanup:
1617 if cleanup:
1618 os.unlink(cleanup)
1618 os.unlink(cleanup)
1619
1619
1620 def init(ui, dest=".", **opts):
1620 def init(ui, dest=".", **opts):
1621 """create a new repository in the given directory
1621 """create a new repository in the given directory
1622
1622
1623 Initialize a new repository in the given directory. If the given
1623 Initialize a new repository in the given directory. If the given
1624 directory does not exist, it is created.
1624 directory does not exist, it is created.
1625
1625
1626 If no directory is given, the current directory is used.
1626 If no directory is given, the current directory is used.
1627
1627
1628 It is possible to specify an ssh:// URL as the destination.
1628 It is possible to specify an ssh:// URL as the destination.
1629 Look at the help text for the pull command for important details
1629 Look at the help text for the pull command for important details
1630 about ssh:// URLs.
1630 about ssh:// URLs.
1631 """
1631 """
1632 setremoteconfig(ui, opts)
1632 setremoteconfig(ui, opts)
1633 hg.repository(ui, dest, create=1)
1633 hg.repository(ui, dest, create=1)
1634
1634
1635 def locate(ui, repo, *pats, **opts):
1635 def locate(ui, repo, *pats, **opts):
1636 """locate files matching specific patterns
1636 """locate files matching specific patterns
1637
1637
1638 Print all files under Mercurial control whose names match the
1638 Print all files under Mercurial control whose names match the
1639 given patterns.
1639 given patterns.
1640
1640
1641 This command searches the entire repository by default. To search
1641 This command searches the entire repository by default. To search
1642 just the current directory and its subdirectories, use "--include .".
1642 just the current directory and its subdirectories, use "--include .".
1643
1643
1644 If no patterns are given to match, this command prints all file
1644 If no patterns are given to match, this command prints all file
1645 names.
1645 names.
1646
1646
1647 If you want to feed the output of this command into the "xargs"
1647 If you want to feed the output of this command into the "xargs"
1648 command, use the "-0" option to both this command and "xargs".
1648 command, use the "-0" option to both this command and "xargs".
1649 This will avoid the problem of "xargs" treating single filenames
1649 This will avoid the problem of "xargs" treating single filenames
1650 that contain white space as multiple filenames.
1650 that contain white space as multiple filenames.
1651 """
1651 """
1652 end = opts['print0'] and '\0' or '\n'
1652 end = opts['print0'] and '\0' or '\n'
1653 rev = opts['rev']
1653 rev = opts['rev']
1654 if rev:
1654 if rev:
1655 node = repo.lookup(rev)
1655 node = repo.lookup(rev)
1656 else:
1656 else:
1657 node = None
1657 node = None
1658
1658
1659 ret = 1
1659 ret = 1
1660 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1660 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1661 badmatch=util.always,
1661 default='relglob'):
1662 default='relglob'):
1663 if src == 'b':
1664 continue
1662 if not node and repo.dirstate.state(abs) == '?':
1665 if not node and repo.dirstate.state(abs) == '?':
1663 continue
1666 continue
1664 if opts['fullpath']:
1667 if opts['fullpath']:
1665 ui.write(os.path.join(repo.root, abs), end)
1668 ui.write(os.path.join(repo.root, abs), end)
1666 else:
1669 else:
1667 ui.write(((pats and rel) or abs), end)
1670 ui.write(((pats and rel) or abs), end)
1668 ret = 0
1671 ret = 0
1669
1672
1670 return ret
1673 return ret
1671
1674
1672 def log(ui, repo, *pats, **opts):
1675 def log(ui, repo, *pats, **opts):
1673 """show revision history of entire repository or files
1676 """show revision history of entire repository or files
1674
1677
1675 Print the revision history of the specified files or the entire
1678 Print the revision history of the specified files or the entire
1676 project.
1679 project.
1677
1680
1678 File history is shown without following rename or copy history of
1681 File history is shown without following rename or copy history of
1679 files. Use -f/--follow with a file name to follow history across
1682 files. Use -f/--follow with a file name to follow history across
1680 renames and copies. --follow without a file name will only show
1683 renames and copies. --follow without a file name will only show
1681 ancestors or descendants of the starting revision. --follow-first
1684 ancestors or descendants of the starting revision. --follow-first
1682 only follows the first parent of merge revisions.
1685 only follows the first parent of merge revisions.
1683
1686
1684 If no revision range is specified, the default is tip:0 unless
1687 If no revision range is specified, the default is tip:0 unless
1685 --follow is set, in which case the working directory parent is
1688 --follow is set, in which case the working directory parent is
1686 used as the starting revision.
1689 used as the starting revision.
1687
1690
1688 By default this command outputs: changeset id and hash, tags,
1691 By default this command outputs: changeset id and hash, tags,
1689 non-trivial parents, user, date and time, and a summary for each
1692 non-trivial parents, user, date and time, and a summary for each
1690 commit. When the -v/--verbose switch is used, the list of changed
1693 commit. When the -v/--verbose switch is used, the list of changed
1691 files and full commit message is shown.
1694 files and full commit message is shown.
1692
1695
1693 NOTE: log -p may generate unexpected diff output for merge
1696 NOTE: log -p may generate unexpected diff output for merge
1694 changesets, as it will compare the merge changeset against its
1697 changesets, as it will compare the merge changeset against its
1695 first parent only. Also, the files: list will only reflect files
1698 first parent only. Also, the files: list will only reflect files
1696 that are different from BOTH parents.
1699 that are different from BOTH parents.
1697
1700
1698 """
1701 """
1699
1702
1700 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1703 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1701 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1704 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1702
1705
1703 if opts['limit']:
1706 if opts['limit']:
1704 try:
1707 try:
1705 limit = int(opts['limit'])
1708 limit = int(opts['limit'])
1706 except ValueError:
1709 except ValueError:
1707 raise util.Abort(_('limit must be a positive integer'))
1710 raise util.Abort(_('limit must be a positive integer'))
1708 if limit <= 0: raise util.Abort(_('limit must be positive'))
1711 if limit <= 0: raise util.Abort(_('limit must be positive'))
1709 else:
1712 else:
1710 limit = sys.maxint
1713 limit = sys.maxint
1711 count = 0
1714 count = 0
1712
1715
1713 if opts['copies'] and opts['rev']:
1716 if opts['copies'] and opts['rev']:
1714 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1717 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1715 else:
1718 else:
1716 endrev = repo.changelog.count()
1719 endrev = repo.changelog.count()
1717 rcache = {}
1720 rcache = {}
1718 ncache = {}
1721 ncache = {}
1719 dcache = []
1722 dcache = []
1720 def getrenamed(fn, rev, man):
1723 def getrenamed(fn, rev, man):
1721 '''looks up all renames for a file (up to endrev) the first
1724 '''looks up all renames for a file (up to endrev) the first
1722 time the file is given. It indexes on the changerev and only
1725 time the file is given. It indexes on the changerev and only
1723 parses the manifest if linkrev != changerev.
1726 parses the manifest if linkrev != changerev.
1724 Returns rename info for fn at changerev rev.'''
1727 Returns rename info for fn at changerev rev.'''
1725 if fn not in rcache:
1728 if fn not in rcache:
1726 rcache[fn] = {}
1729 rcache[fn] = {}
1727 ncache[fn] = {}
1730 ncache[fn] = {}
1728 fl = repo.file(fn)
1731 fl = repo.file(fn)
1729 for i in xrange(fl.count()):
1732 for i in xrange(fl.count()):
1730 node = fl.node(i)
1733 node = fl.node(i)
1731 lr = fl.linkrev(node)
1734 lr = fl.linkrev(node)
1732 renamed = fl.renamed(node)
1735 renamed = fl.renamed(node)
1733 rcache[fn][lr] = renamed
1736 rcache[fn][lr] = renamed
1734 if renamed:
1737 if renamed:
1735 ncache[fn][node] = renamed
1738 ncache[fn][node] = renamed
1736 if lr >= endrev:
1739 if lr >= endrev:
1737 break
1740 break
1738 if rev in rcache[fn]:
1741 if rev in rcache[fn]:
1739 return rcache[fn][rev]
1742 return rcache[fn][rev]
1740 mr = repo.manifest.rev(man)
1743 mr = repo.manifest.rev(man)
1741 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1744 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1742 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1745 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1743 if not dcache or dcache[0] != man:
1746 if not dcache or dcache[0] != man:
1744 dcache[:] = [man, repo.manifest.readdelta(man)]
1747 dcache[:] = [man, repo.manifest.readdelta(man)]
1745 if fn in dcache[1]:
1748 if fn in dcache[1]:
1746 return ncache[fn].get(dcache[1][fn])
1749 return ncache[fn].get(dcache[1][fn])
1747 return None
1750 return None
1748
1751
1749 df = False
1752 df = False
1750 if opts["date"]:
1753 if opts["date"]:
1751 df = util.matchdate(opts["date"])
1754 df = util.matchdate(opts["date"])
1752
1755
1753 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1756 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1754 for st, rev, fns in changeiter:
1757 for st, rev, fns in changeiter:
1755 if st == 'add':
1758 if st == 'add':
1756 changenode = repo.changelog.node(rev)
1759 changenode = repo.changelog.node(rev)
1757 parents = [p for p in repo.changelog.parentrevs(rev)
1760 parents = [p for p in repo.changelog.parentrevs(rev)
1758 if p != nullrev]
1761 if p != nullrev]
1759 if opts['no_merges'] and len(parents) == 2:
1762 if opts['no_merges'] and len(parents) == 2:
1760 continue
1763 continue
1761 if opts['only_merges'] and len(parents) != 2:
1764 if opts['only_merges'] and len(parents) != 2:
1762 continue
1765 continue
1763
1766
1764 if df:
1767 if df:
1765 changes = get(rev)
1768 changes = get(rev)
1766 if not df(changes[2][0]):
1769 if not df(changes[2][0]):
1767 continue
1770 continue
1768
1771
1769 if opts['keyword']:
1772 if opts['keyword']:
1770 changes = get(rev)
1773 changes = get(rev)
1771 miss = 0
1774 miss = 0
1772 for k in [kw.lower() for kw in opts['keyword']]:
1775 for k in [kw.lower() for kw in opts['keyword']]:
1773 if not (k in changes[1].lower() or
1776 if not (k in changes[1].lower() or
1774 k in changes[4].lower() or
1777 k in changes[4].lower() or
1775 k in " ".join(changes[3][:20]).lower()):
1778 k in " ".join(changes[3][:20]).lower()):
1776 miss = 1
1779 miss = 1
1777 break
1780 break
1778 if miss:
1781 if miss:
1779 continue
1782 continue
1780
1783
1781 copies = []
1784 copies = []
1782 if opts.get('copies') and rev:
1785 if opts.get('copies') and rev:
1783 mf = get(rev)[0]
1786 mf = get(rev)[0]
1784 for fn in get(rev)[3]:
1787 for fn in get(rev)[3]:
1785 rename = getrenamed(fn, rev, mf)
1788 rename = getrenamed(fn, rev, mf)
1786 if rename:
1789 if rename:
1787 copies.append((fn, rename[0]))
1790 copies.append((fn, rename[0]))
1788 displayer.show(rev, changenode, copies=copies)
1791 displayer.show(rev, changenode, copies=copies)
1789 elif st == 'iter':
1792 elif st == 'iter':
1790 if count == limit: break
1793 if count == limit: break
1791 if displayer.flush(rev):
1794 if displayer.flush(rev):
1792 count += 1
1795 count += 1
1793
1796
1794 def manifest(ui, repo, rev=None):
1797 def manifest(ui, repo, rev=None):
1795 """output the current or given revision of the project manifest
1798 """output the current or given revision of the project manifest
1796
1799
1797 Print a list of version controlled files for the given revision.
1800 Print a list of version controlled files for the given revision.
1798 If no revision is given, the parent of the working directory is used,
1801 If no revision is given, the parent of the working directory is used,
1799 or tip if no revision is checked out.
1802 or tip if no revision is checked out.
1800
1803
1801 The manifest is the list of files being version controlled. If no revision
1804 The manifest is the list of files being version controlled. If no revision
1802 is given then the first parent of the working directory is used.
1805 is given then the first parent of the working directory is used.
1803
1806
1804 With -v flag, print file permissions. With --debug flag, print
1807 With -v flag, print file permissions. With --debug flag, print
1805 file revision hashes.
1808 file revision hashes.
1806 """
1809 """
1807
1810
1808 m = repo.changectx(rev).manifest()
1811 m = repo.changectx(rev).manifest()
1809 files = m.keys()
1812 files = m.keys()
1810 files.sort()
1813 files.sort()
1811
1814
1812 for f in files:
1815 for f in files:
1813 if ui.debugflag:
1816 if ui.debugflag:
1814 ui.write("%40s " % hex(m[f]))
1817 ui.write("%40s " % hex(m[f]))
1815 if ui.verbose:
1818 if ui.verbose:
1816 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1819 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1817 ui.write("%s\n" % f)
1820 ui.write("%s\n" % f)
1818
1821
1819 def merge(ui, repo, node=None, force=None):
1822 def merge(ui, repo, node=None, force=None):
1820 """merge working directory with another revision
1823 """merge working directory with another revision
1821
1824
1822 Merge the contents of the current working directory and the
1825 Merge the contents of the current working directory and the
1823 requested revision. Files that changed between either parent are
1826 requested revision. Files that changed between either parent are
1824 marked as changed for the next commit and a commit must be
1827 marked as changed for the next commit and a commit must be
1825 performed before any further updates are allowed.
1828 performed before any further updates are allowed.
1826
1829
1827 If no revision is specified, the working directory's parent is a
1830 If no revision is specified, the working directory's parent is a
1828 head revision, and the repository contains exactly one other head,
1831 head revision, and the repository contains exactly one other head,
1829 the other head is merged with by default. Otherwise, an explicit
1832 the other head is merged with by default. Otherwise, an explicit
1830 revision to merge with must be provided.
1833 revision to merge with must be provided.
1831 """
1834 """
1832
1835
1833 if not node:
1836 if not node:
1834 heads = repo.heads()
1837 heads = repo.heads()
1835 if len(heads) > 2:
1838 if len(heads) > 2:
1836 raise util.Abort(_('repo has %d heads - '
1839 raise util.Abort(_('repo has %d heads - '
1837 'please merge with an explicit rev') %
1840 'please merge with an explicit rev') %
1838 len(heads))
1841 len(heads))
1839 if len(heads) == 1:
1842 if len(heads) == 1:
1840 raise util.Abort(_('there is nothing to merge - '
1843 raise util.Abort(_('there is nothing to merge - '
1841 'use "hg update" instead'))
1844 'use "hg update" instead'))
1842 parent = repo.dirstate.parents()[0]
1845 parent = repo.dirstate.parents()[0]
1843 if parent not in heads:
1846 if parent not in heads:
1844 raise util.Abort(_('working dir not at a head rev - '
1847 raise util.Abort(_('working dir not at a head rev - '
1845 'use "hg update" or merge with an explicit rev'))
1848 'use "hg update" or merge with an explicit rev'))
1846 node = parent == heads[0] and heads[-1] or heads[0]
1849 node = parent == heads[0] and heads[-1] or heads[0]
1847 return hg.merge(repo, node, force=force)
1850 return hg.merge(repo, node, force=force)
1848
1851
1849 def outgoing(ui, repo, dest=None, **opts):
1852 def outgoing(ui, repo, dest=None, **opts):
1850 """show changesets not found in destination
1853 """show changesets not found in destination
1851
1854
1852 Show changesets not found in the specified destination repository or
1855 Show changesets not found in the specified destination repository or
1853 the default push location. These are the changesets that would be pushed
1856 the default push location. These are the changesets that would be pushed
1854 if a push was requested.
1857 if a push was requested.
1855
1858
1856 See pull for valid destination format details.
1859 See pull for valid destination format details.
1857 """
1860 """
1858 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1861 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1859 setremoteconfig(ui, opts)
1862 setremoteconfig(ui, opts)
1860 revs = None
1863 revs = None
1861 if opts['rev']:
1864 if opts['rev']:
1862 revs = [repo.lookup(rev) for rev in opts['rev']]
1865 revs = [repo.lookup(rev) for rev in opts['rev']]
1863
1866
1864 other = hg.repository(ui, dest)
1867 other = hg.repository(ui, dest)
1865 ui.status(_('comparing with %s\n') % dest)
1868 ui.status(_('comparing with %s\n') % dest)
1866 o = repo.findoutgoing(other, force=opts['force'])
1869 o = repo.findoutgoing(other, force=opts['force'])
1867 if not o:
1870 if not o:
1868 ui.status(_("no changes found\n"))
1871 ui.status(_("no changes found\n"))
1869 return 1
1872 return 1
1870 o = repo.changelog.nodesbetween(o, revs)[0]
1873 o = repo.changelog.nodesbetween(o, revs)[0]
1871 if opts['newest_first']:
1874 if opts['newest_first']:
1872 o.reverse()
1875 o.reverse()
1873 displayer = cmdutil.show_changeset(ui, repo, opts)
1876 displayer = cmdutil.show_changeset(ui, repo, opts)
1874 for n in o:
1877 for n in o:
1875 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1878 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1876 if opts['no_merges'] and len(parents) == 2:
1879 if opts['no_merges'] and len(parents) == 2:
1877 continue
1880 continue
1878 displayer.show(changenode=n)
1881 displayer.show(changenode=n)
1879
1882
1880 def parents(ui, repo, file_=None, **opts):
1883 def parents(ui, repo, file_=None, **opts):
1881 """show the parents of the working dir or revision
1884 """show the parents of the working dir or revision
1882
1885
1883 Print the working directory's parent revisions.
1886 Print the working directory's parent revisions.
1884 """
1887 """
1885 rev = opts.get('rev')
1888 rev = opts.get('rev')
1886 if rev:
1889 if rev:
1887 if file_:
1890 if file_:
1888 ctx = repo.filectx(file_, changeid=rev)
1891 ctx = repo.filectx(file_, changeid=rev)
1889 else:
1892 else:
1890 ctx = repo.changectx(rev)
1893 ctx = repo.changectx(rev)
1891 p = [cp.node() for cp in ctx.parents()]
1894 p = [cp.node() for cp in ctx.parents()]
1892 else:
1895 else:
1893 p = repo.dirstate.parents()
1896 p = repo.dirstate.parents()
1894
1897
1895 displayer = cmdutil.show_changeset(ui, repo, opts)
1898 displayer = cmdutil.show_changeset(ui, repo, opts)
1896 for n in p:
1899 for n in p:
1897 if n != nullid:
1900 if n != nullid:
1898 displayer.show(changenode=n)
1901 displayer.show(changenode=n)
1899
1902
1900 def paths(ui, repo, search=None):
1903 def paths(ui, repo, search=None):
1901 """show definition of symbolic path names
1904 """show definition of symbolic path names
1902
1905
1903 Show definition of symbolic path name NAME. If no name is given, show
1906 Show definition of symbolic path name NAME. If no name is given, show
1904 definition of available names.
1907 definition of available names.
1905
1908
1906 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1909 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1907 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1910 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1908 """
1911 """
1909 if search:
1912 if search:
1910 for name, path in ui.configitems("paths"):
1913 for name, path in ui.configitems("paths"):
1911 if name == search:
1914 if name == search:
1912 ui.write("%s\n" % path)
1915 ui.write("%s\n" % path)
1913 return
1916 return
1914 ui.warn(_("not found!\n"))
1917 ui.warn(_("not found!\n"))
1915 return 1
1918 return 1
1916 else:
1919 else:
1917 for name, path in ui.configitems("paths"):
1920 for name, path in ui.configitems("paths"):
1918 ui.write("%s = %s\n" % (name, path))
1921 ui.write("%s = %s\n" % (name, path))
1919
1922
1920 def postincoming(ui, repo, modheads, optupdate):
1923 def postincoming(ui, repo, modheads, optupdate):
1921 if modheads == 0:
1924 if modheads == 0:
1922 return
1925 return
1923 if optupdate:
1926 if optupdate:
1924 if modheads == 1:
1927 if modheads == 1:
1925 return hg.update(repo, repo.changelog.tip()) # update
1928 return hg.update(repo, repo.changelog.tip()) # update
1926 else:
1929 else:
1927 ui.status(_("not updating, since new heads added\n"))
1930 ui.status(_("not updating, since new heads added\n"))
1928 if modheads > 1:
1931 if modheads > 1:
1929 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1932 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1930 else:
1933 else:
1931 ui.status(_("(run 'hg update' to get a working copy)\n"))
1934 ui.status(_("(run 'hg update' to get a working copy)\n"))
1932
1935
1933 def pull(ui, repo, source="default", **opts):
1936 def pull(ui, repo, source="default", **opts):
1934 """pull changes from the specified source
1937 """pull changes from the specified source
1935
1938
1936 Pull changes from a remote repository to a local one.
1939 Pull changes from a remote repository to a local one.
1937
1940
1938 This finds all changes from the repository at the specified path
1941 This finds all changes from the repository at the specified path
1939 or URL and adds them to the local repository. By default, this
1942 or URL and adds them to the local repository. By default, this
1940 does not update the copy of the project in the working directory.
1943 does not update the copy of the project in the working directory.
1941
1944
1942 Valid URLs are of the form:
1945 Valid URLs are of the form:
1943
1946
1944 local/filesystem/path (or file://local/filesystem/path)
1947 local/filesystem/path (or file://local/filesystem/path)
1945 http://[user@]host[:port]/[path]
1948 http://[user@]host[:port]/[path]
1946 https://[user@]host[:port]/[path]
1949 https://[user@]host[:port]/[path]
1947 ssh://[user@]host[:port]/[path]
1950 ssh://[user@]host[:port]/[path]
1948 static-http://host[:port]/[path]
1951 static-http://host[:port]/[path]
1949
1952
1950 Paths in the local filesystem can either point to Mercurial
1953 Paths in the local filesystem can either point to Mercurial
1951 repositories or to bundle files (as created by 'hg bundle' or
1954 repositories or to bundle files (as created by 'hg bundle' or
1952 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1955 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1953 allows access to a Mercurial repository where you simply use a web
1956 allows access to a Mercurial repository where you simply use a web
1954 server to publish the .hg directory as static content.
1957 server to publish the .hg directory as static content.
1955
1958
1956 Some notes about using SSH with Mercurial:
1959 Some notes about using SSH with Mercurial:
1957 - SSH requires an accessible shell account on the destination machine
1960 - SSH requires an accessible shell account on the destination machine
1958 and a copy of hg in the remote path or specified with as remotecmd.
1961 and a copy of hg in the remote path or specified with as remotecmd.
1959 - path is relative to the remote user's home directory by default.
1962 - path is relative to the remote user's home directory by default.
1960 Use an extra slash at the start of a path to specify an absolute path:
1963 Use an extra slash at the start of a path to specify an absolute path:
1961 ssh://example.com//tmp/repository
1964 ssh://example.com//tmp/repository
1962 - Mercurial doesn't use its own compression via SSH; the right thing
1965 - Mercurial doesn't use its own compression via SSH; the right thing
1963 to do is to configure it in your ~/.ssh/config, e.g.:
1966 to do is to configure it in your ~/.ssh/config, e.g.:
1964 Host *.mylocalnetwork.example.com
1967 Host *.mylocalnetwork.example.com
1965 Compression no
1968 Compression no
1966 Host *
1969 Host *
1967 Compression yes
1970 Compression yes
1968 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1971 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1969 with the --ssh command line option.
1972 with the --ssh command line option.
1970 """
1973 """
1971 source = ui.expandpath(source)
1974 source = ui.expandpath(source)
1972 setremoteconfig(ui, opts)
1975 setremoteconfig(ui, opts)
1973
1976
1974 other = hg.repository(ui, source)
1977 other = hg.repository(ui, source)
1975 ui.status(_('pulling from %s\n') % (source))
1978 ui.status(_('pulling from %s\n') % (source))
1976 revs = None
1979 revs = None
1977 if opts['rev']:
1980 if opts['rev']:
1978 if 'lookup' in other.capabilities:
1981 if 'lookup' in other.capabilities:
1979 revs = [other.lookup(rev) for rev in opts['rev']]
1982 revs = [other.lookup(rev) for rev in opts['rev']]
1980 else:
1983 else:
1981 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1984 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1982 raise util.Abort(error)
1985 raise util.Abort(error)
1983 modheads = repo.pull(other, heads=revs, force=opts['force'])
1986 modheads = repo.pull(other, heads=revs, force=opts['force'])
1984 return postincoming(ui, repo, modheads, opts['update'])
1987 return postincoming(ui, repo, modheads, opts['update'])
1985
1988
1986 def push(ui, repo, dest=None, **opts):
1989 def push(ui, repo, dest=None, **opts):
1987 """push changes to the specified destination
1990 """push changes to the specified destination
1988
1991
1989 Push changes from the local repository to the given destination.
1992 Push changes from the local repository to the given destination.
1990
1993
1991 This is the symmetrical operation for pull. It helps to move
1994 This is the symmetrical operation for pull. It helps to move
1992 changes from the current repository to a different one. If the
1995 changes from the current repository to a different one. If the
1993 destination is local this is identical to a pull in that directory
1996 destination is local this is identical to a pull in that directory
1994 from the current one.
1997 from the current one.
1995
1998
1996 By default, push will refuse to run if it detects the result would
1999 By default, push will refuse to run if it detects the result would
1997 increase the number of remote heads. This generally indicates the
2000 increase the number of remote heads. This generally indicates the
1998 the client has forgotten to sync and merge before pushing.
2001 the client has forgotten to sync and merge before pushing.
1999
2002
2000 Valid URLs are of the form:
2003 Valid URLs are of the form:
2001
2004
2002 local/filesystem/path (or file://local/filesystem/path)
2005 local/filesystem/path (or file://local/filesystem/path)
2003 ssh://[user@]host[:port]/[path]
2006 ssh://[user@]host[:port]/[path]
2004 http://[user@]host[:port]/[path]
2007 http://[user@]host[:port]/[path]
2005 https://[user@]host[:port]/[path]
2008 https://[user@]host[:port]/[path]
2006
2009
2007 Look at the help text for the pull command for important details
2010 Look at the help text for the pull command for important details
2008 about ssh:// URLs.
2011 about ssh:// URLs.
2009
2012
2010 Pushing to http:// and https:// URLs is only possible, if this
2013 Pushing to http:// and https:// URLs is only possible, if this
2011 feature is explicitly enabled on the remote Mercurial server.
2014 feature is explicitly enabled on the remote Mercurial server.
2012 """
2015 """
2013 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2016 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2014 setremoteconfig(ui, opts)
2017 setremoteconfig(ui, opts)
2015
2018
2016 other = hg.repository(ui, dest)
2019 other = hg.repository(ui, dest)
2017 ui.status('pushing to %s\n' % (dest))
2020 ui.status('pushing to %s\n' % (dest))
2018 revs = None
2021 revs = None
2019 if opts['rev']:
2022 if opts['rev']:
2020 revs = [repo.lookup(rev) for rev in opts['rev']]
2023 revs = [repo.lookup(rev) for rev in opts['rev']]
2021 r = repo.push(other, opts['force'], revs=revs)
2024 r = repo.push(other, opts['force'], revs=revs)
2022 return r == 0
2025 return r == 0
2023
2026
2024 def rawcommit(ui, repo, *pats, **opts):
2027 def rawcommit(ui, repo, *pats, **opts):
2025 """raw commit interface (DEPRECATED)
2028 """raw commit interface (DEPRECATED)
2026
2029
2027 (DEPRECATED)
2030 (DEPRECATED)
2028 Lowlevel commit, for use in helper scripts.
2031 Lowlevel commit, for use in helper scripts.
2029
2032
2030 This command is not intended to be used by normal users, as it is
2033 This command is not intended to be used by normal users, as it is
2031 primarily useful for importing from other SCMs.
2034 primarily useful for importing from other SCMs.
2032
2035
2033 This command is now deprecated and will be removed in a future
2036 This command is now deprecated and will be removed in a future
2034 release, please use debugsetparents and commit instead.
2037 release, please use debugsetparents and commit instead.
2035 """
2038 """
2036
2039
2037 ui.warn(_("(the rawcommit command is deprecated)\n"))
2040 ui.warn(_("(the rawcommit command is deprecated)\n"))
2038
2041
2039 message = logmessage(opts)
2042 message = logmessage(opts)
2040
2043
2041 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2044 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2042 if opts['files']:
2045 if opts['files']:
2043 files += open(opts['files']).read().splitlines()
2046 files += open(opts['files']).read().splitlines()
2044
2047
2045 parents = [repo.lookup(p) for p in opts['parent']]
2048 parents = [repo.lookup(p) for p in opts['parent']]
2046
2049
2047 try:
2050 try:
2048 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2051 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2049 except ValueError, inst:
2052 except ValueError, inst:
2050 raise util.Abort(str(inst))
2053 raise util.Abort(str(inst))
2051
2054
2052 def recover(ui, repo):
2055 def recover(ui, repo):
2053 """roll back an interrupted transaction
2056 """roll back an interrupted transaction
2054
2057
2055 Recover from an interrupted commit or pull.
2058 Recover from an interrupted commit or pull.
2056
2059
2057 This command tries to fix the repository status after an interrupted
2060 This command tries to fix the repository status after an interrupted
2058 operation. It should only be necessary when Mercurial suggests it.
2061 operation. It should only be necessary when Mercurial suggests it.
2059 """
2062 """
2060 if repo.recover():
2063 if repo.recover():
2061 return hg.verify(repo)
2064 return hg.verify(repo)
2062 return 1
2065 return 1
2063
2066
2064 def remove(ui, repo, *pats, **opts):
2067 def remove(ui, repo, *pats, **opts):
2065 """remove the specified files on the next commit
2068 """remove the specified files on the next commit
2066
2069
2067 Schedule the indicated files for removal from the repository.
2070 Schedule the indicated files for removal from the repository.
2068
2071
2069 This only removes files from the current branch, not from the
2072 This only removes files from the current branch, not from the
2070 entire project history. If the files still exist in the working
2073 entire project history. If the files still exist in the working
2071 directory, they will be deleted from it. If invoked with --after,
2074 directory, they will be deleted from it. If invoked with --after,
2072 files that have been manually deleted are marked as removed.
2075 files that have been manually deleted are marked as removed.
2073
2076
2074 This command schedules the files to be removed at the next commit.
2077 This command schedules the files to be removed at the next commit.
2075 To undo a remove before that, see hg revert.
2078 To undo a remove before that, see hg revert.
2076
2079
2077 Modified files and added files are not removed by default. To
2080 Modified files and added files are not removed by default. To
2078 remove them, use the -f/--force option.
2081 remove them, use the -f/--force option.
2079 """
2082 """
2080 names = []
2083 names = []
2081 if not opts['after'] and not pats:
2084 if not opts['after'] and not pats:
2082 raise util.Abort(_('no files specified'))
2085 raise util.Abort(_('no files specified'))
2083 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2086 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2084 exact = dict.fromkeys(files)
2087 exact = dict.fromkeys(files)
2085 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2088 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2086 modified, added, removed, deleted, unknown = mardu
2089 modified, added, removed, deleted, unknown = mardu
2087 remove, forget = [], []
2090 remove, forget = [], []
2088 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2091 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2089 reason = None
2092 reason = None
2090 if abs not in deleted and opts['after']:
2093 if abs not in deleted and opts['after']:
2091 reason = _('is still present')
2094 reason = _('is still present')
2092 elif abs in modified and not opts['force']:
2095 elif abs in modified and not opts['force']:
2093 reason = _('is modified (use -f to force removal)')
2096 reason = _('is modified (use -f to force removal)')
2094 elif abs in added:
2097 elif abs in added:
2095 if opts['force']:
2098 if opts['force']:
2096 forget.append(abs)
2099 forget.append(abs)
2097 continue
2100 continue
2098 reason = _('has been marked for add (use -f to force removal)')
2101 reason = _('has been marked for add (use -f to force removal)')
2099 elif abs in unknown:
2102 elif abs in unknown:
2100 reason = _('is not managed')
2103 reason = _('is not managed')
2101 elif abs in removed:
2104 elif abs in removed:
2102 continue
2105 continue
2103 if reason:
2106 if reason:
2104 if exact:
2107 if exact:
2105 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2108 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2106 else:
2109 else:
2107 if ui.verbose or not exact:
2110 if ui.verbose or not exact:
2108 ui.status(_('removing %s\n') % rel)
2111 ui.status(_('removing %s\n') % rel)
2109 remove.append(abs)
2112 remove.append(abs)
2110 repo.forget(forget)
2113 repo.forget(forget)
2111 repo.remove(remove, unlink=not opts['after'])
2114 repo.remove(remove, unlink=not opts['after'])
2112
2115
2113 def rename(ui, repo, *pats, **opts):
2116 def rename(ui, repo, *pats, **opts):
2114 """rename files; equivalent of copy + remove
2117 """rename files; equivalent of copy + remove
2115
2118
2116 Mark dest as copies of sources; mark sources for deletion. If
2119 Mark dest as copies of sources; mark sources for deletion. If
2117 dest is a directory, copies are put in that directory. If dest is
2120 dest is a directory, copies are put in that directory. If dest is
2118 a file, there can only be one source.
2121 a file, there can only be one source.
2119
2122
2120 By default, this command copies the contents of files as they
2123 By default, this command copies the contents of files as they
2121 stand in the working directory. If invoked with --after, the
2124 stand in the working directory. If invoked with --after, the
2122 operation is recorded, but no copying is performed.
2125 operation is recorded, but no copying is performed.
2123
2126
2124 This command takes effect in the next commit. To undo a rename
2127 This command takes effect in the next commit. To undo a rename
2125 before that, see hg revert.
2128 before that, see hg revert.
2126 """
2129 """
2127 wlock = repo.wlock(0)
2130 wlock = repo.wlock(0)
2128 errs, copied = docopy(ui, repo, pats, opts, wlock)
2131 errs, copied = docopy(ui, repo, pats, opts, wlock)
2129 names = []
2132 names = []
2130 for abs, rel, exact in copied:
2133 for abs, rel, exact in copied:
2131 if ui.verbose or not exact:
2134 if ui.verbose or not exact:
2132 ui.status(_('removing %s\n') % rel)
2135 ui.status(_('removing %s\n') % rel)
2133 names.append(abs)
2136 names.append(abs)
2134 if not opts.get('dry_run'):
2137 if not opts.get('dry_run'):
2135 repo.remove(names, True, wlock)
2138 repo.remove(names, True, wlock)
2136 return errs
2139 return errs
2137
2140
2138 def revert(ui, repo, *pats, **opts):
2141 def revert(ui, repo, *pats, **opts):
2139 """revert files or dirs to their states as of some revision
2142 """revert files or dirs to their states as of some revision
2140
2143
2141 With no revision specified, revert the named files or directories
2144 With no revision specified, revert the named files or directories
2142 to the contents they had in the parent of the working directory.
2145 to the contents they had in the parent of the working directory.
2143 This restores the contents of the affected files to an unmodified
2146 This restores the contents of the affected files to an unmodified
2144 state and unschedules adds, removes, copies, and renames. If the
2147 state and unschedules adds, removes, copies, and renames. If the
2145 working directory has two parents, you must explicitly specify the
2148 working directory has two parents, you must explicitly specify the
2146 revision to revert to.
2149 revision to revert to.
2147
2150
2148 Modified files are saved with a .orig suffix before reverting.
2151 Modified files are saved with a .orig suffix before reverting.
2149 To disable these backups, use --no-backup.
2152 To disable these backups, use --no-backup.
2150
2153
2151 Using the -r option, revert the given files or directories to their
2154 Using the -r option, revert the given files or directories to their
2152 contents as of a specific revision. This can be helpful to "roll
2155 contents as of a specific revision. This can be helpful to "roll
2153 back" some or all of a change that should not have been committed.
2156 back" some or all of a change that should not have been committed.
2154
2157
2155 Revert modifies the working directory. It does not commit any
2158 Revert modifies the working directory. It does not commit any
2156 changes, or change the parent of the working directory. If you
2159 changes, or change the parent of the working directory. If you
2157 revert to a revision other than the parent of the working
2160 revert to a revision other than the parent of the working
2158 directory, the reverted files will thus appear modified
2161 directory, the reverted files will thus appear modified
2159 afterwards.
2162 afterwards.
2160
2163
2161 If a file has been deleted, it is recreated. If the executable
2164 If a file has been deleted, it is recreated. If the executable
2162 mode of a file was changed, it is reset.
2165 mode of a file was changed, it is reset.
2163
2166
2164 If names are given, all files matching the names are reverted.
2167 If names are given, all files matching the names are reverted.
2165
2168
2166 If no arguments are given, no files are reverted.
2169 If no arguments are given, no files are reverted.
2167 """
2170 """
2168
2171
2169 if opts["date"]:
2172 if opts["date"]:
2170 if opts["rev"]:
2173 if opts["rev"]:
2171 raise util.Abort(_("you can't specify a revision and a date"))
2174 raise util.Abort(_("you can't specify a revision and a date"))
2172 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2175 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2173
2176
2174 if not pats and not opts['all']:
2177 if not pats and not opts['all']:
2175 raise util.Abort(_('no files or directories specified; '
2178 raise util.Abort(_('no files or directories specified; '
2176 'use --all to revert the whole repo'))
2179 'use --all to revert the whole repo'))
2177
2180
2178 parent, p2 = repo.dirstate.parents()
2181 parent, p2 = repo.dirstate.parents()
2179 if not opts['rev'] and p2 != nullid:
2182 if not opts['rev'] and p2 != nullid:
2180 raise util.Abort(_('uncommitted merge - please provide a '
2183 raise util.Abort(_('uncommitted merge - please provide a '
2181 'specific revision'))
2184 'specific revision'))
2182 ctx = repo.changectx(opts['rev'])
2185 ctx = repo.changectx(opts['rev'])
2183 node = ctx.node()
2186 node = ctx.node()
2184 mf = ctx.manifest()
2187 mf = ctx.manifest()
2185 if node == parent:
2188 if node == parent:
2186 pmf = mf
2189 pmf = mf
2187 else:
2190 else:
2188 pmf = None
2191 pmf = None
2189
2192
2190 wlock = repo.wlock()
2193 wlock = repo.wlock()
2191
2194
2192 # need all matching names in dirstate and manifest of target rev,
2195 # need all matching names in dirstate and manifest of target rev,
2193 # so have to walk both. do not print errors if files exist in one
2196 # so have to walk both. do not print errors if files exist in one
2194 # but not other.
2197 # but not other.
2195
2198
2196 names = {}
2199 names = {}
2197 target_only = {}
2200 target_only = {}
2198
2201
2199 # walk dirstate.
2202 # walk dirstate.
2200
2203
2201 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2204 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2202 badmatch=mf.has_key):
2205 badmatch=mf.has_key):
2203 names[abs] = (rel, exact)
2206 names[abs] = (rel, exact)
2204 if src == 'b':
2207 if src == 'b':
2205 target_only[abs] = True
2208 target_only[abs] = True
2206
2209
2207 # walk target manifest.
2210 # walk target manifest.
2208
2211
2209 def badmatch(path):
2212 def badmatch(path):
2210 if path in names:
2213 if path in names:
2211 return True
2214 return True
2212 path_ = path + '/'
2215 path_ = path + '/'
2213 for f in names:
2216 for f in names:
2214 if f.startswith(path_):
2217 if f.startswith(path_):
2215 return True
2218 return True
2216 return False
2219 return False
2217
2220
2218 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2221 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2219 badmatch=badmatch):
2222 badmatch=badmatch):
2220 if abs in names or src == 'b':
2223 if abs in names or src == 'b':
2221 continue
2224 continue
2222 names[abs] = (rel, exact)
2225 names[abs] = (rel, exact)
2223 target_only[abs] = True
2226 target_only[abs] = True
2224
2227
2225 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2228 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2226 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2229 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2227
2230
2228 revert = ([], _('reverting %s\n'))
2231 revert = ([], _('reverting %s\n'))
2229 add = ([], _('adding %s\n'))
2232 add = ([], _('adding %s\n'))
2230 remove = ([], _('removing %s\n'))
2233 remove = ([], _('removing %s\n'))
2231 forget = ([], _('forgetting %s\n'))
2234 forget = ([], _('forgetting %s\n'))
2232 undelete = ([], _('undeleting %s\n'))
2235 undelete = ([], _('undeleting %s\n'))
2233 update = {}
2236 update = {}
2234
2237
2235 disptable = (
2238 disptable = (
2236 # dispatch table:
2239 # dispatch table:
2237 # file state
2240 # file state
2238 # action if in target manifest
2241 # action if in target manifest
2239 # action if not in target manifest
2242 # action if not in target manifest
2240 # make backup if in target manifest
2243 # make backup if in target manifest
2241 # make backup if not in target manifest
2244 # make backup if not in target manifest
2242 (modified, revert, remove, True, True),
2245 (modified, revert, remove, True, True),
2243 (added, revert, forget, True, False),
2246 (added, revert, forget, True, False),
2244 (removed, undelete, None, False, False),
2247 (removed, undelete, None, False, False),
2245 (deleted, revert, remove, False, False),
2248 (deleted, revert, remove, False, False),
2246 (unknown, add, None, True, False),
2249 (unknown, add, None, True, False),
2247 (target_only, add, None, False, False),
2250 (target_only, add, None, False, False),
2248 )
2251 )
2249
2252
2250 entries = names.items()
2253 entries = names.items()
2251 entries.sort()
2254 entries.sort()
2252
2255
2253 for abs, (rel, exact) in entries:
2256 for abs, (rel, exact) in entries:
2254 mfentry = mf.get(abs)
2257 mfentry = mf.get(abs)
2255 def handle(xlist, dobackup):
2258 def handle(xlist, dobackup):
2256 xlist[0].append(abs)
2259 xlist[0].append(abs)
2257 update[abs] = 1
2260 update[abs] = 1
2258 if (dobackup and not opts['no_backup'] and
2261 if (dobackup and not opts['no_backup'] and
2259 (os.path.islink(rel) or os.path.exists(rel))):
2262 (os.path.islink(rel) or os.path.exists(rel))):
2260 bakname = "%s.orig" % rel
2263 bakname = "%s.orig" % rel
2261 ui.note(_('saving current version of %s as %s\n') %
2264 ui.note(_('saving current version of %s as %s\n') %
2262 (rel, bakname))
2265 (rel, bakname))
2263 if not opts.get('dry_run'):
2266 if not opts.get('dry_run'):
2264 util.copyfile(rel, bakname)
2267 util.copyfile(rel, bakname)
2265 if ui.verbose or not exact:
2268 if ui.verbose or not exact:
2266 ui.status(xlist[1] % rel)
2269 ui.status(xlist[1] % rel)
2267 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2270 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2268 if abs not in table: continue
2271 if abs not in table: continue
2269 # file has changed in dirstate
2272 # file has changed in dirstate
2270 if mfentry:
2273 if mfentry:
2271 handle(hitlist, backuphit)
2274 handle(hitlist, backuphit)
2272 elif misslist is not None:
2275 elif misslist is not None:
2273 handle(misslist, backupmiss)
2276 handle(misslist, backupmiss)
2274 else:
2277 else:
2275 if exact: ui.warn(_('file not managed: %s\n') % rel)
2278 if exact: ui.warn(_('file not managed: %s\n') % rel)
2276 break
2279 break
2277 else:
2280 else:
2278 # file has not changed in dirstate
2281 # file has not changed in dirstate
2279 if node == parent:
2282 if node == parent:
2280 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2283 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2281 continue
2284 continue
2282 if pmf is None:
2285 if pmf is None:
2283 # only need parent manifest in this unlikely case,
2286 # only need parent manifest in this unlikely case,
2284 # so do not read by default
2287 # so do not read by default
2285 pmf = repo.changectx(parent).manifest()
2288 pmf = repo.changectx(parent).manifest()
2286 if abs in pmf:
2289 if abs in pmf:
2287 if mfentry:
2290 if mfentry:
2288 # if version of file is same in parent and target
2291 # if version of file is same in parent and target
2289 # manifests, do nothing
2292 # manifests, do nothing
2290 if pmf[abs] != mfentry:
2293 if pmf[abs] != mfentry:
2291 handle(revert, False)
2294 handle(revert, False)
2292 else:
2295 else:
2293 handle(remove, False)
2296 handle(remove, False)
2294
2297
2295 if not opts.get('dry_run'):
2298 if not opts.get('dry_run'):
2296 repo.dirstate.forget(forget[0])
2299 repo.dirstate.forget(forget[0])
2297 r = hg.revert(repo, node, update.has_key, wlock)
2300 r = hg.revert(repo, node, update.has_key, wlock)
2298 repo.dirstate.update(add[0], 'a')
2301 repo.dirstate.update(add[0], 'a')
2299 repo.dirstate.update(undelete[0], 'n')
2302 repo.dirstate.update(undelete[0], 'n')
2300 repo.dirstate.update(remove[0], 'r')
2303 repo.dirstate.update(remove[0], 'r')
2301 return r
2304 return r
2302
2305
2303 def rollback(ui, repo):
2306 def rollback(ui, repo):
2304 """roll back the last transaction in this repository
2307 """roll back the last transaction in this repository
2305
2308
2306 Roll back the last transaction in this repository, restoring the
2309 Roll back the last transaction in this repository, restoring the
2307 project to its state prior to the transaction.
2310 project to its state prior to the transaction.
2308
2311
2309 Transactions are used to encapsulate the effects of all commands
2312 Transactions are used to encapsulate the effects of all commands
2310 that create new changesets or propagate existing changesets into a
2313 that create new changesets or propagate existing changesets into a
2311 repository. For example, the following commands are transactional,
2314 repository. For example, the following commands are transactional,
2312 and their effects can be rolled back:
2315 and their effects can be rolled back:
2313
2316
2314 commit
2317 commit
2315 import
2318 import
2316 pull
2319 pull
2317 push (with this repository as destination)
2320 push (with this repository as destination)
2318 unbundle
2321 unbundle
2319
2322
2320 This command should be used with care. There is only one level of
2323 This command should be used with care. There is only one level of
2321 rollback, and there is no way to undo a rollback.
2324 rollback, and there is no way to undo a rollback.
2322
2325
2323 This command is not intended for use on public repositories. Once
2326 This command is not intended for use on public repositories. Once
2324 changes are visible for pull by other users, rolling a transaction
2327 changes are visible for pull by other users, rolling a transaction
2325 back locally is ineffective (someone else may already have pulled
2328 back locally is ineffective (someone else may already have pulled
2326 the changes). Furthermore, a race is possible with readers of the
2329 the changes). Furthermore, a race is possible with readers of the
2327 repository; for example an in-progress pull from the repository
2330 repository; for example an in-progress pull from the repository
2328 may fail if a rollback is performed.
2331 may fail if a rollback is performed.
2329 """
2332 """
2330 repo.rollback()
2333 repo.rollback()
2331
2334
2332 def root(ui, repo):
2335 def root(ui, repo):
2333 """print the root (top) of the current working dir
2336 """print the root (top) of the current working dir
2334
2337
2335 Print the root directory of the current repository.
2338 Print the root directory of the current repository.
2336 """
2339 """
2337 ui.write(repo.root + "\n")
2340 ui.write(repo.root + "\n")
2338
2341
2339 def serve(ui, repo, **opts):
2342 def serve(ui, repo, **opts):
2340 """export the repository via HTTP
2343 """export the repository via HTTP
2341
2344
2342 Start a local HTTP repository browser and pull server.
2345 Start a local HTTP repository browser and pull server.
2343
2346
2344 By default, the server logs accesses to stdout and errors to
2347 By default, the server logs accesses to stdout and errors to
2345 stderr. Use the "-A" and "-E" options to log to files.
2348 stderr. Use the "-A" and "-E" options to log to files.
2346 """
2349 """
2347
2350
2348 if opts["stdio"]:
2351 if opts["stdio"]:
2349 if repo is None:
2352 if repo is None:
2350 raise hg.RepoError(_("There is no Mercurial repository here"
2353 raise hg.RepoError(_("There is no Mercurial repository here"
2351 " (.hg not found)"))
2354 " (.hg not found)"))
2352 s = sshserver.sshserver(ui, repo)
2355 s = sshserver.sshserver(ui, repo)
2353 s.serve_forever()
2356 s.serve_forever()
2354
2357
2355 parentui = ui.parentui or ui
2358 parentui = ui.parentui or ui
2356 optlist = ("name templates style address port ipv6"
2359 optlist = ("name templates style address port ipv6"
2357 " accesslog errorlog webdir_conf")
2360 " accesslog errorlog webdir_conf")
2358 for o in optlist.split():
2361 for o in optlist.split():
2359 if opts[o]:
2362 if opts[o]:
2360 parentui.setconfig("web", o, str(opts[o]))
2363 parentui.setconfig("web", o, str(opts[o]))
2361
2364
2362 if repo is None and not ui.config("web", "webdir_conf"):
2365 if repo is None and not ui.config("web", "webdir_conf"):
2363 raise hg.RepoError(_("There is no Mercurial repository here"
2366 raise hg.RepoError(_("There is no Mercurial repository here"
2364 " (.hg not found)"))
2367 " (.hg not found)"))
2365
2368
2366 if opts['daemon'] and not opts['daemon_pipefds']:
2369 if opts['daemon'] and not opts['daemon_pipefds']:
2367 rfd, wfd = os.pipe()
2370 rfd, wfd = os.pipe()
2368 args = sys.argv[:]
2371 args = sys.argv[:]
2369 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2372 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2370 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2373 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2371 args[0], args)
2374 args[0], args)
2372 os.close(wfd)
2375 os.close(wfd)
2373 os.read(rfd, 1)
2376 os.read(rfd, 1)
2374 os._exit(0)
2377 os._exit(0)
2375
2378
2376 httpd = hgweb.server.create_server(parentui, repo)
2379 httpd = hgweb.server.create_server(parentui, repo)
2377
2380
2378 if ui.verbose:
2381 if ui.verbose:
2379 if httpd.port != 80:
2382 if httpd.port != 80:
2380 ui.status(_('listening at http://%s:%d/\n') %
2383 ui.status(_('listening at http://%s:%d/\n') %
2381 (httpd.addr, httpd.port))
2384 (httpd.addr, httpd.port))
2382 else:
2385 else:
2383 ui.status(_('listening at http://%s/\n') % httpd.addr)
2386 ui.status(_('listening at http://%s/\n') % httpd.addr)
2384
2387
2385 if opts['pid_file']:
2388 if opts['pid_file']:
2386 fp = open(opts['pid_file'], 'w')
2389 fp = open(opts['pid_file'], 'w')
2387 fp.write(str(os.getpid()) + '\n')
2390 fp.write(str(os.getpid()) + '\n')
2388 fp.close()
2391 fp.close()
2389
2392
2390 if opts['daemon_pipefds']:
2393 if opts['daemon_pipefds']:
2391 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2394 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2392 os.close(rfd)
2395 os.close(rfd)
2393 os.write(wfd, 'y')
2396 os.write(wfd, 'y')
2394 os.close(wfd)
2397 os.close(wfd)
2395 sys.stdout.flush()
2398 sys.stdout.flush()
2396 sys.stderr.flush()
2399 sys.stderr.flush()
2397 fd = os.open(util.nulldev, os.O_RDWR)
2400 fd = os.open(util.nulldev, os.O_RDWR)
2398 if fd != 0: os.dup2(fd, 0)
2401 if fd != 0: os.dup2(fd, 0)
2399 if fd != 1: os.dup2(fd, 1)
2402 if fd != 1: os.dup2(fd, 1)
2400 if fd != 2: os.dup2(fd, 2)
2403 if fd != 2: os.dup2(fd, 2)
2401 if fd not in (0, 1, 2): os.close(fd)
2404 if fd not in (0, 1, 2): os.close(fd)
2402
2405
2403 httpd.serve_forever()
2406 httpd.serve_forever()
2404
2407
2405 def status(ui, repo, *pats, **opts):
2408 def status(ui, repo, *pats, **opts):
2406 """show changed files in the working directory
2409 """show changed files in the working directory
2407
2410
2408 Show status of files in the repository. If names are given, only
2411 Show status of files in the repository. If names are given, only
2409 files that match are shown. Files that are clean or ignored, are
2412 files that match are shown. Files that are clean or ignored, are
2410 not listed unless -c (clean), -i (ignored) or -A is given.
2413 not listed unless -c (clean), -i (ignored) or -A is given.
2411
2414
2412 NOTE: status may appear to disagree with diff if permissions have
2415 NOTE: status may appear to disagree with diff if permissions have
2413 changed or a merge has occurred. The standard diff format does not
2416 changed or a merge has occurred. The standard diff format does not
2414 report permission changes and diff only reports changes relative
2417 report permission changes and diff only reports changes relative
2415 to one merge parent.
2418 to one merge parent.
2416
2419
2417 If one revision is given, it is used as the base revision.
2420 If one revision is given, it is used as the base revision.
2418 If two revisions are given, the difference between them is shown.
2421 If two revisions are given, the difference between them is shown.
2419
2422
2420 The codes used to show the status of files are:
2423 The codes used to show the status of files are:
2421 M = modified
2424 M = modified
2422 A = added
2425 A = added
2423 R = removed
2426 R = removed
2424 C = clean
2427 C = clean
2425 ! = deleted, but still tracked
2428 ! = deleted, but still tracked
2426 ? = not tracked
2429 ? = not tracked
2427 I = ignored (not shown by default)
2430 I = ignored (not shown by default)
2428 = the previous added file was copied from here
2431 = the previous added file was copied from here
2429 """
2432 """
2430
2433
2431 all = opts['all']
2434 all = opts['all']
2432 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2435 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2433
2436
2434 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2437 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2435 cwd = (pats and repo.getcwd()) or ''
2438 cwd = (pats and repo.getcwd()) or ''
2436 modified, added, removed, deleted, unknown, ignored, clean = [
2439 modified, added, removed, deleted, unknown, ignored, clean = [
2437 n for n in repo.status(node1=node1, node2=node2, files=files,
2440 n for n in repo.status(node1=node1, node2=node2, files=files,
2438 match=matchfn,
2441 match=matchfn,
2439 list_ignored=all or opts['ignored'],
2442 list_ignored=all or opts['ignored'],
2440 list_clean=all or opts['clean'])]
2443 list_clean=all or opts['clean'])]
2441
2444
2442 changetypes = (('modified', 'M', modified),
2445 changetypes = (('modified', 'M', modified),
2443 ('added', 'A', added),
2446 ('added', 'A', added),
2444 ('removed', 'R', removed),
2447 ('removed', 'R', removed),
2445 ('deleted', '!', deleted),
2448 ('deleted', '!', deleted),
2446 ('unknown', '?', unknown),
2449 ('unknown', '?', unknown),
2447 ('ignored', 'I', ignored))
2450 ('ignored', 'I', ignored))
2448
2451
2449 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2452 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2450
2453
2451 end = opts['print0'] and '\0' or '\n'
2454 end = opts['print0'] and '\0' or '\n'
2452
2455
2453 for opt, char, changes in ([ct for ct in explicit_changetypes
2456 for opt, char, changes in ([ct for ct in explicit_changetypes
2454 if all or opts[ct[0]]]
2457 if all or opts[ct[0]]]
2455 or changetypes):
2458 or changetypes):
2456 if opts['no_status']:
2459 if opts['no_status']:
2457 format = "%%s%s" % end
2460 format = "%%s%s" % end
2458 else:
2461 else:
2459 format = "%s %%s%s" % (char, end)
2462 format = "%s %%s%s" % (char, end)
2460
2463
2461 for f in changes:
2464 for f in changes:
2462 ui.write(format % util.pathto(repo.root, cwd, f))
2465 ui.write(format % util.pathto(repo.root, cwd, f))
2463 if ((all or opts.get('copies')) and not opts.get('no_status')):
2466 if ((all or opts.get('copies')) and not opts.get('no_status')):
2464 copied = repo.dirstate.copied(f)
2467 copied = repo.dirstate.copied(f)
2465 if copied:
2468 if copied:
2466 ui.write(' %s%s' % (util.pathto(repo.root, cwd, copied),
2469 ui.write(' %s%s' % (util.pathto(repo.root, cwd, copied),
2467 end))
2470 end))
2468
2471
2469 def tag(ui, repo, name, rev_=None, **opts):
2472 def tag(ui, repo, name, rev_=None, **opts):
2470 """add a tag for the current or given revision
2473 """add a tag for the current or given revision
2471
2474
2472 Name a particular revision using <name>.
2475 Name a particular revision using <name>.
2473
2476
2474 Tags are used to name particular revisions of the repository and are
2477 Tags are used to name particular revisions of the repository and are
2475 very useful to compare different revision, to go back to significant
2478 very useful to compare different revision, to go back to significant
2476 earlier versions or to mark branch points as releases, etc.
2479 earlier versions or to mark branch points as releases, etc.
2477
2480
2478 If no revision is given, the parent of the working directory is used,
2481 If no revision is given, the parent of the working directory is used,
2479 or tip if no revision is checked out.
2482 or tip if no revision is checked out.
2480
2483
2481 To facilitate version control, distribution, and merging of tags,
2484 To facilitate version control, distribution, and merging of tags,
2482 they are stored as a file named ".hgtags" which is managed
2485 they are stored as a file named ".hgtags" which is managed
2483 similarly to other project files and can be hand-edited if
2486 similarly to other project files and can be hand-edited if
2484 necessary. The file '.hg/localtags' is used for local tags (not
2487 necessary. The file '.hg/localtags' is used for local tags (not
2485 shared among repositories).
2488 shared among repositories).
2486 """
2489 """
2487 if name in ['tip', '.', 'null']:
2490 if name in ['tip', '.', 'null']:
2488 raise util.Abort(_("the name '%s' is reserved") % name)
2491 raise util.Abort(_("the name '%s' is reserved") % name)
2489 if rev_ is not None:
2492 if rev_ is not None:
2490 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2493 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2491 "please use 'hg tag [-r REV] NAME' instead\n"))
2494 "please use 'hg tag [-r REV] NAME' instead\n"))
2492 if opts['rev']:
2495 if opts['rev']:
2493 raise util.Abort(_("use only one form to specify the revision"))
2496 raise util.Abort(_("use only one form to specify the revision"))
2494 if opts['rev'] and opts['remove']:
2497 if opts['rev'] and opts['remove']:
2495 raise util.Abort(_("--rev and --remove are incompatible"))
2498 raise util.Abort(_("--rev and --remove are incompatible"))
2496 if opts['rev']:
2499 if opts['rev']:
2497 rev_ = opts['rev']
2500 rev_ = opts['rev']
2498 message = opts['message']
2501 message = opts['message']
2499 if opts['remove']:
2502 if opts['remove']:
2500 rev_ = nullid
2503 rev_ = nullid
2501 if not message:
2504 if not message:
2502 message = _('Removed tag %s') % name
2505 message = _('Removed tag %s') % name
2503 elif name in repo.tags() and not opts['force']:
2506 elif name in repo.tags() and not opts['force']:
2504 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2507 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2505 % name)
2508 % name)
2506 if not rev_ and repo.dirstate.parents()[1] != nullid:
2509 if not rev_ and repo.dirstate.parents()[1] != nullid:
2507 raise util.Abort(_('uncommitted merge - please provide a '
2510 raise util.Abort(_('uncommitted merge - please provide a '
2508 'specific revision'))
2511 'specific revision'))
2509 r = repo.changectx(rev_).node()
2512 r = repo.changectx(rev_).node()
2510
2513
2511 if not message:
2514 if not message:
2512 message = _('Added tag %s for changeset %s') % (name, short(r))
2515 message = _('Added tag %s for changeset %s') % (name, short(r))
2513
2516
2514 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2517 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2515
2518
2516 def tags(ui, repo):
2519 def tags(ui, repo):
2517 """list repository tags
2520 """list repository tags
2518
2521
2519 List the repository tags.
2522 List the repository tags.
2520
2523
2521 This lists both regular and local tags.
2524 This lists both regular and local tags.
2522 """
2525 """
2523
2526
2524 l = repo.tagslist()
2527 l = repo.tagslist()
2525 l.reverse()
2528 l.reverse()
2526 hexfunc = ui.debugflag and hex or short
2529 hexfunc = ui.debugflag and hex or short
2527 for t, n in l:
2530 for t, n in l:
2528 try:
2531 try:
2529 hn = hexfunc(n)
2532 hn = hexfunc(n)
2530 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2533 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2531 except revlog.LookupError:
2534 except revlog.LookupError:
2532 r = " ?:%s" % hn
2535 r = " ?:%s" % hn
2533 if ui.quiet:
2536 if ui.quiet:
2534 ui.write("%s\n" % t)
2537 ui.write("%s\n" % t)
2535 else:
2538 else:
2536 spaces = " " * (30 - util.locallen(t))
2539 spaces = " " * (30 - util.locallen(t))
2537 ui.write("%s%s %s\n" % (t, spaces, r))
2540 ui.write("%s%s %s\n" % (t, spaces, r))
2538
2541
2539 def tip(ui, repo, **opts):
2542 def tip(ui, repo, **opts):
2540 """show the tip revision
2543 """show the tip revision
2541
2544
2542 Show the tip revision.
2545 Show the tip revision.
2543 """
2546 """
2544 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2547 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2545
2548
2546 def unbundle(ui, repo, fname, **opts):
2549 def unbundle(ui, repo, fname, **opts):
2547 """apply a changegroup file
2550 """apply a changegroup file
2548
2551
2549 Apply a compressed changegroup file generated by the bundle
2552 Apply a compressed changegroup file generated by the bundle
2550 command.
2553 command.
2551 """
2554 """
2552 if os.path.exists(fname):
2555 if os.path.exists(fname):
2553 f = open(fname, "rb")
2556 f = open(fname, "rb")
2554 else:
2557 else:
2555 f = urllib.urlopen(fname)
2558 f = urllib.urlopen(fname)
2556 gen = changegroup.readbundle(f, fname)
2559 gen = changegroup.readbundle(f, fname)
2557 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2560 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2558 return postincoming(ui, repo, modheads, opts['update'])
2561 return postincoming(ui, repo, modheads, opts['update'])
2559
2562
2560 def update(ui, repo, node=None, clean=False, date=None):
2563 def update(ui, repo, node=None, clean=False, date=None):
2561 """update working directory
2564 """update working directory
2562
2565
2563 Update the working directory to the specified revision, or the
2566 Update the working directory to the specified revision, or the
2564 tip of the current branch if none is specified.
2567 tip of the current branch if none is specified.
2565
2568
2566 If there are no outstanding changes in the working directory and
2569 If there are no outstanding changes in the working directory and
2567 there is a linear relationship between the current version and the
2570 there is a linear relationship between the current version and the
2568 requested version, the result is the requested version.
2571 requested version, the result is the requested version.
2569
2572
2570 To merge the working directory with another revision, use the
2573 To merge the working directory with another revision, use the
2571 merge command.
2574 merge command.
2572
2575
2573 By default, update will refuse to run if doing so would require
2576 By default, update will refuse to run if doing so would require
2574 discarding local changes.
2577 discarding local changes.
2575 """
2578 """
2576 if date:
2579 if date:
2577 if node:
2580 if node:
2578 raise util.Abort(_("you can't specify a revision and a date"))
2581 raise util.Abort(_("you can't specify a revision and a date"))
2579 node = cmdutil.finddate(ui, repo, date)
2582 node = cmdutil.finddate(ui, repo, date)
2580
2583
2581 if clean:
2584 if clean:
2582 return hg.clean(repo, node)
2585 return hg.clean(repo, node)
2583 else:
2586 else:
2584 return hg.update(repo, node)
2587 return hg.update(repo, node)
2585
2588
2586 def verify(ui, repo):
2589 def verify(ui, repo):
2587 """verify the integrity of the repository
2590 """verify the integrity of the repository
2588
2591
2589 Verify the integrity of the current repository.
2592 Verify the integrity of the current repository.
2590
2593
2591 This will perform an extensive check of the repository's
2594 This will perform an extensive check of the repository's
2592 integrity, validating the hashes and checksums of each entry in
2595 integrity, validating the hashes and checksums of each entry in
2593 the changelog, manifest, and tracked files, as well as the
2596 the changelog, manifest, and tracked files, as well as the
2594 integrity of their crosslinks and indices.
2597 integrity of their crosslinks and indices.
2595 """
2598 """
2596 return hg.verify(repo)
2599 return hg.verify(repo)
2597
2600
2598 def version_(ui):
2601 def version_(ui):
2599 """output version and copyright information"""
2602 """output version and copyright information"""
2600 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2603 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2601 % version.get_version())
2604 % version.get_version())
2602 ui.status(_(
2605 ui.status(_(
2603 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2606 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2604 "This is free software; see the source for copying conditions. "
2607 "This is free software; see the source for copying conditions. "
2605 "There is NO\nwarranty; "
2608 "There is NO\nwarranty; "
2606 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2609 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2607 ))
2610 ))
2608
2611
2609 # Command options and aliases are listed here, alphabetically
2612 # Command options and aliases are listed here, alphabetically
2610
2613
2611 globalopts = [
2614 globalopts = [
2612 ('R', 'repository', '',
2615 ('R', 'repository', '',
2613 _('repository root directory or symbolic path name')),
2616 _('repository root directory or symbolic path name')),
2614 ('', 'cwd', '', _('change working directory')),
2617 ('', 'cwd', '', _('change working directory')),
2615 ('y', 'noninteractive', None,
2618 ('y', 'noninteractive', None,
2616 _('do not prompt, assume \'yes\' for any required answers')),
2619 _('do not prompt, assume \'yes\' for any required answers')),
2617 ('q', 'quiet', None, _('suppress output')),
2620 ('q', 'quiet', None, _('suppress output')),
2618 ('v', 'verbose', None, _('enable additional output')),
2621 ('v', 'verbose', None, _('enable additional output')),
2619 ('', 'config', [], _('set/override config option')),
2622 ('', 'config', [], _('set/override config option')),
2620 ('', 'debug', None, _('enable debugging output')),
2623 ('', 'debug', None, _('enable debugging output')),
2621 ('', 'debugger', None, _('start debugger')),
2624 ('', 'debugger', None, _('start debugger')),
2622 ('', 'encoding', util._encoding, _('set the charset encoding')),
2625 ('', 'encoding', util._encoding, _('set the charset encoding')),
2623 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2626 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2624 ('', 'lsprof', None, _('print improved command execution profile')),
2627 ('', 'lsprof', None, _('print improved command execution profile')),
2625 ('', 'traceback', None, _('print traceback on exception')),
2628 ('', 'traceback', None, _('print traceback on exception')),
2626 ('', 'time', None, _('time how long the command takes')),
2629 ('', 'time', None, _('time how long the command takes')),
2627 ('', 'profile', None, _('print command execution profile')),
2630 ('', 'profile', None, _('print command execution profile')),
2628 ('', 'version', None, _('output version information and exit')),
2631 ('', 'version', None, _('output version information and exit')),
2629 ('h', 'help', None, _('display help and exit')),
2632 ('h', 'help', None, _('display help and exit')),
2630 ]
2633 ]
2631
2634
2632 dryrunopts = [('n', 'dry-run', None,
2635 dryrunopts = [('n', 'dry-run', None,
2633 _('do not perform actions, just print output'))]
2636 _('do not perform actions, just print output'))]
2634
2637
2635 remoteopts = [
2638 remoteopts = [
2636 ('e', 'ssh', '', _('specify ssh command to use')),
2639 ('e', 'ssh', '', _('specify ssh command to use')),
2637 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2640 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2638 ]
2641 ]
2639
2642
2640 walkopts = [
2643 walkopts = [
2641 ('I', 'include', [], _('include names matching the given patterns')),
2644 ('I', 'include', [], _('include names matching the given patterns')),
2642 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2645 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2643 ]
2646 ]
2644
2647
2645 commitopts = [
2648 commitopts = [
2646 ('m', 'message', '', _('use <text> as commit message')),
2649 ('m', 'message', '', _('use <text> as commit message')),
2647 ('l', 'logfile', '', _('read commit message from <file>')),
2650 ('l', 'logfile', '', _('read commit message from <file>')),
2648 ]
2651 ]
2649
2652
2650 table = {
2653 table = {
2651 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2654 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2652 "addremove":
2655 "addremove":
2653 (addremove,
2656 (addremove,
2654 [('s', 'similarity', '',
2657 [('s', 'similarity', '',
2655 _('guess renamed files by similarity (0<=s<=100)')),
2658 _('guess renamed files by similarity (0<=s<=100)')),
2656 ] + walkopts + dryrunopts,
2659 ] + walkopts + dryrunopts,
2657 _('hg addremove [OPTION]... [FILE]...')),
2660 _('hg addremove [OPTION]... [FILE]...')),
2658 "^annotate":
2661 "^annotate":
2659 (annotate,
2662 (annotate,
2660 [('r', 'rev', '', _('annotate the specified revision')),
2663 [('r', 'rev', '', _('annotate the specified revision')),
2661 ('f', 'follow', None, _('follow file copies and renames')),
2664 ('f', 'follow', None, _('follow file copies and renames')),
2662 ('a', 'text', None, _('treat all files as text')),
2665 ('a', 'text', None, _('treat all files as text')),
2663 ('u', 'user', None, _('list the author')),
2666 ('u', 'user', None, _('list the author')),
2664 ('d', 'date', None, _('list the date')),
2667 ('d', 'date', None, _('list the date')),
2665 ('n', 'number', None, _('list the revision number (default)')),
2668 ('n', 'number', None, _('list the revision number (default)')),
2666 ('c', 'changeset', None, _('list the changeset')),
2669 ('c', 'changeset', None, _('list the changeset')),
2667 ] + walkopts,
2670 ] + walkopts,
2668 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2671 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2669 "archive":
2672 "archive":
2670 (archive,
2673 (archive,
2671 [('', 'no-decode', None, _('do not pass files through decoders')),
2674 [('', 'no-decode', None, _('do not pass files through decoders')),
2672 ('p', 'prefix', '', _('directory prefix for files in archive')),
2675 ('p', 'prefix', '', _('directory prefix for files in archive')),
2673 ('r', 'rev', '', _('revision to distribute')),
2676 ('r', 'rev', '', _('revision to distribute')),
2674 ('t', 'type', '', _('type of distribution to create')),
2677 ('t', 'type', '', _('type of distribution to create')),
2675 ] + walkopts,
2678 ] + walkopts,
2676 _('hg archive [OPTION]... DEST')),
2679 _('hg archive [OPTION]... DEST')),
2677 "backout":
2680 "backout":
2678 (backout,
2681 (backout,
2679 [('', 'merge', None,
2682 [('', 'merge', None,
2680 _('merge with old dirstate parent after backout')),
2683 _('merge with old dirstate parent after backout')),
2681 ('d', 'date', '', _('record datecode as commit date')),
2684 ('d', 'date', '', _('record datecode as commit date')),
2682 ('', 'parent', '', _('parent to choose when backing out merge')),
2685 ('', 'parent', '', _('parent to choose when backing out merge')),
2683 ('u', 'user', '', _('record user as committer')),
2686 ('u', 'user', '', _('record user as committer')),
2684 ] + walkopts + commitopts,
2687 ] + walkopts + commitopts,
2685 _('hg backout [OPTION]... REV')),
2688 _('hg backout [OPTION]... REV')),
2686 "branch": (branch,
2689 "branch": (branch,
2687 [('f', 'force', None,
2690 [('f', 'force', None,
2688 _('set branch name even if it shadows an existing branch'))],
2691 _('set branch name even if it shadows an existing branch'))],
2689 _('hg branch [NAME]')),
2692 _('hg branch [NAME]')),
2690 "branches": (branches, [], _('hg branches')),
2693 "branches": (branches, [], _('hg branches')),
2691 "bundle":
2694 "bundle":
2692 (bundle,
2695 (bundle,
2693 [('f', 'force', None,
2696 [('f', 'force', None,
2694 _('run even when remote repository is unrelated')),
2697 _('run even when remote repository is unrelated')),
2695 ('r', 'rev', [],
2698 ('r', 'rev', [],
2696 _('a changeset you would like to bundle')),
2699 _('a changeset you would like to bundle')),
2697 ('', 'base', [],
2700 ('', 'base', [],
2698 _('a base changeset to specify instead of a destination')),
2701 _('a base changeset to specify instead of a destination')),
2699 ] + remoteopts,
2702 ] + remoteopts,
2700 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2703 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2701 "cat":
2704 "cat":
2702 (cat,
2705 (cat,
2703 [('o', 'output', '', _('print output to file with formatted name')),
2706 [('o', 'output', '', _('print output to file with formatted name')),
2704 ('r', 'rev', '', _('print the given revision')),
2707 ('r', 'rev', '', _('print the given revision')),
2705 ] + walkopts,
2708 ] + walkopts,
2706 _('hg cat [OPTION]... FILE...')),
2709 _('hg cat [OPTION]... FILE...')),
2707 "^clone":
2710 "^clone":
2708 (clone,
2711 (clone,
2709 [('U', 'noupdate', None, _('do not update the new working directory')),
2712 [('U', 'noupdate', None, _('do not update the new working directory')),
2710 ('r', 'rev', [],
2713 ('r', 'rev', [],
2711 _('a changeset you would like to have after cloning')),
2714 _('a changeset you would like to have after cloning')),
2712 ('', 'pull', None, _('use pull protocol to copy metadata')),
2715 ('', 'pull', None, _('use pull protocol to copy metadata')),
2713 ('', 'uncompressed', None,
2716 ('', 'uncompressed', None,
2714 _('use uncompressed transfer (fast over LAN)')),
2717 _('use uncompressed transfer (fast over LAN)')),
2715 ] + remoteopts,
2718 ] + remoteopts,
2716 _('hg clone [OPTION]... SOURCE [DEST]')),
2719 _('hg clone [OPTION]... SOURCE [DEST]')),
2717 "^commit|ci":
2720 "^commit|ci":
2718 (commit,
2721 (commit,
2719 [('A', 'addremove', None,
2722 [('A', 'addremove', None,
2720 _('mark new/missing files as added/removed before committing')),
2723 _('mark new/missing files as added/removed before committing')),
2721 ('d', 'date', '', _('record datecode as commit date')),
2724 ('d', 'date', '', _('record datecode as commit date')),
2722 ('u', 'user', '', _('record user as commiter')),
2725 ('u', 'user', '', _('record user as commiter')),
2723 ] + walkopts + commitopts,
2726 ] + walkopts + commitopts,
2724 _('hg commit [OPTION]... [FILE]...')),
2727 _('hg commit [OPTION]... [FILE]...')),
2725 "copy|cp":
2728 "copy|cp":
2726 (copy,
2729 (copy,
2727 [('A', 'after', None, _('record a copy that has already occurred')),
2730 [('A', 'after', None, _('record a copy that has already occurred')),
2728 ('f', 'force', None,
2731 ('f', 'force', None,
2729 _('forcibly copy over an existing managed file')),
2732 _('forcibly copy over an existing managed file')),
2730 ] + walkopts + dryrunopts,
2733 ] + walkopts + dryrunopts,
2731 _('hg copy [OPTION]... [SOURCE]... DEST')),
2734 _('hg copy [OPTION]... [SOURCE]... DEST')),
2732 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2735 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2733 "debugcomplete":
2736 "debugcomplete":
2734 (debugcomplete,
2737 (debugcomplete,
2735 [('o', 'options', None, _('show the command options'))],
2738 [('o', 'options', None, _('show the command options'))],
2736 _('debugcomplete [-o] CMD')),
2739 _('debugcomplete [-o] CMD')),
2737 "debuginstall": (debuginstall, [], _('debuginstall')),
2740 "debuginstall": (debuginstall, [], _('debuginstall')),
2738 "debugrebuildstate":
2741 "debugrebuildstate":
2739 (debugrebuildstate,
2742 (debugrebuildstate,
2740 [('r', 'rev', '', _('revision to rebuild to'))],
2743 [('r', 'rev', '', _('revision to rebuild to'))],
2741 _('debugrebuildstate [-r REV] [REV]')),
2744 _('debugrebuildstate [-r REV] [REV]')),
2742 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2745 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2743 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2746 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2744 "debugstate": (debugstate, [], _('debugstate')),
2747 "debugstate": (debugstate, [], _('debugstate')),
2745 "debugdate":
2748 "debugdate":
2746 (debugdate,
2749 (debugdate,
2747 [('e', 'extended', None, _('try extended date formats'))],
2750 [('e', 'extended', None, _('try extended date formats'))],
2748 _('debugdate [-e] DATE [RANGE]')),
2751 _('debugdate [-e] DATE [RANGE]')),
2749 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2752 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2750 "debugindex": (debugindex, [], _('debugindex FILE')),
2753 "debugindex": (debugindex, [], _('debugindex FILE')),
2751 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2754 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2752 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2755 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2753 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2756 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2754 "^diff":
2757 "^diff":
2755 (diff,
2758 (diff,
2756 [('r', 'rev', [], _('revision')),
2759 [('r', 'rev', [], _('revision')),
2757 ('a', 'text', None, _('treat all files as text')),
2760 ('a', 'text', None, _('treat all files as text')),
2758 ('p', 'show-function', None,
2761 ('p', 'show-function', None,
2759 _('show which function each change is in')),
2762 _('show which function each change is in')),
2760 ('g', 'git', None, _('use git extended diff format')),
2763 ('g', 'git', None, _('use git extended diff format')),
2761 ('', 'nodates', None, _("don't include dates in diff headers")),
2764 ('', 'nodates', None, _("don't include dates in diff headers")),
2762 ('w', 'ignore-all-space', None,
2765 ('w', 'ignore-all-space', None,
2763 _('ignore white space when comparing lines')),
2766 _('ignore white space when comparing lines')),
2764 ('b', 'ignore-space-change', None,
2767 ('b', 'ignore-space-change', None,
2765 _('ignore changes in the amount of white space')),
2768 _('ignore changes in the amount of white space')),
2766 ('B', 'ignore-blank-lines', None,
2769 ('B', 'ignore-blank-lines', None,
2767 _('ignore changes whose lines are all blank')),
2770 _('ignore changes whose lines are all blank')),
2768 ] + walkopts,
2771 ] + walkopts,
2769 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2772 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2770 "^export":
2773 "^export":
2771 (export,
2774 (export,
2772 [('o', 'output', '', _('print output to file with formatted name')),
2775 [('o', 'output', '', _('print output to file with formatted name')),
2773 ('a', 'text', None, _('treat all files as text')),
2776 ('a', 'text', None, _('treat all files as text')),
2774 ('g', 'git', None, _('use git extended diff format')),
2777 ('g', 'git', None, _('use git extended diff format')),
2775 ('', 'nodates', None, _("don't include dates in diff headers")),
2778 ('', 'nodates', None, _("don't include dates in diff headers")),
2776 ('', 'switch-parent', None, _('diff against the second parent'))],
2779 ('', 'switch-parent', None, _('diff against the second parent'))],
2777 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2780 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2778 "grep":
2781 "grep":
2779 (grep,
2782 (grep,
2780 [('0', 'print0', None, _('end fields with NUL')),
2783 [('0', 'print0', None, _('end fields with NUL')),
2781 ('', 'all', None, _('print all revisions that match')),
2784 ('', 'all', None, _('print all revisions that match')),
2782 ('f', 'follow', None,
2785 ('f', 'follow', None,
2783 _('follow changeset history, or file history across copies and renames')),
2786 _('follow changeset history, or file history across copies and renames')),
2784 ('i', 'ignore-case', None, _('ignore case when matching')),
2787 ('i', 'ignore-case', None, _('ignore case when matching')),
2785 ('l', 'files-with-matches', None,
2788 ('l', 'files-with-matches', None,
2786 _('print only filenames and revs that match')),
2789 _('print only filenames and revs that match')),
2787 ('n', 'line-number', None, _('print matching line numbers')),
2790 ('n', 'line-number', None, _('print matching line numbers')),
2788 ('r', 'rev', [], _('search in given revision range')),
2791 ('r', 'rev', [], _('search in given revision range')),
2789 ('u', 'user', None, _('print user who committed change')),
2792 ('u', 'user', None, _('print user who committed change')),
2790 ] + walkopts,
2793 ] + walkopts,
2791 _('hg grep [OPTION]... PATTERN [FILE]...')),
2794 _('hg grep [OPTION]... PATTERN [FILE]...')),
2792 "heads":
2795 "heads":
2793 (heads,
2796 (heads,
2794 [('', 'style', '', _('display using template map file')),
2797 [('', 'style', '', _('display using template map file')),
2795 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2798 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2796 ('', 'template', '', _('display with template'))],
2799 ('', 'template', '', _('display with template'))],
2797 _('hg heads [-r REV]')),
2800 _('hg heads [-r REV]')),
2798 "help": (help_, [], _('hg help [COMMAND]')),
2801 "help": (help_, [], _('hg help [COMMAND]')),
2799 "identify|id": (identify, [], _('hg identify')),
2802 "identify|id": (identify, [], _('hg identify')),
2800 "import|patch":
2803 "import|patch":
2801 (import_,
2804 (import_,
2802 [('p', 'strip', 1,
2805 [('p', 'strip', 1,
2803 _('directory strip option for patch. This has the same\n'
2806 _('directory strip option for patch. This has the same\n'
2804 'meaning as the corresponding patch option')),
2807 'meaning as the corresponding patch option')),
2805 ('b', 'base', '', _('base path')),
2808 ('b', 'base', '', _('base path')),
2806 ('f', 'force', None,
2809 ('f', 'force', None,
2807 _('skip check for outstanding uncommitted changes')),
2810 _('skip check for outstanding uncommitted changes')),
2808 ('', 'exact', None,
2811 ('', 'exact', None,
2809 _('apply patch to the nodes from which it was generated'))] + commitopts,
2812 _('apply patch to the nodes from which it was generated'))] + commitopts,
2810 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2813 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2811 "incoming|in": (incoming,
2814 "incoming|in": (incoming,
2812 [('M', 'no-merges', None, _('do not show merges')),
2815 [('M', 'no-merges', None, _('do not show merges')),
2813 ('f', 'force', None,
2816 ('f', 'force', None,
2814 _('run even when remote repository is unrelated')),
2817 _('run even when remote repository is unrelated')),
2815 ('', 'style', '', _('display using template map file')),
2818 ('', 'style', '', _('display using template map file')),
2816 ('n', 'newest-first', None, _('show newest record first')),
2819 ('n', 'newest-first', None, _('show newest record first')),
2817 ('', 'bundle', '', _('file to store the bundles into')),
2820 ('', 'bundle', '', _('file to store the bundles into')),
2818 ('p', 'patch', None, _('show patch')),
2821 ('p', 'patch', None, _('show patch')),
2819 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2822 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2820 ('', 'template', '', _('display with template')),
2823 ('', 'template', '', _('display with template')),
2821 ] + remoteopts,
2824 ] + remoteopts,
2822 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2825 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2823 ' [--bundle FILENAME] [SOURCE]')),
2826 ' [--bundle FILENAME] [SOURCE]')),
2824 "^init":
2827 "^init":
2825 (init,
2828 (init,
2826 remoteopts,
2829 remoteopts,
2827 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2830 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2828 "locate":
2831 "locate":
2829 (locate,
2832 (locate,
2830 [('r', 'rev', '', _('search the repository as it stood at rev')),
2833 [('r', 'rev', '', _('search the repository as it stood at rev')),
2831 ('0', 'print0', None,
2834 ('0', 'print0', None,
2832 _('end filenames with NUL, for use with xargs')),
2835 _('end filenames with NUL, for use with xargs')),
2833 ('f', 'fullpath', None,
2836 ('f', 'fullpath', None,
2834 _('print complete paths from the filesystem root')),
2837 _('print complete paths from the filesystem root')),
2835 ] + walkopts,
2838 ] + walkopts,
2836 _('hg locate [OPTION]... [PATTERN]...')),
2839 _('hg locate [OPTION]... [PATTERN]...')),
2837 "^log|history":
2840 "^log|history":
2838 (log,
2841 (log,
2839 [('f', 'follow', None,
2842 [('f', 'follow', None,
2840 _('follow changeset history, or file history across copies and renames')),
2843 _('follow changeset history, or file history across copies and renames')),
2841 ('', 'follow-first', None,
2844 ('', 'follow-first', None,
2842 _('only follow the first parent of merge changesets')),
2845 _('only follow the first parent of merge changesets')),
2843 ('d', 'date', '', _('show revs matching date spec')),
2846 ('d', 'date', '', _('show revs matching date spec')),
2844 ('C', 'copies', None, _('show copied files')),
2847 ('C', 'copies', None, _('show copied files')),
2845 ('k', 'keyword', [], _('search for a keyword')),
2848 ('k', 'keyword', [], _('search for a keyword')),
2846 ('l', 'limit', '', _('limit number of changes displayed')),
2849 ('l', 'limit', '', _('limit number of changes displayed')),
2847 ('r', 'rev', [], _('show the specified revision or range')),
2850 ('r', 'rev', [], _('show the specified revision or range')),
2848 ('', 'removed', None, _('include revs where files were removed')),
2851 ('', 'removed', None, _('include revs where files were removed')),
2849 ('M', 'no-merges', None, _('do not show merges')),
2852 ('M', 'no-merges', None, _('do not show merges')),
2850 ('', 'style', '', _('display using template map file')),
2853 ('', 'style', '', _('display using template map file')),
2851 ('m', 'only-merges', None, _('show only merges')),
2854 ('m', 'only-merges', None, _('show only merges')),
2852 ('p', 'patch', None, _('show patch')),
2855 ('p', 'patch', None, _('show patch')),
2853 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2856 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2854 ('', 'template', '', _('display with template')),
2857 ('', 'template', '', _('display with template')),
2855 ] + walkopts,
2858 ] + walkopts,
2856 _('hg log [OPTION]... [FILE]')),
2859 _('hg log [OPTION]... [FILE]')),
2857 "manifest": (manifest, [], _('hg manifest [REV]')),
2860 "manifest": (manifest, [], _('hg manifest [REV]')),
2858 "^merge":
2861 "^merge":
2859 (merge,
2862 (merge,
2860 [('f', 'force', None, _('force a merge with outstanding changes'))],
2863 [('f', 'force', None, _('force a merge with outstanding changes'))],
2861 _('hg merge [-f] [REV]')),
2864 _('hg merge [-f] [REV]')),
2862 "outgoing|out": (outgoing,
2865 "outgoing|out": (outgoing,
2863 [('M', 'no-merges', None, _('do not show merges')),
2866 [('M', 'no-merges', None, _('do not show merges')),
2864 ('f', 'force', None,
2867 ('f', 'force', None,
2865 _('run even when remote repository is unrelated')),
2868 _('run even when remote repository is unrelated')),
2866 ('p', 'patch', None, _('show patch')),
2869 ('p', 'patch', None, _('show patch')),
2867 ('', 'style', '', _('display using template map file')),
2870 ('', 'style', '', _('display using template map file')),
2868 ('r', 'rev', [], _('a specific revision you would like to push')),
2871 ('r', 'rev', [], _('a specific revision you would like to push')),
2869 ('n', 'newest-first', None, _('show newest record first')),
2872 ('n', 'newest-first', None, _('show newest record first')),
2870 ('', 'template', '', _('display with template')),
2873 ('', 'template', '', _('display with template')),
2871 ] + remoteopts,
2874 ] + remoteopts,
2872 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2875 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2873 "^parents":
2876 "^parents":
2874 (parents,
2877 (parents,
2875 [('r', 'rev', '', _('show parents from the specified rev')),
2878 [('r', 'rev', '', _('show parents from the specified rev')),
2876 ('', 'style', '', _('display using template map file')),
2879 ('', 'style', '', _('display using template map file')),
2877 ('', 'template', '', _('display with template'))],
2880 ('', 'template', '', _('display with template'))],
2878 _('hg parents [-r REV] [FILE]')),
2881 _('hg parents [-r REV] [FILE]')),
2879 "paths": (paths, [], _('hg paths [NAME]')),
2882 "paths": (paths, [], _('hg paths [NAME]')),
2880 "^pull":
2883 "^pull":
2881 (pull,
2884 (pull,
2882 [('u', 'update', None,
2885 [('u', 'update', None,
2883 _('update to new tip if changesets were pulled')),
2886 _('update to new tip if changesets were pulled')),
2884 ('f', 'force', None,
2887 ('f', 'force', None,
2885 _('run even when remote repository is unrelated')),
2888 _('run even when remote repository is unrelated')),
2886 ('r', 'rev', [],
2889 ('r', 'rev', [],
2887 _('a specific revision up to which you would like to pull')),
2890 _('a specific revision up to which you would like to pull')),
2888 ] + remoteopts,
2891 ] + remoteopts,
2889 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2892 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2890 "^push":
2893 "^push":
2891 (push,
2894 (push,
2892 [('f', 'force', None, _('force push')),
2895 [('f', 'force', None, _('force push')),
2893 ('r', 'rev', [], _('a specific revision you would like to push')),
2896 ('r', 'rev', [], _('a specific revision you would like to push')),
2894 ] + remoteopts,
2897 ] + remoteopts,
2895 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2898 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2896 "debugrawcommit|rawcommit":
2899 "debugrawcommit|rawcommit":
2897 (rawcommit,
2900 (rawcommit,
2898 [('p', 'parent', [], _('parent')),
2901 [('p', 'parent', [], _('parent')),
2899 ('d', 'date', '', _('date code')),
2902 ('d', 'date', '', _('date code')),
2900 ('u', 'user', '', _('user')),
2903 ('u', 'user', '', _('user')),
2901 ('F', 'files', '', _('file list'))
2904 ('F', 'files', '', _('file list'))
2902 ] + commitopts,
2905 ] + commitopts,
2903 _('hg debugrawcommit [OPTION]... [FILE]...')),
2906 _('hg debugrawcommit [OPTION]... [FILE]...')),
2904 "recover": (recover, [], _('hg recover')),
2907 "recover": (recover, [], _('hg recover')),
2905 "^remove|rm":
2908 "^remove|rm":
2906 (remove,
2909 (remove,
2907 [('A', 'after', None, _('record remove that has already occurred')),
2910 [('A', 'after', None, _('record remove that has already occurred')),
2908 ('f', 'force', None, _('remove file even if modified')),
2911 ('f', 'force', None, _('remove file even if modified')),
2909 ] + walkopts,
2912 ] + walkopts,
2910 _('hg remove [OPTION]... FILE...')),
2913 _('hg remove [OPTION]... FILE...')),
2911 "rename|mv":
2914 "rename|mv":
2912 (rename,
2915 (rename,
2913 [('A', 'after', None, _('record a rename that has already occurred')),
2916 [('A', 'after', None, _('record a rename that has already occurred')),
2914 ('f', 'force', None,
2917 ('f', 'force', None,
2915 _('forcibly copy over an existing managed file')),
2918 _('forcibly copy over an existing managed file')),
2916 ] + walkopts + dryrunopts,
2919 ] + walkopts + dryrunopts,
2917 _('hg rename [OPTION]... SOURCE... DEST')),
2920 _('hg rename [OPTION]... SOURCE... DEST')),
2918 "^revert":
2921 "^revert":
2919 (revert,
2922 (revert,
2920 [('a', 'all', None, _('revert all changes when no arguments given')),
2923 [('a', 'all', None, _('revert all changes when no arguments given')),
2921 ('d', 'date', '', _('tipmost revision matching date')),
2924 ('d', 'date', '', _('tipmost revision matching date')),
2922 ('r', 'rev', '', _('revision to revert to')),
2925 ('r', 'rev', '', _('revision to revert to')),
2923 ('', 'no-backup', None, _('do not save backup copies of files')),
2926 ('', 'no-backup', None, _('do not save backup copies of files')),
2924 ] + walkopts + dryrunopts,
2927 ] + walkopts + dryrunopts,
2925 _('hg revert [OPTION]... [-r REV] [NAME]...')),
2928 _('hg revert [OPTION]... [-r REV] [NAME]...')),
2926 "rollback": (rollback, [], _('hg rollback')),
2929 "rollback": (rollback, [], _('hg rollback')),
2927 "root": (root, [], _('hg root')),
2930 "root": (root, [], _('hg root')),
2928 "showconfig|debugconfig":
2931 "showconfig|debugconfig":
2929 (showconfig,
2932 (showconfig,
2930 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2933 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2931 _('showconfig [-u] [NAME]...')),
2934 _('showconfig [-u] [NAME]...')),
2932 "^serve":
2935 "^serve":
2933 (serve,
2936 (serve,
2934 [('A', 'accesslog', '', _('name of access log file to write to')),
2937 [('A', 'accesslog', '', _('name of access log file to write to')),
2935 ('d', 'daemon', None, _('run server in background')),
2938 ('d', 'daemon', None, _('run server in background')),
2936 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2939 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2937 ('E', 'errorlog', '', _('name of error log file to write to')),
2940 ('E', 'errorlog', '', _('name of error log file to write to')),
2938 ('p', 'port', 0, _('port to use (default: 8000)')),
2941 ('p', 'port', 0, _('port to use (default: 8000)')),
2939 ('a', 'address', '', _('address to use')),
2942 ('a', 'address', '', _('address to use')),
2940 ('n', 'name', '',
2943 ('n', 'name', '',
2941 _('name to show in web pages (default: working dir)')),
2944 _('name to show in web pages (default: working dir)')),
2942 ('', 'webdir-conf', '', _('name of the webdir config file'
2945 ('', 'webdir-conf', '', _('name of the webdir config file'
2943 ' (serve more than one repo)')),
2946 ' (serve more than one repo)')),
2944 ('', 'pid-file', '', _('name of file to write process ID to')),
2947 ('', 'pid-file', '', _('name of file to write process ID to')),
2945 ('', 'stdio', None, _('for remote clients')),
2948 ('', 'stdio', None, _('for remote clients')),
2946 ('t', 'templates', '', _('web templates to use')),
2949 ('t', 'templates', '', _('web templates to use')),
2947 ('', 'style', '', _('template style to use')),
2950 ('', 'style', '', _('template style to use')),
2948 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2951 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2949 _('hg serve [OPTION]...')),
2952 _('hg serve [OPTION]...')),
2950 "^status|st":
2953 "^status|st":
2951 (status,
2954 (status,
2952 [('A', 'all', None, _('show status of all files')),
2955 [('A', 'all', None, _('show status of all files')),
2953 ('m', 'modified', None, _('show only modified files')),
2956 ('m', 'modified', None, _('show only modified files')),
2954 ('a', 'added', None, _('show only added files')),
2957 ('a', 'added', None, _('show only added files')),
2955 ('r', 'removed', None, _('show only removed files')),
2958 ('r', 'removed', None, _('show only removed files')),
2956 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2959 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2957 ('c', 'clean', None, _('show only files without changes')),
2960 ('c', 'clean', None, _('show only files without changes')),
2958 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2961 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2959 ('i', 'ignored', None, _('show only ignored files')),
2962 ('i', 'ignored', None, _('show only ignored files')),
2960 ('n', 'no-status', None, _('hide status prefix')),
2963 ('n', 'no-status', None, _('hide status prefix')),
2961 ('C', 'copies', None, _('show source of copied files')),
2964 ('C', 'copies', None, _('show source of copied files')),
2962 ('0', 'print0', None,
2965 ('0', 'print0', None,
2963 _('end filenames with NUL, for use with xargs')),
2966 _('end filenames with NUL, for use with xargs')),
2964 ('', 'rev', [], _('show difference from revision')),
2967 ('', 'rev', [], _('show difference from revision')),
2965 ] + walkopts,
2968 ] + walkopts,
2966 _('hg status [OPTION]... [FILE]...')),
2969 _('hg status [OPTION]... [FILE]...')),
2967 "tag":
2970 "tag":
2968 (tag,
2971 (tag,
2969 [('f', 'force', None, _('replace existing tag')),
2972 [('f', 'force', None, _('replace existing tag')),
2970 ('l', 'local', None, _('make the tag local')),
2973 ('l', 'local', None, _('make the tag local')),
2971 ('m', 'message', '', _('message for tag commit log entry')),
2974 ('m', 'message', '', _('message for tag commit log entry')),
2972 ('d', 'date', '', _('record datecode as commit date')),
2975 ('d', 'date', '', _('record datecode as commit date')),
2973 ('u', 'user', '', _('record user as commiter')),
2976 ('u', 'user', '', _('record user as commiter')),
2974 ('r', 'rev', '', _('revision to tag')),
2977 ('r', 'rev', '', _('revision to tag')),
2975 ('', 'remove', None, _('remove a tag'))],
2978 ('', 'remove', None, _('remove a tag'))],
2976 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2979 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2977 "tags": (tags, [], _('hg tags')),
2980 "tags": (tags, [], _('hg tags')),
2978 "tip":
2981 "tip":
2979 (tip,
2982 (tip,
2980 [('', 'style', '', _('display using template map file')),
2983 [('', 'style', '', _('display using template map file')),
2981 ('p', 'patch', None, _('show patch')),
2984 ('p', 'patch', None, _('show patch')),
2982 ('', 'template', '', _('display with template'))],
2985 ('', 'template', '', _('display with template'))],
2983 _('hg tip [-p]')),
2986 _('hg tip [-p]')),
2984 "unbundle":
2987 "unbundle":
2985 (unbundle,
2988 (unbundle,
2986 [('u', 'update', None,
2989 [('u', 'update', None,
2987 _('update to new tip if changesets were unbundled'))],
2990 _('update to new tip if changesets were unbundled'))],
2988 _('hg unbundle [-u] FILE')),
2991 _('hg unbundle [-u] FILE')),
2989 "^update|up|checkout|co":
2992 "^update|up|checkout|co":
2990 (update,
2993 (update,
2991 [('C', 'clean', None, _('overwrite locally modified files')),
2994 [('C', 'clean', None, _('overwrite locally modified files')),
2992 ('d', 'date', '', _('tipmost revision matching date'))],
2995 ('d', 'date', '', _('tipmost revision matching date'))],
2993 _('hg update [-C] [-d DATE] [REV]')),
2996 _('hg update [-C] [-d DATE] [REV]')),
2994 "verify": (verify, [], _('hg verify')),
2997 "verify": (verify, [], _('hg verify')),
2995 "version": (version_, [], _('hg version')),
2998 "version": (version_, [], _('hg version')),
2996 }
2999 }
2997
3000
2998 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3001 norepo = ("clone init version help debugancestor debugcomplete debugdata"
2999 " debugindex debugindexdot debugdate debuginstall")
3002 " debugindex debugindexdot debugdate debuginstall")
3000 optionalrepo = ("paths serve showconfig")
3003 optionalrepo = ("paths serve showconfig")
3001
3004
3002 def findpossible(ui, cmd):
3005 def findpossible(ui, cmd):
3003 """
3006 """
3004 Return cmd -> (aliases, command table entry)
3007 Return cmd -> (aliases, command table entry)
3005 for each matching command.
3008 for each matching command.
3006 Return debug commands (or their aliases) only if no normal command matches.
3009 Return debug commands (or their aliases) only if no normal command matches.
3007 """
3010 """
3008 choice = {}
3011 choice = {}
3009 debugchoice = {}
3012 debugchoice = {}
3010 for e in table.keys():
3013 for e in table.keys():
3011 aliases = e.lstrip("^").split("|")
3014 aliases = e.lstrip("^").split("|")
3012 found = None
3015 found = None
3013 if cmd in aliases:
3016 if cmd in aliases:
3014 found = cmd
3017 found = cmd
3015 elif not ui.config("ui", "strict"):
3018 elif not ui.config("ui", "strict"):
3016 for a in aliases:
3019 for a in aliases:
3017 if a.startswith(cmd):
3020 if a.startswith(cmd):
3018 found = a
3021 found = a
3019 break
3022 break
3020 if found is not None:
3023 if found is not None:
3021 if aliases[0].startswith("debug") or found.startswith("debug"):
3024 if aliases[0].startswith("debug") or found.startswith("debug"):
3022 debugchoice[found] = (aliases, table[e])
3025 debugchoice[found] = (aliases, table[e])
3023 else:
3026 else:
3024 choice[found] = (aliases, table[e])
3027 choice[found] = (aliases, table[e])
3025
3028
3026 if not choice and debugchoice:
3029 if not choice and debugchoice:
3027 choice = debugchoice
3030 choice = debugchoice
3028
3031
3029 return choice
3032 return choice
3030
3033
3031 def findcmd(ui, cmd):
3034 def findcmd(ui, cmd):
3032 """Return (aliases, command table entry) for command string."""
3035 """Return (aliases, command table entry) for command string."""
3033 choice = findpossible(ui, cmd)
3036 choice = findpossible(ui, cmd)
3034
3037
3035 if choice.has_key(cmd):
3038 if choice.has_key(cmd):
3036 return choice[cmd]
3039 return choice[cmd]
3037
3040
3038 if len(choice) > 1:
3041 if len(choice) > 1:
3039 clist = choice.keys()
3042 clist = choice.keys()
3040 clist.sort()
3043 clist.sort()
3041 raise AmbiguousCommand(cmd, clist)
3044 raise AmbiguousCommand(cmd, clist)
3042
3045
3043 if choice:
3046 if choice:
3044 return choice.values()[0]
3047 return choice.values()[0]
3045
3048
3046 raise UnknownCommand(cmd)
3049 raise UnknownCommand(cmd)
3047
3050
3048 def catchterm(*args):
3051 def catchterm(*args):
3049 raise util.SignalInterrupt
3052 raise util.SignalInterrupt
3050
3053
3051 def run():
3054 def run():
3052 sys.exit(dispatch(sys.argv[1:]))
3055 sys.exit(dispatch(sys.argv[1:]))
3053
3056
3054 class ParseError(Exception):
3057 class ParseError(Exception):
3055 """Exception raised on errors in parsing the command line."""
3058 """Exception raised on errors in parsing the command line."""
3056
3059
3057 def parse(ui, args):
3060 def parse(ui, args):
3058 options = {}
3061 options = {}
3059 cmdoptions = {}
3062 cmdoptions = {}
3060
3063
3061 try:
3064 try:
3062 args = fancyopts.fancyopts(args, globalopts, options)
3065 args = fancyopts.fancyopts(args, globalopts, options)
3063 except fancyopts.getopt.GetoptError, inst:
3066 except fancyopts.getopt.GetoptError, inst:
3064 raise ParseError(None, inst)
3067 raise ParseError(None, inst)
3065
3068
3066 if args:
3069 if args:
3067 cmd, args = args[0], args[1:]
3070 cmd, args = args[0], args[1:]
3068 aliases, i = findcmd(ui, cmd)
3071 aliases, i = findcmd(ui, cmd)
3069 cmd = aliases[0]
3072 cmd = aliases[0]
3070 defaults = ui.config("defaults", cmd)
3073 defaults = ui.config("defaults", cmd)
3071 if defaults:
3074 if defaults:
3072 args = shlex.split(defaults) + args
3075 args = shlex.split(defaults) + args
3073 c = list(i[1])
3076 c = list(i[1])
3074 else:
3077 else:
3075 cmd = None
3078 cmd = None
3076 c = []
3079 c = []
3077
3080
3078 # combine global options into local
3081 # combine global options into local
3079 for o in globalopts:
3082 for o in globalopts:
3080 c.append((o[0], o[1], options[o[1]], o[3]))
3083 c.append((o[0], o[1], options[o[1]], o[3]))
3081
3084
3082 try:
3085 try:
3083 args = fancyopts.fancyopts(args, c, cmdoptions)
3086 args = fancyopts.fancyopts(args, c, cmdoptions)
3084 except fancyopts.getopt.GetoptError, inst:
3087 except fancyopts.getopt.GetoptError, inst:
3085 raise ParseError(cmd, inst)
3088 raise ParseError(cmd, inst)
3086
3089
3087 # separate global options back out
3090 # separate global options back out
3088 for o in globalopts:
3091 for o in globalopts:
3089 n = o[1]
3092 n = o[1]
3090 options[n] = cmdoptions[n]
3093 options[n] = cmdoptions[n]
3091 del cmdoptions[n]
3094 del cmdoptions[n]
3092
3095
3093 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3096 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3094
3097
3095 external = {}
3098 external = {}
3096
3099
3097 def findext(name):
3100 def findext(name):
3098 '''return module with given extension name'''
3101 '''return module with given extension name'''
3099 try:
3102 try:
3100 return sys.modules[external[name]]
3103 return sys.modules[external[name]]
3101 except KeyError:
3104 except KeyError:
3102 for k, v in external.iteritems():
3105 for k, v in external.iteritems():
3103 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3106 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3104 return sys.modules[v]
3107 return sys.modules[v]
3105 raise KeyError(name)
3108 raise KeyError(name)
3106
3109
3107 def load_extensions(ui):
3110 def load_extensions(ui):
3108 added = []
3111 added = []
3109 for ext_name, load_from_name in ui.extensions():
3112 for ext_name, load_from_name in ui.extensions():
3110 if ext_name in external:
3113 if ext_name in external:
3111 continue
3114 continue
3112 try:
3115 try:
3113 if load_from_name:
3116 if load_from_name:
3114 # the module will be loaded in sys.modules
3117 # the module will be loaded in sys.modules
3115 # choose an unique name so that it doesn't
3118 # choose an unique name so that it doesn't
3116 # conflicts with other modules
3119 # conflicts with other modules
3117 module_name = "hgext_%s" % ext_name.replace('.', '_')
3120 module_name = "hgext_%s" % ext_name.replace('.', '_')
3118 mod = imp.load_source(module_name, load_from_name)
3121 mod = imp.load_source(module_name, load_from_name)
3119 else:
3122 else:
3120 def importh(name):
3123 def importh(name):
3121 mod = __import__(name)
3124 mod = __import__(name)
3122 components = name.split('.')
3125 components = name.split('.')
3123 for comp in components[1:]:
3126 for comp in components[1:]:
3124 mod = getattr(mod, comp)
3127 mod = getattr(mod, comp)
3125 return mod
3128 return mod
3126 try:
3129 try:
3127 mod = importh("hgext.%s" % ext_name)
3130 mod = importh("hgext.%s" % ext_name)
3128 except ImportError:
3131 except ImportError:
3129 mod = importh(ext_name)
3132 mod = importh(ext_name)
3130 external[ext_name] = mod.__name__
3133 external[ext_name] = mod.__name__
3131 added.append((mod, ext_name))
3134 added.append((mod, ext_name))
3132 except (util.SignalInterrupt, KeyboardInterrupt):
3135 except (util.SignalInterrupt, KeyboardInterrupt):
3133 raise
3136 raise
3134 except Exception, inst:
3137 except Exception, inst:
3135 ui.warn(_("*** failed to import extension %s: %s\n") %
3138 ui.warn(_("*** failed to import extension %s: %s\n") %
3136 (ext_name, inst))
3139 (ext_name, inst))
3137 if ui.print_exc():
3140 if ui.print_exc():
3138 return 1
3141 return 1
3139
3142
3140 for mod, name in added:
3143 for mod, name in added:
3141 uisetup = getattr(mod, 'uisetup', None)
3144 uisetup = getattr(mod, 'uisetup', None)
3142 if uisetup:
3145 if uisetup:
3143 uisetup(ui)
3146 uisetup(ui)
3144 reposetup = getattr(mod, 'reposetup', None)
3147 reposetup = getattr(mod, 'reposetup', None)
3145 if reposetup:
3148 if reposetup:
3146 hg.repo_setup_hooks.append(reposetup)
3149 hg.repo_setup_hooks.append(reposetup)
3147 cmdtable = getattr(mod, 'cmdtable', {})
3150 cmdtable = getattr(mod, 'cmdtable', {})
3148 overrides = [cmd for cmd in cmdtable if cmd in table]
3151 overrides = [cmd for cmd in cmdtable if cmd in table]
3149 if overrides:
3152 if overrides:
3150 ui.warn(_("extension '%s' overrides commands: %s\n")
3153 ui.warn(_("extension '%s' overrides commands: %s\n")
3151 % (name, " ".join(overrides)))
3154 % (name, " ".join(overrides)))
3152 table.update(cmdtable)
3155 table.update(cmdtable)
3153
3156
3154 def parseconfig(config):
3157 def parseconfig(config):
3155 """parse the --config options from the command line"""
3158 """parse the --config options from the command line"""
3156 parsed = []
3159 parsed = []
3157 for cfg in config:
3160 for cfg in config:
3158 try:
3161 try:
3159 name, value = cfg.split('=', 1)
3162 name, value = cfg.split('=', 1)
3160 section, name = name.split('.', 1)
3163 section, name = name.split('.', 1)
3161 if not section or not name:
3164 if not section or not name:
3162 raise IndexError
3165 raise IndexError
3163 parsed.append((section, name, value))
3166 parsed.append((section, name, value))
3164 except (IndexError, ValueError):
3167 except (IndexError, ValueError):
3165 raise util.Abort(_('malformed --config option: %s') % cfg)
3168 raise util.Abort(_('malformed --config option: %s') % cfg)
3166 return parsed
3169 return parsed
3167
3170
3168 def dispatch(args):
3171 def dispatch(args):
3169 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3172 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3170 num = getattr(signal, name, None)
3173 num = getattr(signal, name, None)
3171 if num: signal.signal(num, catchterm)
3174 if num: signal.signal(num, catchterm)
3172
3175
3173 try:
3176 try:
3174 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3177 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3175 except util.Abort, inst:
3178 except util.Abort, inst:
3176 sys.stderr.write(_("abort: %s\n") % inst)
3179 sys.stderr.write(_("abort: %s\n") % inst)
3177 return -1
3180 return -1
3178
3181
3179 load_extensions(u)
3182 load_extensions(u)
3180 u.addreadhook(load_extensions)
3183 u.addreadhook(load_extensions)
3181
3184
3182 try:
3185 try:
3183 cmd, func, args, options, cmdoptions = parse(u, args)
3186 cmd, func, args, options, cmdoptions = parse(u, args)
3184 if options["encoding"]:
3187 if options["encoding"]:
3185 util._encoding = options["encoding"]
3188 util._encoding = options["encoding"]
3186 if options["encodingmode"]:
3189 if options["encodingmode"]:
3187 util._encodingmode = options["encodingmode"]
3190 util._encodingmode = options["encodingmode"]
3188 if options["time"]:
3191 if options["time"]:
3189 def get_times():
3192 def get_times():
3190 t = os.times()
3193 t = os.times()
3191 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3194 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3192 t = (t[0], t[1], t[2], t[3], time.clock())
3195 t = (t[0], t[1], t[2], t[3], time.clock())
3193 return t
3196 return t
3194 s = get_times()
3197 s = get_times()
3195 def print_time():
3198 def print_time():
3196 t = get_times()
3199 t = get_times()
3197 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3200 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3198 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3201 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3199 atexit.register(print_time)
3202 atexit.register(print_time)
3200
3203
3201 # enter the debugger before command execution
3204 # enter the debugger before command execution
3202 if options['debugger']:
3205 if options['debugger']:
3203 pdb.set_trace()
3206 pdb.set_trace()
3204
3207
3205 try:
3208 try:
3206 if options['cwd']:
3209 if options['cwd']:
3207 os.chdir(options['cwd'])
3210 os.chdir(options['cwd'])
3208
3211
3209 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3212 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3210 not options["noninteractive"], options["traceback"],
3213 not options["noninteractive"], options["traceback"],
3211 parseconfig(options["config"]))
3214 parseconfig(options["config"]))
3212
3215
3213 path = u.expandpath(options["repository"]) or ""
3216 path = u.expandpath(options["repository"]) or ""
3214 repo = path and hg.repository(u, path=path) or None
3217 repo = path and hg.repository(u, path=path) or None
3215 if repo and not repo.local():
3218 if repo and not repo.local():
3216 raise util.Abort(_("repository '%s' is not local") % path)
3219 raise util.Abort(_("repository '%s' is not local") % path)
3217
3220
3218 if options['help']:
3221 if options['help']:
3219 return help_(u, cmd, options['version'])
3222 return help_(u, cmd, options['version'])
3220 elif options['version']:
3223 elif options['version']:
3221 return version_(u)
3224 return version_(u)
3222 elif not cmd:
3225 elif not cmd:
3223 return help_(u, 'shortlist')
3226 return help_(u, 'shortlist')
3224
3227
3225 if cmd not in norepo.split():
3228 if cmd not in norepo.split():
3226 try:
3229 try:
3227 if not repo:
3230 if not repo:
3228 repo = hg.repository(u, path=path)
3231 repo = hg.repository(u, path=path)
3229 u = repo.ui
3232 u = repo.ui
3230 except hg.RepoError:
3233 except hg.RepoError:
3231 if cmd not in optionalrepo.split():
3234 if cmd not in optionalrepo.split():
3232 raise
3235 raise
3233 d = lambda: func(u, repo, *args, **cmdoptions)
3236 d = lambda: func(u, repo, *args, **cmdoptions)
3234 else:
3237 else:
3235 d = lambda: func(u, *args, **cmdoptions)
3238 d = lambda: func(u, *args, **cmdoptions)
3236
3239
3237 try:
3240 try:
3238 if options['profile']:
3241 if options['profile']:
3239 import hotshot, hotshot.stats
3242 import hotshot, hotshot.stats
3240 prof = hotshot.Profile("hg.prof")
3243 prof = hotshot.Profile("hg.prof")
3241 try:
3244 try:
3242 try:
3245 try:
3243 return prof.runcall(d)
3246 return prof.runcall(d)
3244 except:
3247 except:
3245 try:
3248 try:
3246 u.warn(_('exception raised - generating '
3249 u.warn(_('exception raised - generating '
3247 'profile anyway\n'))
3250 'profile anyway\n'))
3248 except:
3251 except:
3249 pass
3252 pass
3250 raise
3253 raise
3251 finally:
3254 finally:
3252 prof.close()
3255 prof.close()
3253 stats = hotshot.stats.load("hg.prof")
3256 stats = hotshot.stats.load("hg.prof")
3254 stats.strip_dirs()
3257 stats.strip_dirs()
3255 stats.sort_stats('time', 'calls')
3258 stats.sort_stats('time', 'calls')
3256 stats.print_stats(40)
3259 stats.print_stats(40)
3257 elif options['lsprof']:
3260 elif options['lsprof']:
3258 try:
3261 try:
3259 from mercurial import lsprof
3262 from mercurial import lsprof
3260 except ImportError:
3263 except ImportError:
3261 raise util.Abort(_(
3264 raise util.Abort(_(
3262 'lsprof not available - install from '
3265 'lsprof not available - install from '
3263 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3266 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3264 p = lsprof.Profiler()
3267 p = lsprof.Profiler()
3265 p.enable(subcalls=True)
3268 p.enable(subcalls=True)
3266 try:
3269 try:
3267 return d()
3270 return d()
3268 finally:
3271 finally:
3269 p.disable()
3272 p.disable()
3270 stats = lsprof.Stats(p.getstats())
3273 stats = lsprof.Stats(p.getstats())
3271 stats.sort()
3274 stats.sort()
3272 stats.pprint(top=10, file=sys.stderr, climit=5)
3275 stats.pprint(top=10, file=sys.stderr, climit=5)
3273 else:
3276 else:
3274 return d()
3277 return d()
3275 finally:
3278 finally:
3276 u.flush()
3279 u.flush()
3277 except:
3280 except:
3278 # enter the debugger when we hit an exception
3281 # enter the debugger when we hit an exception
3279 if options['debugger']:
3282 if options['debugger']:
3280 pdb.post_mortem(sys.exc_info()[2])
3283 pdb.post_mortem(sys.exc_info()[2])
3281 u.print_exc()
3284 u.print_exc()
3282 raise
3285 raise
3283 except ParseError, inst:
3286 except ParseError, inst:
3284 if inst.args[0]:
3287 if inst.args[0]:
3285 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3288 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3286 help_(u, inst.args[0])
3289 help_(u, inst.args[0])
3287 else:
3290 else:
3288 u.warn(_("hg: %s\n") % inst.args[1])
3291 u.warn(_("hg: %s\n") % inst.args[1])
3289 help_(u, 'shortlist')
3292 help_(u, 'shortlist')
3290 except AmbiguousCommand, inst:
3293 except AmbiguousCommand, inst:
3291 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3294 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3292 (inst.args[0], " ".join(inst.args[1])))
3295 (inst.args[0], " ".join(inst.args[1])))
3293 except UnknownCommand, inst:
3296 except UnknownCommand, inst:
3294 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3297 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3295 help_(u, 'shortlist')
3298 help_(u, 'shortlist')
3296 except hg.RepoError, inst:
3299 except hg.RepoError, inst:
3297 u.warn(_("abort: %s!\n") % inst)
3300 u.warn(_("abort: %s!\n") % inst)
3298 except lock.LockHeld, inst:
3301 except lock.LockHeld, inst:
3299 if inst.errno == errno.ETIMEDOUT:
3302 if inst.errno == errno.ETIMEDOUT:
3300 reason = _('timed out waiting for lock held by %s') % inst.locker
3303 reason = _('timed out waiting for lock held by %s') % inst.locker
3301 else:
3304 else:
3302 reason = _('lock held by %s') % inst.locker
3305 reason = _('lock held by %s') % inst.locker
3303 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3306 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3304 except lock.LockUnavailable, inst:
3307 except lock.LockUnavailable, inst:
3305 u.warn(_("abort: could not lock %s: %s\n") %
3308 u.warn(_("abort: could not lock %s: %s\n") %
3306 (inst.desc or inst.filename, inst.strerror))
3309 (inst.desc or inst.filename, inst.strerror))
3307 except revlog.RevlogError, inst:
3310 except revlog.RevlogError, inst:
3308 u.warn(_("abort: %s!\n") % inst)
3311 u.warn(_("abort: %s!\n") % inst)
3309 except util.SignalInterrupt:
3312 except util.SignalInterrupt:
3310 u.warn(_("killed!\n"))
3313 u.warn(_("killed!\n"))
3311 except KeyboardInterrupt:
3314 except KeyboardInterrupt:
3312 try:
3315 try:
3313 u.warn(_("interrupted!\n"))
3316 u.warn(_("interrupted!\n"))
3314 except IOError, inst:
3317 except IOError, inst:
3315 if inst.errno == errno.EPIPE:
3318 if inst.errno == errno.EPIPE:
3316 if u.debugflag:
3319 if u.debugflag:
3317 u.warn(_("\nbroken pipe\n"))
3320 u.warn(_("\nbroken pipe\n"))
3318 else:
3321 else:
3319 raise
3322 raise
3320 except socket.error, inst:
3323 except socket.error, inst:
3321 u.warn(_("abort: %s\n") % inst[1])
3324 u.warn(_("abort: %s\n") % inst[1])
3322 except IOError, inst:
3325 except IOError, inst:
3323 if hasattr(inst, "code"):
3326 if hasattr(inst, "code"):
3324 u.warn(_("abort: %s\n") % inst)
3327 u.warn(_("abort: %s\n") % inst)
3325 elif hasattr(inst, "reason"):
3328 elif hasattr(inst, "reason"):
3326 try: # usually it is in the form (errno, strerror)
3329 try: # usually it is in the form (errno, strerror)
3327 reason = inst.reason.args[1]
3330 reason = inst.reason.args[1]
3328 except: # it might be anything, for example a string
3331 except: # it might be anything, for example a string
3329 reason = inst.reason
3332 reason = inst.reason
3330 u.warn(_("abort: error: %s\n") % reason)
3333 u.warn(_("abort: error: %s\n") % reason)
3331 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3334 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3332 if u.debugflag:
3335 if u.debugflag:
3333 u.warn(_("broken pipe\n"))
3336 u.warn(_("broken pipe\n"))
3334 elif getattr(inst, "strerror", None):
3337 elif getattr(inst, "strerror", None):
3335 if getattr(inst, "filename", None):
3338 if getattr(inst, "filename", None):
3336 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3339 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3337 else:
3340 else:
3338 u.warn(_("abort: %s\n") % inst.strerror)
3341 u.warn(_("abort: %s\n") % inst.strerror)
3339 else:
3342 else:
3340 raise
3343 raise
3341 except OSError, inst:
3344 except OSError, inst:
3342 if getattr(inst, "filename", None):
3345 if getattr(inst, "filename", None):
3343 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3346 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3344 else:
3347 else:
3345 u.warn(_("abort: %s\n") % inst.strerror)
3348 u.warn(_("abort: %s\n") % inst.strerror)
3346 except util.UnexpectedOutput, inst:
3349 except util.UnexpectedOutput, inst:
3347 u.warn(_("abort: %s") % inst[0])
3350 u.warn(_("abort: %s") % inst[0])
3348 if not isinstance(inst[1], basestring):
3351 if not isinstance(inst[1], basestring):
3349 u.warn(" %r\n" % (inst[1],))
3352 u.warn(" %r\n" % (inst[1],))
3350 elif not inst[1]:
3353 elif not inst[1]:
3351 u.warn(_(" empty string\n"))
3354 u.warn(_(" empty string\n"))
3352 else:
3355 else:
3353 u.warn("\n%r\n" % util.ellipsis(inst[1]))
3356 u.warn("\n%r\n" % util.ellipsis(inst[1]))
3354 except util.Abort, inst:
3357 except util.Abort, inst:
3355 u.warn(_("abort: %s\n") % inst)
3358 u.warn(_("abort: %s\n") % inst)
3356 except TypeError, inst:
3359 except TypeError, inst:
3357 # was this an argument error?
3360 # was this an argument error?
3358 tb = traceback.extract_tb(sys.exc_info()[2])
3361 tb = traceback.extract_tb(sys.exc_info()[2])
3359 if len(tb) > 2: # no
3362 if len(tb) > 2: # no
3360 raise
3363 raise
3361 u.debug(inst, "\n")
3364 u.debug(inst, "\n")
3362 u.warn(_("%s: invalid arguments\n") % cmd)
3365 u.warn(_("%s: invalid arguments\n") % cmd)
3363 help_(u, cmd)
3366 help_(u, cmd)
3364 except SystemExit, inst:
3367 except SystemExit, inst:
3365 # Commands shouldn't sys.exit directly, but give a return code.
3368 # Commands shouldn't sys.exit directly, but give a return code.
3366 # Just in case catch this and and pass exit code to caller.
3369 # Just in case catch this and and pass exit code to caller.
3367 return inst.code
3370 return inst.code
3368 except:
3371 except:
3369 u.warn(_("** unknown exception encountered, details follow\n"))
3372 u.warn(_("** unknown exception encountered, details follow\n"))
3370 u.warn(_("** report bug details to "
3373 u.warn(_("** report bug details to "
3371 "http://www.selenic.com/mercurial/bts\n"))
3374 "http://www.selenic.com/mercurial/bts\n"))
3372 u.warn(_("** or mercurial@selenic.com\n"))
3375 u.warn(_("** or mercurial@selenic.com\n"))
3373 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3376 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3374 % version.get_version())
3377 % version.get_version())
3375 raise
3378 raise
3376
3379
3377 return -1
3380 return -1
@@ -1,1484 +1,1484 b''
1 """
1 """
2 util.py - Mercurial utility functions and platform specfic implementations
2 util.py - Mercurial utility functions and platform specfic implementations
3
3
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
5 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
6 Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
7
7
8 This software may be used and distributed according to the terms
8 This software may be used and distributed according to the terms
9 of the GNU General Public License, incorporated herein by reference.
9 of the GNU General Public License, incorporated herein by reference.
10
10
11 This contains helper routines that are independent of the SCM core and hide
11 This contains helper routines that are independent of the SCM core and hide
12 platform-specific details from the core.
12 platform-specific details from the core.
13 """
13 """
14
14
15 from i18n import _
15 from i18n import _
16 import cStringIO, errno, getpass, popen2, re, shutil, sys, tempfile
16 import cStringIO, errno, getpass, popen2, re, shutil, sys, tempfile
17 import os, threading, time, calendar, ConfigParser, locale, glob
17 import os, threading, time, calendar, ConfigParser, locale, glob
18
18
19 try:
19 try:
20 _encoding = os.environ.get("HGENCODING") or locale.getpreferredencoding() \
20 _encoding = os.environ.get("HGENCODING") or locale.getpreferredencoding() \
21 or "ascii"
21 or "ascii"
22 except locale.Error:
22 except locale.Error:
23 _encoding = 'ascii'
23 _encoding = 'ascii'
24 _encodingmode = os.environ.get("HGENCODINGMODE", "strict")
24 _encodingmode = os.environ.get("HGENCODINGMODE", "strict")
25 _fallbackencoding = 'ISO-8859-1'
25 _fallbackencoding = 'ISO-8859-1'
26
26
27 def tolocal(s):
27 def tolocal(s):
28 """
28 """
29 Convert a string from internal UTF-8 to local encoding
29 Convert a string from internal UTF-8 to local encoding
30
30
31 All internal strings should be UTF-8 but some repos before the
31 All internal strings should be UTF-8 but some repos before the
32 implementation of locale support may contain latin1 or possibly
32 implementation of locale support may contain latin1 or possibly
33 other character sets. We attempt to decode everything strictly
33 other character sets. We attempt to decode everything strictly
34 using UTF-8, then Latin-1, and failing that, we use UTF-8 and
34 using UTF-8, then Latin-1, and failing that, we use UTF-8 and
35 replace unknown characters.
35 replace unknown characters.
36 """
36 """
37 for e in ('UTF-8', _fallbackencoding):
37 for e in ('UTF-8', _fallbackencoding):
38 try:
38 try:
39 u = s.decode(e) # attempt strict decoding
39 u = s.decode(e) # attempt strict decoding
40 return u.encode(_encoding, "replace")
40 return u.encode(_encoding, "replace")
41 except LookupError, k:
41 except LookupError, k:
42 raise Abort(_("%s, please check your locale settings") % k)
42 raise Abort(_("%s, please check your locale settings") % k)
43 except UnicodeDecodeError:
43 except UnicodeDecodeError:
44 pass
44 pass
45 u = s.decode("utf-8", "replace") # last ditch
45 u = s.decode("utf-8", "replace") # last ditch
46 return u.encode(_encoding, "replace")
46 return u.encode(_encoding, "replace")
47
47
48 def fromlocal(s):
48 def fromlocal(s):
49 """
49 """
50 Convert a string from the local character encoding to UTF-8
50 Convert a string from the local character encoding to UTF-8
51
51
52 We attempt to decode strings using the encoding mode set by
52 We attempt to decode strings using the encoding mode set by
53 HG_ENCODINGMODE, which defaults to 'strict'. In this mode, unknown
53 HG_ENCODINGMODE, which defaults to 'strict'. In this mode, unknown
54 characters will cause an error message. Other modes include
54 characters will cause an error message. Other modes include
55 'replace', which replaces unknown characters with a special
55 'replace', which replaces unknown characters with a special
56 Unicode character, and 'ignore', which drops the character.
56 Unicode character, and 'ignore', which drops the character.
57 """
57 """
58 try:
58 try:
59 return s.decode(_encoding, _encodingmode).encode("utf-8")
59 return s.decode(_encoding, _encodingmode).encode("utf-8")
60 except UnicodeDecodeError, inst:
60 except UnicodeDecodeError, inst:
61 sub = s[max(0, inst.start-10):inst.start+10]
61 sub = s[max(0, inst.start-10):inst.start+10]
62 raise Abort("decoding near '%s': %s!" % (sub, inst))
62 raise Abort("decoding near '%s': %s!" % (sub, inst))
63 except LookupError, k:
63 except LookupError, k:
64 raise Abort(_("%s, please check your locale settings") % k)
64 raise Abort(_("%s, please check your locale settings") % k)
65
65
66 def locallen(s):
66 def locallen(s):
67 """Find the length in characters of a local string"""
67 """Find the length in characters of a local string"""
68 return len(s.decode(_encoding, "replace"))
68 return len(s.decode(_encoding, "replace"))
69
69
70 def localsub(s, a, b=None):
70 def localsub(s, a, b=None):
71 try:
71 try:
72 u = s.decode(_encoding, _encodingmode)
72 u = s.decode(_encoding, _encodingmode)
73 if b is not None:
73 if b is not None:
74 u = u[a:b]
74 u = u[a:b]
75 else:
75 else:
76 u = u[:a]
76 u = u[:a]
77 return u.encode(_encoding, _encodingmode)
77 return u.encode(_encoding, _encodingmode)
78 except UnicodeDecodeError, inst:
78 except UnicodeDecodeError, inst:
79 sub = s[max(0, inst.start-10), inst.start+10]
79 sub = s[max(0, inst.start-10), inst.start+10]
80 raise Abort(_("decoding near '%s': %s!\n") % (sub, inst))
80 raise Abort(_("decoding near '%s': %s!\n") % (sub, inst))
81
81
82 # used by parsedate
82 # used by parsedate
83 defaultdateformats = (
83 defaultdateformats = (
84 '%Y-%m-%d %H:%M:%S',
84 '%Y-%m-%d %H:%M:%S',
85 '%Y-%m-%d %I:%M:%S%p',
85 '%Y-%m-%d %I:%M:%S%p',
86 '%Y-%m-%d %H:%M',
86 '%Y-%m-%d %H:%M',
87 '%Y-%m-%d %I:%M%p',
87 '%Y-%m-%d %I:%M%p',
88 '%Y-%m-%d',
88 '%Y-%m-%d',
89 '%m-%d',
89 '%m-%d',
90 '%m/%d',
90 '%m/%d',
91 '%m/%d/%y',
91 '%m/%d/%y',
92 '%m/%d/%Y',
92 '%m/%d/%Y',
93 '%a %b %d %H:%M:%S %Y',
93 '%a %b %d %H:%M:%S %Y',
94 '%a %b %d %I:%M:%S%p %Y',
94 '%a %b %d %I:%M:%S%p %Y',
95 '%b %d %H:%M:%S %Y',
95 '%b %d %H:%M:%S %Y',
96 '%b %d %I:%M:%S%p %Y',
96 '%b %d %I:%M:%S%p %Y',
97 '%b %d %H:%M:%S',
97 '%b %d %H:%M:%S',
98 '%b %d %I:%M:%S%p',
98 '%b %d %I:%M:%S%p',
99 '%b %d %H:%M',
99 '%b %d %H:%M',
100 '%b %d %I:%M%p',
100 '%b %d %I:%M%p',
101 '%b %d %Y',
101 '%b %d %Y',
102 '%b %d',
102 '%b %d',
103 '%H:%M:%S',
103 '%H:%M:%S',
104 '%I:%M:%SP',
104 '%I:%M:%SP',
105 '%H:%M',
105 '%H:%M',
106 '%I:%M%p',
106 '%I:%M%p',
107 )
107 )
108
108
109 extendeddateformats = defaultdateformats + (
109 extendeddateformats = defaultdateformats + (
110 "%Y",
110 "%Y",
111 "%Y-%m",
111 "%Y-%m",
112 "%b",
112 "%b",
113 "%b %Y",
113 "%b %Y",
114 )
114 )
115
115
116 class SignalInterrupt(Exception):
116 class SignalInterrupt(Exception):
117 """Exception raised on SIGTERM and SIGHUP."""
117 """Exception raised on SIGTERM and SIGHUP."""
118
118
119 # differences from SafeConfigParser:
119 # differences from SafeConfigParser:
120 # - case-sensitive keys
120 # - case-sensitive keys
121 # - allows values that are not strings (this means that you may not
121 # - allows values that are not strings (this means that you may not
122 # be able to save the configuration to a file)
122 # be able to save the configuration to a file)
123 class configparser(ConfigParser.SafeConfigParser):
123 class configparser(ConfigParser.SafeConfigParser):
124 def optionxform(self, optionstr):
124 def optionxform(self, optionstr):
125 return optionstr
125 return optionstr
126
126
127 def set(self, section, option, value):
127 def set(self, section, option, value):
128 return ConfigParser.ConfigParser.set(self, section, option, value)
128 return ConfigParser.ConfigParser.set(self, section, option, value)
129
129
130 def _interpolate(self, section, option, rawval, vars):
130 def _interpolate(self, section, option, rawval, vars):
131 if not isinstance(rawval, basestring):
131 if not isinstance(rawval, basestring):
132 return rawval
132 return rawval
133 return ConfigParser.SafeConfigParser._interpolate(self, section,
133 return ConfigParser.SafeConfigParser._interpolate(self, section,
134 option, rawval, vars)
134 option, rawval, vars)
135
135
136 def cachefunc(func):
136 def cachefunc(func):
137 '''cache the result of function calls'''
137 '''cache the result of function calls'''
138 # XXX doesn't handle keywords args
138 # XXX doesn't handle keywords args
139 cache = {}
139 cache = {}
140 if func.func_code.co_argcount == 1:
140 if func.func_code.co_argcount == 1:
141 # we gain a small amount of time because
141 # we gain a small amount of time because
142 # we don't need to pack/unpack the list
142 # we don't need to pack/unpack the list
143 def f(arg):
143 def f(arg):
144 if arg not in cache:
144 if arg not in cache:
145 cache[arg] = func(arg)
145 cache[arg] = func(arg)
146 return cache[arg]
146 return cache[arg]
147 else:
147 else:
148 def f(*args):
148 def f(*args):
149 if args not in cache:
149 if args not in cache:
150 cache[args] = func(*args)
150 cache[args] = func(*args)
151 return cache[args]
151 return cache[args]
152
152
153 return f
153 return f
154
154
155 def pipefilter(s, cmd):
155 def pipefilter(s, cmd):
156 '''filter string S through command CMD, returning its output'''
156 '''filter string S through command CMD, returning its output'''
157 (pout, pin) = popen2.popen2(cmd, -1, 'b')
157 (pout, pin) = popen2.popen2(cmd, -1, 'b')
158 def writer():
158 def writer():
159 try:
159 try:
160 pin.write(s)
160 pin.write(s)
161 pin.close()
161 pin.close()
162 except IOError, inst:
162 except IOError, inst:
163 if inst.errno != errno.EPIPE:
163 if inst.errno != errno.EPIPE:
164 raise
164 raise
165
165
166 # we should use select instead on UNIX, but this will work on most
166 # we should use select instead on UNIX, but this will work on most
167 # systems, including Windows
167 # systems, including Windows
168 w = threading.Thread(target=writer)
168 w = threading.Thread(target=writer)
169 w.start()
169 w.start()
170 f = pout.read()
170 f = pout.read()
171 pout.close()
171 pout.close()
172 w.join()
172 w.join()
173 return f
173 return f
174
174
175 def tempfilter(s, cmd):
175 def tempfilter(s, cmd):
176 '''filter string S through a pair of temporary files with CMD.
176 '''filter string S through a pair of temporary files with CMD.
177 CMD is used as a template to create the real command to be run,
177 CMD is used as a template to create the real command to be run,
178 with the strings INFILE and OUTFILE replaced by the real names of
178 with the strings INFILE and OUTFILE replaced by the real names of
179 the temporary files generated.'''
179 the temporary files generated.'''
180 inname, outname = None, None
180 inname, outname = None, None
181 try:
181 try:
182 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
182 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
183 fp = os.fdopen(infd, 'wb')
183 fp = os.fdopen(infd, 'wb')
184 fp.write(s)
184 fp.write(s)
185 fp.close()
185 fp.close()
186 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
186 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
187 os.close(outfd)
187 os.close(outfd)
188 cmd = cmd.replace('INFILE', inname)
188 cmd = cmd.replace('INFILE', inname)
189 cmd = cmd.replace('OUTFILE', outname)
189 cmd = cmd.replace('OUTFILE', outname)
190 code = os.system(cmd)
190 code = os.system(cmd)
191 if code: raise Abort(_("command '%s' failed: %s") %
191 if code: raise Abort(_("command '%s' failed: %s") %
192 (cmd, explain_exit(code)))
192 (cmd, explain_exit(code)))
193 return open(outname, 'rb').read()
193 return open(outname, 'rb').read()
194 finally:
194 finally:
195 try:
195 try:
196 if inname: os.unlink(inname)
196 if inname: os.unlink(inname)
197 except: pass
197 except: pass
198 try:
198 try:
199 if outname: os.unlink(outname)
199 if outname: os.unlink(outname)
200 except: pass
200 except: pass
201
201
202 filtertable = {
202 filtertable = {
203 'tempfile:': tempfilter,
203 'tempfile:': tempfilter,
204 'pipe:': pipefilter,
204 'pipe:': pipefilter,
205 }
205 }
206
206
207 def filter(s, cmd):
207 def filter(s, cmd):
208 "filter a string through a command that transforms its input to its output"
208 "filter a string through a command that transforms its input to its output"
209 for name, fn in filtertable.iteritems():
209 for name, fn in filtertable.iteritems():
210 if cmd.startswith(name):
210 if cmd.startswith(name):
211 return fn(s, cmd[len(name):].lstrip())
211 return fn(s, cmd[len(name):].lstrip())
212 return pipefilter(s, cmd)
212 return pipefilter(s, cmd)
213
213
214 def find_in_path(name, path, default=None):
214 def find_in_path(name, path, default=None):
215 '''find name in search path. path can be string (will be split
215 '''find name in search path. path can be string (will be split
216 with os.pathsep), or iterable thing that returns strings. if name
216 with os.pathsep), or iterable thing that returns strings. if name
217 found, return path to name. else return default.'''
217 found, return path to name. else return default.'''
218 if isinstance(path, str):
218 if isinstance(path, str):
219 path = path.split(os.pathsep)
219 path = path.split(os.pathsep)
220 for p in path:
220 for p in path:
221 p_name = os.path.join(p, name)
221 p_name = os.path.join(p, name)
222 if os.path.exists(p_name):
222 if os.path.exists(p_name):
223 return p_name
223 return p_name
224 return default
224 return default
225
225
226 def binary(s):
226 def binary(s):
227 """return true if a string is binary data using diff's heuristic"""
227 """return true if a string is binary data using diff's heuristic"""
228 if s and '\0' in s[:4096]:
228 if s and '\0' in s[:4096]:
229 return True
229 return True
230 return False
230 return False
231
231
232 def unique(g):
232 def unique(g):
233 """return the uniq elements of iterable g"""
233 """return the uniq elements of iterable g"""
234 seen = {}
234 seen = {}
235 l = []
235 l = []
236 for f in g:
236 for f in g:
237 if f not in seen:
237 if f not in seen:
238 seen[f] = 1
238 seen[f] = 1
239 l.append(f)
239 l.append(f)
240 return l
240 return l
241
241
242 class Abort(Exception):
242 class Abort(Exception):
243 """Raised if a command needs to print an error and exit."""
243 """Raised if a command needs to print an error and exit."""
244
244
245 class UnexpectedOutput(Abort):
245 class UnexpectedOutput(Abort):
246 """Raised to print an error with part of output and exit."""
246 """Raised to print an error with part of output and exit."""
247
247
248 def always(fn): return True
248 def always(fn): return True
249 def never(fn): return False
249 def never(fn): return False
250
250
251 def expand_glob(pats):
251 def expand_glob(pats):
252 '''On Windows, expand the implicit globs in a list of patterns'''
252 '''On Windows, expand the implicit globs in a list of patterns'''
253 if os.name != 'nt':
253 if os.name != 'nt':
254 return list(pats)
254 return list(pats)
255 ret = []
255 ret = []
256 for p in pats:
256 for p in pats:
257 kind, name = patkind(p, None)
257 kind, name = patkind(p, None)
258 if kind is None:
258 if kind is None:
259 globbed = glob.glob(name)
259 globbed = glob.glob(name)
260 if globbed:
260 if globbed:
261 ret.extend(globbed)
261 ret.extend(globbed)
262 continue
262 continue
263 # if we couldn't expand the glob, just keep it around
263 # if we couldn't expand the glob, just keep it around
264 ret.append(p)
264 ret.append(p)
265 return ret
265 return ret
266
266
267 def patkind(name, dflt_pat='glob'):
267 def patkind(name, dflt_pat='glob'):
268 """Split a string into an optional pattern kind prefix and the
268 """Split a string into an optional pattern kind prefix and the
269 actual pattern."""
269 actual pattern."""
270 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
270 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
271 if name.startswith(prefix + ':'): return name.split(':', 1)
271 if name.startswith(prefix + ':'): return name.split(':', 1)
272 return dflt_pat, name
272 return dflt_pat, name
273
273
274 def globre(pat, head='^', tail='$'):
274 def globre(pat, head='^', tail='$'):
275 "convert a glob pattern into a regexp"
275 "convert a glob pattern into a regexp"
276 i, n = 0, len(pat)
276 i, n = 0, len(pat)
277 res = ''
277 res = ''
278 group = False
278 group = False
279 def peek(): return i < n and pat[i]
279 def peek(): return i < n and pat[i]
280 while i < n:
280 while i < n:
281 c = pat[i]
281 c = pat[i]
282 i = i+1
282 i = i+1
283 if c == '*':
283 if c == '*':
284 if peek() == '*':
284 if peek() == '*':
285 i += 1
285 i += 1
286 res += '.*'
286 res += '.*'
287 else:
287 else:
288 res += '[^/]*'
288 res += '[^/]*'
289 elif c == '?':
289 elif c == '?':
290 res += '.'
290 res += '.'
291 elif c == '[':
291 elif c == '[':
292 j = i
292 j = i
293 if j < n and pat[j] in '!]':
293 if j < n and pat[j] in '!]':
294 j += 1
294 j += 1
295 while j < n and pat[j] != ']':
295 while j < n and pat[j] != ']':
296 j += 1
296 j += 1
297 if j >= n:
297 if j >= n:
298 res += '\\['
298 res += '\\['
299 else:
299 else:
300 stuff = pat[i:j].replace('\\','\\\\')
300 stuff = pat[i:j].replace('\\','\\\\')
301 i = j + 1
301 i = j + 1
302 if stuff[0] == '!':
302 if stuff[0] == '!':
303 stuff = '^' + stuff[1:]
303 stuff = '^' + stuff[1:]
304 elif stuff[0] == '^':
304 elif stuff[0] == '^':
305 stuff = '\\' + stuff
305 stuff = '\\' + stuff
306 res = '%s[%s]' % (res, stuff)
306 res = '%s[%s]' % (res, stuff)
307 elif c == '{':
307 elif c == '{':
308 group = True
308 group = True
309 res += '(?:'
309 res += '(?:'
310 elif c == '}' and group:
310 elif c == '}' and group:
311 res += ')'
311 res += ')'
312 group = False
312 group = False
313 elif c == ',' and group:
313 elif c == ',' and group:
314 res += '|'
314 res += '|'
315 elif c == '\\':
315 elif c == '\\':
316 p = peek()
316 p = peek()
317 if p:
317 if p:
318 i += 1
318 i += 1
319 res += re.escape(p)
319 res += re.escape(p)
320 else:
320 else:
321 res += re.escape(c)
321 res += re.escape(c)
322 else:
322 else:
323 res += re.escape(c)
323 res += re.escape(c)
324 return head + res + tail
324 return head + res + tail
325
325
326 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
326 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
327
327
328 def pathto(root, n1, n2):
328 def pathto(root, n1, n2):
329 '''return the relative path from one place to another.
329 '''return the relative path from one place to another.
330 root should use os.sep to separate directories
330 root should use os.sep to separate directories
331 n1 should use os.sep to separate directories
331 n1 should use os.sep to separate directories
332 n2 should use "/" to separate directories
332 n2 should use "/" to separate directories
333 returns an os.sep-separated path.
333 returns an os.sep-separated path.
334
334
335 If n1 is a relative path, it's assumed it's
335 If n1 is a relative path, it's assumed it's
336 relative to root.
336 relative to root.
337 n2 should always be relative to root.
337 n2 should always be relative to root.
338 '''
338 '''
339 if not n1: return localpath(n2)
339 if not n1: return localpath(n2)
340 if os.path.isabs(n1):
340 if os.path.isabs(n1):
341 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
341 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
342 return os.path.join(root, localpath(n2))
342 return os.path.join(root, localpath(n2))
343 n2 = '/'.join((pconvert(root), n2))
343 n2 = '/'.join((pconvert(root), n2))
344 a, b = n1.split(os.sep), n2.split('/')
344 a, b = n1.split(os.sep), n2.split('/')
345 a.reverse()
345 a.reverse()
346 b.reverse()
346 b.reverse()
347 while a and b and a[-1] == b[-1]:
347 while a and b and a[-1] == b[-1]:
348 a.pop()
348 a.pop()
349 b.pop()
349 b.pop()
350 b.reverse()
350 b.reverse()
351 return os.sep.join((['..'] * len(a)) + b)
351 return os.sep.join((['..'] * len(a)) + b)
352
352
353 def canonpath(root, cwd, myname):
353 def canonpath(root, cwd, myname):
354 """return the canonical path of myname, given cwd and root"""
354 """return the canonical path of myname, given cwd and root"""
355 if root == os.sep:
355 if root == os.sep:
356 rootsep = os.sep
356 rootsep = os.sep
357 elif root.endswith(os.sep):
357 elif root.endswith(os.sep):
358 rootsep = root
358 rootsep = root
359 else:
359 else:
360 rootsep = root + os.sep
360 rootsep = root + os.sep
361 name = myname
361 name = myname
362 if not os.path.isabs(name):
362 if not os.path.isabs(name):
363 name = os.path.join(root, cwd, name)
363 name = os.path.join(root, cwd, name)
364 name = os.path.normpath(name)
364 name = os.path.normpath(name)
365 if name != rootsep and name.startswith(rootsep):
365 if name != rootsep and name.startswith(rootsep):
366 name = name[len(rootsep):]
366 name = name[len(rootsep):]
367 audit_path(name)
367 audit_path(name)
368 return pconvert(name)
368 return pconvert(name)
369 elif name == root:
369 elif name == root:
370 return ''
370 return ''
371 else:
371 else:
372 # Determine whether `name' is in the hierarchy at or beneath `root',
372 # Determine whether `name' is in the hierarchy at or beneath `root',
373 # by iterating name=dirname(name) until that causes no change (can't
373 # by iterating name=dirname(name) until that causes no change (can't
374 # check name == '/', because that doesn't work on windows). For each
374 # check name == '/', because that doesn't work on windows). For each
375 # `name', compare dev/inode numbers. If they match, the list `rel'
375 # `name', compare dev/inode numbers. If they match, the list `rel'
376 # holds the reversed list of components making up the relative file
376 # holds the reversed list of components making up the relative file
377 # name we want.
377 # name we want.
378 root_st = os.stat(root)
378 root_st = os.stat(root)
379 rel = []
379 rel = []
380 while True:
380 while True:
381 try:
381 try:
382 name_st = os.stat(name)
382 name_st = os.stat(name)
383 except OSError:
383 except OSError:
384 break
384 break
385 if samestat(name_st, root_st):
385 if samestat(name_st, root_st):
386 if not rel:
386 if not rel:
387 # name was actually the same as root (maybe a symlink)
387 # name was actually the same as root (maybe a symlink)
388 return ''
388 return ''
389 rel.reverse()
389 rel.reverse()
390 name = os.path.join(*rel)
390 name = os.path.join(*rel)
391 audit_path(name)
391 audit_path(name)
392 return pconvert(name)
392 return pconvert(name)
393 dirname, basename = os.path.split(name)
393 dirname, basename = os.path.split(name)
394 rel.append(basename)
394 rel.append(basename)
395 if dirname == name:
395 if dirname == name:
396 break
396 break
397 name = dirname
397 name = dirname
398
398
399 raise Abort('%s not under root' % myname)
399 raise Abort('%s not under root' % myname)
400
400
401 def matcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None):
401 def matcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None):
402 return _matcher(canonroot, cwd, names, inc, exc, 'glob', src)
402 return _matcher(canonroot, cwd, names, inc, exc, 'glob', src)
403
403
404 def cmdmatcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None,
404 def cmdmatcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None,
405 globbed=False, default=None):
405 globbed=False, default=None):
406 default = default or 'relpath'
406 default = default or 'relpath'
407 if default == 'relpath' and not globbed:
407 if default == 'relpath' and not globbed:
408 names = expand_glob(names)
408 names = expand_glob(names)
409 return _matcher(canonroot, cwd, names, inc, exc, default, src)
409 return _matcher(canonroot, cwd, names, inc, exc, default, src)
410
410
411 def _matcher(canonroot, cwd, names, inc, exc, dflt_pat, src):
411 def _matcher(canonroot, cwd, names, inc, exc, dflt_pat, src):
412 """build a function to match a set of file patterns
412 """build a function to match a set of file patterns
413
413
414 arguments:
414 arguments:
415 canonroot - the canonical root of the tree you're matching against
415 canonroot - the canonical root of the tree you're matching against
416 cwd - the current working directory, if relevant
416 cwd - the current working directory, if relevant
417 names - patterns to find
417 names - patterns to find
418 inc - patterns to include
418 inc - patterns to include
419 exc - patterns to exclude
419 exc - patterns to exclude
420 dflt_pat - if a pattern in names has no explicit type, assume this one
420 dflt_pat - if a pattern in names has no explicit type, assume this one
421 src - where these patterns came from (e.g. .hgignore)
421 src - where these patterns came from (e.g. .hgignore)
422
422
423 a pattern is one of:
423 a pattern is one of:
424 'glob:<glob>' - a glob relative to cwd
424 'glob:<glob>' - a glob relative to cwd
425 're:<regexp>' - a regular expression
425 're:<regexp>' - a regular expression
426 'path:<path>' - a path relative to canonroot
426 'path:<path>' - a path relative to canonroot
427 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
427 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
428 'relpath:<path>' - a path relative to cwd
428 'relpath:<path>' - a path relative to cwd
429 'relre:<regexp>' - a regexp that doesn't have to match the start of a name
429 'relre:<regexp>' - a regexp that doesn't have to match the start of a name
430 '<something>' - one of the cases above, selected by the dflt_pat argument
430 '<something>' - one of the cases above, selected by the dflt_pat argument
431
431
432 returns:
432 returns:
433 a 3-tuple containing
433 a 3-tuple containing
434 - list of roots (places where one should start a recursive walk of the fs);
434 - list of roots (places where one should start a recursive walk of the fs);
435 this often matches the explicit non-pattern names passed in, but also
435 this often matches the explicit non-pattern names passed in, but also
436 includes the initial part of glob: patterns that has no glob characters
436 includes the initial part of glob: patterns that has no glob characters
437 - a bool match(filename) function
437 - a bool match(filename) function
438 - a bool indicating if any patterns were passed in
438 - a bool indicating if any patterns were passed in
439 """
439 """
440
440
441 # a common case: no patterns at all
441 # a common case: no patterns at all
442 if not names and not inc and not exc:
442 if not names and not inc and not exc:
443 return [], always, False
443 return [], always, False
444
444
445 def contains_glob(name):
445 def contains_glob(name):
446 for c in name:
446 for c in name:
447 if c in _globchars: return True
447 if c in _globchars: return True
448 return False
448 return False
449
449
450 def regex(kind, name):
450 def regex(kind, name, tail):
451 '''convert a pattern into a regular expression'''
451 '''convert a pattern into a regular expression'''
452 if not name:
452 if not name:
453 return ''
453 return ''
454 if kind == 're':
454 if kind == 're':
455 return name
455 return name
456 elif kind == 'path':
456 elif kind == 'path':
457 return '^' + re.escape(name) + '(?:/|$)'
457 return '^' + re.escape(name) + '(?:/|$)'
458 elif kind == 'relglob':
458 elif kind == 'relglob':
459 return globre(name, '(?:|.*/)', '(?:/|$)')
459 return globre(name, '(?:|.*/)', tail)
460 elif kind == 'relpath':
460 elif kind == 'relpath':
461 return re.escape(name) + '(?:/|$)'
461 return re.escape(name) + '(?:/|$)'
462 elif kind == 'relre':
462 elif kind == 'relre':
463 if name.startswith('^'):
463 if name.startswith('^'):
464 return name
464 return name
465 return '.*' + name
465 return '.*' + name
466 return globre(name, '', '(?:/|$)')
466 return globre(name, '', tail)
467
467
468 def matchfn(pats):
468 def matchfn(pats, tail):
469 """build a matching function from a set of patterns"""
469 """build a matching function from a set of patterns"""
470 if not pats:
470 if not pats:
471 return
471 return
472 matches = []
472 matches = []
473 for k, p in pats:
473 for k, p in pats:
474 try:
474 try:
475 pat = '(?:%s)' % regex(k, p)
475 pat = '(?:%s)' % regex(k, p, tail)
476 matches.append(re.compile(pat).match)
476 matches.append(re.compile(pat).match)
477 except re.error:
477 except re.error:
478 if src: raise Abort("%s: invalid pattern (%s): %s" % (src, k, p))
478 if src: raise Abort("%s: invalid pattern (%s): %s" % (src, k, p))
479 else: raise Abort("invalid pattern (%s): %s" % (k, p))
479 else: raise Abort("invalid pattern (%s): %s" % (k, p))
480
480
481 def buildfn(text):
481 def buildfn(text):
482 for m in matches:
482 for m in matches:
483 r = m(text)
483 r = m(text)
484 if r:
484 if r:
485 return r
485 return r
486
486
487 return buildfn
487 return buildfn
488
488
489 def globprefix(pat):
489 def globprefix(pat):
490 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
490 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
491 root = []
491 root = []
492 for p in pat.split('/'):
492 for p in pat.split('/'):
493 if contains_glob(p): break
493 if contains_glob(p): break
494 root.append(p)
494 root.append(p)
495 return '/'.join(root) or '.'
495 return '/'.join(root) or '.'
496
496
497 def normalizepats(names, default):
497 def normalizepats(names, default):
498 pats = []
498 pats = []
499 roots = []
499 roots = []
500 anypats = False
500 anypats = False
501 for kind, name in [patkind(p, default) for p in names]:
501 for kind, name in [patkind(p, default) for p in names]:
502 if kind in ('glob', 'relpath'):
502 if kind in ('glob', 'relpath'):
503 name = canonpath(canonroot, cwd, name)
503 name = canonpath(canonroot, cwd, name)
504 elif kind in ('relglob', 'path'):
504 elif kind in ('relglob', 'path'):
505 name = normpath(name)
505 name = normpath(name)
506
506
507 pats.append((kind, name))
507 pats.append((kind, name))
508
508
509 if kind in ('glob', 're', 'relglob', 'relre'):
509 if kind in ('glob', 're', 'relglob', 'relre'):
510 anypats = True
510 anypats = True
511
511
512 if kind == 'glob':
512 if kind == 'glob':
513 root = globprefix(name)
513 root = globprefix(name)
514 roots.append(root)
514 roots.append(root)
515 elif kind in ('relpath', 'path'):
515 elif kind in ('relpath', 'path'):
516 roots.append(name or '.')
516 roots.append(name or '.')
517 elif kind == 'relglob':
517 elif kind == 'relglob':
518 roots.append('.')
518 roots.append('.')
519 return roots, pats, anypats
519 return roots, pats, anypats
520
520
521 roots, pats, anypats = normalizepats(names, dflt_pat)
521 roots, pats, anypats = normalizepats(names, dflt_pat)
522
522
523 patmatch = matchfn(pats) or always
523 patmatch = matchfn(pats, '$') or always
524 incmatch = always
524 incmatch = always
525 if inc:
525 if inc:
526 dummy, inckinds, dummy = normalizepats(inc, 'glob')
526 dummy, inckinds, dummy = normalizepats(inc, 'glob')
527 incmatch = matchfn(inckinds)
527 incmatch = matchfn(inckinds, '(?:/|$)')
528 excmatch = lambda fn: False
528 excmatch = lambda fn: False
529 if exc:
529 if exc:
530 dummy, exckinds, dummy = normalizepats(exc, 'glob')
530 dummy, exckinds, dummy = normalizepats(exc, 'glob')
531 excmatch = matchfn(exckinds)
531 excmatch = matchfn(exckinds, '(?:/|$)')
532
532
533 if not names and inc and not exc:
533 if not names and inc and not exc:
534 # common case: hgignore patterns
534 # common case: hgignore patterns
535 match = incmatch
535 match = incmatch
536 else:
536 else:
537 match = lambda fn: incmatch(fn) and not excmatch(fn) and patmatch(fn)
537 match = lambda fn: incmatch(fn) and not excmatch(fn) and patmatch(fn)
538
538
539 return (roots, match, (inc or exc or anypats) and True)
539 return (roots, match, (inc or exc or anypats) and True)
540
540
541 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
541 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
542 '''enhanced shell command execution.
542 '''enhanced shell command execution.
543 run with environment maybe modified, maybe in different dir.
543 run with environment maybe modified, maybe in different dir.
544
544
545 if command fails and onerr is None, return status. if ui object,
545 if command fails and onerr is None, return status. if ui object,
546 print error message and return status, else raise onerr object as
546 print error message and return status, else raise onerr object as
547 exception.'''
547 exception.'''
548 def py2shell(val):
548 def py2shell(val):
549 'convert python object into string that is useful to shell'
549 'convert python object into string that is useful to shell'
550 if val in (None, False):
550 if val in (None, False):
551 return '0'
551 return '0'
552 if val == True:
552 if val == True:
553 return '1'
553 return '1'
554 return str(val)
554 return str(val)
555 oldenv = {}
555 oldenv = {}
556 for k in environ:
556 for k in environ:
557 oldenv[k] = os.environ.get(k)
557 oldenv[k] = os.environ.get(k)
558 if cwd is not None:
558 if cwd is not None:
559 oldcwd = os.getcwd()
559 oldcwd = os.getcwd()
560 origcmd = cmd
560 origcmd = cmd
561 if os.name == 'nt':
561 if os.name == 'nt':
562 cmd = '"%s"' % cmd
562 cmd = '"%s"' % cmd
563 try:
563 try:
564 for k, v in environ.iteritems():
564 for k, v in environ.iteritems():
565 os.environ[k] = py2shell(v)
565 os.environ[k] = py2shell(v)
566 if cwd is not None and oldcwd != cwd:
566 if cwd is not None and oldcwd != cwd:
567 os.chdir(cwd)
567 os.chdir(cwd)
568 rc = os.system(cmd)
568 rc = os.system(cmd)
569 if rc and onerr:
569 if rc and onerr:
570 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
570 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
571 explain_exit(rc)[0])
571 explain_exit(rc)[0])
572 if errprefix:
572 if errprefix:
573 errmsg = '%s: %s' % (errprefix, errmsg)
573 errmsg = '%s: %s' % (errprefix, errmsg)
574 try:
574 try:
575 onerr.warn(errmsg + '\n')
575 onerr.warn(errmsg + '\n')
576 except AttributeError:
576 except AttributeError:
577 raise onerr(errmsg)
577 raise onerr(errmsg)
578 return rc
578 return rc
579 finally:
579 finally:
580 for k, v in oldenv.iteritems():
580 for k, v in oldenv.iteritems():
581 if v is None:
581 if v is None:
582 del os.environ[k]
582 del os.environ[k]
583 else:
583 else:
584 os.environ[k] = v
584 os.environ[k] = v
585 if cwd is not None and oldcwd != cwd:
585 if cwd is not None and oldcwd != cwd:
586 os.chdir(oldcwd)
586 os.chdir(oldcwd)
587
587
588 # os.path.lexists is not available on python2.3
588 # os.path.lexists is not available on python2.3
589 def lexists(filename):
589 def lexists(filename):
590 "test whether a file with this name exists. does not follow symlinks"
590 "test whether a file with this name exists. does not follow symlinks"
591 try:
591 try:
592 os.lstat(filename)
592 os.lstat(filename)
593 except:
593 except:
594 return False
594 return False
595 return True
595 return True
596
596
597 def rename(src, dst):
597 def rename(src, dst):
598 """forcibly rename a file"""
598 """forcibly rename a file"""
599 try:
599 try:
600 os.rename(src, dst)
600 os.rename(src, dst)
601 except OSError, err:
601 except OSError, err:
602 # on windows, rename to existing file is not allowed, so we
602 # on windows, rename to existing file is not allowed, so we
603 # must delete destination first. but if file is open, unlink
603 # must delete destination first. but if file is open, unlink
604 # schedules it for delete but does not delete it. rename
604 # schedules it for delete but does not delete it. rename
605 # happens immediately even for open files, so we create
605 # happens immediately even for open files, so we create
606 # temporary file, delete it, rename destination to that name,
606 # temporary file, delete it, rename destination to that name,
607 # then delete that. then rename is safe to do.
607 # then delete that. then rename is safe to do.
608 fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.')
608 fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.')
609 os.close(fd)
609 os.close(fd)
610 os.unlink(temp)
610 os.unlink(temp)
611 os.rename(dst, temp)
611 os.rename(dst, temp)
612 os.unlink(temp)
612 os.unlink(temp)
613 os.rename(src, dst)
613 os.rename(src, dst)
614
614
615 def unlink(f):
615 def unlink(f):
616 """unlink and remove the directory if it is empty"""
616 """unlink and remove the directory if it is empty"""
617 os.unlink(f)
617 os.unlink(f)
618 # try removing directories that might now be empty
618 # try removing directories that might now be empty
619 try:
619 try:
620 os.removedirs(os.path.dirname(f))
620 os.removedirs(os.path.dirname(f))
621 except OSError:
621 except OSError:
622 pass
622 pass
623
623
624 def copyfile(src, dest):
624 def copyfile(src, dest):
625 "copy a file, preserving mode"
625 "copy a file, preserving mode"
626 if os.path.islink(src):
626 if os.path.islink(src):
627 try:
627 try:
628 os.unlink(dest)
628 os.unlink(dest)
629 except:
629 except:
630 pass
630 pass
631 os.symlink(os.readlink(src), dest)
631 os.symlink(os.readlink(src), dest)
632 else:
632 else:
633 try:
633 try:
634 shutil.copyfile(src, dest)
634 shutil.copyfile(src, dest)
635 shutil.copymode(src, dest)
635 shutil.copymode(src, dest)
636 except shutil.Error, inst:
636 except shutil.Error, inst:
637 raise Abort(str(inst))
637 raise Abort(str(inst))
638
638
639 def copyfiles(src, dst, hardlink=None):
639 def copyfiles(src, dst, hardlink=None):
640 """Copy a directory tree using hardlinks if possible"""
640 """Copy a directory tree using hardlinks if possible"""
641
641
642 if hardlink is None:
642 if hardlink is None:
643 hardlink = (os.stat(src).st_dev ==
643 hardlink = (os.stat(src).st_dev ==
644 os.stat(os.path.dirname(dst)).st_dev)
644 os.stat(os.path.dirname(dst)).st_dev)
645
645
646 if os.path.isdir(src):
646 if os.path.isdir(src):
647 os.mkdir(dst)
647 os.mkdir(dst)
648 for name in os.listdir(src):
648 for name in os.listdir(src):
649 srcname = os.path.join(src, name)
649 srcname = os.path.join(src, name)
650 dstname = os.path.join(dst, name)
650 dstname = os.path.join(dst, name)
651 copyfiles(srcname, dstname, hardlink)
651 copyfiles(srcname, dstname, hardlink)
652 else:
652 else:
653 if hardlink:
653 if hardlink:
654 try:
654 try:
655 os_link(src, dst)
655 os_link(src, dst)
656 except (IOError, OSError):
656 except (IOError, OSError):
657 hardlink = False
657 hardlink = False
658 shutil.copy(src, dst)
658 shutil.copy(src, dst)
659 else:
659 else:
660 shutil.copy(src, dst)
660 shutil.copy(src, dst)
661
661
662 def audit_path(path):
662 def audit_path(path):
663 """Abort if path contains dangerous components"""
663 """Abort if path contains dangerous components"""
664 parts = os.path.normcase(path).split(os.sep)
664 parts = os.path.normcase(path).split(os.sep)
665 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
665 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
666 or os.pardir in parts):
666 or os.pardir in parts):
667 raise Abort(_("path contains illegal component: %s\n") % path)
667 raise Abort(_("path contains illegal component: %s\n") % path)
668
668
669 def _makelock_file(info, pathname):
669 def _makelock_file(info, pathname):
670 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
670 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
671 os.write(ld, info)
671 os.write(ld, info)
672 os.close(ld)
672 os.close(ld)
673
673
674 def _readlock_file(pathname):
674 def _readlock_file(pathname):
675 return posixfile(pathname).read()
675 return posixfile(pathname).read()
676
676
677 def nlinks(pathname):
677 def nlinks(pathname):
678 """Return number of hardlinks for the given file."""
678 """Return number of hardlinks for the given file."""
679 return os.lstat(pathname).st_nlink
679 return os.lstat(pathname).st_nlink
680
680
681 if hasattr(os, 'link'):
681 if hasattr(os, 'link'):
682 os_link = os.link
682 os_link = os.link
683 else:
683 else:
684 def os_link(src, dst):
684 def os_link(src, dst):
685 raise OSError(0, _("Hardlinks not supported"))
685 raise OSError(0, _("Hardlinks not supported"))
686
686
687 def fstat(fp):
687 def fstat(fp):
688 '''stat file object that may not have fileno method.'''
688 '''stat file object that may not have fileno method.'''
689 try:
689 try:
690 return os.fstat(fp.fileno())
690 return os.fstat(fp.fileno())
691 except AttributeError:
691 except AttributeError:
692 return os.stat(fp.name)
692 return os.stat(fp.name)
693
693
694 posixfile = file
694 posixfile = file
695
695
696 def is_win_9x():
696 def is_win_9x():
697 '''return true if run on windows 95, 98 or me.'''
697 '''return true if run on windows 95, 98 or me.'''
698 try:
698 try:
699 return sys.getwindowsversion()[3] == 1
699 return sys.getwindowsversion()[3] == 1
700 except AttributeError:
700 except AttributeError:
701 return os.name == 'nt' and 'command' in os.environ.get('comspec', '')
701 return os.name == 'nt' and 'command' in os.environ.get('comspec', '')
702
702
703 getuser_fallback = None
703 getuser_fallback = None
704
704
705 def getuser():
705 def getuser():
706 '''return name of current user'''
706 '''return name of current user'''
707 try:
707 try:
708 return getpass.getuser()
708 return getpass.getuser()
709 except ImportError:
709 except ImportError:
710 # import of pwd will fail on windows - try fallback
710 # import of pwd will fail on windows - try fallback
711 if getuser_fallback:
711 if getuser_fallback:
712 return getuser_fallback()
712 return getuser_fallback()
713 # raised if win32api not available
713 # raised if win32api not available
714 raise Abort(_('user name not available - set USERNAME '
714 raise Abort(_('user name not available - set USERNAME '
715 'environment variable'))
715 'environment variable'))
716
716
717 def username(uid=None):
717 def username(uid=None):
718 """Return the name of the user with the given uid.
718 """Return the name of the user with the given uid.
719
719
720 If uid is None, return the name of the current user."""
720 If uid is None, return the name of the current user."""
721 try:
721 try:
722 import pwd
722 import pwd
723 if uid is None:
723 if uid is None:
724 uid = os.getuid()
724 uid = os.getuid()
725 try:
725 try:
726 return pwd.getpwuid(uid)[0]
726 return pwd.getpwuid(uid)[0]
727 except KeyError:
727 except KeyError:
728 return str(uid)
728 return str(uid)
729 except ImportError:
729 except ImportError:
730 return None
730 return None
731
731
732 def groupname(gid=None):
732 def groupname(gid=None):
733 """Return the name of the group with the given gid.
733 """Return the name of the group with the given gid.
734
734
735 If gid is None, return the name of the current group."""
735 If gid is None, return the name of the current group."""
736 try:
736 try:
737 import grp
737 import grp
738 if gid is None:
738 if gid is None:
739 gid = os.getgid()
739 gid = os.getgid()
740 try:
740 try:
741 return grp.getgrgid(gid)[0]
741 return grp.getgrgid(gid)[0]
742 except KeyError:
742 except KeyError:
743 return str(gid)
743 return str(gid)
744 except ImportError:
744 except ImportError:
745 return None
745 return None
746
746
747 # File system features
747 # File system features
748
748
749 def checkfolding(path):
749 def checkfolding(path):
750 """
750 """
751 Check whether the given path is on a case-sensitive filesystem
751 Check whether the given path is on a case-sensitive filesystem
752
752
753 Requires a path (like /foo/.hg) ending with a foldable final
753 Requires a path (like /foo/.hg) ending with a foldable final
754 directory component.
754 directory component.
755 """
755 """
756 s1 = os.stat(path)
756 s1 = os.stat(path)
757 d, b = os.path.split(path)
757 d, b = os.path.split(path)
758 p2 = os.path.join(d, b.upper())
758 p2 = os.path.join(d, b.upper())
759 if path == p2:
759 if path == p2:
760 p2 = os.path.join(d, b.lower())
760 p2 = os.path.join(d, b.lower())
761 try:
761 try:
762 s2 = os.stat(p2)
762 s2 = os.stat(p2)
763 if s2 == s1:
763 if s2 == s1:
764 return False
764 return False
765 return True
765 return True
766 except:
766 except:
767 return True
767 return True
768
768
769 def checkexec(path):
769 def checkexec(path):
770 """
770 """
771 Check whether the given path is on a filesystem with UNIX-like exec flags
771 Check whether the given path is on a filesystem with UNIX-like exec flags
772
772
773 Requires a directory (like /foo/.hg)
773 Requires a directory (like /foo/.hg)
774 """
774 """
775 fh, fn = tempfile.mkstemp("", "", path)
775 fh, fn = tempfile.mkstemp("", "", path)
776 os.close(fh)
776 os.close(fh)
777 m = os.stat(fn).st_mode
777 m = os.stat(fn).st_mode
778 os.chmod(fn, m ^ 0111)
778 os.chmod(fn, m ^ 0111)
779 r = (os.stat(fn).st_mode != m)
779 r = (os.stat(fn).st_mode != m)
780 os.unlink(fn)
780 os.unlink(fn)
781 return r
781 return r
782
782
783 def execfunc(path, fallback):
783 def execfunc(path, fallback):
784 '''return an is_exec() function with default to fallback'''
784 '''return an is_exec() function with default to fallback'''
785 if checkexec(path):
785 if checkexec(path):
786 return lambda x: is_exec(os.path.join(path, x))
786 return lambda x: is_exec(os.path.join(path, x))
787 return fallback
787 return fallback
788
788
789 def checklink(path):
789 def checklink(path):
790 """check whether the given path is on a symlink-capable filesystem"""
790 """check whether the given path is on a symlink-capable filesystem"""
791 # mktemp is not racy because symlink creation will fail if the
791 # mktemp is not racy because symlink creation will fail if the
792 # file already exists
792 # file already exists
793 name = tempfile.mktemp(dir=path)
793 name = tempfile.mktemp(dir=path)
794 try:
794 try:
795 os.symlink(".", name)
795 os.symlink(".", name)
796 os.unlink(name)
796 os.unlink(name)
797 return True
797 return True
798 except (OSError, AttributeError):
798 except (OSError, AttributeError):
799 return False
799 return False
800
800
801 def linkfunc(path, fallback):
801 def linkfunc(path, fallback):
802 '''return an is_link() function with default to fallback'''
802 '''return an is_link() function with default to fallback'''
803 if checklink(path):
803 if checklink(path):
804 return lambda x: os.path.islink(os.path.join(path, x))
804 return lambda x: os.path.islink(os.path.join(path, x))
805 return fallback
805 return fallback
806
806
807 # Platform specific variants
807 # Platform specific variants
808 if os.name == 'nt':
808 if os.name == 'nt':
809 import msvcrt
809 import msvcrt
810 nulldev = 'NUL:'
810 nulldev = 'NUL:'
811
811
812 class winstdout:
812 class winstdout:
813 '''stdout on windows misbehaves if sent through a pipe'''
813 '''stdout on windows misbehaves if sent through a pipe'''
814
814
815 def __init__(self, fp):
815 def __init__(self, fp):
816 self.fp = fp
816 self.fp = fp
817
817
818 def __getattr__(self, key):
818 def __getattr__(self, key):
819 return getattr(self.fp, key)
819 return getattr(self.fp, key)
820
820
821 def close(self):
821 def close(self):
822 try:
822 try:
823 self.fp.close()
823 self.fp.close()
824 except: pass
824 except: pass
825
825
826 def write(self, s):
826 def write(self, s):
827 try:
827 try:
828 return self.fp.write(s)
828 return self.fp.write(s)
829 except IOError, inst:
829 except IOError, inst:
830 if inst.errno != 0: raise
830 if inst.errno != 0: raise
831 self.close()
831 self.close()
832 raise IOError(errno.EPIPE, 'Broken pipe')
832 raise IOError(errno.EPIPE, 'Broken pipe')
833
833
834 def flush(self):
834 def flush(self):
835 try:
835 try:
836 return self.fp.flush()
836 return self.fp.flush()
837 except IOError, inst:
837 except IOError, inst:
838 if inst.errno != errno.EINVAL: raise
838 if inst.errno != errno.EINVAL: raise
839 self.close()
839 self.close()
840 raise IOError(errno.EPIPE, 'Broken pipe')
840 raise IOError(errno.EPIPE, 'Broken pipe')
841
841
842 sys.stdout = winstdout(sys.stdout)
842 sys.stdout = winstdout(sys.stdout)
843
843
844 def system_rcpath():
844 def system_rcpath():
845 try:
845 try:
846 return system_rcpath_win32()
846 return system_rcpath_win32()
847 except:
847 except:
848 return [r'c:\mercurial\mercurial.ini']
848 return [r'c:\mercurial\mercurial.ini']
849
849
850 def user_rcpath():
850 def user_rcpath():
851 '''return os-specific hgrc search path to the user dir'''
851 '''return os-specific hgrc search path to the user dir'''
852 try:
852 try:
853 userrc = user_rcpath_win32()
853 userrc = user_rcpath_win32()
854 except:
854 except:
855 userrc = os.path.join(os.path.expanduser('~'), 'mercurial.ini')
855 userrc = os.path.join(os.path.expanduser('~'), 'mercurial.ini')
856 path = [userrc]
856 path = [userrc]
857 userprofile = os.environ.get('USERPROFILE')
857 userprofile = os.environ.get('USERPROFILE')
858 if userprofile:
858 if userprofile:
859 path.append(os.path.join(userprofile, 'mercurial.ini'))
859 path.append(os.path.join(userprofile, 'mercurial.ini'))
860 return path
860 return path
861
861
862 def parse_patch_output(output_line):
862 def parse_patch_output(output_line):
863 """parses the output produced by patch and returns the file name"""
863 """parses the output produced by patch and returns the file name"""
864 pf = output_line[14:]
864 pf = output_line[14:]
865 if pf[0] == '`':
865 if pf[0] == '`':
866 pf = pf[1:-1] # Remove the quotes
866 pf = pf[1:-1] # Remove the quotes
867 return pf
867 return pf
868
868
869 def testpid(pid):
869 def testpid(pid):
870 '''return False if pid dead, True if running or not known'''
870 '''return False if pid dead, True if running or not known'''
871 return True
871 return True
872
872
873 def set_exec(f, mode):
873 def set_exec(f, mode):
874 pass
874 pass
875
875
876 def set_link(f, mode):
876 def set_link(f, mode):
877 pass
877 pass
878
878
879 def set_binary(fd):
879 def set_binary(fd):
880 msvcrt.setmode(fd.fileno(), os.O_BINARY)
880 msvcrt.setmode(fd.fileno(), os.O_BINARY)
881
881
882 def pconvert(path):
882 def pconvert(path):
883 return path.replace("\\", "/")
883 return path.replace("\\", "/")
884
884
885 def localpath(path):
885 def localpath(path):
886 return path.replace('/', '\\')
886 return path.replace('/', '\\')
887
887
888 def normpath(path):
888 def normpath(path):
889 return pconvert(os.path.normpath(path))
889 return pconvert(os.path.normpath(path))
890
890
891 makelock = _makelock_file
891 makelock = _makelock_file
892 readlock = _readlock_file
892 readlock = _readlock_file
893
893
894 def samestat(s1, s2):
894 def samestat(s1, s2):
895 return False
895 return False
896
896
897 # A sequence of backslashes is special iff it precedes a double quote:
897 # A sequence of backslashes is special iff it precedes a double quote:
898 # - if there's an even number of backslashes, the double quote is not
898 # - if there's an even number of backslashes, the double quote is not
899 # quoted (i.e. it ends the quoted region)
899 # quoted (i.e. it ends the quoted region)
900 # - if there's an odd number of backslashes, the double quote is quoted
900 # - if there's an odd number of backslashes, the double quote is quoted
901 # - in both cases, every pair of backslashes is unquoted into a single
901 # - in both cases, every pair of backslashes is unquoted into a single
902 # backslash
902 # backslash
903 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
903 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
904 # So, to quote a string, we must surround it in double quotes, double
904 # So, to quote a string, we must surround it in double quotes, double
905 # the number of backslashes that preceed double quotes and add another
905 # the number of backslashes that preceed double quotes and add another
906 # backslash before every double quote (being careful with the double
906 # backslash before every double quote (being careful with the double
907 # quote we've appended to the end)
907 # quote we've appended to the end)
908 _quotere = None
908 _quotere = None
909 def shellquote(s):
909 def shellquote(s):
910 global _quotere
910 global _quotere
911 if _quotere is None:
911 if _quotere is None:
912 _quotere = re.compile(r'(\\*)("|\\$)')
912 _quotere = re.compile(r'(\\*)("|\\$)')
913 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
913 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
914
914
915 def explain_exit(code):
915 def explain_exit(code):
916 return _("exited with status %d") % code, code
916 return _("exited with status %d") % code, code
917
917
918 # if you change this stub into a real check, please try to implement the
918 # if you change this stub into a real check, please try to implement the
919 # username and groupname functions above, too.
919 # username and groupname functions above, too.
920 def isowner(fp, st=None):
920 def isowner(fp, st=None):
921 return True
921 return True
922
922
923 try:
923 try:
924 # override functions with win32 versions if possible
924 # override functions with win32 versions if possible
925 from util_win32 import *
925 from util_win32 import *
926 if not is_win_9x():
926 if not is_win_9x():
927 posixfile = posixfile_nt
927 posixfile = posixfile_nt
928 except ImportError:
928 except ImportError:
929 pass
929 pass
930
930
931 else:
931 else:
932 nulldev = '/dev/null'
932 nulldev = '/dev/null'
933 _umask = os.umask(0)
933 _umask = os.umask(0)
934 os.umask(_umask)
934 os.umask(_umask)
935
935
936 def rcfiles(path):
936 def rcfiles(path):
937 rcs = [os.path.join(path, 'hgrc')]
937 rcs = [os.path.join(path, 'hgrc')]
938 rcdir = os.path.join(path, 'hgrc.d')
938 rcdir = os.path.join(path, 'hgrc.d')
939 try:
939 try:
940 rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir)
940 rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir)
941 if f.endswith(".rc")])
941 if f.endswith(".rc")])
942 except OSError:
942 except OSError:
943 pass
943 pass
944 return rcs
944 return rcs
945
945
946 def system_rcpath():
946 def system_rcpath():
947 path = []
947 path = []
948 # old mod_python does not set sys.argv
948 # old mod_python does not set sys.argv
949 if len(getattr(sys, 'argv', [])) > 0:
949 if len(getattr(sys, 'argv', [])) > 0:
950 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
950 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
951 '/../etc/mercurial'))
951 '/../etc/mercurial'))
952 path.extend(rcfiles('/etc/mercurial'))
952 path.extend(rcfiles('/etc/mercurial'))
953 return path
953 return path
954
954
955 def user_rcpath():
955 def user_rcpath():
956 return [os.path.expanduser('~/.hgrc')]
956 return [os.path.expanduser('~/.hgrc')]
957
957
958 def parse_patch_output(output_line):
958 def parse_patch_output(output_line):
959 """parses the output produced by patch and returns the file name"""
959 """parses the output produced by patch and returns the file name"""
960 pf = output_line[14:]
960 pf = output_line[14:]
961 if pf.startswith("'") and pf.endswith("'") and " " in pf:
961 if pf.startswith("'") and pf.endswith("'") and " " in pf:
962 pf = pf[1:-1] # Remove the quotes
962 pf = pf[1:-1] # Remove the quotes
963 return pf
963 return pf
964
964
965 def is_exec(f):
965 def is_exec(f):
966 """check whether a file is executable"""
966 """check whether a file is executable"""
967 return (os.lstat(f).st_mode & 0100 != 0)
967 return (os.lstat(f).st_mode & 0100 != 0)
968
968
969 def set_exec(f, mode):
969 def set_exec(f, mode):
970 s = os.lstat(f).st_mode
970 s = os.lstat(f).st_mode
971 if (s & 0100 != 0) == mode:
971 if (s & 0100 != 0) == mode:
972 return
972 return
973 if mode:
973 if mode:
974 # Turn on +x for every +r bit when making a file executable
974 # Turn on +x for every +r bit when making a file executable
975 # and obey umask.
975 # and obey umask.
976 os.chmod(f, s | (s & 0444) >> 2 & ~_umask)
976 os.chmod(f, s | (s & 0444) >> 2 & ~_umask)
977 else:
977 else:
978 os.chmod(f, s & 0666)
978 os.chmod(f, s & 0666)
979
979
980 def set_link(f, mode):
980 def set_link(f, mode):
981 """make a file a symbolic link/regular file
981 """make a file a symbolic link/regular file
982
982
983 if a file is changed to a link, its contents become the link data
983 if a file is changed to a link, its contents become the link data
984 if a link is changed to a file, its link data become its contents
984 if a link is changed to a file, its link data become its contents
985 """
985 """
986
986
987 m = os.path.islink(f)
987 m = os.path.islink(f)
988 if m == bool(mode):
988 if m == bool(mode):
989 return
989 return
990
990
991 if mode: # switch file to link
991 if mode: # switch file to link
992 data = file(f).read()
992 data = file(f).read()
993 os.unlink(f)
993 os.unlink(f)
994 os.symlink(data, f)
994 os.symlink(data, f)
995 else:
995 else:
996 data = os.readlink(f)
996 data = os.readlink(f)
997 os.unlink(f)
997 os.unlink(f)
998 file(f, "w").write(data)
998 file(f, "w").write(data)
999
999
1000 def set_binary(fd):
1000 def set_binary(fd):
1001 pass
1001 pass
1002
1002
1003 def pconvert(path):
1003 def pconvert(path):
1004 return path
1004 return path
1005
1005
1006 def localpath(path):
1006 def localpath(path):
1007 return path
1007 return path
1008
1008
1009 normpath = os.path.normpath
1009 normpath = os.path.normpath
1010 samestat = os.path.samestat
1010 samestat = os.path.samestat
1011
1011
1012 def makelock(info, pathname):
1012 def makelock(info, pathname):
1013 try:
1013 try:
1014 os.symlink(info, pathname)
1014 os.symlink(info, pathname)
1015 except OSError, why:
1015 except OSError, why:
1016 if why.errno == errno.EEXIST:
1016 if why.errno == errno.EEXIST:
1017 raise
1017 raise
1018 else:
1018 else:
1019 _makelock_file(info, pathname)
1019 _makelock_file(info, pathname)
1020
1020
1021 def readlock(pathname):
1021 def readlock(pathname):
1022 try:
1022 try:
1023 return os.readlink(pathname)
1023 return os.readlink(pathname)
1024 except OSError, why:
1024 except OSError, why:
1025 if why.errno == errno.EINVAL:
1025 if why.errno == errno.EINVAL:
1026 return _readlock_file(pathname)
1026 return _readlock_file(pathname)
1027 else:
1027 else:
1028 raise
1028 raise
1029
1029
1030 def shellquote(s):
1030 def shellquote(s):
1031 return "'%s'" % s.replace("'", "'\\''")
1031 return "'%s'" % s.replace("'", "'\\''")
1032
1032
1033 def testpid(pid):
1033 def testpid(pid):
1034 '''return False if pid dead, True if running or not sure'''
1034 '''return False if pid dead, True if running or not sure'''
1035 try:
1035 try:
1036 os.kill(pid, 0)
1036 os.kill(pid, 0)
1037 return True
1037 return True
1038 except OSError, inst:
1038 except OSError, inst:
1039 return inst.errno != errno.ESRCH
1039 return inst.errno != errno.ESRCH
1040
1040
1041 def explain_exit(code):
1041 def explain_exit(code):
1042 """return a 2-tuple (desc, code) describing a process's status"""
1042 """return a 2-tuple (desc, code) describing a process's status"""
1043 if os.WIFEXITED(code):
1043 if os.WIFEXITED(code):
1044 val = os.WEXITSTATUS(code)
1044 val = os.WEXITSTATUS(code)
1045 return _("exited with status %d") % val, val
1045 return _("exited with status %d") % val, val
1046 elif os.WIFSIGNALED(code):
1046 elif os.WIFSIGNALED(code):
1047 val = os.WTERMSIG(code)
1047 val = os.WTERMSIG(code)
1048 return _("killed by signal %d") % val, val
1048 return _("killed by signal %d") % val, val
1049 elif os.WIFSTOPPED(code):
1049 elif os.WIFSTOPPED(code):
1050 val = os.WSTOPSIG(code)
1050 val = os.WSTOPSIG(code)
1051 return _("stopped by signal %d") % val, val
1051 return _("stopped by signal %d") % val, val
1052 raise ValueError(_("invalid exit code"))
1052 raise ValueError(_("invalid exit code"))
1053
1053
1054 def isowner(fp, st=None):
1054 def isowner(fp, st=None):
1055 """Return True if the file object f belongs to the current user.
1055 """Return True if the file object f belongs to the current user.
1056
1056
1057 The return value of a util.fstat(f) may be passed as the st argument.
1057 The return value of a util.fstat(f) may be passed as the st argument.
1058 """
1058 """
1059 if st is None:
1059 if st is None:
1060 st = fstat(fp)
1060 st = fstat(fp)
1061 return st.st_uid == os.getuid()
1061 return st.st_uid == os.getuid()
1062
1062
1063 def _buildencodefun():
1063 def _buildencodefun():
1064 e = '_'
1064 e = '_'
1065 win_reserved = [ord(x) for x in '\\:*?"<>|']
1065 win_reserved = [ord(x) for x in '\\:*?"<>|']
1066 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
1066 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
1067 for x in (range(32) + range(126, 256) + win_reserved):
1067 for x in (range(32) + range(126, 256) + win_reserved):
1068 cmap[chr(x)] = "~%02x" % x
1068 cmap[chr(x)] = "~%02x" % x
1069 for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
1069 for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
1070 cmap[chr(x)] = e + chr(x).lower()
1070 cmap[chr(x)] = e + chr(x).lower()
1071 dmap = {}
1071 dmap = {}
1072 for k, v in cmap.iteritems():
1072 for k, v in cmap.iteritems():
1073 dmap[v] = k
1073 dmap[v] = k
1074 def decode(s):
1074 def decode(s):
1075 i = 0
1075 i = 0
1076 while i < len(s):
1076 while i < len(s):
1077 for l in xrange(1, 4):
1077 for l in xrange(1, 4):
1078 try:
1078 try:
1079 yield dmap[s[i:i+l]]
1079 yield dmap[s[i:i+l]]
1080 i += l
1080 i += l
1081 break
1081 break
1082 except KeyError:
1082 except KeyError:
1083 pass
1083 pass
1084 else:
1084 else:
1085 raise KeyError
1085 raise KeyError
1086 return (lambda s: "".join([cmap[c] for c in s]),
1086 return (lambda s: "".join([cmap[c] for c in s]),
1087 lambda s: "".join(list(decode(s))))
1087 lambda s: "".join(list(decode(s))))
1088
1088
1089 encodefilename, decodefilename = _buildencodefun()
1089 encodefilename, decodefilename = _buildencodefun()
1090
1090
1091 def encodedopener(openerfn, fn):
1091 def encodedopener(openerfn, fn):
1092 def o(path, *args, **kw):
1092 def o(path, *args, **kw):
1093 return openerfn(fn(path), *args, **kw)
1093 return openerfn(fn(path), *args, **kw)
1094 return o
1094 return o
1095
1095
1096 def opener(base, audit=True):
1096 def opener(base, audit=True):
1097 """
1097 """
1098 return a function that opens files relative to base
1098 return a function that opens files relative to base
1099
1099
1100 this function is used to hide the details of COW semantics and
1100 this function is used to hide the details of COW semantics and
1101 remote file access from higher level code.
1101 remote file access from higher level code.
1102 """
1102 """
1103 p = base
1103 p = base
1104 audit_p = audit
1104 audit_p = audit
1105
1105
1106 def mktempcopy(name):
1106 def mktempcopy(name):
1107 d, fn = os.path.split(name)
1107 d, fn = os.path.split(name)
1108 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
1108 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
1109 os.close(fd)
1109 os.close(fd)
1110 ofp = posixfile(temp, "wb")
1110 ofp = posixfile(temp, "wb")
1111 try:
1111 try:
1112 try:
1112 try:
1113 ifp = posixfile(name, "rb")
1113 ifp = posixfile(name, "rb")
1114 except IOError, inst:
1114 except IOError, inst:
1115 if not getattr(inst, 'filename', None):
1115 if not getattr(inst, 'filename', None):
1116 inst.filename = name
1116 inst.filename = name
1117 raise
1117 raise
1118 for chunk in filechunkiter(ifp):
1118 for chunk in filechunkiter(ifp):
1119 ofp.write(chunk)
1119 ofp.write(chunk)
1120 ifp.close()
1120 ifp.close()
1121 ofp.close()
1121 ofp.close()
1122 except:
1122 except:
1123 try: os.unlink(temp)
1123 try: os.unlink(temp)
1124 except: pass
1124 except: pass
1125 raise
1125 raise
1126 st = os.lstat(name)
1126 st = os.lstat(name)
1127 os.chmod(temp, st.st_mode)
1127 os.chmod(temp, st.st_mode)
1128 return temp
1128 return temp
1129
1129
1130 class atomictempfile(posixfile):
1130 class atomictempfile(posixfile):
1131 """the file will only be copied when rename is called"""
1131 """the file will only be copied when rename is called"""
1132 def __init__(self, name, mode):
1132 def __init__(self, name, mode):
1133 self.__name = name
1133 self.__name = name
1134 self.temp = mktempcopy(name)
1134 self.temp = mktempcopy(name)
1135 posixfile.__init__(self, self.temp, mode)
1135 posixfile.__init__(self, self.temp, mode)
1136 def rename(self):
1136 def rename(self):
1137 if not self.closed:
1137 if not self.closed:
1138 posixfile.close(self)
1138 posixfile.close(self)
1139 rename(self.temp, localpath(self.__name))
1139 rename(self.temp, localpath(self.__name))
1140 def __del__(self):
1140 def __del__(self):
1141 if not self.closed:
1141 if not self.closed:
1142 try:
1142 try:
1143 os.unlink(self.temp)
1143 os.unlink(self.temp)
1144 except: pass
1144 except: pass
1145 posixfile.close(self)
1145 posixfile.close(self)
1146
1146
1147 class atomicfile(atomictempfile):
1147 class atomicfile(atomictempfile):
1148 """the file will only be copied on close"""
1148 """the file will only be copied on close"""
1149 def __init__(self, name, mode):
1149 def __init__(self, name, mode):
1150 atomictempfile.__init__(self, name, mode)
1150 atomictempfile.__init__(self, name, mode)
1151 def close(self):
1151 def close(self):
1152 self.rename()
1152 self.rename()
1153 def __del__(self):
1153 def __del__(self):
1154 self.rename()
1154 self.rename()
1155
1155
1156 def o(path, mode="r", text=False, atomic=False, atomictemp=False):
1156 def o(path, mode="r", text=False, atomic=False, atomictemp=False):
1157 if audit_p:
1157 if audit_p:
1158 audit_path(path)
1158 audit_path(path)
1159 f = os.path.join(p, path)
1159 f = os.path.join(p, path)
1160
1160
1161 if not text:
1161 if not text:
1162 mode += "b" # for that other OS
1162 mode += "b" # for that other OS
1163
1163
1164 if mode[0] != "r":
1164 if mode[0] != "r":
1165 try:
1165 try:
1166 nlink = nlinks(f)
1166 nlink = nlinks(f)
1167 except OSError:
1167 except OSError:
1168 d = os.path.dirname(f)
1168 d = os.path.dirname(f)
1169 if not os.path.isdir(d):
1169 if not os.path.isdir(d):
1170 os.makedirs(d)
1170 os.makedirs(d)
1171 else:
1171 else:
1172 if atomic:
1172 if atomic:
1173 return atomicfile(f, mode)
1173 return atomicfile(f, mode)
1174 elif atomictemp:
1174 elif atomictemp:
1175 return atomictempfile(f, mode)
1175 return atomictempfile(f, mode)
1176 if nlink > 1:
1176 if nlink > 1:
1177 rename(mktempcopy(f), f)
1177 rename(mktempcopy(f), f)
1178 return posixfile(f, mode)
1178 return posixfile(f, mode)
1179
1179
1180 return o
1180 return o
1181
1181
1182 class chunkbuffer(object):
1182 class chunkbuffer(object):
1183 """Allow arbitrary sized chunks of data to be efficiently read from an
1183 """Allow arbitrary sized chunks of data to be efficiently read from an
1184 iterator over chunks of arbitrary size."""
1184 iterator over chunks of arbitrary size."""
1185
1185
1186 def __init__(self, in_iter, targetsize = 2**16):
1186 def __init__(self, in_iter, targetsize = 2**16):
1187 """in_iter is the iterator that's iterating over the input chunks.
1187 """in_iter is the iterator that's iterating over the input chunks.
1188 targetsize is how big a buffer to try to maintain."""
1188 targetsize is how big a buffer to try to maintain."""
1189 self.in_iter = iter(in_iter)
1189 self.in_iter = iter(in_iter)
1190 self.buf = ''
1190 self.buf = ''
1191 self.targetsize = int(targetsize)
1191 self.targetsize = int(targetsize)
1192 if self.targetsize <= 0:
1192 if self.targetsize <= 0:
1193 raise ValueError(_("targetsize must be greater than 0, was %d") %
1193 raise ValueError(_("targetsize must be greater than 0, was %d") %
1194 targetsize)
1194 targetsize)
1195 self.iterempty = False
1195 self.iterempty = False
1196
1196
1197 def fillbuf(self):
1197 def fillbuf(self):
1198 """Ignore target size; read every chunk from iterator until empty."""
1198 """Ignore target size; read every chunk from iterator until empty."""
1199 if not self.iterempty:
1199 if not self.iterempty:
1200 collector = cStringIO.StringIO()
1200 collector = cStringIO.StringIO()
1201 collector.write(self.buf)
1201 collector.write(self.buf)
1202 for ch in self.in_iter:
1202 for ch in self.in_iter:
1203 collector.write(ch)
1203 collector.write(ch)
1204 self.buf = collector.getvalue()
1204 self.buf = collector.getvalue()
1205 self.iterempty = True
1205 self.iterempty = True
1206
1206
1207 def read(self, l):
1207 def read(self, l):
1208 """Read L bytes of data from the iterator of chunks of data.
1208 """Read L bytes of data from the iterator of chunks of data.
1209 Returns less than L bytes if the iterator runs dry."""
1209 Returns less than L bytes if the iterator runs dry."""
1210 if l > len(self.buf) and not self.iterempty:
1210 if l > len(self.buf) and not self.iterempty:
1211 # Clamp to a multiple of self.targetsize
1211 # Clamp to a multiple of self.targetsize
1212 targetsize = self.targetsize * ((l // self.targetsize) + 1)
1212 targetsize = self.targetsize * ((l // self.targetsize) + 1)
1213 collector = cStringIO.StringIO()
1213 collector = cStringIO.StringIO()
1214 collector.write(self.buf)
1214 collector.write(self.buf)
1215 collected = len(self.buf)
1215 collected = len(self.buf)
1216 for chunk in self.in_iter:
1216 for chunk in self.in_iter:
1217 collector.write(chunk)
1217 collector.write(chunk)
1218 collected += len(chunk)
1218 collected += len(chunk)
1219 if collected >= targetsize:
1219 if collected >= targetsize:
1220 break
1220 break
1221 if collected < targetsize:
1221 if collected < targetsize:
1222 self.iterempty = True
1222 self.iterempty = True
1223 self.buf = collector.getvalue()
1223 self.buf = collector.getvalue()
1224 s, self.buf = self.buf[:l], buffer(self.buf, l)
1224 s, self.buf = self.buf[:l], buffer(self.buf, l)
1225 return s
1225 return s
1226
1226
1227 def filechunkiter(f, size=65536, limit=None):
1227 def filechunkiter(f, size=65536, limit=None):
1228 """Create a generator that produces the data in the file size
1228 """Create a generator that produces the data in the file size
1229 (default 65536) bytes at a time, up to optional limit (default is
1229 (default 65536) bytes at a time, up to optional limit (default is
1230 to read all data). Chunks may be less than size bytes if the
1230 to read all data). Chunks may be less than size bytes if the
1231 chunk is the last chunk in the file, or the file is a socket or
1231 chunk is the last chunk in the file, or the file is a socket or
1232 some other type of file that sometimes reads less data than is
1232 some other type of file that sometimes reads less data than is
1233 requested."""
1233 requested."""
1234 assert size >= 0
1234 assert size >= 0
1235 assert limit is None or limit >= 0
1235 assert limit is None or limit >= 0
1236 while True:
1236 while True:
1237 if limit is None: nbytes = size
1237 if limit is None: nbytes = size
1238 else: nbytes = min(limit, size)
1238 else: nbytes = min(limit, size)
1239 s = nbytes and f.read(nbytes)
1239 s = nbytes and f.read(nbytes)
1240 if not s: break
1240 if not s: break
1241 if limit: limit -= len(s)
1241 if limit: limit -= len(s)
1242 yield s
1242 yield s
1243
1243
1244 def makedate():
1244 def makedate():
1245 lt = time.localtime()
1245 lt = time.localtime()
1246 if lt[8] == 1 and time.daylight:
1246 if lt[8] == 1 and time.daylight:
1247 tz = time.altzone
1247 tz = time.altzone
1248 else:
1248 else:
1249 tz = time.timezone
1249 tz = time.timezone
1250 return time.mktime(lt), tz
1250 return time.mktime(lt), tz
1251
1251
1252 def datestr(date=None, format='%a %b %d %H:%M:%S %Y', timezone=True):
1252 def datestr(date=None, format='%a %b %d %H:%M:%S %Y', timezone=True):
1253 """represent a (unixtime, offset) tuple as a localized time.
1253 """represent a (unixtime, offset) tuple as a localized time.
1254 unixtime is seconds since the epoch, and offset is the time zone's
1254 unixtime is seconds since the epoch, and offset is the time zone's
1255 number of seconds away from UTC. if timezone is false, do not
1255 number of seconds away from UTC. if timezone is false, do not
1256 append time zone to string."""
1256 append time zone to string."""
1257 t, tz = date or makedate()
1257 t, tz = date or makedate()
1258 s = time.strftime(format, time.gmtime(float(t) - tz))
1258 s = time.strftime(format, time.gmtime(float(t) - tz))
1259 if timezone:
1259 if timezone:
1260 s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60))
1260 s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60))
1261 return s
1261 return s
1262
1262
1263 def strdate(string, format, defaults):
1263 def strdate(string, format, defaults):
1264 """parse a localized time string and return a (unixtime, offset) tuple.
1264 """parse a localized time string and return a (unixtime, offset) tuple.
1265 if the string cannot be parsed, ValueError is raised."""
1265 if the string cannot be parsed, ValueError is raised."""
1266 def timezone(string):
1266 def timezone(string):
1267 tz = string.split()[-1]
1267 tz = string.split()[-1]
1268 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1268 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1269 tz = int(tz)
1269 tz = int(tz)
1270 offset = - 3600 * (tz / 100) - 60 * (tz % 100)
1270 offset = - 3600 * (tz / 100) - 60 * (tz % 100)
1271 return offset
1271 return offset
1272 if tz == "GMT" or tz == "UTC":
1272 if tz == "GMT" or tz == "UTC":
1273 return 0
1273 return 0
1274 return None
1274 return None
1275
1275
1276 # NOTE: unixtime = localunixtime + offset
1276 # NOTE: unixtime = localunixtime + offset
1277 offset, date = timezone(string), string
1277 offset, date = timezone(string), string
1278 if offset != None:
1278 if offset != None:
1279 date = " ".join(string.split()[:-1])
1279 date = " ".join(string.split()[:-1])
1280
1280
1281 # add missing elements from defaults
1281 # add missing elements from defaults
1282 for part in defaults:
1282 for part in defaults:
1283 found = [True for p in part if ("%"+p) in format]
1283 found = [True for p in part if ("%"+p) in format]
1284 if not found:
1284 if not found:
1285 date += "@" + defaults[part]
1285 date += "@" + defaults[part]
1286 format += "@%" + part[0]
1286 format += "@%" + part[0]
1287
1287
1288 timetuple = time.strptime(date, format)
1288 timetuple = time.strptime(date, format)
1289 localunixtime = int(calendar.timegm(timetuple))
1289 localunixtime = int(calendar.timegm(timetuple))
1290 if offset is None:
1290 if offset is None:
1291 # local timezone
1291 # local timezone
1292 unixtime = int(time.mktime(timetuple))
1292 unixtime = int(time.mktime(timetuple))
1293 offset = unixtime - localunixtime
1293 offset = unixtime - localunixtime
1294 else:
1294 else:
1295 unixtime = localunixtime + offset
1295 unixtime = localunixtime + offset
1296 return unixtime, offset
1296 return unixtime, offset
1297
1297
1298 def parsedate(string, formats=None, defaults=None):
1298 def parsedate(string, formats=None, defaults=None):
1299 """parse a localized time string and return a (unixtime, offset) tuple.
1299 """parse a localized time string and return a (unixtime, offset) tuple.
1300 The date may be a "unixtime offset" string or in one of the specified
1300 The date may be a "unixtime offset" string or in one of the specified
1301 formats."""
1301 formats."""
1302 if not string:
1302 if not string:
1303 return 0, 0
1303 return 0, 0
1304 if not formats:
1304 if not formats:
1305 formats = defaultdateformats
1305 formats = defaultdateformats
1306 string = string.strip()
1306 string = string.strip()
1307 try:
1307 try:
1308 when, offset = map(int, string.split(' '))
1308 when, offset = map(int, string.split(' '))
1309 except ValueError:
1309 except ValueError:
1310 # fill out defaults
1310 # fill out defaults
1311 if not defaults:
1311 if not defaults:
1312 defaults = {}
1312 defaults = {}
1313 now = makedate()
1313 now = makedate()
1314 for part in "d mb yY HI M S".split():
1314 for part in "d mb yY HI M S".split():
1315 if part not in defaults:
1315 if part not in defaults:
1316 if part[0] in "HMS":
1316 if part[0] in "HMS":
1317 defaults[part] = "00"
1317 defaults[part] = "00"
1318 elif part[0] in "dm":
1318 elif part[0] in "dm":
1319 defaults[part] = "1"
1319 defaults[part] = "1"
1320 else:
1320 else:
1321 defaults[part] = datestr(now, "%" + part[0], False)
1321 defaults[part] = datestr(now, "%" + part[0], False)
1322
1322
1323 for format in formats:
1323 for format in formats:
1324 try:
1324 try:
1325 when, offset = strdate(string, format, defaults)
1325 when, offset = strdate(string, format, defaults)
1326 except ValueError:
1326 except ValueError:
1327 pass
1327 pass
1328 else:
1328 else:
1329 break
1329 break
1330 else:
1330 else:
1331 raise Abort(_('invalid date: %r ') % string)
1331 raise Abort(_('invalid date: %r ') % string)
1332 # validate explicit (probably user-specified) date and
1332 # validate explicit (probably user-specified) date and
1333 # time zone offset. values must fit in signed 32 bits for
1333 # time zone offset. values must fit in signed 32 bits for
1334 # current 32-bit linux runtimes. timezones go from UTC-12
1334 # current 32-bit linux runtimes. timezones go from UTC-12
1335 # to UTC+14
1335 # to UTC+14
1336 if abs(when) > 0x7fffffff:
1336 if abs(when) > 0x7fffffff:
1337 raise Abort(_('date exceeds 32 bits: %d') % when)
1337 raise Abort(_('date exceeds 32 bits: %d') % when)
1338 if offset < -50400 or offset > 43200:
1338 if offset < -50400 or offset > 43200:
1339 raise Abort(_('impossible time zone offset: %d') % offset)
1339 raise Abort(_('impossible time zone offset: %d') % offset)
1340 return when, offset
1340 return when, offset
1341
1341
1342 def matchdate(date):
1342 def matchdate(date):
1343 """Return a function that matches a given date match specifier
1343 """Return a function that matches a given date match specifier
1344
1344
1345 Formats include:
1345 Formats include:
1346
1346
1347 '{date}' match a given date to the accuracy provided
1347 '{date}' match a given date to the accuracy provided
1348
1348
1349 '<{date}' on or before a given date
1349 '<{date}' on or before a given date
1350
1350
1351 '>{date}' on or after a given date
1351 '>{date}' on or after a given date
1352
1352
1353 """
1353 """
1354
1354
1355 def lower(date):
1355 def lower(date):
1356 return parsedate(date, extendeddateformats)[0]
1356 return parsedate(date, extendeddateformats)[0]
1357
1357
1358 def upper(date):
1358 def upper(date):
1359 d = dict(mb="12", HI="23", M="59", S="59")
1359 d = dict(mb="12", HI="23", M="59", S="59")
1360 for days in "31 30 29".split():
1360 for days in "31 30 29".split():
1361 try:
1361 try:
1362 d["d"] = days
1362 d["d"] = days
1363 return parsedate(date, extendeddateformats, d)[0]
1363 return parsedate(date, extendeddateformats, d)[0]
1364 except:
1364 except:
1365 pass
1365 pass
1366 d["d"] = "28"
1366 d["d"] = "28"
1367 return parsedate(date, extendeddateformats, d)[0]
1367 return parsedate(date, extendeddateformats, d)[0]
1368
1368
1369 if date[0] == "<":
1369 if date[0] == "<":
1370 when = upper(date[1:])
1370 when = upper(date[1:])
1371 return lambda x: x <= when
1371 return lambda x: x <= when
1372 elif date[0] == ">":
1372 elif date[0] == ">":
1373 when = lower(date[1:])
1373 when = lower(date[1:])
1374 return lambda x: x >= when
1374 return lambda x: x >= when
1375 elif date[0] == "-":
1375 elif date[0] == "-":
1376 try:
1376 try:
1377 days = int(date[1:])
1377 days = int(date[1:])
1378 except ValueError:
1378 except ValueError:
1379 raise Abort(_("invalid day spec: %s") % date[1:])
1379 raise Abort(_("invalid day spec: %s") % date[1:])
1380 when = makedate()[0] - days * 3600 * 24
1380 when = makedate()[0] - days * 3600 * 24
1381 return lambda x: x >= when
1381 return lambda x: x >= when
1382 elif " to " in date:
1382 elif " to " in date:
1383 a, b = date.split(" to ")
1383 a, b = date.split(" to ")
1384 start, stop = lower(a), upper(b)
1384 start, stop = lower(a), upper(b)
1385 return lambda x: x >= start and x <= stop
1385 return lambda x: x >= start and x <= stop
1386 else:
1386 else:
1387 start, stop = lower(date), upper(date)
1387 start, stop = lower(date), upper(date)
1388 return lambda x: x >= start and x <= stop
1388 return lambda x: x >= start and x <= stop
1389
1389
1390 def shortuser(user):
1390 def shortuser(user):
1391 """Return a short representation of a user name or email address."""
1391 """Return a short representation of a user name or email address."""
1392 f = user.find('@')
1392 f = user.find('@')
1393 if f >= 0:
1393 if f >= 0:
1394 user = user[:f]
1394 user = user[:f]
1395 f = user.find('<')
1395 f = user.find('<')
1396 if f >= 0:
1396 if f >= 0:
1397 user = user[f+1:]
1397 user = user[f+1:]
1398 f = user.find(' ')
1398 f = user.find(' ')
1399 if f >= 0:
1399 if f >= 0:
1400 user = user[:f]
1400 user = user[:f]
1401 f = user.find('.')
1401 f = user.find('.')
1402 if f >= 0:
1402 if f >= 0:
1403 user = user[:f]
1403 user = user[:f]
1404 return user
1404 return user
1405
1405
1406 def ellipsis(text, maxlength=400):
1406 def ellipsis(text, maxlength=400):
1407 """Trim string to at most maxlength (default: 400) characters."""
1407 """Trim string to at most maxlength (default: 400) characters."""
1408 if len(text) <= maxlength:
1408 if len(text) <= maxlength:
1409 return text
1409 return text
1410 else:
1410 else:
1411 return "%s..." % (text[:maxlength-3])
1411 return "%s..." % (text[:maxlength-3])
1412
1412
1413 def walkrepos(path):
1413 def walkrepos(path):
1414 '''yield every hg repository under path, recursively.'''
1414 '''yield every hg repository under path, recursively.'''
1415 def errhandler(err):
1415 def errhandler(err):
1416 if err.filename == path:
1416 if err.filename == path:
1417 raise err
1417 raise err
1418
1418
1419 for root, dirs, files in os.walk(path, onerror=errhandler):
1419 for root, dirs, files in os.walk(path, onerror=errhandler):
1420 for d in dirs:
1420 for d in dirs:
1421 if d == '.hg':
1421 if d == '.hg':
1422 yield root
1422 yield root
1423 dirs[:] = []
1423 dirs[:] = []
1424 break
1424 break
1425
1425
1426 _rcpath = None
1426 _rcpath = None
1427
1427
1428 def os_rcpath():
1428 def os_rcpath():
1429 '''return default os-specific hgrc search path'''
1429 '''return default os-specific hgrc search path'''
1430 path = system_rcpath()
1430 path = system_rcpath()
1431 path.extend(user_rcpath())
1431 path.extend(user_rcpath())
1432 path = [os.path.normpath(f) for f in path]
1432 path = [os.path.normpath(f) for f in path]
1433 return path
1433 return path
1434
1434
1435 def rcpath():
1435 def rcpath():
1436 '''return hgrc search path. if env var HGRCPATH is set, use it.
1436 '''return hgrc search path. if env var HGRCPATH is set, use it.
1437 for each item in path, if directory, use files ending in .rc,
1437 for each item in path, if directory, use files ending in .rc,
1438 else use item.
1438 else use item.
1439 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1439 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1440 if no HGRCPATH, use default os-specific path.'''
1440 if no HGRCPATH, use default os-specific path.'''
1441 global _rcpath
1441 global _rcpath
1442 if _rcpath is None:
1442 if _rcpath is None:
1443 if 'HGRCPATH' in os.environ:
1443 if 'HGRCPATH' in os.environ:
1444 _rcpath = []
1444 _rcpath = []
1445 for p in os.environ['HGRCPATH'].split(os.pathsep):
1445 for p in os.environ['HGRCPATH'].split(os.pathsep):
1446 if not p: continue
1446 if not p: continue
1447 if os.path.isdir(p):
1447 if os.path.isdir(p):
1448 for f in os.listdir(p):
1448 for f in os.listdir(p):
1449 if f.endswith('.rc'):
1449 if f.endswith('.rc'):
1450 _rcpath.append(os.path.join(p, f))
1450 _rcpath.append(os.path.join(p, f))
1451 else:
1451 else:
1452 _rcpath.append(p)
1452 _rcpath.append(p)
1453 else:
1453 else:
1454 _rcpath = os_rcpath()
1454 _rcpath = os_rcpath()
1455 return _rcpath
1455 return _rcpath
1456
1456
1457 def bytecount(nbytes):
1457 def bytecount(nbytes):
1458 '''return byte count formatted as readable string, with units'''
1458 '''return byte count formatted as readable string, with units'''
1459
1459
1460 units = (
1460 units = (
1461 (100, 1<<30, _('%.0f GB')),
1461 (100, 1<<30, _('%.0f GB')),
1462 (10, 1<<30, _('%.1f GB')),
1462 (10, 1<<30, _('%.1f GB')),
1463 (1, 1<<30, _('%.2f GB')),
1463 (1, 1<<30, _('%.2f GB')),
1464 (100, 1<<20, _('%.0f MB')),
1464 (100, 1<<20, _('%.0f MB')),
1465 (10, 1<<20, _('%.1f MB')),
1465 (10, 1<<20, _('%.1f MB')),
1466 (1, 1<<20, _('%.2f MB')),
1466 (1, 1<<20, _('%.2f MB')),
1467 (100, 1<<10, _('%.0f KB')),
1467 (100, 1<<10, _('%.0f KB')),
1468 (10, 1<<10, _('%.1f KB')),
1468 (10, 1<<10, _('%.1f KB')),
1469 (1, 1<<10, _('%.2f KB')),
1469 (1, 1<<10, _('%.2f KB')),
1470 (1, 1, _('%.0f bytes')),
1470 (1, 1, _('%.0f bytes')),
1471 )
1471 )
1472
1472
1473 for multiplier, divisor, format in units:
1473 for multiplier, divisor, format in units:
1474 if nbytes >= divisor * multiplier:
1474 if nbytes >= divisor * multiplier:
1475 return format % (nbytes / float(divisor))
1475 return format % (nbytes / float(divisor))
1476 return units[-1][2] % nbytes
1476 return units[-1][2] % nbytes
1477
1477
1478 def drop_scheme(scheme, path):
1478 def drop_scheme(scheme, path):
1479 sc = scheme + ':'
1479 sc = scheme + ':'
1480 if path.startswith(sc):
1480 if path.startswith(sc):
1481 path = path[len(sc):]
1481 path = path[len(sc):]
1482 if path.startswith('//'):
1482 if path.startswith('//'):
1483 path = path[2:]
1483 path = path[2:]
1484 return path
1484 return path
@@ -1,52 +1,56 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 hglocate()
3 hglocate()
4 {
4 {
5 echo "hg locate $@"
5 echo "hg locate $@"
6 hg locate "$@"
6 hg locate "$@"
7 ret=$?
7 ret=$?
8 echo
8 echo
9 return $ret
9 return $ret
10 }
10 }
11
11
12 mkdir t
12 mkdir t
13 cd t
13 cd t
14 hg init
14 hg init
15 echo 0 > a
15 echo 0 > a
16 echo 0 > b
16 echo 0 > b
17 echo 0 > t.h
17 echo 0 > t.h
18 mkdir t
18 mkdir t
19 echo 0 > t/x
19 echo 0 > t/x
20 echo 0 > t/b
20 echo 0 > t/b
21 echo 0 > t/e.h
21 echo 0 > t/e.h
22 mkdir dir.h
23 echo 0 > dir.h/foo
22 hg ci -A -m m -d "1000000 0"
24 hg ci -A -m m -d "1000000 0"
23 touch nottracked
25 touch nottracked
24 hglocate a && echo locate succeeded || echo locate failed
26 hglocate a && echo locate succeeded || echo locate failed
25 hglocate NONEXISTENT && echo locate succeeded || echo locate failed
27 hglocate NONEXISTENT && echo locate succeeded || echo locate failed
26 hglocate
28 hglocate
27 hg rm a
29 hg rm a
28 hg ci -m m -d "1000000 0"
30 hg ci -m m -d "1000000 0"
29 hglocate a
31 hglocate a
30 hglocate NONEXISTENT
32 hglocate NONEXISTENT
33 hglocate relpath:NONEXISTENT
31 hglocate
34 hglocate
32 hglocate -r 0 a
35 hglocate -r 0 a
33 hglocate -r 0 NONEXISTENT
36 hglocate -r 0 NONEXISTENT
37 hglocate -r 0 relpath:NONEXISTENT
34 hglocate -r 0
38 hglocate -r 0
35 echo % -I/-X with relative path should work
39 echo % -I/-X with relative path should work
36 cd t
40 cd t
37 hglocate
41 hglocate
38 hglocate -I ../t
42 hglocate -I ../t
39 # test issue294
43 # test issue294
40 cd ..
44 cd ..
41 rm -r t
45 rm -r t
42 hglocate t
46 hglocate 't/**'
43 mkdir otherdir
47 mkdir otherdir
44 cd otherdir
48 cd otherdir
45 hglocate b
49 hglocate b
46 hglocate '*.h'
50 hglocate '*.h'
47 hglocate path:t/x
51 hglocate path:t/x
48 hglocate 're:.*\.h'
52 hglocate 're:.*\.h$'
49 hglocate -r 0 b
53 hglocate -r 0 b
50 hglocate -r 0 '*.h'
54 hglocate -r 0 '*.h'
51 hglocate -r 0 path:t/x
55 hglocate -r 0 path:t/x
52 hglocate -r 0 're:.*\.h'
56 hglocate -r 0 're:.*\.h$'
@@ -1,93 +1,102 b''
1 adding a
1 adding a
2 adding b
2 adding b
3 adding dir.h/foo
3 adding t.h
4 adding t.h
4 adding t/b
5 adding t/b
5 adding t/e.h
6 adding t/e.h
6 adding t/x
7 adding t/x
7 hg locate a
8 hg locate a
8 a
9 a
9
10
10 locate succeeded
11 locate succeeded
11 hg locate NONEXISTENT
12 hg locate NONEXISTENT
12
13
13 locate failed
14 locate failed
14 hg locate
15 hg locate
15 a
16 a
16 b
17 b
18 dir.h/foo
17 t.h
19 t.h
18 t/b
20 t/b
19 t/e.h
21 t/e.h
20 t/x
22 t/x
21
23
22 hg locate a
24 hg locate a
23
25
24 hg locate NONEXISTENT
26 hg locate NONEXISTENT
25
27
28 hg locate relpath:NONEXISTENT
29
26 hg locate
30 hg locate
27 b
31 b
32 dir.h/foo
28 t.h
33 t.h
29 t/b
34 t/b
30 t/e.h
35 t/e.h
31 t/x
36 t/x
32
37
33 hg locate -r 0 a
38 hg locate -r 0 a
34 a
39 a
35
40
36 hg locate -r 0 NONEXISTENT
41 hg locate -r 0 NONEXISTENT
37
42
43 hg locate -r 0 relpath:NONEXISTENT
44
38 hg locate -r 0
45 hg locate -r 0
39 a
46 a
40 b
47 b
48 dir.h/foo
41 t.h
49 t.h
42 t/b
50 t/b
43 t/e.h
51 t/e.h
44 t/x
52 t/x
45
53
46 % -I/-X with relative path should work
54 % -I/-X with relative path should work
47 hg locate
55 hg locate
48 b
56 b
57 dir.h/foo
49 t.h
58 t.h
50 t/b
59 t/b
51 t/e.h
60 t/e.h
52 t/x
61 t/x
53
62
54 hg locate -I ../t
63 hg locate -I ../t
55 t/b
64 t/b
56 t/e.h
65 t/e.h
57 t/x
66 t/x
58
67
59 hg locate t
68 hg locate t/**
60 t/b
69 t/b
61 t/e.h
70 t/e.h
62 t/x
71 t/x
63
72
64 hg locate b
73 hg locate b
65 ../b
74 ../b
66 ../t/b
75 ../t/b
67
76
68 hg locate *.h
77 hg locate *.h
69 ../t.h
78 ../t.h
70 ../t/e.h
79 ../t/e.h
71
80
72 hg locate path:t/x
81 hg locate path:t/x
73 ../t/x
82 ../t/x
74
83
75 hg locate re:.*\.h
84 hg locate re:.*\.h$
76 ../t.h
85 ../t.h
77 ../t/e.h
86 ../t/e.h
78
87
79 hg locate -r 0 b
88 hg locate -r 0 b
80 ../b
89 ../b
81 ../t/b
90 ../t/b
82
91
83 hg locate -r 0 *.h
92 hg locate -r 0 *.h
84 ../t.h
93 ../t.h
85 ../t/e.h
94 ../t/e.h
86
95
87 hg locate -r 0 path:t/x
96 hg locate -r 0 path:t/x
88 ../t/x
97 ../t/x
89
98
90 hg locate -r 0 re:.*\.h
99 hg locate -r 0 re:.*\.h$
91 ../t.h
100 ../t.h
92 ../t/e.h
101 ../t/e.h
93
102
@@ -1,98 +1,100 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 debugwalk()
3 debugwalk()
4 {
4 {
5 echo "hg debugwalk $@"
5 echo "hg debugwalk $@"
6 hg debugwalk "$@"
6 hg debugwalk "$@"
7 echo
7 echo
8 }
8 }
9
9
10 chdir()
10 chdir()
11 {
11 {
12 echo "cd $@"
12 echo "cd $@"
13 cd "$@"
13 cd "$@"
14 echo
14 echo
15 }
15 }
16
16
17 mkdir t
17 mkdir t
18 cd t
18 cd t
19 hg init
19 hg init
20 mkdir -p beans
20 mkdir -p beans
21 for b in kidney navy turtle borlotti black pinto; do
21 for b in kidney navy turtle borlotti black pinto; do
22 echo $b > beans/$b
22 echo $b > beans/$b
23 done
23 done
24 mkdir -p mammals/Procyonidae
24 mkdir -p mammals/Procyonidae
25 for m in cacomistle coatimundi raccoon; do
25 for m in cacomistle coatimundi raccoon; do
26 echo $m > mammals/Procyonidae/$m
26 echo $m > mammals/Procyonidae/$m
27 done
27 done
28 echo skunk > mammals/skunk
28 echo skunk > mammals/skunk
29 echo fennel > fennel
29 echo fennel > fennel
30 echo fenugreek > fenugreek
30 echo fenugreek > fenugreek
31 echo fiddlehead > fiddlehead
31 echo fiddlehead > fiddlehead
32 echo glob:glob > glob:glob
32 echo glob:glob > glob:glob
33 hg addremove
33 hg addremove
34 hg commit -m "commit #0" -d "1000000 0"
34 hg commit -m "commit #0" -d "1000000 0"
35 debugwalk
35 debugwalk
36 debugwalk -I.
36 debugwalk -I.
37 chdir mammals
37 chdir mammals
38 debugwalk
38 debugwalk
39 debugwalk -X ../beans
39 debugwalk -X ../beans
40 debugwalk -I '*k'
40 debugwalk -I '*k'
41 debugwalk -I 'glob:*k'
41 debugwalk -I 'glob:*k'
42 debugwalk -I 'relglob:*k'
42 debugwalk -I 'relglob:*k'
43 debugwalk -I 'relglob:*k' .
43 debugwalk -I 'relglob:*k' .
44 debugwalk -I 're:.*k$'
44 debugwalk -I 're:.*k$'
45 debugwalk -I 'relre:.*k$'
45 debugwalk -I 'relre:.*k$'
46 debugwalk -I 'path:beans'
46 debugwalk -I 'path:beans'
47 debugwalk -I 'relpath:../beans'
47 debugwalk -I 'relpath:../beans'
48 debugwalk .
48 debugwalk .
49 debugwalk -I.
49 debugwalk -I.
50 debugwalk Procyonidae
50 debugwalk Procyonidae
51 chdir Procyonidae
51 chdir Procyonidae
52 debugwalk .
52 debugwalk .
53 debugwalk ..
53 debugwalk ..
54 chdir ..
54 chdir ..
55 debugwalk ../beans
55 debugwalk ../beans
56 debugwalk .
56 debugwalk .
57 debugwalk .hg
57 debugwalk .hg
58 debugwalk ../.hg
58 debugwalk ../.hg
59 chdir ..
59 chdir ..
60 debugwalk -Ibeans
60 debugwalk -Ibeans
61 debugwalk 'glob:mammals/../beans/b*'
61 debugwalk 'glob:mammals/../beans/b*'
62 debugwalk '-X*/Procyonidae' mammals
62 debugwalk '-X*/Procyonidae' mammals
63 debugwalk path:mammals
63 debugwalk path:mammals
64 debugwalk ..
64 debugwalk ..
65 debugwalk beans/../..
65 debugwalk beans/../..
66 debugwalk .hg
66 debugwalk .hg
67 debugwalk beans/../.hg
67 debugwalk beans/../.hg
68 debugwalk beans/../.hg/data
68 debugwalk beans/../.hg/data
69 debugwalk beans/.hg
69 debugwalk beans/.hg
70 # Don't know how to test absolute paths without always getting a false
70 # Don't know how to test absolute paths without always getting a false
71 # error.
71 # error.
72 #debugwalk `pwd`/beans
72 #debugwalk `pwd`/beans
73 #debugwalk `pwd`/..
73 #debugwalk `pwd`/..
74 debugwalk glob:\*
74 debugwalk glob:\*
75 debugwalk 'glob:**e'
75 debugwalk 're:.*[kb]$'
76 debugwalk 're:.*[kb]$'
76 debugwalk path:beans/black
77 debugwalk path:beans/black
77 debugwalk path:beans//black
78 debugwalk path:beans//black
78 debugwalk relglob:Procyonidae
79 debugwalk relglob:Procyonidae
79 debugwalk relglob:Procyonidae/ fennel
80 debugwalk 'relglob:Procyonidae/**'
81 debugwalk 'relglob:Procyonidae/**' fennel
80 debugwalk beans 'glob:beans/*'
82 debugwalk beans 'glob:beans/*'
81 debugwalk 'glob:mamm**'
83 debugwalk 'glob:mamm**'
82 debugwalk 'glob:mamm**' fennel
84 debugwalk 'glob:mamm**' fennel
83 debugwalk 'glob:j*'
85 debugwalk 'glob:j*'
84 debugwalk NOEXIST
86 debugwalk NOEXIST
85 mkfifo fifo
87 mkfifo fifo
86 debugwalk fifo
88 debugwalk fifo
87 rm fenugreek
89 rm fenugreek
88 debugwalk fenugreek
90 debugwalk fenugreek
89 hg rm fenugreek
91 hg rm fenugreek
90 debugwalk fenugreek
92 debugwalk fenugreek
91 touch new
93 touch new
92 debugwalk new
94 debugwalk new
93 chdir ..
95 chdir ..
94 debugwalk -R t t/mammals/skunk
96 debugwalk -R t t/mammals/skunk
95 mkdir t2
97 mkdir t2
96 chdir t2
98 chdir t2
97 debugwalk -R ../t ../t/mammals/skunk
99 debugwalk -R ../t ../t/mammals/skunk
98 debugwalk --cwd ../t mammals/skunk
100 debugwalk --cwd ../t mammals/skunk
@@ -1,301 +1,297 b''
1 adding beans/black
1 adding beans/black
2 adding beans/borlotti
2 adding beans/borlotti
3 adding beans/kidney
3 adding beans/kidney
4 adding beans/navy
4 adding beans/navy
5 adding beans/pinto
5 adding beans/pinto
6 adding beans/turtle
6 adding beans/turtle
7 adding fennel
7 adding fennel
8 adding fenugreek
8 adding fenugreek
9 adding fiddlehead
9 adding fiddlehead
10 adding glob:glob
10 adding glob:glob
11 adding mammals/Procyonidae/cacomistle
11 adding mammals/Procyonidae/cacomistle
12 adding mammals/Procyonidae/coatimundi
12 adding mammals/Procyonidae/coatimundi
13 adding mammals/Procyonidae/raccoon
13 adding mammals/Procyonidae/raccoon
14 adding mammals/skunk
14 adding mammals/skunk
15 hg debugwalk
15 hg debugwalk
16 f beans/black beans/black
16 f beans/black beans/black
17 f beans/borlotti beans/borlotti
17 f beans/borlotti beans/borlotti
18 f beans/kidney beans/kidney
18 f beans/kidney beans/kidney
19 f beans/navy beans/navy
19 f beans/navy beans/navy
20 f beans/pinto beans/pinto
20 f beans/pinto beans/pinto
21 f beans/turtle beans/turtle
21 f beans/turtle beans/turtle
22 f fennel fennel
22 f fennel fennel
23 f fenugreek fenugreek
23 f fenugreek fenugreek
24 f fiddlehead fiddlehead
24 f fiddlehead fiddlehead
25 f glob:glob glob:glob
25 f glob:glob glob:glob
26 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
26 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
27 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
27 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
28 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
28 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
29 f mammals/skunk mammals/skunk
29 f mammals/skunk mammals/skunk
30
30
31 hg debugwalk -I.
31 hg debugwalk -I.
32 f beans/black beans/black
32 f beans/black beans/black
33 f beans/borlotti beans/borlotti
33 f beans/borlotti beans/borlotti
34 f beans/kidney beans/kidney
34 f beans/kidney beans/kidney
35 f beans/navy beans/navy
35 f beans/navy beans/navy
36 f beans/pinto beans/pinto
36 f beans/pinto beans/pinto
37 f beans/turtle beans/turtle
37 f beans/turtle beans/turtle
38 f fennel fennel
38 f fennel fennel
39 f fenugreek fenugreek
39 f fenugreek fenugreek
40 f fiddlehead fiddlehead
40 f fiddlehead fiddlehead
41 f glob:glob glob:glob
41 f glob:glob glob:glob
42 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
42 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
43 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
43 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
44 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
44 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
45 f mammals/skunk mammals/skunk
45 f mammals/skunk mammals/skunk
46
46
47 cd mammals
47 cd mammals
48
48
49 hg debugwalk
49 hg debugwalk
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 glob:glob ../glob:glob
59 f glob:glob ../glob:glob
60 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
60 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
61 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
61 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
62 f mammals/Procyonidae/raccoon Procyonidae/raccoon
62 f mammals/Procyonidae/raccoon Procyonidae/raccoon
63 f mammals/skunk skunk
63 f mammals/skunk skunk
64
64
65 hg debugwalk -X ../beans
65 hg debugwalk -X ../beans
66 f fennel ../fennel
66 f fennel ../fennel
67 f fenugreek ../fenugreek
67 f fenugreek ../fenugreek
68 f fiddlehead ../fiddlehead
68 f fiddlehead ../fiddlehead
69 f glob:glob ../glob:glob
69 f glob:glob ../glob:glob
70 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
70 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
71 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
71 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
72 f mammals/Procyonidae/raccoon Procyonidae/raccoon
72 f mammals/Procyonidae/raccoon Procyonidae/raccoon
73 f mammals/skunk skunk
73 f mammals/skunk skunk
74
74
75 hg debugwalk -I *k
75 hg debugwalk -I *k
76 f mammals/skunk skunk
76 f mammals/skunk skunk
77
77
78 hg debugwalk -I glob:*k
78 hg debugwalk -I glob:*k
79 f mammals/skunk skunk
79 f mammals/skunk skunk
80
80
81 hg debugwalk -I relglob:*k
81 hg debugwalk -I relglob:*k
82 f beans/black ../beans/black
82 f beans/black ../beans/black
83 f fenugreek ../fenugreek
83 f fenugreek ../fenugreek
84 f mammals/skunk skunk
84 f mammals/skunk skunk
85
85
86 hg debugwalk -I relglob:*k .
86 hg debugwalk -I relglob:*k .
87 f mammals/skunk skunk
87 f mammals/skunk skunk
88
88
89 hg debugwalk -I re:.*k$
89 hg debugwalk -I re:.*k$
90 f beans/black ../beans/black
90 f beans/black ../beans/black
91 f fenugreek ../fenugreek
91 f fenugreek ../fenugreek
92 f mammals/skunk skunk
92 f mammals/skunk skunk
93
93
94 hg debugwalk -I relre:.*k$
94 hg debugwalk -I relre:.*k$
95 f beans/black ../beans/black
95 f beans/black ../beans/black
96 f fenugreek ../fenugreek
96 f fenugreek ../fenugreek
97 f mammals/skunk skunk
97 f mammals/skunk skunk
98
98
99 hg debugwalk -I path:beans
99 hg debugwalk -I path:beans
100 f beans/black ../beans/black
100 f beans/black ../beans/black
101 f beans/borlotti ../beans/borlotti
101 f beans/borlotti ../beans/borlotti
102 f beans/kidney ../beans/kidney
102 f beans/kidney ../beans/kidney
103 f beans/navy ../beans/navy
103 f beans/navy ../beans/navy
104 f beans/pinto ../beans/pinto
104 f beans/pinto ../beans/pinto
105 f beans/turtle ../beans/turtle
105 f beans/turtle ../beans/turtle
106
106
107 hg debugwalk -I relpath:../beans
107 hg debugwalk -I relpath:../beans
108 f beans/black ../beans/black
108 f beans/black ../beans/black
109 f beans/borlotti ../beans/borlotti
109 f beans/borlotti ../beans/borlotti
110 f beans/kidney ../beans/kidney
110 f beans/kidney ../beans/kidney
111 f beans/navy ../beans/navy
111 f beans/navy ../beans/navy
112 f beans/pinto ../beans/pinto
112 f beans/pinto ../beans/pinto
113 f beans/turtle ../beans/turtle
113 f beans/turtle ../beans/turtle
114
114
115 hg debugwalk .
115 hg debugwalk .
116 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
116 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
117 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
117 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
118 f mammals/Procyonidae/raccoon Procyonidae/raccoon
118 f mammals/Procyonidae/raccoon Procyonidae/raccoon
119 f mammals/skunk skunk
119 f mammals/skunk skunk
120
120
121 hg debugwalk -I.
121 hg debugwalk -I.
122 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
122 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
123 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
123 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
124 f mammals/Procyonidae/raccoon Procyonidae/raccoon
124 f mammals/Procyonidae/raccoon Procyonidae/raccoon
125 f mammals/skunk skunk
125 f mammals/skunk skunk
126
126
127 hg debugwalk Procyonidae
127 hg debugwalk Procyonidae
128 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
128 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
129 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
129 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
130 f mammals/Procyonidae/raccoon Procyonidae/raccoon
130 f mammals/Procyonidae/raccoon Procyonidae/raccoon
131
131
132 cd Procyonidae
132 cd Procyonidae
133
133
134 hg debugwalk .
134 hg debugwalk .
135 f mammals/Procyonidae/cacomistle cacomistle
135 f mammals/Procyonidae/cacomistle cacomistle
136 f mammals/Procyonidae/coatimundi coatimundi
136 f mammals/Procyonidae/coatimundi coatimundi
137 f mammals/Procyonidae/raccoon raccoon
137 f mammals/Procyonidae/raccoon raccoon
138
138
139 hg debugwalk ..
139 hg debugwalk ..
140 f mammals/Procyonidae/cacomistle cacomistle
140 f mammals/Procyonidae/cacomistle cacomistle
141 f mammals/Procyonidae/coatimundi coatimundi
141 f mammals/Procyonidae/coatimundi coatimundi
142 f mammals/Procyonidae/raccoon raccoon
142 f mammals/Procyonidae/raccoon raccoon
143 f mammals/skunk ../skunk
143 f mammals/skunk ../skunk
144
144
145 cd ..
145 cd ..
146
146
147 hg debugwalk ../beans
147 hg debugwalk ../beans
148 f beans/black ../beans/black
148 f beans/black ../beans/black
149 f beans/borlotti ../beans/borlotti
149 f beans/borlotti ../beans/borlotti
150 f beans/kidney ../beans/kidney
150 f beans/kidney ../beans/kidney
151 f beans/navy ../beans/navy
151 f beans/navy ../beans/navy
152 f beans/pinto ../beans/pinto
152 f beans/pinto ../beans/pinto
153 f beans/turtle ../beans/turtle
153 f beans/turtle ../beans/turtle
154
154
155 hg debugwalk .
155 hg debugwalk .
156 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
156 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
157 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
157 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
158 f mammals/Procyonidae/raccoon Procyonidae/raccoon
158 f mammals/Procyonidae/raccoon Procyonidae/raccoon
159 f mammals/skunk skunk
159 f mammals/skunk skunk
160
160
161 hg debugwalk .hg
161 hg debugwalk .hg
162 .hg: No such file or directory
162 .hg: No such file or directory
163
163
164 hg debugwalk ../.hg
164 hg debugwalk ../.hg
165 abort: path contains illegal component: .hg
165 abort: path contains illegal component: .hg
166
166
167
167
168 cd ..
168 cd ..
169
169
170 hg debugwalk -Ibeans
170 hg debugwalk -Ibeans
171 f beans/black beans/black
171 f beans/black beans/black
172 f beans/borlotti beans/borlotti
172 f beans/borlotti beans/borlotti
173 f beans/kidney beans/kidney
173 f beans/kidney beans/kidney
174 f beans/navy beans/navy
174 f beans/navy beans/navy
175 f beans/pinto beans/pinto
175 f beans/pinto beans/pinto
176 f beans/turtle beans/turtle
176 f beans/turtle beans/turtle
177
177
178 hg debugwalk glob:mammals/../beans/b*
178 hg debugwalk glob:mammals/../beans/b*
179 f beans/black beans/black
179 f beans/black beans/black
180 f beans/borlotti beans/borlotti
180 f beans/borlotti beans/borlotti
181
181
182 hg debugwalk -X*/Procyonidae mammals
182 hg debugwalk -X*/Procyonidae mammals
183 f mammals/skunk mammals/skunk
183 f mammals/skunk mammals/skunk
184
184
185 hg debugwalk path:mammals
185 hg debugwalk path:mammals
186 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
186 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
187 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
187 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
188 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
188 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
189 f mammals/skunk mammals/skunk
189 f mammals/skunk mammals/skunk
190
190
191 hg debugwalk ..
191 hg debugwalk ..
192 abort: .. not under root
192 abort: .. not under root
193
193
194 hg debugwalk beans/../..
194 hg debugwalk beans/../..
195 abort: beans/../.. not under root
195 abort: beans/../.. not under root
196
196
197 hg debugwalk .hg
197 hg debugwalk .hg
198 abort: path contains illegal component: .hg
198 abort: path contains illegal component: .hg
199
199
200
200
201 hg debugwalk beans/../.hg
201 hg debugwalk beans/../.hg
202 abort: path contains illegal component: .hg
202 abort: path contains illegal component: .hg
203
203
204
204
205 hg debugwalk beans/../.hg/data
205 hg debugwalk beans/../.hg/data
206 abort: path contains illegal component: .hg/data
206 abort: path contains illegal component: .hg/data
207
207
208
208
209 hg debugwalk beans/.hg
209 hg debugwalk beans/.hg
210 beans/.hg: No such file or directory
210 beans/.hg: No such file or directory
211
211
212 hg debugwalk glob:*
212 hg debugwalk glob:*
213 f beans/black beans/black
213 f fennel fennel
214 f beans/borlotti beans/borlotti
214 f fenugreek fenugreek
215 f beans/kidney beans/kidney
215 f fiddlehead fiddlehead
216 f beans/navy beans/navy
216 f glob:glob glob:glob
217 f beans/pinto beans/pinto
217
218 hg debugwalk glob:**e
218 f beans/turtle beans/turtle
219 f beans/turtle beans/turtle
219 f fennel fennel
220 f fenugreek fenugreek
221 f fiddlehead fiddlehead
222 f glob:glob glob:glob
223 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
220 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
224 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
225 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
226 f mammals/skunk mammals/skunk
227
221
228 hg debugwalk re:.*[kb]$
222 hg debugwalk re:.*[kb]$
229 f beans/black beans/black
223 f beans/black beans/black
230 f fenugreek fenugreek
224 f fenugreek fenugreek
231 f glob:glob glob:glob
225 f glob:glob glob:glob
232 f mammals/skunk mammals/skunk
226 f mammals/skunk mammals/skunk
233
227
234 hg debugwalk path:beans/black
228 hg debugwalk path:beans/black
235 f beans/black beans/black exact
229 f beans/black beans/black exact
236
230
237 hg debugwalk path:beans//black
231 hg debugwalk path:beans//black
238 f beans/black beans/black exact
232 f beans/black beans/black exact
239
233
240 hg debugwalk relglob:Procyonidae
234 hg debugwalk relglob:Procyonidae
235
236 hg debugwalk relglob:Procyonidae/**
241 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
237 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
242 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
238 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
243 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
239 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
244
240
245 hg debugwalk relglob:Procyonidae/ fennel
241 hg debugwalk relglob:Procyonidae/** fennel
246 f fennel fennel exact
242 f fennel fennel exact
247 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
243 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
248 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
244 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
249 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
245 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
250
246
251 hg debugwalk beans glob:beans/*
247 hg debugwalk beans glob:beans/*
252 f beans/black beans/black
248 f beans/black beans/black
253 f beans/borlotti beans/borlotti
249 f beans/borlotti beans/borlotti
254 f beans/kidney beans/kidney
250 f beans/kidney beans/kidney
255 f beans/navy beans/navy
251 f beans/navy beans/navy
256 f beans/pinto beans/pinto
252 f beans/pinto beans/pinto
257 f beans/turtle beans/turtle
253 f beans/turtle beans/turtle
258
254
259 hg debugwalk glob:mamm**
255 hg debugwalk glob:mamm**
260 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
256 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
261 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
257 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
262 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
258 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
263 f mammals/skunk mammals/skunk
259 f mammals/skunk mammals/skunk
264
260
265 hg debugwalk glob:mamm** fennel
261 hg debugwalk glob:mamm** fennel
266 f fennel fennel exact
262 f fennel fennel exact
267 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
263 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
268 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
264 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
269 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
265 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
270 f mammals/skunk mammals/skunk
266 f mammals/skunk mammals/skunk
271
267
272 hg debugwalk glob:j*
268 hg debugwalk glob:j*
273
269
274 hg debugwalk NOEXIST
270 hg debugwalk NOEXIST
275 NOEXIST: No such file or directory
271 NOEXIST: No such file or directory
276
272
277 hg debugwalk fifo
273 hg debugwalk fifo
278 fifo: unsupported file type (type is fifo)
274 fifo: unsupported file type (type is fifo)
279
275
280 hg debugwalk fenugreek
276 hg debugwalk fenugreek
281 m fenugreek fenugreek exact
277 m fenugreek fenugreek exact
282
278
283 hg debugwalk fenugreek
279 hg debugwalk fenugreek
284 m fenugreek fenugreek exact
280 m fenugreek fenugreek exact
285
281
286 hg debugwalk new
282 hg debugwalk new
287 f new new exact
283 f new new exact
288
284
289 cd ..
285 cd ..
290
286
291 hg debugwalk -R t t/mammals/skunk
287 hg debugwalk -R t t/mammals/skunk
292 f mammals/skunk t/mammals/skunk exact
288 f mammals/skunk t/mammals/skunk exact
293
289
294 cd t2
290 cd t2
295
291
296 hg debugwalk -R ../t ../t/mammals/skunk
292 hg debugwalk -R ../t ../t/mammals/skunk
297 f mammals/skunk ../t/mammals/skunk exact
293 f mammals/skunk ../t/mammals/skunk exact
298
294
299 hg debugwalk --cwd ../t mammals/skunk
295 hg debugwalk --cwd ../t mammals/skunk
300 f mammals/skunk mammals/skunk exact
296 f mammals/skunk mammals/skunk exact
301
297
General Comments 0
You need to be logged in to leave comments. Login now