##// END OF EJS Templates
Merge with mpm
Brendan Cully -
r3818:bcdab0b2 merge default
parent child Browse files
Show More
@@ -1,3107 +1,3114 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 from demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), "bisect os re sys signal imp urllib pdb shlex stat")
11 demandload(globals(), "bisect os re sys signal imp urllib pdb shlex stat")
12 demandload(globals(), "fancyopts ui hg util lock revlog bundlerepo")
12 demandload(globals(), "fancyopts ui hg util lock revlog bundlerepo")
13 demandload(globals(), "difflib patch time help")
13 demandload(globals(), "difflib patch time help")
14 demandload(globals(), "traceback errno version atexit")
14 demandload(globals(), "traceback errno version atexit")
15 demandload(globals(), "archival changegroup cmdutil hgweb.server sshserver")
15 demandload(globals(), "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.
60 The files will be added to the repository at the next commit.
61
61
62 If no names are given, add all files in the repository.
62 If no names are given, add all files in the repository.
63 """
63 """
64
64
65 names = []
65 names = []
66 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
66 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
67 if exact:
67 if exact:
68 if ui.verbose:
68 if ui.verbose:
69 ui.status(_('adding %s\n') % rel)
69 ui.status(_('adding %s\n') % rel)
70 names.append(abs)
70 names.append(abs)
71 elif repo.dirstate.state(abs) == '?':
71 elif repo.dirstate.state(abs) == '?':
72 ui.status(_('adding %s\n') % rel)
72 ui.status(_('adding %s\n') % rel)
73 names.append(abs)
73 names.append(abs)
74 if not opts.get('dry_run'):
74 if not opts.get('dry_run'):
75 repo.add(names)
75 repo.add(names)
76
76
77 def addremove(ui, repo, *pats, **opts):
77 def addremove(ui, repo, *pats, **opts):
78 """add all new files, delete all missing files
78 """add all new files, delete all missing files
79
79
80 Add all new files and remove all missing files from the repository.
80 Add all new files and remove all missing files from the repository.
81
81
82 New files are ignored if they match any of the patterns in .hgignore. As
82 New files are ignored if they match any of the patterns in .hgignore. As
83 with add, these changes take effect at the next commit.
83 with add, these changes take effect at the next commit.
84
84
85 Use the -s option to detect renamed files. With a parameter > 0,
85 Use the -s option to detect renamed files. With a parameter > 0,
86 this compares every removed file with every added file and records
86 this compares every removed file with every added file and records
87 those similar enough as renames. This option takes a percentage
87 those similar enough as renames. This option takes a percentage
88 between 0 (disabled) and 100 (files must be identical) as its
88 between 0 (disabled) and 100 (files must be identical) as its
89 parameter. Detecting renamed files this way can be expensive.
89 parameter. Detecting renamed files this way can be expensive.
90 """
90 """
91 sim = float(opts.get('similarity') or 0)
91 sim = float(opts.get('similarity') or 0)
92 if sim < 0 or sim > 100:
92 if sim < 0 or sim > 100:
93 raise util.Abort(_('similarity must be between 0 and 100'))
93 raise util.Abort(_('similarity must be between 0 and 100'))
94 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
94 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
95
95
96 def annotate(ui, repo, *pats, **opts):
96 def annotate(ui, repo, *pats, **opts):
97 """show changeset information per file line
97 """show changeset information per file line
98
98
99 List changes in files, showing the revision id responsible for each line
99 List changes in files, showing the revision id responsible for each line
100
100
101 This command is useful to discover who did a change or when a change took
101 This command is useful to discover who did a change or when a change took
102 place.
102 place.
103
103
104 Without the -a option, annotate will avoid processing files it
104 Without the -a option, annotate will avoid processing files it
105 detects as binary. With -a, annotate will generate an annotation
105 detects as binary. With -a, annotate will generate an annotation
106 anyway, probably with undesirable results.
106 anyway, probably with undesirable results.
107 """
107 """
108 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
108 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
109
109
110 if not pats:
110 if not pats:
111 raise util.Abort(_('at least one file name or pattern required'))
111 raise util.Abort(_('at least one file name or pattern required'))
112
112
113 opmap = [['user', lambda x: ui.shortuser(x.user())],
113 opmap = [['user', lambda x: ui.shortuser(x.user())],
114 ['number', lambda x: str(x.rev())],
114 ['number', lambda x: str(x.rev())],
115 ['changeset', lambda x: short(x.node())],
115 ['changeset', lambda x: short(x.node())],
116 ['date', getdate], ['follow', lambda x: x.path()]]
116 ['date', getdate], ['follow', lambda x: x.path()]]
117 if (not opts['user'] and not opts['changeset'] and not opts['date']
117 if (not opts['user'] and not opts['changeset'] and not opts['date']
118 and not opts['follow']):
118 and not opts['follow']):
119 opts['number'] = 1
119 opts['number'] = 1
120
120
121 ctx = repo.changectx(opts['rev'])
121 ctx = repo.changectx(opts['rev'])
122
122
123 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
123 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
124 node=ctx.node()):
124 node=ctx.node()):
125 fctx = ctx.filectx(abs)
125 fctx = ctx.filectx(abs)
126 if not opts['text'] and util.binary(fctx.data()):
126 if not opts['text'] and util.binary(fctx.data()):
127 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
127 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
128 continue
128 continue
129
129
130 lines = fctx.annotate(follow=opts.get('follow'))
130 lines = fctx.annotate(follow=opts.get('follow'))
131 pieces = []
131 pieces = []
132
132
133 for o, f in opmap:
133 for o, f in opmap:
134 if opts[o]:
134 if opts[o]:
135 l = [f(n) for n, dummy in lines]
135 l = [f(n) for n, dummy in lines]
136 if l:
136 if l:
137 m = max(map(len, l))
137 m = max(map(len, l))
138 pieces.append(["%*s" % (m, x) for x in l])
138 pieces.append(["%*s" % (m, x) for x in l])
139
139
140 if pieces:
140 if pieces:
141 for p, l in zip(zip(*pieces), lines):
141 for p, l in zip(zip(*pieces), lines):
142 ui.write("%s: %s" % (" ".join(p), l[1]))
142 ui.write("%s: %s" % (" ".join(p), l[1]))
143
143
144 def archive(ui, repo, dest, **opts):
144 def archive(ui, repo, dest, **opts):
145 '''create unversioned archive of a repository revision
145 '''create unversioned archive of a repository revision
146
146
147 By default, the revision used is the parent of the working
147 By default, the revision used is the parent of the working
148 directory; use "-r" to specify a different revision.
148 directory; use "-r" to specify a different revision.
149
149
150 To specify the type of archive to create, use "-t". Valid
150 To specify the type of archive to create, use "-t". Valid
151 types are:
151 types are:
152
152
153 "files" (default): a directory full of files
153 "files" (default): a directory full of files
154 "tar": tar archive, uncompressed
154 "tar": tar archive, uncompressed
155 "tbz2": tar archive, compressed using bzip2
155 "tbz2": tar archive, compressed using bzip2
156 "tgz": tar archive, compressed using gzip
156 "tgz": tar archive, compressed using gzip
157 "uzip": zip archive, uncompressed
157 "uzip": zip archive, uncompressed
158 "zip": zip archive, compressed using deflate
158 "zip": zip archive, compressed using deflate
159
159
160 The exact name of the destination archive or directory is given
160 The exact name of the destination archive or directory is given
161 using a format string; see "hg help export" for details.
161 using a format string; see "hg help export" for details.
162
162
163 Each member added to an archive file has a directory prefix
163 Each member added to an archive file has a directory prefix
164 prepended. Use "-p" to specify a format string for the prefix.
164 prepended. Use "-p" to specify a format string for the prefix.
165 The default is the basename of the archive, with suffixes removed.
165 The default is the basename of the archive, with suffixes removed.
166 '''
166 '''
167
167
168 node = repo.changectx(opts['rev']).node()
168 node = repo.changectx(opts['rev']).node()
169 dest = cmdutil.make_filename(repo, dest, node)
169 dest = cmdutil.make_filename(repo, dest, node)
170 if os.path.realpath(dest) == repo.root:
170 if os.path.realpath(dest) == repo.root:
171 raise util.Abort(_('repository root cannot be destination'))
171 raise util.Abort(_('repository root cannot be destination'))
172 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
172 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
173 kind = opts.get('type') or 'files'
173 kind = opts.get('type') or 'files'
174 prefix = opts['prefix']
174 prefix = opts['prefix']
175 if dest == '-':
175 if dest == '-':
176 if kind == 'files':
176 if kind == 'files':
177 raise util.Abort(_('cannot archive plain files to stdout'))
177 raise util.Abort(_('cannot archive plain files to stdout'))
178 dest = sys.stdout
178 dest = sys.stdout
179 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
179 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
180 prefix = cmdutil.make_filename(repo, prefix, node)
180 prefix = cmdutil.make_filename(repo, prefix, node)
181 archival.archive(repo, dest, node, kind, not opts['no_decode'],
181 archival.archive(repo, dest, node, kind, not opts['no_decode'],
182 matchfn, prefix)
182 matchfn, prefix)
183
183
184 def backout(ui, repo, rev, **opts):
184 def backout(ui, repo, rev, **opts):
185 '''reverse effect of earlier changeset
185 '''reverse effect of earlier changeset
186
186
187 Commit the backed out changes as a new changeset. The new
187 Commit the backed out changes as a new changeset. The new
188 changeset is a child of the backed out changeset.
188 changeset is a child of the backed out changeset.
189
189
190 If you back out a changeset other than the tip, a new head is
190 If you back out a changeset other than the tip, a new head is
191 created. This head is the parent of the working directory. If
191 created. This head is the parent of the working directory. If
192 you back out an old changeset, your working directory will appear
192 you back out an old changeset, your working directory will appear
193 old after the backout. You should merge the backout changeset
193 old after the backout. You should merge the backout changeset
194 with another head.
194 with another head.
195
195
196 The --merge option remembers the parent of the working directory
196 The --merge option remembers the parent of the working directory
197 before starting the backout, then merges the new head with that
197 before starting the backout, then merges the new head with that
198 changeset afterwards. This saves you from doing the merge by
198 changeset afterwards. This saves you from doing the merge by
199 hand. The result of this merge is not committed, as for a normal
199 hand. The result of this merge is not committed, as for a normal
200 merge.'''
200 merge.'''
201
201
202 bail_if_changed(repo)
202 bail_if_changed(repo)
203 op1, op2 = repo.dirstate.parents()
203 op1, op2 = repo.dirstate.parents()
204 if op2 != nullid:
204 if op2 != nullid:
205 raise util.Abort(_('outstanding uncommitted merge'))
205 raise util.Abort(_('outstanding uncommitted merge'))
206 node = repo.lookup(rev)
206 node = repo.lookup(rev)
207 p1, p2 = repo.changelog.parents(node)
207 p1, p2 = repo.changelog.parents(node)
208 if p1 == nullid:
208 if p1 == nullid:
209 raise util.Abort(_('cannot back out a change with no parents'))
209 raise util.Abort(_('cannot back out a change with no parents'))
210 if p2 != nullid:
210 if p2 != nullid:
211 if not opts['parent']:
211 if not opts['parent']:
212 raise util.Abort(_('cannot back out a merge changeset without '
212 raise util.Abort(_('cannot back out a merge changeset without '
213 '--parent'))
213 '--parent'))
214 p = repo.lookup(opts['parent'])
214 p = repo.lookup(opts['parent'])
215 if p not in (p1, p2):
215 if p not in (p1, p2):
216 raise util.Abort(_('%s is not a parent of %s') %
216 raise util.Abort(_('%s is not a parent of %s') %
217 (short(p), short(node)))
217 (short(p), short(node)))
218 parent = p
218 parent = p
219 else:
219 else:
220 if opts['parent']:
220 if opts['parent']:
221 raise util.Abort(_('cannot use --parent on non-merge changeset'))
221 raise util.Abort(_('cannot use --parent on non-merge changeset'))
222 parent = p1
222 parent = p1
223 hg.clean(repo, node, show_stats=False)
223 hg.clean(repo, node, show_stats=False)
224 revert_opts = opts.copy()
224 revert_opts = opts.copy()
225 revert_opts['all'] = True
225 revert_opts['all'] = True
226 revert_opts['rev'] = hex(parent)
226 revert_opts['rev'] = hex(parent)
227 revert(ui, repo, **revert_opts)
227 revert(ui, repo, **revert_opts)
228 commit_opts = opts.copy()
228 commit_opts = opts.copy()
229 commit_opts['addremove'] = False
229 commit_opts['addremove'] = False
230 if not commit_opts['message'] and not commit_opts['logfile']:
230 if not commit_opts['message'] and not commit_opts['logfile']:
231 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
231 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
232 commit_opts['force_editor'] = True
232 commit_opts['force_editor'] = True
233 commit(ui, repo, **commit_opts)
233 commit(ui, repo, **commit_opts)
234 def nice(node):
234 def nice(node):
235 return '%d:%s' % (repo.changelog.rev(node), short(node))
235 return '%d:%s' % (repo.changelog.rev(node), short(node))
236 ui.status(_('changeset %s backs out changeset %s\n') %
236 ui.status(_('changeset %s backs out changeset %s\n') %
237 (nice(repo.changelog.tip()), nice(node)))
237 (nice(repo.changelog.tip()), nice(node)))
238 if op1 != node:
238 if op1 != node:
239 if opts['merge']:
239 if opts['merge']:
240 ui.status(_('merging with changeset %s\n') % nice(op1))
240 ui.status(_('merging with changeset %s\n') % nice(op1))
241 n = _lookup(repo, hex(op1))
241 n = _lookup(repo, hex(op1))
242 hg.merge(repo, n)
242 hg.merge(repo, n)
243 else:
243 else:
244 ui.status(_('the backout changeset is a new head - '
244 ui.status(_('the backout changeset is a new head - '
245 'do not forget to merge\n'))
245 'do not forget to merge\n'))
246 ui.status(_('(use "backout --merge" '
246 ui.status(_('(use "backout --merge" '
247 'if you want to auto-merge)\n'))
247 'if you want to auto-merge)\n'))
248
248
249 def branch(ui, repo, label=None):
249 def branch(ui, repo, label=None):
250 """set or show the current branch name
250 """set or show the current branch name
251
251
252 With <name>, set the current branch name. Otherwise, show the
252 With <name>, set the current branch name. Otherwise, show the
253 current branch name.
253 current branch name.
254 """
254 """
255
255
256 if label is not None:
256 if label is not None:
257 repo.opener("branch", "w").write(label)
257 repo.opener("branch", "w").write(label)
258 else:
258 else:
259 b = repo.workingctx().branch()
259 b = repo.workingctx().branch()
260 if b:
260 if b:
261 ui.write("%s\n" % b)
261 ui.write("%s\n" % b)
262
262
263 def branches(ui, repo):
263 def branches(ui, repo):
264 """list repository named branches
264 """list repository named branches
265
265
266 List the repository's named branches.
266 List the repository's named branches.
267 """
267 """
268 b = repo.branchtags()
268 b = repo.branchtags()
269 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
269 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
270 l.sort()
270 l.sort()
271 for r, n, t in l:
271 for r, n, t in l:
272 hexfunc = ui.debugflag and hex or short
272 hexfunc = ui.debugflag and hex or short
273 if ui.quiet:
273 if ui.quiet:
274 ui.write("%s\n" % t)
274 ui.write("%s\n" % t)
275 else:
275 else:
276 t = util.localsub(t, 30)
276 t = util.localsub(t, 30)
277 t += " " * (30 - util.locallen(t))
277 t += " " * (30 - util.locallen(t))
278 ui.write("%s %s:%s\n" % (t, -r, hexfunc(n)))
278 ui.write("%s %s:%s\n" % (t, -r, hexfunc(n)))
279
279
280 def bundle(ui, repo, fname, dest=None, **opts):
280 def bundle(ui, repo, fname, dest=None, **opts):
281 """create a changegroup file
281 """create a changegroup file
282
282
283 Generate a compressed changegroup file collecting changesets not
283 Generate a compressed changegroup file collecting changesets not
284 found in the other repository.
284 found in the other repository.
285
285
286 If no destination repository is specified the destination is assumed
286 If no destination repository is specified the destination is assumed
287 to have all the nodes specified by one or more --base parameters.
287 to have all the nodes specified by one or more --base parameters.
288
288
289 The bundle file can then be transferred using conventional means and
289 The bundle file can then be transferred using conventional means and
290 applied to another repository with the unbundle or pull command.
290 applied to another repository with the unbundle or pull command.
291 This is useful when direct push and pull are not available or when
291 This is useful when direct push and pull are not available or when
292 exporting an entire repository is undesirable.
292 exporting an entire repository is undesirable.
293
293
294 Applying bundles preserves all changeset contents including
294 Applying bundles preserves all changeset contents including
295 permissions, copy/rename information, and revision history.
295 permissions, copy/rename information, and revision history.
296 """
296 """
297 revs = opts.get('rev') or None
297 revs = opts.get('rev') or None
298 if revs:
298 if revs:
299 revs = [repo.lookup(rev) for rev in revs]
299 revs = [repo.lookup(rev) for rev in revs]
300 base = opts.get('base')
300 base = opts.get('base')
301 if base:
301 if base:
302 if dest:
302 if dest:
303 raise util.Abort(_("--base is incompatible with specifiying "
303 raise util.Abort(_("--base is incompatible with specifiying "
304 "a destination"))
304 "a destination"))
305 base = [repo.lookup(rev) for rev in base]
305 base = [repo.lookup(rev) for rev in base]
306 # create the right base
306 # create the right base
307 # XXX: nodesbetween / changegroup* should be "fixed" instead
307 # XXX: nodesbetween / changegroup* should be "fixed" instead
308 o = []
308 o = []
309 has = {nullid: None}
309 has = {nullid: None}
310 for n in base:
310 for n in base:
311 has.update(repo.changelog.reachable(n))
311 has.update(repo.changelog.reachable(n))
312 if revs:
312 if revs:
313 visit = list(revs)
313 visit = list(revs)
314 else:
314 else:
315 visit = repo.changelog.heads()
315 visit = repo.changelog.heads()
316 seen = {}
316 seen = {}
317 while visit:
317 while visit:
318 n = visit.pop(0)
318 n = visit.pop(0)
319 parents = [p for p in repo.changelog.parents(n) if p not in has]
319 parents = [p for p in repo.changelog.parents(n) if p not in has]
320 if len(parents) == 0:
320 if len(parents) == 0:
321 o.insert(0, n)
321 o.insert(0, n)
322 else:
322 else:
323 for p in parents:
323 for p in parents:
324 if p not in seen:
324 if p not in seen:
325 seen[p] = 1
325 seen[p] = 1
326 visit.append(p)
326 visit.append(p)
327 else:
327 else:
328 setremoteconfig(ui, opts)
328 setremoteconfig(ui, opts)
329 dest = ui.expandpath(dest or 'default-push', dest or 'default')
329 dest = ui.expandpath(dest or 'default-push', dest or 'default')
330 other = hg.repository(ui, dest)
330 other = hg.repository(ui, dest)
331 o = repo.findoutgoing(other, force=opts['force'])
331 o = repo.findoutgoing(other, force=opts['force'])
332
332
333 if revs:
333 if revs:
334 cg = repo.changegroupsubset(o, revs, 'bundle')
334 cg = repo.changegroupsubset(o, revs, 'bundle')
335 else:
335 else:
336 cg = repo.changegroup(o, 'bundle')
336 cg = repo.changegroup(o, 'bundle')
337 changegroup.writebundle(cg, fname, "HG10BZ")
337 changegroup.writebundle(cg, fname, "HG10BZ")
338
338
339 def cat(ui, repo, file1, *pats, **opts):
339 def cat(ui, repo, file1, *pats, **opts):
340 """output the latest or given revisions of files
340 """output the latest or given revisions of files
341
341
342 Print the specified files as they were at the given revision.
342 Print the specified files as they were at the given revision.
343 If no revision is given then working dir parent is used, or tip
343 If no revision is given then working dir parent is used, or tip
344 if no revision is checked out.
344 if no revision is checked out.
345
345
346 Output may be to a file, in which case the name of the file is
346 Output may be to a file, in which case the name of the file is
347 given using a format string. The formatting rules are the same as
347 given using a format string. The formatting rules are the same as
348 for the export command, with the following additions:
348 for the export command, with the following additions:
349
349
350 %s basename of file being printed
350 %s basename of file being printed
351 %d dirname of file being printed, or '.' if in repo root
351 %d dirname of file being printed, or '.' if in repo root
352 %p root-relative path name of file being printed
352 %p root-relative path name of file being printed
353 """
353 """
354 ctx = repo.changectx(opts['rev'])
354 ctx = repo.changectx(opts['rev'])
355 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
355 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
356 ctx.node()):
356 ctx.node()):
357 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
357 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
358 fp.write(ctx.filectx(abs).data())
358 fp.write(ctx.filectx(abs).data())
359
359
360 def clone(ui, source, dest=None, **opts):
360 def clone(ui, source, dest=None, **opts):
361 """make a copy of an existing repository
361 """make a copy of an existing repository
362
362
363 Create a copy of an existing repository in a new directory.
363 Create a copy of an existing repository in a new directory.
364
364
365 If no destination directory name is specified, it defaults to the
365 If no destination directory name is specified, it defaults to the
366 basename of the source.
366 basename of the source.
367
367
368 The location of the source is added to the new repository's
368 The location of the source is added to the new repository's
369 .hg/hgrc file, as the default to be used for future pulls.
369 .hg/hgrc file, as the default to be used for future pulls.
370
370
371 For efficiency, hardlinks are used for cloning whenever the source
371 For efficiency, hardlinks are used for cloning whenever the source
372 and destination are on the same filesystem (note this applies only
372 and destination are on the same filesystem (note this applies only
373 to the repository data, not to the checked out files). Some
373 to the repository data, not to the checked out files). Some
374 filesystems, such as AFS, implement hardlinking incorrectly, but
374 filesystems, such as AFS, implement hardlinking incorrectly, but
375 do not report errors. In these cases, use the --pull option to
375 do not report errors. In these cases, use the --pull option to
376 avoid hardlinking.
376 avoid hardlinking.
377
377
378 You can safely clone repositories and checked out files using full
378 You can safely clone repositories and checked out files using full
379 hardlinks with
379 hardlinks with
380
380
381 $ cp -al REPO REPOCLONE
381 $ cp -al REPO REPOCLONE
382
382
383 which is the fastest way to clone. However, the operation is not
383 which is the fastest way to clone. However, the operation is not
384 atomic (making sure REPO is not modified during the operation is
384 atomic (making sure REPO is not modified during the operation is
385 up to you) and you have to make sure your editor breaks hardlinks
385 up to you) and you have to make sure your editor breaks hardlinks
386 (Emacs and most Linux Kernel tools do so).
386 (Emacs and most Linux Kernel tools do so).
387
387
388 If you use the -r option to clone up to a specific revision, no
388 If you use the -r option to clone up to a specific revision, no
389 subsequent revisions will be present in the cloned repository.
389 subsequent revisions will be present in the cloned repository.
390 This option implies --pull, even on local repositories.
390 This option implies --pull, even on local repositories.
391
391
392 See pull for valid source format details.
392 See pull for valid source format details.
393
393
394 It is possible to specify an ssh:// URL as the destination, but no
394 It is possible to specify an ssh:// URL as the destination, but no
395 .hg/hgrc and working directory will be created on the remote side.
395 .hg/hgrc and working directory will be created on the remote side.
396 Look at the help text for the pull command for important details
396 Look at the help text for the pull command for important details
397 about ssh:// URLs.
397 about ssh:// URLs.
398 """
398 """
399 setremoteconfig(ui, opts)
399 setremoteconfig(ui, opts)
400 hg.clone(ui, ui.expandpath(source), dest,
400 hg.clone(ui, ui.expandpath(source), dest,
401 pull=opts['pull'],
401 pull=opts['pull'],
402 stream=opts['uncompressed'],
402 stream=opts['uncompressed'],
403 rev=opts['rev'],
403 rev=opts['rev'],
404 update=not opts['noupdate'])
404 update=not opts['noupdate'])
405
405
406 def commit(ui, repo, *pats, **opts):
406 def commit(ui, repo, *pats, **opts):
407 """commit the specified files or all outstanding changes
407 """commit the specified files or all outstanding changes
408
408
409 Commit changes to the given files into the repository.
409 Commit changes to the given files into the repository.
410
410
411 If a list of files is omitted, all changes reported by "hg status"
411 If a list of files is omitted, all changes reported by "hg status"
412 will be committed.
412 will be committed.
413
413
414 If no commit message is specified, the editor configured in your hgrc
414 If no commit message is specified, the editor configured in your hgrc
415 or in the EDITOR environment variable is started to enter a message.
415 or in the EDITOR environment variable is started to enter a message.
416 """
416 """
417 message = logmessage(opts)
417 message = logmessage(opts)
418
418
419 if opts['addremove']:
419 if opts['addremove']:
420 cmdutil.addremove(repo, pats, opts)
420 cmdutil.addremove(repo, pats, opts)
421 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
421 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
422 if pats:
422 if pats:
423 status = repo.status(files=fns, match=match)
423 status = repo.status(files=fns, match=match)
424 modified, added, removed, deleted, unknown = status[:5]
424 modified, added, removed, deleted, unknown = status[:5]
425 files = modified + added + removed
425 files = modified + added + removed
426 slist = None
426 slist = None
427 for f in fns:
427 for f in fns:
428 if f not in files:
428 if f not in files:
429 rf = repo.wjoin(f)
429 rf = repo.wjoin(f)
430 if f in unknown:
430 if f in unknown:
431 raise util.Abort(_("file %s not tracked!") % rf)
431 raise util.Abort(_("file %s not tracked!") % rf)
432 try:
432 try:
433 mode = os.lstat(rf)[stat.ST_MODE]
433 mode = os.lstat(rf)[stat.ST_MODE]
434 except OSError:
434 except OSError:
435 raise util.Abort(_("file %s not found!") % rf)
435 raise util.Abort(_("file %s not found!") % rf)
436 if stat.S_ISDIR(mode):
436 if stat.S_ISDIR(mode):
437 name = f + '/'
437 name = f + '/'
438 if slist is None:
438 if slist is None:
439 slist = list(files)
439 slist = list(files)
440 slist.sort()
440 slist.sort()
441 i = bisect.bisect(slist, name)
441 i = bisect.bisect(slist, name)
442 if i >= len(slist) or not slist[i].startswith(name):
442 if i >= len(slist) or not slist[i].startswith(name):
443 raise util.Abort(_("no match under directory %s!")
443 raise util.Abort(_("no match under directory %s!")
444 % rf)
444 % rf)
445 elif not stat.S_ISREG(mode):
445 elif not stat.S_ISREG(mode):
446 raise util.Abort(_("can't commit %s: "
446 raise util.Abort(_("can't commit %s: "
447 "unsupported file type!") % rf)
447 "unsupported file type!") % rf)
448 else:
448 else:
449 files = []
449 files = []
450 try:
450 try:
451 repo.commit(files, message, opts['user'], opts['date'], match,
451 repo.commit(files, message, opts['user'], opts['date'], match,
452 force_editor=opts.get('force_editor'))
452 force_editor=opts.get('force_editor'))
453 except ValueError, inst:
453 except ValueError, inst:
454 raise util.Abort(str(inst))
454 raise util.Abort(str(inst))
455
455
456 def docopy(ui, repo, pats, opts, wlock):
456 def docopy(ui, repo, pats, opts, wlock):
457 # called with the repo lock held
457 # called with the repo lock held
458 #
458 #
459 # hgsep => pathname that uses "/" to separate directories
459 # hgsep => pathname that uses "/" to separate directories
460 # ossep => pathname that uses os.sep to separate directories
460 # ossep => pathname that uses os.sep to separate directories
461 cwd = repo.getcwd()
461 cwd = repo.getcwd()
462 errors = 0
462 errors = 0
463 copied = []
463 copied = []
464 targets = {}
464 targets = {}
465
465
466 # abs: hgsep
466 # abs: hgsep
467 # rel: ossep
467 # rel: ossep
468 # return: hgsep
468 # return: hgsep
469 def okaytocopy(abs, rel, exact):
469 def okaytocopy(abs, rel, exact):
470 reasons = {'?': _('is not managed'),
470 reasons = {'?': _('is not managed'),
471 'a': _('has been marked for add'),
471 'a': _('has been marked for add'),
472 'r': _('has been marked for remove')}
472 'r': _('has been marked for remove')}
473 state = repo.dirstate.state(abs)
473 state = repo.dirstate.state(abs)
474 reason = reasons.get(state)
474 reason = reasons.get(state)
475 if reason:
475 if reason:
476 if state == 'a':
476 if state == 'a':
477 origsrc = repo.dirstate.copied(abs)
477 origsrc = repo.dirstate.copied(abs)
478 if origsrc is not None:
478 if origsrc is not None:
479 return origsrc
479 return origsrc
480 if exact:
480 if exact:
481 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
481 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
482 else:
482 else:
483 return abs
483 return abs
484
484
485 # origsrc: hgsep
485 # origsrc: hgsep
486 # abssrc: hgsep
486 # abssrc: hgsep
487 # relsrc: ossep
487 # relsrc: ossep
488 # target: ossep
488 # target: ossep
489 def copy(origsrc, abssrc, relsrc, target, exact):
489 def copy(origsrc, abssrc, relsrc, target, exact):
490 abstarget = util.canonpath(repo.root, cwd, target)
490 abstarget = util.canonpath(repo.root, cwd, target)
491 reltarget = util.pathto(cwd, abstarget)
491 reltarget = util.pathto(cwd, abstarget)
492 prevsrc = targets.get(abstarget)
492 prevsrc = targets.get(abstarget)
493 if prevsrc is not None:
493 if prevsrc is not None:
494 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
494 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
495 (reltarget, util.localpath(abssrc),
495 (reltarget, util.localpath(abssrc),
496 util.localpath(prevsrc)))
496 util.localpath(prevsrc)))
497 return
497 return
498 if (not opts['after'] and os.path.exists(reltarget) or
498 if (not opts['after'] and os.path.exists(reltarget) or
499 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
499 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
500 if not opts['force']:
500 if not opts['force']:
501 ui.warn(_('%s: not overwriting - file exists\n') %
501 ui.warn(_('%s: not overwriting - file exists\n') %
502 reltarget)
502 reltarget)
503 return
503 return
504 if not opts['after'] and not opts.get('dry_run'):
504 if not opts['after'] and not opts.get('dry_run'):
505 os.unlink(reltarget)
505 os.unlink(reltarget)
506 if opts['after']:
506 if opts['after']:
507 if not os.path.exists(reltarget):
507 if not os.path.exists(reltarget):
508 return
508 return
509 else:
509 else:
510 targetdir = os.path.dirname(reltarget) or '.'
510 targetdir = os.path.dirname(reltarget) or '.'
511 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
511 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
512 os.makedirs(targetdir)
512 os.makedirs(targetdir)
513 try:
513 try:
514 restore = repo.dirstate.state(abstarget) == 'r'
514 restore = repo.dirstate.state(abstarget) == 'r'
515 if restore and not opts.get('dry_run'):
515 if restore and not opts.get('dry_run'):
516 repo.undelete([abstarget], wlock)
516 repo.undelete([abstarget], wlock)
517 try:
517 try:
518 if not opts.get('dry_run'):
518 if not opts.get('dry_run'):
519 util.copyfile(relsrc, reltarget)
519 util.copyfile(relsrc, reltarget)
520 restore = False
520 restore = False
521 finally:
521 finally:
522 if restore:
522 if restore:
523 repo.remove([abstarget], wlock)
523 repo.remove([abstarget], wlock)
524 except IOError, inst:
524 except IOError, inst:
525 if inst.errno == errno.ENOENT:
525 if inst.errno == errno.ENOENT:
526 ui.warn(_('%s: deleted in working copy\n') % relsrc)
526 ui.warn(_('%s: deleted in working copy\n') % relsrc)
527 else:
527 else:
528 ui.warn(_('%s: cannot copy - %s\n') %
528 ui.warn(_('%s: cannot copy - %s\n') %
529 (relsrc, inst.strerror))
529 (relsrc, inst.strerror))
530 errors += 1
530 errors += 1
531 return
531 return
532 if ui.verbose or not exact:
532 if ui.verbose or not exact:
533 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
533 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
534 targets[abstarget] = abssrc
534 targets[abstarget] = abssrc
535 if abstarget != origsrc and not opts.get('dry_run'):
535 if abstarget != origsrc and not opts.get('dry_run'):
536 repo.copy(origsrc, abstarget, wlock)
536 repo.copy(origsrc, abstarget, wlock)
537 copied.append((abssrc, relsrc, exact))
537 copied.append((abssrc, relsrc, exact))
538
538
539 # pat: ossep
539 # pat: ossep
540 # dest ossep
540 # dest ossep
541 # srcs: list of (hgsep, hgsep, ossep, bool)
541 # srcs: list of (hgsep, hgsep, ossep, bool)
542 # return: function that takes hgsep and returns ossep
542 # return: function that takes hgsep and returns ossep
543 def targetpathfn(pat, dest, srcs):
543 def targetpathfn(pat, dest, srcs):
544 if os.path.isdir(pat):
544 if os.path.isdir(pat):
545 abspfx = util.canonpath(repo.root, cwd, pat)
545 abspfx = util.canonpath(repo.root, cwd, pat)
546 abspfx = util.localpath(abspfx)
546 abspfx = util.localpath(abspfx)
547 if destdirexists:
547 if destdirexists:
548 striplen = len(os.path.split(abspfx)[0])
548 striplen = len(os.path.split(abspfx)[0])
549 else:
549 else:
550 striplen = len(abspfx)
550 striplen = len(abspfx)
551 if striplen:
551 if striplen:
552 striplen += len(os.sep)
552 striplen += len(os.sep)
553 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
553 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
554 elif destdirexists:
554 elif destdirexists:
555 res = lambda p: os.path.join(dest,
555 res = lambda p: os.path.join(dest,
556 os.path.basename(util.localpath(p)))
556 os.path.basename(util.localpath(p)))
557 else:
557 else:
558 res = lambda p: dest
558 res = lambda p: dest
559 return res
559 return res
560
560
561 # pat: ossep
561 # pat: ossep
562 # dest ossep
562 # dest ossep
563 # srcs: list of (hgsep, hgsep, ossep, bool)
563 # srcs: list of (hgsep, hgsep, ossep, bool)
564 # return: function that takes hgsep and returns ossep
564 # return: function that takes hgsep and returns ossep
565 def targetpathafterfn(pat, dest, srcs):
565 def targetpathafterfn(pat, dest, srcs):
566 if util.patkind(pat, None)[0]:
566 if util.patkind(pat, None)[0]:
567 # a mercurial pattern
567 # a mercurial pattern
568 res = lambda p: os.path.join(dest,
568 res = lambda p: os.path.join(dest,
569 os.path.basename(util.localpath(p)))
569 os.path.basename(util.localpath(p)))
570 else:
570 else:
571 abspfx = util.canonpath(repo.root, cwd, pat)
571 abspfx = util.canonpath(repo.root, cwd, pat)
572 if len(abspfx) < len(srcs[0][0]):
572 if len(abspfx) < len(srcs[0][0]):
573 # A directory. Either the target path contains the last
573 # A directory. Either the target path contains the last
574 # component of the source path or it does not.
574 # component of the source path or it does not.
575 def evalpath(striplen):
575 def evalpath(striplen):
576 score = 0
576 score = 0
577 for s in srcs:
577 for s in srcs:
578 t = os.path.join(dest, util.localpath(s[0])[striplen:])
578 t = os.path.join(dest, util.localpath(s[0])[striplen:])
579 if os.path.exists(t):
579 if os.path.exists(t):
580 score += 1
580 score += 1
581 return score
581 return score
582
582
583 abspfx = util.localpath(abspfx)
583 abspfx = util.localpath(abspfx)
584 striplen = len(abspfx)
584 striplen = len(abspfx)
585 if striplen:
585 if striplen:
586 striplen += len(os.sep)
586 striplen += len(os.sep)
587 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
587 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
588 score = evalpath(striplen)
588 score = evalpath(striplen)
589 striplen1 = len(os.path.split(abspfx)[0])
589 striplen1 = len(os.path.split(abspfx)[0])
590 if striplen1:
590 if striplen1:
591 striplen1 += len(os.sep)
591 striplen1 += len(os.sep)
592 if evalpath(striplen1) > score:
592 if evalpath(striplen1) > score:
593 striplen = striplen1
593 striplen = striplen1
594 res = lambda p: os.path.join(dest,
594 res = lambda p: os.path.join(dest,
595 util.localpath(p)[striplen:])
595 util.localpath(p)[striplen:])
596 else:
596 else:
597 # a file
597 # a file
598 if destdirexists:
598 if destdirexists:
599 res = lambda p: os.path.join(dest,
599 res = lambda p: os.path.join(dest,
600 os.path.basename(util.localpath(p)))
600 os.path.basename(util.localpath(p)))
601 else:
601 else:
602 res = lambda p: dest
602 res = lambda p: dest
603 return res
603 return res
604
604
605
605
606 pats = list(pats)
606 pats = list(pats)
607 if not pats:
607 if not pats:
608 raise util.Abort(_('no source or destination specified'))
608 raise util.Abort(_('no source or destination specified'))
609 if len(pats) == 1:
609 if len(pats) == 1:
610 raise util.Abort(_('no destination specified'))
610 raise util.Abort(_('no destination specified'))
611 dest = pats.pop()
611 dest = pats.pop()
612 destdirexists = os.path.isdir(dest)
612 destdirexists = os.path.isdir(dest)
613 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
613 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
614 raise util.Abort(_('with multiple sources, destination must be an '
614 raise util.Abort(_('with multiple sources, destination must be an '
615 'existing directory'))
615 'existing directory'))
616 if opts['after']:
616 if opts['after']:
617 tfn = targetpathafterfn
617 tfn = targetpathafterfn
618 else:
618 else:
619 tfn = targetpathfn
619 tfn = targetpathfn
620 copylist = []
620 copylist = []
621 for pat in pats:
621 for pat in pats:
622 srcs = []
622 srcs = []
623 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
623 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
624 origsrc = okaytocopy(abssrc, relsrc, exact)
624 origsrc = okaytocopy(abssrc, relsrc, exact)
625 if origsrc:
625 if origsrc:
626 srcs.append((origsrc, abssrc, relsrc, exact))
626 srcs.append((origsrc, abssrc, relsrc, exact))
627 if not srcs:
627 if not srcs:
628 continue
628 continue
629 copylist.append((tfn(pat, dest, srcs), srcs))
629 copylist.append((tfn(pat, dest, srcs), srcs))
630 if not copylist:
630 if not copylist:
631 raise util.Abort(_('no files to copy'))
631 raise util.Abort(_('no files to copy'))
632
632
633 for targetpath, srcs in copylist:
633 for targetpath, srcs in copylist:
634 for origsrc, abssrc, relsrc, exact in srcs:
634 for origsrc, abssrc, relsrc, exact in srcs:
635 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
635 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
636
636
637 if errors:
637 if errors:
638 ui.warn(_('(consider using --after)\n'))
638 ui.warn(_('(consider using --after)\n'))
639 return errors, copied
639 return errors, copied
640
640
641 def copy(ui, repo, *pats, **opts):
641 def copy(ui, repo, *pats, **opts):
642 """mark files as copied for the next commit
642 """mark files as copied for the next commit
643
643
644 Mark dest as having copies of source files. If dest is a
644 Mark dest as having copies of source files. If dest is a
645 directory, copies are put in that directory. If dest is a file,
645 directory, copies are put in that directory. If dest is a file,
646 there can only be one source.
646 there can only be one source.
647
647
648 By default, this command copies the contents of files as they
648 By default, this command copies the contents of files as they
649 stand in the working directory. If invoked with --after, the
649 stand in the working directory. If invoked with --after, the
650 operation is recorded, but no copying is performed.
650 operation is recorded, but no copying is performed.
651
651
652 This command takes effect in the next commit.
652 This command takes effect in the next commit.
653 """
653 """
654 wlock = repo.wlock(0)
654 wlock = repo.wlock(0)
655 errs, copied = docopy(ui, repo, pats, opts, wlock)
655 errs, copied = docopy(ui, repo, pats, opts, wlock)
656 return errs
656 return errs
657
657
658 def debugancestor(ui, index, rev1, rev2):
658 def debugancestor(ui, index, rev1, rev2):
659 """find the ancestor revision of two revisions in a given index"""
659 """find the ancestor revision of two revisions in a given index"""
660 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
660 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
661 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
661 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
662 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
662 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
663
663
664 def debugcomplete(ui, cmd='', **opts):
664 def debugcomplete(ui, cmd='', **opts):
665 """returns the completion list associated with the given command"""
665 """returns the completion list associated with the given command"""
666
666
667 if opts['options']:
667 if opts['options']:
668 options = []
668 options = []
669 otables = [globalopts]
669 otables = [globalopts]
670 if cmd:
670 if cmd:
671 aliases, entry = findcmd(ui, cmd)
671 aliases, entry = findcmd(ui, cmd)
672 otables.append(entry[1])
672 otables.append(entry[1])
673 for t in otables:
673 for t in otables:
674 for o in t:
674 for o in t:
675 if o[0]:
675 if o[0]:
676 options.append('-%s' % o[0])
676 options.append('-%s' % o[0])
677 options.append('--%s' % o[1])
677 options.append('--%s' % o[1])
678 ui.write("%s\n" % "\n".join(options))
678 ui.write("%s\n" % "\n".join(options))
679 return
679 return
680
680
681 clist = findpossible(ui, cmd).keys()
681 clist = findpossible(ui, cmd).keys()
682 clist.sort()
682 clist.sort()
683 ui.write("%s\n" % "\n".join(clist))
683 ui.write("%s\n" % "\n".join(clist))
684
684
685 def debugrebuildstate(ui, repo, rev=None):
685 def debugrebuildstate(ui, repo, rev=None):
686 """rebuild the dirstate as it would look like for the given revision"""
686 """rebuild the dirstate as it would look like for the given revision"""
687 if not rev:
687 if not rev:
688 rev = repo.changelog.tip()
688 rev = repo.changelog.tip()
689 else:
689 else:
690 rev = repo.lookup(rev)
690 rev = repo.lookup(rev)
691 change = repo.changelog.read(rev)
691 change = repo.changelog.read(rev)
692 n = change[0]
692 n = change[0]
693 files = repo.manifest.read(n)
693 files = repo.manifest.read(n)
694 wlock = repo.wlock()
694 wlock = repo.wlock()
695 repo.dirstate.rebuild(rev, files)
695 repo.dirstate.rebuild(rev, files)
696
696
697 def debugcheckstate(ui, repo):
697 def debugcheckstate(ui, repo):
698 """validate the correctness of the current dirstate"""
698 """validate the correctness of the current dirstate"""
699 parent1, parent2 = repo.dirstate.parents()
699 parent1, parent2 = repo.dirstate.parents()
700 repo.dirstate.read()
700 repo.dirstate.read()
701 dc = repo.dirstate.map
701 dc = repo.dirstate.map
702 keys = dc.keys()
702 keys = dc.keys()
703 keys.sort()
703 keys.sort()
704 m1n = repo.changelog.read(parent1)[0]
704 m1n = repo.changelog.read(parent1)[0]
705 m2n = repo.changelog.read(parent2)[0]
705 m2n = repo.changelog.read(parent2)[0]
706 m1 = repo.manifest.read(m1n)
706 m1 = repo.manifest.read(m1n)
707 m2 = repo.manifest.read(m2n)
707 m2 = repo.manifest.read(m2n)
708 errors = 0
708 errors = 0
709 for f in dc:
709 for f in dc:
710 state = repo.dirstate.state(f)
710 state = repo.dirstate.state(f)
711 if state in "nr" and f not in m1:
711 if state in "nr" and f not in m1:
712 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
712 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
713 errors += 1
713 errors += 1
714 if state in "a" and f in m1:
714 if state in "a" and f in m1:
715 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
715 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
716 errors += 1
716 errors += 1
717 if state in "m" and f not in m1 and f not in m2:
717 if state in "m" and f not in m1 and f not in m2:
718 ui.warn(_("%s in state %s, but not in either manifest\n") %
718 ui.warn(_("%s in state %s, but not in either manifest\n") %
719 (f, state))
719 (f, state))
720 errors += 1
720 errors += 1
721 for f in m1:
721 for f in m1:
722 state = repo.dirstate.state(f)
722 state = repo.dirstate.state(f)
723 if state not in "nrm":
723 if state not in "nrm":
724 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
724 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
725 errors += 1
725 errors += 1
726 if errors:
726 if errors:
727 error = _(".hg/dirstate inconsistent with current parent's manifest")
727 error = _(".hg/dirstate inconsistent with current parent's manifest")
728 raise util.Abort(error)
728 raise util.Abort(error)
729
729
730 def showconfig(ui, repo, *values, **opts):
730 def showconfig(ui, repo, *values, **opts):
731 """show combined config settings from all hgrc files
731 """show combined config settings from all hgrc files
732
732
733 With no args, print names and values of all config items.
733 With no args, print names and values of all config items.
734
734
735 With one arg of the form section.name, print just the value of
735 With one arg of the form section.name, print just the value of
736 that config item.
736 that config item.
737
737
738 With multiple args, print names and values of all config items
738 With multiple args, print names and values of all config items
739 with matching section names."""
739 with matching section names."""
740
740
741 untrusted = bool(opts.get('untrusted'))
741 untrusted = bool(opts.get('untrusted'))
742 if values:
742 if values:
743 if len([v for v in values if '.' in v]) > 1:
743 if len([v for v in values if '.' in v]) > 1:
744 raise util.Abort(_('only one config item permitted'))
744 raise util.Abort(_('only one config item permitted'))
745 for section, name, value in ui.walkconfig(untrusted=untrusted):
745 for section, name, value in ui.walkconfig(untrusted=untrusted):
746 sectname = section + '.' + name
746 sectname = section + '.' + name
747 if values:
747 if values:
748 for v in values:
748 for v in values:
749 if v == section:
749 if v == section:
750 ui.write('%s=%s\n' % (sectname, value))
750 ui.write('%s=%s\n' % (sectname, value))
751 elif v == sectname:
751 elif v == sectname:
752 ui.write(value, '\n')
752 ui.write(value, '\n')
753 else:
753 else:
754 ui.write('%s=%s\n' % (sectname, value))
754 ui.write('%s=%s\n' % (sectname, value))
755
755
756 def debugsetparents(ui, repo, rev1, rev2=None):
756 def debugsetparents(ui, repo, rev1, rev2=None):
757 """manually set the parents of the current working directory
757 """manually set the parents of the current working directory
758
758
759 This is useful for writing repository conversion tools, but should
759 This is useful for writing repository conversion tools, but should
760 be used with care.
760 be used with care.
761 """
761 """
762
762
763 if not rev2:
763 if not rev2:
764 rev2 = hex(nullid)
764 rev2 = hex(nullid)
765
765
766 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
766 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
767
767
768 def debugstate(ui, repo):
768 def debugstate(ui, repo):
769 """show the contents of the current dirstate"""
769 """show the contents of the current dirstate"""
770 repo.dirstate.read()
770 repo.dirstate.read()
771 dc = repo.dirstate.map
771 dc = repo.dirstate.map
772 keys = dc.keys()
772 keys = dc.keys()
773 keys.sort()
773 keys.sort()
774 for file_ in keys:
774 for file_ in keys:
775 ui.write("%c %3o %10d %s %s\n"
775 ui.write("%c %3o %10d %s %s\n"
776 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
776 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
777 time.strftime("%x %X",
777 time.strftime("%x %X",
778 time.localtime(dc[file_][3])), file_))
778 time.localtime(dc[file_][3])), file_))
779 for f in repo.dirstate.copies():
779 for f in repo.dirstate.copies():
780 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
780 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
781
781
782 def debugdata(ui, file_, rev):
782 def debugdata(ui, file_, rev):
783 """dump the contents of an data file revision"""
783 """dump the contents of an data file revision"""
784 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
784 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
785 file_[:-2] + ".i", file_, 0)
785 file_[:-2] + ".i", file_, 0)
786 try:
786 try:
787 ui.write(r.revision(r.lookup(rev)))
787 ui.write(r.revision(r.lookup(rev)))
788 except KeyError:
788 except KeyError:
789 raise util.Abort(_('invalid revision identifier %s') % rev)
789 raise util.Abort(_('invalid revision identifier %s') % rev)
790
790
791 def debugdate(ui, date):
792 """parse and display a date"""
793 d = util.parsedate(date)
794 ui.write("internal: %s %s\n" % d)
795 ui.write("standard: %s\n" % util.datestr(d))
796
791 def debugindex(ui, file_):
797 def debugindex(ui, file_):
792 """dump the contents of an index file"""
798 """dump the contents of an index file"""
793 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
799 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
794 ui.write(" rev offset length base linkrev" +
800 ui.write(" rev offset length base linkrev" +
795 " nodeid p1 p2\n")
801 " nodeid p1 p2\n")
796 for i in xrange(r.count()):
802 for i in xrange(r.count()):
797 node = r.node(i)
803 node = r.node(i)
798 pp = r.parents(node)
804 pp = r.parents(node)
799 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
805 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
800 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
806 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
801 short(node), short(pp[0]), short(pp[1])))
807 short(node), short(pp[0]), short(pp[1])))
802
808
803 def debugindexdot(ui, file_):
809 def debugindexdot(ui, file_):
804 """dump an index DAG as a .dot file"""
810 """dump an index DAG as a .dot file"""
805 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
811 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
806 ui.write("digraph G {\n")
812 ui.write("digraph G {\n")
807 for i in xrange(r.count()):
813 for i in xrange(r.count()):
808 node = r.node(i)
814 node = r.node(i)
809 pp = r.parents(node)
815 pp = r.parents(node)
810 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
816 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
811 if pp[1] != nullid:
817 if pp[1] != nullid:
812 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
818 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
813 ui.write("}\n")
819 ui.write("}\n")
814
820
815 def debugrename(ui, repo, file1, *pats, **opts):
821 def debugrename(ui, repo, file1, *pats, **opts):
816 """dump rename information"""
822 """dump rename information"""
817
823
818 ctx = repo.changectx(opts.get('rev', 'tip'))
824 ctx = repo.changectx(opts.get('rev', 'tip'))
819 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
825 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
820 ctx.node()):
826 ctx.node()):
821 m = ctx.filectx(abs).renamed()
827 m = ctx.filectx(abs).renamed()
822 if m:
828 if m:
823 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
829 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
824 else:
830 else:
825 ui.write(_("%s not renamed\n") % rel)
831 ui.write(_("%s not renamed\n") % rel)
826
832
827 def debugwalk(ui, repo, *pats, **opts):
833 def debugwalk(ui, repo, *pats, **opts):
828 """show how files match on given patterns"""
834 """show how files match on given patterns"""
829 items = list(cmdutil.walk(repo, pats, opts))
835 items = list(cmdutil.walk(repo, pats, opts))
830 if not items:
836 if not items:
831 return
837 return
832 fmt = '%%s %%-%ds %%-%ds %%s' % (
838 fmt = '%%s %%-%ds %%-%ds %%s' % (
833 max([len(abs) for (src, abs, rel, exact) in items]),
839 max([len(abs) for (src, abs, rel, exact) in items]),
834 max([len(rel) for (src, abs, rel, exact) in items]))
840 max([len(rel) for (src, abs, rel, exact) in items]))
835 for src, abs, rel, exact in items:
841 for src, abs, rel, exact in items:
836 line = fmt % (src, abs, rel, exact and 'exact' or '')
842 line = fmt % (src, abs, rel, exact and 'exact' or '')
837 ui.write("%s\n" % line.rstrip())
843 ui.write("%s\n" % line.rstrip())
838
844
839 def diff(ui, repo, *pats, **opts):
845 def diff(ui, repo, *pats, **opts):
840 """diff repository (or selected files)
846 """diff repository (or selected files)
841
847
842 Show differences between revisions for the specified files.
848 Show differences between revisions for the specified files.
843
849
844 Differences between files are shown using the unified diff format.
850 Differences between files are shown using the unified diff format.
845
851
846 When two revision arguments are given, then changes are shown
852 When two revision arguments are given, then changes are shown
847 between those revisions. If only one revision is specified then
853 between those revisions. If only one revision is specified then
848 that revision is compared to the working directory, and, when no
854 that revision is compared to the working directory, and, when no
849 revisions are specified, the working directory files are compared
855 revisions are specified, the working directory files are compared
850 to its parent.
856 to its parent.
851
857
852 Without the -a option, diff will avoid generating diffs of files
858 Without the -a option, diff will avoid generating diffs of files
853 it detects as binary. With -a, diff will generate a diff anyway,
859 it detects as binary. With -a, diff will generate a diff anyway,
854 probably with undesirable results.
860 probably with undesirable results.
855 """
861 """
856 node1, node2 = cmdutil.revpair(repo, opts['rev'])
862 node1, node2 = cmdutil.revpair(repo, opts['rev'])
857
863
858 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
864 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
859
865
860 patch.diff(repo, node1, node2, fns, match=matchfn,
866 patch.diff(repo, node1, node2, fns, match=matchfn,
861 opts=patch.diffopts(ui, opts))
867 opts=patch.diffopts(ui, opts))
862
868
863 def export(ui, repo, *changesets, **opts):
869 def export(ui, repo, *changesets, **opts):
864 """dump the header and diffs for one or more changesets
870 """dump the header and diffs for one or more changesets
865
871
866 Print the changeset header and diffs for one or more revisions.
872 Print the changeset header and diffs for one or more revisions.
867
873
868 The information shown in the changeset header is: author,
874 The information shown in the changeset header is: author,
869 changeset hash, parent and commit comment.
875 changeset hash, parent and commit comment.
870
876
871 Output may be to a file, in which case the name of the file is
877 Output may be to a file, in which case the name of the file is
872 given using a format string. The formatting rules are as follows:
878 given using a format string. The formatting rules are as follows:
873
879
874 %% literal "%" character
880 %% literal "%" character
875 %H changeset hash (40 bytes of hexadecimal)
881 %H changeset hash (40 bytes of hexadecimal)
876 %N number of patches being generated
882 %N number of patches being generated
877 %R changeset revision number
883 %R changeset revision number
878 %b basename of the exporting repository
884 %b basename of the exporting repository
879 %h short-form changeset hash (12 bytes of hexadecimal)
885 %h short-form changeset hash (12 bytes of hexadecimal)
880 %n zero-padded sequence number, starting at 1
886 %n zero-padded sequence number, starting at 1
881 %r zero-padded changeset revision number
887 %r zero-padded changeset revision number
882
888
883 Without the -a option, export will avoid generating diffs of files
889 Without the -a option, export will avoid generating diffs of files
884 it detects as binary. With -a, export will generate a diff anyway,
890 it detects as binary. With -a, export will generate a diff anyway,
885 probably with undesirable results.
891 probably with undesirable results.
886
892
887 With the --switch-parent option, the diff will be against the second
893 With the --switch-parent option, the diff will be against the second
888 parent. It can be useful to review a merge.
894 parent. It can be useful to review a merge.
889 """
895 """
890 if not changesets:
896 if not changesets:
891 raise util.Abort(_("export requires at least one changeset"))
897 raise util.Abort(_("export requires at least one changeset"))
892 revs = cmdutil.revrange(repo, changesets)
898 revs = cmdutil.revrange(repo, changesets)
893 if len(revs) > 1:
899 if len(revs) > 1:
894 ui.note(_('exporting patches:\n'))
900 ui.note(_('exporting patches:\n'))
895 else:
901 else:
896 ui.note(_('exporting patch:\n'))
902 ui.note(_('exporting patch:\n'))
897 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
903 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
898 switch_parent=opts['switch_parent'],
904 switch_parent=opts['switch_parent'],
899 opts=patch.diffopts(ui, opts))
905 opts=patch.diffopts(ui, opts))
900
906
901 def grep(ui, repo, pattern, *pats, **opts):
907 def grep(ui, repo, pattern, *pats, **opts):
902 """search for a pattern in specified files and revisions
908 """search for a pattern in specified files and revisions
903
909
904 Search revisions of files for a regular expression.
910 Search revisions of files for a regular expression.
905
911
906 This command behaves differently than Unix grep. It only accepts
912 This command behaves differently than Unix grep. It only accepts
907 Python/Perl regexps. It searches repository history, not the
913 Python/Perl regexps. It searches repository history, not the
908 working directory. It always prints the revision number in which
914 working directory. It always prints the revision number in which
909 a match appears.
915 a match appears.
910
916
911 By default, grep only prints output for the first revision of a
917 By default, grep only prints output for the first revision of a
912 file in which it finds a match. To get it to print every revision
918 file in which it finds a match. To get it to print every revision
913 that contains a change in match status ("-" for a match that
919 that contains a change in match status ("-" for a match that
914 becomes a non-match, or "+" for a non-match that becomes a match),
920 becomes a non-match, or "+" for a non-match that becomes a match),
915 use the --all flag.
921 use the --all flag.
916 """
922 """
917 reflags = 0
923 reflags = 0
918 if opts['ignore_case']:
924 if opts['ignore_case']:
919 reflags |= re.I
925 reflags |= re.I
920 regexp = re.compile(pattern, reflags)
926 regexp = re.compile(pattern, reflags)
921 sep, eol = ':', '\n'
927 sep, eol = ':', '\n'
922 if opts['print0']:
928 if opts['print0']:
923 sep = eol = '\0'
929 sep = eol = '\0'
924
930
925 fcache = {}
931 fcache = {}
926 def getfile(fn):
932 def getfile(fn):
927 if fn not in fcache:
933 if fn not in fcache:
928 fcache[fn] = repo.file(fn)
934 fcache[fn] = repo.file(fn)
929 return fcache[fn]
935 return fcache[fn]
930
936
931 def matchlines(body):
937 def matchlines(body):
932 begin = 0
938 begin = 0
933 linenum = 0
939 linenum = 0
934 while True:
940 while True:
935 match = regexp.search(body, begin)
941 match = regexp.search(body, begin)
936 if not match:
942 if not match:
937 break
943 break
938 mstart, mend = match.span()
944 mstart, mend = match.span()
939 linenum += body.count('\n', begin, mstart) + 1
945 linenum += body.count('\n', begin, mstart) + 1
940 lstart = body.rfind('\n', begin, mstart) + 1 or begin
946 lstart = body.rfind('\n', begin, mstart) + 1 or begin
941 lend = body.find('\n', mend)
947 lend = body.find('\n', mend)
942 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
948 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
943 begin = lend + 1
949 begin = lend + 1
944
950
945 class linestate(object):
951 class linestate(object):
946 def __init__(self, line, linenum, colstart, colend):
952 def __init__(self, line, linenum, colstart, colend):
947 self.line = line
953 self.line = line
948 self.linenum = linenum
954 self.linenum = linenum
949 self.colstart = colstart
955 self.colstart = colstart
950 self.colend = colend
956 self.colend = colend
951
957
952 def __eq__(self, other):
958 def __eq__(self, other):
953 return self.line == other.line
959 return self.line == other.line
954
960
955 matches = {}
961 matches = {}
956 copies = {}
962 copies = {}
957 def grepbody(fn, rev, body):
963 def grepbody(fn, rev, body):
958 matches[rev].setdefault(fn, [])
964 matches[rev].setdefault(fn, [])
959 m = matches[rev][fn]
965 m = matches[rev][fn]
960 for lnum, cstart, cend, line in matchlines(body):
966 for lnum, cstart, cend, line in matchlines(body):
961 s = linestate(line, lnum, cstart, cend)
967 s = linestate(line, lnum, cstart, cend)
962 m.append(s)
968 m.append(s)
963
969
964 def difflinestates(a, b):
970 def difflinestates(a, b):
965 sm = difflib.SequenceMatcher(None, a, b)
971 sm = difflib.SequenceMatcher(None, a, b)
966 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
972 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
967 if tag == 'insert':
973 if tag == 'insert':
968 for i in xrange(blo, bhi):
974 for i in xrange(blo, bhi):
969 yield ('+', b[i])
975 yield ('+', b[i])
970 elif tag == 'delete':
976 elif tag == 'delete':
971 for i in xrange(alo, ahi):
977 for i in xrange(alo, ahi):
972 yield ('-', a[i])
978 yield ('-', a[i])
973 elif tag == 'replace':
979 elif tag == 'replace':
974 for i in xrange(alo, ahi):
980 for i in xrange(alo, ahi):
975 yield ('-', a[i])
981 yield ('-', a[i])
976 for i in xrange(blo, bhi):
982 for i in xrange(blo, bhi):
977 yield ('+', b[i])
983 yield ('+', b[i])
978
984
979 prev = {}
985 prev = {}
980 def display(fn, rev, states, prevstates):
986 def display(fn, rev, states, prevstates):
981 counts = {'-': 0, '+': 0}
987 counts = {'-': 0, '+': 0}
982 filerevmatches = {}
988 filerevmatches = {}
983 if incrementing or not opts['all']:
989 if incrementing or not opts['all']:
984 a, b, r = prevstates, states, rev
990 a, b, r = prevstates, states, rev
985 else:
991 else:
986 a, b, r = states, prevstates, prev.get(fn, -1)
992 a, b, r = states, prevstates, prev.get(fn, -1)
987 for change, l in difflinestates(a, b):
993 for change, l in difflinestates(a, b):
988 cols = [fn, str(r)]
994 cols = [fn, str(r)]
989 if opts['line_number']:
995 if opts['line_number']:
990 cols.append(str(l.linenum))
996 cols.append(str(l.linenum))
991 if opts['all']:
997 if opts['all']:
992 cols.append(change)
998 cols.append(change)
993 if opts['user']:
999 if opts['user']:
994 cols.append(ui.shortuser(get(r)[1]))
1000 cols.append(ui.shortuser(get(r)[1]))
995 if opts['files_with_matches']:
1001 if opts['files_with_matches']:
996 c = (fn, r)
1002 c = (fn, r)
997 if c in filerevmatches:
1003 if c in filerevmatches:
998 continue
1004 continue
999 filerevmatches[c] = 1
1005 filerevmatches[c] = 1
1000 else:
1006 else:
1001 cols.append(l.line)
1007 cols.append(l.line)
1002 ui.write(sep.join(cols), eol)
1008 ui.write(sep.join(cols), eol)
1003 counts[change] += 1
1009 counts[change] += 1
1004 return counts['+'], counts['-']
1010 return counts['+'], counts['-']
1005
1011
1006 fstate = {}
1012 fstate = {}
1007 skip = {}
1013 skip = {}
1008 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1014 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1009 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1015 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1010 count = 0
1016 count = 0
1011 incrementing = False
1017 incrementing = False
1012 follow = opts.get('follow')
1018 follow = opts.get('follow')
1013 for st, rev, fns in changeiter:
1019 for st, rev, fns in changeiter:
1014 if st == 'window':
1020 if st == 'window':
1015 incrementing = rev
1021 incrementing = rev
1016 matches.clear()
1022 matches.clear()
1017 elif st == 'add':
1023 elif st == 'add':
1018 mf = repo.changectx(rev).manifest()
1024 mf = repo.changectx(rev).manifest()
1019 matches[rev] = {}
1025 matches[rev] = {}
1020 for fn in fns:
1026 for fn in fns:
1021 if fn in skip:
1027 if fn in skip:
1022 continue
1028 continue
1023 fstate.setdefault(fn, {})
1029 fstate.setdefault(fn, {})
1024 try:
1030 try:
1025 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1031 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1026 if follow:
1032 if follow:
1027 copied = getfile(fn).renamed(mf[fn])
1033 copied = getfile(fn).renamed(mf[fn])
1028 if copied:
1034 if copied:
1029 copies.setdefault(rev, {})[fn] = copied[0]
1035 copies.setdefault(rev, {})[fn] = copied[0]
1030 except KeyError:
1036 except KeyError:
1031 pass
1037 pass
1032 elif st == 'iter':
1038 elif st == 'iter':
1033 states = matches[rev].items()
1039 states = matches[rev].items()
1034 states.sort()
1040 states.sort()
1035 for fn, m in states:
1041 for fn, m in states:
1036 copy = copies.get(rev, {}).get(fn)
1042 copy = copies.get(rev, {}).get(fn)
1037 if fn in skip:
1043 if fn in skip:
1038 if copy:
1044 if copy:
1039 skip[copy] = True
1045 skip[copy] = True
1040 continue
1046 continue
1041 if incrementing or not opts['all'] or fstate[fn]:
1047 if incrementing or not opts['all'] or fstate[fn]:
1042 pos, neg = display(fn, rev, m, fstate[fn])
1048 pos, neg = display(fn, rev, m, fstate[fn])
1043 count += pos + neg
1049 count += pos + neg
1044 if pos and not opts['all']:
1050 if pos and not opts['all']:
1045 skip[fn] = True
1051 skip[fn] = True
1046 if copy:
1052 if copy:
1047 skip[copy] = True
1053 skip[copy] = True
1048 fstate[fn] = m
1054 fstate[fn] = m
1049 if copy:
1055 if copy:
1050 fstate[copy] = m
1056 fstate[copy] = m
1051 prev[fn] = rev
1057 prev[fn] = rev
1052
1058
1053 if not incrementing:
1059 if not incrementing:
1054 fstate = fstate.items()
1060 fstate = fstate.items()
1055 fstate.sort()
1061 fstate.sort()
1056 for fn, state in fstate:
1062 for fn, state in fstate:
1057 if fn in skip:
1063 if fn in skip:
1058 continue
1064 continue
1059 if fn not in copies.get(prev[fn], {}):
1065 if fn not in copies.get(prev[fn], {}):
1060 display(fn, rev, {}, state)
1066 display(fn, rev, {}, state)
1061 return (count == 0 and 1) or 0
1067 return (count == 0 and 1) or 0
1062
1068
1063 def heads(ui, repo, **opts):
1069 def heads(ui, repo, **opts):
1064 """show current repository heads
1070 """show current repository heads
1065
1071
1066 Show all repository head changesets.
1072 Show all repository head changesets.
1067
1073
1068 Repository "heads" are changesets that don't have children
1074 Repository "heads" are changesets that don't have children
1069 changesets. They are where development generally takes place and
1075 changesets. They are where development generally takes place and
1070 are the usual targets for update and merge operations.
1076 are the usual targets for update and merge operations.
1071 """
1077 """
1072 if opts['rev']:
1078 if opts['rev']:
1073 heads = repo.heads(repo.lookup(opts['rev']))
1079 heads = repo.heads(repo.lookup(opts['rev']))
1074 else:
1080 else:
1075 heads = repo.heads()
1081 heads = repo.heads()
1076 displayer = cmdutil.show_changeset(ui, repo, opts)
1082 displayer = cmdutil.show_changeset(ui, repo, opts)
1077 for n in heads:
1083 for n in heads:
1078 displayer.show(changenode=n)
1084 displayer.show(changenode=n)
1079
1085
1080 def help_(ui, name=None, with_version=False):
1086 def help_(ui, name=None, with_version=False):
1081 """show help for a command, extension, or list of commands
1087 """show help for a command, extension, or list of commands
1082
1088
1083 With no arguments, print a list of commands and short help.
1089 With no arguments, print a list of commands and short help.
1084
1090
1085 Given a command name, print help for that command.
1091 Given a command name, print help for that command.
1086
1092
1087 Given an extension name, print help for that extension, and the
1093 Given an extension name, print help for that extension, and the
1088 commands it provides."""
1094 commands it provides."""
1089 option_lists = []
1095 option_lists = []
1090
1096
1091 def helpcmd(name):
1097 def helpcmd(name):
1092 if with_version:
1098 if with_version:
1093 version_(ui)
1099 version_(ui)
1094 ui.write('\n')
1100 ui.write('\n')
1095 aliases, i = findcmd(ui, name)
1101 aliases, i = findcmd(ui, name)
1096 # synopsis
1102 # synopsis
1097 ui.write("%s\n\n" % i[2])
1103 ui.write("%s\n\n" % i[2])
1098
1104
1099 # description
1105 # description
1100 doc = i[0].__doc__
1106 doc = i[0].__doc__
1101 if not doc:
1107 if not doc:
1102 doc = _("(No help text available)")
1108 doc = _("(No help text available)")
1103 if ui.quiet:
1109 if ui.quiet:
1104 doc = doc.splitlines(0)[0]
1110 doc = doc.splitlines(0)[0]
1105 ui.write("%s\n" % doc.rstrip())
1111 ui.write("%s\n" % doc.rstrip())
1106
1112
1107 if not ui.quiet:
1113 if not ui.quiet:
1108 # aliases
1114 # aliases
1109 if len(aliases) > 1:
1115 if len(aliases) > 1:
1110 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1116 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1111
1117
1112 # options
1118 # options
1113 if i[1]:
1119 if i[1]:
1114 option_lists.append(("options", i[1]))
1120 option_lists.append(("options", i[1]))
1115
1121
1116 def helplist(select=None):
1122 def helplist(select=None):
1117 h = {}
1123 h = {}
1118 cmds = {}
1124 cmds = {}
1119 for c, e in table.items():
1125 for c, e in table.items():
1120 f = c.split("|", 1)[0]
1126 f = c.split("|", 1)[0]
1121 if select and not select(f):
1127 if select and not select(f):
1122 continue
1128 continue
1123 if name == "shortlist" and not f.startswith("^"):
1129 if name == "shortlist" and not f.startswith("^"):
1124 continue
1130 continue
1125 f = f.lstrip("^")
1131 f = f.lstrip("^")
1126 if not ui.debugflag and f.startswith("debug"):
1132 if not ui.debugflag and f.startswith("debug"):
1127 continue
1133 continue
1128 doc = e[0].__doc__
1134 doc = e[0].__doc__
1129 if not doc:
1135 if not doc:
1130 doc = _("(No help text available)")
1136 doc = _("(No help text available)")
1131 h[f] = doc.splitlines(0)[0].rstrip()
1137 h[f] = doc.splitlines(0)[0].rstrip()
1132 cmds[f] = c.lstrip("^")
1138 cmds[f] = c.lstrip("^")
1133
1139
1134 fns = h.keys()
1140 fns = h.keys()
1135 fns.sort()
1141 fns.sort()
1136 m = max(map(len, fns))
1142 m = max(map(len, fns))
1137 for f in fns:
1143 for f in fns:
1138 if ui.verbose:
1144 if ui.verbose:
1139 commands = cmds[f].replace("|",", ")
1145 commands = cmds[f].replace("|",", ")
1140 ui.write(" %s:\n %s\n"%(commands, h[f]))
1146 ui.write(" %s:\n %s\n"%(commands, h[f]))
1141 else:
1147 else:
1142 ui.write(' %-*s %s\n' % (m, f, h[f]))
1148 ui.write(' %-*s %s\n' % (m, f, h[f]))
1143
1149
1144 def helptopic(name):
1150 def helptopic(name):
1145 v = None
1151 v = None
1146 for i in help.helptable:
1152 for i in help.helptable:
1147 l = i.split('|')
1153 l = i.split('|')
1148 if name in l:
1154 if name in l:
1149 v = i
1155 v = i
1150 header = l[-1]
1156 header = l[-1]
1151 if not v:
1157 if not v:
1152 raise UnknownCommand(name)
1158 raise UnknownCommand(name)
1153
1159
1154 # description
1160 # description
1155 doc = help.helptable[v]
1161 doc = help.helptable[v]
1156 if not doc:
1162 if not doc:
1157 doc = _("(No help text available)")
1163 doc = _("(No help text available)")
1158 if callable(doc):
1164 if callable(doc):
1159 doc = doc()
1165 doc = doc()
1160
1166
1161 ui.write("%s\n" % header)
1167 ui.write("%s\n" % header)
1162 ui.write("%s\n" % doc.rstrip())
1168 ui.write("%s\n" % doc.rstrip())
1163
1169
1164 def helpext(name):
1170 def helpext(name):
1165 try:
1171 try:
1166 mod = findext(name)
1172 mod = findext(name)
1167 except KeyError:
1173 except KeyError:
1168 raise UnknownCommand(name)
1174 raise UnknownCommand(name)
1169
1175
1170 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1176 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1171 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1177 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1172 for d in doc[1:]:
1178 for d in doc[1:]:
1173 ui.write(d, '\n')
1179 ui.write(d, '\n')
1174
1180
1175 ui.status('\n')
1181 ui.status('\n')
1176 if ui.verbose:
1182 if ui.verbose:
1177 ui.status(_('list of commands:\n\n'))
1183 ui.status(_('list of commands:\n\n'))
1178 else:
1184 else:
1179 ui.status(_('list of commands (use "hg help -v %s" '
1185 ui.status(_('list of commands (use "hg help -v %s" '
1180 'to show aliases and global options):\n\n') % name)
1186 'to show aliases and global options):\n\n') % name)
1181
1187
1182 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
1188 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
1183 helplist(modcmds.has_key)
1189 helplist(modcmds.has_key)
1184
1190
1185 if name and name != 'shortlist':
1191 if name and name != 'shortlist':
1186 i = None
1192 i = None
1187 for f in (helpcmd, helptopic, helpext):
1193 for f in (helpcmd, helptopic, helpext):
1188 try:
1194 try:
1189 f(name)
1195 f(name)
1190 i = None
1196 i = None
1191 break
1197 break
1192 except UnknownCommand, inst:
1198 except UnknownCommand, inst:
1193 i = inst
1199 i = inst
1194 if i:
1200 if i:
1195 raise i
1201 raise i
1196
1202
1197 else:
1203 else:
1198 # program name
1204 # program name
1199 if ui.verbose or with_version:
1205 if ui.verbose or with_version:
1200 version_(ui)
1206 version_(ui)
1201 else:
1207 else:
1202 ui.status(_("Mercurial Distributed SCM\n"))
1208 ui.status(_("Mercurial Distributed SCM\n"))
1203 ui.status('\n')
1209 ui.status('\n')
1204
1210
1205 # list of commands
1211 # list of commands
1206 if name == "shortlist":
1212 if name == "shortlist":
1207 ui.status(_('basic commands (use "hg help" '
1213 ui.status(_('basic commands (use "hg help" '
1208 'for the full list or option "-v" for details):\n\n'))
1214 'for the full list or option "-v" for details):\n\n'))
1209 elif ui.verbose:
1215 elif ui.verbose:
1210 ui.status(_('list of commands:\n\n'))
1216 ui.status(_('list of commands:\n\n'))
1211 else:
1217 else:
1212 ui.status(_('list of commands (use "hg help -v" '
1218 ui.status(_('list of commands (use "hg help -v" '
1213 'to show aliases and global options):\n\n'))
1219 'to show aliases and global options):\n\n'))
1214
1220
1215 helplist()
1221 helplist()
1216
1222
1217 # global options
1223 # global options
1218 if ui.verbose:
1224 if ui.verbose:
1219 option_lists.append(("global options", globalopts))
1225 option_lists.append(("global options", globalopts))
1220
1226
1221 # list all option lists
1227 # list all option lists
1222 opt_output = []
1228 opt_output = []
1223 for title, options in option_lists:
1229 for title, options in option_lists:
1224 opt_output.append(("\n%s:\n" % title, None))
1230 opt_output.append(("\n%s:\n" % title, None))
1225 for shortopt, longopt, default, desc in options:
1231 for shortopt, longopt, default, desc in options:
1226 if "DEPRECATED" in desc and not ui.verbose: continue
1232 if "DEPRECATED" in desc and not ui.verbose: continue
1227 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1233 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1228 longopt and " --%s" % longopt),
1234 longopt and " --%s" % longopt),
1229 "%s%s" % (desc,
1235 "%s%s" % (desc,
1230 default
1236 default
1231 and _(" (default: %s)") % default
1237 and _(" (default: %s)") % default
1232 or "")))
1238 or "")))
1233
1239
1234 if opt_output:
1240 if opt_output:
1235 opts_len = max([len(line[0]) for line in opt_output if line[1]])
1241 opts_len = max([len(line[0]) for line in opt_output if line[1]])
1236 for first, second in opt_output:
1242 for first, second in opt_output:
1237 if second:
1243 if second:
1238 ui.write(" %-*s %s\n" % (opts_len, first, second))
1244 ui.write(" %-*s %s\n" % (opts_len, first, second))
1239 else:
1245 else:
1240 ui.write("%s\n" % first)
1246 ui.write("%s\n" % first)
1241
1247
1242 def identify(ui, repo):
1248 def identify(ui, repo):
1243 """print information about the working copy
1249 """print information about the working copy
1244
1250
1245 Print a short summary of the current state of the repo.
1251 Print a short summary of the current state of the repo.
1246
1252
1247 This summary identifies the repository state using one or two parent
1253 This summary identifies the repository state using one or two parent
1248 hash identifiers, followed by a "+" if there are uncommitted changes
1254 hash identifiers, followed by a "+" if there are uncommitted changes
1249 in the working directory, followed by a list of tags for this revision.
1255 in the working directory, followed by a list of tags for this revision.
1250 """
1256 """
1251 parents = [p for p in repo.dirstate.parents() if p != nullid]
1257 parents = [p for p in repo.dirstate.parents() if p != nullid]
1252 if not parents:
1258 if not parents:
1253 ui.write(_("unknown\n"))
1259 ui.write(_("unknown\n"))
1254 return
1260 return
1255
1261
1256 hexfunc = ui.debugflag and hex or short
1262 hexfunc = ui.debugflag and hex or short
1257 modified, added, removed, deleted = repo.status()[:4]
1263 modified, added, removed, deleted = repo.status()[:4]
1258 output = ["%s%s" %
1264 output = ["%s%s" %
1259 ('+'.join([hexfunc(parent) for parent in parents]),
1265 ('+'.join([hexfunc(parent) for parent in parents]),
1260 (modified or added or removed or deleted) and "+" or "")]
1266 (modified or added or removed or deleted) and "+" or "")]
1261
1267
1262 if not ui.quiet:
1268 if not ui.quiet:
1263
1269
1264 branch = repo.workingctx().branch()
1270 branch = repo.workingctx().branch()
1265 if branch:
1271 if branch:
1266 output.append("(%s)" % branch)
1272 output.append("(%s)" % branch)
1267
1273
1268 # multiple tags for a single parent separated by '/'
1274 # multiple tags for a single parent separated by '/'
1269 parenttags = ['/'.join(tags)
1275 parenttags = ['/'.join(tags)
1270 for tags in map(repo.nodetags, parents) if tags]
1276 for tags in map(repo.nodetags, parents) if tags]
1271 # tags for multiple parents separated by ' + '
1277 # tags for multiple parents separated by ' + '
1272 if parenttags:
1278 if parenttags:
1273 output.append(' + '.join(parenttags))
1279 output.append(' + '.join(parenttags))
1274
1280
1275 ui.write("%s\n" % ' '.join(output))
1281 ui.write("%s\n" % ' '.join(output))
1276
1282
1277 def import_(ui, repo, patch1, *patches, **opts):
1283 def import_(ui, repo, patch1, *patches, **opts):
1278 """import an ordered set of patches
1284 """import an ordered set of patches
1279
1285
1280 Import a list of patches and commit them individually.
1286 Import a list of patches and commit them individually.
1281
1287
1282 If there are outstanding changes in the working directory, import
1288 If there are outstanding changes in the working directory, import
1283 will abort unless given the -f flag.
1289 will abort unless given the -f flag.
1284
1290
1285 You can import a patch straight from a mail message. Even patches
1291 You can import a patch straight from a mail message. Even patches
1286 as attachments work (body part must be type text/plain or
1292 as attachments work (body part must be type text/plain or
1287 text/x-patch to be used). From and Subject headers of email
1293 text/x-patch to be used). From and Subject headers of email
1288 message are used as default committer and commit message. All
1294 message are used as default committer and commit message. All
1289 text/plain body parts before first diff are added to commit
1295 text/plain body parts before first diff are added to commit
1290 message.
1296 message.
1291
1297
1292 If imported patch was generated by hg export, user and description
1298 If imported patch was generated by hg export, user and description
1293 from patch override values from message headers and body. Values
1299 from patch override values from message headers and body. Values
1294 given on command line with -m and -u override these.
1300 given on command line with -m and -u override these.
1295
1301
1296 To read a patch from standard input, use patch name "-".
1302 To read a patch from standard input, use patch name "-".
1297 """
1303 """
1298 patches = (patch1,) + patches
1304 patches = (patch1,) + patches
1299
1305
1300 if not opts['force']:
1306 if not opts['force']:
1301 bail_if_changed(repo)
1307 bail_if_changed(repo)
1302
1308
1303 d = opts["base"]
1309 d = opts["base"]
1304 strip = opts["strip"]
1310 strip = opts["strip"]
1305
1311
1306 wlock = repo.wlock()
1312 wlock = repo.wlock()
1307 lock = repo.lock()
1313 lock = repo.lock()
1308
1314
1309 for p in patches:
1315 for p in patches:
1310 pf = os.path.join(d, p)
1316 pf = os.path.join(d, p)
1311
1317
1312 if pf == '-':
1318 if pf == '-':
1313 ui.status(_("applying patch from stdin\n"))
1319 ui.status(_("applying patch from stdin\n"))
1314 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1320 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1315 else:
1321 else:
1316 ui.status(_("applying %s\n") % p)
1322 ui.status(_("applying %s\n") % p)
1317 tmpname, message, user, date = patch.extract(ui, file(pf))
1323 tmpname, message, user, date = patch.extract(ui, file(pf))
1318
1324
1319 if tmpname is None:
1325 if tmpname is None:
1320 raise util.Abort(_('no diffs found'))
1326 raise util.Abort(_('no diffs found'))
1321
1327
1322 try:
1328 try:
1323 if opts['message']:
1329 if opts['message']:
1324 # pickup the cmdline msg
1330 # pickup the cmdline msg
1325 message = opts['message']
1331 message = opts['message']
1326 elif message:
1332 elif message:
1327 # pickup the patch msg
1333 # pickup the patch msg
1328 message = message.strip()
1334 message = message.strip()
1329 else:
1335 else:
1330 # launch the editor
1336 # launch the editor
1331 message = None
1337 message = None
1332 ui.debug(_('message:\n%s\n') % message)
1338 ui.debug(_('message:\n%s\n') % message)
1333
1339
1334 files = {}
1340 files = {}
1335 try:
1341 try:
1336 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1342 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1337 files=files)
1343 files=files)
1338 finally:
1344 finally:
1339 files = patch.updatedir(ui, repo, files, wlock=wlock)
1345 files = patch.updatedir(ui, repo, files, wlock=wlock)
1340 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1346 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1341 finally:
1347 finally:
1342 os.unlink(tmpname)
1348 os.unlink(tmpname)
1343
1349
1344 def incoming(ui, repo, source="default", **opts):
1350 def incoming(ui, repo, source="default", **opts):
1345 """show new changesets found in source
1351 """show new changesets found in source
1346
1352
1347 Show new changesets found in the specified path/URL or the default
1353 Show new changesets found in the specified path/URL or the default
1348 pull location. These are the changesets that would be pulled if a pull
1354 pull location. These are the changesets that would be pulled if a pull
1349 was requested.
1355 was requested.
1350
1356
1351 For remote repository, using --bundle avoids downloading the changesets
1357 For remote repository, using --bundle avoids downloading the changesets
1352 twice if the incoming is followed by a pull.
1358 twice if the incoming is followed by a pull.
1353
1359
1354 See pull for valid source format details.
1360 See pull for valid source format details.
1355 """
1361 """
1356 source = ui.expandpath(source)
1362 source = ui.expandpath(source)
1357 setremoteconfig(ui, opts)
1363 setremoteconfig(ui, opts)
1358
1364
1359 other = hg.repository(ui, source)
1365 other = hg.repository(ui, source)
1360 incoming = repo.findincoming(other, force=opts["force"])
1366 incoming = repo.findincoming(other, force=opts["force"])
1361 if not incoming:
1367 if not incoming:
1362 ui.status(_("no changes found\n"))
1368 ui.status(_("no changes found\n"))
1363 return
1369 return
1364
1370
1365 cleanup = None
1371 cleanup = None
1366 try:
1372 try:
1367 fname = opts["bundle"]
1373 fname = opts["bundle"]
1368 if fname or not other.local():
1374 if fname or not other.local():
1369 # create a bundle (uncompressed if other repo is not local)
1375 # create a bundle (uncompressed if other repo is not local)
1370 cg = other.changegroup(incoming, "incoming")
1376 cg = other.changegroup(incoming, "incoming")
1371 bundletype = other.local() and "HG10BZ" or "HG10UN"
1377 bundletype = other.local() and "HG10BZ" or "HG10UN"
1372 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1378 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1373 # keep written bundle?
1379 # keep written bundle?
1374 if opts["bundle"]:
1380 if opts["bundle"]:
1375 cleanup = None
1381 cleanup = None
1376 if not other.local():
1382 if not other.local():
1377 # use the created uncompressed bundlerepo
1383 # use the created uncompressed bundlerepo
1378 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1384 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1379
1385
1380 revs = None
1386 revs = None
1381 if opts['rev']:
1387 if opts['rev']:
1382 revs = [other.lookup(rev) for rev in opts['rev']]
1388 revs = [other.lookup(rev) for rev in opts['rev']]
1383 o = other.changelog.nodesbetween(incoming, revs)[0]
1389 o = other.changelog.nodesbetween(incoming, revs)[0]
1384 if opts['newest_first']:
1390 if opts['newest_first']:
1385 o.reverse()
1391 o.reverse()
1386 displayer = cmdutil.show_changeset(ui, other, opts)
1392 displayer = cmdutil.show_changeset(ui, other, opts)
1387 for n in o:
1393 for n in o:
1388 parents = [p for p in other.changelog.parents(n) if p != nullid]
1394 parents = [p for p in other.changelog.parents(n) if p != nullid]
1389 if opts['no_merges'] and len(parents) == 2:
1395 if opts['no_merges'] and len(parents) == 2:
1390 continue
1396 continue
1391 displayer.show(changenode=n)
1397 displayer.show(changenode=n)
1392 finally:
1398 finally:
1393 if hasattr(other, 'close'):
1399 if hasattr(other, 'close'):
1394 other.close()
1400 other.close()
1395 if cleanup:
1401 if cleanup:
1396 os.unlink(cleanup)
1402 os.unlink(cleanup)
1397
1403
1398 def init(ui, dest=".", **opts):
1404 def init(ui, dest=".", **opts):
1399 """create a new repository in the given directory
1405 """create a new repository in the given directory
1400
1406
1401 Initialize a new repository in the given directory. If the given
1407 Initialize a new repository in the given directory. If the given
1402 directory does not exist, it is created.
1408 directory does not exist, it is created.
1403
1409
1404 If no directory is given, the current directory is used.
1410 If no directory is given, the current directory is used.
1405
1411
1406 It is possible to specify an ssh:// URL as the destination.
1412 It is possible to specify an ssh:// URL as the destination.
1407 Look at the help text for the pull command for important details
1413 Look at the help text for the pull command for important details
1408 about ssh:// URLs.
1414 about ssh:// URLs.
1409 """
1415 """
1410 setremoteconfig(ui, opts)
1416 setremoteconfig(ui, opts)
1411 hg.repository(ui, dest, create=1)
1417 hg.repository(ui, dest, create=1)
1412
1418
1413 def locate(ui, repo, *pats, **opts):
1419 def locate(ui, repo, *pats, **opts):
1414 """locate files matching specific patterns
1420 """locate files matching specific patterns
1415
1421
1416 Print all files under Mercurial control whose names match the
1422 Print all files under Mercurial control whose names match the
1417 given patterns.
1423 given patterns.
1418
1424
1419 This command searches the current directory and its
1425 This command searches the current directory and its
1420 subdirectories. To search an entire repository, move to the root
1426 subdirectories. To search an entire repository, move to the root
1421 of the repository.
1427 of the repository.
1422
1428
1423 If no patterns are given to match, this command prints all file
1429 If no patterns are given to match, this command prints all file
1424 names.
1430 names.
1425
1431
1426 If you want to feed the output of this command into the "xargs"
1432 If you want to feed the output of this command into the "xargs"
1427 command, use the "-0" option to both this command and "xargs".
1433 command, use the "-0" option to both this command and "xargs".
1428 This will avoid the problem of "xargs" treating single filenames
1434 This will avoid the problem of "xargs" treating single filenames
1429 that contain white space as multiple filenames.
1435 that contain white space as multiple filenames.
1430 """
1436 """
1431 end = opts['print0'] and '\0' or '\n'
1437 end = opts['print0'] and '\0' or '\n'
1432 rev = opts['rev']
1438 rev = opts['rev']
1433 if rev:
1439 if rev:
1434 node = repo.lookup(rev)
1440 node = repo.lookup(rev)
1435 else:
1441 else:
1436 node = None
1442 node = None
1437
1443
1438 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1444 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1439 head='(?:.*/|)'):
1445 head='(?:.*/|)'):
1440 if not node and repo.dirstate.state(abs) == '?':
1446 if not node and repo.dirstate.state(abs) == '?':
1441 continue
1447 continue
1442 if opts['fullpath']:
1448 if opts['fullpath']:
1443 ui.write(os.path.join(repo.root, abs), end)
1449 ui.write(os.path.join(repo.root, abs), end)
1444 else:
1450 else:
1445 ui.write(((pats and rel) or abs), end)
1451 ui.write(((pats and rel) or abs), end)
1446
1452
1447 def log(ui, repo, *pats, **opts):
1453 def log(ui, repo, *pats, **opts):
1448 """show revision history of entire repository or files
1454 """show revision history of entire repository or files
1449
1455
1450 Print the revision history of the specified files or the entire
1456 Print the revision history of the specified files or the entire
1451 project.
1457 project.
1452
1458
1453 File history is shown without following rename or copy history of
1459 File history is shown without following rename or copy history of
1454 files. Use -f/--follow with a file name to follow history across
1460 files. Use -f/--follow with a file name to follow history across
1455 renames and copies. --follow without a file name will only show
1461 renames and copies. --follow without a file name will only show
1456 ancestors or descendants of the starting revision. --follow-first
1462 ancestors or descendants of the starting revision. --follow-first
1457 only follows the first parent of merge revisions.
1463 only follows the first parent of merge revisions.
1458
1464
1459 If no revision range is specified, the default is tip:0 unless
1465 If no revision range is specified, the default is tip:0 unless
1460 --follow is set, in which case the working directory parent is
1466 --follow is set, in which case the working directory parent is
1461 used as the starting revision.
1467 used as the starting revision.
1462
1468
1463 By default this command outputs: changeset id and hash, tags,
1469 By default this command outputs: changeset id and hash, tags,
1464 non-trivial parents, user, date and time, and a summary for each
1470 non-trivial parents, user, date and time, and a summary for each
1465 commit. When the -v/--verbose switch is used, the list of changed
1471 commit. When the -v/--verbose switch is used, the list of changed
1466 files and full commit message is shown.
1472 files and full commit message is shown.
1467 """
1473 """
1468
1474
1469 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1475 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1470 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1476 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1471
1477
1472 if opts['limit']:
1478 if opts['limit']:
1473 try:
1479 try:
1474 limit = int(opts['limit'])
1480 limit = int(opts['limit'])
1475 except ValueError:
1481 except ValueError:
1476 raise util.Abort(_('limit must be a positive integer'))
1482 raise util.Abort(_('limit must be a positive integer'))
1477 if limit <= 0: raise util.Abort(_('limit must be positive'))
1483 if limit <= 0: raise util.Abort(_('limit must be positive'))
1478 else:
1484 else:
1479 limit = sys.maxint
1485 limit = sys.maxint
1480 count = 0
1486 count = 0
1481
1487
1482 if opts['copies'] and opts['rev']:
1488 if opts['copies'] and opts['rev']:
1483 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1489 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1484 else:
1490 else:
1485 endrev = repo.changelog.count()
1491 endrev = repo.changelog.count()
1486 rcache = {}
1492 rcache = {}
1487 ncache = {}
1493 ncache = {}
1488 dcache = []
1494 dcache = []
1489 def getrenamed(fn, rev, man):
1495 def getrenamed(fn, rev, man):
1490 '''looks up all renames for a file (up to endrev) the first
1496 '''looks up all renames for a file (up to endrev) the first
1491 time the file is given. It indexes on the changerev and only
1497 time the file is given. It indexes on the changerev and only
1492 parses the manifest if linkrev != changerev.
1498 parses the manifest if linkrev != changerev.
1493 Returns rename info for fn at changerev rev.'''
1499 Returns rename info for fn at changerev rev.'''
1494 if fn not in rcache:
1500 if fn not in rcache:
1495 rcache[fn] = {}
1501 rcache[fn] = {}
1496 ncache[fn] = {}
1502 ncache[fn] = {}
1497 fl = repo.file(fn)
1503 fl = repo.file(fn)
1498 for i in xrange(fl.count()):
1504 for i in xrange(fl.count()):
1499 node = fl.node(i)
1505 node = fl.node(i)
1500 lr = fl.linkrev(node)
1506 lr = fl.linkrev(node)
1501 renamed = fl.renamed(node)
1507 renamed = fl.renamed(node)
1502 rcache[fn][lr] = renamed
1508 rcache[fn][lr] = renamed
1503 if renamed:
1509 if renamed:
1504 ncache[fn][node] = renamed
1510 ncache[fn][node] = renamed
1505 if lr >= endrev:
1511 if lr >= endrev:
1506 break
1512 break
1507 if rev in rcache[fn]:
1513 if rev in rcache[fn]:
1508 return rcache[fn][rev]
1514 return rcache[fn][rev]
1509 mr = repo.manifest.rev(man)
1515 mr = repo.manifest.rev(man)
1510 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1516 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1511 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1517 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1512 if not dcache or dcache[0] != man:
1518 if not dcache or dcache[0] != man:
1513 dcache[:] = [man, repo.manifest.readdelta(man)]
1519 dcache[:] = [man, repo.manifest.readdelta(man)]
1514 if fn in dcache[1]:
1520 if fn in dcache[1]:
1515 return ncache[fn].get(dcache[1][fn])
1521 return ncache[fn].get(dcache[1][fn])
1516 return None
1522 return None
1517
1523
1518 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
1524 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
1519 for st, rev, fns in changeiter:
1525 for st, rev, fns in changeiter:
1520 if st == 'add':
1526 if st == 'add':
1521 changenode = repo.changelog.node(rev)
1527 changenode = repo.changelog.node(rev)
1522 parents = [p for p in repo.changelog.parentrevs(rev)
1528 parents = [p for p in repo.changelog.parentrevs(rev)
1523 if p != nullrev]
1529 if p != nullrev]
1524 if opts['no_merges'] and len(parents) == 2:
1530 if opts['no_merges'] and len(parents) == 2:
1525 continue
1531 continue
1526 if opts['only_merges'] and len(parents) != 2:
1532 if opts['only_merges'] and len(parents) != 2:
1527 continue
1533 continue
1528
1534
1529 if opts['keyword']:
1535 if opts['keyword']:
1530 changes = get(rev)
1536 changes = get(rev)
1531 miss = 0
1537 miss = 0
1532 for k in [kw.lower() for kw in opts['keyword']]:
1538 for k in [kw.lower() for kw in opts['keyword']]:
1533 if not (k in changes[1].lower() or
1539 if not (k in changes[1].lower() or
1534 k in changes[4].lower() or
1540 k in changes[4].lower() or
1535 k in " ".join(changes[3][:20]).lower()):
1541 k in " ".join(changes[3][:20]).lower()):
1536 miss = 1
1542 miss = 1
1537 break
1543 break
1538 if miss:
1544 if miss:
1539 continue
1545 continue
1540
1546
1541 copies = []
1547 copies = []
1542 if opts.get('copies') and rev:
1548 if opts.get('copies') and rev:
1543 mf = get(rev)[0]
1549 mf = get(rev)[0]
1544 for fn in get(rev)[3]:
1550 for fn in get(rev)[3]:
1545 rename = getrenamed(fn, rev, mf)
1551 rename = getrenamed(fn, rev, mf)
1546 if rename:
1552 if rename:
1547 copies.append((fn, rename[0]))
1553 copies.append((fn, rename[0]))
1548 displayer.show(rev, changenode, copies=copies)
1554 displayer.show(rev, changenode, copies=copies)
1549 elif st == 'iter':
1555 elif st == 'iter':
1550 if count == limit: break
1556 if count == limit: break
1551 if displayer.flush(rev):
1557 if displayer.flush(rev):
1552 count += 1
1558 count += 1
1553
1559
1554 def manifest(ui, repo, rev=None):
1560 def manifest(ui, repo, rev=None):
1555 """output the latest or given revision of the project manifest
1561 """output the latest or given revision of the project manifest
1556
1562
1557 Print a list of version controlled files for the given revision.
1563 Print a list of version controlled files for the given revision.
1558
1564
1559 The manifest is the list of files being version controlled. If no revision
1565 The manifest is the list of files being version controlled. If no revision
1560 is given then the first parent of the working directory is used.
1566 is given then the first parent of the working directory is used.
1561
1567
1562 With -v flag, print file permissions. With --debug flag, print
1568 With -v flag, print file permissions. With --debug flag, print
1563 file revision hashes.
1569 file revision hashes.
1564 """
1570 """
1565
1571
1566 m = repo.changectx(rev).manifest()
1572 m = repo.changectx(rev).manifest()
1567 files = m.keys()
1573 files = m.keys()
1568 files.sort()
1574 files.sort()
1569
1575
1570 for f in files:
1576 for f in files:
1571 if ui.debugflag:
1577 if ui.debugflag:
1572 ui.write("%40s " % hex(m[f]))
1578 ui.write("%40s " % hex(m[f]))
1573 if ui.verbose:
1579 if ui.verbose:
1574 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1580 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1575 ui.write("%s\n" % f)
1581 ui.write("%s\n" % f)
1576
1582
1577 def merge(ui, repo, node=None, force=None, branch=None):
1583 def merge(ui, repo, node=None, force=None, branch=None):
1578 """Merge working directory with another revision
1584 """Merge working directory with another revision
1579
1585
1580 Merge the contents of the current working directory and the
1586 Merge the contents of the current working directory and the
1581 requested revision. Files that changed between either parent are
1587 requested revision. Files that changed between either parent are
1582 marked as changed for the next commit and a commit must be
1588 marked as changed for the next commit and a commit must be
1583 performed before any further updates are allowed.
1589 performed before any further updates are allowed.
1584
1590
1585 If no revision is specified, the working directory's parent is a
1591 If no revision is specified, the working directory's parent is a
1586 head revision, and the repository contains exactly one other head,
1592 head revision, and the repository contains exactly one other head,
1587 the other head is merged with by default. Otherwise, an explicit
1593 the other head is merged with by default. Otherwise, an explicit
1588 revision to merge with must be provided.
1594 revision to merge with must be provided.
1589 """
1595 """
1590
1596
1591 if node or branch:
1597 if node or branch:
1592 node = _lookup(repo, node, branch)
1598 node = _lookup(repo, node, branch)
1593 else:
1599 else:
1594 heads = repo.heads()
1600 heads = repo.heads()
1595 if len(heads) > 2:
1601 if len(heads) > 2:
1596 raise util.Abort(_('repo has %d heads - '
1602 raise util.Abort(_('repo has %d heads - '
1597 'please merge with an explicit rev') %
1603 'please merge with an explicit rev') %
1598 len(heads))
1604 len(heads))
1599 if len(heads) == 1:
1605 if len(heads) == 1:
1600 raise util.Abort(_('there is nothing to merge - '
1606 raise util.Abort(_('there is nothing to merge - '
1601 'use "hg update" instead'))
1607 'use "hg update" instead'))
1602 parent = repo.dirstate.parents()[0]
1608 parent = repo.dirstate.parents()[0]
1603 if parent not in heads:
1609 if parent not in heads:
1604 raise util.Abort(_('working dir not at a head rev - '
1610 raise util.Abort(_('working dir not at a head rev - '
1605 'use "hg update" or merge with an explicit rev'))
1611 'use "hg update" or merge with an explicit rev'))
1606 node = parent == heads[0] and heads[-1] or heads[0]
1612 node = parent == heads[0] and heads[-1] or heads[0]
1607 return hg.merge(repo, node, force=force)
1613 return hg.merge(repo, node, force=force)
1608
1614
1609 def outgoing(ui, repo, dest=None, **opts):
1615 def outgoing(ui, repo, dest=None, **opts):
1610 """show changesets not found in destination
1616 """show changesets not found in destination
1611
1617
1612 Show changesets not found in the specified destination repository or
1618 Show changesets not found in the specified destination repository or
1613 the default push location. These are the changesets that would be pushed
1619 the default push location. These are the changesets that would be pushed
1614 if a push was requested.
1620 if a push was requested.
1615
1621
1616 See pull for valid destination format details.
1622 See pull for valid destination format details.
1617 """
1623 """
1618 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1624 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1619 setremoteconfig(ui, opts)
1625 setremoteconfig(ui, opts)
1620 revs = None
1626 revs = None
1621 if opts['rev']:
1627 if opts['rev']:
1622 revs = [repo.lookup(rev) for rev in opts['rev']]
1628 revs = [repo.lookup(rev) for rev in opts['rev']]
1623
1629
1624 other = hg.repository(ui, dest)
1630 other = hg.repository(ui, dest)
1625 o = repo.findoutgoing(other, force=opts['force'])
1631 o = repo.findoutgoing(other, force=opts['force'])
1626 if not o:
1632 if not o:
1627 ui.status(_("no changes found\n"))
1633 ui.status(_("no changes found\n"))
1628 return
1634 return
1629 o = repo.changelog.nodesbetween(o, revs)[0]
1635 o = repo.changelog.nodesbetween(o, revs)[0]
1630 if opts['newest_first']:
1636 if opts['newest_first']:
1631 o.reverse()
1637 o.reverse()
1632 displayer = cmdutil.show_changeset(ui, repo, opts)
1638 displayer = cmdutil.show_changeset(ui, repo, opts)
1633 for n in o:
1639 for n in o:
1634 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1640 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1635 if opts['no_merges'] and len(parents) == 2:
1641 if opts['no_merges'] and len(parents) == 2:
1636 continue
1642 continue
1637 displayer.show(changenode=n)
1643 displayer.show(changenode=n)
1638
1644
1639 def parents(ui, repo, file_=None, **opts):
1645 def parents(ui, repo, file_=None, **opts):
1640 """show the parents of the working dir or revision
1646 """show the parents of the working dir or revision
1641
1647
1642 Print the working directory's parent revisions.
1648 Print the working directory's parent revisions.
1643 """
1649 """
1644 rev = opts.get('rev')
1650 rev = opts.get('rev')
1645 if rev:
1651 if rev:
1646 if file_:
1652 if file_:
1647 ctx = repo.filectx(file_, changeid=rev)
1653 ctx = repo.filectx(file_, changeid=rev)
1648 else:
1654 else:
1649 ctx = repo.changectx(rev)
1655 ctx = repo.changectx(rev)
1650 p = [cp.node() for cp in ctx.parents()]
1656 p = [cp.node() for cp in ctx.parents()]
1651 else:
1657 else:
1652 p = repo.dirstate.parents()
1658 p = repo.dirstate.parents()
1653
1659
1654 displayer = cmdutil.show_changeset(ui, repo, opts)
1660 displayer = cmdutil.show_changeset(ui, repo, opts)
1655 for n in p:
1661 for n in p:
1656 if n != nullid:
1662 if n != nullid:
1657 displayer.show(changenode=n)
1663 displayer.show(changenode=n)
1658
1664
1659 def paths(ui, repo, search=None):
1665 def paths(ui, repo, search=None):
1660 """show definition of symbolic path names
1666 """show definition of symbolic path names
1661
1667
1662 Show definition of symbolic path name NAME. If no name is given, show
1668 Show definition of symbolic path name NAME. If no name is given, show
1663 definition of available names.
1669 definition of available names.
1664
1670
1665 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1671 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1666 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1672 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1667 """
1673 """
1668 if search:
1674 if search:
1669 for name, path in ui.configitems("paths"):
1675 for name, path in ui.configitems("paths"):
1670 if name == search:
1676 if name == search:
1671 ui.write("%s\n" % path)
1677 ui.write("%s\n" % path)
1672 return
1678 return
1673 ui.warn(_("not found!\n"))
1679 ui.warn(_("not found!\n"))
1674 return 1
1680 return 1
1675 else:
1681 else:
1676 for name, path in ui.configitems("paths"):
1682 for name, path in ui.configitems("paths"):
1677 ui.write("%s = %s\n" % (name, path))
1683 ui.write("%s = %s\n" % (name, path))
1678
1684
1679 def postincoming(ui, repo, modheads, optupdate):
1685 def postincoming(ui, repo, modheads, optupdate):
1680 if modheads == 0:
1686 if modheads == 0:
1681 return
1687 return
1682 if optupdate:
1688 if optupdate:
1683 if modheads == 1:
1689 if modheads == 1:
1684 return hg.update(repo, repo.changelog.tip()) # update
1690 return hg.update(repo, repo.changelog.tip()) # update
1685 else:
1691 else:
1686 ui.status(_("not updating, since new heads added\n"))
1692 ui.status(_("not updating, since new heads added\n"))
1687 if modheads > 1:
1693 if modheads > 1:
1688 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1694 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1689 else:
1695 else:
1690 ui.status(_("(run 'hg update' to get a working copy)\n"))
1696 ui.status(_("(run 'hg update' to get a working copy)\n"))
1691
1697
1692 def pull(ui, repo, source="default", **opts):
1698 def pull(ui, repo, source="default", **opts):
1693 """pull changes from the specified source
1699 """pull changes from the specified source
1694
1700
1695 Pull changes from a remote repository to a local one.
1701 Pull changes from a remote repository to a local one.
1696
1702
1697 This finds all changes from the repository at the specified path
1703 This finds all changes from the repository at the specified path
1698 or URL and adds them to the local repository. By default, this
1704 or URL and adds them to the local repository. By default, this
1699 does not update the copy of the project in the working directory.
1705 does not update the copy of the project in the working directory.
1700
1706
1701 Valid URLs are of the form:
1707 Valid URLs are of the form:
1702
1708
1703 local/filesystem/path (or file://local/filesystem/path)
1709 local/filesystem/path (or file://local/filesystem/path)
1704 http://[user@]host[:port]/[path]
1710 http://[user@]host[:port]/[path]
1705 https://[user@]host[:port]/[path]
1711 https://[user@]host[:port]/[path]
1706 ssh://[user@]host[:port]/[path]
1712 ssh://[user@]host[:port]/[path]
1707 static-http://host[:port]/[path]
1713 static-http://host[:port]/[path]
1708
1714
1709 Paths in the local filesystem can either point to Mercurial
1715 Paths in the local filesystem can either point to Mercurial
1710 repositories or to bundle files (as created by 'hg bundle' or
1716 repositories or to bundle files (as created by 'hg bundle' or
1711 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1717 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1712 allows access to a Mercurial repository where you simply use a web
1718 allows access to a Mercurial repository where you simply use a web
1713 server to publish the .hg directory as static content.
1719 server to publish the .hg directory as static content.
1714
1720
1715 Some notes about using SSH with Mercurial:
1721 Some notes about using SSH with Mercurial:
1716 - SSH requires an accessible shell account on the destination machine
1722 - SSH requires an accessible shell account on the destination machine
1717 and a copy of hg in the remote path or specified with as remotecmd.
1723 and a copy of hg in the remote path or specified with as remotecmd.
1718 - path is relative to the remote user's home directory by default.
1724 - path is relative to the remote user's home directory by default.
1719 Use an extra slash at the start of a path to specify an absolute path:
1725 Use an extra slash at the start of a path to specify an absolute path:
1720 ssh://example.com//tmp/repository
1726 ssh://example.com//tmp/repository
1721 - Mercurial doesn't use its own compression via SSH; the right thing
1727 - Mercurial doesn't use its own compression via SSH; the right thing
1722 to do is to configure it in your ~/.ssh/config, e.g.:
1728 to do is to configure it in your ~/.ssh/config, e.g.:
1723 Host *.mylocalnetwork.example.com
1729 Host *.mylocalnetwork.example.com
1724 Compression no
1730 Compression no
1725 Host *
1731 Host *
1726 Compression yes
1732 Compression yes
1727 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1733 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1728 with the --ssh command line option.
1734 with the --ssh command line option.
1729 """
1735 """
1730 source = ui.expandpath(source)
1736 source = ui.expandpath(source)
1731 setremoteconfig(ui, opts)
1737 setremoteconfig(ui, opts)
1732
1738
1733 other = hg.repository(ui, source)
1739 other = hg.repository(ui, source)
1734 ui.status(_('pulling from %s\n') % (source))
1740 ui.status(_('pulling from %s\n') % (source))
1735 revs = None
1741 revs = None
1736 if opts['rev']:
1742 if opts['rev']:
1737 if 'lookup' in other.capabilities:
1743 if 'lookup' in other.capabilities:
1738 revs = [other.lookup(rev) for rev in opts['rev']]
1744 revs = [other.lookup(rev) for rev in opts['rev']]
1739 else:
1745 else:
1740 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1746 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1741 raise util.Abort(error)
1747 raise util.Abort(error)
1742 modheads = repo.pull(other, heads=revs, force=opts['force'])
1748 modheads = repo.pull(other, heads=revs, force=opts['force'])
1743 return postincoming(ui, repo, modheads, opts['update'])
1749 return postincoming(ui, repo, modheads, opts['update'])
1744
1750
1745 def push(ui, repo, dest=None, **opts):
1751 def push(ui, repo, dest=None, **opts):
1746 """push changes to the specified destination
1752 """push changes to the specified destination
1747
1753
1748 Push changes from the local repository to the given destination.
1754 Push changes from the local repository to the given destination.
1749
1755
1750 This is the symmetrical operation for pull. It helps to move
1756 This is the symmetrical operation for pull. It helps to move
1751 changes from the current repository to a different one. If the
1757 changes from the current repository to a different one. If the
1752 destination is local this is identical to a pull in that directory
1758 destination is local this is identical to a pull in that directory
1753 from the current one.
1759 from the current one.
1754
1760
1755 By default, push will refuse to run if it detects the result would
1761 By default, push will refuse to run if it detects the result would
1756 increase the number of remote heads. This generally indicates the
1762 increase the number of remote heads. This generally indicates the
1757 the client has forgotten to sync and merge before pushing.
1763 the client has forgotten to sync and merge before pushing.
1758
1764
1759 Valid URLs are of the form:
1765 Valid URLs are of the form:
1760
1766
1761 local/filesystem/path (or file://local/filesystem/path)
1767 local/filesystem/path (or file://local/filesystem/path)
1762 ssh://[user@]host[:port]/[path]
1768 ssh://[user@]host[:port]/[path]
1763 http://[user@]host[:port]/[path]
1769 http://[user@]host[:port]/[path]
1764 https://[user@]host[:port]/[path]
1770 https://[user@]host[:port]/[path]
1765
1771
1766 Look at the help text for the pull command for important details
1772 Look at the help text for the pull command for important details
1767 about ssh:// URLs.
1773 about ssh:// URLs.
1768
1774
1769 Pushing to http:// and https:// URLs is only possible, if this
1775 Pushing to http:// and https:// URLs is only possible, if this
1770 feature is explicitly enabled on the remote Mercurial server.
1776 feature is explicitly enabled on the remote Mercurial server.
1771 """
1777 """
1772 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1778 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1773 setremoteconfig(ui, opts)
1779 setremoteconfig(ui, opts)
1774
1780
1775 other = hg.repository(ui, dest)
1781 other = hg.repository(ui, dest)
1776 ui.status('pushing to %s\n' % (dest))
1782 ui.status('pushing to %s\n' % (dest))
1777 revs = None
1783 revs = None
1778 if opts['rev']:
1784 if opts['rev']:
1779 revs = [repo.lookup(rev) for rev in opts['rev']]
1785 revs = [repo.lookup(rev) for rev in opts['rev']]
1780 r = repo.push(other, opts['force'], revs=revs)
1786 r = repo.push(other, opts['force'], revs=revs)
1781 return r == 0
1787 return r == 0
1782
1788
1783 def rawcommit(ui, repo, *pats, **opts):
1789 def rawcommit(ui, repo, *pats, **opts):
1784 """raw commit interface (DEPRECATED)
1790 """raw commit interface (DEPRECATED)
1785
1791
1786 (DEPRECATED)
1792 (DEPRECATED)
1787 Lowlevel commit, for use in helper scripts.
1793 Lowlevel commit, for use in helper scripts.
1788
1794
1789 This command is not intended to be used by normal users, as it is
1795 This command is not intended to be used by normal users, as it is
1790 primarily useful for importing from other SCMs.
1796 primarily useful for importing from other SCMs.
1791
1797
1792 This command is now deprecated and will be removed in a future
1798 This command is now deprecated and will be removed in a future
1793 release, please use debugsetparents and commit instead.
1799 release, please use debugsetparents and commit instead.
1794 """
1800 """
1795
1801
1796 ui.warn(_("(the rawcommit command is deprecated)\n"))
1802 ui.warn(_("(the rawcommit command is deprecated)\n"))
1797
1803
1798 message = logmessage(opts)
1804 message = logmessage(opts)
1799
1805
1800 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
1806 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
1801 if opts['files']:
1807 if opts['files']:
1802 files += open(opts['files']).read().splitlines()
1808 files += open(opts['files']).read().splitlines()
1803
1809
1804 parents = [repo.lookup(p) for p in opts['parent']]
1810 parents = [repo.lookup(p) for p in opts['parent']]
1805
1811
1806 try:
1812 try:
1807 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
1813 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
1808 except ValueError, inst:
1814 except ValueError, inst:
1809 raise util.Abort(str(inst))
1815 raise util.Abort(str(inst))
1810
1816
1811 def recover(ui, repo):
1817 def recover(ui, repo):
1812 """roll back an interrupted transaction
1818 """roll back an interrupted transaction
1813
1819
1814 Recover from an interrupted commit or pull.
1820 Recover from an interrupted commit or pull.
1815
1821
1816 This command tries to fix the repository status after an interrupted
1822 This command tries to fix the repository status after an interrupted
1817 operation. It should only be necessary when Mercurial suggests it.
1823 operation. It should only be necessary when Mercurial suggests it.
1818 """
1824 """
1819 if repo.recover():
1825 if repo.recover():
1820 return hg.verify(repo)
1826 return hg.verify(repo)
1821 return 1
1827 return 1
1822
1828
1823 def remove(ui, repo, *pats, **opts):
1829 def remove(ui, repo, *pats, **opts):
1824 """remove the specified files on the next commit
1830 """remove the specified files on the next commit
1825
1831
1826 Schedule the indicated files for removal from the repository.
1832 Schedule the indicated files for removal from the repository.
1827
1833
1828 This command schedules the files to be removed at the next commit.
1834 This command schedules the files to be removed at the next commit.
1829 This only removes files from the current branch, not from the
1835 This only removes files from the current branch, not from the
1830 entire project history. If the files still exist in the working
1836 entire project history. If the files still exist in the working
1831 directory, they will be deleted from it. If invoked with --after,
1837 directory, they will be deleted from it. If invoked with --after,
1832 files that have been manually deleted are marked as removed.
1838 files that have been manually deleted are marked as removed.
1833
1839
1834 Modified files and added files are not removed by default. To
1840 Modified files and added files are not removed by default. To
1835 remove them, use the -f/--force option.
1841 remove them, use the -f/--force option.
1836 """
1842 """
1837 names = []
1843 names = []
1838 if not opts['after'] and not pats:
1844 if not opts['after'] and not pats:
1839 raise util.Abort(_('no files specified'))
1845 raise util.Abort(_('no files specified'))
1840 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1846 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1841 exact = dict.fromkeys(files)
1847 exact = dict.fromkeys(files)
1842 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
1848 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
1843 modified, added, removed, deleted, unknown = mardu
1849 modified, added, removed, deleted, unknown = mardu
1844 remove, forget = [], []
1850 remove, forget = [], []
1845 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
1851 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
1846 reason = None
1852 reason = None
1847 if abs not in deleted and opts['after']:
1853 if abs not in deleted and opts['after']:
1848 reason = _('is still present')
1854 reason = _('is still present')
1849 elif abs in modified and not opts['force']:
1855 elif abs in modified and not opts['force']:
1850 reason = _('is modified (use -f to force removal)')
1856 reason = _('is modified (use -f to force removal)')
1851 elif abs in added:
1857 elif abs in added:
1852 if opts['force']:
1858 if opts['force']:
1853 forget.append(abs)
1859 forget.append(abs)
1854 continue
1860 continue
1855 reason = _('has been marked for add (use -f to force removal)')
1861 reason = _('has been marked for add (use -f to force removal)')
1856 elif abs in unknown:
1862 elif abs in unknown:
1857 reason = _('is not managed')
1863 reason = _('is not managed')
1858 elif abs in removed:
1864 elif abs in removed:
1859 continue
1865 continue
1860 if reason:
1866 if reason:
1861 if exact:
1867 if exact:
1862 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1868 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1863 else:
1869 else:
1864 if ui.verbose or not exact:
1870 if ui.verbose or not exact:
1865 ui.status(_('removing %s\n') % rel)
1871 ui.status(_('removing %s\n') % rel)
1866 remove.append(abs)
1872 remove.append(abs)
1867 repo.forget(forget)
1873 repo.forget(forget)
1868 repo.remove(remove, unlink=not opts['after'])
1874 repo.remove(remove, unlink=not opts['after'])
1869
1875
1870 def rename(ui, repo, *pats, **opts):
1876 def rename(ui, repo, *pats, **opts):
1871 """rename files; equivalent of copy + remove
1877 """rename files; equivalent of copy + remove
1872
1878
1873 Mark dest as copies of sources; mark sources for deletion. If
1879 Mark dest as copies of sources; mark sources for deletion. If
1874 dest is a directory, copies are put in that directory. If dest is
1880 dest is a directory, copies are put in that directory. If dest is
1875 a file, there can only be one source.
1881 a file, there can only be one source.
1876
1882
1877 By default, this command copies the contents of files as they
1883 By default, this command copies the contents of files as they
1878 stand in the working directory. If invoked with --after, the
1884 stand in the working directory. If invoked with --after, the
1879 operation is recorded, but no copying is performed.
1885 operation is recorded, but no copying is performed.
1880
1886
1881 This command takes effect in the next commit.
1887 This command takes effect in the next commit.
1882 """
1888 """
1883 wlock = repo.wlock(0)
1889 wlock = repo.wlock(0)
1884 errs, copied = docopy(ui, repo, pats, opts, wlock)
1890 errs, copied = docopy(ui, repo, pats, opts, wlock)
1885 names = []
1891 names = []
1886 for abs, rel, exact in copied:
1892 for abs, rel, exact in copied:
1887 if ui.verbose or not exact:
1893 if ui.verbose or not exact:
1888 ui.status(_('removing %s\n') % rel)
1894 ui.status(_('removing %s\n') % rel)
1889 names.append(abs)
1895 names.append(abs)
1890 if not opts.get('dry_run'):
1896 if not opts.get('dry_run'):
1891 repo.remove(names, True, wlock)
1897 repo.remove(names, True, wlock)
1892 return errs
1898 return errs
1893
1899
1894 def revert(ui, repo, *pats, **opts):
1900 def revert(ui, repo, *pats, **opts):
1895 """revert files or dirs to their states as of some revision
1901 """revert files or dirs to their states as of some revision
1896
1902
1897 With no revision specified, revert the named files or directories
1903 With no revision specified, revert the named files or directories
1898 to the contents they had in the parent of the working directory.
1904 to the contents they had in the parent of the working directory.
1899 This restores the contents of the affected files to an unmodified
1905 This restores the contents of the affected files to an unmodified
1900 state. If the working directory has two parents, you must
1906 state. If the working directory has two parents, you must
1901 explicitly specify the revision to revert to.
1907 explicitly specify the revision to revert to.
1902
1908
1903 Modified files are saved with a .orig suffix before reverting.
1909 Modified files are saved with a .orig suffix before reverting.
1904 To disable these backups, use --no-backup.
1910 To disable these backups, use --no-backup.
1905
1911
1906 Using the -r option, revert the given files or directories to their
1912 Using the -r option, revert the given files or directories to their
1907 contents as of a specific revision. This can be helpful to "roll
1913 contents as of a specific revision. This can be helpful to "roll
1908 back" some or all of a change that should not have been committed.
1914 back" some or all of a change that should not have been committed.
1909
1915
1910 Revert modifies the working directory. It does not commit any
1916 Revert modifies the working directory. It does not commit any
1911 changes, or change the parent of the working directory. If you
1917 changes, or change the parent of the working directory. If you
1912 revert to a revision other than the parent of the working
1918 revert to a revision other than the parent of the working
1913 directory, the reverted files will thus appear modified
1919 directory, the reverted files will thus appear modified
1914 afterwards.
1920 afterwards.
1915
1921
1916 If a file has been deleted, it is recreated. If the executable
1922 If a file has been deleted, it is recreated. If the executable
1917 mode of a file was changed, it is reset.
1923 mode of a file was changed, it is reset.
1918
1924
1919 If names are given, all files matching the names are reverted.
1925 If names are given, all files matching the names are reverted.
1920
1926
1921 If no arguments are given, no files are reverted.
1927 If no arguments are given, no files are reverted.
1922 """
1928 """
1923
1929
1924 if not pats and not opts['all']:
1930 if not pats and not opts['all']:
1925 raise util.Abort(_('no files or directories specified; '
1931 raise util.Abort(_('no files or directories specified; '
1926 'use --all to revert the whole repo'))
1932 'use --all to revert the whole repo'))
1927
1933
1928 parent, p2 = repo.dirstate.parents()
1934 parent, p2 = repo.dirstate.parents()
1929 if not opts['rev'] and p2 != nullid:
1935 if not opts['rev'] and p2 != nullid:
1930 raise util.Abort(_('uncommitted merge - please provide a '
1936 raise util.Abort(_('uncommitted merge - please provide a '
1931 'specific revision'))
1937 'specific revision'))
1932 node = repo.changectx(opts['rev']).node()
1938 node = repo.changectx(opts['rev']).node()
1933 mf = repo.manifest.read(repo.changelog.read(node)[0])
1939 mf = repo.manifest.read(repo.changelog.read(node)[0])
1934 if node == parent:
1940 if node == parent:
1935 pmf = mf
1941 pmf = mf
1936 else:
1942 else:
1937 pmf = None
1943 pmf = None
1938
1944
1939 wlock = repo.wlock()
1945 wlock = repo.wlock()
1940
1946
1941 # need all matching names in dirstate and manifest of target rev,
1947 # need all matching names in dirstate and manifest of target rev,
1942 # so have to walk both. do not print errors if files exist in one
1948 # so have to walk both. do not print errors if files exist in one
1943 # but not other.
1949 # but not other.
1944
1950
1945 names = {}
1951 names = {}
1946 target_only = {}
1952 target_only = {}
1947
1953
1948 # walk dirstate.
1954 # walk dirstate.
1949
1955
1950 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
1956 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
1951 badmatch=mf.has_key):
1957 badmatch=mf.has_key):
1952 names[abs] = (rel, exact)
1958 names[abs] = (rel, exact)
1953 if src == 'b':
1959 if src == 'b':
1954 target_only[abs] = True
1960 target_only[abs] = True
1955
1961
1956 # walk target manifest.
1962 # walk target manifest.
1957
1963
1958 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1964 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1959 badmatch=names.has_key):
1965 badmatch=names.has_key):
1960 if abs in names: continue
1966 if abs in names: continue
1961 names[abs] = (rel, exact)
1967 names[abs] = (rel, exact)
1962 target_only[abs] = True
1968 target_only[abs] = True
1963
1969
1964 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
1970 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
1965 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
1971 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
1966
1972
1967 revert = ([], _('reverting %s\n'))
1973 revert = ([], _('reverting %s\n'))
1968 add = ([], _('adding %s\n'))
1974 add = ([], _('adding %s\n'))
1969 remove = ([], _('removing %s\n'))
1975 remove = ([], _('removing %s\n'))
1970 forget = ([], _('forgetting %s\n'))
1976 forget = ([], _('forgetting %s\n'))
1971 undelete = ([], _('undeleting %s\n'))
1977 undelete = ([], _('undeleting %s\n'))
1972 update = {}
1978 update = {}
1973
1979
1974 disptable = (
1980 disptable = (
1975 # dispatch table:
1981 # dispatch table:
1976 # file state
1982 # file state
1977 # action if in target manifest
1983 # action if in target manifest
1978 # action if not in target manifest
1984 # action if not in target manifest
1979 # make backup if in target manifest
1985 # make backup if in target manifest
1980 # make backup if not in target manifest
1986 # make backup if not in target manifest
1981 (modified, revert, remove, True, True),
1987 (modified, revert, remove, True, True),
1982 (added, revert, forget, True, False),
1988 (added, revert, forget, True, False),
1983 (removed, undelete, None, False, False),
1989 (removed, undelete, None, False, False),
1984 (deleted, revert, remove, False, False),
1990 (deleted, revert, remove, False, False),
1985 (unknown, add, None, True, False),
1991 (unknown, add, None, True, False),
1986 (target_only, add, None, False, False),
1992 (target_only, add, None, False, False),
1987 )
1993 )
1988
1994
1989 entries = names.items()
1995 entries = names.items()
1990 entries.sort()
1996 entries.sort()
1991
1997
1992 for abs, (rel, exact) in entries:
1998 for abs, (rel, exact) in entries:
1993 mfentry = mf.get(abs)
1999 mfentry = mf.get(abs)
1994 def handle(xlist, dobackup):
2000 def handle(xlist, dobackup):
1995 xlist[0].append(abs)
2001 xlist[0].append(abs)
1996 update[abs] = 1
2002 update[abs] = 1
1997 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2003 if dobackup and not opts['no_backup'] and os.path.exists(rel):
1998 bakname = "%s.orig" % rel
2004 bakname = "%s.orig" % rel
1999 ui.note(_('saving current version of %s as %s\n') %
2005 ui.note(_('saving current version of %s as %s\n') %
2000 (rel, bakname))
2006 (rel, bakname))
2001 if not opts.get('dry_run'):
2007 if not opts.get('dry_run'):
2002 util.copyfile(rel, bakname)
2008 util.copyfile(rel, bakname)
2003 if ui.verbose or not exact:
2009 if ui.verbose or not exact:
2004 ui.status(xlist[1] % rel)
2010 ui.status(xlist[1] % rel)
2005 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2011 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2006 if abs not in table: continue
2012 if abs not in table: continue
2007 # file has changed in dirstate
2013 # file has changed in dirstate
2008 if mfentry:
2014 if mfentry:
2009 handle(hitlist, backuphit)
2015 handle(hitlist, backuphit)
2010 elif misslist is not None:
2016 elif misslist is not None:
2011 handle(misslist, backupmiss)
2017 handle(misslist, backupmiss)
2012 else:
2018 else:
2013 if exact: ui.warn(_('file not managed: %s\n') % rel)
2019 if exact: ui.warn(_('file not managed: %s\n') % rel)
2014 break
2020 break
2015 else:
2021 else:
2016 # file has not changed in dirstate
2022 # file has not changed in dirstate
2017 if node == parent:
2023 if node == parent:
2018 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2024 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2019 continue
2025 continue
2020 if pmf is None:
2026 if pmf is None:
2021 # only need parent manifest in this unlikely case,
2027 # only need parent manifest in this unlikely case,
2022 # so do not read by default
2028 # so do not read by default
2023 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2029 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2024 if abs in pmf:
2030 if abs in pmf:
2025 if mfentry:
2031 if mfentry:
2026 # if version of file is same in parent and target
2032 # if version of file is same in parent and target
2027 # manifests, do nothing
2033 # manifests, do nothing
2028 if pmf[abs] != mfentry:
2034 if pmf[abs] != mfentry:
2029 handle(revert, False)
2035 handle(revert, False)
2030 else:
2036 else:
2031 handle(remove, False)
2037 handle(remove, False)
2032
2038
2033 if not opts.get('dry_run'):
2039 if not opts.get('dry_run'):
2034 repo.dirstate.forget(forget[0])
2040 repo.dirstate.forget(forget[0])
2035 r = hg.revert(repo, node, update.has_key, wlock)
2041 r = hg.revert(repo, node, update.has_key, wlock)
2036 repo.dirstate.update(add[0], 'a')
2042 repo.dirstate.update(add[0], 'a')
2037 repo.dirstate.update(undelete[0], 'n')
2043 repo.dirstate.update(undelete[0], 'n')
2038 repo.dirstate.update(remove[0], 'r')
2044 repo.dirstate.update(remove[0], 'r')
2039 return r
2045 return r
2040
2046
2041 def rollback(ui, repo):
2047 def rollback(ui, repo):
2042 """roll back the last transaction in this repository
2048 """roll back the last transaction in this repository
2043
2049
2044 Roll back the last transaction in this repository, restoring the
2050 Roll back the last transaction in this repository, restoring the
2045 project to its state prior to the transaction.
2051 project to its state prior to the transaction.
2046
2052
2047 Transactions are used to encapsulate the effects of all commands
2053 Transactions are used to encapsulate the effects of all commands
2048 that create new changesets or propagate existing changesets into a
2054 that create new changesets or propagate existing changesets into a
2049 repository. For example, the following commands are transactional,
2055 repository. For example, the following commands are transactional,
2050 and their effects can be rolled back:
2056 and their effects can be rolled back:
2051
2057
2052 commit
2058 commit
2053 import
2059 import
2054 pull
2060 pull
2055 push (with this repository as destination)
2061 push (with this repository as destination)
2056 unbundle
2062 unbundle
2057
2063
2058 This command should be used with care. There is only one level of
2064 This command should be used with care. There is only one level of
2059 rollback, and there is no way to undo a rollback.
2065 rollback, and there is no way to undo a rollback.
2060
2066
2061 This command is not intended for use on public repositories. Once
2067 This command is not intended for use on public repositories. Once
2062 changes are visible for pull by other users, rolling a transaction
2068 changes are visible for pull by other users, rolling a transaction
2063 back locally is ineffective (someone else may already have pulled
2069 back locally is ineffective (someone else may already have pulled
2064 the changes). Furthermore, a race is possible with readers of the
2070 the changes). Furthermore, a race is possible with readers of the
2065 repository; for example an in-progress pull from the repository
2071 repository; for example an in-progress pull from the repository
2066 may fail if a rollback is performed.
2072 may fail if a rollback is performed.
2067 """
2073 """
2068 repo.rollback()
2074 repo.rollback()
2069
2075
2070 def root(ui, repo):
2076 def root(ui, repo):
2071 """print the root (top) of the current working dir
2077 """print the root (top) of the current working dir
2072
2078
2073 Print the root directory of the current repository.
2079 Print the root directory of the current repository.
2074 """
2080 """
2075 ui.write(repo.root + "\n")
2081 ui.write(repo.root + "\n")
2076
2082
2077 def serve(ui, repo, **opts):
2083 def serve(ui, repo, **opts):
2078 """export the repository via HTTP
2084 """export the repository via HTTP
2079
2085
2080 Start a local HTTP repository browser and pull server.
2086 Start a local HTTP repository browser and pull server.
2081
2087
2082 By default, the server logs accesses to stdout and errors to
2088 By default, the server logs accesses to stdout and errors to
2083 stderr. Use the "-A" and "-E" options to log to files.
2089 stderr. Use the "-A" and "-E" options to log to files.
2084 """
2090 """
2085
2091
2086 if opts["stdio"]:
2092 if opts["stdio"]:
2087 if repo is None:
2093 if repo is None:
2088 raise hg.RepoError(_("There is no Mercurial repository here"
2094 raise hg.RepoError(_("There is no Mercurial repository here"
2089 " (.hg not found)"))
2095 " (.hg not found)"))
2090 s = sshserver.sshserver(ui, repo)
2096 s = sshserver.sshserver(ui, repo)
2091 s.serve_forever()
2097 s.serve_forever()
2092
2098
2093 optlist = ("name templates style address port ipv6"
2099 optlist = ("name templates style address port ipv6"
2094 " accesslog errorlog webdir_conf")
2100 " accesslog errorlog webdir_conf")
2095 for o in optlist.split():
2101 for o in optlist.split():
2096 if opts[o]:
2102 if opts[o]:
2097 ui.setconfig("web", o, str(opts[o]))
2103 ui.setconfig("web", o, str(opts[o]))
2098
2104
2099 if repo is None and not ui.config("web", "webdir_conf"):
2105 if repo is None and not ui.config("web", "webdir_conf"):
2100 raise hg.RepoError(_("There is no Mercurial repository here"
2106 raise hg.RepoError(_("There is no Mercurial repository here"
2101 " (.hg not found)"))
2107 " (.hg not found)"))
2102
2108
2103 if opts['daemon'] and not opts['daemon_pipefds']:
2109 if opts['daemon'] and not opts['daemon_pipefds']:
2104 rfd, wfd = os.pipe()
2110 rfd, wfd = os.pipe()
2105 args = sys.argv[:]
2111 args = sys.argv[:]
2106 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2112 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2107 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2113 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2108 args[0], args)
2114 args[0], args)
2109 os.close(wfd)
2115 os.close(wfd)
2110 os.read(rfd, 1)
2116 os.read(rfd, 1)
2111 os._exit(0)
2117 os._exit(0)
2112
2118
2113 httpd = hgweb.server.create_server(ui, repo)
2119 httpd = hgweb.server.create_server(ui, repo)
2114
2120
2115 if ui.verbose:
2121 if ui.verbose:
2116 if httpd.port != 80:
2122 if httpd.port != 80:
2117 ui.status(_('listening at http://%s:%d/\n') %
2123 ui.status(_('listening at http://%s:%d/\n') %
2118 (httpd.addr, httpd.port))
2124 (httpd.addr, httpd.port))
2119 else:
2125 else:
2120 ui.status(_('listening at http://%s/\n') % httpd.addr)
2126 ui.status(_('listening at http://%s/\n') % httpd.addr)
2121
2127
2122 if opts['pid_file']:
2128 if opts['pid_file']:
2123 fp = open(opts['pid_file'], 'w')
2129 fp = open(opts['pid_file'], 'w')
2124 fp.write(str(os.getpid()) + '\n')
2130 fp.write(str(os.getpid()) + '\n')
2125 fp.close()
2131 fp.close()
2126
2132
2127 if opts['daemon_pipefds']:
2133 if opts['daemon_pipefds']:
2128 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2134 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2129 os.close(rfd)
2135 os.close(rfd)
2130 os.write(wfd, 'y')
2136 os.write(wfd, 'y')
2131 os.close(wfd)
2137 os.close(wfd)
2132 sys.stdout.flush()
2138 sys.stdout.flush()
2133 sys.stderr.flush()
2139 sys.stderr.flush()
2134 fd = os.open(util.nulldev, os.O_RDWR)
2140 fd = os.open(util.nulldev, os.O_RDWR)
2135 if fd != 0: os.dup2(fd, 0)
2141 if fd != 0: os.dup2(fd, 0)
2136 if fd != 1: os.dup2(fd, 1)
2142 if fd != 1: os.dup2(fd, 1)
2137 if fd != 2: os.dup2(fd, 2)
2143 if fd != 2: os.dup2(fd, 2)
2138 if fd not in (0, 1, 2): os.close(fd)
2144 if fd not in (0, 1, 2): os.close(fd)
2139
2145
2140 httpd.serve_forever()
2146 httpd.serve_forever()
2141
2147
2142 def status(ui, repo, *pats, **opts):
2148 def status(ui, repo, *pats, **opts):
2143 """show changed files in the working directory
2149 """show changed files in the working directory
2144
2150
2145 Show status of files in the repository. If names are given, only
2151 Show status of files in the repository. If names are given, only
2146 files that match are shown. Files that are clean or ignored, are
2152 files that match are shown. Files that are clean or ignored, are
2147 not listed unless -c (clean), -i (ignored) or -A is given.
2153 not listed unless -c (clean), -i (ignored) or -A is given.
2148
2154
2149 If one revision is given, it is used as the base revision.
2155 If one revision is given, it is used as the base revision.
2150 If two revisions are given, the difference between them is shown.
2156 If two revisions are given, the difference between them is shown.
2151
2157
2152 The codes used to show the status of files are:
2158 The codes used to show the status of files are:
2153 M = modified
2159 M = modified
2154 A = added
2160 A = added
2155 R = removed
2161 R = removed
2156 C = clean
2162 C = clean
2157 ! = deleted, but still tracked
2163 ! = deleted, but still tracked
2158 ? = not tracked
2164 ? = not tracked
2159 I = ignored (not shown by default)
2165 I = ignored (not shown by default)
2160 = the previous added file was copied from here
2166 = the previous added file was copied from here
2161 """
2167 """
2162
2168
2163 all = opts['all']
2169 all = opts['all']
2164 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2170 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2165
2171
2166 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2172 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2167 cwd = (pats and repo.getcwd()) or ''
2173 cwd = (pats and repo.getcwd()) or ''
2168 modified, added, removed, deleted, unknown, ignored, clean = [
2174 modified, added, removed, deleted, unknown, ignored, clean = [
2169 [util.pathto(cwd, x) for x in n]
2175 [util.pathto(cwd, x) for x in n]
2170 for n in repo.status(node1=node1, node2=node2, files=files,
2176 for n in repo.status(node1=node1, node2=node2, files=files,
2171 match=matchfn,
2177 match=matchfn,
2172 list_ignored=all or opts['ignored'],
2178 list_ignored=all or opts['ignored'],
2173 list_clean=all or opts['clean'])]
2179 list_clean=all or opts['clean'])]
2174
2180
2175 changetypes = (('modified', 'M', modified),
2181 changetypes = (('modified', 'M', modified),
2176 ('added', 'A', added),
2182 ('added', 'A', added),
2177 ('removed', 'R', removed),
2183 ('removed', 'R', removed),
2178 ('deleted', '!', deleted),
2184 ('deleted', '!', deleted),
2179 ('unknown', '?', unknown),
2185 ('unknown', '?', unknown),
2180 ('ignored', 'I', ignored))
2186 ('ignored', 'I', ignored))
2181
2187
2182 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2188 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2183
2189
2184 end = opts['print0'] and '\0' or '\n'
2190 end = opts['print0'] and '\0' or '\n'
2185
2191
2186 for opt, char, changes in ([ct for ct in explicit_changetypes
2192 for opt, char, changes in ([ct for ct in explicit_changetypes
2187 if all or opts[ct[0]]]
2193 if all or opts[ct[0]]]
2188 or changetypes):
2194 or changetypes):
2189 if opts['no_status']:
2195 if opts['no_status']:
2190 format = "%%s%s" % end
2196 format = "%%s%s" % end
2191 else:
2197 else:
2192 format = "%s %%s%s" % (char, end)
2198 format = "%s %%s%s" % (char, end)
2193
2199
2194 for f in changes:
2200 for f in changes:
2195 ui.write(format % f)
2201 ui.write(format % f)
2196 if ((all or opts.get('copies')) and not opts.get('no_status')):
2202 if ((all or opts.get('copies')) and not opts.get('no_status')):
2197 copied = repo.dirstate.copied(f)
2203 copied = repo.dirstate.copied(f)
2198 if copied:
2204 if copied:
2199 ui.write(' %s%s' % (copied, end))
2205 ui.write(' %s%s' % (copied, end))
2200
2206
2201 def tag(ui, repo, name, rev_=None, **opts):
2207 def tag(ui, repo, name, rev_=None, **opts):
2202 """add a tag for the current tip or a given revision
2208 """add a tag for the current tip or a given revision
2203
2209
2204 Name a particular revision using <name>.
2210 Name a particular revision using <name>.
2205
2211
2206 Tags are used to name particular revisions of the repository and are
2212 Tags are used to name particular revisions of the repository and are
2207 very useful to compare different revision, to go back to significant
2213 very useful to compare different revision, to go back to significant
2208 earlier versions or to mark branch points as releases, etc.
2214 earlier versions or to mark branch points as releases, etc.
2209
2215
2210 If no revision is given, the parent of the working directory is used.
2216 If no revision is given, the parent of the working directory is used.
2211
2217
2212 To facilitate version control, distribution, and merging of tags,
2218 To facilitate version control, distribution, and merging of tags,
2213 they are stored as a file named ".hgtags" which is managed
2219 they are stored as a file named ".hgtags" which is managed
2214 similarly to other project files and can be hand-edited if
2220 similarly to other project files and can be hand-edited if
2215 necessary. The file '.hg/localtags' is used for local tags (not
2221 necessary. The file '.hg/localtags' is used for local tags (not
2216 shared among repositories).
2222 shared among repositories).
2217 """
2223 """
2218 if name in ['tip', '.', 'null']:
2224 if name in ['tip', '.', 'null']:
2219 raise util.Abort(_("the name '%s' is reserved") % name)
2225 raise util.Abort(_("the name '%s' is reserved") % name)
2220 if rev_ is not None:
2226 if rev_ is not None:
2221 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2227 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2222 "please use 'hg tag [-r REV] NAME' instead\n"))
2228 "please use 'hg tag [-r REV] NAME' instead\n"))
2223 if opts['rev']:
2229 if opts['rev']:
2224 raise util.Abort(_("use only one form to specify the revision"))
2230 raise util.Abort(_("use only one form to specify the revision"))
2225 if opts['rev']:
2231 if opts['rev']:
2226 rev_ = opts['rev']
2232 rev_ = opts['rev']
2227 if not rev_ and repo.dirstate.parents()[1] != nullid:
2233 if not rev_ and repo.dirstate.parents()[1] != nullid:
2228 raise util.Abort(_('uncommitted merge - please provide a '
2234 raise util.Abort(_('uncommitted merge - please provide a '
2229 'specific revision'))
2235 'specific revision'))
2230 r = repo.changectx(rev_).node()
2236 r = repo.changectx(rev_).node()
2231
2237
2232 message = opts['message']
2238 message = opts['message']
2233 if not message:
2239 if not message:
2234 message = _('Added tag %s for changeset %s') % (name, short(r))
2240 message = _('Added tag %s for changeset %s') % (name, short(r))
2235
2241
2236 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2242 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2237
2243
2238 def tags(ui, repo):
2244 def tags(ui, repo):
2239 """list repository tags
2245 """list repository tags
2240
2246
2241 List the repository tags.
2247 List the repository tags.
2242
2248
2243 This lists both regular and local tags.
2249 This lists both regular and local tags.
2244 """
2250 """
2245
2251
2246 l = repo.tagslist()
2252 l = repo.tagslist()
2247 l.reverse()
2253 l.reverse()
2248 hexfunc = ui.debugflag and hex or short
2254 hexfunc = ui.debugflag and hex or short
2249 for t, n in l:
2255 for t, n in l:
2250 try:
2256 try:
2251 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2257 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2252 except KeyError:
2258 except KeyError:
2253 r = " ?:?"
2259 r = " ?:?"
2254 if ui.quiet:
2260 if ui.quiet:
2255 ui.write("%s\n" % t)
2261 ui.write("%s\n" % t)
2256 else:
2262 else:
2257 t = util.localsub(t, 30)
2263 t = util.localsub(t, 30)
2258 t += " " * (30 - util.locallen(t))
2264 t += " " * (30 - util.locallen(t))
2259 ui.write("%s %s\n" % (t, r))
2265 ui.write("%s %s\n" % (t, r))
2260
2266
2261 def tip(ui, repo, **opts):
2267 def tip(ui, repo, **opts):
2262 """show the tip revision
2268 """show the tip revision
2263
2269
2264 Show the tip revision.
2270 Show the tip revision.
2265 """
2271 """
2266 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2272 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2267
2273
2268 def unbundle(ui, repo, fname, **opts):
2274 def unbundle(ui, repo, fname, **opts):
2269 """apply a changegroup file
2275 """apply a changegroup file
2270
2276
2271 Apply a compressed changegroup file generated by the bundle
2277 Apply a compressed changegroup file generated by the bundle
2272 command.
2278 command.
2273 """
2279 """
2274 gen = changegroup.readbundle(urllib.urlopen(fname))
2280 gen = changegroup.readbundle(urllib.urlopen(fname))
2275 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2281 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2276 return postincoming(ui, repo, modheads, opts['update'])
2282 return postincoming(ui, repo, modheads, opts['update'])
2277
2283
2278 def update(ui, repo, node=None, clean=False, branch=None):
2284 def update(ui, repo, node=None, clean=False, branch=None):
2279 """update or merge working directory
2285 """update or merge working directory
2280
2286
2281 Update the working directory to the specified revision.
2287 Update the working directory to the specified revision.
2282
2288
2283 If there are no outstanding changes in the working directory and
2289 If there are no outstanding changes in the working directory and
2284 there is a linear relationship between the current version and the
2290 there is a linear relationship between the current version and the
2285 requested version, the result is the requested version.
2291 requested version, the result is the requested version.
2286
2292
2287 To merge the working directory with another revision, use the
2293 To merge the working directory with another revision, use the
2288 merge command.
2294 merge command.
2289
2295
2290 By default, update will refuse to run if doing so would require
2296 By default, update will refuse to run if doing so would require
2291 merging or discarding local changes.
2297 merging or discarding local changes.
2292 """
2298 """
2293 node = _lookup(repo, node, branch)
2299 node = _lookup(repo, node, branch)
2294 if clean:
2300 if clean:
2295 return hg.clean(repo, node)
2301 return hg.clean(repo, node)
2296 else:
2302 else:
2297 return hg.update(repo, node)
2303 return hg.update(repo, node)
2298
2304
2299 def _lookup(repo, node, branch=None):
2305 def _lookup(repo, node, branch=None):
2300 if branch:
2306 if branch:
2301 repo.ui.warn(_("the --branch option is deprecated, "
2307 repo.ui.warn(_("the --branch option is deprecated, "
2302 "please use 'hg branch' instead\n"))
2308 "please use 'hg branch' instead\n"))
2303 br = repo.branchlookup(branch=branch)
2309 br = repo.branchlookup(branch=branch)
2304 found = []
2310 found = []
2305 for x in br:
2311 for x in br:
2306 if branch in br[x]:
2312 if branch in br[x]:
2307 found.append(x)
2313 found.append(x)
2308 if len(found) > 1:
2314 if len(found) > 1:
2309 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2315 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2310 for x in found:
2316 for x in found:
2311 cmdutil.show_changeset(ui, repo, {}).show(changenode=x)
2317 cmdutil.show_changeset(ui, repo, {}).show(changenode=x)
2312 raise util.Abort("")
2318 raise util.Abort("")
2313 if len(found) == 1:
2319 if len(found) == 1:
2314 node = found[0]
2320 node = found[0]
2315 repo.ui.warn(_("Using head %s for branch %s\n")
2321 repo.ui.warn(_("Using head %s for branch %s\n")
2316 % (short(node), branch))
2322 % (short(node), branch))
2317 else:
2323 else:
2318 raise util.Abort(_("branch %s not found") % branch)
2324 raise util.Abort(_("branch %s not found") % branch)
2319 else:
2325 else:
2320 node = node and repo.lookup(node) or repo.changelog.tip()
2326 node = node and repo.lookup(node) or repo.changelog.tip()
2321 return node
2327 return node
2322
2328
2323 def verify(ui, repo):
2329 def verify(ui, repo):
2324 """verify the integrity of the repository
2330 """verify the integrity of the repository
2325
2331
2326 Verify the integrity of the current repository.
2332 Verify the integrity of the current repository.
2327
2333
2328 This will perform an extensive check of the repository's
2334 This will perform an extensive check of the repository's
2329 integrity, validating the hashes and checksums of each entry in
2335 integrity, validating the hashes and checksums of each entry in
2330 the changelog, manifest, and tracked files, as well as the
2336 the changelog, manifest, and tracked files, as well as the
2331 integrity of their crosslinks and indices.
2337 integrity of their crosslinks and indices.
2332 """
2338 """
2333 return hg.verify(repo)
2339 return hg.verify(repo)
2334
2340
2335 def version_(ui):
2341 def version_(ui):
2336 """output version and copyright information"""
2342 """output version and copyright information"""
2337 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2343 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2338 % version.get_version())
2344 % version.get_version())
2339 ui.status(_(
2345 ui.status(_(
2340 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2346 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2341 "This is free software; see the source for copying conditions. "
2347 "This is free software; see the source for copying conditions. "
2342 "There is NO\nwarranty; "
2348 "There is NO\nwarranty; "
2343 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2349 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2344 ))
2350 ))
2345
2351
2346 # Command options and aliases are listed here, alphabetically
2352 # Command options and aliases are listed here, alphabetically
2347
2353
2348 globalopts = [
2354 globalopts = [
2349 ('R', 'repository', '',
2355 ('R', 'repository', '',
2350 _('repository root directory or symbolic path name')),
2356 _('repository root directory or symbolic path name')),
2351 ('', 'cwd', '', _('change working directory')),
2357 ('', 'cwd', '', _('change working directory')),
2352 ('y', 'noninteractive', None,
2358 ('y', 'noninteractive', None,
2353 _('do not prompt, assume \'yes\' for any required answers')),
2359 _('do not prompt, assume \'yes\' for any required answers')),
2354 ('q', 'quiet', None, _('suppress output')),
2360 ('q', 'quiet', None, _('suppress output')),
2355 ('v', 'verbose', None, _('enable additional output')),
2361 ('v', 'verbose', None, _('enable additional output')),
2356 ('', 'config', [], _('set/override config option')),
2362 ('', 'config', [], _('set/override config option')),
2357 ('', 'debug', None, _('enable debugging output')),
2363 ('', 'debug', None, _('enable debugging output')),
2358 ('', 'debugger', None, _('start debugger')),
2364 ('', 'debugger', None, _('start debugger')),
2359 ('', 'encoding', util._encoding, _('set the charset encoding')),
2365 ('', 'encoding', util._encoding, _('set the charset encoding')),
2360 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2366 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2361 ('', 'lsprof', None, _('print improved command execution profile')),
2367 ('', 'lsprof', None, _('print improved command execution profile')),
2362 ('', 'traceback', None, _('print traceback on exception')),
2368 ('', 'traceback', None, _('print traceback on exception')),
2363 ('', 'time', None, _('time how long the command takes')),
2369 ('', 'time', None, _('time how long the command takes')),
2364 ('', 'profile', None, _('print command execution profile')),
2370 ('', 'profile', None, _('print command execution profile')),
2365 ('', 'version', None, _('output version information and exit')),
2371 ('', 'version', None, _('output version information and exit')),
2366 ('h', 'help', None, _('display help and exit')),
2372 ('h', 'help', None, _('display help and exit')),
2367 ]
2373 ]
2368
2374
2369 dryrunopts = [('n', 'dry-run', None,
2375 dryrunopts = [('n', 'dry-run', None,
2370 _('do not perform actions, just print output'))]
2376 _('do not perform actions, just print output'))]
2371
2377
2372 remoteopts = [
2378 remoteopts = [
2373 ('e', 'ssh', '', _('specify ssh command to use')),
2379 ('e', 'ssh', '', _('specify ssh command to use')),
2374 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2380 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2375 ]
2381 ]
2376
2382
2377 walkopts = [
2383 walkopts = [
2378 ('I', 'include', [], _('include names matching the given patterns')),
2384 ('I', 'include', [], _('include names matching the given patterns')),
2379 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2385 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2380 ]
2386 ]
2381
2387
2382 table = {
2388 table = {
2383 "^add":
2389 "^add":
2384 (add,
2390 (add,
2385 walkopts + dryrunopts,
2391 walkopts + dryrunopts,
2386 _('hg add [OPTION]... [FILE]...')),
2392 _('hg add [OPTION]... [FILE]...')),
2387 "addremove":
2393 "addremove":
2388 (addremove,
2394 (addremove,
2389 [('s', 'similarity', '',
2395 [('s', 'similarity', '',
2390 _('guess renamed files by similarity (0<=s<=100)')),
2396 _('guess renamed files by similarity (0<=s<=100)')),
2391 ] + walkopts + dryrunopts,
2397 ] + walkopts + dryrunopts,
2392 _('hg addremove [OPTION]... [FILE]...')),
2398 _('hg addremove [OPTION]... [FILE]...')),
2393 "^annotate":
2399 "^annotate":
2394 (annotate,
2400 (annotate,
2395 [('r', 'rev', '', _('annotate the specified revision')),
2401 [('r', 'rev', '', _('annotate the specified revision')),
2396 ('f', 'follow', None, _('follow file copies and renames')),
2402 ('f', 'follow', None, _('follow file copies and renames')),
2397 ('a', 'text', None, _('treat all files as text')),
2403 ('a', 'text', None, _('treat all files as text')),
2398 ('u', 'user', None, _('list the author')),
2404 ('u', 'user', None, _('list the author')),
2399 ('d', 'date', None, _('list the date')),
2405 ('d', 'date', None, _('list the date')),
2400 ('n', 'number', None, _('list the revision number (default)')),
2406 ('n', 'number', None, _('list the revision number (default)')),
2401 ('c', 'changeset', None, _('list the changeset')),
2407 ('c', 'changeset', None, _('list the changeset')),
2402 ] + walkopts,
2408 ] + walkopts,
2403 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2409 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2404 "archive":
2410 "archive":
2405 (archive,
2411 (archive,
2406 [('', 'no-decode', None, _('do not pass files through decoders')),
2412 [('', 'no-decode', None, _('do not pass files through decoders')),
2407 ('p', 'prefix', '', _('directory prefix for files in archive')),
2413 ('p', 'prefix', '', _('directory prefix for files in archive')),
2408 ('r', 'rev', '', _('revision to distribute')),
2414 ('r', 'rev', '', _('revision to distribute')),
2409 ('t', 'type', '', _('type of distribution to create')),
2415 ('t', 'type', '', _('type of distribution to create')),
2410 ] + walkopts,
2416 ] + walkopts,
2411 _('hg archive [OPTION]... DEST')),
2417 _('hg archive [OPTION]... DEST')),
2412 "backout":
2418 "backout":
2413 (backout,
2419 (backout,
2414 [('', 'merge', None,
2420 [('', 'merge', None,
2415 _('merge with old dirstate parent after backout')),
2421 _('merge with old dirstate parent after backout')),
2416 ('m', 'message', '', _('use <text> as commit message')),
2422 ('m', 'message', '', _('use <text> as commit message')),
2417 ('l', 'logfile', '', _('read commit message from <file>')),
2423 ('l', 'logfile', '', _('read commit message from <file>')),
2418 ('d', 'date', '', _('record datecode as commit date')),
2424 ('d', 'date', '', _('record datecode as commit date')),
2419 ('', 'parent', '', _('parent to choose when backing out merge')),
2425 ('', 'parent', '', _('parent to choose when backing out merge')),
2420 ('u', 'user', '', _('record user as committer')),
2426 ('u', 'user', '', _('record user as committer')),
2421 ] + walkopts,
2427 ] + walkopts,
2422 _('hg backout [OPTION]... REV')),
2428 _('hg backout [OPTION]... REV')),
2423 "branch": (branch, [], _('hg branch [NAME]')),
2429 "branch": (branch, [], _('hg branch [NAME]')),
2424 "branches": (branches, [], _('hg branches')),
2430 "branches": (branches, [], _('hg branches')),
2425 "bundle":
2431 "bundle":
2426 (bundle,
2432 (bundle,
2427 [('f', 'force', None,
2433 [('f', 'force', None,
2428 _('run even when remote repository is unrelated')),
2434 _('run even when remote repository is unrelated')),
2429 ('r', 'rev', [],
2435 ('r', 'rev', [],
2430 _('a changeset you would like to bundle')),
2436 _('a changeset you would like to bundle')),
2431 ('', 'base', [],
2437 ('', 'base', [],
2432 _('a base changeset to specify instead of a destination')),
2438 _('a base changeset to specify instead of a destination')),
2433 ] + remoteopts,
2439 ] + remoteopts,
2434 _('hg bundle [--base REV]... [--rev REV]... FILE [DEST]')),
2440 _('hg bundle [--base REV]... [--rev REV]... FILE [DEST]')),
2435 "cat":
2441 "cat":
2436 (cat,
2442 (cat,
2437 [('o', 'output', '', _('print output to file with formatted name')),
2443 [('o', 'output', '', _('print output to file with formatted name')),
2438 ('r', 'rev', '', _('print the given revision')),
2444 ('r', 'rev', '', _('print the given revision')),
2439 ] + walkopts,
2445 ] + walkopts,
2440 _('hg cat [OPTION]... FILE...')),
2446 _('hg cat [OPTION]... FILE...')),
2441 "^clone":
2447 "^clone":
2442 (clone,
2448 (clone,
2443 [('U', 'noupdate', None, _('do not update the new working directory')),
2449 [('U', 'noupdate', None, _('do not update the new working directory')),
2444 ('r', 'rev', [],
2450 ('r', 'rev', [],
2445 _('a changeset you would like to have after cloning')),
2451 _('a changeset you would like to have after cloning')),
2446 ('', 'pull', None, _('use pull protocol to copy metadata')),
2452 ('', 'pull', None, _('use pull protocol to copy metadata')),
2447 ('', 'uncompressed', None,
2453 ('', 'uncompressed', None,
2448 _('use uncompressed transfer (fast over LAN)')),
2454 _('use uncompressed transfer (fast over LAN)')),
2449 ] + remoteopts,
2455 ] + remoteopts,
2450 _('hg clone [OPTION]... SOURCE [DEST]')),
2456 _('hg clone [OPTION]... SOURCE [DEST]')),
2451 "^commit|ci":
2457 "^commit|ci":
2452 (commit,
2458 (commit,
2453 [('A', 'addremove', None,
2459 [('A', 'addremove', None,
2454 _('mark new/missing files as added/removed before committing')),
2460 _('mark new/missing files as added/removed before committing')),
2455 ('m', 'message', '', _('use <text> as commit message')),
2461 ('m', 'message', '', _('use <text> as commit message')),
2456 ('l', 'logfile', '', _('read the commit message from <file>')),
2462 ('l', 'logfile', '', _('read the commit message from <file>')),
2457 ('d', 'date', '', _('record datecode as commit date')),
2463 ('d', 'date', '', _('record datecode as commit date')),
2458 ('u', 'user', '', _('record user as commiter')),
2464 ('u', 'user', '', _('record user as commiter')),
2459 ] + walkopts,
2465 ] + walkopts,
2460 _('hg commit [OPTION]... [FILE]...')),
2466 _('hg commit [OPTION]... [FILE]...')),
2461 "copy|cp":
2467 "copy|cp":
2462 (copy,
2468 (copy,
2463 [('A', 'after', None, _('record a copy that has already occurred')),
2469 [('A', 'after', None, _('record a copy that has already occurred')),
2464 ('f', 'force', None,
2470 ('f', 'force', None,
2465 _('forcibly copy over an existing managed file')),
2471 _('forcibly copy over an existing managed file')),
2466 ] + walkopts + dryrunopts,
2472 ] + walkopts + dryrunopts,
2467 _('hg copy [OPTION]... [SOURCE]... DEST')),
2473 _('hg copy [OPTION]... [SOURCE]... DEST')),
2468 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2474 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2469 "debugcomplete":
2475 "debugcomplete":
2470 (debugcomplete,
2476 (debugcomplete,
2471 [('o', 'options', None, _('show the command options'))],
2477 [('o', 'options', None, _('show the command options'))],
2472 _('debugcomplete [-o] CMD')),
2478 _('debugcomplete [-o] CMD')),
2473 "debugrebuildstate":
2479 "debugrebuildstate":
2474 (debugrebuildstate,
2480 (debugrebuildstate,
2475 [('r', 'rev', '', _('revision to rebuild to'))],
2481 [('r', 'rev', '', _('revision to rebuild to'))],
2476 _('debugrebuildstate [-r REV] [REV]')),
2482 _('debugrebuildstate [-r REV] [REV]')),
2477 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2483 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2478 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2484 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2479 "debugstate": (debugstate, [], _('debugstate')),
2485 "debugstate": (debugstate, [], _('debugstate')),
2486 "debugdate": (debugdate, [], _('debugdata DATE')),
2480 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2487 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2481 "debugindex": (debugindex, [], _('debugindex FILE')),
2488 "debugindex": (debugindex, [], _('debugindex FILE')),
2482 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2489 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2483 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2490 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2484 "debugwalk":
2491 "debugwalk":
2485 (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2492 (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2486 "^diff":
2493 "^diff":
2487 (diff,
2494 (diff,
2488 [('r', 'rev', [], _('revision')),
2495 [('r', 'rev', [], _('revision')),
2489 ('a', 'text', None, _('treat all files as text')),
2496 ('a', 'text', None, _('treat all files as text')),
2490 ('p', 'show-function', None,
2497 ('p', 'show-function', None,
2491 _('show which function each change is in')),
2498 _('show which function each change is in')),
2492 ('g', 'git', None, _('use git extended diff format')),
2499 ('g', 'git', None, _('use git extended diff format')),
2493 ('', 'nodates', None, _("don't include dates in diff headers")),
2500 ('', 'nodates', None, _("don't include dates in diff headers")),
2494 ('w', 'ignore-all-space', None,
2501 ('w', 'ignore-all-space', None,
2495 _('ignore white space when comparing lines')),
2502 _('ignore white space when comparing lines')),
2496 ('b', 'ignore-space-change', None,
2503 ('b', 'ignore-space-change', None,
2497 _('ignore changes in the amount of white space')),
2504 _('ignore changes in the amount of white space')),
2498 ('B', 'ignore-blank-lines', None,
2505 ('B', 'ignore-blank-lines', None,
2499 _('ignore changes whose lines are all blank')),
2506 _('ignore changes whose lines are all blank')),
2500 ] + walkopts,
2507 ] + walkopts,
2501 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2508 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2502 "^export":
2509 "^export":
2503 (export,
2510 (export,
2504 [('o', 'output', '', _('print output to file with formatted name')),
2511 [('o', 'output', '', _('print output to file with formatted name')),
2505 ('a', 'text', None, _('treat all files as text')),
2512 ('a', 'text', None, _('treat all files as text')),
2506 ('g', 'git', None, _('use git extended diff format')),
2513 ('g', 'git', None, _('use git extended diff format')),
2507 ('', 'nodates', None, _("don't include dates in diff headers")),
2514 ('', 'nodates', None, _("don't include dates in diff headers")),
2508 ('', 'switch-parent', None, _('diff against the second parent'))],
2515 ('', 'switch-parent', None, _('diff against the second parent'))],
2509 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2516 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2510 "grep":
2517 "grep":
2511 (grep,
2518 (grep,
2512 [('0', 'print0', None, _('end fields with NUL')),
2519 [('0', 'print0', None, _('end fields with NUL')),
2513 ('', 'all', None, _('print all revisions that match')),
2520 ('', 'all', None, _('print all revisions that match')),
2514 ('f', 'follow', None,
2521 ('f', 'follow', None,
2515 _('follow changeset history, or file history across copies and renames')),
2522 _('follow changeset history, or file history across copies and renames')),
2516 ('i', 'ignore-case', None, _('ignore case when matching')),
2523 ('i', 'ignore-case', None, _('ignore case when matching')),
2517 ('l', 'files-with-matches', None,
2524 ('l', 'files-with-matches', None,
2518 _('print only filenames and revs that match')),
2525 _('print only filenames and revs that match')),
2519 ('n', 'line-number', None, _('print matching line numbers')),
2526 ('n', 'line-number', None, _('print matching line numbers')),
2520 ('r', 'rev', [], _('search in given revision range')),
2527 ('r', 'rev', [], _('search in given revision range')),
2521 ('u', 'user', None, _('print user who committed change')),
2528 ('u', 'user', None, _('print user who committed change')),
2522 ] + walkopts,
2529 ] + walkopts,
2523 _('hg grep [OPTION]... PATTERN [FILE]...')),
2530 _('hg grep [OPTION]... PATTERN [FILE]...')),
2524 "heads":
2531 "heads":
2525 (heads,
2532 (heads,
2526 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2533 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2527 ('', 'style', '', _('display using template map file')),
2534 ('', 'style', '', _('display using template map file')),
2528 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2535 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2529 ('', 'template', '', _('display with template'))],
2536 ('', 'template', '', _('display with template'))],
2530 _('hg heads [-r REV]')),
2537 _('hg heads [-r REV]')),
2531 "help": (help_, [], _('hg help [COMMAND]')),
2538 "help": (help_, [], _('hg help [COMMAND]')),
2532 "identify|id": (identify, [], _('hg identify')),
2539 "identify|id": (identify, [], _('hg identify')),
2533 "import|patch":
2540 "import|patch":
2534 (import_,
2541 (import_,
2535 [('p', 'strip', 1,
2542 [('p', 'strip', 1,
2536 _('directory strip option for patch. This has the same\n'
2543 _('directory strip option for patch. This has the same\n'
2537 'meaning as the corresponding patch option')),
2544 'meaning as the corresponding patch option')),
2538 ('m', 'message', '', _('use <text> as commit message')),
2545 ('m', 'message', '', _('use <text> as commit message')),
2539 ('b', 'base', '', _('base path (DEPRECATED)')),
2546 ('b', 'base', '', _('base path (DEPRECATED)')),
2540 ('f', 'force', None,
2547 ('f', 'force', None,
2541 _('skip check for outstanding uncommitted changes'))],
2548 _('skip check for outstanding uncommitted changes'))],
2542 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2549 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2543 "incoming|in": (incoming,
2550 "incoming|in": (incoming,
2544 [('M', 'no-merges', None, _('do not show merges')),
2551 [('M', 'no-merges', None, _('do not show merges')),
2545 ('f', 'force', None,
2552 ('f', 'force', None,
2546 _('run even when remote repository is unrelated')),
2553 _('run even when remote repository is unrelated')),
2547 ('', 'style', '', _('display using template map file')),
2554 ('', 'style', '', _('display using template map file')),
2548 ('n', 'newest-first', None, _('show newest record first')),
2555 ('n', 'newest-first', None, _('show newest record first')),
2549 ('', 'bundle', '', _('file to store the bundles into')),
2556 ('', 'bundle', '', _('file to store the bundles into')),
2550 ('p', 'patch', None, _('show patch')),
2557 ('p', 'patch', None, _('show patch')),
2551 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2558 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2552 ('', 'template', '', _('display with template')),
2559 ('', 'template', '', _('display with template')),
2553 ] + remoteopts,
2560 ] + remoteopts,
2554 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2561 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2555 ' [--bundle FILENAME] [SOURCE]')),
2562 ' [--bundle FILENAME] [SOURCE]')),
2556 "^init":
2563 "^init":
2557 (init, remoteopts, _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2564 (init, remoteopts, _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2558 "locate":
2565 "locate":
2559 (locate,
2566 (locate,
2560 [('r', 'rev', '', _('search the repository as it stood at rev')),
2567 [('r', 'rev', '', _('search the repository as it stood at rev')),
2561 ('0', 'print0', None,
2568 ('0', 'print0', None,
2562 _('end filenames with NUL, for use with xargs')),
2569 _('end filenames with NUL, for use with xargs')),
2563 ('f', 'fullpath', None,
2570 ('f', 'fullpath', None,
2564 _('print complete paths from the filesystem root')),
2571 _('print complete paths from the filesystem root')),
2565 ] + walkopts,
2572 ] + walkopts,
2566 _('hg locate [OPTION]... [PATTERN]...')),
2573 _('hg locate [OPTION]... [PATTERN]...')),
2567 "^log|history":
2574 "^log|history":
2568 (log,
2575 (log,
2569 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2576 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2570 ('f', 'follow', None,
2577 ('f', 'follow', None,
2571 _('follow changeset history, or file history across copies and renames')),
2578 _('follow changeset history, or file history across copies and renames')),
2572 ('', 'follow-first', None,
2579 ('', 'follow-first', None,
2573 _('only follow the first parent of merge changesets')),
2580 _('only follow the first parent of merge changesets')),
2574 ('C', 'copies', None, _('show copied files')),
2581 ('C', 'copies', None, _('show copied files')),
2575 ('k', 'keyword', [], _('search for a keyword')),
2582 ('k', 'keyword', [], _('search for a keyword')),
2576 ('l', 'limit', '', _('limit number of changes displayed')),
2583 ('l', 'limit', '', _('limit number of changes displayed')),
2577 ('r', 'rev', [], _('show the specified revision or range')),
2584 ('r', 'rev', [], _('show the specified revision or range')),
2578 ('', 'removed', None, _('include revs where files were removed')),
2585 ('', 'removed', None, _('include revs where files were removed')),
2579 ('M', 'no-merges', None, _('do not show merges')),
2586 ('M', 'no-merges', None, _('do not show merges')),
2580 ('', 'style', '', _('display using template map file')),
2587 ('', 'style', '', _('display using template map file')),
2581 ('m', 'only-merges', None, _('show only merges')),
2588 ('m', 'only-merges', None, _('show only merges')),
2582 ('p', 'patch', None, _('show patch')),
2589 ('p', 'patch', None, _('show patch')),
2583 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2590 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2584 ('', 'template', '', _('display with template')),
2591 ('', 'template', '', _('display with template')),
2585 ] + walkopts,
2592 ] + walkopts,
2586 _('hg log [OPTION]... [FILE]')),
2593 _('hg log [OPTION]... [FILE]')),
2587 "manifest": (manifest, [], _('hg manifest [REV]')),
2594 "manifest": (manifest, [], _('hg manifest [REV]')),
2588 "merge":
2595 "merge":
2589 (merge,
2596 (merge,
2590 [('b', 'branch', '', _('merge with head of a specific branch (DEPRECATED)')),
2597 [('b', 'branch', '', _('merge with head of a specific branch (DEPRECATED)')),
2591 ('f', 'force', None, _('force a merge with outstanding changes'))],
2598 ('f', 'force', None, _('force a merge with outstanding changes'))],
2592 _('hg merge [-f] [REV]')),
2599 _('hg merge [-f] [REV]')),
2593 "outgoing|out": (outgoing,
2600 "outgoing|out": (outgoing,
2594 [('M', 'no-merges', None, _('do not show merges')),
2601 [('M', 'no-merges', None, _('do not show merges')),
2595 ('f', 'force', None,
2602 ('f', 'force', None,
2596 _('run even when remote repository is unrelated')),
2603 _('run even when remote repository is unrelated')),
2597 ('p', 'patch', None, _('show patch')),
2604 ('p', 'patch', None, _('show patch')),
2598 ('', 'style', '', _('display using template map file')),
2605 ('', 'style', '', _('display using template map file')),
2599 ('r', 'rev', [], _('a specific revision you would like to push')),
2606 ('r', 'rev', [], _('a specific revision you would like to push')),
2600 ('n', 'newest-first', None, _('show newest record first')),
2607 ('n', 'newest-first', None, _('show newest record first')),
2601 ('', 'template', '', _('display with template')),
2608 ('', 'template', '', _('display with template')),
2602 ] + remoteopts,
2609 ] + remoteopts,
2603 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
2610 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
2604 "^parents":
2611 "^parents":
2605 (parents,
2612 (parents,
2606 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2613 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2607 ('r', 'rev', '', _('show parents from the specified rev')),
2614 ('r', 'rev', '', _('show parents from the specified rev')),
2608 ('', 'style', '', _('display using template map file')),
2615 ('', 'style', '', _('display using template map file')),
2609 ('', 'template', '', _('display with template'))],
2616 ('', 'template', '', _('display with template'))],
2610 _('hg parents [-r REV] [FILE]')),
2617 _('hg parents [-r REV] [FILE]')),
2611 "paths": (paths, [], _('hg paths [NAME]')),
2618 "paths": (paths, [], _('hg paths [NAME]')),
2612 "^pull":
2619 "^pull":
2613 (pull,
2620 (pull,
2614 [('u', 'update', None,
2621 [('u', 'update', None,
2615 _('update to new tip if changesets were pulled')),
2622 _('update to new tip if changesets were pulled')),
2616 ('f', 'force', None,
2623 ('f', 'force', None,
2617 _('run even when remote repository is unrelated')),
2624 _('run even when remote repository is unrelated')),
2618 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2625 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2619 ] + remoteopts,
2626 ] + remoteopts,
2620 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
2627 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
2621 "^push":
2628 "^push":
2622 (push,
2629 (push,
2623 [('f', 'force', None, _('force push')),
2630 [('f', 'force', None, _('force push')),
2624 ('r', 'rev', [], _('a specific revision you would like to push')),
2631 ('r', 'rev', [], _('a specific revision you would like to push')),
2625 ] + remoteopts,
2632 ] + remoteopts,
2626 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
2633 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
2627 "debugrawcommit|rawcommit":
2634 "debugrawcommit|rawcommit":
2628 (rawcommit,
2635 (rawcommit,
2629 [('p', 'parent', [], _('parent')),
2636 [('p', 'parent', [], _('parent')),
2630 ('d', 'date', '', _('date code')),
2637 ('d', 'date', '', _('date code')),
2631 ('u', 'user', '', _('user')),
2638 ('u', 'user', '', _('user')),
2632 ('F', 'files', '', _('file list')),
2639 ('F', 'files', '', _('file list')),
2633 ('m', 'message', '', _('commit message')),
2640 ('m', 'message', '', _('commit message')),
2634 ('l', 'logfile', '', _('commit message file'))],
2641 ('l', 'logfile', '', _('commit message file'))],
2635 _('hg debugrawcommit [OPTION]... [FILE]...')),
2642 _('hg debugrawcommit [OPTION]... [FILE]...')),
2636 "recover": (recover, [], _('hg recover')),
2643 "recover": (recover, [], _('hg recover')),
2637 "^remove|rm":
2644 "^remove|rm":
2638 (remove,
2645 (remove,
2639 [('A', 'after', None, _('record remove that has already occurred')),
2646 [('A', 'after', None, _('record remove that has already occurred')),
2640 ('f', 'force', None, _('remove file even if modified')),
2647 ('f', 'force', None, _('remove file even if modified')),
2641 ] + walkopts,
2648 ] + walkopts,
2642 _('hg remove [OPTION]... FILE...')),
2649 _('hg remove [OPTION]... FILE...')),
2643 "rename|mv":
2650 "rename|mv":
2644 (rename,
2651 (rename,
2645 [('A', 'after', None, _('record a rename that has already occurred')),
2652 [('A', 'after', None, _('record a rename that has already occurred')),
2646 ('f', 'force', None,
2653 ('f', 'force', None,
2647 _('forcibly copy over an existing managed file')),
2654 _('forcibly copy over an existing managed file')),
2648 ] + walkopts + dryrunopts,
2655 ] + walkopts + dryrunopts,
2649 _('hg rename [OPTION]... SOURCE... DEST')),
2656 _('hg rename [OPTION]... SOURCE... DEST')),
2650 "^revert":
2657 "^revert":
2651 (revert,
2658 (revert,
2652 [('a', 'all', None, _('revert all changes when no arguments given')),
2659 [('a', 'all', None, _('revert all changes when no arguments given')),
2653 ('r', 'rev', '', _('revision to revert to')),
2660 ('r', 'rev', '', _('revision to revert to')),
2654 ('', 'no-backup', None, _('do not save backup copies of files')),
2661 ('', 'no-backup', None, _('do not save backup copies of files')),
2655 ] + walkopts + dryrunopts,
2662 ] + walkopts + dryrunopts,
2656 _('hg revert [-r REV] [NAME]...')),
2663 _('hg revert [-r REV] [NAME]...')),
2657 "rollback": (rollback, [], _('hg rollback')),
2664 "rollback": (rollback, [], _('hg rollback')),
2658 "root": (root, [], _('hg root')),
2665 "root": (root, [], _('hg root')),
2659 "showconfig|debugconfig":
2666 "showconfig|debugconfig":
2660 (showconfig,
2667 (showconfig,
2661 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2668 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2662 _('showconfig [-u] [NAME]...')),
2669 _('showconfig [-u] [NAME]...')),
2663 "^serve":
2670 "^serve":
2664 (serve,
2671 (serve,
2665 [('A', 'accesslog', '', _('name of access log file to write to')),
2672 [('A', 'accesslog', '', _('name of access log file to write to')),
2666 ('d', 'daemon', None, _('run server in background')),
2673 ('d', 'daemon', None, _('run server in background')),
2667 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2674 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2668 ('E', 'errorlog', '', _('name of error log file to write to')),
2675 ('E', 'errorlog', '', _('name of error log file to write to')),
2669 ('p', 'port', 0, _('port to use (default: 8000)')),
2676 ('p', 'port', 0, _('port to use (default: 8000)')),
2670 ('a', 'address', '', _('address to use')),
2677 ('a', 'address', '', _('address to use')),
2671 ('n', 'name', '',
2678 ('n', 'name', '',
2672 _('name to show in web pages (default: working dir)')),
2679 _('name to show in web pages (default: working dir)')),
2673 ('', 'webdir-conf', '', _('name of the webdir config file'
2680 ('', 'webdir-conf', '', _('name of the webdir config file'
2674 ' (serve more than one repo)')),
2681 ' (serve more than one repo)')),
2675 ('', 'pid-file', '', _('name of file to write process ID to')),
2682 ('', 'pid-file', '', _('name of file to write process ID to')),
2676 ('', 'stdio', None, _('for remote clients')),
2683 ('', 'stdio', None, _('for remote clients')),
2677 ('t', 'templates', '', _('web templates to use')),
2684 ('t', 'templates', '', _('web templates to use')),
2678 ('', 'style', '', _('template style to use')),
2685 ('', 'style', '', _('template style to use')),
2679 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2686 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2680 _('hg serve [OPTION]...')),
2687 _('hg serve [OPTION]...')),
2681 "^status|st":
2688 "^status|st":
2682 (status,
2689 (status,
2683 [('A', 'all', None, _('show status of all files')),
2690 [('A', 'all', None, _('show status of all files')),
2684 ('m', 'modified', None, _('show only modified files')),
2691 ('m', 'modified', None, _('show only modified files')),
2685 ('a', 'added', None, _('show only added files')),
2692 ('a', 'added', None, _('show only added files')),
2686 ('r', 'removed', None, _('show only removed files')),
2693 ('r', 'removed', None, _('show only removed files')),
2687 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2694 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2688 ('c', 'clean', None, _('show only files without changes')),
2695 ('c', 'clean', None, _('show only files without changes')),
2689 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2696 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2690 ('i', 'ignored', None, _('show ignored files')),
2697 ('i', 'ignored', None, _('show ignored files')),
2691 ('n', 'no-status', None, _('hide status prefix')),
2698 ('n', 'no-status', None, _('hide status prefix')),
2692 ('C', 'copies', None, _('show source of copied files')),
2699 ('C', 'copies', None, _('show source of copied files')),
2693 ('0', 'print0', None,
2700 ('0', 'print0', None,
2694 _('end filenames with NUL, for use with xargs')),
2701 _('end filenames with NUL, for use with xargs')),
2695 ('', 'rev', [], _('show difference from revision')),
2702 ('', 'rev', [], _('show difference from revision')),
2696 ] + walkopts,
2703 ] + walkopts,
2697 _('hg status [OPTION]... [FILE]...')),
2704 _('hg status [OPTION]... [FILE]...')),
2698 "tag":
2705 "tag":
2699 (tag,
2706 (tag,
2700 [('l', 'local', None, _('make the tag local')),
2707 [('l', 'local', None, _('make the tag local')),
2701 ('m', 'message', '', _('message for tag commit log entry')),
2708 ('m', 'message', '', _('message for tag commit log entry')),
2702 ('d', 'date', '', _('record datecode as commit date')),
2709 ('d', 'date', '', _('record datecode as commit date')),
2703 ('u', 'user', '', _('record user as commiter')),
2710 ('u', 'user', '', _('record user as commiter')),
2704 ('r', 'rev', '', _('revision to tag'))],
2711 ('r', 'rev', '', _('revision to tag'))],
2705 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2712 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2706 "tags": (tags, [], _('hg tags')),
2713 "tags": (tags, [], _('hg tags')),
2707 "tip":
2714 "tip":
2708 (tip,
2715 (tip,
2709 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2716 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2710 ('', 'style', '', _('display using template map file')),
2717 ('', 'style', '', _('display using template map file')),
2711 ('p', 'patch', None, _('show patch')),
2718 ('p', 'patch', None, _('show patch')),
2712 ('', 'template', '', _('display with template'))],
2719 ('', 'template', '', _('display with template'))],
2713 _('hg tip [-p]')),
2720 _('hg tip [-p]')),
2714 "unbundle":
2721 "unbundle":
2715 (unbundle,
2722 (unbundle,
2716 [('u', 'update', None,
2723 [('u', 'update', None,
2717 _('update to new tip if changesets were unbundled'))],
2724 _('update to new tip if changesets were unbundled'))],
2718 _('hg unbundle [-u] FILE')),
2725 _('hg unbundle [-u] FILE')),
2719 "^update|up|checkout|co":
2726 "^update|up|checkout|co":
2720 (update,
2727 (update,
2721 [('b', 'branch', '',
2728 [('b', 'branch', '',
2722 _('checkout the head of a specific branch (DEPRECATED)')),
2729 _('checkout the head of a specific branch (DEPRECATED)')),
2723 ('C', 'clean', None, _('overwrite locally modified files'))],
2730 ('C', 'clean', None, _('overwrite locally modified files'))],
2724 _('hg update [-C] [REV]')),
2731 _('hg update [-C] [REV]')),
2725 "verify": (verify, [], _('hg verify')),
2732 "verify": (verify, [], _('hg verify')),
2726 "version": (version_, [], _('hg version')),
2733 "version": (version_, [], _('hg version')),
2727 }
2734 }
2728
2735
2729 norepo = ("clone init version help debugancestor debugcomplete debugdata"
2736 norepo = ("clone init version help debugancestor debugcomplete debugdata"
2730 " debugindex debugindexdot")
2737 " debugindex debugindexdot debugdate")
2731 optionalrepo = ("paths serve showconfig")
2738 optionalrepo = ("paths serve showconfig")
2732
2739
2733 def findpossible(ui, cmd):
2740 def findpossible(ui, cmd):
2734 """
2741 """
2735 Return cmd -> (aliases, command table entry)
2742 Return cmd -> (aliases, command table entry)
2736 for each matching command.
2743 for each matching command.
2737 Return debug commands (or their aliases) only if no normal command matches.
2744 Return debug commands (or their aliases) only if no normal command matches.
2738 """
2745 """
2739 choice = {}
2746 choice = {}
2740 debugchoice = {}
2747 debugchoice = {}
2741 for e in table.keys():
2748 for e in table.keys():
2742 aliases = e.lstrip("^").split("|")
2749 aliases = e.lstrip("^").split("|")
2743 found = None
2750 found = None
2744 if cmd in aliases:
2751 if cmd in aliases:
2745 found = cmd
2752 found = cmd
2746 elif not ui.config("ui", "strict"):
2753 elif not ui.config("ui", "strict"):
2747 for a in aliases:
2754 for a in aliases:
2748 if a.startswith(cmd):
2755 if a.startswith(cmd):
2749 found = a
2756 found = a
2750 break
2757 break
2751 if found is not None:
2758 if found is not None:
2752 if aliases[0].startswith("debug") or found.startswith("debug"):
2759 if aliases[0].startswith("debug") or found.startswith("debug"):
2753 debugchoice[found] = (aliases, table[e])
2760 debugchoice[found] = (aliases, table[e])
2754 else:
2761 else:
2755 choice[found] = (aliases, table[e])
2762 choice[found] = (aliases, table[e])
2756
2763
2757 if not choice and debugchoice:
2764 if not choice and debugchoice:
2758 choice = debugchoice
2765 choice = debugchoice
2759
2766
2760 return choice
2767 return choice
2761
2768
2762 def findcmd(ui, cmd):
2769 def findcmd(ui, cmd):
2763 """Return (aliases, command table entry) for command string."""
2770 """Return (aliases, command table entry) for command string."""
2764 choice = findpossible(ui, cmd)
2771 choice = findpossible(ui, cmd)
2765
2772
2766 if choice.has_key(cmd):
2773 if choice.has_key(cmd):
2767 return choice[cmd]
2774 return choice[cmd]
2768
2775
2769 if len(choice) > 1:
2776 if len(choice) > 1:
2770 clist = choice.keys()
2777 clist = choice.keys()
2771 clist.sort()
2778 clist.sort()
2772 raise AmbiguousCommand(cmd, clist)
2779 raise AmbiguousCommand(cmd, clist)
2773
2780
2774 if choice:
2781 if choice:
2775 return choice.values()[0]
2782 return choice.values()[0]
2776
2783
2777 raise UnknownCommand(cmd)
2784 raise UnknownCommand(cmd)
2778
2785
2779 def catchterm(*args):
2786 def catchterm(*args):
2780 raise util.SignalInterrupt
2787 raise util.SignalInterrupt
2781
2788
2782 def run():
2789 def run():
2783 sys.exit(dispatch(sys.argv[1:]))
2790 sys.exit(dispatch(sys.argv[1:]))
2784
2791
2785 class ParseError(Exception):
2792 class ParseError(Exception):
2786 """Exception raised on errors in parsing the command line."""
2793 """Exception raised on errors in parsing the command line."""
2787
2794
2788 def parse(ui, args):
2795 def parse(ui, args):
2789 options = {}
2796 options = {}
2790 cmdoptions = {}
2797 cmdoptions = {}
2791
2798
2792 try:
2799 try:
2793 args = fancyopts.fancyopts(args, globalopts, options)
2800 args = fancyopts.fancyopts(args, globalopts, options)
2794 except fancyopts.getopt.GetoptError, inst:
2801 except fancyopts.getopt.GetoptError, inst:
2795 raise ParseError(None, inst)
2802 raise ParseError(None, inst)
2796
2803
2797 if args:
2804 if args:
2798 cmd, args = args[0], args[1:]
2805 cmd, args = args[0], args[1:]
2799 aliases, i = findcmd(ui, cmd)
2806 aliases, i = findcmd(ui, cmd)
2800 cmd = aliases[0]
2807 cmd = aliases[0]
2801 defaults = ui.config("defaults", cmd)
2808 defaults = ui.config("defaults", cmd)
2802 if defaults:
2809 if defaults:
2803 args = shlex.split(defaults) + args
2810 args = shlex.split(defaults) + args
2804 c = list(i[1])
2811 c = list(i[1])
2805 else:
2812 else:
2806 cmd = None
2813 cmd = None
2807 c = []
2814 c = []
2808
2815
2809 # combine global options into local
2816 # combine global options into local
2810 for o in globalopts:
2817 for o in globalopts:
2811 c.append((o[0], o[1], options[o[1]], o[3]))
2818 c.append((o[0], o[1], options[o[1]], o[3]))
2812
2819
2813 try:
2820 try:
2814 args = fancyopts.fancyopts(args, c, cmdoptions)
2821 args = fancyopts.fancyopts(args, c, cmdoptions)
2815 except fancyopts.getopt.GetoptError, inst:
2822 except fancyopts.getopt.GetoptError, inst:
2816 raise ParseError(cmd, inst)
2823 raise ParseError(cmd, inst)
2817
2824
2818 # separate global options back out
2825 # separate global options back out
2819 for o in globalopts:
2826 for o in globalopts:
2820 n = o[1]
2827 n = o[1]
2821 options[n] = cmdoptions[n]
2828 options[n] = cmdoptions[n]
2822 del cmdoptions[n]
2829 del cmdoptions[n]
2823
2830
2824 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2831 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2825
2832
2826 external = {}
2833 external = {}
2827
2834
2828 def findext(name):
2835 def findext(name):
2829 '''return module with given extension name'''
2836 '''return module with given extension name'''
2830 try:
2837 try:
2831 return sys.modules[external[name]]
2838 return sys.modules[external[name]]
2832 except KeyError:
2839 except KeyError:
2833 for k, v in external.iteritems():
2840 for k, v in external.iteritems():
2834 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
2841 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
2835 return sys.modules[v]
2842 return sys.modules[v]
2836 raise KeyError(name)
2843 raise KeyError(name)
2837
2844
2838 def load_extensions(ui):
2845 def load_extensions(ui):
2839 added = []
2846 added = []
2840 for ext_name, load_from_name in ui.extensions():
2847 for ext_name, load_from_name in ui.extensions():
2841 if ext_name in external:
2848 if ext_name in external:
2842 continue
2849 continue
2843 try:
2850 try:
2844 if load_from_name:
2851 if load_from_name:
2845 # the module will be loaded in sys.modules
2852 # the module will be loaded in sys.modules
2846 # choose an unique name so that it doesn't
2853 # choose an unique name so that it doesn't
2847 # conflicts with other modules
2854 # conflicts with other modules
2848 module_name = "hgext_%s" % ext_name.replace('.', '_')
2855 module_name = "hgext_%s" % ext_name.replace('.', '_')
2849 mod = imp.load_source(module_name, load_from_name)
2856 mod = imp.load_source(module_name, load_from_name)
2850 else:
2857 else:
2851 def importh(name):
2858 def importh(name):
2852 mod = __import__(name)
2859 mod = __import__(name)
2853 components = name.split('.')
2860 components = name.split('.')
2854 for comp in components[1:]:
2861 for comp in components[1:]:
2855 mod = getattr(mod, comp)
2862 mod = getattr(mod, comp)
2856 return mod
2863 return mod
2857 try:
2864 try:
2858 mod = importh("hgext.%s" % ext_name)
2865 mod = importh("hgext.%s" % ext_name)
2859 except ImportError:
2866 except ImportError:
2860 mod = importh(ext_name)
2867 mod = importh(ext_name)
2861 external[ext_name] = mod.__name__
2868 external[ext_name] = mod.__name__
2862 added.append((mod, ext_name))
2869 added.append((mod, ext_name))
2863 except (util.SignalInterrupt, KeyboardInterrupt):
2870 except (util.SignalInterrupt, KeyboardInterrupt):
2864 raise
2871 raise
2865 except Exception, inst:
2872 except Exception, inst:
2866 ui.warn(_("*** failed to import extension %s: %s\n") %
2873 ui.warn(_("*** failed to import extension %s: %s\n") %
2867 (ext_name, inst))
2874 (ext_name, inst))
2868 if ui.print_exc():
2875 if ui.print_exc():
2869 return 1
2876 return 1
2870
2877
2871 for mod, name in added:
2878 for mod, name in added:
2872 uisetup = getattr(mod, 'uisetup', None)
2879 uisetup = getattr(mod, 'uisetup', None)
2873 if uisetup:
2880 if uisetup:
2874 uisetup(ui)
2881 uisetup(ui)
2875 cmdtable = getattr(mod, 'cmdtable', {})
2882 cmdtable = getattr(mod, 'cmdtable', {})
2876 for t in cmdtable:
2883 for t in cmdtable:
2877 if t in table:
2884 if t in table:
2878 ui.warn(_("module %s overrides %s\n") % (name, t))
2885 ui.warn(_("module %s overrides %s\n") % (name, t))
2879 table.update(cmdtable)
2886 table.update(cmdtable)
2880
2887
2881 def parseconfig(config):
2888 def parseconfig(config):
2882 """parse the --config options from the command line"""
2889 """parse the --config options from the command line"""
2883 parsed = []
2890 parsed = []
2884 for cfg in config:
2891 for cfg in config:
2885 try:
2892 try:
2886 name, value = cfg.split('=', 1)
2893 name, value = cfg.split('=', 1)
2887 section, name = name.split('.', 1)
2894 section, name = name.split('.', 1)
2888 if not section or not name:
2895 if not section or not name:
2889 raise IndexError
2896 raise IndexError
2890 parsed.append((section, name, value))
2897 parsed.append((section, name, value))
2891 except (IndexError, ValueError):
2898 except (IndexError, ValueError):
2892 raise util.Abort(_('malformed --config option: %s') % cfg)
2899 raise util.Abort(_('malformed --config option: %s') % cfg)
2893 return parsed
2900 return parsed
2894
2901
2895 def dispatch(args):
2902 def dispatch(args):
2896 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
2903 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
2897 num = getattr(signal, name, None)
2904 num = getattr(signal, name, None)
2898 if num: signal.signal(num, catchterm)
2905 if num: signal.signal(num, catchterm)
2899
2906
2900 try:
2907 try:
2901 u = ui.ui(traceback='--traceback' in sys.argv[1:])
2908 u = ui.ui(traceback='--traceback' in sys.argv[1:])
2902 except util.Abort, inst:
2909 except util.Abort, inst:
2903 sys.stderr.write(_("abort: %s\n") % inst)
2910 sys.stderr.write(_("abort: %s\n") % inst)
2904 return -1
2911 return -1
2905
2912
2906 load_extensions(u)
2913 load_extensions(u)
2907 u.addreadhook(load_extensions)
2914 u.addreadhook(load_extensions)
2908
2915
2909 try:
2916 try:
2910 cmd, func, args, options, cmdoptions = parse(u, args)
2917 cmd, func, args, options, cmdoptions = parse(u, args)
2911 if options["encoding"]:
2918 if options["encoding"]:
2912 util._encoding = options["encoding"]
2919 util._encoding = options["encoding"]
2913 if options["encodingmode"]:
2920 if options["encodingmode"]:
2914 util._encodingmode = options["encodingmode"]
2921 util._encodingmode = options["encodingmode"]
2915 if options["time"]:
2922 if options["time"]:
2916 def get_times():
2923 def get_times():
2917 t = os.times()
2924 t = os.times()
2918 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2925 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2919 t = (t[0], t[1], t[2], t[3], time.clock())
2926 t = (t[0], t[1], t[2], t[3], time.clock())
2920 return t
2927 return t
2921 s = get_times()
2928 s = get_times()
2922 def print_time():
2929 def print_time():
2923 t = get_times()
2930 t = get_times()
2924 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2931 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2925 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2932 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2926 atexit.register(print_time)
2933 atexit.register(print_time)
2927
2934
2928 # enter the debugger before command execution
2935 # enter the debugger before command execution
2929 if options['debugger']:
2936 if options['debugger']:
2930 pdb.set_trace()
2937 pdb.set_trace()
2931
2938
2932 try:
2939 try:
2933 if options['cwd']:
2940 if options['cwd']:
2934 try:
2941 try:
2935 os.chdir(options['cwd'])
2942 os.chdir(options['cwd'])
2936 except OSError, inst:
2943 except OSError, inst:
2937 raise util.Abort('%s: %s' %
2944 raise util.Abort('%s: %s' %
2938 (options['cwd'], inst.strerror))
2945 (options['cwd'], inst.strerror))
2939
2946
2940 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2947 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2941 not options["noninteractive"], options["traceback"],
2948 not options["noninteractive"], options["traceback"],
2942 parseconfig(options["config"]))
2949 parseconfig(options["config"]))
2943
2950
2944 path = u.expandpath(options["repository"]) or ""
2951 path = u.expandpath(options["repository"]) or ""
2945 repo = path and hg.repository(u, path=path) or None
2952 repo = path and hg.repository(u, path=path) or None
2946 if repo and not repo.local():
2953 if repo and not repo.local():
2947 raise util.Abort(_("repository '%s' is not local") % path)
2954 raise util.Abort(_("repository '%s' is not local") % path)
2948
2955
2949 if options['help']:
2956 if options['help']:
2950 return help_(u, cmd, options['version'])
2957 return help_(u, cmd, options['version'])
2951 elif options['version']:
2958 elif options['version']:
2952 return version_(u)
2959 return version_(u)
2953 elif not cmd:
2960 elif not cmd:
2954 return help_(u, 'shortlist')
2961 return help_(u, 'shortlist')
2955
2962
2956 if cmd not in norepo.split():
2963 if cmd not in norepo.split():
2957 try:
2964 try:
2958 if not repo:
2965 if not repo:
2959 repo = hg.repository(u, path=path)
2966 repo = hg.repository(u, path=path)
2960 u = repo.ui
2967 u = repo.ui
2961 for name in external.itervalues():
2968 for name in external.itervalues():
2962 mod = sys.modules[name]
2969 mod = sys.modules[name]
2963 if hasattr(mod, 'reposetup'):
2970 if hasattr(mod, 'reposetup'):
2964 mod.reposetup(u, repo)
2971 mod.reposetup(u, repo)
2965 hg.repo_setup_hooks.append(mod.reposetup)
2972 hg.repo_setup_hooks.append(mod.reposetup)
2966 except hg.RepoError:
2973 except hg.RepoError:
2967 if cmd not in optionalrepo.split():
2974 if cmd not in optionalrepo.split():
2968 raise
2975 raise
2969 d = lambda: func(u, repo, *args, **cmdoptions)
2976 d = lambda: func(u, repo, *args, **cmdoptions)
2970 else:
2977 else:
2971 d = lambda: func(u, *args, **cmdoptions)
2978 d = lambda: func(u, *args, **cmdoptions)
2972
2979
2973 try:
2980 try:
2974 if options['profile']:
2981 if options['profile']:
2975 import hotshot, hotshot.stats
2982 import hotshot, hotshot.stats
2976 prof = hotshot.Profile("hg.prof")
2983 prof = hotshot.Profile("hg.prof")
2977 try:
2984 try:
2978 try:
2985 try:
2979 return prof.runcall(d)
2986 return prof.runcall(d)
2980 except:
2987 except:
2981 try:
2988 try:
2982 u.warn(_('exception raised - generating '
2989 u.warn(_('exception raised - generating '
2983 'profile anyway\n'))
2990 'profile anyway\n'))
2984 except:
2991 except:
2985 pass
2992 pass
2986 raise
2993 raise
2987 finally:
2994 finally:
2988 prof.close()
2995 prof.close()
2989 stats = hotshot.stats.load("hg.prof")
2996 stats = hotshot.stats.load("hg.prof")
2990 stats.strip_dirs()
2997 stats.strip_dirs()
2991 stats.sort_stats('time', 'calls')
2998 stats.sort_stats('time', 'calls')
2992 stats.print_stats(40)
2999 stats.print_stats(40)
2993 elif options['lsprof']:
3000 elif options['lsprof']:
2994 try:
3001 try:
2995 from mercurial import lsprof
3002 from mercurial import lsprof
2996 except ImportError:
3003 except ImportError:
2997 raise util.Abort(_(
3004 raise util.Abort(_(
2998 'lsprof not available - install from '
3005 'lsprof not available - install from '
2999 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3006 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3000 p = lsprof.Profiler()
3007 p = lsprof.Profiler()
3001 p.enable(subcalls=True)
3008 p.enable(subcalls=True)
3002 try:
3009 try:
3003 return d()
3010 return d()
3004 finally:
3011 finally:
3005 p.disable()
3012 p.disable()
3006 stats = lsprof.Stats(p.getstats())
3013 stats = lsprof.Stats(p.getstats())
3007 stats.sort()
3014 stats.sort()
3008 stats.pprint(top=10, file=sys.stderr, climit=5)
3015 stats.pprint(top=10, file=sys.stderr, climit=5)
3009 else:
3016 else:
3010 return d()
3017 return d()
3011 finally:
3018 finally:
3012 u.flush()
3019 u.flush()
3013 except:
3020 except:
3014 # enter the debugger when we hit an exception
3021 # enter the debugger when we hit an exception
3015 if options['debugger']:
3022 if options['debugger']:
3016 pdb.post_mortem(sys.exc_info()[2])
3023 pdb.post_mortem(sys.exc_info()[2])
3017 u.print_exc()
3024 u.print_exc()
3018 raise
3025 raise
3019 except ParseError, inst:
3026 except ParseError, inst:
3020 if inst.args[0]:
3027 if inst.args[0]:
3021 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3028 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3022 help_(u, inst.args[0])
3029 help_(u, inst.args[0])
3023 else:
3030 else:
3024 u.warn(_("hg: %s\n") % inst.args[1])
3031 u.warn(_("hg: %s\n") % inst.args[1])
3025 help_(u, 'shortlist')
3032 help_(u, 'shortlist')
3026 except AmbiguousCommand, inst:
3033 except AmbiguousCommand, inst:
3027 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3034 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3028 (inst.args[0], " ".join(inst.args[1])))
3035 (inst.args[0], " ".join(inst.args[1])))
3029 except UnknownCommand, inst:
3036 except UnknownCommand, inst:
3030 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3037 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3031 help_(u, 'shortlist')
3038 help_(u, 'shortlist')
3032 except hg.RepoError, inst:
3039 except hg.RepoError, inst:
3033 u.warn(_("abort: %s!\n") % inst)
3040 u.warn(_("abort: %s!\n") % inst)
3034 except lock.LockHeld, inst:
3041 except lock.LockHeld, inst:
3035 if inst.errno == errno.ETIMEDOUT:
3042 if inst.errno == errno.ETIMEDOUT:
3036 reason = _('timed out waiting for lock held by %s') % inst.locker
3043 reason = _('timed out waiting for lock held by %s') % inst.locker
3037 else:
3044 else:
3038 reason = _('lock held by %s') % inst.locker
3045 reason = _('lock held by %s') % inst.locker
3039 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3046 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3040 except lock.LockUnavailable, inst:
3047 except lock.LockUnavailable, inst:
3041 u.warn(_("abort: could not lock %s: %s\n") %
3048 u.warn(_("abort: could not lock %s: %s\n") %
3042 (inst.desc or inst.filename, inst.strerror))
3049 (inst.desc or inst.filename, inst.strerror))
3043 except revlog.RevlogError, inst:
3050 except revlog.RevlogError, inst:
3044 u.warn(_("abort: %s!\n") % inst)
3051 u.warn(_("abort: %s!\n") % inst)
3045 except util.SignalInterrupt:
3052 except util.SignalInterrupt:
3046 u.warn(_("killed!\n"))
3053 u.warn(_("killed!\n"))
3047 except KeyboardInterrupt:
3054 except KeyboardInterrupt:
3048 try:
3055 try:
3049 u.warn(_("interrupted!\n"))
3056 u.warn(_("interrupted!\n"))
3050 except IOError, inst:
3057 except IOError, inst:
3051 if inst.errno == errno.EPIPE:
3058 if inst.errno == errno.EPIPE:
3052 if u.debugflag:
3059 if u.debugflag:
3053 u.warn(_("\nbroken pipe\n"))
3060 u.warn(_("\nbroken pipe\n"))
3054 else:
3061 else:
3055 raise
3062 raise
3056 except IOError, inst:
3063 except IOError, inst:
3057 if hasattr(inst, "code"):
3064 if hasattr(inst, "code"):
3058 u.warn(_("abort: %s\n") % inst)
3065 u.warn(_("abort: %s\n") % inst)
3059 elif hasattr(inst, "reason"):
3066 elif hasattr(inst, "reason"):
3060 u.warn(_("abort: error: %s\n") % inst.reason[1])
3067 u.warn(_("abort: error: %s\n") % inst.reason[1])
3061 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3068 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3062 if u.debugflag:
3069 if u.debugflag:
3063 u.warn(_("broken pipe\n"))
3070 u.warn(_("broken pipe\n"))
3064 elif getattr(inst, "strerror", None):
3071 elif getattr(inst, "strerror", None):
3065 if getattr(inst, "filename", None):
3072 if getattr(inst, "filename", None):
3066 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3073 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3067 else:
3074 else:
3068 u.warn(_("abort: %s\n") % inst.strerror)
3075 u.warn(_("abort: %s\n") % inst.strerror)
3069 else:
3076 else:
3070 raise
3077 raise
3071 except OSError, inst:
3078 except OSError, inst:
3072 if getattr(inst, "filename", None):
3079 if getattr(inst, "filename", None):
3073 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3080 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3074 else:
3081 else:
3075 u.warn(_("abort: %s\n") % inst.strerror)
3082 u.warn(_("abort: %s\n") % inst.strerror)
3076 except util.UnexpectedOutput, inst:
3083 except util.UnexpectedOutput, inst:
3077 u.warn(_("abort: %s") % inst[0])
3084 u.warn(_("abort: %s") % inst[0])
3078 if not isinstance(inst[1], basestring):
3085 if not isinstance(inst[1], basestring):
3079 u.warn(" %r\n" % (inst[1],))
3086 u.warn(" %r\n" % (inst[1],))
3080 elif not inst[1]:
3087 elif not inst[1]:
3081 u.warn(_(" empty string\n"))
3088 u.warn(_(" empty string\n"))
3082 else:
3089 else:
3083 u.warn("\n%r\n" % util.ellipsis(inst[1]))
3090 u.warn("\n%r\n" % util.ellipsis(inst[1]))
3084 except util.Abort, inst:
3091 except util.Abort, inst:
3085 u.warn(_("abort: %s\n") % inst)
3092 u.warn(_("abort: %s\n") % inst)
3086 except TypeError, inst:
3093 except TypeError, inst:
3087 # was this an argument error?
3094 # was this an argument error?
3088 tb = traceback.extract_tb(sys.exc_info()[2])
3095 tb = traceback.extract_tb(sys.exc_info()[2])
3089 if len(tb) > 2: # no
3096 if len(tb) > 2: # no
3090 raise
3097 raise
3091 u.debug(inst, "\n")
3098 u.debug(inst, "\n")
3092 u.warn(_("%s: invalid arguments\n") % cmd)
3099 u.warn(_("%s: invalid arguments\n") % cmd)
3093 help_(u, cmd)
3100 help_(u, cmd)
3094 except SystemExit, inst:
3101 except SystemExit, inst:
3095 # Commands shouldn't sys.exit directly, but give a return code.
3102 # Commands shouldn't sys.exit directly, but give a return code.
3096 # Just in case catch this and and pass exit code to caller.
3103 # Just in case catch this and and pass exit code to caller.
3097 return inst.code
3104 return inst.code
3098 except:
3105 except:
3099 u.warn(_("** unknown exception encountered, details follow\n"))
3106 u.warn(_("** unknown exception encountered, details follow\n"))
3100 u.warn(_("** report bug details to "
3107 u.warn(_("** report bug details to "
3101 "http://www.selenic.com/mercurial/bts\n"))
3108 "http://www.selenic.com/mercurial/bts\n"))
3102 u.warn(_("** or mercurial@selenic.com\n"))
3109 u.warn(_("** or mercurial@selenic.com\n"))
3103 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3110 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3104 % version.get_version())
3111 % version.get_version())
3105 raise
3112 raise
3106
3113
3107 return -1
3114 return -1
@@ -1,153 +1,147 b''
1 # help.py - help data for mercurial
1 # help.py - help data for mercurial
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 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 helptable = {
8 helptable = {
9 "dates|Date Formats":
9 "dates|Date Formats":
10 r'''
10 r'''
11 Some commands (backout, commit, tag) allow the user to specify a date.
11 Some commands (backout, commit, tag) allow the user to specify a date.
12 Possible formats for dates are:
12 Many date formats are acceptible. Here are some examples:
13
14 YYYY-mm-dd \HH:MM[:SS] [(+|-)NNNN]::
15 This is a subset of ISO 8601, allowing just the recommended notations
16 for date and time. The last part represents the timezone; if omitted,
17 local time is assumed. Examples:
18
19 "2005-08-22 03:27 -0700"
20
21 "2006-04-19 21:39:51"
22
13
23 aaa bbb dd HH:MM:SS YYYY [(+|-)NNNN]::
14 "Wed Dec 6 13:18:29 2006" (local timezone assumed)
24 This is the date format used by the C library. Here, aaa stands for
15 "Dec 6 13:18 -0600" (year assumed, time offset provided)
25 abbreviated weekday name and bbb for abbreviated month name. The last
16 "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
26 part represents the timezone; if omitted, local time is assumed.
17 "Dec 6" (midnight)
27 Examples:
18 "13:18" (today assumed)
19 "3:39" (3:39AM assumed)
20 "3:39pm" (15:39)
21 "2006-12-6 13:18:29" (ISO 8601 format)
22 "2006-12-6 13:18"
23 "2006-12-6"
24 "12-6"
25 "12/6"
26 "12/6/6" (Dec 6 2006)
27 "" (Jan 1 00:00:00 1970 UTC)
28
28
29 "Mon Aug 22 03:27:00 2005 -0700"
29 Lastly, there is Mercurial's internal format:
30
30
31 "Wed Apr 19 21:39:51 2006"
31 "1165432709 0" (Wed Dec 6 13:18:29 2006 UTC)
32
32
33 unixtime offset::
34 This is the internal representation format for dates. unixtime is
33 This is the internal representation format for dates. unixtime is
35 the number of seconds since the epoch (1970-01-01 00:00 UTC). offset
34 the number of seconds since the epoch (1970-01-01 00:00 UTC). offset
36 is the offset of the local timezone, in seconds west of UTC (negative
35 is the offset of the local timezone, in seconds west of UTC (negative
37 if the timezone is east of UTC).
36 if the timezone is east of UTC).
38 Examples:
39
40 "1124706420 25200" (2005-08-22 03:27:00 -0700)
41
42 "1145475591 -7200" (2006-04-19 21:39:51 +0200)
43 ''',
37 ''',
44
38
45 'environment|env|Environment Variables':
39 'environment|env|Environment Variables':
46 r'''
40 r'''
47 HGEDITOR::
41 HGEDITOR::
48 This is the name of the editor to use when committing. Defaults to the
42 This is the name of the editor to use when committing. Defaults to the
49 value of EDITOR.
43 value of EDITOR.
50
44
51 (deprecated, use .hgrc)
45 (deprecated, use .hgrc)
52
46
53 HGENCODING::
47 HGENCODING::
54 This overrides the default locale setting detected by Mercurial.
48 This overrides the default locale setting detected by Mercurial.
55 This setting is used to convert data including usernames,
49 This setting is used to convert data including usernames,
56 changeset descriptions, tag names, and branches. This setting can
50 changeset descriptions, tag names, and branches. This setting can
57 be overridden with the --encoding command-line option.
51 be overridden with the --encoding command-line option.
58
52
59 HGENCODINGMODE::
53 HGENCODINGMODE::
60 This sets Mercurial's behavior for handling unknown characters
54 This sets Mercurial's behavior for handling unknown characters
61 while transcoding user inputs. The default is "strict", which
55 while transcoding user inputs. The default is "strict", which
62 causes Mercurial to abort if it can't translate a character. Other
56 causes Mercurial to abort if it can't translate a character. Other
63 settings include "replace", which replaces unknown characters, and
57 settings include "replace", which replaces unknown characters, and
64 "ignore", which drops them. This setting can be overridden with
58 "ignore", which drops them. This setting can be overridden with
65 the --encodingmode command-line option.
59 the --encodingmode command-line option.
66
60
67 HGMERGE::
61 HGMERGE::
68 An executable to use for resolving merge conflicts. The program
62 An executable to use for resolving merge conflicts. The program
69 will be executed with three arguments: local file, remote file,
63 will be executed with three arguments: local file, remote file,
70 ancestor file.
64 ancestor file.
71
65
72 The default program is "hgmerge", which is a shell script provided
66 The default program is "hgmerge", which is a shell script provided
73 by Mercurial with some sensible defaults.
67 by Mercurial with some sensible defaults.
74
68
75 (deprecated, use .hgrc)
69 (deprecated, use .hgrc)
76
70
77 HGRCPATH::
71 HGRCPATH::
78 A list of files or directories to search for hgrc files. Item
72 A list of files or directories to search for hgrc files. Item
79 separator is ":" on Unix, ";" on Windows. If HGRCPATH is not set,
73 separator is ":" on Unix, ";" on Windows. If HGRCPATH is not set,
80 platform default search path is used. If empty, only .hg/hgrc of
74 platform default search path is used. If empty, only .hg/hgrc of
81 current repository is read.
75 current repository is read.
82
76
83 For each element in path, if a directory, all entries in directory
77 For each element in path, if a directory, all entries in directory
84 ending with ".rc" are added to path. Else, element itself is
78 ending with ".rc" are added to path. Else, element itself is
85 added to path.
79 added to path.
86
80
87 HGUSER::
81 HGUSER::
88 This is the string used for the author of a commit.
82 This is the string used for the author of a commit.
89
83
90 (deprecated, use .hgrc)
84 (deprecated, use .hgrc)
91
85
92 EMAIL::
86 EMAIL::
93 If HGUSER is not set, this will be used as the author for a commit.
87 If HGUSER is not set, this will be used as the author for a commit.
94
88
95 LOGNAME::
89 LOGNAME::
96 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
90 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
97 '@hostname' appended) as the author value for a commit.
91 '@hostname' appended) as the author value for a commit.
98
92
99 EDITOR::
93 EDITOR::
100 This is the name of the editor used in the hgmerge script. It will be
94 This is the name of the editor used in the hgmerge script. It will be
101 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
95 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
102
96
103 PYTHONPATH::
97 PYTHONPATH::
104 This is used by Python to find imported modules and may need to be set
98 This is used by Python to find imported modules and may need to be set
105 appropriately if Mercurial is not installed system-wide.
99 appropriately if Mercurial is not installed system-wide.
106 ''',
100 ''',
107
101
108 "patterns|File Name Patterns": r'''
102 "patterns|File Name Patterns": r'''
109 Mercurial accepts several notations for identifying one or more
103 Mercurial accepts several notations for identifying one or more
110 files at a time.
104 files at a time.
111
105
112 By default, Mercurial treats filenames as shell-style extended
106 By default, Mercurial treats filenames as shell-style extended
113 glob patterns.
107 glob patterns.
114
108
115 Alternate pattern notations must be specified explicitly.
109 Alternate pattern notations must be specified explicitly.
116
110
117 To use a plain path name without any pattern matching, start a
111 To use a plain path name without any pattern matching, start a
118 name with "path:". These path names must match completely, from
112 name with "path:". These path names must match completely, from
119 the root of the current repository.
113 the root of the current repository.
120
114
121 To use an extended glob, start a name with "glob:". Globs are
115 To use an extended glob, start a name with "glob:". Globs are
122 rooted at the current directory; a glob such as "*.c" will match
116 rooted at the current directory; a glob such as "*.c" will match
123 files ending in ".c" in the current directory only.
117 files ending in ".c" in the current directory only.
124
118
125 The supported glob syntax extensions are "**" to match any string
119 The supported glob syntax extensions are "**" to match any string
126 across path separators, and "{a,b}" to mean "a or b".
120 across path separators, and "{a,b}" to mean "a or b".
127
121
128 To use a Perl/Python regular expression, start a name with "re:".
122 To use a Perl/Python regular expression, start a name with "re:".
129 Regexp pattern matching is anchored at the root of the repository.
123 Regexp pattern matching is anchored at the root of the repository.
130
124
131 Plain examples:
125 Plain examples:
132
126
133 path:foo/bar a name bar in a directory named foo in the root of
127 path:foo/bar a name bar in a directory named foo in the root of
134 the repository
128 the repository
135 path:path:name a file or directory named "path:name"
129 path:path:name a file or directory named "path:name"
136
130
137 Glob examples:
131 Glob examples:
138
132
139 glob:*.c any name ending in ".c" in the current directory
133 glob:*.c any name ending in ".c" in the current directory
140 *.c any name ending in ".c" in the current directory
134 *.c any name ending in ".c" in the current directory
141 **.c any name ending in ".c" in the current directory, or
135 **.c any name ending in ".c" in the current directory, or
142 any subdirectory
136 any subdirectory
143 foo/*.c any name ending in ".c" in the directory foo
137 foo/*.c any name ending in ".c" in the directory foo
144 foo/**.c any name ending in ".c" in the directory foo, or any
138 foo/**.c any name ending in ".c" in the directory foo, or any
145 subdirectory
139 subdirectory
146
140
147 Regexp examples:
141 Regexp examples:
148
142
149 re:.*\.c$ any name ending in ".c", anywhere in the repository
143 re:.*\.c$ any name ending in ".c", anywhere in the repository
150
144
151 ''',
145 ''',
152 }
146 }
153
147
@@ -1,1182 +1,1218 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 gettext as _
15 from i18n import gettext as _
16 from demandload import *
16 from demandload import *
17 demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile")
17 demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile")
18 demandload(globals(), "os threading time calendar ConfigParser locale")
18 demandload(globals(), "os threading time calendar ConfigParser locale")
19
19
20 _encoding = os.environ.get("HGENCODING") or locale.getpreferredencoding()
20 _encoding = os.environ.get("HGENCODING") or locale.getpreferredencoding()
21 _encodingmode = os.environ.get("HGENCODINGMODE", "strict")
21 _encodingmode = os.environ.get("HGENCODINGMODE", "strict")
22
22
23 def tolocal(s):
23 def tolocal(s):
24 """
24 """
25 Convert a string from internal UTF-8 to local encoding
25 Convert a string from internal UTF-8 to local encoding
26
26
27 All internal strings should be UTF-8 but some repos before the
27 All internal strings should be UTF-8 but some repos before the
28 implementation of locale support may contain latin1 or possibly
28 implementation of locale support may contain latin1 or possibly
29 other character sets. We attempt to decode everything strictly
29 other character sets. We attempt to decode everything strictly
30 using UTF-8, then Latin-1, and failing that, we use UTF-8 and
30 using UTF-8, then Latin-1, and failing that, we use UTF-8 and
31 replace unknown characters.
31 replace unknown characters.
32 """
32 """
33 for e in "utf-8 latin1".split():
33 for e in "utf-8 latin1".split():
34 try:
34 try:
35 u = s.decode(e) # attempt strict decoding
35 u = s.decode(e) # attempt strict decoding
36 return u.encode(_encoding, "replace")
36 return u.encode(_encoding, "replace")
37 except UnicodeDecodeError:
37 except UnicodeDecodeError:
38 pass
38 pass
39 u = s.decode("utf-8", "replace") # last ditch
39 u = s.decode("utf-8", "replace") # last ditch
40 return u.encode(_encoding, "replace")
40 return u.encode(_encoding, "replace")
41
41
42 def fromlocal(s):
42 def fromlocal(s):
43 """
43 """
44 Convert a string from the local character encoding to UTF-8
44 Convert a string from the local character encoding to UTF-8
45
45
46 We attempt to decode strings using the encoding mode set by
46 We attempt to decode strings using the encoding mode set by
47 HG_ENCODINGMODE, which defaults to 'strict'. In this mode, unknown
47 HG_ENCODINGMODE, which defaults to 'strict'. In this mode, unknown
48 characters will cause an error message. Other modes include
48 characters will cause an error message. Other modes include
49 'replace', which replaces unknown characters with a special
49 'replace', which replaces unknown characters with a special
50 Unicode character, and 'ignore', which drops the character.
50 Unicode character, and 'ignore', which drops the character.
51 """
51 """
52 try:
52 try:
53 return s.decode(_encoding, _encodingmode).encode("utf-8")
53 return s.decode(_encoding, _encodingmode).encode("utf-8")
54 except UnicodeDecodeError, inst:
54 except UnicodeDecodeError, inst:
55 sub = s[max(0, inst.start-10):inst.start+10]
55 sub = s[max(0, inst.start-10):inst.start+10]
56 raise Abort("decoding near '%s': %s!\n" % (sub, inst))
56 raise Abort("decoding near '%s': %s!\n" % (sub, inst))
57
57
58 def locallen(s):
58 def locallen(s):
59 """Find the length in characters of a local string"""
59 """Find the length in characters of a local string"""
60 return len(s.decode(_encoding, "replace"))
60 return len(s.decode(_encoding, "replace"))
61
61
62 def localsub(s, a, b=None):
62 def localsub(s, a, b=None):
63 try:
63 try:
64 u = s.decode(_encoding, _encodingmode)
64 u = s.decode(_encoding, _encodingmode)
65 if b is not None:
65 if b is not None:
66 u = u[a:b]
66 u = u[a:b]
67 else:
67 else:
68 u = u[:a]
68 u = u[:a]
69 return u.encode(_encoding, _encodingmode)
69 return u.encode(_encoding, _encodingmode)
70 except UnicodeDecodeError, inst:
70 except UnicodeDecodeError, inst:
71 sub = s[max(0, inst.start-10), inst.start+10]
71 sub = s[max(0, inst.start-10), inst.start+10]
72 raise Abort("decoding near '%s': %s!\n" % (sub, inst))
72 raise Abort("decoding near '%s': %s!\n" % (sub, inst))
73
73
74 # used by parsedate
74 # used by parsedate
75 defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M',
75 defaultdateformats = (
76 '%a %b %d %H:%M:%S %Y')
76 '%Y-%m-%d %H:%M:%S',
77 '%Y-%m-%d %I:%M:%S%p',
78 '%Y-%m-%d %H:%M',
79 '%Y-%m-%d %I:%M%p',
80 '%Y-%m-%d',
81 '%m-%d',
82 '%m/%d',
83 '%m/%d/%y',
84 '%m/%d/%Y',
85 '%a %b %d %H:%M:%S %Y',
86 '%a %b %d %I:%M:%S%p %Y',
87 '%b %d %H:%M:%S %Y',
88 '%b %d %I:%M:%S%p',
89 '%b %d %H:%M',
90 '%b %d %I:%M%p',
91 '%b %d %Y',
92 '%b %d',
93 '%H:%M:%S',
94 '%I:%M:%SP',
95 '%H:%M',
96 '%I:%M%p',
97 )
77
98
78 class SignalInterrupt(Exception):
99 class SignalInterrupt(Exception):
79 """Exception raised on SIGTERM and SIGHUP."""
100 """Exception raised on SIGTERM and SIGHUP."""
80
101
81 # like SafeConfigParser but with case-sensitive keys
102 # like SafeConfigParser but with case-sensitive keys
82 class configparser(ConfigParser.SafeConfigParser):
103 class configparser(ConfigParser.SafeConfigParser):
83 def optionxform(self, optionstr):
104 def optionxform(self, optionstr):
84 return optionstr
105 return optionstr
85
106
86 def cachefunc(func):
107 def cachefunc(func):
87 '''cache the result of function calls'''
108 '''cache the result of function calls'''
88 # XXX doesn't handle keywords args
109 # XXX doesn't handle keywords args
89 cache = {}
110 cache = {}
90 if func.func_code.co_argcount == 1:
111 if func.func_code.co_argcount == 1:
91 # we gain a small amount of time because
112 # we gain a small amount of time because
92 # we don't need to pack/unpack the list
113 # we don't need to pack/unpack the list
93 def f(arg):
114 def f(arg):
94 if arg not in cache:
115 if arg not in cache:
95 cache[arg] = func(arg)
116 cache[arg] = func(arg)
96 return cache[arg]
117 return cache[arg]
97 else:
118 else:
98 def f(*args):
119 def f(*args):
99 if args not in cache:
120 if args not in cache:
100 cache[args] = func(*args)
121 cache[args] = func(*args)
101 return cache[args]
122 return cache[args]
102
123
103 return f
124 return f
104
125
105 def pipefilter(s, cmd):
126 def pipefilter(s, cmd):
106 '''filter string S through command CMD, returning its output'''
127 '''filter string S through command CMD, returning its output'''
107 (pout, pin) = popen2.popen2(cmd, -1, 'b')
128 (pout, pin) = popen2.popen2(cmd, -1, 'b')
108 def writer():
129 def writer():
109 try:
130 try:
110 pin.write(s)
131 pin.write(s)
111 pin.close()
132 pin.close()
112 except IOError, inst:
133 except IOError, inst:
113 if inst.errno != errno.EPIPE:
134 if inst.errno != errno.EPIPE:
114 raise
135 raise
115
136
116 # we should use select instead on UNIX, but this will work on most
137 # we should use select instead on UNIX, but this will work on most
117 # systems, including Windows
138 # systems, including Windows
118 w = threading.Thread(target=writer)
139 w = threading.Thread(target=writer)
119 w.start()
140 w.start()
120 f = pout.read()
141 f = pout.read()
121 pout.close()
142 pout.close()
122 w.join()
143 w.join()
123 return f
144 return f
124
145
125 def tempfilter(s, cmd):
146 def tempfilter(s, cmd):
126 '''filter string S through a pair of temporary files with CMD.
147 '''filter string S through a pair of temporary files with CMD.
127 CMD is used as a template to create the real command to be run,
148 CMD is used as a template to create the real command to be run,
128 with the strings INFILE and OUTFILE replaced by the real names of
149 with the strings INFILE and OUTFILE replaced by the real names of
129 the temporary files generated.'''
150 the temporary files generated.'''
130 inname, outname = None, None
151 inname, outname = None, None
131 try:
152 try:
132 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
153 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
133 fp = os.fdopen(infd, 'wb')
154 fp = os.fdopen(infd, 'wb')
134 fp.write(s)
155 fp.write(s)
135 fp.close()
156 fp.close()
136 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
157 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
137 os.close(outfd)
158 os.close(outfd)
138 cmd = cmd.replace('INFILE', inname)
159 cmd = cmd.replace('INFILE', inname)
139 cmd = cmd.replace('OUTFILE', outname)
160 cmd = cmd.replace('OUTFILE', outname)
140 code = os.system(cmd)
161 code = os.system(cmd)
141 if code: raise Abort(_("command '%s' failed: %s") %
162 if code: raise Abort(_("command '%s' failed: %s") %
142 (cmd, explain_exit(code)))
163 (cmd, explain_exit(code)))
143 return open(outname, 'rb').read()
164 return open(outname, 'rb').read()
144 finally:
165 finally:
145 try:
166 try:
146 if inname: os.unlink(inname)
167 if inname: os.unlink(inname)
147 except: pass
168 except: pass
148 try:
169 try:
149 if outname: os.unlink(outname)
170 if outname: os.unlink(outname)
150 except: pass
171 except: pass
151
172
152 filtertable = {
173 filtertable = {
153 'tempfile:': tempfilter,
174 'tempfile:': tempfilter,
154 'pipe:': pipefilter,
175 'pipe:': pipefilter,
155 }
176 }
156
177
157 def filter(s, cmd):
178 def filter(s, cmd):
158 "filter a string through a command that transforms its input to its output"
179 "filter a string through a command that transforms its input to its output"
159 for name, fn in filtertable.iteritems():
180 for name, fn in filtertable.iteritems():
160 if cmd.startswith(name):
181 if cmd.startswith(name):
161 return fn(s, cmd[len(name):].lstrip())
182 return fn(s, cmd[len(name):].lstrip())
162 return pipefilter(s, cmd)
183 return pipefilter(s, cmd)
163
184
164 def find_in_path(name, path, default=None):
185 def find_in_path(name, path, default=None):
165 '''find name in search path. path can be string (will be split
186 '''find name in search path. path can be string (will be split
166 with os.pathsep), or iterable thing that returns strings. if name
187 with os.pathsep), or iterable thing that returns strings. if name
167 found, return path to name. else return default.'''
188 found, return path to name. else return default.'''
168 if isinstance(path, str):
189 if isinstance(path, str):
169 path = path.split(os.pathsep)
190 path = path.split(os.pathsep)
170 for p in path:
191 for p in path:
171 p_name = os.path.join(p, name)
192 p_name = os.path.join(p, name)
172 if os.path.exists(p_name):
193 if os.path.exists(p_name):
173 return p_name
194 return p_name
174 return default
195 return default
175
196
176 def binary(s):
197 def binary(s):
177 """return true if a string is binary data using diff's heuristic"""
198 """return true if a string is binary data using diff's heuristic"""
178 if s and '\0' in s[:4096]:
199 if s and '\0' in s[:4096]:
179 return True
200 return True
180 return False
201 return False
181
202
182 def unique(g):
203 def unique(g):
183 """return the uniq elements of iterable g"""
204 """return the uniq elements of iterable g"""
184 seen = {}
205 seen = {}
185 l = []
206 l = []
186 for f in g:
207 for f in g:
187 if f not in seen:
208 if f not in seen:
188 seen[f] = 1
209 seen[f] = 1
189 l.append(f)
210 l.append(f)
190 return l
211 return l
191
212
192 class Abort(Exception):
213 class Abort(Exception):
193 """Raised if a command needs to print an error and exit."""
214 """Raised if a command needs to print an error and exit."""
194
215
195 class UnexpectedOutput(Abort):
216 class UnexpectedOutput(Abort):
196 """Raised to print an error with part of output and exit."""
217 """Raised to print an error with part of output and exit."""
197
218
198 def always(fn): return True
219 def always(fn): return True
199 def never(fn): return False
220 def never(fn): return False
200
221
201 def patkind(name, dflt_pat='glob'):
222 def patkind(name, dflt_pat='glob'):
202 """Split a string into an optional pattern kind prefix and the
223 """Split a string into an optional pattern kind prefix and the
203 actual pattern."""
224 actual pattern."""
204 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
225 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
205 if name.startswith(prefix + ':'): return name.split(':', 1)
226 if name.startswith(prefix + ':'): return name.split(':', 1)
206 return dflt_pat, name
227 return dflt_pat, name
207
228
208 def globre(pat, head='^', tail='$'):
229 def globre(pat, head='^', tail='$'):
209 "convert a glob pattern into a regexp"
230 "convert a glob pattern into a regexp"
210 i, n = 0, len(pat)
231 i, n = 0, len(pat)
211 res = ''
232 res = ''
212 group = False
233 group = False
213 def peek(): return i < n and pat[i]
234 def peek(): return i < n and pat[i]
214 while i < n:
235 while i < n:
215 c = pat[i]
236 c = pat[i]
216 i = i+1
237 i = i+1
217 if c == '*':
238 if c == '*':
218 if peek() == '*':
239 if peek() == '*':
219 i += 1
240 i += 1
220 res += '.*'
241 res += '.*'
221 else:
242 else:
222 res += '[^/]*'
243 res += '[^/]*'
223 elif c == '?':
244 elif c == '?':
224 res += '.'
245 res += '.'
225 elif c == '[':
246 elif c == '[':
226 j = i
247 j = i
227 if j < n and pat[j] in '!]':
248 if j < n and pat[j] in '!]':
228 j += 1
249 j += 1
229 while j < n and pat[j] != ']':
250 while j < n and pat[j] != ']':
230 j += 1
251 j += 1
231 if j >= n:
252 if j >= n:
232 res += '\\['
253 res += '\\['
233 else:
254 else:
234 stuff = pat[i:j].replace('\\','\\\\')
255 stuff = pat[i:j].replace('\\','\\\\')
235 i = j + 1
256 i = j + 1
236 if stuff[0] == '!':
257 if stuff[0] == '!':
237 stuff = '^' + stuff[1:]
258 stuff = '^' + stuff[1:]
238 elif stuff[0] == '^':
259 elif stuff[0] == '^':
239 stuff = '\\' + stuff
260 stuff = '\\' + stuff
240 res = '%s[%s]' % (res, stuff)
261 res = '%s[%s]' % (res, stuff)
241 elif c == '{':
262 elif c == '{':
242 group = True
263 group = True
243 res += '(?:'
264 res += '(?:'
244 elif c == '}' and group:
265 elif c == '}' and group:
245 res += ')'
266 res += ')'
246 group = False
267 group = False
247 elif c == ',' and group:
268 elif c == ',' and group:
248 res += '|'
269 res += '|'
249 elif c == '\\':
270 elif c == '\\':
250 p = peek()
271 p = peek()
251 if p:
272 if p:
252 i += 1
273 i += 1
253 res += re.escape(p)
274 res += re.escape(p)
254 else:
275 else:
255 res += re.escape(c)
276 res += re.escape(c)
256 else:
277 else:
257 res += re.escape(c)
278 res += re.escape(c)
258 return head + res + tail
279 return head + res + tail
259
280
260 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
281 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
261
282
262 def pathto(n1, n2):
283 def pathto(n1, n2):
263 '''return the relative path from one place to another.
284 '''return the relative path from one place to another.
264 n1 should use os.sep to separate directories
285 n1 should use os.sep to separate directories
265 n2 should use "/" to separate directories
286 n2 should use "/" to separate directories
266 returns an os.sep-separated path.
287 returns an os.sep-separated path.
267 '''
288 '''
268 if not n1: return localpath(n2)
289 if not n1: return localpath(n2)
269 a, b = n1.split(os.sep), n2.split('/')
290 a, b = n1.split(os.sep), n2.split('/')
270 a.reverse()
291 a.reverse()
271 b.reverse()
292 b.reverse()
272 while a and b and a[-1] == b[-1]:
293 while a and b and a[-1] == b[-1]:
273 a.pop()
294 a.pop()
274 b.pop()
295 b.pop()
275 b.reverse()
296 b.reverse()
276 return os.sep.join((['..'] * len(a)) + b)
297 return os.sep.join((['..'] * len(a)) + b)
277
298
278 def canonpath(root, cwd, myname):
299 def canonpath(root, cwd, myname):
279 """return the canonical path of myname, given cwd and root"""
300 """return the canonical path of myname, given cwd and root"""
280 if root == os.sep:
301 if root == os.sep:
281 rootsep = os.sep
302 rootsep = os.sep
282 elif root.endswith(os.sep):
303 elif root.endswith(os.sep):
283 rootsep = root
304 rootsep = root
284 else:
305 else:
285 rootsep = root + os.sep
306 rootsep = root + os.sep
286 name = myname
307 name = myname
287 if not os.path.isabs(name):
308 if not os.path.isabs(name):
288 name = os.path.join(root, cwd, name)
309 name = os.path.join(root, cwd, name)
289 name = os.path.normpath(name)
310 name = os.path.normpath(name)
290 if name != rootsep and name.startswith(rootsep):
311 if name != rootsep and name.startswith(rootsep):
291 name = name[len(rootsep):]
312 name = name[len(rootsep):]
292 audit_path(name)
313 audit_path(name)
293 return pconvert(name)
314 return pconvert(name)
294 elif name == root:
315 elif name == root:
295 return ''
316 return ''
296 else:
317 else:
297 # Determine whether `name' is in the hierarchy at or beneath `root',
318 # Determine whether `name' is in the hierarchy at or beneath `root',
298 # by iterating name=dirname(name) until that causes no change (can't
319 # by iterating name=dirname(name) until that causes no change (can't
299 # check name == '/', because that doesn't work on windows). For each
320 # check name == '/', because that doesn't work on windows). For each
300 # `name', compare dev/inode numbers. If they match, the list `rel'
321 # `name', compare dev/inode numbers. If they match, the list `rel'
301 # holds the reversed list of components making up the relative file
322 # holds the reversed list of components making up the relative file
302 # name we want.
323 # name we want.
303 root_st = os.stat(root)
324 root_st = os.stat(root)
304 rel = []
325 rel = []
305 while True:
326 while True:
306 try:
327 try:
307 name_st = os.stat(name)
328 name_st = os.stat(name)
308 except OSError:
329 except OSError:
309 break
330 break
310 if samestat(name_st, root_st):
331 if samestat(name_st, root_st):
311 rel.reverse()
332 rel.reverse()
312 name = os.path.join(*rel)
333 name = os.path.join(*rel)
313 audit_path(name)
334 audit_path(name)
314 return pconvert(name)
335 return pconvert(name)
315 dirname, basename = os.path.split(name)
336 dirname, basename = os.path.split(name)
316 rel.append(basename)
337 rel.append(basename)
317 if dirname == name:
338 if dirname == name:
318 break
339 break
319 name = dirname
340 name = dirname
320
341
321 raise Abort('%s not under root' % myname)
342 raise Abort('%s not under root' % myname)
322
343
323 def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
344 def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
324 return _matcher(canonroot, cwd, names, inc, exc, head, 'glob', src)
345 return _matcher(canonroot, cwd, names, inc, exc, head, 'glob', src)
325
346
326 def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
347 def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
327 if os.name == 'nt':
348 if os.name == 'nt':
328 dflt_pat = 'glob'
349 dflt_pat = 'glob'
329 else:
350 else:
330 dflt_pat = 'relpath'
351 dflt_pat = 'relpath'
331 return _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src)
352 return _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src)
332
353
333 def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src):
354 def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src):
334 """build a function to match a set of file patterns
355 """build a function to match a set of file patterns
335
356
336 arguments:
357 arguments:
337 canonroot - the canonical root of the tree you're matching against
358 canonroot - the canonical root of the tree you're matching against
338 cwd - the current working directory, if relevant
359 cwd - the current working directory, if relevant
339 names - patterns to find
360 names - patterns to find
340 inc - patterns to include
361 inc - patterns to include
341 exc - patterns to exclude
362 exc - patterns to exclude
342 head - a regex to prepend to patterns to control whether a match is rooted
363 head - a regex to prepend to patterns to control whether a match is rooted
343
364
344 a pattern is one of:
365 a pattern is one of:
345 'glob:<rooted glob>'
366 'glob:<rooted glob>'
346 're:<rooted regexp>'
367 're:<rooted regexp>'
347 'path:<rooted path>'
368 'path:<rooted path>'
348 'relglob:<relative glob>'
369 'relglob:<relative glob>'
349 'relpath:<relative path>'
370 'relpath:<relative path>'
350 'relre:<relative regexp>'
371 'relre:<relative regexp>'
351 '<rooted path or regexp>'
372 '<rooted path or regexp>'
352
373
353 returns:
374 returns:
354 a 3-tuple containing
375 a 3-tuple containing
355 - list of explicit non-pattern names passed in
376 - list of explicit non-pattern names passed in
356 - a bool match(filename) function
377 - a bool match(filename) function
357 - a bool indicating if any patterns were passed in
378 - a bool indicating if any patterns were passed in
358
379
359 todo:
380 todo:
360 make head regex a rooted bool
381 make head regex a rooted bool
361 """
382 """
362
383
363 def contains_glob(name):
384 def contains_glob(name):
364 for c in name:
385 for c in name:
365 if c in _globchars: return True
386 if c in _globchars: return True
366 return False
387 return False
367
388
368 def regex(kind, name, tail):
389 def regex(kind, name, tail):
369 '''convert a pattern into a regular expression'''
390 '''convert a pattern into a regular expression'''
370 if kind == 're':
391 if kind == 're':
371 return name
392 return name
372 elif kind == 'path':
393 elif kind == 'path':
373 return '^' + re.escape(name) + '(?:/|$)'
394 return '^' + re.escape(name) + '(?:/|$)'
374 elif kind == 'relglob':
395 elif kind == 'relglob':
375 return head + globre(name, '(?:|.*/)', tail)
396 return head + globre(name, '(?:|.*/)', tail)
376 elif kind == 'relpath':
397 elif kind == 'relpath':
377 return head + re.escape(name) + tail
398 return head + re.escape(name) + tail
378 elif kind == 'relre':
399 elif kind == 'relre':
379 if name.startswith('^'):
400 if name.startswith('^'):
380 return name
401 return name
381 return '.*' + name
402 return '.*' + name
382 return head + globre(name, '', tail)
403 return head + globre(name, '', tail)
383
404
384 def matchfn(pats, tail):
405 def matchfn(pats, tail):
385 """build a matching function from a set of patterns"""
406 """build a matching function from a set of patterns"""
386 if not pats:
407 if not pats:
387 return
408 return
388 matches = []
409 matches = []
389 for k, p in pats:
410 for k, p in pats:
390 try:
411 try:
391 pat = '(?:%s)' % regex(k, p, tail)
412 pat = '(?:%s)' % regex(k, p, tail)
392 matches.append(re.compile(pat).match)
413 matches.append(re.compile(pat).match)
393 except re.error:
414 except re.error:
394 if src: raise Abort("%s: invalid pattern (%s): %s" % (src, k, p))
415 if src: raise Abort("%s: invalid pattern (%s): %s" % (src, k, p))
395 else: raise Abort("invalid pattern (%s): %s" % (k, p))
416 else: raise Abort("invalid pattern (%s): %s" % (k, p))
396
417
397 def buildfn(text):
418 def buildfn(text):
398 for m in matches:
419 for m in matches:
399 r = m(text)
420 r = m(text)
400 if r:
421 if r:
401 return r
422 return r
402
423
403 return buildfn
424 return buildfn
404
425
405 def globprefix(pat):
426 def globprefix(pat):
406 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
427 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
407 root = []
428 root = []
408 for p in pat.split(os.sep):
429 for p in pat.split(os.sep):
409 if contains_glob(p): break
430 if contains_glob(p): break
410 root.append(p)
431 root.append(p)
411 return '/'.join(root)
432 return '/'.join(root)
412
433
413 pats = []
434 pats = []
414 files = []
435 files = []
415 roots = []
436 roots = []
416 for kind, name in [patkind(p, dflt_pat) for p in names]:
437 for kind, name in [patkind(p, dflt_pat) for p in names]:
417 if kind in ('glob', 'relpath'):
438 if kind in ('glob', 'relpath'):
418 name = canonpath(canonroot, cwd, name)
439 name = canonpath(canonroot, cwd, name)
419 if name == '':
440 if name == '':
420 kind, name = 'glob', '**'
441 kind, name = 'glob', '**'
421 if kind in ('glob', 'path', 're'):
442 if kind in ('glob', 'path', 're'):
422 pats.append((kind, name))
443 pats.append((kind, name))
423 if kind == 'glob':
444 if kind == 'glob':
424 root = globprefix(name)
445 root = globprefix(name)
425 if root: roots.append(root)
446 if root: roots.append(root)
426 elif kind == 'relpath':
447 elif kind == 'relpath':
427 files.append((kind, name))
448 files.append((kind, name))
428 roots.append(name)
449 roots.append(name)
429
450
430 patmatch = matchfn(pats, '$') or always
451 patmatch = matchfn(pats, '$') or always
431 filematch = matchfn(files, '(?:/|$)') or always
452 filematch = matchfn(files, '(?:/|$)') or always
432 incmatch = always
453 incmatch = always
433 if inc:
454 if inc:
434 inckinds = [patkind(canonpath(canonroot, cwd, i)) for i in inc]
455 inckinds = [patkind(canonpath(canonroot, cwd, i)) for i in inc]
435 incmatch = matchfn(inckinds, '(?:/|$)')
456 incmatch = matchfn(inckinds, '(?:/|$)')
436 excmatch = lambda fn: False
457 excmatch = lambda fn: False
437 if exc:
458 if exc:
438 exckinds = [patkind(canonpath(canonroot, cwd, x)) for x in exc]
459 exckinds = [patkind(canonpath(canonroot, cwd, x)) for x in exc]
439 excmatch = matchfn(exckinds, '(?:/|$)')
460 excmatch = matchfn(exckinds, '(?:/|$)')
440
461
441 return (roots,
462 return (roots,
442 lambda fn: (incmatch(fn) and not excmatch(fn) and
463 lambda fn: (incmatch(fn) and not excmatch(fn) and
443 (fn.endswith('/') or
464 (fn.endswith('/') or
444 (not pats and not files) or
465 (not pats and not files) or
445 (pats and patmatch(fn)) or
466 (pats and patmatch(fn)) or
446 (files and filematch(fn)))),
467 (files and filematch(fn)))),
447 (inc or exc or (pats and pats != [('glob', '**')])) and True)
468 (inc or exc or (pats and pats != [('glob', '**')])) and True)
448
469
449 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
470 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
450 '''enhanced shell command execution.
471 '''enhanced shell command execution.
451 run with environment maybe modified, maybe in different dir.
472 run with environment maybe modified, maybe in different dir.
452
473
453 if command fails and onerr is None, return status. if ui object,
474 if command fails and onerr is None, return status. if ui object,
454 print error message and return status, else raise onerr object as
475 print error message and return status, else raise onerr object as
455 exception.'''
476 exception.'''
456 def py2shell(val):
477 def py2shell(val):
457 'convert python object into string that is useful to shell'
478 'convert python object into string that is useful to shell'
458 if val in (None, False):
479 if val in (None, False):
459 return '0'
480 return '0'
460 if val == True:
481 if val == True:
461 return '1'
482 return '1'
462 return str(val)
483 return str(val)
463 oldenv = {}
484 oldenv = {}
464 for k in environ:
485 for k in environ:
465 oldenv[k] = os.environ.get(k)
486 oldenv[k] = os.environ.get(k)
466 if cwd is not None:
487 if cwd is not None:
467 oldcwd = os.getcwd()
488 oldcwd = os.getcwd()
468 try:
489 try:
469 for k, v in environ.iteritems():
490 for k, v in environ.iteritems():
470 os.environ[k] = py2shell(v)
491 os.environ[k] = py2shell(v)
471 if cwd is not None and oldcwd != cwd:
492 if cwd is not None and oldcwd != cwd:
472 os.chdir(cwd)
493 os.chdir(cwd)
473 rc = os.system(cmd)
494 rc = os.system(cmd)
474 if rc and onerr:
495 if rc and onerr:
475 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
496 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
476 explain_exit(rc)[0])
497 explain_exit(rc)[0])
477 if errprefix:
498 if errprefix:
478 errmsg = '%s: %s' % (errprefix, errmsg)
499 errmsg = '%s: %s' % (errprefix, errmsg)
479 try:
500 try:
480 onerr.warn(errmsg + '\n')
501 onerr.warn(errmsg + '\n')
481 except AttributeError:
502 except AttributeError:
482 raise onerr(errmsg)
503 raise onerr(errmsg)
483 return rc
504 return rc
484 finally:
505 finally:
485 for k, v in oldenv.iteritems():
506 for k, v in oldenv.iteritems():
486 if v is None:
507 if v is None:
487 del os.environ[k]
508 del os.environ[k]
488 else:
509 else:
489 os.environ[k] = v
510 os.environ[k] = v
490 if cwd is not None and oldcwd != cwd:
511 if cwd is not None and oldcwd != cwd:
491 os.chdir(oldcwd)
512 os.chdir(oldcwd)
492
513
493 def rename(src, dst):
514 def rename(src, dst):
494 """forcibly rename a file"""
515 """forcibly rename a file"""
495 try:
516 try:
496 os.rename(src, dst)
517 os.rename(src, dst)
497 except OSError, err:
518 except OSError, err:
498 # on windows, rename to existing file is not allowed, so we
519 # on windows, rename to existing file is not allowed, so we
499 # must delete destination first. but if file is open, unlink
520 # must delete destination first. but if file is open, unlink
500 # schedules it for delete but does not delete it. rename
521 # schedules it for delete but does not delete it. rename
501 # happens immediately even for open files, so we create
522 # happens immediately even for open files, so we create
502 # temporary file, delete it, rename destination to that name,
523 # temporary file, delete it, rename destination to that name,
503 # then delete that. then rename is safe to do.
524 # then delete that. then rename is safe to do.
504 fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.')
525 fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.')
505 os.close(fd)
526 os.close(fd)
506 os.unlink(temp)
527 os.unlink(temp)
507 os.rename(dst, temp)
528 os.rename(dst, temp)
508 os.unlink(temp)
529 os.unlink(temp)
509 os.rename(src, dst)
530 os.rename(src, dst)
510
531
511 def unlink(f):
532 def unlink(f):
512 """unlink and remove the directory if it is empty"""
533 """unlink and remove the directory if it is empty"""
513 os.unlink(f)
534 os.unlink(f)
514 # try removing directories that might now be empty
535 # try removing directories that might now be empty
515 try:
536 try:
516 os.removedirs(os.path.dirname(f))
537 os.removedirs(os.path.dirname(f))
517 except OSError:
538 except OSError:
518 pass
539 pass
519
540
520 def copyfile(src, dest):
541 def copyfile(src, dest):
521 "copy a file, preserving mode"
542 "copy a file, preserving mode"
522 try:
543 try:
523 shutil.copyfile(src, dest)
544 shutil.copyfile(src, dest)
524 shutil.copymode(src, dest)
545 shutil.copymode(src, dest)
525 except shutil.Error, inst:
546 except shutil.Error, inst:
526 raise util.Abort(str(inst))
547 raise util.Abort(str(inst))
527
548
528 def copyfiles(src, dst, hardlink=None):
549 def copyfiles(src, dst, hardlink=None):
529 """Copy a directory tree using hardlinks if possible"""
550 """Copy a directory tree using hardlinks if possible"""
530
551
531 if hardlink is None:
552 if hardlink is None:
532 hardlink = (os.stat(src).st_dev ==
553 hardlink = (os.stat(src).st_dev ==
533 os.stat(os.path.dirname(dst)).st_dev)
554 os.stat(os.path.dirname(dst)).st_dev)
534
555
535 if os.path.isdir(src):
556 if os.path.isdir(src):
536 os.mkdir(dst)
557 os.mkdir(dst)
537 for name in os.listdir(src):
558 for name in os.listdir(src):
538 srcname = os.path.join(src, name)
559 srcname = os.path.join(src, name)
539 dstname = os.path.join(dst, name)
560 dstname = os.path.join(dst, name)
540 copyfiles(srcname, dstname, hardlink)
561 copyfiles(srcname, dstname, hardlink)
541 else:
562 else:
542 if hardlink:
563 if hardlink:
543 try:
564 try:
544 os_link(src, dst)
565 os_link(src, dst)
545 except (IOError, OSError):
566 except (IOError, OSError):
546 hardlink = False
567 hardlink = False
547 shutil.copy(src, dst)
568 shutil.copy(src, dst)
548 else:
569 else:
549 shutil.copy(src, dst)
570 shutil.copy(src, dst)
550
571
551 def audit_path(path):
572 def audit_path(path):
552 """Abort if path contains dangerous components"""
573 """Abort if path contains dangerous components"""
553 parts = os.path.normcase(path).split(os.sep)
574 parts = os.path.normcase(path).split(os.sep)
554 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
575 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
555 or os.pardir in parts):
576 or os.pardir in parts):
556 raise Abort(_("path contains illegal component: %s\n") % path)
577 raise Abort(_("path contains illegal component: %s\n") % path)
557
578
558 def _makelock_file(info, pathname):
579 def _makelock_file(info, pathname):
559 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
580 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
560 os.write(ld, info)
581 os.write(ld, info)
561 os.close(ld)
582 os.close(ld)
562
583
563 def _readlock_file(pathname):
584 def _readlock_file(pathname):
564 return posixfile(pathname).read()
585 return posixfile(pathname).read()
565
586
566 def nlinks(pathname):
587 def nlinks(pathname):
567 """Return number of hardlinks for the given file."""
588 """Return number of hardlinks for the given file."""
568 return os.lstat(pathname).st_nlink
589 return os.lstat(pathname).st_nlink
569
590
570 if hasattr(os, 'link'):
591 if hasattr(os, 'link'):
571 os_link = os.link
592 os_link = os.link
572 else:
593 else:
573 def os_link(src, dst):
594 def os_link(src, dst):
574 raise OSError(0, _("Hardlinks not supported"))
595 raise OSError(0, _("Hardlinks not supported"))
575
596
576 def fstat(fp):
597 def fstat(fp):
577 '''stat file object that may not have fileno method.'''
598 '''stat file object that may not have fileno method.'''
578 try:
599 try:
579 return os.fstat(fp.fileno())
600 return os.fstat(fp.fileno())
580 except AttributeError:
601 except AttributeError:
581 return os.stat(fp.name)
602 return os.stat(fp.name)
582
603
583 posixfile = file
604 posixfile = file
584
605
585 def is_win_9x():
606 def is_win_9x():
586 '''return true if run on windows 95, 98 or me.'''
607 '''return true if run on windows 95, 98 or me.'''
587 try:
608 try:
588 return sys.getwindowsversion()[3] == 1
609 return sys.getwindowsversion()[3] == 1
589 except AttributeError:
610 except AttributeError:
590 return os.name == 'nt' and 'command' in os.environ.get('comspec', '')
611 return os.name == 'nt' and 'command' in os.environ.get('comspec', '')
591
612
592 getuser_fallback = None
613 getuser_fallback = None
593
614
594 def getuser():
615 def getuser():
595 '''return name of current user'''
616 '''return name of current user'''
596 try:
617 try:
597 return getpass.getuser()
618 return getpass.getuser()
598 except ImportError:
619 except ImportError:
599 # import of pwd will fail on windows - try fallback
620 # import of pwd will fail on windows - try fallback
600 if getuser_fallback:
621 if getuser_fallback:
601 return getuser_fallback()
622 return getuser_fallback()
602 # raised if win32api not available
623 # raised if win32api not available
603 raise Abort(_('user name not available - set USERNAME '
624 raise Abort(_('user name not available - set USERNAME '
604 'environment variable'))
625 'environment variable'))
605
626
606 def username(uid=None):
627 def username(uid=None):
607 """Return the name of the user with the given uid.
628 """Return the name of the user with the given uid.
608
629
609 If uid is None, return the name of the current user."""
630 If uid is None, return the name of the current user."""
610 try:
631 try:
611 import pwd
632 import pwd
612 if uid is None:
633 if uid is None:
613 uid = os.getuid()
634 uid = os.getuid()
614 try:
635 try:
615 return pwd.getpwuid(uid)[0]
636 return pwd.getpwuid(uid)[0]
616 except KeyError:
637 except KeyError:
617 return str(uid)
638 return str(uid)
618 except ImportError:
639 except ImportError:
619 return None
640 return None
620
641
621 def groupname(gid=None):
642 def groupname(gid=None):
622 """Return the name of the group with the given gid.
643 """Return the name of the group with the given gid.
623
644
624 If gid is None, return the name of the current group."""
645 If gid is None, return the name of the current group."""
625 try:
646 try:
626 import grp
647 import grp
627 if gid is None:
648 if gid is None:
628 gid = os.getgid()
649 gid = os.getgid()
629 try:
650 try:
630 return grp.getgrgid(gid)[0]
651 return grp.getgrgid(gid)[0]
631 except KeyError:
652 except KeyError:
632 return str(gid)
653 return str(gid)
633 except ImportError:
654 except ImportError:
634 return None
655 return None
635
656
636 # File system features
657 # File system features
637
658
638 def checkfolding(path):
659 def checkfolding(path):
639 """
660 """
640 Check whether the given path is on a case-sensitive filesystem
661 Check whether the given path is on a case-sensitive filesystem
641
662
642 Requires a path (like /foo/.hg) ending with a foldable final
663 Requires a path (like /foo/.hg) ending with a foldable final
643 directory component.
664 directory component.
644 """
665 """
645 s1 = os.stat(path)
666 s1 = os.stat(path)
646 d, b = os.path.split(path)
667 d, b = os.path.split(path)
647 p2 = os.path.join(d, b.upper())
668 p2 = os.path.join(d, b.upper())
648 if path == p2:
669 if path == p2:
649 p2 = os.path.join(d, b.lower())
670 p2 = os.path.join(d, b.lower())
650 try:
671 try:
651 s2 = os.stat(p2)
672 s2 = os.stat(p2)
652 if s2 == s1:
673 if s2 == s1:
653 return False
674 return False
654 return True
675 return True
655 except:
676 except:
656 return True
677 return True
657
678
658 # Platform specific variants
679 # Platform specific variants
659 if os.name == 'nt':
680 if os.name == 'nt':
660 demandload(globals(), "msvcrt")
681 demandload(globals(), "msvcrt")
661 nulldev = 'NUL:'
682 nulldev = 'NUL:'
662
683
663 class winstdout:
684 class winstdout:
664 '''stdout on windows misbehaves if sent through a pipe'''
685 '''stdout on windows misbehaves if sent through a pipe'''
665
686
666 def __init__(self, fp):
687 def __init__(self, fp):
667 self.fp = fp
688 self.fp = fp
668
689
669 def __getattr__(self, key):
690 def __getattr__(self, key):
670 return getattr(self.fp, key)
691 return getattr(self.fp, key)
671
692
672 def close(self):
693 def close(self):
673 try:
694 try:
674 self.fp.close()
695 self.fp.close()
675 except: pass
696 except: pass
676
697
677 def write(self, s):
698 def write(self, s):
678 try:
699 try:
679 return self.fp.write(s)
700 return self.fp.write(s)
680 except IOError, inst:
701 except IOError, inst:
681 if inst.errno != 0: raise
702 if inst.errno != 0: raise
682 self.close()
703 self.close()
683 raise IOError(errno.EPIPE, 'Broken pipe')
704 raise IOError(errno.EPIPE, 'Broken pipe')
684
705
685 sys.stdout = winstdout(sys.stdout)
706 sys.stdout = winstdout(sys.stdout)
686
707
687 def system_rcpath():
708 def system_rcpath():
688 try:
709 try:
689 return system_rcpath_win32()
710 return system_rcpath_win32()
690 except:
711 except:
691 return [r'c:\mercurial\mercurial.ini']
712 return [r'c:\mercurial\mercurial.ini']
692
713
693 def os_rcpath():
714 def os_rcpath():
694 '''return default os-specific hgrc search path'''
715 '''return default os-specific hgrc search path'''
695 path = system_rcpath()
716 path = system_rcpath()
696 path.append(user_rcpath())
717 path.append(user_rcpath())
697 userprofile = os.environ.get('USERPROFILE')
718 userprofile = os.environ.get('USERPROFILE')
698 if userprofile:
719 if userprofile:
699 path.append(os.path.join(userprofile, 'mercurial.ini'))
720 path.append(os.path.join(userprofile, 'mercurial.ini'))
700 return path
721 return path
701
722
702 def user_rcpath():
723 def user_rcpath():
703 '''return os-specific hgrc search path to the user dir'''
724 '''return os-specific hgrc search path to the user dir'''
704 return os.path.join(os.path.expanduser('~'), 'mercurial.ini')
725 return os.path.join(os.path.expanduser('~'), 'mercurial.ini')
705
726
706 def parse_patch_output(output_line):
727 def parse_patch_output(output_line):
707 """parses the output produced by patch and returns the file name"""
728 """parses the output produced by patch and returns the file name"""
708 pf = output_line[14:]
729 pf = output_line[14:]
709 if pf[0] == '`':
730 if pf[0] == '`':
710 pf = pf[1:-1] # Remove the quotes
731 pf = pf[1:-1] # Remove the quotes
711 return pf
732 return pf
712
733
713 def testpid(pid):
734 def testpid(pid):
714 '''return False if pid dead, True if running or not known'''
735 '''return False if pid dead, True if running or not known'''
715 return True
736 return True
716
737
717 def is_exec(f, last):
738 def is_exec(f, last):
718 return last
739 return last
719
740
720 def set_exec(f, mode):
741 def set_exec(f, mode):
721 pass
742 pass
722
743
723 def set_binary(fd):
744 def set_binary(fd):
724 msvcrt.setmode(fd.fileno(), os.O_BINARY)
745 msvcrt.setmode(fd.fileno(), os.O_BINARY)
725
746
726 def pconvert(path):
747 def pconvert(path):
727 return path.replace("\\", "/")
748 return path.replace("\\", "/")
728
749
729 def localpath(path):
750 def localpath(path):
730 return path.replace('/', '\\')
751 return path.replace('/', '\\')
731
752
732 def normpath(path):
753 def normpath(path):
733 return pconvert(os.path.normpath(path))
754 return pconvert(os.path.normpath(path))
734
755
735 makelock = _makelock_file
756 makelock = _makelock_file
736 readlock = _readlock_file
757 readlock = _readlock_file
737
758
738 def samestat(s1, s2):
759 def samestat(s1, s2):
739 return False
760 return False
740
761
741 def shellquote(s):
762 def shellquote(s):
742 return '"%s"' % s.replace('"', '\\"')
763 return '"%s"' % s.replace('"', '\\"')
743
764
744 def explain_exit(code):
765 def explain_exit(code):
745 return _("exited with status %d") % code, code
766 return _("exited with status %d") % code, code
746
767
747 # if you change this stub into a real check, please try to implement the
768 # if you change this stub into a real check, please try to implement the
748 # username and groupname functions above, too.
769 # username and groupname functions above, too.
749 def isowner(fp, st=None):
770 def isowner(fp, st=None):
750 return True
771 return True
751
772
752 try:
773 try:
753 # override functions with win32 versions if possible
774 # override functions with win32 versions if possible
754 from util_win32 import *
775 from util_win32 import *
755 if not is_win_9x():
776 if not is_win_9x():
756 posixfile = posixfile_nt
777 posixfile = posixfile_nt
757 except ImportError:
778 except ImportError:
758 pass
779 pass
759
780
760 else:
781 else:
761 nulldev = '/dev/null'
782 nulldev = '/dev/null'
762
783
763 def rcfiles(path):
784 def rcfiles(path):
764 rcs = [os.path.join(path, 'hgrc')]
785 rcs = [os.path.join(path, 'hgrc')]
765 rcdir = os.path.join(path, 'hgrc.d')
786 rcdir = os.path.join(path, 'hgrc.d')
766 try:
787 try:
767 rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir)
788 rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir)
768 if f.endswith(".rc")])
789 if f.endswith(".rc")])
769 except OSError:
790 except OSError:
770 pass
791 pass
771 return rcs
792 return rcs
772
793
773 def os_rcpath():
794 def os_rcpath():
774 '''return default os-specific hgrc search path'''
795 '''return default os-specific hgrc search path'''
775 path = []
796 path = []
776 # old mod_python does not set sys.argv
797 # old mod_python does not set sys.argv
777 if len(getattr(sys, 'argv', [])) > 0:
798 if len(getattr(sys, 'argv', [])) > 0:
778 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
799 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
779 '/../etc/mercurial'))
800 '/../etc/mercurial'))
780 path.extend(rcfiles('/etc/mercurial'))
801 path.extend(rcfiles('/etc/mercurial'))
781 path.append(os.path.expanduser('~/.hgrc'))
802 path.append(os.path.expanduser('~/.hgrc'))
782 path = [os.path.normpath(f) for f in path]
803 path = [os.path.normpath(f) for f in path]
783 return path
804 return path
784
805
785 def parse_patch_output(output_line):
806 def parse_patch_output(output_line):
786 """parses the output produced by patch and returns the file name"""
807 """parses the output produced by patch and returns the file name"""
787 pf = output_line[14:]
808 pf = output_line[14:]
788 if pf.startswith("'") and pf.endswith("'") and " " in pf:
809 if pf.startswith("'") and pf.endswith("'") and " " in pf:
789 pf = pf[1:-1] # Remove the quotes
810 pf = pf[1:-1] # Remove the quotes
790 return pf
811 return pf
791
812
792 def is_exec(f, last):
813 def is_exec(f, last):
793 """check whether a file is executable"""
814 """check whether a file is executable"""
794 return (os.lstat(f).st_mode & 0100 != 0)
815 return (os.lstat(f).st_mode & 0100 != 0)
795
816
796 def set_exec(f, mode):
817 def set_exec(f, mode):
797 s = os.lstat(f).st_mode
818 s = os.lstat(f).st_mode
798 if (s & 0100 != 0) == mode:
819 if (s & 0100 != 0) == mode:
799 return
820 return
800 if mode:
821 if mode:
801 # Turn on +x for every +r bit when making a file executable
822 # Turn on +x for every +r bit when making a file executable
802 # and obey umask.
823 # and obey umask.
803 umask = os.umask(0)
824 umask = os.umask(0)
804 os.umask(umask)
825 os.umask(umask)
805 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
826 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
806 else:
827 else:
807 os.chmod(f, s & 0666)
828 os.chmod(f, s & 0666)
808
829
809 def set_binary(fd):
830 def set_binary(fd):
810 pass
831 pass
811
832
812 def pconvert(path):
833 def pconvert(path):
813 return path
834 return path
814
835
815 def localpath(path):
836 def localpath(path):
816 return path
837 return path
817
838
818 normpath = os.path.normpath
839 normpath = os.path.normpath
819 samestat = os.path.samestat
840 samestat = os.path.samestat
820
841
821 def makelock(info, pathname):
842 def makelock(info, pathname):
822 try:
843 try:
823 os.symlink(info, pathname)
844 os.symlink(info, pathname)
824 except OSError, why:
845 except OSError, why:
825 if why.errno == errno.EEXIST:
846 if why.errno == errno.EEXIST:
826 raise
847 raise
827 else:
848 else:
828 _makelock_file(info, pathname)
849 _makelock_file(info, pathname)
829
850
830 def readlock(pathname):
851 def readlock(pathname):
831 try:
852 try:
832 return os.readlink(pathname)
853 return os.readlink(pathname)
833 except OSError, why:
854 except OSError, why:
834 if why.errno == errno.EINVAL:
855 if why.errno == errno.EINVAL:
835 return _readlock_file(pathname)
856 return _readlock_file(pathname)
836 else:
857 else:
837 raise
858 raise
838
859
839 def shellquote(s):
860 def shellquote(s):
840 return "'%s'" % s.replace("'", "'\\''")
861 return "'%s'" % s.replace("'", "'\\''")
841
862
842 def testpid(pid):
863 def testpid(pid):
843 '''return False if pid dead, True if running or not sure'''
864 '''return False if pid dead, True if running or not sure'''
844 try:
865 try:
845 os.kill(pid, 0)
866 os.kill(pid, 0)
846 return True
867 return True
847 except OSError, inst:
868 except OSError, inst:
848 return inst.errno != errno.ESRCH
869 return inst.errno != errno.ESRCH
849
870
850 def explain_exit(code):
871 def explain_exit(code):
851 """return a 2-tuple (desc, code) describing a process's status"""
872 """return a 2-tuple (desc, code) describing a process's status"""
852 if os.WIFEXITED(code):
873 if os.WIFEXITED(code):
853 val = os.WEXITSTATUS(code)
874 val = os.WEXITSTATUS(code)
854 return _("exited with status %d") % val, val
875 return _("exited with status %d") % val, val
855 elif os.WIFSIGNALED(code):
876 elif os.WIFSIGNALED(code):
856 val = os.WTERMSIG(code)
877 val = os.WTERMSIG(code)
857 return _("killed by signal %d") % val, val
878 return _("killed by signal %d") % val, val
858 elif os.WIFSTOPPED(code):
879 elif os.WIFSTOPPED(code):
859 val = os.WSTOPSIG(code)
880 val = os.WSTOPSIG(code)
860 return _("stopped by signal %d") % val, val
881 return _("stopped by signal %d") % val, val
861 raise ValueError(_("invalid exit code"))
882 raise ValueError(_("invalid exit code"))
862
883
863 def isowner(fp, st=None):
884 def isowner(fp, st=None):
864 """Return True if the file object f belongs to the current user.
885 """Return True if the file object f belongs to the current user.
865
886
866 The return value of a util.fstat(f) may be passed as the st argument.
887 The return value of a util.fstat(f) may be passed as the st argument.
867 """
888 """
868 if st is None:
889 if st is None:
869 st = fstat(f)
890 st = fstat(f)
870 return st.st_uid == os.getuid()
891 return st.st_uid == os.getuid()
871
892
872
893
873 def opener(base, audit=True):
894 def opener(base, audit=True):
874 """
895 """
875 return a function that opens files relative to base
896 return a function that opens files relative to base
876
897
877 this function is used to hide the details of COW semantics and
898 this function is used to hide the details of COW semantics and
878 remote file access from higher level code.
899 remote file access from higher level code.
879 """
900 """
880 p = base
901 p = base
881 audit_p = audit
902 audit_p = audit
882
903
883 def mktempcopy(name):
904 def mktempcopy(name):
884 d, fn = os.path.split(name)
905 d, fn = os.path.split(name)
885 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
906 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
886 os.close(fd)
907 os.close(fd)
887 ofp = posixfile(temp, "wb")
908 ofp = posixfile(temp, "wb")
888 try:
909 try:
889 try:
910 try:
890 ifp = posixfile(name, "rb")
911 ifp = posixfile(name, "rb")
891 except IOError, inst:
912 except IOError, inst:
892 if not getattr(inst, 'filename', None):
913 if not getattr(inst, 'filename', None):
893 inst.filename = name
914 inst.filename = name
894 raise
915 raise
895 for chunk in filechunkiter(ifp):
916 for chunk in filechunkiter(ifp):
896 ofp.write(chunk)
917 ofp.write(chunk)
897 ifp.close()
918 ifp.close()
898 ofp.close()
919 ofp.close()
899 except:
920 except:
900 try: os.unlink(temp)
921 try: os.unlink(temp)
901 except: pass
922 except: pass
902 raise
923 raise
903 st = os.lstat(name)
924 st = os.lstat(name)
904 os.chmod(temp, st.st_mode)
925 os.chmod(temp, st.st_mode)
905 return temp
926 return temp
906
927
907 class atomictempfile(posixfile):
928 class atomictempfile(posixfile):
908 """the file will only be copied when rename is called"""
929 """the file will only be copied when rename is called"""
909 def __init__(self, name, mode):
930 def __init__(self, name, mode):
910 self.__name = name
931 self.__name = name
911 self.temp = mktempcopy(name)
932 self.temp = mktempcopy(name)
912 posixfile.__init__(self, self.temp, mode)
933 posixfile.__init__(self, self.temp, mode)
913 def rename(self):
934 def rename(self):
914 if not self.closed:
935 if not self.closed:
915 posixfile.close(self)
936 posixfile.close(self)
916 rename(self.temp, localpath(self.__name))
937 rename(self.temp, localpath(self.__name))
917 def __del__(self):
938 def __del__(self):
918 if not self.closed:
939 if not self.closed:
919 try:
940 try:
920 os.unlink(self.temp)
941 os.unlink(self.temp)
921 except: pass
942 except: pass
922 posixfile.close(self)
943 posixfile.close(self)
923
944
924 class atomicfile(atomictempfile):
945 class atomicfile(atomictempfile):
925 """the file will only be copied on close"""
946 """the file will only be copied on close"""
926 def __init__(self, name, mode):
947 def __init__(self, name, mode):
927 atomictempfile.__init__(self, name, mode)
948 atomictempfile.__init__(self, name, mode)
928 def close(self):
949 def close(self):
929 self.rename()
950 self.rename()
930 def __del__(self):
951 def __del__(self):
931 self.rename()
952 self.rename()
932
953
933 def o(path, mode="r", text=False, atomic=False, atomictemp=False):
954 def o(path, mode="r", text=False, atomic=False, atomictemp=False):
934 if audit_p:
955 if audit_p:
935 audit_path(path)
956 audit_path(path)
936 f = os.path.join(p, path)
957 f = os.path.join(p, path)
937
958
938 if not text:
959 if not text:
939 mode += "b" # for that other OS
960 mode += "b" # for that other OS
940
961
941 if mode[0] != "r":
962 if mode[0] != "r":
942 try:
963 try:
943 nlink = nlinks(f)
964 nlink = nlinks(f)
944 except OSError:
965 except OSError:
945 d = os.path.dirname(f)
966 d = os.path.dirname(f)
946 if not os.path.isdir(d):
967 if not os.path.isdir(d):
947 os.makedirs(d)
968 os.makedirs(d)
948 else:
969 else:
949 if atomic:
970 if atomic:
950 return atomicfile(f, mode)
971 return atomicfile(f, mode)
951 elif atomictemp:
972 elif atomictemp:
952 return atomictempfile(f, mode)
973 return atomictempfile(f, mode)
953 if nlink > 1:
974 if nlink > 1:
954 rename(mktempcopy(f), f)
975 rename(mktempcopy(f), f)
955 return posixfile(f, mode)
976 return posixfile(f, mode)
956
977
957 return o
978 return o
958
979
959 class chunkbuffer(object):
980 class chunkbuffer(object):
960 """Allow arbitrary sized chunks of data to be efficiently read from an
981 """Allow arbitrary sized chunks of data to be efficiently read from an
961 iterator over chunks of arbitrary size."""
982 iterator over chunks of arbitrary size."""
962
983
963 def __init__(self, in_iter, targetsize = 2**16):
984 def __init__(self, in_iter, targetsize = 2**16):
964 """in_iter is the iterator that's iterating over the input chunks.
985 """in_iter is the iterator that's iterating over the input chunks.
965 targetsize is how big a buffer to try to maintain."""
986 targetsize is how big a buffer to try to maintain."""
966 self.in_iter = iter(in_iter)
987 self.in_iter = iter(in_iter)
967 self.buf = ''
988 self.buf = ''
968 self.targetsize = int(targetsize)
989 self.targetsize = int(targetsize)
969 if self.targetsize <= 0:
990 if self.targetsize <= 0:
970 raise ValueError(_("targetsize must be greater than 0, was %d") %
991 raise ValueError(_("targetsize must be greater than 0, was %d") %
971 targetsize)
992 targetsize)
972 self.iterempty = False
993 self.iterempty = False
973
994
974 def fillbuf(self):
995 def fillbuf(self):
975 """Ignore target size; read every chunk from iterator until empty."""
996 """Ignore target size; read every chunk from iterator until empty."""
976 if not self.iterempty:
997 if not self.iterempty:
977 collector = cStringIO.StringIO()
998 collector = cStringIO.StringIO()
978 collector.write(self.buf)
999 collector.write(self.buf)
979 for ch in self.in_iter:
1000 for ch in self.in_iter:
980 collector.write(ch)
1001 collector.write(ch)
981 self.buf = collector.getvalue()
1002 self.buf = collector.getvalue()
982 self.iterempty = True
1003 self.iterempty = True
983
1004
984 def read(self, l):
1005 def read(self, l):
985 """Read L bytes of data from the iterator of chunks of data.
1006 """Read L bytes of data from the iterator of chunks of data.
986 Returns less than L bytes if the iterator runs dry."""
1007 Returns less than L bytes if the iterator runs dry."""
987 if l > len(self.buf) and not self.iterempty:
1008 if l > len(self.buf) and not self.iterempty:
988 # Clamp to a multiple of self.targetsize
1009 # Clamp to a multiple of self.targetsize
989 targetsize = self.targetsize * ((l // self.targetsize) + 1)
1010 targetsize = self.targetsize * ((l // self.targetsize) + 1)
990 collector = cStringIO.StringIO()
1011 collector = cStringIO.StringIO()
991 collector.write(self.buf)
1012 collector.write(self.buf)
992 collected = len(self.buf)
1013 collected = len(self.buf)
993 for chunk in self.in_iter:
1014 for chunk in self.in_iter:
994 collector.write(chunk)
1015 collector.write(chunk)
995 collected += len(chunk)
1016 collected += len(chunk)
996 if collected >= targetsize:
1017 if collected >= targetsize:
997 break
1018 break
998 if collected < targetsize:
1019 if collected < targetsize:
999 self.iterempty = True
1020 self.iterempty = True
1000 self.buf = collector.getvalue()
1021 self.buf = collector.getvalue()
1001 s, self.buf = self.buf[:l], buffer(self.buf, l)
1022 s, self.buf = self.buf[:l], buffer(self.buf, l)
1002 return s
1023 return s
1003
1024
1004 def filechunkiter(f, size=65536, limit=None):
1025 def filechunkiter(f, size=65536, limit=None):
1005 """Create a generator that produces the data in the file size
1026 """Create a generator that produces the data in the file size
1006 (default 65536) bytes at a time, up to optional limit (default is
1027 (default 65536) bytes at a time, up to optional limit (default is
1007 to read all data). Chunks may be less than size bytes if the
1028 to read all data). Chunks may be less than size bytes if the
1008 chunk is the last chunk in the file, or the file is a socket or
1029 chunk is the last chunk in the file, or the file is a socket or
1009 some other type of file that sometimes reads less data than is
1030 some other type of file that sometimes reads less data than is
1010 requested."""
1031 requested."""
1011 assert size >= 0
1032 assert size >= 0
1012 assert limit is None or limit >= 0
1033 assert limit is None or limit >= 0
1013 while True:
1034 while True:
1014 if limit is None: nbytes = size
1035 if limit is None: nbytes = size
1015 else: nbytes = min(limit, size)
1036 else: nbytes = min(limit, size)
1016 s = nbytes and f.read(nbytes)
1037 s = nbytes and f.read(nbytes)
1017 if not s: break
1038 if not s: break
1018 if limit: limit -= len(s)
1039 if limit: limit -= len(s)
1019 yield s
1040 yield s
1020
1041
1021 def makedate():
1042 def makedate():
1022 lt = time.localtime()
1043 lt = time.localtime()
1023 if lt[8] == 1 and time.daylight:
1044 if lt[8] == 1 and time.daylight:
1024 tz = time.altzone
1045 tz = time.altzone
1025 else:
1046 else:
1026 tz = time.timezone
1047 tz = time.timezone
1027 return time.mktime(lt), tz
1048 return time.mktime(lt), tz
1028
1049
1029 def datestr(date=None, format='%a %b %d %H:%M:%S %Y', timezone=True):
1050 def datestr(date=None, format='%a %b %d %H:%M:%S %Y', timezone=True):
1030 """represent a (unixtime, offset) tuple as a localized time.
1051 """represent a (unixtime, offset) tuple as a localized time.
1031 unixtime is seconds since the epoch, and offset is the time zone's
1052 unixtime is seconds since the epoch, and offset is the time zone's
1032 number of seconds away from UTC. if timezone is false, do not
1053 number of seconds away from UTC. if timezone is false, do not
1033 append time zone to string."""
1054 append time zone to string."""
1034 t, tz = date or makedate()
1055 t, tz = date or makedate()
1035 s = time.strftime(format, time.gmtime(float(t) - tz))
1056 s = time.strftime(format, time.gmtime(float(t) - tz))
1036 if timezone:
1057 if timezone:
1037 s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60))
1058 s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60))
1038 return s
1059 return s
1039
1060
1040 def strdate(string, format='%a %b %d %H:%M:%S %Y'):
1061 def strdate(string, format='%a %b %d %H:%M:%S %Y'):
1041 """parse a localized time string and return a (unixtime, offset) tuple.
1062 """parse a localized time string and return a (unixtime, offset) tuple.
1042 if the string cannot be parsed, ValueError is raised."""
1063 if the string cannot be parsed, ValueError is raised."""
1043 def hastimezone(string):
1064 def timezone(string):
1044 return (string[-4:].isdigit() and
1065 tz = string.split()[-1]
1045 (string[-5] == '+' or string[-5] == '-') and
1066 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1046 string[-6].isspace())
1067 tz = int(tz)
1068 offset = - 3600 * (tz / 100) - 60 * (tz % 100)
1069 return offset
1070 if tz == "GMT" or tz == "UTC":
1071 return 0
1072 return None
1047
1073
1048 # NOTE: unixtime = localunixtime + offset
1074 # NOTE: unixtime = localunixtime + offset
1049 if hastimezone(string):
1075 offset, date = timezone(string), string
1050 date, tz = string[:-6], string[-5:]
1076 if offset != None:
1051 tz = int(tz)
1077 date = " ".join(string.split()[:-1])
1052 offset = - 3600 * (tz / 100) - 60 * (tz % 100)
1078
1053 else:
1079 # add missing elements
1054 date, offset = string, None
1080 if '%y' not in format.lower():
1081 date += "@" + datestr(makedate(), "%Y", False)
1082 format += "@%Y"
1083 if '%m' not in format and '%b' not in format:
1084 date += "@" + datestr(makedate(), "%m", False)
1085 format += "@%m"
1086 if '%d' not in format:
1087 date += "@" + datestr(makedate(), "%d", False)
1088 format += "@%d"
1089
1055 timetuple = time.strptime(date, format)
1090 timetuple = time.strptime(date, format)
1056 localunixtime = int(calendar.timegm(timetuple))
1091 localunixtime = int(calendar.timegm(timetuple))
1057 if offset is None:
1092 if offset is None:
1058 # local timezone
1093 # local timezone
1059 unixtime = int(time.mktime(timetuple))
1094 unixtime = int(time.mktime(timetuple))
1060 offset = unixtime - localunixtime
1095 offset = unixtime - localunixtime
1061 else:
1096 else:
1062 unixtime = localunixtime + offset
1097 unixtime = localunixtime + offset
1063 return unixtime, offset
1098 return unixtime, offset
1064
1099
1065 def parsedate(string, formats=None):
1100 def parsedate(string, formats=None):
1066 """parse a localized time string and return a (unixtime, offset) tuple.
1101 """parse a localized time string and return a (unixtime, offset) tuple.
1067 The date may be a "unixtime offset" string or in one of the specified
1102 The date may be a "unixtime offset" string or in one of the specified
1068 formats."""
1103 formats."""
1104 if not string:
1105 return 0, 0
1069 if not formats:
1106 if not formats:
1070 formats = defaultdateformats
1107 formats = defaultdateformats
1108 string = string.strip()
1071 try:
1109 try:
1072 when, offset = map(int, string.split(' '))
1110 when, offset = map(int, string.split(' '))
1073 except ValueError:
1111 except ValueError:
1074 for format in formats:
1112 for format in formats:
1075 try:
1113 try:
1076 when, offset = strdate(string, format)
1114 when, offset = strdate(string, format)
1077 except ValueError:
1115 except ValueError:
1078 pass
1116 pass
1079 else:
1117 else:
1080 break
1118 break
1081 else:
1119 else:
1082 raise ValueError(_('invalid date: %r '
1120 raise Abort(_('invalid date: %r ') % string)
1083 'see hg(1) manual page for details')
1084 % string)
1085 # validate explicit (probably user-specified) date and
1121 # validate explicit (probably user-specified) date and
1086 # time zone offset. values must fit in signed 32 bits for
1122 # time zone offset. values must fit in signed 32 bits for
1087 # current 32-bit linux runtimes. timezones go from UTC-12
1123 # current 32-bit linux runtimes. timezones go from UTC-12
1088 # to UTC+14
1124 # to UTC+14
1089 if abs(when) > 0x7fffffff:
1125 if abs(when) > 0x7fffffff:
1090 raise ValueError(_('date exceeds 32 bits: %d') % when)
1126 raise Abort(_('date exceeds 32 bits: %d') % when)
1091 if offset < -50400 or offset > 43200:
1127 if offset < -50400 or offset > 43200:
1092 raise ValueError(_('impossible time zone offset: %d') % offset)
1128 raise Abort(_('impossible time zone offset: %d') % offset)
1093 return when, offset
1129 return when, offset
1094
1130
1095 def shortuser(user):
1131 def shortuser(user):
1096 """Return a short representation of a user name or email address."""
1132 """Return a short representation of a user name or email address."""
1097 f = user.find('@')
1133 f = user.find('@')
1098 if f >= 0:
1134 if f >= 0:
1099 user = user[:f]
1135 user = user[:f]
1100 f = user.find('<')
1136 f = user.find('<')
1101 if f >= 0:
1137 if f >= 0:
1102 user = user[f+1:]
1138 user = user[f+1:]
1103 f = user.find(' ')
1139 f = user.find(' ')
1104 if f >= 0:
1140 if f >= 0:
1105 user = user[:f]
1141 user = user[:f]
1106 f = user.find('.')
1142 f = user.find('.')
1107 if f >= 0:
1143 if f >= 0:
1108 user = user[:f]
1144 user = user[:f]
1109 return user
1145 return user
1110
1146
1111 def ellipsis(text, maxlength=400):
1147 def ellipsis(text, maxlength=400):
1112 """Trim string to at most maxlength (default: 400) characters."""
1148 """Trim string to at most maxlength (default: 400) characters."""
1113 if len(text) <= maxlength:
1149 if len(text) <= maxlength:
1114 return text
1150 return text
1115 else:
1151 else:
1116 return "%s..." % (text[:maxlength-3])
1152 return "%s..." % (text[:maxlength-3])
1117
1153
1118 def walkrepos(path):
1154 def walkrepos(path):
1119 '''yield every hg repository under path, recursively.'''
1155 '''yield every hg repository under path, recursively.'''
1120 def errhandler(err):
1156 def errhandler(err):
1121 if err.filename == path:
1157 if err.filename == path:
1122 raise err
1158 raise err
1123
1159
1124 for root, dirs, files in os.walk(path, onerror=errhandler):
1160 for root, dirs, files in os.walk(path, onerror=errhandler):
1125 for d in dirs:
1161 for d in dirs:
1126 if d == '.hg':
1162 if d == '.hg':
1127 yield root
1163 yield root
1128 dirs[:] = []
1164 dirs[:] = []
1129 break
1165 break
1130
1166
1131 _rcpath = None
1167 _rcpath = None
1132
1168
1133 def rcpath():
1169 def rcpath():
1134 '''return hgrc search path. if env var HGRCPATH is set, use it.
1170 '''return hgrc search path. if env var HGRCPATH is set, use it.
1135 for each item in path, if directory, use files ending in .rc,
1171 for each item in path, if directory, use files ending in .rc,
1136 else use item.
1172 else use item.
1137 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1173 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1138 if no HGRCPATH, use default os-specific path.'''
1174 if no HGRCPATH, use default os-specific path.'''
1139 global _rcpath
1175 global _rcpath
1140 if _rcpath is None:
1176 if _rcpath is None:
1141 if 'HGRCPATH' in os.environ:
1177 if 'HGRCPATH' in os.environ:
1142 _rcpath = []
1178 _rcpath = []
1143 for p in os.environ['HGRCPATH'].split(os.pathsep):
1179 for p in os.environ['HGRCPATH'].split(os.pathsep):
1144 if not p: continue
1180 if not p: continue
1145 if os.path.isdir(p):
1181 if os.path.isdir(p):
1146 for f in os.listdir(p):
1182 for f in os.listdir(p):
1147 if f.endswith('.rc'):
1183 if f.endswith('.rc'):
1148 _rcpath.append(os.path.join(p, f))
1184 _rcpath.append(os.path.join(p, f))
1149 else:
1185 else:
1150 _rcpath.append(p)
1186 _rcpath.append(p)
1151 else:
1187 else:
1152 _rcpath = os_rcpath()
1188 _rcpath = os_rcpath()
1153 return _rcpath
1189 return _rcpath
1154
1190
1155 def bytecount(nbytes):
1191 def bytecount(nbytes):
1156 '''return byte count formatted as readable string, with units'''
1192 '''return byte count formatted as readable string, with units'''
1157
1193
1158 units = (
1194 units = (
1159 (100, 1<<30, _('%.0f GB')),
1195 (100, 1<<30, _('%.0f GB')),
1160 (10, 1<<30, _('%.1f GB')),
1196 (10, 1<<30, _('%.1f GB')),
1161 (1, 1<<30, _('%.2f GB')),
1197 (1, 1<<30, _('%.2f GB')),
1162 (100, 1<<20, _('%.0f MB')),
1198 (100, 1<<20, _('%.0f MB')),
1163 (10, 1<<20, _('%.1f MB')),
1199 (10, 1<<20, _('%.1f MB')),
1164 (1, 1<<20, _('%.2f MB')),
1200 (1, 1<<20, _('%.2f MB')),
1165 (100, 1<<10, _('%.0f KB')),
1201 (100, 1<<10, _('%.0f KB')),
1166 (10, 1<<10, _('%.1f KB')),
1202 (10, 1<<10, _('%.1f KB')),
1167 (1, 1<<10, _('%.2f KB')),
1203 (1, 1<<10, _('%.2f KB')),
1168 (1, 1, _('%.0f bytes')),
1204 (1, 1, _('%.0f bytes')),
1169 )
1205 )
1170
1206
1171 for multiplier, divisor, format in units:
1207 for multiplier, divisor, format in units:
1172 if nbytes >= divisor * multiplier:
1208 if nbytes >= divisor * multiplier:
1173 return format % (nbytes / float(divisor))
1209 return format % (nbytes / float(divisor))
1174 return units[-1][2] % nbytes
1210 return units[-1][2] % nbytes
1175
1211
1176 def drop_scheme(scheme, path):
1212 def drop_scheme(scheme, path):
1177 sc = scheme + ':'
1213 sc = scheme + ':'
1178 if path.startswith(sc):
1214 if path.startswith(sc):
1179 path = path[len(sc):]
1215 path = path[len(sc):]
1180 if path.startswith('//'):
1216 if path.startswith('//'):
1181 path = path[2:]
1217 path = path[2:]
1182 return path
1218 return path
@@ -1,72 +1,67 b''
1 % commit date test
1 % commit date test
2 abort: impossible time zone offset: 4444444
2 abort: impossible time zone offset: 4444444
3 transaction abort!
3 transaction abort!
4 rollback completed
4 rollback completed
5 abort: invalid date: '1\t15.1' see hg(1) manual page for details
5 abort: invalid date: '1\t15.1'
6 transaction abort!
7 rollback completed
8 abort: invalid date: 'foo bar' see hg(1) manual page for details
9 transaction abort!
6 transaction abort!
10 rollback completed
7 rollback completed
11 abort: invalid date: ' 1 4444' see hg(1) manual page for details
8 abort: invalid date: 'foo bar'
12 transaction abort!
9 transaction abort!
13 rollback completed
10 rollback completed
14 abort: date exceeds 32 bits: 111111111111
11 nothing changed
15 transaction abort!
16 rollback completed
17 % partial commit test
12 % partial commit test
18 trouble committing bar!
13 trouble committing bar!
19 abort: No such file or directory: .../test/bar
14 abort: No such file or directory: .../test/bar
20 adding dir/file
15 adding dir/file
21 dir/file
16 dir/file
22 adding dir.file
17 adding dir.file
23 abort: no match under directory .../test/dir!
18 abort: no match under directory .../test/dir!
24 abort: no match under directory .../test/bleh!
19 abort: no match under directory .../test/bleh!
25 abort: no match under directory .../test/dir2!
20 abort: no match under directory .../test/dir2!
26 dir/file
21 dir/file
27 does-not-exist: No such file or directory
22 does-not-exist: No such file or directory
28 abort: file .../test/does-not-exist not found!
23 abort: file .../test/does-not-exist not found!
29 baz: unsupported file type (type is symbolic link)
24 baz: unsupported file type (type is symbolic link)
30 abort: can't commit .../test/baz: unsupported file type!
25 abort: can't commit .../test/baz: unsupported file type!
31 abort: file .../test/quux not tracked!
26 abort: file .../test/quux not tracked!
32 dir/file
27 dir/file
33 % partial subdir commit test
28 % partial subdir commit test
34 adding bar/bar
29 adding bar/bar
35 adding foo/foo
30 adding foo/foo
36 % subdir log 1
31 % subdir log 1
37 changeset: 0:6ef3cb06bb80
32 changeset: 0:6ef3cb06bb80
38 user: test
33 user: test
39 date: Mon Jan 12 13:46:40 1970 +0000
34 date: Mon Jan 12 13:46:40 1970 +0000
40 files: foo/foo
35 files: foo/foo
41 description:
36 description:
42 commit-subdir-1
37 commit-subdir-1
43
38
44
39
45 % subdir log 2
40 % subdir log 2
46 changeset: 1:f2e51572cf5a
41 changeset: 1:f2e51572cf5a
47 tag: tip
42 tag: tip
48 user: test
43 user: test
49 date: Mon Jan 12 13:46:41 1970 +0000
44 date: Mon Jan 12 13:46:41 1970 +0000
50 files: bar/bar
45 files: bar/bar
51 description:
46 description:
52 commit-subdir-2
47 commit-subdir-2
53
48
54
49
55 % full log
50 % full log
56 changeset: 1:f2e51572cf5a
51 changeset: 1:f2e51572cf5a
57 tag: tip
52 tag: tip
58 user: test
53 user: test
59 date: Mon Jan 12 13:46:41 1970 +0000
54 date: Mon Jan 12 13:46:41 1970 +0000
60 files: bar/bar
55 files: bar/bar
61 description:
56 description:
62 commit-subdir-2
57 commit-subdir-2
63
58
64
59
65 changeset: 0:6ef3cb06bb80
60 changeset: 0:6ef3cb06bb80
66 user: test
61 user: test
67 date: Mon Jan 12 13:46:40 1970 +0000
62 date: Mon Jan 12 13:46:40 1970 +0000
68 files: foo/foo
63 files: foo/foo
69 description:
64 description:
70 commit-subdir-1
65 commit-subdir-1
71
66
72
67
@@ -1,154 +1,155 b''
1 % Show all commands except debug commands
1 % Show all commands except debug commands
2 add
2 add
3 addremove
3 addremove
4 annotate
4 annotate
5 archive
5 archive
6 backout
6 backout
7 branch
7 branch
8 branches
8 branches
9 bundle
9 bundle
10 cat
10 cat
11 clone
11 clone
12 commit
12 commit
13 copy
13 copy
14 diff
14 diff
15 export
15 export
16 grep
16 grep
17 heads
17 heads
18 help
18 help
19 identify
19 identify
20 import
20 import
21 incoming
21 incoming
22 init
22 init
23 locate
23 locate
24 log
24 log
25 manifest
25 manifest
26 merge
26 merge
27 outgoing
27 outgoing
28 parents
28 parents
29 paths
29 paths
30 pull
30 pull
31 push
31 push
32 recover
32 recover
33 remove
33 remove
34 rename
34 rename
35 revert
35 revert
36 rollback
36 rollback
37 root
37 root
38 serve
38 serve
39 showconfig
39 showconfig
40 status
40 status
41 tag
41 tag
42 tags
42 tags
43 tip
43 tip
44 unbundle
44 unbundle
45 update
45 update
46 verify
46 verify
47 version
47 version
48
48
49 % Show all commands that start with "a"
49 % Show all commands that start with "a"
50 add
50 add
51 addremove
51 addremove
52 annotate
52 annotate
53 archive
53 archive
54
54
55 % Do not show debug commands if there are other candidates
55 % Do not show debug commands if there are other candidates
56 diff
56 diff
57
57
58 % Show debug commands if there are no other candidates
58 % Show debug commands if there are no other candidates
59 debugancestor
59 debugancestor
60 debugcheckstate
60 debugcheckstate
61 debugcomplete
61 debugcomplete
62 debugconfig
62 debugconfig
63 debugdata
63 debugdata
64 debugdate
64 debugindex
65 debugindex
65 debugindexdot
66 debugindexdot
66 debugrawcommit
67 debugrawcommit
67 debugrebuildstate
68 debugrebuildstate
68 debugrename
69 debugrename
69 debugsetparents
70 debugsetparents
70 debugstate
71 debugstate
71 debugwalk
72 debugwalk
72
73
73 % Do not show the alias of a debug command if there are other candidates
74 % Do not show the alias of a debug command if there are other candidates
74 % (this should hide rawcommit)
75 % (this should hide rawcommit)
75 recover
76 recover
76 remove
77 remove
77 rename
78 rename
78 revert
79 revert
79 rollback
80 rollback
80 root
81 root
81
82
82 % Show the alias of a debug command if there are no other candidates
83 % Show the alias of a debug command if there are no other candidates
83 rawcommit
84 rawcommit
84
85
85 % Show the global options
86 % Show the global options
86 --config
87 --config
87 --cwd
88 --cwd
88 --debug
89 --debug
89 --debugger
90 --debugger
90 --encoding
91 --encoding
91 --encodingmode
92 --encodingmode
92 --help
93 --help
93 --lsprof
94 --lsprof
94 --noninteractive
95 --noninteractive
95 --profile
96 --profile
96 --quiet
97 --quiet
97 --repository
98 --repository
98 --time
99 --time
99 --traceback
100 --traceback
100 --verbose
101 --verbose
101 --version
102 --version
102 -R
103 -R
103 -h
104 -h
104 -q
105 -q
105 -v
106 -v
106 -y
107 -y
107
108
108 % Show the options for the "serve" command
109 % Show the options for the "serve" command
109 --accesslog
110 --accesslog
110 --address
111 --address
111 --config
112 --config
112 --cwd
113 --cwd
113 --daemon
114 --daemon
114 --daemon-pipefds
115 --daemon-pipefds
115 --debug
116 --debug
116 --debugger
117 --debugger
117 --encoding
118 --encoding
118 --encodingmode
119 --encodingmode
119 --errorlog
120 --errorlog
120 --help
121 --help
121 --ipv6
122 --ipv6
122 --lsprof
123 --lsprof
123 --name
124 --name
124 --noninteractive
125 --noninteractive
125 --pid-file
126 --pid-file
126 --port
127 --port
127 --profile
128 --profile
128 --quiet
129 --quiet
129 --repository
130 --repository
130 --stdio
131 --stdio
131 --style
132 --style
132 --templates
133 --templates
133 --time
134 --time
134 --traceback
135 --traceback
135 --verbose
136 --verbose
136 --version
137 --version
137 --webdir-conf
138 --webdir-conf
138 -6
139 -6
139 -A
140 -A
140 -E
141 -E
141 -R
142 -R
142 -a
143 -a
143 -d
144 -d
144 -h
145 -h
145 -n
146 -n
146 -p
147 -p
147 -q
148 -q
148 -t
149 -t
149 -v
150 -v
150 -y
151 -y
151
152
152 % Show an error if we use --options with an ambiguous abbreviation
153 % Show an error if we use --options with an ambiguous abbreviation
153 hg: command 's' is ambiguous:
154 hg: command 's' is ambiguous:
154 serve showconfig status
155 serve showconfig status
@@ -1,23 +1,23 b''
1 reverting a
1 reverting a
2 changeset 3:107ce1ee2b43 backs out changeset 1:25a1420a55f8
2 changeset 3:107ce1ee2b43 backs out changeset 1:25a1420a55f8
3 merging with changeset 2:e6c3abc120e7
3 merging with changeset 2:e6c3abc120e7
4 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
5 (branch merge, don't forget to commit)
5 (branch merge, don't forget to commit)
6 abort: invalid date: 'should fail' see hg(1) manual page for details
6 abort: invalid date: 'should fail'
7 transaction abort!
7 transaction abort!
8 rollback completed
8 rollback completed
9 abort: date exceeds 32 bits: 100000000000000000
9 abort: date exceeds 32 bits: 100000000000000000
10 transaction abort!
10 transaction abort!
11 rollback completed
11 rollback completed
12 abort: impossible time zone offset: 1400000
12 abort: impossible time zone offset: 1400000
13 transaction abort!
13 transaction abort!
14 rollback completed
14 rollback completed
15 Sun Jan 15 13:30:00 2006 +0500
15 Sun Jan 15 13:30:00 2006 +0500
16 Sun Jan 15 13:30:00 2006 -0800
16 Sun Jan 15 13:30:00 2006 -0800
17 Sat Jul 15 13:30:00 2006 +0500
17 Sat Jul 15 13:30:00 2006 +0500
18 Sat Jul 15 13:30:00 2006 -0700
18 Sat Jul 15 13:30:00 2006 -0700
19 Sun Jun 11 00:26:40 2006 -0400
19 Sun Jun 11 00:26:40 2006 -0400
20 Sat Apr 15 13:30:00 2006 +0200
20 Sat Apr 15 13:30:00 2006 +0200
21 Sat Apr 15 13:30:00 2006 +0000
21 Sat Apr 15 13:30:00 2006 +0000
22 Wed Feb 01 13:00:30 2006 -0500
22 Wed Feb 01 13:00:30 2006 -0500
23 Wed Feb 01 13:00:30 2006 +0000
23 Wed Feb 01 13:00:30 2006 +0000
General Comments 0
You need to be logged in to leave comments. Login now