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