##// END OF EJS Templates
revset: report a parse error if a revset is not parsed completely (issue2654)
Bernhard Leiner -
r14496:ffcb7e4d stable
parent child Browse files
Show More
@@ -1,4757 +1,4757 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, difflib, time, tempfile
11 import os, re, sys, difflib, time, tempfile
12 import hg, util, revlog, extensions, copies, error, bookmarks
12 import hg, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, mdiff, url, encoding, templatekw, discovery
13 import patch, help, mdiff, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
15 import merge as mergemod
15 import merge as mergemod
16 import minirst, revset
16 import minirst, revset
17 import dagparser
17 import dagparser
18
18
19 # Commands start here, listed alphabetically
19 # Commands start here, listed alphabetically
20
20
21 def add(ui, repo, *pats, **opts):
21 def add(ui, repo, *pats, **opts):
22 """add the specified files on the next commit
22 """add the specified files on the next commit
23
23
24 Schedule files to be version controlled and added to the
24 Schedule files to be version controlled and added to the
25 repository.
25 repository.
26
26
27 The files will be added to the repository at the next commit. To
27 The files will be added to the repository at the next commit. To
28 undo an add before that, see :hg:`forget`.
28 undo an add before that, see :hg:`forget`.
29
29
30 If no names are given, add all files to the repository.
30 If no names are given, add all files to the repository.
31
31
32 .. container:: verbose
32 .. container:: verbose
33
33
34 An example showing how new (unknown) files are added
34 An example showing how new (unknown) files are added
35 automatically by :hg:`add`::
35 automatically by :hg:`add`::
36
36
37 $ ls
37 $ ls
38 foo.c
38 foo.c
39 $ hg status
39 $ hg status
40 ? foo.c
40 ? foo.c
41 $ hg add
41 $ hg add
42 adding foo.c
42 adding foo.c
43 $ hg status
43 $ hg status
44 A foo.c
44 A foo.c
45
45
46 Returns 0 if all files are successfully added.
46 Returns 0 if all files are successfully added.
47 """
47 """
48
48
49 m = cmdutil.match(repo, pats, opts)
49 m = cmdutil.match(repo, pats, opts)
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
51 opts.get('subrepos'), prefix="")
51 opts.get('subrepos'), prefix="")
52 return rejected and 1 or 0
52 return rejected and 1 or 0
53
53
54 def addremove(ui, repo, *pats, **opts):
54 def addremove(ui, repo, *pats, **opts):
55 """add all new files, delete all missing files
55 """add all new files, delete all missing files
56
56
57 Add all new files and remove all missing files from the
57 Add all new files and remove all missing files from the
58 repository.
58 repository.
59
59
60 New files are ignored if they match any of the patterns in
60 New files are ignored if they match any of the patterns in
61 ``.hgignore``. As with add, these changes take effect at the next
61 ``.hgignore``. As with add, these changes take effect at the next
62 commit.
62 commit.
63
63
64 Use the -s/--similarity option to detect renamed files. With a
64 Use the -s/--similarity option to detect renamed files. With a
65 parameter greater than 0, this compares every removed file with
65 parameter greater than 0, this compares every removed file with
66 every added file and records those similar enough as renames. This
66 every added file and records those similar enough as renames. This
67 option takes a percentage between 0 (disabled) and 100 (files must
67 option takes a percentage between 0 (disabled) and 100 (files must
68 be identical) as its parameter. Detecting renamed files this way
68 be identical) as its parameter. Detecting renamed files this way
69 can be expensive. After using this option, :hg:`status -C` can be
69 can be expensive. After using this option, :hg:`status -C` can be
70 used to check which files were identified as moved or renamed.
70 used to check which files were identified as moved or renamed.
71
71
72 Returns 0 if all files are successfully added.
72 Returns 0 if all files are successfully added.
73 """
73 """
74 try:
74 try:
75 sim = float(opts.get('similarity') or 100)
75 sim = float(opts.get('similarity') or 100)
76 except ValueError:
76 except ValueError:
77 raise util.Abort(_('similarity must be a number'))
77 raise util.Abort(_('similarity must be a number'))
78 if sim < 0 or sim > 100:
78 if sim < 0 or sim > 100:
79 raise util.Abort(_('similarity must be between 0 and 100'))
79 raise util.Abort(_('similarity must be between 0 and 100'))
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
81
81
82 def annotate(ui, repo, *pats, **opts):
82 def annotate(ui, repo, *pats, **opts):
83 """show changeset information by line for each file
83 """show changeset information by line for each file
84
84
85 List changes in files, showing the revision id responsible for
85 List changes in files, showing the revision id responsible for
86 each line
86 each line
87
87
88 This command is useful for discovering when a change was made and
88 This command is useful for discovering when a change was made and
89 by whom.
89 by whom.
90
90
91 Without the -a/--text option, annotate will avoid processing files
91 Without the -a/--text option, annotate will avoid processing files
92 it detects as binary. With -a, annotate will annotate the file
92 it detects as binary. With -a, annotate will annotate the file
93 anyway, although the results will probably be neither useful
93 anyway, although the results will probably be neither useful
94 nor desirable.
94 nor desirable.
95
95
96 Returns 0 on success.
96 Returns 0 on success.
97 """
97 """
98 if opts.get('follow'):
98 if opts.get('follow'):
99 # --follow is deprecated and now just an alias for -f/--file
99 # --follow is deprecated and now just an alias for -f/--file
100 # to mimic the behavior of Mercurial before version 1.5
100 # to mimic the behavior of Mercurial before version 1.5
101 opts['file'] = 1
101 opts['file'] = 1
102
102
103 datefunc = ui.quiet and util.shortdate or util.datestr
103 datefunc = ui.quiet and util.shortdate or util.datestr
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
105
105
106 if not pats:
106 if not pats:
107 raise util.Abort(_('at least one filename or pattern is required'))
107 raise util.Abort(_('at least one filename or pattern is required'))
108
108
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
110 ('number', lambda x: str(x[0].rev())),
110 ('number', lambda x: str(x[0].rev())),
111 ('changeset', lambda x: short(x[0].node())),
111 ('changeset', lambda x: short(x[0].node())),
112 ('date', getdate),
112 ('date', getdate),
113 ('file', lambda x: x[0].path()),
113 ('file', lambda x: x[0].path()),
114 ]
114 ]
115
115
116 if (not opts.get('user') and not opts.get('changeset')
116 if (not opts.get('user') and not opts.get('changeset')
117 and not opts.get('date') and not opts.get('file')):
117 and not opts.get('date') and not opts.get('file')):
118 opts['number'] = 1
118 opts['number'] = 1
119
119
120 linenumber = opts.get('line_number') is not None
120 linenumber = opts.get('line_number') is not None
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
123
123
124 funcmap = [func for op, func in opmap if opts.get(op)]
124 funcmap = [func for op, func in opmap if opts.get(op)]
125 if linenumber:
125 if linenumber:
126 lastfunc = funcmap[-1]
126 lastfunc = funcmap[-1]
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
128
128
129 ctx = cmdutil.revsingle(repo, opts.get('rev'))
129 ctx = cmdutil.revsingle(repo, opts.get('rev'))
130 m = cmdutil.match(repo, pats, opts)
130 m = cmdutil.match(repo, pats, opts)
131 follow = not opts.get('no_follow')
131 follow = not opts.get('no_follow')
132 for abs in ctx.walk(m):
132 for abs in ctx.walk(m):
133 fctx = ctx[abs]
133 fctx = ctx[abs]
134 if not opts.get('text') and util.binary(fctx.data()):
134 if not opts.get('text') and util.binary(fctx.data()):
135 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
135 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
136 continue
136 continue
137
137
138 lines = fctx.annotate(follow=follow, linenumber=linenumber)
138 lines = fctx.annotate(follow=follow, linenumber=linenumber)
139 pieces = []
139 pieces = []
140
140
141 for f in funcmap:
141 for f in funcmap:
142 l = [f(n) for n, dummy in lines]
142 l = [f(n) for n, dummy in lines]
143 if l:
143 if l:
144 sized = [(x, encoding.colwidth(x)) for x in l]
144 sized = [(x, encoding.colwidth(x)) for x in l]
145 ml = max([w for x, w in sized])
145 ml = max([w for x, w in sized])
146 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
146 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
147
147
148 if pieces:
148 if pieces:
149 for p, l in zip(zip(*pieces), lines):
149 for p, l in zip(zip(*pieces), lines):
150 ui.write("%s: %s" % (" ".join(p), l[1]))
150 ui.write("%s: %s" % (" ".join(p), l[1]))
151
151
152 def archive(ui, repo, dest, **opts):
152 def archive(ui, repo, dest, **opts):
153 '''create an unversioned archive of a repository revision
153 '''create an unversioned archive of a repository revision
154
154
155 By default, the revision used is the parent of the working
155 By default, the revision used is the parent of the working
156 directory; use -r/--rev to specify a different revision.
156 directory; use -r/--rev to specify a different revision.
157
157
158 The archive type is automatically detected based on file
158 The archive type is automatically detected based on file
159 extension (or override using -t/--type).
159 extension (or override using -t/--type).
160
160
161 Valid types are:
161 Valid types are:
162
162
163 :``files``: a directory full of files (default)
163 :``files``: a directory full of files (default)
164 :``tar``: tar archive, uncompressed
164 :``tar``: tar archive, uncompressed
165 :``tbz2``: tar archive, compressed using bzip2
165 :``tbz2``: tar archive, compressed using bzip2
166 :``tgz``: tar archive, compressed using gzip
166 :``tgz``: tar archive, compressed using gzip
167 :``uzip``: zip archive, uncompressed
167 :``uzip``: zip archive, uncompressed
168 :``zip``: zip archive, compressed using deflate
168 :``zip``: zip archive, compressed using deflate
169
169
170 The exact name of the destination archive or directory is given
170 The exact name of the destination archive or directory is given
171 using a format string; see :hg:`help export` for details.
171 using a format string; see :hg:`help export` for details.
172
172
173 Each member added to an archive file has a directory prefix
173 Each member added to an archive file has a directory prefix
174 prepended. Use -p/--prefix to specify a format string for the
174 prepended. Use -p/--prefix to specify a format string for the
175 prefix. The default is the basename of the archive, with suffixes
175 prefix. The default is the basename of the archive, with suffixes
176 removed.
176 removed.
177
177
178 Returns 0 on success.
178 Returns 0 on success.
179 '''
179 '''
180
180
181 ctx = cmdutil.revsingle(repo, opts.get('rev'))
181 ctx = cmdutil.revsingle(repo, opts.get('rev'))
182 if not ctx:
182 if not ctx:
183 raise util.Abort(_('no working directory: please specify a revision'))
183 raise util.Abort(_('no working directory: please specify a revision'))
184 node = ctx.node()
184 node = ctx.node()
185 dest = cmdutil.make_filename(repo, dest, node)
185 dest = cmdutil.make_filename(repo, dest, node)
186 if os.path.realpath(dest) == repo.root:
186 if os.path.realpath(dest) == repo.root:
187 raise util.Abort(_('repository root cannot be destination'))
187 raise util.Abort(_('repository root cannot be destination'))
188
188
189 kind = opts.get('type') or archival.guesskind(dest) or 'files'
189 kind = opts.get('type') or archival.guesskind(dest) or 'files'
190 prefix = opts.get('prefix')
190 prefix = opts.get('prefix')
191
191
192 if dest == '-':
192 if dest == '-':
193 if kind == 'files':
193 if kind == 'files':
194 raise util.Abort(_('cannot archive plain files to stdout'))
194 raise util.Abort(_('cannot archive plain files to stdout'))
195 dest = sys.stdout
195 dest = sys.stdout
196 if not prefix:
196 if not prefix:
197 prefix = os.path.basename(repo.root) + '-%h'
197 prefix = os.path.basename(repo.root) + '-%h'
198
198
199 prefix = cmdutil.make_filename(repo, prefix, node)
199 prefix = cmdutil.make_filename(repo, prefix, node)
200 matchfn = cmdutil.match(repo, [], opts)
200 matchfn = cmdutil.match(repo, [], opts)
201 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
201 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
202 matchfn, prefix, subrepos=opts.get('subrepos'))
202 matchfn, prefix, subrepos=opts.get('subrepos'))
203
203
204 def backout(ui, repo, node=None, rev=None, **opts):
204 def backout(ui, repo, node=None, rev=None, **opts):
205 '''reverse effect of earlier changeset
205 '''reverse effect of earlier changeset
206
206
207 Prepare a new changeset with the effect of REV undone in the
207 Prepare a new changeset with the effect of REV undone in the
208 current working directory.
208 current working directory.
209
209
210 If REV is the parent of the working directory, then this new changeset
210 If REV is the parent of the working directory, then this new changeset
211 is committed automatically. Otherwise, hg needs to merge the
211 is committed automatically. Otherwise, hg needs to merge the
212 changes and the merged result is left uncommitted.
212 changes and the merged result is left uncommitted.
213
213
214 By default, the pending changeset will have one parent,
214 By default, the pending changeset will have one parent,
215 maintaining a linear history. With --merge, the pending changeset
215 maintaining a linear history. With --merge, the pending changeset
216 will instead have two parents: the old parent of the working
216 will instead have two parents: the old parent of the working
217 directory and a new child of REV that simply undoes REV.
217 directory and a new child of REV that simply undoes REV.
218
218
219 Before version 1.7, the behavior without --merge was equivalent to
219 Before version 1.7, the behavior without --merge was equivalent to
220 specifying --merge followed by :hg:`update --clean .` to cancel
220 specifying --merge followed by :hg:`update --clean .` to cancel
221 the merge and leave the child of REV as a head to be merged
221 the merge and leave the child of REV as a head to be merged
222 separately.
222 separately.
223
223
224 See :hg:`help dates` for a list of formats valid for -d/--date.
224 See :hg:`help dates` for a list of formats valid for -d/--date.
225
225
226 Returns 0 on success.
226 Returns 0 on success.
227 '''
227 '''
228 if rev and node:
228 if rev and node:
229 raise util.Abort(_("please specify just one revision"))
229 raise util.Abort(_("please specify just one revision"))
230
230
231 if not rev:
231 if not rev:
232 rev = node
232 rev = node
233
233
234 if not rev:
234 if not rev:
235 raise util.Abort(_("please specify a revision to backout"))
235 raise util.Abort(_("please specify a revision to backout"))
236
236
237 date = opts.get('date')
237 date = opts.get('date')
238 if date:
238 if date:
239 opts['date'] = util.parsedate(date)
239 opts['date'] = util.parsedate(date)
240
240
241 cmdutil.bail_if_changed(repo)
241 cmdutil.bail_if_changed(repo)
242 node = cmdutil.revsingle(repo, rev).node()
242 node = cmdutil.revsingle(repo, rev).node()
243
243
244 op1, op2 = repo.dirstate.parents()
244 op1, op2 = repo.dirstate.parents()
245 a = repo.changelog.ancestor(op1, node)
245 a = repo.changelog.ancestor(op1, node)
246 if a != node:
246 if a != node:
247 raise util.Abort(_('cannot backout change on a different branch'))
247 raise util.Abort(_('cannot backout change on a different branch'))
248
248
249 p1, p2 = repo.changelog.parents(node)
249 p1, p2 = repo.changelog.parents(node)
250 if p1 == nullid:
250 if p1 == nullid:
251 raise util.Abort(_('cannot backout a change with no parents'))
251 raise util.Abort(_('cannot backout a change with no parents'))
252 if p2 != nullid:
252 if p2 != nullid:
253 if not opts.get('parent'):
253 if not opts.get('parent'):
254 raise util.Abort(_('cannot backout a merge changeset without '
254 raise util.Abort(_('cannot backout a merge changeset without '
255 '--parent'))
255 '--parent'))
256 p = repo.lookup(opts['parent'])
256 p = repo.lookup(opts['parent'])
257 if p not in (p1, p2):
257 if p not in (p1, p2):
258 raise util.Abort(_('%s is not a parent of %s') %
258 raise util.Abort(_('%s is not a parent of %s') %
259 (short(p), short(node)))
259 (short(p), short(node)))
260 parent = p
260 parent = p
261 else:
261 else:
262 if opts.get('parent'):
262 if opts.get('parent'):
263 raise util.Abort(_('cannot use --parent on non-merge changeset'))
263 raise util.Abort(_('cannot use --parent on non-merge changeset'))
264 parent = p1
264 parent = p1
265
265
266 # the backout should appear on the same branch
266 # the backout should appear on the same branch
267 branch = repo.dirstate.branch()
267 branch = repo.dirstate.branch()
268 hg.clean(repo, node, show_stats=False)
268 hg.clean(repo, node, show_stats=False)
269 repo.dirstate.setbranch(branch)
269 repo.dirstate.setbranch(branch)
270 revert_opts = opts.copy()
270 revert_opts = opts.copy()
271 revert_opts['date'] = None
271 revert_opts['date'] = None
272 revert_opts['all'] = True
272 revert_opts['all'] = True
273 revert_opts['rev'] = hex(parent)
273 revert_opts['rev'] = hex(parent)
274 revert_opts['no_backup'] = None
274 revert_opts['no_backup'] = None
275 revert(ui, repo, **revert_opts)
275 revert(ui, repo, **revert_opts)
276 if not opts.get('merge') and op1 != node:
276 if not opts.get('merge') and op1 != node:
277 try:
277 try:
278 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
278 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
279 return hg.update(repo, op1)
279 return hg.update(repo, op1)
280 finally:
280 finally:
281 ui.setconfig('ui', 'forcemerge', '')
281 ui.setconfig('ui', 'forcemerge', '')
282
282
283 commit_opts = opts.copy()
283 commit_opts = opts.copy()
284 commit_opts['addremove'] = False
284 commit_opts['addremove'] = False
285 if not commit_opts['message'] and not commit_opts['logfile']:
285 if not commit_opts['message'] and not commit_opts['logfile']:
286 # we don't translate commit messages
286 # we don't translate commit messages
287 commit_opts['message'] = "Backed out changeset %s" % short(node)
287 commit_opts['message'] = "Backed out changeset %s" % short(node)
288 commit_opts['force_editor'] = True
288 commit_opts['force_editor'] = True
289 commit(ui, repo, **commit_opts)
289 commit(ui, repo, **commit_opts)
290 def nice(node):
290 def nice(node):
291 return '%d:%s' % (repo.changelog.rev(node), short(node))
291 return '%d:%s' % (repo.changelog.rev(node), short(node))
292 ui.status(_('changeset %s backs out changeset %s\n') %
292 ui.status(_('changeset %s backs out changeset %s\n') %
293 (nice(repo.changelog.tip()), nice(node)))
293 (nice(repo.changelog.tip()), nice(node)))
294 if opts.get('merge') and op1 != node:
294 if opts.get('merge') and op1 != node:
295 hg.clean(repo, op1, show_stats=False)
295 hg.clean(repo, op1, show_stats=False)
296 ui.status(_('merging with changeset %s\n')
296 ui.status(_('merging with changeset %s\n')
297 % nice(repo.changelog.tip()))
297 % nice(repo.changelog.tip()))
298 try:
298 try:
299 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
299 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
300 return hg.merge(repo, hex(repo.changelog.tip()))
300 return hg.merge(repo, hex(repo.changelog.tip()))
301 finally:
301 finally:
302 ui.setconfig('ui', 'forcemerge', '')
302 ui.setconfig('ui', 'forcemerge', '')
303 return 0
303 return 0
304
304
305 def bisect(ui, repo, rev=None, extra=None, command=None,
305 def bisect(ui, repo, rev=None, extra=None, command=None,
306 reset=None, good=None, bad=None, skip=None, noupdate=None):
306 reset=None, good=None, bad=None, skip=None, noupdate=None):
307 """subdivision search of changesets
307 """subdivision search of changesets
308
308
309 This command helps to find changesets which introduce problems. To
309 This command helps to find changesets which introduce problems. To
310 use, mark the earliest changeset you know exhibits the problem as
310 use, mark the earliest changeset you know exhibits the problem as
311 bad, then mark the latest changeset which is free from the problem
311 bad, then mark the latest changeset which is free from the problem
312 as good. Bisect will update your working directory to a revision
312 as good. Bisect will update your working directory to a revision
313 for testing (unless the -U/--noupdate option is specified). Once
313 for testing (unless the -U/--noupdate option is specified). Once
314 you have performed tests, mark the working directory as good or
314 you have performed tests, mark the working directory as good or
315 bad, and bisect will either update to another candidate changeset
315 bad, and bisect will either update to another candidate changeset
316 or announce that it has found the bad revision.
316 or announce that it has found the bad revision.
317
317
318 As a shortcut, you can also use the revision argument to mark a
318 As a shortcut, you can also use the revision argument to mark a
319 revision as good or bad without checking it out first.
319 revision as good or bad without checking it out first.
320
320
321 If you supply a command, it will be used for automatic bisection.
321 If you supply a command, it will be used for automatic bisection.
322 Its exit status will be used to mark revisions as good or bad:
322 Its exit status will be used to mark revisions as good or bad:
323 status 0 means good, 125 means to skip the revision, 127
323 status 0 means good, 125 means to skip the revision, 127
324 (command not found) will abort the bisection, and any other
324 (command not found) will abort the bisection, and any other
325 non-zero exit status means the revision is bad.
325 non-zero exit status means the revision is bad.
326
326
327 Returns 0 on success.
327 Returns 0 on success.
328 """
328 """
329 def print_result(nodes, good):
329 def print_result(nodes, good):
330 displayer = cmdutil.show_changeset(ui, repo, {})
330 displayer = cmdutil.show_changeset(ui, repo, {})
331 if len(nodes) == 1:
331 if len(nodes) == 1:
332 # narrowed it down to a single revision
332 # narrowed it down to a single revision
333 if good:
333 if good:
334 ui.write(_("The first good revision is:\n"))
334 ui.write(_("The first good revision is:\n"))
335 else:
335 else:
336 ui.write(_("The first bad revision is:\n"))
336 ui.write(_("The first bad revision is:\n"))
337 displayer.show(repo[nodes[0]])
337 displayer.show(repo[nodes[0]])
338 parents = repo[nodes[0]].parents()
338 parents = repo[nodes[0]].parents()
339 if len(parents) > 1:
339 if len(parents) > 1:
340 side = good and state['bad'] or state['good']
340 side = good and state['bad'] or state['good']
341 num = len(set(i.node() for i in parents) & set(side))
341 num = len(set(i.node() for i in parents) & set(side))
342 if num == 1:
342 if num == 1:
343 common = parents[0].ancestor(parents[1])
343 common = parents[0].ancestor(parents[1])
344 ui.write(_('Not all ancestors of this changeset have been'
344 ui.write(_('Not all ancestors of this changeset have been'
345 ' checked.\nTo check the other ancestors, start'
345 ' checked.\nTo check the other ancestors, start'
346 ' from the common ancestor, %s.\n' % common))
346 ' from the common ancestor, %s.\n' % common))
347 else:
347 else:
348 # multiple possible revisions
348 # multiple possible revisions
349 if good:
349 if good:
350 ui.write(_("Due to skipped revisions, the first "
350 ui.write(_("Due to skipped revisions, the first "
351 "good revision could be any of:\n"))
351 "good revision could be any of:\n"))
352 else:
352 else:
353 ui.write(_("Due to skipped revisions, the first "
353 ui.write(_("Due to skipped revisions, the first "
354 "bad revision could be any of:\n"))
354 "bad revision could be any of:\n"))
355 for n in nodes:
355 for n in nodes:
356 displayer.show(repo[n])
356 displayer.show(repo[n])
357 displayer.close()
357 displayer.close()
358
358
359 def check_state(state, interactive=True):
359 def check_state(state, interactive=True):
360 if not state['good'] or not state['bad']:
360 if not state['good'] or not state['bad']:
361 if (good or bad or skip or reset) and interactive:
361 if (good or bad or skip or reset) and interactive:
362 return
362 return
363 if not state['good']:
363 if not state['good']:
364 raise util.Abort(_('cannot bisect (no known good revisions)'))
364 raise util.Abort(_('cannot bisect (no known good revisions)'))
365 else:
365 else:
366 raise util.Abort(_('cannot bisect (no known bad revisions)'))
366 raise util.Abort(_('cannot bisect (no known bad revisions)'))
367 return True
367 return True
368
368
369 # backward compatibility
369 # backward compatibility
370 if rev in "good bad reset init".split():
370 if rev in "good bad reset init".split():
371 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
371 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
372 cmd, rev, extra = rev, extra, None
372 cmd, rev, extra = rev, extra, None
373 if cmd == "good":
373 if cmd == "good":
374 good = True
374 good = True
375 elif cmd == "bad":
375 elif cmd == "bad":
376 bad = True
376 bad = True
377 else:
377 else:
378 reset = True
378 reset = True
379 elif extra or good + bad + skip + reset + bool(command) > 1:
379 elif extra or good + bad + skip + reset + bool(command) > 1:
380 raise util.Abort(_('incompatible arguments'))
380 raise util.Abort(_('incompatible arguments'))
381
381
382 if reset:
382 if reset:
383 p = repo.join("bisect.state")
383 p = repo.join("bisect.state")
384 if os.path.exists(p):
384 if os.path.exists(p):
385 os.unlink(p)
385 os.unlink(p)
386 return
386 return
387
387
388 state = hbisect.load_state(repo)
388 state = hbisect.load_state(repo)
389
389
390 if command:
390 if command:
391 changesets = 1
391 changesets = 1
392 try:
392 try:
393 while changesets:
393 while changesets:
394 # update state
394 # update state
395 status = util.system(command)
395 status = util.system(command)
396 if status == 125:
396 if status == 125:
397 transition = "skip"
397 transition = "skip"
398 elif status == 0:
398 elif status == 0:
399 transition = "good"
399 transition = "good"
400 # status < 0 means process was killed
400 # status < 0 means process was killed
401 elif status == 127:
401 elif status == 127:
402 raise util.Abort(_("failed to execute %s") % command)
402 raise util.Abort(_("failed to execute %s") % command)
403 elif status < 0:
403 elif status < 0:
404 raise util.Abort(_("%s killed") % command)
404 raise util.Abort(_("%s killed") % command)
405 else:
405 else:
406 transition = "bad"
406 transition = "bad"
407 ctx = cmdutil.revsingle(repo, rev)
407 ctx = cmdutil.revsingle(repo, rev)
408 rev = None # clear for future iterations
408 rev = None # clear for future iterations
409 state[transition].append(ctx.node())
409 state[transition].append(ctx.node())
410 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
410 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
411 check_state(state, interactive=False)
411 check_state(state, interactive=False)
412 # bisect
412 # bisect
413 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
413 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
414 # update to next check
414 # update to next check
415 cmdutil.bail_if_changed(repo)
415 cmdutil.bail_if_changed(repo)
416 hg.clean(repo, nodes[0], show_stats=False)
416 hg.clean(repo, nodes[0], show_stats=False)
417 finally:
417 finally:
418 hbisect.save_state(repo, state)
418 hbisect.save_state(repo, state)
419 print_result(nodes, good)
419 print_result(nodes, good)
420 return
420 return
421
421
422 # update state
422 # update state
423
423
424 if rev:
424 if rev:
425 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
425 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
426 else:
426 else:
427 nodes = [repo.lookup('.')]
427 nodes = [repo.lookup('.')]
428
428
429 if good or bad or skip:
429 if good or bad or skip:
430 if good:
430 if good:
431 state['good'] += nodes
431 state['good'] += nodes
432 elif bad:
432 elif bad:
433 state['bad'] += nodes
433 state['bad'] += nodes
434 elif skip:
434 elif skip:
435 state['skip'] += nodes
435 state['skip'] += nodes
436 hbisect.save_state(repo, state)
436 hbisect.save_state(repo, state)
437
437
438 if not check_state(state):
438 if not check_state(state):
439 return
439 return
440
440
441 # actually bisect
441 # actually bisect
442 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
442 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
443 if changesets == 0:
443 if changesets == 0:
444 print_result(nodes, good)
444 print_result(nodes, good)
445 else:
445 else:
446 assert len(nodes) == 1 # only a single node can be tested next
446 assert len(nodes) == 1 # only a single node can be tested next
447 node = nodes[0]
447 node = nodes[0]
448 # compute the approximate number of remaining tests
448 # compute the approximate number of remaining tests
449 tests, size = 0, 2
449 tests, size = 0, 2
450 while size <= changesets:
450 while size <= changesets:
451 tests, size = tests + 1, size * 2
451 tests, size = tests + 1, size * 2
452 rev = repo.changelog.rev(node)
452 rev = repo.changelog.rev(node)
453 ui.write(_("Testing changeset %d:%s "
453 ui.write(_("Testing changeset %d:%s "
454 "(%d changesets remaining, ~%d tests)\n")
454 "(%d changesets remaining, ~%d tests)\n")
455 % (rev, short(node), changesets, tests))
455 % (rev, short(node), changesets, tests))
456 if not noupdate:
456 if not noupdate:
457 cmdutil.bail_if_changed(repo)
457 cmdutil.bail_if_changed(repo)
458 return hg.clean(repo, node)
458 return hg.clean(repo, node)
459
459
460 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
460 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
461 '''track a line of development with movable markers
461 '''track a line of development with movable markers
462
462
463 Bookmarks are pointers to certain commits that move when
463 Bookmarks are pointers to certain commits that move when
464 committing. Bookmarks are local. They can be renamed, copied and
464 committing. Bookmarks are local. They can be renamed, copied and
465 deleted. It is possible to use bookmark names in :hg:`merge` and
465 deleted. It is possible to use bookmark names in :hg:`merge` and
466 :hg:`update` to merge and update respectively to a given bookmark.
466 :hg:`update` to merge and update respectively to a given bookmark.
467
467
468 You can use :hg:`bookmark NAME` to set a bookmark on the working
468 You can use :hg:`bookmark NAME` to set a bookmark on the working
469 directory's parent revision with the given name. If you specify
469 directory's parent revision with the given name. If you specify
470 a revision using -r REV (where REV may be an existing bookmark),
470 a revision using -r REV (where REV may be an existing bookmark),
471 the bookmark is assigned to that revision.
471 the bookmark is assigned to that revision.
472
472
473 Bookmarks can be pushed and pulled between repositories (see :hg:`help
473 Bookmarks can be pushed and pulled between repositories (see :hg:`help
474 push` and :hg:`help pull`). This requires both the local and remote
474 push` and :hg:`help pull`). This requires both the local and remote
475 repositories to support bookmarks. For versions prior to 1.8, this means
475 repositories to support bookmarks. For versions prior to 1.8, this means
476 the bookmarks extension must be enabled.
476 the bookmarks extension must be enabled.
477 '''
477 '''
478 hexfn = ui.debugflag and hex or short
478 hexfn = ui.debugflag and hex or short
479 marks = repo._bookmarks
479 marks = repo._bookmarks
480 cur = repo.changectx('.').node()
480 cur = repo.changectx('.').node()
481
481
482 if rename:
482 if rename:
483 if rename not in marks:
483 if rename not in marks:
484 raise util.Abort(_("a bookmark of this name does not exist"))
484 raise util.Abort(_("a bookmark of this name does not exist"))
485 if mark in marks and not force:
485 if mark in marks and not force:
486 raise util.Abort(_("a bookmark of the same name already exists"))
486 raise util.Abort(_("a bookmark of the same name already exists"))
487 if mark is None:
487 if mark is None:
488 raise util.Abort(_("new bookmark name required"))
488 raise util.Abort(_("new bookmark name required"))
489 marks[mark] = marks[rename]
489 marks[mark] = marks[rename]
490 if repo._bookmarkcurrent == rename:
490 if repo._bookmarkcurrent == rename:
491 bookmarks.setcurrent(repo, mark)
491 bookmarks.setcurrent(repo, mark)
492 del marks[rename]
492 del marks[rename]
493 bookmarks.write(repo)
493 bookmarks.write(repo)
494 return
494 return
495
495
496 if delete:
496 if delete:
497 if mark is None:
497 if mark is None:
498 raise util.Abort(_("bookmark name required"))
498 raise util.Abort(_("bookmark name required"))
499 if mark not in marks:
499 if mark not in marks:
500 raise util.Abort(_("a bookmark of this name does not exist"))
500 raise util.Abort(_("a bookmark of this name does not exist"))
501 if mark == repo._bookmarkcurrent:
501 if mark == repo._bookmarkcurrent:
502 bookmarks.setcurrent(repo, None)
502 bookmarks.setcurrent(repo, None)
503 del marks[mark]
503 del marks[mark]
504 bookmarks.write(repo)
504 bookmarks.write(repo)
505 return
505 return
506
506
507 if mark is not None:
507 if mark is not None:
508 if "\n" in mark:
508 if "\n" in mark:
509 raise util.Abort(_("bookmark name cannot contain newlines"))
509 raise util.Abort(_("bookmark name cannot contain newlines"))
510 mark = mark.strip()
510 mark = mark.strip()
511 if not mark:
511 if not mark:
512 raise util.Abort(_("bookmark names cannot consist entirely of "
512 raise util.Abort(_("bookmark names cannot consist entirely of "
513 "whitespace"))
513 "whitespace"))
514 if mark in marks and not force:
514 if mark in marks and not force:
515 raise util.Abort(_("a bookmark of the same name already exists"))
515 raise util.Abort(_("a bookmark of the same name already exists"))
516 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
516 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
517 and not force):
517 and not force):
518 raise util.Abort(
518 raise util.Abort(
519 _("a bookmark cannot have the name of an existing branch"))
519 _("a bookmark cannot have the name of an existing branch"))
520 if rev:
520 if rev:
521 marks[mark] = repo.lookup(rev)
521 marks[mark] = repo.lookup(rev)
522 else:
522 else:
523 marks[mark] = repo.changectx('.').node()
523 marks[mark] = repo.changectx('.').node()
524 if repo.changectx('.').node() == marks[mark]:
524 if repo.changectx('.').node() == marks[mark]:
525 bookmarks.setcurrent(repo, mark)
525 bookmarks.setcurrent(repo, mark)
526 bookmarks.write(repo)
526 bookmarks.write(repo)
527 return
527 return
528
528
529 if mark is None:
529 if mark is None:
530 if rev:
530 if rev:
531 raise util.Abort(_("bookmark name required"))
531 raise util.Abort(_("bookmark name required"))
532 if len(marks) == 0:
532 if len(marks) == 0:
533 ui.status(_("no bookmarks set\n"))
533 ui.status(_("no bookmarks set\n"))
534 else:
534 else:
535 for bmark, n in sorted(marks.iteritems()):
535 for bmark, n in sorted(marks.iteritems()):
536 current = repo._bookmarkcurrent
536 current = repo._bookmarkcurrent
537 if bmark == current and n == cur:
537 if bmark == current and n == cur:
538 prefix, label = '*', 'bookmarks.current'
538 prefix, label = '*', 'bookmarks.current'
539 else:
539 else:
540 prefix, label = ' ', ''
540 prefix, label = ' ', ''
541
541
542 if ui.quiet:
542 if ui.quiet:
543 ui.write("%s\n" % bmark, label=label)
543 ui.write("%s\n" % bmark, label=label)
544 else:
544 else:
545 ui.write(" %s %-25s %d:%s\n" % (
545 ui.write(" %s %-25s %d:%s\n" % (
546 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
546 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
547 label=label)
547 label=label)
548 return
548 return
549
549
550 def branch(ui, repo, label=None, **opts):
550 def branch(ui, repo, label=None, **opts):
551 """set or show the current branch name
551 """set or show the current branch name
552
552
553 With no argument, show the current branch name. With one argument,
553 With no argument, show the current branch name. With one argument,
554 set the working directory branch name (the branch will not exist
554 set the working directory branch name (the branch will not exist
555 in the repository until the next commit). Standard practice
555 in the repository until the next commit). Standard practice
556 recommends that primary development take place on the 'default'
556 recommends that primary development take place on the 'default'
557 branch.
557 branch.
558
558
559 Unless -f/--force is specified, branch will not let you set a
559 Unless -f/--force is specified, branch will not let you set a
560 branch name that already exists, even if it's inactive.
560 branch name that already exists, even if it's inactive.
561
561
562 Use -C/--clean to reset the working directory branch to that of
562 Use -C/--clean to reset the working directory branch to that of
563 the parent of the working directory, negating a previous branch
563 the parent of the working directory, negating a previous branch
564 change.
564 change.
565
565
566 Use the command :hg:`update` to switch to an existing branch. Use
566 Use the command :hg:`update` to switch to an existing branch. Use
567 :hg:`commit --close-branch` to mark this branch as closed.
567 :hg:`commit --close-branch` to mark this branch as closed.
568
568
569 Returns 0 on success.
569 Returns 0 on success.
570 """
570 """
571
571
572 if opts.get('clean'):
572 if opts.get('clean'):
573 label = repo[None].parents()[0].branch()
573 label = repo[None].parents()[0].branch()
574 repo.dirstate.setbranch(label)
574 repo.dirstate.setbranch(label)
575 ui.status(_('reset working directory to branch %s\n') % label)
575 ui.status(_('reset working directory to branch %s\n') % label)
576 elif label:
576 elif label:
577 if not opts.get('force') and label in repo.branchtags():
577 if not opts.get('force') and label in repo.branchtags():
578 if label not in [p.branch() for p in repo.parents()]:
578 if label not in [p.branch() for p in repo.parents()]:
579 raise util.Abort(_('a branch of the same name already exists'
579 raise util.Abort(_('a branch of the same name already exists'
580 " (use 'hg update' to switch to it)"))
580 " (use 'hg update' to switch to it)"))
581 repo.dirstate.setbranch(label)
581 repo.dirstate.setbranch(label)
582 ui.status(_('marked working directory as branch %s\n') % label)
582 ui.status(_('marked working directory as branch %s\n') % label)
583 else:
583 else:
584 ui.write("%s\n" % repo.dirstate.branch())
584 ui.write("%s\n" % repo.dirstate.branch())
585
585
586 def branches(ui, repo, active=False, closed=False):
586 def branches(ui, repo, active=False, closed=False):
587 """list repository named branches
587 """list repository named branches
588
588
589 List the repository's named branches, indicating which ones are
589 List the repository's named branches, indicating which ones are
590 inactive. If -c/--closed is specified, also list branches which have
590 inactive. If -c/--closed is specified, also list branches which have
591 been marked closed (see :hg:`commit --close-branch`).
591 been marked closed (see :hg:`commit --close-branch`).
592
592
593 If -a/--active is specified, only show active branches. A branch
593 If -a/--active is specified, only show active branches. A branch
594 is considered active if it contains repository heads.
594 is considered active if it contains repository heads.
595
595
596 Use the command :hg:`update` to switch to an existing branch.
596 Use the command :hg:`update` to switch to an existing branch.
597
597
598 Returns 0.
598 Returns 0.
599 """
599 """
600
600
601 hexfunc = ui.debugflag and hex or short
601 hexfunc = ui.debugflag and hex or short
602 activebranches = [repo[n].branch() for n in repo.heads()]
602 activebranches = [repo[n].branch() for n in repo.heads()]
603 def testactive(tag, node):
603 def testactive(tag, node):
604 realhead = tag in activebranches
604 realhead = tag in activebranches
605 open = node in repo.branchheads(tag, closed=False)
605 open = node in repo.branchheads(tag, closed=False)
606 return realhead and open
606 return realhead and open
607 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
607 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
608 for tag, node in repo.branchtags().items()],
608 for tag, node in repo.branchtags().items()],
609 reverse=True)
609 reverse=True)
610
610
611 for isactive, node, tag in branches:
611 for isactive, node, tag in branches:
612 if (not active) or isactive:
612 if (not active) or isactive:
613 if ui.quiet:
613 if ui.quiet:
614 ui.write("%s\n" % tag)
614 ui.write("%s\n" % tag)
615 else:
615 else:
616 hn = repo.lookup(node)
616 hn = repo.lookup(node)
617 if isactive:
617 if isactive:
618 label = 'branches.active'
618 label = 'branches.active'
619 notice = ''
619 notice = ''
620 elif hn not in repo.branchheads(tag, closed=False):
620 elif hn not in repo.branchheads(tag, closed=False):
621 if not closed:
621 if not closed:
622 continue
622 continue
623 label = 'branches.closed'
623 label = 'branches.closed'
624 notice = _(' (closed)')
624 notice = _(' (closed)')
625 else:
625 else:
626 label = 'branches.inactive'
626 label = 'branches.inactive'
627 notice = _(' (inactive)')
627 notice = _(' (inactive)')
628 if tag == repo.dirstate.branch():
628 if tag == repo.dirstate.branch():
629 label = 'branches.current'
629 label = 'branches.current'
630 rev = str(node).rjust(31 - encoding.colwidth(tag))
630 rev = str(node).rjust(31 - encoding.colwidth(tag))
631 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
631 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
632 tag = ui.label(tag, label)
632 tag = ui.label(tag, label)
633 ui.write("%s %s%s\n" % (tag, rev, notice))
633 ui.write("%s %s%s\n" % (tag, rev, notice))
634
634
635 def bundle(ui, repo, fname, dest=None, **opts):
635 def bundle(ui, repo, fname, dest=None, **opts):
636 """create a changegroup file
636 """create a changegroup file
637
637
638 Generate a compressed changegroup file collecting changesets not
638 Generate a compressed changegroup file collecting changesets not
639 known to be in another repository.
639 known to be in another repository.
640
640
641 If you omit the destination repository, then hg assumes the
641 If you omit the destination repository, then hg assumes the
642 destination will have all the nodes you specify with --base
642 destination will have all the nodes you specify with --base
643 parameters. To create a bundle containing all changesets, use
643 parameters. To create a bundle containing all changesets, use
644 -a/--all (or --base null).
644 -a/--all (or --base null).
645
645
646 You can change compression method with the -t/--type option.
646 You can change compression method with the -t/--type option.
647 The available compression methods are: none, bzip2, and
647 The available compression methods are: none, bzip2, and
648 gzip (by default, bundles are compressed using bzip2).
648 gzip (by default, bundles are compressed using bzip2).
649
649
650 The bundle file can then be transferred using conventional means
650 The bundle file can then be transferred using conventional means
651 and applied to another repository with the unbundle or pull
651 and applied to another repository with the unbundle or pull
652 command. This is useful when direct push and pull are not
652 command. This is useful when direct push and pull are not
653 available or when exporting an entire repository is undesirable.
653 available or when exporting an entire repository is undesirable.
654
654
655 Applying bundles preserves all changeset contents including
655 Applying bundles preserves all changeset contents including
656 permissions, copy/rename information, and revision history.
656 permissions, copy/rename information, and revision history.
657
657
658 Returns 0 on success, 1 if no changes found.
658 Returns 0 on success, 1 if no changes found.
659 """
659 """
660 revs = None
660 revs = None
661 if 'rev' in opts:
661 if 'rev' in opts:
662 revs = cmdutil.revrange(repo, opts['rev'])
662 revs = cmdutil.revrange(repo, opts['rev'])
663
663
664 if opts.get('all'):
664 if opts.get('all'):
665 base = ['null']
665 base = ['null']
666 else:
666 else:
667 base = cmdutil.revrange(repo, opts.get('base'))
667 base = cmdutil.revrange(repo, opts.get('base'))
668 if base:
668 if base:
669 if dest:
669 if dest:
670 raise util.Abort(_("--base is incompatible with specifying "
670 raise util.Abort(_("--base is incompatible with specifying "
671 "a destination"))
671 "a destination"))
672 base = [repo.lookup(rev) for rev in base]
672 base = [repo.lookup(rev) for rev in base]
673 # create the right base
673 # create the right base
674 # XXX: nodesbetween / changegroup* should be "fixed" instead
674 # XXX: nodesbetween / changegroup* should be "fixed" instead
675 o = []
675 o = []
676 has = set((nullid,))
676 has = set((nullid,))
677 for n in base:
677 for n in base:
678 has.update(repo.changelog.reachable(n))
678 has.update(repo.changelog.reachable(n))
679 if revs:
679 if revs:
680 revs = [repo.lookup(rev) for rev in revs]
680 revs = [repo.lookup(rev) for rev in revs]
681 visit = revs[:]
681 visit = revs[:]
682 has.difference_update(visit)
682 has.difference_update(visit)
683 else:
683 else:
684 visit = repo.changelog.heads()
684 visit = repo.changelog.heads()
685 seen = {}
685 seen = {}
686 while visit:
686 while visit:
687 n = visit.pop(0)
687 n = visit.pop(0)
688 parents = [p for p in repo.changelog.parents(n) if p not in has]
688 parents = [p for p in repo.changelog.parents(n) if p not in has]
689 if len(parents) == 0:
689 if len(parents) == 0:
690 if n not in has:
690 if n not in has:
691 o.append(n)
691 o.append(n)
692 else:
692 else:
693 for p in parents:
693 for p in parents:
694 if p not in seen:
694 if p not in seen:
695 seen[p] = 1
695 seen[p] = 1
696 visit.append(p)
696 visit.append(p)
697 else:
697 else:
698 dest = ui.expandpath(dest or 'default-push', dest or 'default')
698 dest = ui.expandpath(dest or 'default-push', dest or 'default')
699 dest, branches = hg.parseurl(dest, opts.get('branch'))
699 dest, branches = hg.parseurl(dest, opts.get('branch'))
700 other = hg.repository(hg.remoteui(repo, opts), dest)
700 other = hg.repository(hg.remoteui(repo, opts), dest)
701 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
701 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
702 if revs:
702 if revs:
703 revs = [repo.lookup(rev) for rev in revs]
703 revs = [repo.lookup(rev) for rev in revs]
704 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
704 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
705
705
706 if not o:
706 if not o:
707 ui.status(_("no changes found\n"))
707 ui.status(_("no changes found\n"))
708 return 1
708 return 1
709
709
710 if revs:
710 if revs:
711 cg = repo.changegroupsubset(o, revs, 'bundle')
711 cg = repo.changegroupsubset(o, revs, 'bundle')
712 else:
712 else:
713 cg = repo.changegroup(o, 'bundle')
713 cg = repo.changegroup(o, 'bundle')
714
714
715 bundletype = opts.get('type', 'bzip2').lower()
715 bundletype = opts.get('type', 'bzip2').lower()
716 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
716 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
717 bundletype = btypes.get(bundletype)
717 bundletype = btypes.get(bundletype)
718 if bundletype not in changegroup.bundletypes:
718 if bundletype not in changegroup.bundletypes:
719 raise util.Abort(_('unknown bundle type specified with --type'))
719 raise util.Abort(_('unknown bundle type specified with --type'))
720
720
721 changegroup.writebundle(cg, fname, bundletype)
721 changegroup.writebundle(cg, fname, bundletype)
722
722
723 def cat(ui, repo, file1, *pats, **opts):
723 def cat(ui, repo, file1, *pats, **opts):
724 """output the current or given revision of files
724 """output the current or given revision of files
725
725
726 Print the specified files as they were at the given revision. If
726 Print the specified files as they were at the given revision. If
727 no revision is given, the parent of the working directory is used,
727 no revision is given, the parent of the working directory is used,
728 or tip if no revision is checked out.
728 or tip if no revision is checked out.
729
729
730 Output may be to a file, in which case the name of the file is
730 Output may be to a file, in which case the name of the file is
731 given using a format string. The formatting rules are the same as
731 given using a format string. The formatting rules are the same as
732 for the export command, with the following additions:
732 for the export command, with the following additions:
733
733
734 :``%s``: basename of file being printed
734 :``%s``: basename of file being printed
735 :``%d``: dirname of file being printed, or '.' if in repository root
735 :``%d``: dirname of file being printed, or '.' if in repository root
736 :``%p``: root-relative path name of file being printed
736 :``%p``: root-relative path name of file being printed
737
737
738 Returns 0 on success.
738 Returns 0 on success.
739 """
739 """
740 ctx = cmdutil.revsingle(repo, opts.get('rev'))
740 ctx = cmdutil.revsingle(repo, opts.get('rev'))
741 err = 1
741 err = 1
742 m = cmdutil.match(repo, (file1,) + pats, opts)
742 m = cmdutil.match(repo, (file1,) + pats, opts)
743 for abs in ctx.walk(m):
743 for abs in ctx.walk(m):
744 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
744 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
745 data = ctx[abs].data()
745 data = ctx[abs].data()
746 if opts.get('decode'):
746 if opts.get('decode'):
747 data = repo.wwritedata(abs, data)
747 data = repo.wwritedata(abs, data)
748 fp.write(data)
748 fp.write(data)
749 fp.close()
749 fp.close()
750 err = 0
750 err = 0
751 return err
751 return err
752
752
753 def clone(ui, source, dest=None, **opts):
753 def clone(ui, source, dest=None, **opts):
754 """make a copy of an existing repository
754 """make a copy of an existing repository
755
755
756 Create a copy of an existing repository in a new directory.
756 Create a copy of an existing repository in a new directory.
757
757
758 If no destination directory name is specified, it defaults to the
758 If no destination directory name is specified, it defaults to the
759 basename of the source.
759 basename of the source.
760
760
761 The location of the source is added to the new repository's
761 The location of the source is added to the new repository's
762 ``.hg/hgrc`` file, as the default to be used for future pulls.
762 ``.hg/hgrc`` file, as the default to be used for future pulls.
763
763
764 See :hg:`help urls` for valid source format details.
764 See :hg:`help urls` for valid source format details.
765
765
766 It is possible to specify an ``ssh://`` URL as the destination, but no
766 It is possible to specify an ``ssh://`` URL as the destination, but no
767 ``.hg/hgrc`` and working directory will be created on the remote side.
767 ``.hg/hgrc`` and working directory will be created on the remote side.
768 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
768 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
769
769
770 A set of changesets (tags, or branch names) to pull may be specified
770 A set of changesets (tags, or branch names) to pull may be specified
771 by listing each changeset (tag, or branch name) with -r/--rev.
771 by listing each changeset (tag, or branch name) with -r/--rev.
772 If -r/--rev is used, the cloned repository will contain only a subset
772 If -r/--rev is used, the cloned repository will contain only a subset
773 of the changesets of the source repository. Only the set of changesets
773 of the changesets of the source repository. Only the set of changesets
774 defined by all -r/--rev options (including all their ancestors)
774 defined by all -r/--rev options (including all their ancestors)
775 will be pulled into the destination repository.
775 will be pulled into the destination repository.
776 No subsequent changesets (including subsequent tags) will be present
776 No subsequent changesets (including subsequent tags) will be present
777 in the destination.
777 in the destination.
778
778
779 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
779 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
780 local source repositories.
780 local source repositories.
781
781
782 For efficiency, hardlinks are used for cloning whenever the source
782 For efficiency, hardlinks are used for cloning whenever the source
783 and destination are on the same filesystem (note this applies only
783 and destination are on the same filesystem (note this applies only
784 to the repository data, not to the working directory). Some
784 to the repository data, not to the working directory). Some
785 filesystems, such as AFS, implement hardlinking incorrectly, but
785 filesystems, such as AFS, implement hardlinking incorrectly, but
786 do not report errors. In these cases, use the --pull option to
786 do not report errors. In these cases, use the --pull option to
787 avoid hardlinking.
787 avoid hardlinking.
788
788
789 In some cases, you can clone repositories and the working directory
789 In some cases, you can clone repositories and the working directory
790 using full hardlinks with ::
790 using full hardlinks with ::
791
791
792 $ cp -al REPO REPOCLONE
792 $ cp -al REPO REPOCLONE
793
793
794 This is the fastest way to clone, but it is not always safe. The
794 This is the fastest way to clone, but it is not always safe. The
795 operation is not atomic (making sure REPO is not modified during
795 operation is not atomic (making sure REPO is not modified during
796 the operation is up to you) and you have to make sure your editor
796 the operation is up to you) and you have to make sure your editor
797 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
797 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
798 this is not compatible with certain extensions that place their
798 this is not compatible with certain extensions that place their
799 metadata under the .hg directory, such as mq.
799 metadata under the .hg directory, such as mq.
800
800
801 Mercurial will update the working directory to the first applicable
801 Mercurial will update the working directory to the first applicable
802 revision from this list:
802 revision from this list:
803
803
804 a) null if -U or the source repository has no changesets
804 a) null if -U or the source repository has no changesets
805 b) if -u . and the source repository is local, the first parent of
805 b) if -u . and the source repository is local, the first parent of
806 the source repository's working directory
806 the source repository's working directory
807 c) the changeset specified with -u (if a branch name, this means the
807 c) the changeset specified with -u (if a branch name, this means the
808 latest head of that branch)
808 latest head of that branch)
809 d) the changeset specified with -r
809 d) the changeset specified with -r
810 e) the tipmost head specified with -b
810 e) the tipmost head specified with -b
811 f) the tipmost head specified with the url#branch source syntax
811 f) the tipmost head specified with the url#branch source syntax
812 g) the tipmost head of the default branch
812 g) the tipmost head of the default branch
813 h) tip
813 h) tip
814
814
815 Returns 0 on success.
815 Returns 0 on success.
816 """
816 """
817 if opts.get('noupdate') and opts.get('updaterev'):
817 if opts.get('noupdate') and opts.get('updaterev'):
818 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
818 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
819
819
820 r = hg.clone(hg.remoteui(ui, opts), source, dest,
820 r = hg.clone(hg.remoteui(ui, opts), source, dest,
821 pull=opts.get('pull'),
821 pull=opts.get('pull'),
822 stream=opts.get('uncompressed'),
822 stream=opts.get('uncompressed'),
823 rev=opts.get('rev'),
823 rev=opts.get('rev'),
824 update=opts.get('updaterev') or not opts.get('noupdate'),
824 update=opts.get('updaterev') or not opts.get('noupdate'),
825 branch=opts.get('branch'))
825 branch=opts.get('branch'))
826
826
827 return r is None
827 return r is None
828
828
829 def commit(ui, repo, *pats, **opts):
829 def commit(ui, repo, *pats, **opts):
830 """commit the specified files or all outstanding changes
830 """commit the specified files or all outstanding changes
831
831
832 Commit changes to the given files into the repository. Unlike a
832 Commit changes to the given files into the repository. Unlike a
833 centralized SCM, this operation is a local operation. See
833 centralized SCM, this operation is a local operation. See
834 :hg:`push` for a way to actively distribute your changes.
834 :hg:`push` for a way to actively distribute your changes.
835
835
836 If a list of files is omitted, all changes reported by :hg:`status`
836 If a list of files is omitted, all changes reported by :hg:`status`
837 will be committed.
837 will be committed.
838
838
839 If you are committing the result of a merge, do not provide any
839 If you are committing the result of a merge, do not provide any
840 filenames or -I/-X filters.
840 filenames or -I/-X filters.
841
841
842 If no commit message is specified, Mercurial starts your
842 If no commit message is specified, Mercurial starts your
843 configured editor where you can enter a message. In case your
843 configured editor where you can enter a message. In case your
844 commit fails, you will find a backup of your message in
844 commit fails, you will find a backup of your message in
845 ``.hg/last-message.txt``.
845 ``.hg/last-message.txt``.
846
846
847 See :hg:`help dates` for a list of formats valid for -d/--date.
847 See :hg:`help dates` for a list of formats valid for -d/--date.
848
848
849 Returns 0 on success, 1 if nothing changed.
849 Returns 0 on success, 1 if nothing changed.
850 """
850 """
851 extra = {}
851 extra = {}
852 if opts.get('close_branch'):
852 if opts.get('close_branch'):
853 if repo['.'].node() not in repo.branchheads():
853 if repo['.'].node() not in repo.branchheads():
854 # The topo heads set is included in the branch heads set of the
854 # The topo heads set is included in the branch heads set of the
855 # current branch, so it's sufficient to test branchheads
855 # current branch, so it's sufficient to test branchheads
856 raise util.Abort(_('can only close branch heads'))
856 raise util.Abort(_('can only close branch heads'))
857 extra['close'] = 1
857 extra['close'] = 1
858 e = cmdutil.commiteditor
858 e = cmdutil.commiteditor
859 if opts.get('force_editor'):
859 if opts.get('force_editor'):
860 e = cmdutil.commitforceeditor
860 e = cmdutil.commitforceeditor
861
861
862 def commitfunc(ui, repo, message, match, opts):
862 def commitfunc(ui, repo, message, match, opts):
863 return repo.commit(message, opts.get('user'), opts.get('date'), match,
863 return repo.commit(message, opts.get('user'), opts.get('date'), match,
864 editor=e, extra=extra)
864 editor=e, extra=extra)
865
865
866 branch = repo[None].branch()
866 branch = repo[None].branch()
867 bheads = repo.branchheads(branch)
867 bheads = repo.branchheads(branch)
868
868
869 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
869 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
870 if not node:
870 if not node:
871 ui.status(_("nothing changed\n"))
871 ui.status(_("nothing changed\n"))
872 return 1
872 return 1
873
873
874 ctx = repo[node]
874 ctx = repo[node]
875 parents = ctx.parents()
875 parents = ctx.parents()
876
876
877 if bheads and not [x for x in parents
877 if bheads and not [x for x in parents
878 if x.node() in bheads and x.branch() == branch]:
878 if x.node() in bheads and x.branch() == branch]:
879 ui.status(_('created new head\n'))
879 ui.status(_('created new head\n'))
880 # The message is not printed for initial roots. For the other
880 # The message is not printed for initial roots. For the other
881 # changesets, it is printed in the following situations:
881 # changesets, it is printed in the following situations:
882 #
882 #
883 # Par column: for the 2 parents with ...
883 # Par column: for the 2 parents with ...
884 # N: null or no parent
884 # N: null or no parent
885 # B: parent is on another named branch
885 # B: parent is on another named branch
886 # C: parent is a regular non head changeset
886 # C: parent is a regular non head changeset
887 # H: parent was a branch head of the current branch
887 # H: parent was a branch head of the current branch
888 # Msg column: whether we print "created new head" message
888 # Msg column: whether we print "created new head" message
889 # In the following, it is assumed that there already exists some
889 # In the following, it is assumed that there already exists some
890 # initial branch heads of the current branch, otherwise nothing is
890 # initial branch heads of the current branch, otherwise nothing is
891 # printed anyway.
891 # printed anyway.
892 #
892 #
893 # Par Msg Comment
893 # Par Msg Comment
894 # NN y additional topo root
894 # NN y additional topo root
895 #
895 #
896 # BN y additional branch root
896 # BN y additional branch root
897 # CN y additional topo head
897 # CN y additional topo head
898 # HN n usual case
898 # HN n usual case
899 #
899 #
900 # BB y weird additional branch root
900 # BB y weird additional branch root
901 # CB y branch merge
901 # CB y branch merge
902 # HB n merge with named branch
902 # HB n merge with named branch
903 #
903 #
904 # CC y additional head from merge
904 # CC y additional head from merge
905 # CH n merge with a head
905 # CH n merge with a head
906 #
906 #
907 # HH n head merge: head count decreases
907 # HH n head merge: head count decreases
908
908
909 if not opts.get('close_branch'):
909 if not opts.get('close_branch'):
910 for r in parents:
910 for r in parents:
911 if r.extra().get('close') and r.branch() == branch:
911 if r.extra().get('close') and r.branch() == branch:
912 ui.status(_('reopening closed branch head %d\n') % r)
912 ui.status(_('reopening closed branch head %d\n') % r)
913
913
914 if ui.debugflag:
914 if ui.debugflag:
915 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
915 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
916 elif ui.verbose:
916 elif ui.verbose:
917 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
917 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
918
918
919 def copy(ui, repo, *pats, **opts):
919 def copy(ui, repo, *pats, **opts):
920 """mark files as copied for the next commit
920 """mark files as copied for the next commit
921
921
922 Mark dest as having copies of source files. If dest is a
922 Mark dest as having copies of source files. If dest is a
923 directory, copies are put in that directory. If dest is a file,
923 directory, copies are put in that directory. If dest is a file,
924 the source must be a single file.
924 the source must be a single file.
925
925
926 By default, this command copies the contents of files as they
926 By default, this command copies the contents of files as they
927 exist in the working directory. If invoked with -A/--after, the
927 exist in the working directory. If invoked with -A/--after, the
928 operation is recorded, but no copying is performed.
928 operation is recorded, but no copying is performed.
929
929
930 This command takes effect with the next commit. To undo a copy
930 This command takes effect with the next commit. To undo a copy
931 before that, see :hg:`revert`.
931 before that, see :hg:`revert`.
932
932
933 Returns 0 on success, 1 if errors are encountered.
933 Returns 0 on success, 1 if errors are encountered.
934 """
934 """
935 wlock = repo.wlock(False)
935 wlock = repo.wlock(False)
936 try:
936 try:
937 return cmdutil.copy(ui, repo, pats, opts)
937 return cmdutil.copy(ui, repo, pats, opts)
938 finally:
938 finally:
939 wlock.release()
939 wlock.release()
940
940
941 def debugancestor(ui, repo, *args):
941 def debugancestor(ui, repo, *args):
942 """find the ancestor revision of two revisions in a given index"""
942 """find the ancestor revision of two revisions in a given index"""
943 if len(args) == 3:
943 if len(args) == 3:
944 index, rev1, rev2 = args
944 index, rev1, rev2 = args
945 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
945 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
946 lookup = r.lookup
946 lookup = r.lookup
947 elif len(args) == 2:
947 elif len(args) == 2:
948 if not repo:
948 if not repo:
949 raise util.Abort(_("there is no Mercurial repository here "
949 raise util.Abort(_("there is no Mercurial repository here "
950 "(.hg not found)"))
950 "(.hg not found)"))
951 rev1, rev2 = args
951 rev1, rev2 = args
952 r = repo.changelog
952 r = repo.changelog
953 lookup = repo.lookup
953 lookup = repo.lookup
954 else:
954 else:
955 raise util.Abort(_('either two or three arguments required'))
955 raise util.Abort(_('either two or three arguments required'))
956 a = r.ancestor(lookup(rev1), lookup(rev2))
956 a = r.ancestor(lookup(rev1), lookup(rev2))
957 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
957 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
958
958
959 def debugbuilddag(ui, repo, text,
959 def debugbuilddag(ui, repo, text,
960 mergeable_file=False,
960 mergeable_file=False,
961 appended_file=False,
961 appended_file=False,
962 overwritten_file=False,
962 overwritten_file=False,
963 new_file=False):
963 new_file=False):
964 """builds a repo with a given dag from scratch in the current empty repo
964 """builds a repo with a given dag from scratch in the current empty repo
965
965
966 Elements:
966 Elements:
967
967
968 - "+n" is a linear run of n nodes based on the current default parent
968 - "+n" is a linear run of n nodes based on the current default parent
969 - "." is a single node based on the current default parent
969 - "." is a single node based on the current default parent
970 - "$" resets the default parent to null (implied at the start);
970 - "$" resets the default parent to null (implied at the start);
971 otherwise the default parent is always the last node created
971 otherwise the default parent is always the last node created
972 - "<p" sets the default parent to the backref p
972 - "<p" sets the default parent to the backref p
973 - "*p" is a fork at parent p, which is a backref
973 - "*p" is a fork at parent p, which is a backref
974 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
974 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
975 - "/p2" is a merge of the preceding node and p2
975 - "/p2" is a merge of the preceding node and p2
976 - ":tag" defines a local tag for the preceding node
976 - ":tag" defines a local tag for the preceding node
977 - "@branch" sets the named branch for subsequent nodes
977 - "@branch" sets the named branch for subsequent nodes
978 - "!command" runs the command using your shell
978 - "!command" runs the command using your shell
979 - "!!my command\\n" is like "!", but to the end of the line
979 - "!!my command\\n" is like "!", but to the end of the line
980 - "#...\\n" is a comment up to the end of the line
980 - "#...\\n" is a comment up to the end of the line
981
981
982 Whitespace between the above elements is ignored.
982 Whitespace between the above elements is ignored.
983
983
984 A backref is either
984 A backref is either
985
985
986 - a number n, which references the node curr-n, where curr is the current
986 - a number n, which references the node curr-n, where curr is the current
987 node, or
987 node, or
988 - the name of a local tag you placed earlier using ":tag", or
988 - the name of a local tag you placed earlier using ":tag", or
989 - empty to denote the default parent.
989 - empty to denote the default parent.
990
990
991 All string valued-elements are either strictly alphanumeric, or must
991 All string valued-elements are either strictly alphanumeric, or must
992 be enclosed in double quotes ("..."), with "\\" as escape character.
992 be enclosed in double quotes ("..."), with "\\" as escape character.
993
993
994 Note that the --overwritten-file and --appended-file options imply the
994 Note that the --overwritten-file and --appended-file options imply the
995 use of "HGMERGE=internal:local" during DAG buildup.
995 use of "HGMERGE=internal:local" during DAG buildup.
996 """
996 """
997
997
998 if not (mergeable_file or appended_file or overwritten_file or new_file):
998 if not (mergeable_file or appended_file or overwritten_file or new_file):
999 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
999 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
1000
1000
1001 if len(repo.changelog) > 0:
1001 if len(repo.changelog) > 0:
1002 raise util.Abort(_('repository is not empty'))
1002 raise util.Abort(_('repository is not empty'))
1003
1003
1004 if overwritten_file or appended_file:
1004 if overwritten_file or appended_file:
1005 # we don't want to fail in merges during buildup
1005 # we don't want to fail in merges during buildup
1006 os.environ['HGMERGE'] = 'internal:local'
1006 os.environ['HGMERGE'] = 'internal:local'
1007
1007
1008 def writefile(fname, text, fmode="wb"):
1008 def writefile(fname, text, fmode="wb"):
1009 f = open(fname, fmode)
1009 f = open(fname, fmode)
1010 try:
1010 try:
1011 f.write(text)
1011 f.write(text)
1012 finally:
1012 finally:
1013 f.close()
1013 f.close()
1014
1014
1015 if mergeable_file:
1015 if mergeable_file:
1016 linesperrev = 2
1016 linesperrev = 2
1017 # determine number of revs in DAG
1017 # determine number of revs in DAG
1018 n = 0
1018 n = 0
1019 for type, data in dagparser.parsedag(text):
1019 for type, data in dagparser.parsedag(text):
1020 if type == 'n':
1020 if type == 'n':
1021 n += 1
1021 n += 1
1022 # make a file with k lines per rev
1022 # make a file with k lines per rev
1023 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
1023 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
1024 + "\n")
1024 + "\n")
1025
1025
1026 at = -1
1026 at = -1
1027 atbranch = 'default'
1027 atbranch = 'default'
1028 for type, data in dagparser.parsedag(text):
1028 for type, data in dagparser.parsedag(text):
1029 if type == 'n':
1029 if type == 'n':
1030 ui.status('node %s\n' % str(data))
1030 ui.status('node %s\n' % str(data))
1031 id, ps = data
1031 id, ps = data
1032 p1 = ps[0]
1032 p1 = ps[0]
1033 if p1 != at:
1033 if p1 != at:
1034 update(ui, repo, node=str(p1), clean=True)
1034 update(ui, repo, node=str(p1), clean=True)
1035 at = p1
1035 at = p1
1036 if repo.dirstate.branch() != atbranch:
1036 if repo.dirstate.branch() != atbranch:
1037 branch(ui, repo, atbranch, force=True)
1037 branch(ui, repo, atbranch, force=True)
1038 if len(ps) > 1:
1038 if len(ps) > 1:
1039 p2 = ps[1]
1039 p2 = ps[1]
1040 merge(ui, repo, node=p2)
1040 merge(ui, repo, node=p2)
1041
1041
1042 if mergeable_file:
1042 if mergeable_file:
1043 f = open("mf", "rb+")
1043 f = open("mf", "rb+")
1044 try:
1044 try:
1045 lines = f.read().split("\n")
1045 lines = f.read().split("\n")
1046 lines[id * linesperrev] += " r%i" % id
1046 lines[id * linesperrev] += " r%i" % id
1047 f.seek(0)
1047 f.seek(0)
1048 f.write("\n".join(lines))
1048 f.write("\n".join(lines))
1049 finally:
1049 finally:
1050 f.close()
1050 f.close()
1051
1051
1052 if appended_file:
1052 if appended_file:
1053 writefile("af", "r%i\n" % id, "ab")
1053 writefile("af", "r%i\n" % id, "ab")
1054
1054
1055 if overwritten_file:
1055 if overwritten_file:
1056 writefile("of", "r%i\n" % id)
1056 writefile("of", "r%i\n" % id)
1057
1057
1058 if new_file:
1058 if new_file:
1059 writefile("nf%i" % id, "r%i\n" % id)
1059 writefile("nf%i" % id, "r%i\n" % id)
1060
1060
1061 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
1061 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
1062 at = id
1062 at = id
1063 elif type == 'l':
1063 elif type == 'l':
1064 id, name = data
1064 id, name = data
1065 ui.status('tag %s\n' % name)
1065 ui.status('tag %s\n' % name)
1066 tag(ui, repo, name, local=True)
1066 tag(ui, repo, name, local=True)
1067 elif type == 'a':
1067 elif type == 'a':
1068 ui.status('branch %s\n' % data)
1068 ui.status('branch %s\n' % data)
1069 atbranch = data
1069 atbranch = data
1070 elif type in 'cC':
1070 elif type in 'cC':
1071 r = util.system(data, cwd=repo.root)
1071 r = util.system(data, cwd=repo.root)
1072 if r:
1072 if r:
1073 desc, r = util.explain_exit(r)
1073 desc, r = util.explain_exit(r)
1074 raise util.Abort(_('%s command %s') % (data, desc))
1074 raise util.Abort(_('%s command %s') % (data, desc))
1075
1075
1076 def debugcommands(ui, cmd='', *args):
1076 def debugcommands(ui, cmd='', *args):
1077 """list all available commands and options"""
1077 """list all available commands and options"""
1078 for cmd, vals in sorted(table.iteritems()):
1078 for cmd, vals in sorted(table.iteritems()):
1079 cmd = cmd.split('|')[0].strip('^')
1079 cmd = cmd.split('|')[0].strip('^')
1080 opts = ', '.join([i[1] for i in vals[1]])
1080 opts = ', '.join([i[1] for i in vals[1]])
1081 ui.write('%s: %s\n' % (cmd, opts))
1081 ui.write('%s: %s\n' % (cmd, opts))
1082
1082
1083 def debugcomplete(ui, cmd='', **opts):
1083 def debugcomplete(ui, cmd='', **opts):
1084 """returns the completion list associated with the given command"""
1084 """returns the completion list associated with the given command"""
1085
1085
1086 if opts.get('options'):
1086 if opts.get('options'):
1087 options = []
1087 options = []
1088 otables = [globalopts]
1088 otables = [globalopts]
1089 if cmd:
1089 if cmd:
1090 aliases, entry = cmdutil.findcmd(cmd, table, False)
1090 aliases, entry = cmdutil.findcmd(cmd, table, False)
1091 otables.append(entry[1])
1091 otables.append(entry[1])
1092 for t in otables:
1092 for t in otables:
1093 for o in t:
1093 for o in t:
1094 if "(DEPRECATED)" in o[3]:
1094 if "(DEPRECATED)" in o[3]:
1095 continue
1095 continue
1096 if o[0]:
1096 if o[0]:
1097 options.append('-%s' % o[0])
1097 options.append('-%s' % o[0])
1098 options.append('--%s' % o[1])
1098 options.append('--%s' % o[1])
1099 ui.write("%s\n" % "\n".join(options))
1099 ui.write("%s\n" % "\n".join(options))
1100 return
1100 return
1101
1101
1102 cmdlist = cmdutil.findpossible(cmd, table)
1102 cmdlist = cmdutil.findpossible(cmd, table)
1103 if ui.verbose:
1103 if ui.verbose:
1104 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1104 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1105 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1105 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1106
1106
1107 def debugfsinfo(ui, path = "."):
1107 def debugfsinfo(ui, path = "."):
1108 """show information detected about current filesystem"""
1108 """show information detected about current filesystem"""
1109 open('.debugfsinfo', 'w').write('')
1109 open('.debugfsinfo', 'w').write('')
1110 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1110 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1111 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1111 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1112 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1112 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1113 and 'yes' or 'no'))
1113 and 'yes' or 'no'))
1114 os.unlink('.debugfsinfo')
1114 os.unlink('.debugfsinfo')
1115
1115
1116 def debugrebuildstate(ui, repo, rev="tip"):
1116 def debugrebuildstate(ui, repo, rev="tip"):
1117 """rebuild the dirstate as it would look like for the given revision"""
1117 """rebuild the dirstate as it would look like for the given revision"""
1118 ctx = cmdutil.revsingle(repo, rev)
1118 ctx = cmdutil.revsingle(repo, rev)
1119 wlock = repo.wlock()
1119 wlock = repo.wlock()
1120 try:
1120 try:
1121 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1121 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1122 finally:
1122 finally:
1123 wlock.release()
1123 wlock.release()
1124
1124
1125 def debugcheckstate(ui, repo):
1125 def debugcheckstate(ui, repo):
1126 """validate the correctness of the current dirstate"""
1126 """validate the correctness of the current dirstate"""
1127 parent1, parent2 = repo.dirstate.parents()
1127 parent1, parent2 = repo.dirstate.parents()
1128 m1 = repo[parent1].manifest()
1128 m1 = repo[parent1].manifest()
1129 m2 = repo[parent2].manifest()
1129 m2 = repo[parent2].manifest()
1130 errors = 0
1130 errors = 0
1131 for f in repo.dirstate:
1131 for f in repo.dirstate:
1132 state = repo.dirstate[f]
1132 state = repo.dirstate[f]
1133 if state in "nr" and f not in m1:
1133 if state in "nr" and f not in m1:
1134 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1134 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1135 errors += 1
1135 errors += 1
1136 if state in "a" and f in m1:
1136 if state in "a" and f in m1:
1137 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1137 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1138 errors += 1
1138 errors += 1
1139 if state in "m" and f not in m1 and f not in m2:
1139 if state in "m" and f not in m1 and f not in m2:
1140 ui.warn(_("%s in state %s, but not in either manifest\n") %
1140 ui.warn(_("%s in state %s, but not in either manifest\n") %
1141 (f, state))
1141 (f, state))
1142 errors += 1
1142 errors += 1
1143 for f in m1:
1143 for f in m1:
1144 state = repo.dirstate[f]
1144 state = repo.dirstate[f]
1145 if state not in "nrm":
1145 if state not in "nrm":
1146 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1146 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1147 errors += 1
1147 errors += 1
1148 if errors:
1148 if errors:
1149 error = _(".hg/dirstate inconsistent with current parent's manifest")
1149 error = _(".hg/dirstate inconsistent with current parent's manifest")
1150 raise util.Abort(error)
1150 raise util.Abort(error)
1151
1151
1152 def showconfig(ui, repo, *values, **opts):
1152 def showconfig(ui, repo, *values, **opts):
1153 """show combined config settings from all hgrc files
1153 """show combined config settings from all hgrc files
1154
1154
1155 With no arguments, print names and values of all config items.
1155 With no arguments, print names and values of all config items.
1156
1156
1157 With one argument of the form section.name, print just the value
1157 With one argument of the form section.name, print just the value
1158 of that config item.
1158 of that config item.
1159
1159
1160 With multiple arguments, print names and values of all config
1160 With multiple arguments, print names and values of all config
1161 items with matching section names.
1161 items with matching section names.
1162
1162
1163 With --debug, the source (filename and line number) is printed
1163 With --debug, the source (filename and line number) is printed
1164 for each config item.
1164 for each config item.
1165
1165
1166 Returns 0 on success.
1166 Returns 0 on success.
1167 """
1167 """
1168
1168
1169 for f in util.rcpath():
1169 for f in util.rcpath():
1170 ui.debug(_('read config from: %s\n') % f)
1170 ui.debug(_('read config from: %s\n') % f)
1171 untrusted = bool(opts.get('untrusted'))
1171 untrusted = bool(opts.get('untrusted'))
1172 if values:
1172 if values:
1173 sections = [v for v in values if '.' not in v]
1173 sections = [v for v in values if '.' not in v]
1174 items = [v for v in values if '.' in v]
1174 items = [v for v in values if '.' in v]
1175 if len(items) > 1 or items and sections:
1175 if len(items) > 1 or items and sections:
1176 raise util.Abort(_('only one config item permitted'))
1176 raise util.Abort(_('only one config item permitted'))
1177 for section, name, value in ui.walkconfig(untrusted=untrusted):
1177 for section, name, value in ui.walkconfig(untrusted=untrusted):
1178 sectname = section + '.' + name
1178 sectname = section + '.' + name
1179 if values:
1179 if values:
1180 for v in values:
1180 for v in values:
1181 if v == section:
1181 if v == section:
1182 ui.debug('%s: ' %
1182 ui.debug('%s: ' %
1183 ui.configsource(section, name, untrusted))
1183 ui.configsource(section, name, untrusted))
1184 ui.write('%s=%s\n' % (sectname, value))
1184 ui.write('%s=%s\n' % (sectname, value))
1185 elif v == sectname:
1185 elif v == sectname:
1186 ui.debug('%s: ' %
1186 ui.debug('%s: ' %
1187 ui.configsource(section, name, untrusted))
1187 ui.configsource(section, name, untrusted))
1188 ui.write(value, '\n')
1188 ui.write(value, '\n')
1189 else:
1189 else:
1190 ui.debug('%s: ' %
1190 ui.debug('%s: ' %
1191 ui.configsource(section, name, untrusted))
1191 ui.configsource(section, name, untrusted))
1192 ui.write('%s=%s\n' % (sectname, value))
1192 ui.write('%s=%s\n' % (sectname, value))
1193
1193
1194 def debugpushkey(ui, repopath, namespace, *keyinfo):
1194 def debugpushkey(ui, repopath, namespace, *keyinfo):
1195 '''access the pushkey key/value protocol
1195 '''access the pushkey key/value protocol
1196
1196
1197 With two args, list the keys in the given namespace.
1197 With two args, list the keys in the given namespace.
1198
1198
1199 With five args, set a key to new if it currently is set to old.
1199 With five args, set a key to new if it currently is set to old.
1200 Reports success or failure.
1200 Reports success or failure.
1201 '''
1201 '''
1202
1202
1203 target = hg.repository(ui, repopath)
1203 target = hg.repository(ui, repopath)
1204 if keyinfo:
1204 if keyinfo:
1205 key, old, new = keyinfo
1205 key, old, new = keyinfo
1206 r = target.pushkey(namespace, key, old, new)
1206 r = target.pushkey(namespace, key, old, new)
1207 ui.status(str(r) + '\n')
1207 ui.status(str(r) + '\n')
1208 return not r
1208 return not r
1209 else:
1209 else:
1210 for k, v in target.listkeys(namespace).iteritems():
1210 for k, v in target.listkeys(namespace).iteritems():
1211 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1211 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1212 v.encode('string-escape')))
1212 v.encode('string-escape')))
1213
1213
1214 def debugrevspec(ui, repo, expr):
1214 def debugrevspec(ui, repo, expr):
1215 '''parse and apply a revision specification'''
1215 '''parse and apply a revision specification'''
1216 if ui.verbose:
1216 if ui.verbose:
1217 tree = revset.parse(expr)
1217 tree = revset.parse(expr)[0]
1218 ui.note(tree, "\n")
1218 ui.note(tree, "\n")
1219 func = revset.match(expr)
1219 func = revset.match(expr)
1220 for c in func(repo, range(len(repo))):
1220 for c in func(repo, range(len(repo))):
1221 ui.write("%s\n" % c)
1221 ui.write("%s\n" % c)
1222
1222
1223 def debugsetparents(ui, repo, rev1, rev2=None):
1223 def debugsetparents(ui, repo, rev1, rev2=None):
1224 """manually set the parents of the current working directory
1224 """manually set the parents of the current working directory
1225
1225
1226 This is useful for writing repository conversion tools, but should
1226 This is useful for writing repository conversion tools, but should
1227 be used with care.
1227 be used with care.
1228
1228
1229 Returns 0 on success.
1229 Returns 0 on success.
1230 """
1230 """
1231
1231
1232 r1 = cmdutil.revsingle(repo, rev1).node()
1232 r1 = cmdutil.revsingle(repo, rev1).node()
1233 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1233 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1234
1234
1235 wlock = repo.wlock()
1235 wlock = repo.wlock()
1236 try:
1236 try:
1237 repo.dirstate.setparents(r1, r2)
1237 repo.dirstate.setparents(r1, r2)
1238 finally:
1238 finally:
1239 wlock.release()
1239 wlock.release()
1240
1240
1241 def debugstate(ui, repo, nodates=None):
1241 def debugstate(ui, repo, nodates=None):
1242 """show the contents of the current dirstate"""
1242 """show the contents of the current dirstate"""
1243 timestr = ""
1243 timestr = ""
1244 showdate = not nodates
1244 showdate = not nodates
1245 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1245 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1246 if showdate:
1246 if showdate:
1247 if ent[3] == -1:
1247 if ent[3] == -1:
1248 # Pad or slice to locale representation
1248 # Pad or slice to locale representation
1249 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1249 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1250 time.localtime(0)))
1250 time.localtime(0)))
1251 timestr = 'unset'
1251 timestr = 'unset'
1252 timestr = (timestr[:locale_len] +
1252 timestr = (timestr[:locale_len] +
1253 ' ' * (locale_len - len(timestr)))
1253 ' ' * (locale_len - len(timestr)))
1254 else:
1254 else:
1255 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1255 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1256 time.localtime(ent[3]))
1256 time.localtime(ent[3]))
1257 if ent[1] & 020000:
1257 if ent[1] & 020000:
1258 mode = 'lnk'
1258 mode = 'lnk'
1259 else:
1259 else:
1260 mode = '%3o' % (ent[1] & 0777)
1260 mode = '%3o' % (ent[1] & 0777)
1261 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1261 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1262 for f in repo.dirstate.copies():
1262 for f in repo.dirstate.copies():
1263 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1263 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1264
1264
1265 def debugsub(ui, repo, rev=None):
1265 def debugsub(ui, repo, rev=None):
1266 ctx = cmdutil.revsingle(repo, rev, None)
1266 ctx = cmdutil.revsingle(repo, rev, None)
1267 for k, v in sorted(ctx.substate.items()):
1267 for k, v in sorted(ctx.substate.items()):
1268 ui.write('path %s\n' % k)
1268 ui.write('path %s\n' % k)
1269 ui.write(' source %s\n' % v[0])
1269 ui.write(' source %s\n' % v[0])
1270 ui.write(' revision %s\n' % v[1])
1270 ui.write(' revision %s\n' % v[1])
1271
1271
1272 def debugdag(ui, repo, file_=None, *revs, **opts):
1272 def debugdag(ui, repo, file_=None, *revs, **opts):
1273 """format the changelog or an index DAG as a concise textual description
1273 """format the changelog or an index DAG as a concise textual description
1274
1274
1275 If you pass a revlog index, the revlog's DAG is emitted. If you list
1275 If you pass a revlog index, the revlog's DAG is emitted. If you list
1276 revision numbers, they get labelled in the output as rN.
1276 revision numbers, they get labelled in the output as rN.
1277
1277
1278 Otherwise, the changelog DAG of the current repo is emitted.
1278 Otherwise, the changelog DAG of the current repo is emitted.
1279 """
1279 """
1280 spaces = opts.get('spaces')
1280 spaces = opts.get('spaces')
1281 dots = opts.get('dots')
1281 dots = opts.get('dots')
1282 if file_:
1282 if file_:
1283 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1283 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1284 revs = set((int(r) for r in revs))
1284 revs = set((int(r) for r in revs))
1285 def events():
1285 def events():
1286 for r in rlog:
1286 for r in rlog:
1287 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1287 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1288 if r in revs:
1288 if r in revs:
1289 yield 'l', (r, "r%i" % r)
1289 yield 'l', (r, "r%i" % r)
1290 elif repo:
1290 elif repo:
1291 cl = repo.changelog
1291 cl = repo.changelog
1292 tags = opts.get('tags')
1292 tags = opts.get('tags')
1293 branches = opts.get('branches')
1293 branches = opts.get('branches')
1294 if tags:
1294 if tags:
1295 labels = {}
1295 labels = {}
1296 for l, n in repo.tags().items():
1296 for l, n in repo.tags().items():
1297 labels.setdefault(cl.rev(n), []).append(l)
1297 labels.setdefault(cl.rev(n), []).append(l)
1298 def events():
1298 def events():
1299 b = "default"
1299 b = "default"
1300 for r in cl:
1300 for r in cl:
1301 if branches:
1301 if branches:
1302 newb = cl.read(cl.node(r))[5]['branch']
1302 newb = cl.read(cl.node(r))[5]['branch']
1303 if newb != b:
1303 if newb != b:
1304 yield 'a', newb
1304 yield 'a', newb
1305 b = newb
1305 b = newb
1306 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1306 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1307 if tags:
1307 if tags:
1308 ls = labels.get(r)
1308 ls = labels.get(r)
1309 if ls:
1309 if ls:
1310 for l in ls:
1310 for l in ls:
1311 yield 'l', (r, l)
1311 yield 'l', (r, l)
1312 else:
1312 else:
1313 raise util.Abort(_('need repo for changelog dag'))
1313 raise util.Abort(_('need repo for changelog dag'))
1314
1314
1315 for line in dagparser.dagtextlines(events(),
1315 for line in dagparser.dagtextlines(events(),
1316 addspaces=spaces,
1316 addspaces=spaces,
1317 wraplabels=True,
1317 wraplabels=True,
1318 wrapannotations=True,
1318 wrapannotations=True,
1319 wrapnonlinear=dots,
1319 wrapnonlinear=dots,
1320 usedots=dots,
1320 usedots=dots,
1321 maxlinewidth=70):
1321 maxlinewidth=70):
1322 ui.write(line)
1322 ui.write(line)
1323 ui.write("\n")
1323 ui.write("\n")
1324
1324
1325 def debugdata(ui, repo, file_, rev):
1325 def debugdata(ui, repo, file_, rev):
1326 """dump the contents of a data file revision"""
1326 """dump the contents of a data file revision"""
1327 r = None
1327 r = None
1328 if repo:
1328 if repo:
1329 filelog = repo.file(file_)
1329 filelog = repo.file(file_)
1330 if len(filelog):
1330 if len(filelog):
1331 r = filelog
1331 r = filelog
1332 if not r:
1332 if not r:
1333 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1333 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1334 try:
1334 try:
1335 ui.write(r.revision(r.lookup(rev)))
1335 ui.write(r.revision(r.lookup(rev)))
1336 except KeyError:
1336 except KeyError:
1337 raise util.Abort(_('invalid revision identifier %s') % rev)
1337 raise util.Abort(_('invalid revision identifier %s') % rev)
1338
1338
1339 def debugdate(ui, date, range=None, **opts):
1339 def debugdate(ui, date, range=None, **opts):
1340 """parse and display a date"""
1340 """parse and display a date"""
1341 if opts["extended"]:
1341 if opts["extended"]:
1342 d = util.parsedate(date, util.extendeddateformats)
1342 d = util.parsedate(date, util.extendeddateformats)
1343 else:
1343 else:
1344 d = util.parsedate(date)
1344 d = util.parsedate(date)
1345 ui.write("internal: %s %s\n" % d)
1345 ui.write("internal: %s %s\n" % d)
1346 ui.write("standard: %s\n" % util.datestr(d))
1346 ui.write("standard: %s\n" % util.datestr(d))
1347 if range:
1347 if range:
1348 m = util.matchdate(range)
1348 m = util.matchdate(range)
1349 ui.write("match: %s\n" % m(d[0]))
1349 ui.write("match: %s\n" % m(d[0]))
1350
1350
1351 def debugignore(ui, repo, *values, **opts):
1351 def debugignore(ui, repo, *values, **opts):
1352 """display the combined ignore pattern"""
1352 """display the combined ignore pattern"""
1353 ignore = repo.dirstate._ignore
1353 ignore = repo.dirstate._ignore
1354 if hasattr(ignore, 'includepat'):
1354 if hasattr(ignore, 'includepat'):
1355 ui.write("%s\n" % ignore.includepat)
1355 ui.write("%s\n" % ignore.includepat)
1356 else:
1356 else:
1357 raise util.Abort(_("no ignore patterns found"))
1357 raise util.Abort(_("no ignore patterns found"))
1358
1358
1359 def debugindex(ui, repo, file_, **opts):
1359 def debugindex(ui, repo, file_, **opts):
1360 """dump the contents of an index file"""
1360 """dump the contents of an index file"""
1361 r = None
1361 r = None
1362 if repo:
1362 if repo:
1363 filelog = repo.file(file_)
1363 filelog = repo.file(file_)
1364 if len(filelog):
1364 if len(filelog):
1365 r = filelog
1365 r = filelog
1366
1366
1367 format = opts.get('format', 0)
1367 format = opts.get('format', 0)
1368 if format not in (0, 1):
1368 if format not in (0, 1):
1369 raise util.Abort(_("unknown format %d") % format)
1369 raise util.Abort(_("unknown format %d") % format)
1370
1370
1371 if not r:
1371 if not r:
1372 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1372 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1373
1373
1374 if format == 0:
1374 if format == 0:
1375 ui.write(" rev offset length base linkrev"
1375 ui.write(" rev offset length base linkrev"
1376 " nodeid p1 p2\n")
1376 " nodeid p1 p2\n")
1377 elif format == 1:
1377 elif format == 1:
1378 ui.write(" rev flag offset length"
1378 ui.write(" rev flag offset length"
1379 " size base link p1 p2 nodeid\n")
1379 " size base link p1 p2 nodeid\n")
1380
1380
1381 for i in r:
1381 for i in r:
1382 node = r.node(i)
1382 node = r.node(i)
1383 if format == 0:
1383 if format == 0:
1384 try:
1384 try:
1385 pp = r.parents(node)
1385 pp = r.parents(node)
1386 except:
1386 except:
1387 pp = [nullid, nullid]
1387 pp = [nullid, nullid]
1388 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1388 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1389 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1389 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1390 short(node), short(pp[0]), short(pp[1])))
1390 short(node), short(pp[0]), short(pp[1])))
1391 elif format == 1:
1391 elif format == 1:
1392 pr = r.parentrevs(i)
1392 pr = r.parentrevs(i)
1393 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1393 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1394 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1394 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1395 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1395 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1396
1396
1397 def debugindexdot(ui, repo, file_):
1397 def debugindexdot(ui, repo, file_):
1398 """dump an index DAG as a graphviz dot file"""
1398 """dump an index DAG as a graphviz dot file"""
1399 r = None
1399 r = None
1400 if repo:
1400 if repo:
1401 filelog = repo.file(file_)
1401 filelog = repo.file(file_)
1402 if len(filelog):
1402 if len(filelog):
1403 r = filelog
1403 r = filelog
1404 if not r:
1404 if not r:
1405 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1405 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1406 ui.write("digraph G {\n")
1406 ui.write("digraph G {\n")
1407 for i in r:
1407 for i in r:
1408 node = r.node(i)
1408 node = r.node(i)
1409 pp = r.parents(node)
1409 pp = r.parents(node)
1410 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1410 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1411 if pp[1] != nullid:
1411 if pp[1] != nullid:
1412 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1412 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1413 ui.write("}\n")
1413 ui.write("}\n")
1414
1414
1415 def debuginstall(ui):
1415 def debuginstall(ui):
1416 '''test Mercurial installation
1416 '''test Mercurial installation
1417
1417
1418 Returns 0 on success.
1418 Returns 0 on success.
1419 '''
1419 '''
1420
1420
1421 def writetemp(contents):
1421 def writetemp(contents):
1422 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1422 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1423 f = os.fdopen(fd, "wb")
1423 f = os.fdopen(fd, "wb")
1424 f.write(contents)
1424 f.write(contents)
1425 f.close()
1425 f.close()
1426 return name
1426 return name
1427
1427
1428 problems = 0
1428 problems = 0
1429
1429
1430 # encoding
1430 # encoding
1431 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1431 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1432 try:
1432 try:
1433 encoding.fromlocal("test")
1433 encoding.fromlocal("test")
1434 except util.Abort, inst:
1434 except util.Abort, inst:
1435 ui.write(" %s\n" % inst)
1435 ui.write(" %s\n" % inst)
1436 ui.write(_(" (check that your locale is properly set)\n"))
1436 ui.write(_(" (check that your locale is properly set)\n"))
1437 problems += 1
1437 problems += 1
1438
1438
1439 # compiled modules
1439 # compiled modules
1440 ui.status(_("Checking installed modules (%s)...\n")
1440 ui.status(_("Checking installed modules (%s)...\n")
1441 % os.path.dirname(__file__))
1441 % os.path.dirname(__file__))
1442 try:
1442 try:
1443 import bdiff, mpatch, base85, osutil
1443 import bdiff, mpatch, base85, osutil
1444 except Exception, inst:
1444 except Exception, inst:
1445 ui.write(" %s\n" % inst)
1445 ui.write(" %s\n" % inst)
1446 ui.write(_(" One or more extensions could not be found"))
1446 ui.write(_(" One or more extensions could not be found"))
1447 ui.write(_(" (check that you compiled the extensions)\n"))
1447 ui.write(_(" (check that you compiled the extensions)\n"))
1448 problems += 1
1448 problems += 1
1449
1449
1450 # templates
1450 # templates
1451 ui.status(_("Checking templates...\n"))
1451 ui.status(_("Checking templates...\n"))
1452 try:
1452 try:
1453 import templater
1453 import templater
1454 templater.templater(templater.templatepath("map-cmdline.default"))
1454 templater.templater(templater.templatepath("map-cmdline.default"))
1455 except Exception, inst:
1455 except Exception, inst:
1456 ui.write(" %s\n" % inst)
1456 ui.write(" %s\n" % inst)
1457 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1457 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1458 problems += 1
1458 problems += 1
1459
1459
1460 # patch
1460 # patch
1461 ui.status(_("Checking patch...\n"))
1461 ui.status(_("Checking patch...\n"))
1462 patchproblems = 0
1462 patchproblems = 0
1463 a = "1\n2\n3\n4\n"
1463 a = "1\n2\n3\n4\n"
1464 b = "1\n2\n3\ninsert\n4\n"
1464 b = "1\n2\n3\ninsert\n4\n"
1465 fa = writetemp(a)
1465 fa = writetemp(a)
1466 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1466 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1467 os.path.basename(fa))
1467 os.path.basename(fa))
1468 fd = writetemp(d)
1468 fd = writetemp(d)
1469
1469
1470 files = {}
1470 files = {}
1471 try:
1471 try:
1472 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1472 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1473 except util.Abort, e:
1473 except util.Abort, e:
1474 ui.write(_(" patch call failed:\n"))
1474 ui.write(_(" patch call failed:\n"))
1475 ui.write(" " + str(e) + "\n")
1475 ui.write(" " + str(e) + "\n")
1476 patchproblems += 1
1476 patchproblems += 1
1477 else:
1477 else:
1478 if list(files) != [os.path.basename(fa)]:
1478 if list(files) != [os.path.basename(fa)]:
1479 ui.write(_(" unexpected patch output!\n"))
1479 ui.write(_(" unexpected patch output!\n"))
1480 patchproblems += 1
1480 patchproblems += 1
1481 a = open(fa).read()
1481 a = open(fa).read()
1482 if a != b:
1482 if a != b:
1483 ui.write(_(" patch test failed!\n"))
1483 ui.write(_(" patch test failed!\n"))
1484 patchproblems += 1
1484 patchproblems += 1
1485
1485
1486 if patchproblems:
1486 if patchproblems:
1487 if ui.config('ui', 'patch'):
1487 if ui.config('ui', 'patch'):
1488 ui.write(_(" (Current patch tool may be incompatible with patch,"
1488 ui.write(_(" (Current patch tool may be incompatible with patch,"
1489 " or misconfigured. Please check your configuration"
1489 " or misconfigured. Please check your configuration"
1490 " file)\n"))
1490 " file)\n"))
1491 else:
1491 else:
1492 ui.write(_(" Internal patcher failure, please report this error"
1492 ui.write(_(" Internal patcher failure, please report this error"
1493 " to http://mercurial.selenic.com/wiki/BugTracker\n"))
1493 " to http://mercurial.selenic.com/wiki/BugTracker\n"))
1494 problems += patchproblems
1494 problems += patchproblems
1495
1495
1496 os.unlink(fa)
1496 os.unlink(fa)
1497 os.unlink(fd)
1497 os.unlink(fd)
1498
1498
1499 # editor
1499 # editor
1500 ui.status(_("Checking commit editor...\n"))
1500 ui.status(_("Checking commit editor...\n"))
1501 editor = ui.geteditor()
1501 editor = ui.geteditor()
1502 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1502 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1503 if not cmdpath:
1503 if not cmdpath:
1504 if editor == 'vi':
1504 if editor == 'vi':
1505 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1505 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1506 ui.write(_(" (specify a commit editor in your configuration"
1506 ui.write(_(" (specify a commit editor in your configuration"
1507 " file)\n"))
1507 " file)\n"))
1508 else:
1508 else:
1509 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1509 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1510 ui.write(_(" (specify a commit editor in your configuration"
1510 ui.write(_(" (specify a commit editor in your configuration"
1511 " file)\n"))
1511 " file)\n"))
1512 problems += 1
1512 problems += 1
1513
1513
1514 # check username
1514 # check username
1515 ui.status(_("Checking username...\n"))
1515 ui.status(_("Checking username...\n"))
1516 try:
1516 try:
1517 ui.username()
1517 ui.username()
1518 except util.Abort, e:
1518 except util.Abort, e:
1519 ui.write(" %s\n" % e)
1519 ui.write(" %s\n" % e)
1520 ui.write(_(" (specify a username in your configuration file)\n"))
1520 ui.write(_(" (specify a username in your configuration file)\n"))
1521 problems += 1
1521 problems += 1
1522
1522
1523 if not problems:
1523 if not problems:
1524 ui.status(_("No problems detected\n"))
1524 ui.status(_("No problems detected\n"))
1525 else:
1525 else:
1526 ui.write(_("%s problems detected,"
1526 ui.write(_("%s problems detected,"
1527 " please check your install!\n") % problems)
1527 " please check your install!\n") % problems)
1528
1528
1529 return problems
1529 return problems
1530
1530
1531 def debugrename(ui, repo, file1, *pats, **opts):
1531 def debugrename(ui, repo, file1, *pats, **opts):
1532 """dump rename information"""
1532 """dump rename information"""
1533
1533
1534 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1534 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1535 m = cmdutil.match(repo, (file1,) + pats, opts)
1535 m = cmdutil.match(repo, (file1,) + pats, opts)
1536 for abs in ctx.walk(m):
1536 for abs in ctx.walk(m):
1537 fctx = ctx[abs]
1537 fctx = ctx[abs]
1538 o = fctx.filelog().renamed(fctx.filenode())
1538 o = fctx.filelog().renamed(fctx.filenode())
1539 rel = m.rel(abs)
1539 rel = m.rel(abs)
1540 if o:
1540 if o:
1541 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1541 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1542 else:
1542 else:
1543 ui.write(_("%s not renamed\n") % rel)
1543 ui.write(_("%s not renamed\n") % rel)
1544
1544
1545 def debugwalk(ui, repo, *pats, **opts):
1545 def debugwalk(ui, repo, *pats, **opts):
1546 """show how files match on given patterns"""
1546 """show how files match on given patterns"""
1547 m = cmdutil.match(repo, pats, opts)
1547 m = cmdutil.match(repo, pats, opts)
1548 items = list(repo.walk(m))
1548 items = list(repo.walk(m))
1549 if not items:
1549 if not items:
1550 return
1550 return
1551 fmt = 'f %%-%ds %%-%ds %%s' % (
1551 fmt = 'f %%-%ds %%-%ds %%s' % (
1552 max([len(abs) for abs in items]),
1552 max([len(abs) for abs in items]),
1553 max([len(m.rel(abs)) for abs in items]))
1553 max([len(m.rel(abs)) for abs in items]))
1554 for abs in items:
1554 for abs in items:
1555 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1555 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1556 ui.write("%s\n" % line.rstrip())
1556 ui.write("%s\n" % line.rstrip())
1557
1557
1558 def diff(ui, repo, *pats, **opts):
1558 def diff(ui, repo, *pats, **opts):
1559 """diff repository (or selected files)
1559 """diff repository (or selected files)
1560
1560
1561 Show differences between revisions for the specified files.
1561 Show differences between revisions for the specified files.
1562
1562
1563 Differences between files are shown using the unified diff format.
1563 Differences between files are shown using the unified diff format.
1564
1564
1565 .. note::
1565 .. note::
1566 diff may generate unexpected results for merges, as it will
1566 diff may generate unexpected results for merges, as it will
1567 default to comparing against the working directory's first
1567 default to comparing against the working directory's first
1568 parent changeset if no revisions are specified.
1568 parent changeset if no revisions are specified.
1569
1569
1570 When two revision arguments are given, then changes are shown
1570 When two revision arguments are given, then changes are shown
1571 between those revisions. If only one revision is specified then
1571 between those revisions. If only one revision is specified then
1572 that revision is compared to the working directory, and, when no
1572 that revision is compared to the working directory, and, when no
1573 revisions are specified, the working directory files are compared
1573 revisions are specified, the working directory files are compared
1574 to its parent.
1574 to its parent.
1575
1575
1576 Alternatively you can specify -c/--change with a revision to see
1576 Alternatively you can specify -c/--change with a revision to see
1577 the changes in that changeset relative to its first parent.
1577 the changes in that changeset relative to its first parent.
1578
1578
1579 Without the -a/--text option, diff will avoid generating diffs of
1579 Without the -a/--text option, diff will avoid generating diffs of
1580 files it detects as binary. With -a, diff will generate a diff
1580 files it detects as binary. With -a, diff will generate a diff
1581 anyway, probably with undesirable results.
1581 anyway, probably with undesirable results.
1582
1582
1583 Use the -g/--git option to generate diffs in the git extended diff
1583 Use the -g/--git option to generate diffs in the git extended diff
1584 format. For more information, read :hg:`help diffs`.
1584 format. For more information, read :hg:`help diffs`.
1585
1585
1586 Returns 0 on success.
1586 Returns 0 on success.
1587 """
1587 """
1588
1588
1589 revs = opts.get('rev')
1589 revs = opts.get('rev')
1590 change = opts.get('change')
1590 change = opts.get('change')
1591 stat = opts.get('stat')
1591 stat = opts.get('stat')
1592 reverse = opts.get('reverse')
1592 reverse = opts.get('reverse')
1593
1593
1594 if revs and change:
1594 if revs and change:
1595 msg = _('cannot specify --rev and --change at the same time')
1595 msg = _('cannot specify --rev and --change at the same time')
1596 raise util.Abort(msg)
1596 raise util.Abort(msg)
1597 elif change:
1597 elif change:
1598 node2 = repo.lookup(change)
1598 node2 = repo.lookup(change)
1599 node1 = repo[node2].parents()[0].node()
1599 node1 = repo[node2].parents()[0].node()
1600 else:
1600 else:
1601 node1, node2 = cmdutil.revpair(repo, revs)
1601 node1, node2 = cmdutil.revpair(repo, revs)
1602
1602
1603 if reverse:
1603 if reverse:
1604 node1, node2 = node2, node1
1604 node1, node2 = node2, node1
1605
1605
1606 diffopts = patch.diffopts(ui, opts)
1606 diffopts = patch.diffopts(ui, opts)
1607 m = cmdutil.match(repo, pats, opts)
1607 m = cmdutil.match(repo, pats, opts)
1608 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1608 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1609 listsubrepos=opts.get('subrepos'))
1609 listsubrepos=opts.get('subrepos'))
1610
1610
1611 def export(ui, repo, *changesets, **opts):
1611 def export(ui, repo, *changesets, **opts):
1612 """dump the header and diffs for one or more changesets
1612 """dump the header and diffs for one or more changesets
1613
1613
1614 Print the changeset header and diffs for one or more revisions.
1614 Print the changeset header and diffs for one or more revisions.
1615
1615
1616 The information shown in the changeset header is: author, date,
1616 The information shown in the changeset header is: author, date,
1617 branch name (if non-default), changeset hash, parent(s) and commit
1617 branch name (if non-default), changeset hash, parent(s) and commit
1618 comment.
1618 comment.
1619
1619
1620 .. note::
1620 .. note::
1621 export may generate unexpected diff output for merge
1621 export may generate unexpected diff output for merge
1622 changesets, as it will compare the merge changeset against its
1622 changesets, as it will compare the merge changeset against its
1623 first parent only.
1623 first parent only.
1624
1624
1625 Output may be to a file, in which case the name of the file is
1625 Output may be to a file, in which case the name of the file is
1626 given using a format string. The formatting rules are as follows:
1626 given using a format string. The formatting rules are as follows:
1627
1627
1628 :``%%``: literal "%" character
1628 :``%%``: literal "%" character
1629 :``%H``: changeset hash (40 hexadecimal digits)
1629 :``%H``: changeset hash (40 hexadecimal digits)
1630 :``%N``: number of patches being generated
1630 :``%N``: number of patches being generated
1631 :``%R``: changeset revision number
1631 :``%R``: changeset revision number
1632 :``%b``: basename of the exporting repository
1632 :``%b``: basename of the exporting repository
1633 :``%h``: short-form changeset hash (12 hexadecimal digits)
1633 :``%h``: short-form changeset hash (12 hexadecimal digits)
1634 :``%n``: zero-padded sequence number, starting at 1
1634 :``%n``: zero-padded sequence number, starting at 1
1635 :``%r``: zero-padded changeset revision number
1635 :``%r``: zero-padded changeset revision number
1636
1636
1637 Without the -a/--text option, export will avoid generating diffs
1637 Without the -a/--text option, export will avoid generating diffs
1638 of files it detects as binary. With -a, export will generate a
1638 of files it detects as binary. With -a, export will generate a
1639 diff anyway, probably with undesirable results.
1639 diff anyway, probably with undesirable results.
1640
1640
1641 Use the -g/--git option to generate diffs in the git extended diff
1641 Use the -g/--git option to generate diffs in the git extended diff
1642 format. See :hg:`help diffs` for more information.
1642 format. See :hg:`help diffs` for more information.
1643
1643
1644 With the --switch-parent option, the diff will be against the
1644 With the --switch-parent option, the diff will be against the
1645 second parent. It can be useful to review a merge.
1645 second parent. It can be useful to review a merge.
1646
1646
1647 Returns 0 on success.
1647 Returns 0 on success.
1648 """
1648 """
1649 changesets += tuple(opts.get('rev', []))
1649 changesets += tuple(opts.get('rev', []))
1650 if not changesets:
1650 if not changesets:
1651 raise util.Abort(_("export requires at least one changeset"))
1651 raise util.Abort(_("export requires at least one changeset"))
1652 revs = cmdutil.revrange(repo, changesets)
1652 revs = cmdutil.revrange(repo, changesets)
1653 if len(revs) > 1:
1653 if len(revs) > 1:
1654 ui.note(_('exporting patches:\n'))
1654 ui.note(_('exporting patches:\n'))
1655 else:
1655 else:
1656 ui.note(_('exporting patch:\n'))
1656 ui.note(_('exporting patch:\n'))
1657 cmdutil.export(repo, revs, template=opts.get('output'),
1657 cmdutil.export(repo, revs, template=opts.get('output'),
1658 switch_parent=opts.get('switch_parent'),
1658 switch_parent=opts.get('switch_parent'),
1659 opts=patch.diffopts(ui, opts))
1659 opts=patch.diffopts(ui, opts))
1660
1660
1661 def forget(ui, repo, *pats, **opts):
1661 def forget(ui, repo, *pats, **opts):
1662 """forget the specified files on the next commit
1662 """forget the specified files on the next commit
1663
1663
1664 Mark the specified files so they will no longer be tracked
1664 Mark the specified files so they will no longer be tracked
1665 after the next commit.
1665 after the next commit.
1666
1666
1667 This only removes files from the current branch, not from the
1667 This only removes files from the current branch, not from the
1668 entire project history, and it does not delete them from the
1668 entire project history, and it does not delete them from the
1669 working directory.
1669 working directory.
1670
1670
1671 To undo a forget before the next commit, see :hg:`add`.
1671 To undo a forget before the next commit, see :hg:`add`.
1672
1672
1673 Returns 0 on success.
1673 Returns 0 on success.
1674 """
1674 """
1675
1675
1676 if not pats:
1676 if not pats:
1677 raise util.Abort(_('no files specified'))
1677 raise util.Abort(_('no files specified'))
1678
1678
1679 m = cmdutil.match(repo, pats, opts)
1679 m = cmdutil.match(repo, pats, opts)
1680 s = repo.status(match=m, clean=True)
1680 s = repo.status(match=m, clean=True)
1681 forget = sorted(s[0] + s[1] + s[3] + s[6])
1681 forget = sorted(s[0] + s[1] + s[3] + s[6])
1682 errs = 0
1682 errs = 0
1683
1683
1684 for f in m.files():
1684 for f in m.files():
1685 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1685 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1686 ui.warn(_('not removing %s: file is already untracked\n')
1686 ui.warn(_('not removing %s: file is already untracked\n')
1687 % m.rel(f))
1687 % m.rel(f))
1688 errs = 1
1688 errs = 1
1689
1689
1690 for f in forget:
1690 for f in forget:
1691 if ui.verbose or not m.exact(f):
1691 if ui.verbose or not m.exact(f):
1692 ui.status(_('removing %s\n') % m.rel(f))
1692 ui.status(_('removing %s\n') % m.rel(f))
1693
1693
1694 repo[None].remove(forget, unlink=False)
1694 repo[None].remove(forget, unlink=False)
1695 return errs
1695 return errs
1696
1696
1697 def grep(ui, repo, pattern, *pats, **opts):
1697 def grep(ui, repo, pattern, *pats, **opts):
1698 """search for a pattern in specified files and revisions
1698 """search for a pattern in specified files and revisions
1699
1699
1700 Search revisions of files for a regular expression.
1700 Search revisions of files for a regular expression.
1701
1701
1702 This command behaves differently than Unix grep. It only accepts
1702 This command behaves differently than Unix grep. It only accepts
1703 Python/Perl regexps. It searches repository history, not the
1703 Python/Perl regexps. It searches repository history, not the
1704 working directory. It always prints the revision number in which a
1704 working directory. It always prints the revision number in which a
1705 match appears.
1705 match appears.
1706
1706
1707 By default, grep only prints output for the first revision of a
1707 By default, grep only prints output for the first revision of a
1708 file in which it finds a match. To get it to print every revision
1708 file in which it finds a match. To get it to print every revision
1709 that contains a change in match status ("-" for a match that
1709 that contains a change in match status ("-" for a match that
1710 becomes a non-match, or "+" for a non-match that becomes a match),
1710 becomes a non-match, or "+" for a non-match that becomes a match),
1711 use the --all flag.
1711 use the --all flag.
1712
1712
1713 Returns 0 if a match is found, 1 otherwise.
1713 Returns 0 if a match is found, 1 otherwise.
1714 """
1714 """
1715 reflags = 0
1715 reflags = 0
1716 if opts.get('ignore_case'):
1716 if opts.get('ignore_case'):
1717 reflags |= re.I
1717 reflags |= re.I
1718 try:
1718 try:
1719 regexp = re.compile(pattern, reflags)
1719 regexp = re.compile(pattern, reflags)
1720 except re.error, inst:
1720 except re.error, inst:
1721 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1721 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1722 return 1
1722 return 1
1723 sep, eol = ':', '\n'
1723 sep, eol = ':', '\n'
1724 if opts.get('print0'):
1724 if opts.get('print0'):
1725 sep = eol = '\0'
1725 sep = eol = '\0'
1726
1726
1727 getfile = util.lrucachefunc(repo.file)
1727 getfile = util.lrucachefunc(repo.file)
1728
1728
1729 def matchlines(body):
1729 def matchlines(body):
1730 begin = 0
1730 begin = 0
1731 linenum = 0
1731 linenum = 0
1732 while True:
1732 while True:
1733 match = regexp.search(body, begin)
1733 match = regexp.search(body, begin)
1734 if not match:
1734 if not match:
1735 break
1735 break
1736 mstart, mend = match.span()
1736 mstart, mend = match.span()
1737 linenum += body.count('\n', begin, mstart) + 1
1737 linenum += body.count('\n', begin, mstart) + 1
1738 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1738 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1739 begin = body.find('\n', mend) + 1 or len(body)
1739 begin = body.find('\n', mend) + 1 or len(body)
1740 lend = begin - 1
1740 lend = begin - 1
1741 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1741 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1742
1742
1743 class linestate(object):
1743 class linestate(object):
1744 def __init__(self, line, linenum, colstart, colend):
1744 def __init__(self, line, linenum, colstart, colend):
1745 self.line = line
1745 self.line = line
1746 self.linenum = linenum
1746 self.linenum = linenum
1747 self.colstart = colstart
1747 self.colstart = colstart
1748 self.colend = colend
1748 self.colend = colend
1749
1749
1750 def __hash__(self):
1750 def __hash__(self):
1751 return hash((self.linenum, self.line))
1751 return hash((self.linenum, self.line))
1752
1752
1753 def __eq__(self, other):
1753 def __eq__(self, other):
1754 return self.line == other.line
1754 return self.line == other.line
1755
1755
1756 matches = {}
1756 matches = {}
1757 copies = {}
1757 copies = {}
1758 def grepbody(fn, rev, body):
1758 def grepbody(fn, rev, body):
1759 matches[rev].setdefault(fn, [])
1759 matches[rev].setdefault(fn, [])
1760 m = matches[rev][fn]
1760 m = matches[rev][fn]
1761 for lnum, cstart, cend, line in matchlines(body):
1761 for lnum, cstart, cend, line in matchlines(body):
1762 s = linestate(line, lnum, cstart, cend)
1762 s = linestate(line, lnum, cstart, cend)
1763 m.append(s)
1763 m.append(s)
1764
1764
1765 def difflinestates(a, b):
1765 def difflinestates(a, b):
1766 sm = difflib.SequenceMatcher(None, a, b)
1766 sm = difflib.SequenceMatcher(None, a, b)
1767 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1767 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1768 if tag == 'insert':
1768 if tag == 'insert':
1769 for i in xrange(blo, bhi):
1769 for i in xrange(blo, bhi):
1770 yield ('+', b[i])
1770 yield ('+', b[i])
1771 elif tag == 'delete':
1771 elif tag == 'delete':
1772 for i in xrange(alo, ahi):
1772 for i in xrange(alo, ahi):
1773 yield ('-', a[i])
1773 yield ('-', a[i])
1774 elif tag == 'replace':
1774 elif tag == 'replace':
1775 for i in xrange(alo, ahi):
1775 for i in xrange(alo, ahi):
1776 yield ('-', a[i])
1776 yield ('-', a[i])
1777 for i in xrange(blo, bhi):
1777 for i in xrange(blo, bhi):
1778 yield ('+', b[i])
1778 yield ('+', b[i])
1779
1779
1780 def display(fn, ctx, pstates, states):
1780 def display(fn, ctx, pstates, states):
1781 rev = ctx.rev()
1781 rev = ctx.rev()
1782 datefunc = ui.quiet and util.shortdate or util.datestr
1782 datefunc = ui.quiet and util.shortdate or util.datestr
1783 found = False
1783 found = False
1784 filerevmatches = {}
1784 filerevmatches = {}
1785 if opts.get('all'):
1785 if opts.get('all'):
1786 iter = difflinestates(pstates, states)
1786 iter = difflinestates(pstates, states)
1787 else:
1787 else:
1788 iter = [('', l) for l in states]
1788 iter = [('', l) for l in states]
1789 for change, l in iter:
1789 for change, l in iter:
1790 cols = [fn, str(rev)]
1790 cols = [fn, str(rev)]
1791 before, match, after = None, None, None
1791 before, match, after = None, None, None
1792 if opts.get('line_number'):
1792 if opts.get('line_number'):
1793 cols.append(str(l.linenum))
1793 cols.append(str(l.linenum))
1794 if opts.get('all'):
1794 if opts.get('all'):
1795 cols.append(change)
1795 cols.append(change)
1796 if opts.get('user'):
1796 if opts.get('user'):
1797 cols.append(ui.shortuser(ctx.user()))
1797 cols.append(ui.shortuser(ctx.user()))
1798 if opts.get('date'):
1798 if opts.get('date'):
1799 cols.append(datefunc(ctx.date()))
1799 cols.append(datefunc(ctx.date()))
1800 if opts.get('files_with_matches'):
1800 if opts.get('files_with_matches'):
1801 c = (fn, rev)
1801 c = (fn, rev)
1802 if c in filerevmatches:
1802 if c in filerevmatches:
1803 continue
1803 continue
1804 filerevmatches[c] = 1
1804 filerevmatches[c] = 1
1805 else:
1805 else:
1806 before = l.line[:l.colstart]
1806 before = l.line[:l.colstart]
1807 match = l.line[l.colstart:l.colend]
1807 match = l.line[l.colstart:l.colend]
1808 after = l.line[l.colend:]
1808 after = l.line[l.colend:]
1809 ui.write(sep.join(cols))
1809 ui.write(sep.join(cols))
1810 if before is not None:
1810 if before is not None:
1811 ui.write(sep + before)
1811 ui.write(sep + before)
1812 ui.write(match, label='grep.match')
1812 ui.write(match, label='grep.match')
1813 ui.write(after)
1813 ui.write(after)
1814 ui.write(eol)
1814 ui.write(eol)
1815 found = True
1815 found = True
1816 return found
1816 return found
1817
1817
1818 skip = {}
1818 skip = {}
1819 revfiles = {}
1819 revfiles = {}
1820 matchfn = cmdutil.match(repo, pats, opts)
1820 matchfn = cmdutil.match(repo, pats, opts)
1821 found = False
1821 found = False
1822 follow = opts.get('follow')
1822 follow = opts.get('follow')
1823
1823
1824 def prep(ctx, fns):
1824 def prep(ctx, fns):
1825 rev = ctx.rev()
1825 rev = ctx.rev()
1826 pctx = ctx.parents()[0]
1826 pctx = ctx.parents()[0]
1827 parent = pctx.rev()
1827 parent = pctx.rev()
1828 matches.setdefault(rev, {})
1828 matches.setdefault(rev, {})
1829 matches.setdefault(parent, {})
1829 matches.setdefault(parent, {})
1830 files = revfiles.setdefault(rev, [])
1830 files = revfiles.setdefault(rev, [])
1831 for fn in fns:
1831 for fn in fns:
1832 flog = getfile(fn)
1832 flog = getfile(fn)
1833 try:
1833 try:
1834 fnode = ctx.filenode(fn)
1834 fnode = ctx.filenode(fn)
1835 except error.LookupError:
1835 except error.LookupError:
1836 continue
1836 continue
1837
1837
1838 copied = flog.renamed(fnode)
1838 copied = flog.renamed(fnode)
1839 copy = follow and copied and copied[0]
1839 copy = follow and copied and copied[0]
1840 if copy:
1840 if copy:
1841 copies.setdefault(rev, {})[fn] = copy
1841 copies.setdefault(rev, {})[fn] = copy
1842 if fn in skip:
1842 if fn in skip:
1843 if copy:
1843 if copy:
1844 skip[copy] = True
1844 skip[copy] = True
1845 continue
1845 continue
1846 files.append(fn)
1846 files.append(fn)
1847
1847
1848 if fn not in matches[rev]:
1848 if fn not in matches[rev]:
1849 grepbody(fn, rev, flog.read(fnode))
1849 grepbody(fn, rev, flog.read(fnode))
1850
1850
1851 pfn = copy or fn
1851 pfn = copy or fn
1852 if pfn not in matches[parent]:
1852 if pfn not in matches[parent]:
1853 try:
1853 try:
1854 fnode = pctx.filenode(pfn)
1854 fnode = pctx.filenode(pfn)
1855 grepbody(pfn, parent, flog.read(fnode))
1855 grepbody(pfn, parent, flog.read(fnode))
1856 except error.LookupError:
1856 except error.LookupError:
1857 pass
1857 pass
1858
1858
1859 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1859 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1860 rev = ctx.rev()
1860 rev = ctx.rev()
1861 parent = ctx.parents()[0].rev()
1861 parent = ctx.parents()[0].rev()
1862 for fn in sorted(revfiles.get(rev, [])):
1862 for fn in sorted(revfiles.get(rev, [])):
1863 states = matches[rev][fn]
1863 states = matches[rev][fn]
1864 copy = copies.get(rev, {}).get(fn)
1864 copy = copies.get(rev, {}).get(fn)
1865 if fn in skip:
1865 if fn in skip:
1866 if copy:
1866 if copy:
1867 skip[copy] = True
1867 skip[copy] = True
1868 continue
1868 continue
1869 pstates = matches.get(parent, {}).get(copy or fn, [])
1869 pstates = matches.get(parent, {}).get(copy or fn, [])
1870 if pstates or states:
1870 if pstates or states:
1871 r = display(fn, ctx, pstates, states)
1871 r = display(fn, ctx, pstates, states)
1872 found = found or r
1872 found = found or r
1873 if r and not opts.get('all'):
1873 if r and not opts.get('all'):
1874 skip[fn] = True
1874 skip[fn] = True
1875 if copy:
1875 if copy:
1876 skip[copy] = True
1876 skip[copy] = True
1877 del matches[rev]
1877 del matches[rev]
1878 del revfiles[rev]
1878 del revfiles[rev]
1879
1879
1880 return not found
1880 return not found
1881
1881
1882 def heads(ui, repo, *branchrevs, **opts):
1882 def heads(ui, repo, *branchrevs, **opts):
1883 """show current repository heads or show branch heads
1883 """show current repository heads or show branch heads
1884
1884
1885 With no arguments, show all repository branch heads.
1885 With no arguments, show all repository branch heads.
1886
1886
1887 Repository "heads" are changesets with no child changesets. They are
1887 Repository "heads" are changesets with no child changesets. They are
1888 where development generally takes place and are the usual targets
1888 where development generally takes place and are the usual targets
1889 for update and merge operations. Branch heads are changesets that have
1889 for update and merge operations. Branch heads are changesets that have
1890 no child changeset on the same branch.
1890 no child changeset on the same branch.
1891
1891
1892 If one or more REVs are given, only branch heads on the branches
1892 If one or more REVs are given, only branch heads on the branches
1893 associated with the specified changesets are shown.
1893 associated with the specified changesets are shown.
1894
1894
1895 If -c/--closed is specified, also show branch heads marked closed
1895 If -c/--closed is specified, also show branch heads marked closed
1896 (see :hg:`commit --close-branch`).
1896 (see :hg:`commit --close-branch`).
1897
1897
1898 If STARTREV is specified, only those heads that are descendants of
1898 If STARTREV is specified, only those heads that are descendants of
1899 STARTREV will be displayed.
1899 STARTREV will be displayed.
1900
1900
1901 If -t/--topo is specified, named branch mechanics will be ignored and only
1901 If -t/--topo is specified, named branch mechanics will be ignored and only
1902 changesets without children will be shown.
1902 changesets without children will be shown.
1903
1903
1904 Returns 0 if matching heads are found, 1 if not.
1904 Returns 0 if matching heads are found, 1 if not.
1905 """
1905 """
1906
1906
1907 start = None
1907 start = None
1908 if 'rev' in opts:
1908 if 'rev' in opts:
1909 start = cmdutil.revsingle(repo, opts['rev'], None).node()
1909 start = cmdutil.revsingle(repo, opts['rev'], None).node()
1910
1910
1911 if opts.get('topo'):
1911 if opts.get('topo'):
1912 heads = [repo[h] for h in repo.heads(start)]
1912 heads = [repo[h] for h in repo.heads(start)]
1913 else:
1913 else:
1914 heads = []
1914 heads = []
1915 for b, ls in repo.branchmap().iteritems():
1915 for b, ls in repo.branchmap().iteritems():
1916 if start is None:
1916 if start is None:
1917 heads += [repo[h] for h in ls]
1917 heads += [repo[h] for h in ls]
1918 continue
1918 continue
1919 startrev = repo.changelog.rev(start)
1919 startrev = repo.changelog.rev(start)
1920 descendants = set(repo.changelog.descendants(startrev))
1920 descendants = set(repo.changelog.descendants(startrev))
1921 descendants.add(startrev)
1921 descendants.add(startrev)
1922 rev = repo.changelog.rev
1922 rev = repo.changelog.rev
1923 heads += [repo[h] for h in ls if rev(h) in descendants]
1923 heads += [repo[h] for h in ls if rev(h) in descendants]
1924
1924
1925 if branchrevs:
1925 if branchrevs:
1926 branches = set(repo[br].branch() for br in branchrevs)
1926 branches = set(repo[br].branch() for br in branchrevs)
1927 heads = [h for h in heads if h.branch() in branches]
1927 heads = [h for h in heads if h.branch() in branches]
1928
1928
1929 if not opts.get('closed'):
1929 if not opts.get('closed'):
1930 heads = [h for h in heads if not h.extra().get('close')]
1930 heads = [h for h in heads if not h.extra().get('close')]
1931
1931
1932 if opts.get('active') and branchrevs:
1932 if opts.get('active') and branchrevs:
1933 dagheads = repo.heads(start)
1933 dagheads = repo.heads(start)
1934 heads = [h for h in heads if h.node() in dagheads]
1934 heads = [h for h in heads if h.node() in dagheads]
1935
1935
1936 if branchrevs:
1936 if branchrevs:
1937 haveheads = set(h.branch() for h in heads)
1937 haveheads = set(h.branch() for h in heads)
1938 if branches - haveheads:
1938 if branches - haveheads:
1939 headless = ', '.join(b for b in branches - haveheads)
1939 headless = ', '.join(b for b in branches - haveheads)
1940 msg = _('no open branch heads found on branches %s')
1940 msg = _('no open branch heads found on branches %s')
1941 if opts.get('rev'):
1941 if opts.get('rev'):
1942 msg += _(' (started at %s)' % opts['rev'])
1942 msg += _(' (started at %s)' % opts['rev'])
1943 ui.warn((msg + '\n') % headless)
1943 ui.warn((msg + '\n') % headless)
1944
1944
1945 if not heads:
1945 if not heads:
1946 return 1
1946 return 1
1947
1947
1948 heads = sorted(heads, key=lambda x: -x.rev())
1948 heads = sorted(heads, key=lambda x: -x.rev())
1949 displayer = cmdutil.show_changeset(ui, repo, opts)
1949 displayer = cmdutil.show_changeset(ui, repo, opts)
1950 for ctx in heads:
1950 for ctx in heads:
1951 displayer.show(ctx)
1951 displayer.show(ctx)
1952 displayer.close()
1952 displayer.close()
1953
1953
1954 def help_(ui, name=None, with_version=False, unknowncmd=False):
1954 def help_(ui, name=None, with_version=False, unknowncmd=False):
1955 """show help for a given topic or a help overview
1955 """show help for a given topic or a help overview
1956
1956
1957 With no arguments, print a list of commands with short help messages.
1957 With no arguments, print a list of commands with short help messages.
1958
1958
1959 Given a topic, extension, or command name, print help for that
1959 Given a topic, extension, or command name, print help for that
1960 topic.
1960 topic.
1961
1961
1962 Returns 0 if successful.
1962 Returns 0 if successful.
1963 """
1963 """
1964 option_lists = []
1964 option_lists = []
1965 textwidth = ui.termwidth() - 2
1965 textwidth = ui.termwidth() - 2
1966
1966
1967 def addglobalopts(aliases):
1967 def addglobalopts(aliases):
1968 if ui.verbose:
1968 if ui.verbose:
1969 option_lists.append((_("global options:"), globalopts))
1969 option_lists.append((_("global options:"), globalopts))
1970 if name == 'shortlist':
1970 if name == 'shortlist':
1971 option_lists.append((_('use "hg help" for the full list '
1971 option_lists.append((_('use "hg help" for the full list '
1972 'of commands'), ()))
1972 'of commands'), ()))
1973 else:
1973 else:
1974 if name == 'shortlist':
1974 if name == 'shortlist':
1975 msg = _('use "hg help" for the full list of commands '
1975 msg = _('use "hg help" for the full list of commands '
1976 'or "hg -v" for details')
1976 'or "hg -v" for details')
1977 elif aliases:
1977 elif aliases:
1978 msg = _('use "hg -v help%s" to show builtin aliases and '
1978 msg = _('use "hg -v help%s" to show builtin aliases and '
1979 'global options') % (name and " " + name or "")
1979 'global options') % (name and " " + name or "")
1980 else:
1980 else:
1981 msg = _('use "hg -v help %s" to show global options') % name
1981 msg = _('use "hg -v help %s" to show global options') % name
1982 option_lists.append((msg, ()))
1982 option_lists.append((msg, ()))
1983
1983
1984 def helpcmd(name):
1984 def helpcmd(name):
1985 if with_version:
1985 if with_version:
1986 version_(ui)
1986 version_(ui)
1987 ui.write('\n')
1987 ui.write('\n')
1988
1988
1989 try:
1989 try:
1990 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1990 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1991 except error.AmbiguousCommand, inst:
1991 except error.AmbiguousCommand, inst:
1992 # py3k fix: except vars can't be used outside the scope of the
1992 # py3k fix: except vars can't be used outside the scope of the
1993 # except block, nor can be used inside a lambda. python issue4617
1993 # except block, nor can be used inside a lambda. python issue4617
1994 prefix = inst.args[0]
1994 prefix = inst.args[0]
1995 select = lambda c: c.lstrip('^').startswith(prefix)
1995 select = lambda c: c.lstrip('^').startswith(prefix)
1996 helplist(_('list of commands:\n\n'), select)
1996 helplist(_('list of commands:\n\n'), select)
1997 return
1997 return
1998
1998
1999 # check if it's an invalid alias and display its error if it is
1999 # check if it's an invalid alias and display its error if it is
2000 if getattr(entry[0], 'badalias', False):
2000 if getattr(entry[0], 'badalias', False):
2001 if not unknowncmd:
2001 if not unknowncmd:
2002 entry[0](ui)
2002 entry[0](ui)
2003 return
2003 return
2004
2004
2005 # synopsis
2005 # synopsis
2006 if len(entry) > 2:
2006 if len(entry) > 2:
2007 if entry[2].startswith('hg'):
2007 if entry[2].startswith('hg'):
2008 ui.write("%s\n" % entry[2])
2008 ui.write("%s\n" % entry[2])
2009 else:
2009 else:
2010 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2010 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2011 else:
2011 else:
2012 ui.write('hg %s\n' % aliases[0])
2012 ui.write('hg %s\n' % aliases[0])
2013
2013
2014 # aliases
2014 # aliases
2015 if not ui.quiet and len(aliases) > 1:
2015 if not ui.quiet and len(aliases) > 1:
2016 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2016 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2017
2017
2018 # description
2018 # description
2019 doc = gettext(entry[0].__doc__)
2019 doc = gettext(entry[0].__doc__)
2020 if not doc:
2020 if not doc:
2021 doc = _("(no help text available)")
2021 doc = _("(no help text available)")
2022 if hasattr(entry[0], 'definition'): # aliased command
2022 if hasattr(entry[0], 'definition'): # aliased command
2023 if entry[0].definition.startswith('!'): # shell alias
2023 if entry[0].definition.startswith('!'): # shell alias
2024 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2024 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2025 else:
2025 else:
2026 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2026 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2027 if ui.quiet:
2027 if ui.quiet:
2028 doc = doc.splitlines()[0]
2028 doc = doc.splitlines()[0]
2029 keep = ui.verbose and ['verbose'] or []
2029 keep = ui.verbose and ['verbose'] or []
2030 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2030 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2031 ui.write("\n%s\n" % formatted)
2031 ui.write("\n%s\n" % formatted)
2032 if pruned:
2032 if pruned:
2033 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2033 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2034
2034
2035 if not ui.quiet:
2035 if not ui.quiet:
2036 # options
2036 # options
2037 if entry[1]:
2037 if entry[1]:
2038 option_lists.append((_("options:\n"), entry[1]))
2038 option_lists.append((_("options:\n"), entry[1]))
2039
2039
2040 addglobalopts(False)
2040 addglobalopts(False)
2041
2041
2042 def helplist(header, select=None):
2042 def helplist(header, select=None):
2043 h = {}
2043 h = {}
2044 cmds = {}
2044 cmds = {}
2045 for c, e in table.iteritems():
2045 for c, e in table.iteritems():
2046 f = c.split("|", 1)[0]
2046 f = c.split("|", 1)[0]
2047 if select and not select(f):
2047 if select and not select(f):
2048 continue
2048 continue
2049 if (not select and name != 'shortlist' and
2049 if (not select and name != 'shortlist' and
2050 e[0].__module__ != __name__):
2050 e[0].__module__ != __name__):
2051 continue
2051 continue
2052 if name == "shortlist" and not f.startswith("^"):
2052 if name == "shortlist" and not f.startswith("^"):
2053 continue
2053 continue
2054 f = f.lstrip("^")
2054 f = f.lstrip("^")
2055 if not ui.debugflag and f.startswith("debug"):
2055 if not ui.debugflag and f.startswith("debug"):
2056 continue
2056 continue
2057 doc = e[0].__doc__
2057 doc = e[0].__doc__
2058 if doc and 'DEPRECATED' in doc and not ui.verbose:
2058 if doc and 'DEPRECATED' in doc and not ui.verbose:
2059 continue
2059 continue
2060 doc = gettext(doc)
2060 doc = gettext(doc)
2061 if not doc:
2061 if not doc:
2062 doc = _("(no help text available)")
2062 doc = _("(no help text available)")
2063 h[f] = doc.splitlines()[0].rstrip()
2063 h[f] = doc.splitlines()[0].rstrip()
2064 cmds[f] = c.lstrip("^")
2064 cmds[f] = c.lstrip("^")
2065
2065
2066 if not h:
2066 if not h:
2067 ui.status(_('no commands defined\n'))
2067 ui.status(_('no commands defined\n'))
2068 return
2068 return
2069
2069
2070 ui.status(header)
2070 ui.status(header)
2071 fns = sorted(h)
2071 fns = sorted(h)
2072 m = max(map(len, fns))
2072 m = max(map(len, fns))
2073 for f in fns:
2073 for f in fns:
2074 if ui.verbose:
2074 if ui.verbose:
2075 commands = cmds[f].replace("|",", ")
2075 commands = cmds[f].replace("|",", ")
2076 ui.write(" %s:\n %s\n"%(commands, h[f]))
2076 ui.write(" %s:\n %s\n"%(commands, h[f]))
2077 else:
2077 else:
2078 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2078 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2079 initindent=' %-*s ' % (m, f),
2079 initindent=' %-*s ' % (m, f),
2080 hangindent=' ' * (m + 4))))
2080 hangindent=' ' * (m + 4))))
2081
2081
2082 if not ui.quiet:
2082 if not ui.quiet:
2083 addglobalopts(True)
2083 addglobalopts(True)
2084
2084
2085 def helptopic(name):
2085 def helptopic(name):
2086 for names, header, doc in help.helptable:
2086 for names, header, doc in help.helptable:
2087 if name in names:
2087 if name in names:
2088 break
2088 break
2089 else:
2089 else:
2090 raise error.UnknownCommand(name)
2090 raise error.UnknownCommand(name)
2091
2091
2092 # description
2092 # description
2093 if not doc:
2093 if not doc:
2094 doc = _("(no help text available)")
2094 doc = _("(no help text available)")
2095 if hasattr(doc, '__call__'):
2095 if hasattr(doc, '__call__'):
2096 doc = doc()
2096 doc = doc()
2097
2097
2098 ui.write("%s\n\n" % header)
2098 ui.write("%s\n\n" % header)
2099 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2099 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2100
2100
2101 def helpext(name):
2101 def helpext(name):
2102 try:
2102 try:
2103 mod = extensions.find(name)
2103 mod = extensions.find(name)
2104 doc = gettext(mod.__doc__) or _('no help text available')
2104 doc = gettext(mod.__doc__) or _('no help text available')
2105 except KeyError:
2105 except KeyError:
2106 mod = None
2106 mod = None
2107 doc = extensions.disabledext(name)
2107 doc = extensions.disabledext(name)
2108 if not doc:
2108 if not doc:
2109 raise error.UnknownCommand(name)
2109 raise error.UnknownCommand(name)
2110
2110
2111 if '\n' not in doc:
2111 if '\n' not in doc:
2112 head, tail = doc, ""
2112 head, tail = doc, ""
2113 else:
2113 else:
2114 head, tail = doc.split('\n', 1)
2114 head, tail = doc.split('\n', 1)
2115 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2115 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2116 if tail:
2116 if tail:
2117 ui.write(minirst.format(tail, textwidth))
2117 ui.write(minirst.format(tail, textwidth))
2118 ui.status('\n\n')
2118 ui.status('\n\n')
2119
2119
2120 if mod:
2120 if mod:
2121 try:
2121 try:
2122 ct = mod.cmdtable
2122 ct = mod.cmdtable
2123 except AttributeError:
2123 except AttributeError:
2124 ct = {}
2124 ct = {}
2125 modcmds = set([c.split('|', 1)[0] for c in ct])
2125 modcmds = set([c.split('|', 1)[0] for c in ct])
2126 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2126 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2127 else:
2127 else:
2128 ui.write(_('use "hg help extensions" for information on enabling '
2128 ui.write(_('use "hg help extensions" for information on enabling '
2129 'extensions\n'))
2129 'extensions\n'))
2130
2130
2131 def helpextcmd(name):
2131 def helpextcmd(name):
2132 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2132 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2133 doc = gettext(mod.__doc__).splitlines()[0]
2133 doc = gettext(mod.__doc__).splitlines()[0]
2134
2134
2135 msg = help.listexts(_("'%s' is provided by the following "
2135 msg = help.listexts(_("'%s' is provided by the following "
2136 "extension:") % cmd, {ext: doc}, len(ext),
2136 "extension:") % cmd, {ext: doc}, len(ext),
2137 indent=4)
2137 indent=4)
2138 ui.write(minirst.format(msg, textwidth))
2138 ui.write(minirst.format(msg, textwidth))
2139 ui.write('\n\n')
2139 ui.write('\n\n')
2140 ui.write(_('use "hg help extensions" for information on enabling '
2140 ui.write(_('use "hg help extensions" for information on enabling '
2141 'extensions\n'))
2141 'extensions\n'))
2142
2142
2143 help.addtopichook('revsets', revset.makedoc)
2143 help.addtopichook('revsets', revset.makedoc)
2144
2144
2145 if name and name != 'shortlist':
2145 if name and name != 'shortlist':
2146 i = None
2146 i = None
2147 if unknowncmd:
2147 if unknowncmd:
2148 queries = (helpextcmd,)
2148 queries = (helpextcmd,)
2149 else:
2149 else:
2150 queries = (helptopic, helpcmd, helpext, helpextcmd)
2150 queries = (helptopic, helpcmd, helpext, helpextcmd)
2151 for f in queries:
2151 for f in queries:
2152 try:
2152 try:
2153 f(name)
2153 f(name)
2154 i = None
2154 i = None
2155 break
2155 break
2156 except error.UnknownCommand, inst:
2156 except error.UnknownCommand, inst:
2157 i = inst
2157 i = inst
2158 if i:
2158 if i:
2159 raise i
2159 raise i
2160
2160
2161 else:
2161 else:
2162 # program name
2162 # program name
2163 if ui.verbose or with_version:
2163 if ui.verbose or with_version:
2164 version_(ui)
2164 version_(ui)
2165 else:
2165 else:
2166 ui.status(_("Mercurial Distributed SCM\n"))
2166 ui.status(_("Mercurial Distributed SCM\n"))
2167 ui.status('\n')
2167 ui.status('\n')
2168
2168
2169 # list of commands
2169 # list of commands
2170 if name == "shortlist":
2170 if name == "shortlist":
2171 header = _('basic commands:\n\n')
2171 header = _('basic commands:\n\n')
2172 else:
2172 else:
2173 header = _('list of commands:\n\n')
2173 header = _('list of commands:\n\n')
2174
2174
2175 helplist(header)
2175 helplist(header)
2176 if name != 'shortlist':
2176 if name != 'shortlist':
2177 exts, maxlength = extensions.enabled()
2177 exts, maxlength = extensions.enabled()
2178 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2178 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2179 if text:
2179 if text:
2180 ui.write("\n%s\n" % minirst.format(text, textwidth))
2180 ui.write("\n%s\n" % minirst.format(text, textwidth))
2181
2181
2182 # list all option lists
2182 # list all option lists
2183 opt_output = []
2183 opt_output = []
2184 multioccur = False
2184 multioccur = False
2185 for title, options in option_lists:
2185 for title, options in option_lists:
2186 opt_output.append(("\n%s" % title, None))
2186 opt_output.append(("\n%s" % title, None))
2187 for option in options:
2187 for option in options:
2188 if len(option) == 5:
2188 if len(option) == 5:
2189 shortopt, longopt, default, desc, optlabel = option
2189 shortopt, longopt, default, desc, optlabel = option
2190 else:
2190 else:
2191 shortopt, longopt, default, desc = option
2191 shortopt, longopt, default, desc = option
2192 optlabel = _("VALUE") # default label
2192 optlabel = _("VALUE") # default label
2193
2193
2194 if _("DEPRECATED") in desc and not ui.verbose:
2194 if _("DEPRECATED") in desc and not ui.verbose:
2195 continue
2195 continue
2196 if isinstance(default, list):
2196 if isinstance(default, list):
2197 numqualifier = " %s [+]" % optlabel
2197 numqualifier = " %s [+]" % optlabel
2198 multioccur = True
2198 multioccur = True
2199 elif (default is not None) and not isinstance(default, bool):
2199 elif (default is not None) and not isinstance(default, bool):
2200 numqualifier = " %s" % optlabel
2200 numqualifier = " %s" % optlabel
2201 else:
2201 else:
2202 numqualifier = ""
2202 numqualifier = ""
2203 opt_output.append(("%2s%s" %
2203 opt_output.append(("%2s%s" %
2204 (shortopt and "-%s" % shortopt,
2204 (shortopt and "-%s" % shortopt,
2205 longopt and " --%s%s" %
2205 longopt and " --%s%s" %
2206 (longopt, numqualifier)),
2206 (longopt, numqualifier)),
2207 "%s%s" % (desc,
2207 "%s%s" % (desc,
2208 default
2208 default
2209 and _(" (default: %s)") % default
2209 and _(" (default: %s)") % default
2210 or "")))
2210 or "")))
2211 if multioccur:
2211 if multioccur:
2212 msg = _("\n[+] marked option can be specified multiple times")
2212 msg = _("\n[+] marked option can be specified multiple times")
2213 if ui.verbose and name != 'shortlist':
2213 if ui.verbose and name != 'shortlist':
2214 opt_output.append((msg, None))
2214 opt_output.append((msg, None))
2215 else:
2215 else:
2216 opt_output.insert(-1, (msg, None))
2216 opt_output.insert(-1, (msg, None))
2217
2217
2218 if not name:
2218 if not name:
2219 ui.write(_("\nadditional help topics:\n\n"))
2219 ui.write(_("\nadditional help topics:\n\n"))
2220 topics = []
2220 topics = []
2221 for names, header, doc in help.helptable:
2221 for names, header, doc in help.helptable:
2222 topics.append((sorted(names, key=len, reverse=True)[0], header))
2222 topics.append((sorted(names, key=len, reverse=True)[0], header))
2223 topics_len = max([len(s[0]) for s in topics])
2223 topics_len = max([len(s[0]) for s in topics])
2224 for t, desc in topics:
2224 for t, desc in topics:
2225 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2225 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2226
2226
2227 if opt_output:
2227 if opt_output:
2228 colwidth = encoding.colwidth
2228 colwidth = encoding.colwidth
2229 # normalize: (opt or message, desc or None, width of opt)
2229 # normalize: (opt or message, desc or None, width of opt)
2230 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2230 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2231 for opt, desc in opt_output]
2231 for opt, desc in opt_output]
2232 hanging = max([e[2] for e in entries])
2232 hanging = max([e[2] for e in entries])
2233 for opt, desc, width in entries:
2233 for opt, desc, width in entries:
2234 if desc:
2234 if desc:
2235 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2235 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2236 hangindent = ' ' * (hanging + 3)
2236 hangindent = ' ' * (hanging + 3)
2237 ui.write('%s\n' % (util.wrap(desc, textwidth,
2237 ui.write('%s\n' % (util.wrap(desc, textwidth,
2238 initindent=initindent,
2238 initindent=initindent,
2239 hangindent=hangindent)))
2239 hangindent=hangindent)))
2240 else:
2240 else:
2241 ui.write("%s\n" % opt)
2241 ui.write("%s\n" % opt)
2242
2242
2243 def identify(ui, repo, source=None, rev=None,
2243 def identify(ui, repo, source=None, rev=None,
2244 num=None, id=None, branch=None, tags=None, bookmarks=None):
2244 num=None, id=None, branch=None, tags=None, bookmarks=None):
2245 """identify the working copy or specified revision
2245 """identify the working copy or specified revision
2246
2246
2247 Print a summary identifying the repository state at REV using one or
2247 Print a summary identifying the repository state at REV using one or
2248 two parent hash identifiers, followed by a "+" if the working
2248 two parent hash identifiers, followed by a "+" if the working
2249 directory has uncommitted changes, the branch name (if not default),
2249 directory has uncommitted changes, the branch name (if not default),
2250 a list of tags, and a list of bookmarks.
2250 a list of tags, and a list of bookmarks.
2251
2251
2252 When REV is not given, print a summary of the current state of the
2252 When REV is not given, print a summary of the current state of the
2253 repository.
2253 repository.
2254
2254
2255 Specifying a path to a repository root or Mercurial bundle will
2255 Specifying a path to a repository root or Mercurial bundle will
2256 cause lookup to operate on that repository/bundle.
2256 cause lookup to operate on that repository/bundle.
2257
2257
2258 Returns 0 if successful.
2258 Returns 0 if successful.
2259 """
2259 """
2260
2260
2261 if not repo and not source:
2261 if not repo and not source:
2262 raise util.Abort(_("there is no Mercurial repository here "
2262 raise util.Abort(_("there is no Mercurial repository here "
2263 "(.hg not found)"))
2263 "(.hg not found)"))
2264
2264
2265 hexfunc = ui.debugflag and hex or short
2265 hexfunc = ui.debugflag and hex or short
2266 default = not (num or id or branch or tags or bookmarks)
2266 default = not (num or id or branch or tags or bookmarks)
2267 output = []
2267 output = []
2268
2268
2269 revs = []
2269 revs = []
2270 if source:
2270 if source:
2271 source, branches = hg.parseurl(ui.expandpath(source))
2271 source, branches = hg.parseurl(ui.expandpath(source))
2272 repo = hg.repository(ui, source)
2272 repo = hg.repository(ui, source)
2273 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2273 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2274
2274
2275 if not repo.local():
2275 if not repo.local():
2276 if not rev and revs:
2276 if not rev and revs:
2277 rev = revs[0]
2277 rev = revs[0]
2278 if not rev:
2278 if not rev:
2279 rev = "tip"
2279 rev = "tip"
2280 if num or branch or tags or bookmarks:
2280 if num or branch or tags or bookmarks:
2281 raise util.Abort(_("can't query remote revision number,"
2281 raise util.Abort(_("can't query remote revision number,"
2282 " branch, tags, or bookmarks"))
2282 " branch, tags, or bookmarks"))
2283 output = [hexfunc(repo.lookup(rev))]
2283 output = [hexfunc(repo.lookup(rev))]
2284 elif not rev:
2284 elif not rev:
2285 ctx = repo[None]
2285 ctx = repo[None]
2286 parents = ctx.parents()
2286 parents = ctx.parents()
2287 changed = False
2287 changed = False
2288 if default or id or num:
2288 if default or id or num:
2289 changed = util.any(repo.status())
2289 changed = util.any(repo.status())
2290 if default or id:
2290 if default or id:
2291 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2291 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2292 (changed) and "+" or "")]
2292 (changed) and "+" or "")]
2293 if num:
2293 if num:
2294 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2294 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2295 (changed) and "+" or ""))
2295 (changed) and "+" or ""))
2296 else:
2296 else:
2297 ctx = cmdutil.revsingle(repo, rev)
2297 ctx = cmdutil.revsingle(repo, rev)
2298 if default or id:
2298 if default or id:
2299 output = [hexfunc(ctx.node())]
2299 output = [hexfunc(ctx.node())]
2300 if num:
2300 if num:
2301 output.append(str(ctx.rev()))
2301 output.append(str(ctx.rev()))
2302
2302
2303 if repo.local() and default and not ui.quiet:
2303 if repo.local() and default and not ui.quiet:
2304 b = ctx.branch()
2304 b = ctx.branch()
2305 if b != 'default':
2305 if b != 'default':
2306 output.append("(%s)" % b)
2306 output.append("(%s)" % b)
2307
2307
2308 # multiple tags for a single parent separated by '/'
2308 # multiple tags for a single parent separated by '/'
2309 t = "/".join(ctx.tags())
2309 t = "/".join(ctx.tags())
2310 if t:
2310 if t:
2311 output.append(t)
2311 output.append(t)
2312
2312
2313 # multiple bookmarks for a single parent separated by '/'
2313 # multiple bookmarks for a single parent separated by '/'
2314 bm = '/'.join(ctx.bookmarks())
2314 bm = '/'.join(ctx.bookmarks())
2315 if bm:
2315 if bm:
2316 output.append(bm)
2316 output.append(bm)
2317
2317
2318 if branch:
2318 if branch:
2319 output.append(ctx.branch())
2319 output.append(ctx.branch())
2320
2320
2321 if tags:
2321 if tags:
2322 output.extend(ctx.tags())
2322 output.extend(ctx.tags())
2323
2323
2324 if bookmarks:
2324 if bookmarks:
2325 output.extend(ctx.bookmarks())
2325 output.extend(ctx.bookmarks())
2326
2326
2327 ui.write("%s\n" % ' '.join(output))
2327 ui.write("%s\n" % ' '.join(output))
2328
2328
2329 def import_(ui, repo, patch1, *patches, **opts):
2329 def import_(ui, repo, patch1, *patches, **opts):
2330 """import an ordered set of patches
2330 """import an ordered set of patches
2331
2331
2332 Import a list of patches and commit them individually (unless
2332 Import a list of patches and commit them individually (unless
2333 --no-commit is specified).
2333 --no-commit is specified).
2334
2334
2335 If there are outstanding changes in the working directory, import
2335 If there are outstanding changes in the working directory, import
2336 will abort unless given the -f/--force flag.
2336 will abort unless given the -f/--force flag.
2337
2337
2338 You can import a patch straight from a mail message. Even patches
2338 You can import a patch straight from a mail message. Even patches
2339 as attachments work (to use the body part, it must have type
2339 as attachments work (to use the body part, it must have type
2340 text/plain or text/x-patch). From and Subject headers of email
2340 text/plain or text/x-patch). From and Subject headers of email
2341 message are used as default committer and commit message. All
2341 message are used as default committer and commit message. All
2342 text/plain body parts before first diff are added to commit
2342 text/plain body parts before first diff are added to commit
2343 message.
2343 message.
2344
2344
2345 If the imported patch was generated by :hg:`export`, user and
2345 If the imported patch was generated by :hg:`export`, user and
2346 description from patch override values from message headers and
2346 description from patch override values from message headers and
2347 body. Values given on command line with -m/--message and -u/--user
2347 body. Values given on command line with -m/--message and -u/--user
2348 override these.
2348 override these.
2349
2349
2350 If --exact is specified, import will set the working directory to
2350 If --exact is specified, import will set the working directory to
2351 the parent of each patch before applying it, and will abort if the
2351 the parent of each patch before applying it, and will abort if the
2352 resulting changeset has a different ID than the one recorded in
2352 resulting changeset has a different ID than the one recorded in
2353 the patch. This may happen due to character set problems or other
2353 the patch. This may happen due to character set problems or other
2354 deficiencies in the text patch format.
2354 deficiencies in the text patch format.
2355
2355
2356 With -s/--similarity, hg will attempt to discover renames and
2356 With -s/--similarity, hg will attempt to discover renames and
2357 copies in the patch in the same way as 'addremove'.
2357 copies in the patch in the same way as 'addremove'.
2358
2358
2359 To read a patch from standard input, use "-" as the patch name. If
2359 To read a patch from standard input, use "-" as the patch name. If
2360 a URL is specified, the patch will be downloaded from it.
2360 a URL is specified, the patch will be downloaded from it.
2361 See :hg:`help dates` for a list of formats valid for -d/--date.
2361 See :hg:`help dates` for a list of formats valid for -d/--date.
2362
2362
2363 Returns 0 on success.
2363 Returns 0 on success.
2364 """
2364 """
2365 patches = (patch1,) + patches
2365 patches = (patch1,) + patches
2366
2366
2367 date = opts.get('date')
2367 date = opts.get('date')
2368 if date:
2368 if date:
2369 opts['date'] = util.parsedate(date)
2369 opts['date'] = util.parsedate(date)
2370
2370
2371 try:
2371 try:
2372 sim = float(opts.get('similarity') or 0)
2372 sim = float(opts.get('similarity') or 0)
2373 except ValueError:
2373 except ValueError:
2374 raise util.Abort(_('similarity must be a number'))
2374 raise util.Abort(_('similarity must be a number'))
2375 if sim < 0 or sim > 100:
2375 if sim < 0 or sim > 100:
2376 raise util.Abort(_('similarity must be between 0 and 100'))
2376 raise util.Abort(_('similarity must be between 0 and 100'))
2377
2377
2378 if opts.get('exact') or not opts.get('force'):
2378 if opts.get('exact') or not opts.get('force'):
2379 cmdutil.bail_if_changed(repo)
2379 cmdutil.bail_if_changed(repo)
2380
2380
2381 d = opts["base"]
2381 d = opts["base"]
2382 strip = opts["strip"]
2382 strip = opts["strip"]
2383 wlock = lock = None
2383 wlock = lock = None
2384 msgs = []
2384 msgs = []
2385
2385
2386 def tryone(ui, hunk):
2386 def tryone(ui, hunk):
2387 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2387 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2388 patch.extract(ui, hunk)
2388 patch.extract(ui, hunk)
2389
2389
2390 if not tmpname:
2390 if not tmpname:
2391 return None
2391 return None
2392 commitid = _('to working directory')
2392 commitid = _('to working directory')
2393
2393
2394 try:
2394 try:
2395 cmdline_message = cmdutil.logmessage(opts)
2395 cmdline_message = cmdutil.logmessage(opts)
2396 if cmdline_message:
2396 if cmdline_message:
2397 # pickup the cmdline msg
2397 # pickup the cmdline msg
2398 message = cmdline_message
2398 message = cmdline_message
2399 elif message:
2399 elif message:
2400 # pickup the patch msg
2400 # pickup the patch msg
2401 message = message.strip()
2401 message = message.strip()
2402 else:
2402 else:
2403 # launch the editor
2403 # launch the editor
2404 message = None
2404 message = None
2405 ui.debug('message:\n%s\n' % message)
2405 ui.debug('message:\n%s\n' % message)
2406
2406
2407 wp = repo.parents()
2407 wp = repo.parents()
2408 if opts.get('exact'):
2408 if opts.get('exact'):
2409 if not nodeid or not p1:
2409 if not nodeid or not p1:
2410 raise util.Abort(_('not a Mercurial patch'))
2410 raise util.Abort(_('not a Mercurial patch'))
2411 p1 = repo.lookup(p1)
2411 p1 = repo.lookup(p1)
2412 p2 = repo.lookup(p2 or hex(nullid))
2412 p2 = repo.lookup(p2 or hex(nullid))
2413
2413
2414 if p1 != wp[0].node():
2414 if p1 != wp[0].node():
2415 hg.clean(repo, p1)
2415 hg.clean(repo, p1)
2416 repo.dirstate.setparents(p1, p2)
2416 repo.dirstate.setparents(p1, p2)
2417 elif p2:
2417 elif p2:
2418 try:
2418 try:
2419 p1 = repo.lookup(p1)
2419 p1 = repo.lookup(p1)
2420 p2 = repo.lookup(p2)
2420 p2 = repo.lookup(p2)
2421 if p1 == wp[0].node():
2421 if p1 == wp[0].node():
2422 repo.dirstate.setparents(p1, p2)
2422 repo.dirstate.setparents(p1, p2)
2423 except error.RepoError:
2423 except error.RepoError:
2424 pass
2424 pass
2425 if opts.get('exact') or opts.get('import_branch'):
2425 if opts.get('exact') or opts.get('import_branch'):
2426 repo.dirstate.setbranch(branch or 'default')
2426 repo.dirstate.setbranch(branch or 'default')
2427
2427
2428 files = {}
2428 files = {}
2429 try:
2429 try:
2430 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2430 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2431 files=files, eolmode=None)
2431 files=files, eolmode=None)
2432 finally:
2432 finally:
2433 files = cmdutil.updatedir(ui, repo, files,
2433 files = cmdutil.updatedir(ui, repo, files,
2434 similarity=sim / 100.0)
2434 similarity=sim / 100.0)
2435 if opts.get('no_commit'):
2435 if opts.get('no_commit'):
2436 if message:
2436 if message:
2437 msgs.append(message)
2437 msgs.append(message)
2438 else:
2438 else:
2439 if opts.get('exact'):
2439 if opts.get('exact'):
2440 m = None
2440 m = None
2441 else:
2441 else:
2442 m = cmdutil.matchfiles(repo, files or [])
2442 m = cmdutil.matchfiles(repo, files or [])
2443 n = repo.commit(message, opts.get('user') or user,
2443 n = repo.commit(message, opts.get('user') or user,
2444 opts.get('date') or date, match=m,
2444 opts.get('date') or date, match=m,
2445 editor=cmdutil.commiteditor)
2445 editor=cmdutil.commiteditor)
2446 if opts.get('exact'):
2446 if opts.get('exact'):
2447 if hex(n) != nodeid:
2447 if hex(n) != nodeid:
2448 repo.rollback()
2448 repo.rollback()
2449 raise util.Abort(_('patch is damaged'
2449 raise util.Abort(_('patch is damaged'
2450 ' or loses information'))
2450 ' or loses information'))
2451 # Force a dirstate write so that the next transaction
2451 # Force a dirstate write so that the next transaction
2452 # backups an up-do-date file.
2452 # backups an up-do-date file.
2453 repo.dirstate.write()
2453 repo.dirstate.write()
2454 if n:
2454 if n:
2455 commitid = short(n)
2455 commitid = short(n)
2456
2456
2457 return commitid
2457 return commitid
2458 finally:
2458 finally:
2459 os.unlink(tmpname)
2459 os.unlink(tmpname)
2460
2460
2461 try:
2461 try:
2462 wlock = repo.wlock()
2462 wlock = repo.wlock()
2463 lock = repo.lock()
2463 lock = repo.lock()
2464 lastcommit = None
2464 lastcommit = None
2465 for p in patches:
2465 for p in patches:
2466 pf = os.path.join(d, p)
2466 pf = os.path.join(d, p)
2467
2467
2468 if pf == '-':
2468 if pf == '-':
2469 ui.status(_("applying patch from stdin\n"))
2469 ui.status(_("applying patch from stdin\n"))
2470 pf = sys.stdin
2470 pf = sys.stdin
2471 else:
2471 else:
2472 ui.status(_("applying %s\n") % p)
2472 ui.status(_("applying %s\n") % p)
2473 pf = url.open(ui, pf)
2473 pf = url.open(ui, pf)
2474
2474
2475 haspatch = False
2475 haspatch = False
2476 for hunk in patch.split(pf):
2476 for hunk in patch.split(pf):
2477 commitid = tryone(ui, hunk)
2477 commitid = tryone(ui, hunk)
2478 if commitid:
2478 if commitid:
2479 haspatch = True
2479 haspatch = True
2480 if lastcommit:
2480 if lastcommit:
2481 ui.status(_('applied %s\n') % lastcommit)
2481 ui.status(_('applied %s\n') % lastcommit)
2482 lastcommit = commitid
2482 lastcommit = commitid
2483
2483
2484 if not haspatch:
2484 if not haspatch:
2485 raise util.Abort(_('no diffs found'))
2485 raise util.Abort(_('no diffs found'))
2486
2486
2487 if msgs:
2487 if msgs:
2488 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2488 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2489 finally:
2489 finally:
2490 release(lock, wlock)
2490 release(lock, wlock)
2491
2491
2492 def incoming(ui, repo, source="default", **opts):
2492 def incoming(ui, repo, source="default", **opts):
2493 """show new changesets found in source
2493 """show new changesets found in source
2494
2494
2495 Show new changesets found in the specified path/URL or the default
2495 Show new changesets found in the specified path/URL or the default
2496 pull location. These are the changesets that would have been pulled
2496 pull location. These are the changesets that would have been pulled
2497 if a pull at the time you issued this command.
2497 if a pull at the time you issued this command.
2498
2498
2499 For remote repository, using --bundle avoids downloading the
2499 For remote repository, using --bundle avoids downloading the
2500 changesets twice if the incoming is followed by a pull.
2500 changesets twice if the incoming is followed by a pull.
2501
2501
2502 See pull for valid source format details.
2502 See pull for valid source format details.
2503
2503
2504 Returns 0 if there are incoming changes, 1 otherwise.
2504 Returns 0 if there are incoming changes, 1 otherwise.
2505 """
2505 """
2506 if opts.get('bundle') and opts.get('subrepos'):
2506 if opts.get('bundle') and opts.get('subrepos'):
2507 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2507 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2508
2508
2509 if opts.get('bookmarks'):
2509 if opts.get('bookmarks'):
2510 source, branches = hg.parseurl(ui.expandpath(source),
2510 source, branches = hg.parseurl(ui.expandpath(source),
2511 opts.get('branch'))
2511 opts.get('branch'))
2512 other = hg.repository(hg.remoteui(repo, opts), source)
2512 other = hg.repository(hg.remoteui(repo, opts), source)
2513 if 'bookmarks' not in other.listkeys('namespaces'):
2513 if 'bookmarks' not in other.listkeys('namespaces'):
2514 ui.warn(_("remote doesn't support bookmarks\n"))
2514 ui.warn(_("remote doesn't support bookmarks\n"))
2515 return 0
2515 return 0
2516 ui.status(_('comparing with %s\n') % url.hidepassword(source))
2516 ui.status(_('comparing with %s\n') % url.hidepassword(source))
2517 return bookmarks.diff(ui, repo, other)
2517 return bookmarks.diff(ui, repo, other)
2518
2518
2519 repo._subtoppath = ui.expandpath(source)
2519 repo._subtoppath = ui.expandpath(source)
2520 try:
2520 try:
2521 ret = hg.incoming(ui, repo, source, opts)
2521 ret = hg.incoming(ui, repo, source, opts)
2522 return ret
2522 return ret
2523 finally:
2523 finally:
2524 del repo._subtoppath
2524 del repo._subtoppath
2525
2525
2526
2526
2527 def init(ui, dest=".", **opts):
2527 def init(ui, dest=".", **opts):
2528 """create a new repository in the given directory
2528 """create a new repository in the given directory
2529
2529
2530 Initialize a new repository in the given directory. If the given
2530 Initialize a new repository in the given directory. If the given
2531 directory does not exist, it will be created.
2531 directory does not exist, it will be created.
2532
2532
2533 If no directory is given, the current directory is used.
2533 If no directory is given, the current directory is used.
2534
2534
2535 It is possible to specify an ``ssh://`` URL as the destination.
2535 It is possible to specify an ``ssh://`` URL as the destination.
2536 See :hg:`help urls` for more information.
2536 See :hg:`help urls` for more information.
2537
2537
2538 Returns 0 on success.
2538 Returns 0 on success.
2539 """
2539 """
2540 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2540 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2541
2541
2542 def locate(ui, repo, *pats, **opts):
2542 def locate(ui, repo, *pats, **opts):
2543 """locate files matching specific patterns
2543 """locate files matching specific patterns
2544
2544
2545 Print files under Mercurial control in the working directory whose
2545 Print files under Mercurial control in the working directory whose
2546 names match the given patterns.
2546 names match the given patterns.
2547
2547
2548 By default, this command searches all directories in the working
2548 By default, this command searches all directories in the working
2549 directory. To search just the current directory and its
2549 directory. To search just the current directory and its
2550 subdirectories, use "--include .".
2550 subdirectories, use "--include .".
2551
2551
2552 If no patterns are given to match, this command prints the names
2552 If no patterns are given to match, this command prints the names
2553 of all files under Mercurial control in the working directory.
2553 of all files under Mercurial control in the working directory.
2554
2554
2555 If you want to feed the output of this command into the "xargs"
2555 If you want to feed the output of this command into the "xargs"
2556 command, use the -0 option to both this command and "xargs". This
2556 command, use the -0 option to both this command and "xargs". This
2557 will avoid the problem of "xargs" treating single filenames that
2557 will avoid the problem of "xargs" treating single filenames that
2558 contain whitespace as multiple filenames.
2558 contain whitespace as multiple filenames.
2559
2559
2560 Returns 0 if a match is found, 1 otherwise.
2560 Returns 0 if a match is found, 1 otherwise.
2561 """
2561 """
2562 end = opts.get('print0') and '\0' or '\n'
2562 end = opts.get('print0') and '\0' or '\n'
2563 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2563 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2564
2564
2565 ret = 1
2565 ret = 1
2566 m = cmdutil.match(repo, pats, opts, default='relglob')
2566 m = cmdutil.match(repo, pats, opts, default='relglob')
2567 m.bad = lambda x, y: False
2567 m.bad = lambda x, y: False
2568 for abs in repo[rev].walk(m):
2568 for abs in repo[rev].walk(m):
2569 if not rev and abs not in repo.dirstate:
2569 if not rev and abs not in repo.dirstate:
2570 continue
2570 continue
2571 if opts.get('fullpath'):
2571 if opts.get('fullpath'):
2572 ui.write(repo.wjoin(abs), end)
2572 ui.write(repo.wjoin(abs), end)
2573 else:
2573 else:
2574 ui.write(((pats and m.rel(abs)) or abs), end)
2574 ui.write(((pats and m.rel(abs)) or abs), end)
2575 ret = 0
2575 ret = 0
2576
2576
2577 return ret
2577 return ret
2578
2578
2579 def log(ui, repo, *pats, **opts):
2579 def log(ui, repo, *pats, **opts):
2580 """show revision history of entire repository or files
2580 """show revision history of entire repository or files
2581
2581
2582 Print the revision history of the specified files or the entire
2582 Print the revision history of the specified files or the entire
2583 project.
2583 project.
2584
2584
2585 File history is shown without following rename or copy history of
2585 File history is shown without following rename or copy history of
2586 files. Use -f/--follow with a filename to follow history across
2586 files. Use -f/--follow with a filename to follow history across
2587 renames and copies. --follow without a filename will only show
2587 renames and copies. --follow without a filename will only show
2588 ancestors or descendants of the starting revision. --follow-first
2588 ancestors or descendants of the starting revision. --follow-first
2589 only follows the first parent of merge revisions.
2589 only follows the first parent of merge revisions.
2590
2590
2591 If no revision range is specified, the default is ``tip:0`` unless
2591 If no revision range is specified, the default is ``tip:0`` unless
2592 --follow is set, in which case the working directory parent is
2592 --follow is set, in which case the working directory parent is
2593 used as the starting revision. You can specify a revision set for
2593 used as the starting revision. You can specify a revision set for
2594 log, see :hg:`help revsets` for more information.
2594 log, see :hg:`help revsets` for more information.
2595
2595
2596 See :hg:`help dates` for a list of formats valid for -d/--date.
2596 See :hg:`help dates` for a list of formats valid for -d/--date.
2597
2597
2598 By default this command prints revision number and changeset id,
2598 By default this command prints revision number and changeset id,
2599 tags, non-trivial parents, user, date and time, and a summary for
2599 tags, non-trivial parents, user, date and time, and a summary for
2600 each commit. When the -v/--verbose switch is used, the list of
2600 each commit. When the -v/--verbose switch is used, the list of
2601 changed files and full commit message are shown.
2601 changed files and full commit message are shown.
2602
2602
2603 .. note::
2603 .. note::
2604 log -p/--patch may generate unexpected diff output for merge
2604 log -p/--patch may generate unexpected diff output for merge
2605 changesets, as it will only compare the merge changeset against
2605 changesets, as it will only compare the merge changeset against
2606 its first parent. Also, only files different from BOTH parents
2606 its first parent. Also, only files different from BOTH parents
2607 will appear in files:.
2607 will appear in files:.
2608
2608
2609 Returns 0 on success.
2609 Returns 0 on success.
2610 """
2610 """
2611
2611
2612 matchfn = cmdutil.match(repo, pats, opts)
2612 matchfn = cmdutil.match(repo, pats, opts)
2613 limit = cmdutil.loglimit(opts)
2613 limit = cmdutil.loglimit(opts)
2614 count = 0
2614 count = 0
2615
2615
2616 endrev = None
2616 endrev = None
2617 if opts.get('copies') and opts.get('rev'):
2617 if opts.get('copies') and opts.get('rev'):
2618 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2618 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2619
2619
2620 df = False
2620 df = False
2621 if opts["date"]:
2621 if opts["date"]:
2622 df = util.matchdate(opts["date"])
2622 df = util.matchdate(opts["date"])
2623
2623
2624 branches = opts.get('branch', []) + opts.get('only_branch', [])
2624 branches = opts.get('branch', []) + opts.get('only_branch', [])
2625 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2625 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2626
2626
2627 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2627 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2628 def prep(ctx, fns):
2628 def prep(ctx, fns):
2629 rev = ctx.rev()
2629 rev = ctx.rev()
2630 parents = [p for p in repo.changelog.parentrevs(rev)
2630 parents = [p for p in repo.changelog.parentrevs(rev)
2631 if p != nullrev]
2631 if p != nullrev]
2632 if opts.get('no_merges') and len(parents) == 2:
2632 if opts.get('no_merges') and len(parents) == 2:
2633 return
2633 return
2634 if opts.get('only_merges') and len(parents) != 2:
2634 if opts.get('only_merges') and len(parents) != 2:
2635 return
2635 return
2636 if opts.get('branch') and ctx.branch() not in opts['branch']:
2636 if opts.get('branch') and ctx.branch() not in opts['branch']:
2637 return
2637 return
2638 if df and not df(ctx.date()[0]):
2638 if df and not df(ctx.date()[0]):
2639 return
2639 return
2640 if opts['user'] and not [k for k in opts['user']
2640 if opts['user'] and not [k for k in opts['user']
2641 if k.lower() in ctx.user().lower()]:
2641 if k.lower() in ctx.user().lower()]:
2642 return
2642 return
2643 if opts.get('keyword'):
2643 if opts.get('keyword'):
2644 for k in [kw.lower() for kw in opts['keyword']]:
2644 for k in [kw.lower() for kw in opts['keyword']]:
2645 if (k in ctx.user().lower() or
2645 if (k in ctx.user().lower() or
2646 k in ctx.description().lower() or
2646 k in ctx.description().lower() or
2647 k in " ".join(ctx.files()).lower()):
2647 k in " ".join(ctx.files()).lower()):
2648 break
2648 break
2649 else:
2649 else:
2650 return
2650 return
2651
2651
2652 copies = None
2652 copies = None
2653 if opts.get('copies') and rev:
2653 if opts.get('copies') and rev:
2654 copies = []
2654 copies = []
2655 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2655 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2656 for fn in ctx.files():
2656 for fn in ctx.files():
2657 rename = getrenamed(fn, rev)
2657 rename = getrenamed(fn, rev)
2658 if rename:
2658 if rename:
2659 copies.append((fn, rename[0]))
2659 copies.append((fn, rename[0]))
2660
2660
2661 revmatchfn = None
2661 revmatchfn = None
2662 if opts.get('patch') or opts.get('stat'):
2662 if opts.get('patch') or opts.get('stat'):
2663 if opts.get('follow') or opts.get('follow_first'):
2663 if opts.get('follow') or opts.get('follow_first'):
2664 # note: this might be wrong when following through merges
2664 # note: this might be wrong when following through merges
2665 revmatchfn = cmdutil.match(repo, fns, default='path')
2665 revmatchfn = cmdutil.match(repo, fns, default='path')
2666 else:
2666 else:
2667 revmatchfn = matchfn
2667 revmatchfn = matchfn
2668
2668
2669 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2669 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2670
2670
2671 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2671 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2672 if count == limit:
2672 if count == limit:
2673 break
2673 break
2674 if displayer.flush(ctx.rev()):
2674 if displayer.flush(ctx.rev()):
2675 count += 1
2675 count += 1
2676 displayer.close()
2676 displayer.close()
2677
2677
2678 def manifest(ui, repo, node=None, rev=None):
2678 def manifest(ui, repo, node=None, rev=None):
2679 """output the current or given revision of the project manifest
2679 """output the current or given revision of the project manifest
2680
2680
2681 Print a list of version controlled files for the given revision.
2681 Print a list of version controlled files for the given revision.
2682 If no revision is given, the first parent of the working directory
2682 If no revision is given, the first parent of the working directory
2683 is used, or the null revision if no revision is checked out.
2683 is used, or the null revision if no revision is checked out.
2684
2684
2685 With -v, print file permissions, symlink and executable bits.
2685 With -v, print file permissions, symlink and executable bits.
2686 With --debug, print file revision hashes.
2686 With --debug, print file revision hashes.
2687
2687
2688 Returns 0 on success.
2688 Returns 0 on success.
2689 """
2689 """
2690
2690
2691 if rev and node:
2691 if rev and node:
2692 raise util.Abort(_("please specify just one revision"))
2692 raise util.Abort(_("please specify just one revision"))
2693
2693
2694 if not node:
2694 if not node:
2695 node = rev
2695 node = rev
2696
2696
2697 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2697 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2698 ctx = cmdutil.revsingle(repo, node)
2698 ctx = cmdutil.revsingle(repo, node)
2699 for f in ctx:
2699 for f in ctx:
2700 if ui.debugflag:
2700 if ui.debugflag:
2701 ui.write("%40s " % hex(ctx.manifest()[f]))
2701 ui.write("%40s " % hex(ctx.manifest()[f]))
2702 if ui.verbose:
2702 if ui.verbose:
2703 ui.write(decor[ctx.flags(f)])
2703 ui.write(decor[ctx.flags(f)])
2704 ui.write("%s\n" % f)
2704 ui.write("%s\n" % f)
2705
2705
2706 def merge(ui, repo, node=None, **opts):
2706 def merge(ui, repo, node=None, **opts):
2707 """merge working directory with another revision
2707 """merge working directory with another revision
2708
2708
2709 The current working directory is updated with all changes made in
2709 The current working directory is updated with all changes made in
2710 the requested revision since the last common predecessor revision.
2710 the requested revision since the last common predecessor revision.
2711
2711
2712 Files that changed between either parent are marked as changed for
2712 Files that changed between either parent are marked as changed for
2713 the next commit and a commit must be performed before any further
2713 the next commit and a commit must be performed before any further
2714 updates to the repository are allowed. The next commit will have
2714 updates to the repository are allowed. The next commit will have
2715 two parents.
2715 two parents.
2716
2716
2717 ``--tool`` can be used to specify the merge tool used for file
2717 ``--tool`` can be used to specify the merge tool used for file
2718 merges. It overrides the HGMERGE environment variable and your
2718 merges. It overrides the HGMERGE environment variable and your
2719 configuration files.
2719 configuration files.
2720
2720
2721 If no revision is specified, the working directory's parent is a
2721 If no revision is specified, the working directory's parent is a
2722 head revision, and the current branch contains exactly one other
2722 head revision, and the current branch contains exactly one other
2723 head, the other head is merged with by default. Otherwise, an
2723 head, the other head is merged with by default. Otherwise, an
2724 explicit revision with which to merge with must be provided.
2724 explicit revision with which to merge with must be provided.
2725
2725
2726 :hg:`resolve` must be used to resolve unresolved files.
2726 :hg:`resolve` must be used to resolve unresolved files.
2727
2727
2728 To undo an uncommitted merge, use :hg:`update --clean .` which
2728 To undo an uncommitted merge, use :hg:`update --clean .` which
2729 will check out a clean copy of the original merge parent, losing
2729 will check out a clean copy of the original merge parent, losing
2730 all changes.
2730 all changes.
2731
2731
2732 Returns 0 on success, 1 if there are unresolved files.
2732 Returns 0 on success, 1 if there are unresolved files.
2733 """
2733 """
2734
2734
2735 if opts.get('rev') and node:
2735 if opts.get('rev') and node:
2736 raise util.Abort(_("please specify just one revision"))
2736 raise util.Abort(_("please specify just one revision"))
2737 if not node:
2737 if not node:
2738 node = opts.get('rev')
2738 node = opts.get('rev')
2739
2739
2740 if not node:
2740 if not node:
2741 branch = repo[None].branch()
2741 branch = repo[None].branch()
2742 bheads = repo.branchheads(branch)
2742 bheads = repo.branchheads(branch)
2743 if len(bheads) > 2:
2743 if len(bheads) > 2:
2744 raise util.Abort(_(
2744 raise util.Abort(_(
2745 'branch \'%s\' has %d heads - '
2745 'branch \'%s\' has %d heads - '
2746 'please merge with an explicit rev\n'
2746 'please merge with an explicit rev\n'
2747 '(run \'hg heads .\' to see heads)')
2747 '(run \'hg heads .\' to see heads)')
2748 % (branch, len(bheads)))
2748 % (branch, len(bheads)))
2749
2749
2750 parent = repo.dirstate.parents()[0]
2750 parent = repo.dirstate.parents()[0]
2751 if len(bheads) == 1:
2751 if len(bheads) == 1:
2752 if len(repo.heads()) > 1:
2752 if len(repo.heads()) > 1:
2753 raise util.Abort(_(
2753 raise util.Abort(_(
2754 'branch \'%s\' has one head - '
2754 'branch \'%s\' has one head - '
2755 'please merge with an explicit rev\n'
2755 'please merge with an explicit rev\n'
2756 '(run \'hg heads\' to see all heads)')
2756 '(run \'hg heads\' to see all heads)')
2757 % branch)
2757 % branch)
2758 msg = _('there is nothing to merge')
2758 msg = _('there is nothing to merge')
2759 if parent != repo.lookup(repo[None].branch()):
2759 if parent != repo.lookup(repo[None].branch()):
2760 msg = _('%s - use "hg update" instead') % msg
2760 msg = _('%s - use "hg update" instead') % msg
2761 raise util.Abort(msg)
2761 raise util.Abort(msg)
2762
2762
2763 if parent not in bheads:
2763 if parent not in bheads:
2764 raise util.Abort(_('working dir not at a head rev - '
2764 raise util.Abort(_('working dir not at a head rev - '
2765 'use "hg update" or merge with an explicit rev'))
2765 'use "hg update" or merge with an explicit rev'))
2766 node = parent == bheads[0] and bheads[-1] or bheads[0]
2766 node = parent == bheads[0] and bheads[-1] or bheads[0]
2767 else:
2767 else:
2768 node = cmdutil.revsingle(repo, node).node()
2768 node = cmdutil.revsingle(repo, node).node()
2769
2769
2770 if opts.get('preview'):
2770 if opts.get('preview'):
2771 # find nodes that are ancestors of p2 but not of p1
2771 # find nodes that are ancestors of p2 but not of p1
2772 p1 = repo.lookup('.')
2772 p1 = repo.lookup('.')
2773 p2 = repo.lookup(node)
2773 p2 = repo.lookup(node)
2774 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2774 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2775
2775
2776 displayer = cmdutil.show_changeset(ui, repo, opts)
2776 displayer = cmdutil.show_changeset(ui, repo, opts)
2777 for node in nodes:
2777 for node in nodes:
2778 displayer.show(repo[node])
2778 displayer.show(repo[node])
2779 displayer.close()
2779 displayer.close()
2780 return 0
2780 return 0
2781
2781
2782 try:
2782 try:
2783 # ui.forcemerge is an internal variable, do not document
2783 # ui.forcemerge is an internal variable, do not document
2784 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2784 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2785 return hg.merge(repo, node, force=opts.get('force'))
2785 return hg.merge(repo, node, force=opts.get('force'))
2786 finally:
2786 finally:
2787 ui.setconfig('ui', 'forcemerge', '')
2787 ui.setconfig('ui', 'forcemerge', '')
2788
2788
2789 def outgoing(ui, repo, dest=None, **opts):
2789 def outgoing(ui, repo, dest=None, **opts):
2790 """show changesets not found in the destination
2790 """show changesets not found in the destination
2791
2791
2792 Show changesets not found in the specified destination repository
2792 Show changesets not found in the specified destination repository
2793 or the default push location. These are the changesets that would
2793 or the default push location. These are the changesets that would
2794 be pushed if a push was requested.
2794 be pushed if a push was requested.
2795
2795
2796 See pull for details of valid destination formats.
2796 See pull for details of valid destination formats.
2797
2797
2798 Returns 0 if there are outgoing changes, 1 otherwise.
2798 Returns 0 if there are outgoing changes, 1 otherwise.
2799 """
2799 """
2800
2800
2801 if opts.get('bookmarks'):
2801 if opts.get('bookmarks'):
2802 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2802 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2803 dest, branches = hg.parseurl(dest, opts.get('branch'))
2803 dest, branches = hg.parseurl(dest, opts.get('branch'))
2804 other = hg.repository(hg.remoteui(repo, opts), dest)
2804 other = hg.repository(hg.remoteui(repo, opts), dest)
2805 if 'bookmarks' not in other.listkeys('namespaces'):
2805 if 'bookmarks' not in other.listkeys('namespaces'):
2806 ui.warn(_("remote doesn't support bookmarks\n"))
2806 ui.warn(_("remote doesn't support bookmarks\n"))
2807 return 0
2807 return 0
2808 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2808 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2809 return bookmarks.diff(ui, other, repo)
2809 return bookmarks.diff(ui, other, repo)
2810
2810
2811 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
2811 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
2812 try:
2812 try:
2813 ret = hg.outgoing(ui, repo, dest, opts)
2813 ret = hg.outgoing(ui, repo, dest, opts)
2814 return ret
2814 return ret
2815 finally:
2815 finally:
2816 del repo._subtoppath
2816 del repo._subtoppath
2817
2817
2818 def parents(ui, repo, file_=None, **opts):
2818 def parents(ui, repo, file_=None, **opts):
2819 """show the parents of the working directory or revision
2819 """show the parents of the working directory or revision
2820
2820
2821 Print the working directory's parent revisions. If a revision is
2821 Print the working directory's parent revisions. If a revision is
2822 given via -r/--rev, the parent of that revision will be printed.
2822 given via -r/--rev, the parent of that revision will be printed.
2823 If a file argument is given, the revision in which the file was
2823 If a file argument is given, the revision in which the file was
2824 last changed (before the working directory revision or the
2824 last changed (before the working directory revision or the
2825 argument to --rev if given) is printed.
2825 argument to --rev if given) is printed.
2826
2826
2827 Returns 0 on success.
2827 Returns 0 on success.
2828 """
2828 """
2829
2829
2830 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2830 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2831
2831
2832 if file_:
2832 if file_:
2833 m = cmdutil.match(repo, (file_,), opts)
2833 m = cmdutil.match(repo, (file_,), opts)
2834 if m.anypats() or len(m.files()) != 1:
2834 if m.anypats() or len(m.files()) != 1:
2835 raise util.Abort(_('can only specify an explicit filename'))
2835 raise util.Abort(_('can only specify an explicit filename'))
2836 file_ = m.files()[0]
2836 file_ = m.files()[0]
2837 filenodes = []
2837 filenodes = []
2838 for cp in ctx.parents():
2838 for cp in ctx.parents():
2839 if not cp:
2839 if not cp:
2840 continue
2840 continue
2841 try:
2841 try:
2842 filenodes.append(cp.filenode(file_))
2842 filenodes.append(cp.filenode(file_))
2843 except error.LookupError:
2843 except error.LookupError:
2844 pass
2844 pass
2845 if not filenodes:
2845 if not filenodes:
2846 raise util.Abort(_("'%s' not found in manifest!") % file_)
2846 raise util.Abort(_("'%s' not found in manifest!") % file_)
2847 fl = repo.file(file_)
2847 fl = repo.file(file_)
2848 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2848 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2849 else:
2849 else:
2850 p = [cp.node() for cp in ctx.parents()]
2850 p = [cp.node() for cp in ctx.parents()]
2851
2851
2852 displayer = cmdutil.show_changeset(ui, repo, opts)
2852 displayer = cmdutil.show_changeset(ui, repo, opts)
2853 for n in p:
2853 for n in p:
2854 if n != nullid:
2854 if n != nullid:
2855 displayer.show(repo[n])
2855 displayer.show(repo[n])
2856 displayer.close()
2856 displayer.close()
2857
2857
2858 def paths(ui, repo, search=None):
2858 def paths(ui, repo, search=None):
2859 """show aliases for remote repositories
2859 """show aliases for remote repositories
2860
2860
2861 Show definition of symbolic path name NAME. If no name is given,
2861 Show definition of symbolic path name NAME. If no name is given,
2862 show definition of all available names.
2862 show definition of all available names.
2863
2863
2864 Path names are defined in the [paths] section of your
2864 Path names are defined in the [paths] section of your
2865 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2865 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2866 repository, ``.hg/hgrc`` is used, too.
2866 repository, ``.hg/hgrc`` is used, too.
2867
2867
2868 The path names ``default`` and ``default-push`` have a special
2868 The path names ``default`` and ``default-push`` have a special
2869 meaning. When performing a push or pull operation, they are used
2869 meaning. When performing a push or pull operation, they are used
2870 as fallbacks if no location is specified on the command-line.
2870 as fallbacks if no location is specified on the command-line.
2871 When ``default-push`` is set, it will be used for push and
2871 When ``default-push`` is set, it will be used for push and
2872 ``default`` will be used for pull; otherwise ``default`` is used
2872 ``default`` will be used for pull; otherwise ``default`` is used
2873 as the fallback for both. When cloning a repository, the clone
2873 as the fallback for both. When cloning a repository, the clone
2874 source is written as ``default`` in ``.hg/hgrc``. Note that
2874 source is written as ``default`` in ``.hg/hgrc``. Note that
2875 ``default`` and ``default-push`` apply to all inbound (e.g.
2875 ``default`` and ``default-push`` apply to all inbound (e.g.
2876 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2876 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2877 :hg:`bundle`) operations.
2877 :hg:`bundle`) operations.
2878
2878
2879 See :hg:`help urls` for more information.
2879 See :hg:`help urls` for more information.
2880
2880
2881 Returns 0 on success.
2881 Returns 0 on success.
2882 """
2882 """
2883 if search:
2883 if search:
2884 for name, path in ui.configitems("paths"):
2884 for name, path in ui.configitems("paths"):
2885 if name == search:
2885 if name == search:
2886 ui.write("%s\n" % url.hidepassword(path))
2886 ui.write("%s\n" % url.hidepassword(path))
2887 return
2887 return
2888 ui.warn(_("not found!\n"))
2888 ui.warn(_("not found!\n"))
2889 return 1
2889 return 1
2890 else:
2890 else:
2891 for name, path in ui.configitems("paths"):
2891 for name, path in ui.configitems("paths"):
2892 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2892 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2893
2893
2894 def postincoming(ui, repo, modheads, optupdate, checkout):
2894 def postincoming(ui, repo, modheads, optupdate, checkout):
2895 if modheads == 0:
2895 if modheads == 0:
2896 return
2896 return
2897 if optupdate:
2897 if optupdate:
2898 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2898 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2899 return hg.update(repo, checkout)
2899 return hg.update(repo, checkout)
2900 else:
2900 else:
2901 ui.status(_("not updating, since new heads added\n"))
2901 ui.status(_("not updating, since new heads added\n"))
2902 if modheads > 1:
2902 if modheads > 1:
2903 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2903 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2904 else:
2904 else:
2905 ui.status(_("(run 'hg update' to get a working copy)\n"))
2905 ui.status(_("(run 'hg update' to get a working copy)\n"))
2906
2906
2907 def pull(ui, repo, source="default", **opts):
2907 def pull(ui, repo, source="default", **opts):
2908 """pull changes from the specified source
2908 """pull changes from the specified source
2909
2909
2910 Pull changes from a remote repository to a local one.
2910 Pull changes from a remote repository to a local one.
2911
2911
2912 This finds all changes from the repository at the specified path
2912 This finds all changes from the repository at the specified path
2913 or URL and adds them to a local repository (the current one unless
2913 or URL and adds them to a local repository (the current one unless
2914 -R is specified). By default, this does not update the copy of the
2914 -R is specified). By default, this does not update the copy of the
2915 project in the working directory.
2915 project in the working directory.
2916
2916
2917 Use :hg:`incoming` if you want to see what would have been added
2917 Use :hg:`incoming` if you want to see what would have been added
2918 by a pull at the time you issued this command. If you then decide
2918 by a pull at the time you issued this command. If you then decide
2919 to add those changes to the repository, you should use :hg:`pull
2919 to add those changes to the repository, you should use :hg:`pull
2920 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2920 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2921
2921
2922 If SOURCE is omitted, the 'default' path will be used.
2922 If SOURCE is omitted, the 'default' path will be used.
2923 See :hg:`help urls` for more information.
2923 See :hg:`help urls` for more information.
2924
2924
2925 Returns 0 on success, 1 if an update had unresolved files.
2925 Returns 0 on success, 1 if an update had unresolved files.
2926 """
2926 """
2927 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2927 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2928 other = hg.repository(hg.remoteui(repo, opts), source)
2928 other = hg.repository(hg.remoteui(repo, opts), source)
2929 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2929 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2930 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2930 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2931
2931
2932 if opts.get('bookmark'):
2932 if opts.get('bookmark'):
2933 if not revs:
2933 if not revs:
2934 revs = []
2934 revs = []
2935 rb = other.listkeys('bookmarks')
2935 rb = other.listkeys('bookmarks')
2936 for b in opts['bookmark']:
2936 for b in opts['bookmark']:
2937 if b not in rb:
2937 if b not in rb:
2938 raise util.Abort(_('remote bookmark %s not found!') % b)
2938 raise util.Abort(_('remote bookmark %s not found!') % b)
2939 revs.append(rb[b])
2939 revs.append(rb[b])
2940
2940
2941 if revs:
2941 if revs:
2942 try:
2942 try:
2943 revs = [other.lookup(rev) for rev in revs]
2943 revs = [other.lookup(rev) for rev in revs]
2944 except error.CapabilityError:
2944 except error.CapabilityError:
2945 err = _("other repository doesn't support revision lookup, "
2945 err = _("other repository doesn't support revision lookup, "
2946 "so a rev cannot be specified.")
2946 "so a rev cannot be specified.")
2947 raise util.Abort(err)
2947 raise util.Abort(err)
2948
2948
2949 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2949 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2950 if checkout:
2950 if checkout:
2951 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2951 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2952 repo._subtoppath = source
2952 repo._subtoppath = source
2953 try:
2953 try:
2954 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
2954 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
2955
2955
2956 finally:
2956 finally:
2957 del repo._subtoppath
2957 del repo._subtoppath
2958
2958
2959 # update specified bookmarks
2959 # update specified bookmarks
2960 if opts.get('bookmark'):
2960 if opts.get('bookmark'):
2961 for b in opts['bookmark']:
2961 for b in opts['bookmark']:
2962 # explicit pull overrides local bookmark if any
2962 # explicit pull overrides local bookmark if any
2963 ui.status(_("importing bookmark %s\n") % b)
2963 ui.status(_("importing bookmark %s\n") % b)
2964 repo._bookmarks[b] = repo[rb[b]].node()
2964 repo._bookmarks[b] = repo[rb[b]].node()
2965 bookmarks.write(repo)
2965 bookmarks.write(repo)
2966
2966
2967 return ret
2967 return ret
2968
2968
2969 def push(ui, repo, dest=None, **opts):
2969 def push(ui, repo, dest=None, **opts):
2970 """push changes to the specified destination
2970 """push changes to the specified destination
2971
2971
2972 Push changesets from the local repository to the specified
2972 Push changesets from the local repository to the specified
2973 destination.
2973 destination.
2974
2974
2975 This operation is symmetrical to pull: it is identical to a pull
2975 This operation is symmetrical to pull: it is identical to a pull
2976 in the destination repository from the current one.
2976 in the destination repository from the current one.
2977
2977
2978 By default, push will not allow creation of new heads at the
2978 By default, push will not allow creation of new heads at the
2979 destination, since multiple heads would make it unclear which head
2979 destination, since multiple heads would make it unclear which head
2980 to use. In this situation, it is recommended to pull and merge
2980 to use. In this situation, it is recommended to pull and merge
2981 before pushing.
2981 before pushing.
2982
2982
2983 Use --new-branch if you want to allow push to create a new named
2983 Use --new-branch if you want to allow push to create a new named
2984 branch that is not present at the destination. This allows you to
2984 branch that is not present at the destination. This allows you to
2985 only create a new branch without forcing other changes.
2985 only create a new branch without forcing other changes.
2986
2986
2987 Use -f/--force to override the default behavior and push all
2987 Use -f/--force to override the default behavior and push all
2988 changesets on all branches.
2988 changesets on all branches.
2989
2989
2990 If -r/--rev is used, the specified revision and all its ancestors
2990 If -r/--rev is used, the specified revision and all its ancestors
2991 will be pushed to the remote repository.
2991 will be pushed to the remote repository.
2992
2992
2993 Please see :hg:`help urls` for important details about ``ssh://``
2993 Please see :hg:`help urls` for important details about ``ssh://``
2994 URLs. If DESTINATION is omitted, a default path will be used.
2994 URLs. If DESTINATION is omitted, a default path will be used.
2995
2995
2996 Returns 0 if push was successful, 1 if nothing to push.
2996 Returns 0 if push was successful, 1 if nothing to push.
2997 """
2997 """
2998
2998
2999 if opts.get('bookmark'):
2999 if opts.get('bookmark'):
3000 for b in opts['bookmark']:
3000 for b in opts['bookmark']:
3001 # translate -B options to -r so changesets get pushed
3001 # translate -B options to -r so changesets get pushed
3002 if b in repo._bookmarks:
3002 if b in repo._bookmarks:
3003 opts.setdefault('rev', []).append(b)
3003 opts.setdefault('rev', []).append(b)
3004 else:
3004 else:
3005 # if we try to push a deleted bookmark, translate it to null
3005 # if we try to push a deleted bookmark, translate it to null
3006 # this lets simultaneous -r, -b options continue working
3006 # this lets simultaneous -r, -b options continue working
3007 opts.setdefault('rev', []).append("null")
3007 opts.setdefault('rev', []).append("null")
3008
3008
3009 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3009 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3010 dest, branches = hg.parseurl(dest, opts.get('branch'))
3010 dest, branches = hg.parseurl(dest, opts.get('branch'))
3011 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
3011 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
3012 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3012 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3013 other = hg.repository(hg.remoteui(repo, opts), dest)
3013 other = hg.repository(hg.remoteui(repo, opts), dest)
3014 if revs:
3014 if revs:
3015 revs = [repo.lookup(rev) for rev in revs]
3015 revs = [repo.lookup(rev) for rev in revs]
3016
3016
3017 repo._subtoppath = dest
3017 repo._subtoppath = dest
3018 try:
3018 try:
3019 # push subrepos depth-first for coherent ordering
3019 # push subrepos depth-first for coherent ordering
3020 c = repo['']
3020 c = repo['']
3021 subs = c.substate # only repos that are committed
3021 subs = c.substate # only repos that are committed
3022 for s in sorted(subs):
3022 for s in sorted(subs):
3023 if not c.sub(s).push(opts.get('force')):
3023 if not c.sub(s).push(opts.get('force')):
3024 return False
3024 return False
3025 finally:
3025 finally:
3026 del repo._subtoppath
3026 del repo._subtoppath
3027 result = repo.push(other, opts.get('force'), revs=revs,
3027 result = repo.push(other, opts.get('force'), revs=revs,
3028 newbranch=opts.get('new_branch'))
3028 newbranch=opts.get('new_branch'))
3029
3029
3030 result = (result == 0)
3030 result = (result == 0)
3031
3031
3032 if opts.get('bookmark'):
3032 if opts.get('bookmark'):
3033 rb = other.listkeys('bookmarks')
3033 rb = other.listkeys('bookmarks')
3034 for b in opts['bookmark']:
3034 for b in opts['bookmark']:
3035 # explicit push overrides remote bookmark if any
3035 # explicit push overrides remote bookmark if any
3036 if b in repo._bookmarks:
3036 if b in repo._bookmarks:
3037 ui.status(_("exporting bookmark %s\n") % b)
3037 ui.status(_("exporting bookmark %s\n") % b)
3038 new = repo[b].hex()
3038 new = repo[b].hex()
3039 elif b in rb:
3039 elif b in rb:
3040 ui.status(_("deleting remote bookmark %s\n") % b)
3040 ui.status(_("deleting remote bookmark %s\n") % b)
3041 new = '' # delete
3041 new = '' # delete
3042 else:
3042 else:
3043 ui.warn(_('bookmark %s does not exist on the local '
3043 ui.warn(_('bookmark %s does not exist on the local '
3044 'or remote repository!\n') % b)
3044 'or remote repository!\n') % b)
3045 return 2
3045 return 2
3046 old = rb.get(b, '')
3046 old = rb.get(b, '')
3047 r = other.pushkey('bookmarks', b, old, new)
3047 r = other.pushkey('bookmarks', b, old, new)
3048 if not r:
3048 if not r:
3049 ui.warn(_('updating bookmark %s failed!\n') % b)
3049 ui.warn(_('updating bookmark %s failed!\n') % b)
3050 if not result:
3050 if not result:
3051 result = 2
3051 result = 2
3052
3052
3053 return result
3053 return result
3054
3054
3055 def recover(ui, repo):
3055 def recover(ui, repo):
3056 """roll back an interrupted transaction
3056 """roll back an interrupted transaction
3057
3057
3058 Recover from an interrupted commit or pull.
3058 Recover from an interrupted commit or pull.
3059
3059
3060 This command tries to fix the repository status after an
3060 This command tries to fix the repository status after an
3061 interrupted operation. It should only be necessary when Mercurial
3061 interrupted operation. It should only be necessary when Mercurial
3062 suggests it.
3062 suggests it.
3063
3063
3064 Returns 0 if successful, 1 if nothing to recover or verify fails.
3064 Returns 0 if successful, 1 if nothing to recover or verify fails.
3065 """
3065 """
3066 if repo.recover():
3066 if repo.recover():
3067 return hg.verify(repo)
3067 return hg.verify(repo)
3068 return 1
3068 return 1
3069
3069
3070 def remove(ui, repo, *pats, **opts):
3070 def remove(ui, repo, *pats, **opts):
3071 """remove the specified files on the next commit
3071 """remove the specified files on the next commit
3072
3072
3073 Schedule the indicated files for removal from the repository.
3073 Schedule the indicated files for removal from the repository.
3074
3074
3075 This only removes files from the current branch, not from the
3075 This only removes files from the current branch, not from the
3076 entire project history. -A/--after can be used to remove only
3076 entire project history. -A/--after can be used to remove only
3077 files that have already been deleted, -f/--force can be used to
3077 files that have already been deleted, -f/--force can be used to
3078 force deletion, and -Af can be used to remove files from the next
3078 force deletion, and -Af can be used to remove files from the next
3079 revision without deleting them from the working directory.
3079 revision without deleting them from the working directory.
3080
3080
3081 The following table details the behavior of remove for different
3081 The following table details the behavior of remove for different
3082 file states (columns) and option combinations (rows). The file
3082 file states (columns) and option combinations (rows). The file
3083 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3083 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3084 reported by :hg:`status`). The actions are Warn, Remove (from
3084 reported by :hg:`status`). The actions are Warn, Remove (from
3085 branch) and Delete (from disk)::
3085 branch) and Delete (from disk)::
3086
3086
3087 A C M !
3087 A C M !
3088 none W RD W R
3088 none W RD W R
3089 -f R RD RD R
3089 -f R RD RD R
3090 -A W W W R
3090 -A W W W R
3091 -Af R R R R
3091 -Af R R R R
3092
3092
3093 This command schedules the files to be removed at the next commit.
3093 This command schedules the files to be removed at the next commit.
3094 To undo a remove before that, see :hg:`revert`.
3094 To undo a remove before that, see :hg:`revert`.
3095
3095
3096 Returns 0 on success, 1 if any warnings encountered.
3096 Returns 0 on success, 1 if any warnings encountered.
3097 """
3097 """
3098
3098
3099 ret = 0
3099 ret = 0
3100 after, force = opts.get('after'), opts.get('force')
3100 after, force = opts.get('after'), opts.get('force')
3101 if not pats and not after:
3101 if not pats and not after:
3102 raise util.Abort(_('no files specified'))
3102 raise util.Abort(_('no files specified'))
3103
3103
3104 m = cmdutil.match(repo, pats, opts)
3104 m = cmdutil.match(repo, pats, opts)
3105 s = repo.status(match=m, clean=True)
3105 s = repo.status(match=m, clean=True)
3106 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3106 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3107
3107
3108 for f in m.files():
3108 for f in m.files():
3109 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3109 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3110 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3110 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3111 ret = 1
3111 ret = 1
3112
3112
3113 if force:
3113 if force:
3114 remove, forget = modified + deleted + clean, added
3114 remove, forget = modified + deleted + clean, added
3115 elif after:
3115 elif after:
3116 remove, forget = deleted, []
3116 remove, forget = deleted, []
3117 for f in modified + added + clean:
3117 for f in modified + added + clean:
3118 ui.warn(_('not removing %s: file still exists (use -f'
3118 ui.warn(_('not removing %s: file still exists (use -f'
3119 ' to force removal)\n') % m.rel(f))
3119 ' to force removal)\n') % m.rel(f))
3120 ret = 1
3120 ret = 1
3121 else:
3121 else:
3122 remove, forget = deleted + clean, []
3122 remove, forget = deleted + clean, []
3123 for f in modified:
3123 for f in modified:
3124 ui.warn(_('not removing %s: file is modified (use -f'
3124 ui.warn(_('not removing %s: file is modified (use -f'
3125 ' to force removal)\n') % m.rel(f))
3125 ' to force removal)\n') % m.rel(f))
3126 ret = 1
3126 ret = 1
3127 for f in added:
3127 for f in added:
3128 ui.warn(_('not removing %s: file has been marked for add (use -f'
3128 ui.warn(_('not removing %s: file has been marked for add (use -f'
3129 ' to force removal)\n') % m.rel(f))
3129 ' to force removal)\n') % m.rel(f))
3130 ret = 1
3130 ret = 1
3131
3131
3132 for f in sorted(remove + forget):
3132 for f in sorted(remove + forget):
3133 if ui.verbose or not m.exact(f):
3133 if ui.verbose or not m.exact(f):
3134 ui.status(_('removing %s\n') % m.rel(f))
3134 ui.status(_('removing %s\n') % m.rel(f))
3135
3135
3136 repo[None].forget(forget)
3136 repo[None].forget(forget)
3137 repo[None].remove(remove, unlink=not after)
3137 repo[None].remove(remove, unlink=not after)
3138 return ret
3138 return ret
3139
3139
3140 def rename(ui, repo, *pats, **opts):
3140 def rename(ui, repo, *pats, **opts):
3141 """rename files; equivalent of copy + remove
3141 """rename files; equivalent of copy + remove
3142
3142
3143 Mark dest as copies of sources; mark sources for deletion. If dest
3143 Mark dest as copies of sources; mark sources for deletion. If dest
3144 is a directory, copies are put in that directory. If dest is a
3144 is a directory, copies are put in that directory. If dest is a
3145 file, there can only be one source.
3145 file, there can only be one source.
3146
3146
3147 By default, this command copies the contents of files as they
3147 By default, this command copies the contents of files as they
3148 exist in the working directory. If invoked with -A/--after, the
3148 exist in the working directory. If invoked with -A/--after, the
3149 operation is recorded, but no copying is performed.
3149 operation is recorded, but no copying is performed.
3150
3150
3151 This command takes effect at the next commit. To undo a rename
3151 This command takes effect at the next commit. To undo a rename
3152 before that, see :hg:`revert`.
3152 before that, see :hg:`revert`.
3153
3153
3154 Returns 0 on success, 1 if errors are encountered.
3154 Returns 0 on success, 1 if errors are encountered.
3155 """
3155 """
3156 wlock = repo.wlock(False)
3156 wlock = repo.wlock(False)
3157 try:
3157 try:
3158 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3158 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3159 finally:
3159 finally:
3160 wlock.release()
3160 wlock.release()
3161
3161
3162 def resolve(ui, repo, *pats, **opts):
3162 def resolve(ui, repo, *pats, **opts):
3163 """redo merges or set/view the merge status of files
3163 """redo merges or set/view the merge status of files
3164
3164
3165 Merges with unresolved conflicts are often the result of
3165 Merges with unresolved conflicts are often the result of
3166 non-interactive merging using the ``internal:merge`` configuration
3166 non-interactive merging using the ``internal:merge`` configuration
3167 setting, or a command-line merge tool like ``diff3``. The resolve
3167 setting, or a command-line merge tool like ``diff3``. The resolve
3168 command is used to manage the files involved in a merge, after
3168 command is used to manage the files involved in a merge, after
3169 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3169 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3170 working directory must have two parents).
3170 working directory must have two parents).
3171
3171
3172 The resolve command can be used in the following ways:
3172 The resolve command can be used in the following ways:
3173
3173
3174 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3174 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3175 files, discarding any previous merge attempts. Re-merging is not
3175 files, discarding any previous merge attempts. Re-merging is not
3176 performed for files already marked as resolved. Use ``--all/-a``
3176 performed for files already marked as resolved. Use ``--all/-a``
3177 to selects all unresolved files. ``--tool`` can be used to specify
3177 to selects all unresolved files. ``--tool`` can be used to specify
3178 the merge tool used for the given files. It overrides the HGMERGE
3178 the merge tool used for the given files. It overrides the HGMERGE
3179 environment variable and your configuration files.
3179 environment variable and your configuration files.
3180
3180
3181 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3181 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3182 (e.g. after having manually fixed-up the files). The default is
3182 (e.g. after having manually fixed-up the files). The default is
3183 to mark all unresolved files.
3183 to mark all unresolved files.
3184
3184
3185 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3185 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3186 default is to mark all resolved files.
3186 default is to mark all resolved files.
3187
3187
3188 - :hg:`resolve -l`: list files which had or still have conflicts.
3188 - :hg:`resolve -l`: list files which had or still have conflicts.
3189 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3189 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3190
3190
3191 Note that Mercurial will not let you commit files with unresolved
3191 Note that Mercurial will not let you commit files with unresolved
3192 merge conflicts. You must use :hg:`resolve -m ...` before you can
3192 merge conflicts. You must use :hg:`resolve -m ...` before you can
3193 commit after a conflicting merge.
3193 commit after a conflicting merge.
3194
3194
3195 Returns 0 on success, 1 if any files fail a resolve attempt.
3195 Returns 0 on success, 1 if any files fail a resolve attempt.
3196 """
3196 """
3197
3197
3198 all, mark, unmark, show, nostatus = \
3198 all, mark, unmark, show, nostatus = \
3199 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3199 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3200
3200
3201 if (show and (mark or unmark)) or (mark and unmark):
3201 if (show and (mark or unmark)) or (mark and unmark):
3202 raise util.Abort(_("too many options specified"))
3202 raise util.Abort(_("too many options specified"))
3203 if pats and all:
3203 if pats and all:
3204 raise util.Abort(_("can't specify --all and patterns"))
3204 raise util.Abort(_("can't specify --all and patterns"))
3205 if not (all or pats or show or mark or unmark):
3205 if not (all or pats or show or mark or unmark):
3206 raise util.Abort(_('no files or directories specified; '
3206 raise util.Abort(_('no files or directories specified; '
3207 'use --all to remerge all files'))
3207 'use --all to remerge all files'))
3208
3208
3209 ms = mergemod.mergestate(repo)
3209 ms = mergemod.mergestate(repo)
3210 m = cmdutil.match(repo, pats, opts)
3210 m = cmdutil.match(repo, pats, opts)
3211 ret = 0
3211 ret = 0
3212
3212
3213 for f in ms:
3213 for f in ms:
3214 if m(f):
3214 if m(f):
3215 if show:
3215 if show:
3216 if nostatus:
3216 if nostatus:
3217 ui.write("%s\n" % f)
3217 ui.write("%s\n" % f)
3218 else:
3218 else:
3219 ui.write("%s %s\n" % (ms[f].upper(), f),
3219 ui.write("%s %s\n" % (ms[f].upper(), f),
3220 label='resolve.' +
3220 label='resolve.' +
3221 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3221 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3222 elif mark:
3222 elif mark:
3223 ms.mark(f, "r")
3223 ms.mark(f, "r")
3224 elif unmark:
3224 elif unmark:
3225 ms.mark(f, "u")
3225 ms.mark(f, "u")
3226 else:
3226 else:
3227 wctx = repo[None]
3227 wctx = repo[None]
3228 mctx = wctx.parents()[-1]
3228 mctx = wctx.parents()[-1]
3229
3229
3230 # backup pre-resolve (merge uses .orig for its own purposes)
3230 # backup pre-resolve (merge uses .orig for its own purposes)
3231 a = repo.wjoin(f)
3231 a = repo.wjoin(f)
3232 util.copyfile(a, a + ".resolve")
3232 util.copyfile(a, a + ".resolve")
3233
3233
3234 try:
3234 try:
3235 # resolve file
3235 # resolve file
3236 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3236 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3237 if ms.resolve(f, wctx, mctx):
3237 if ms.resolve(f, wctx, mctx):
3238 ret = 1
3238 ret = 1
3239 finally:
3239 finally:
3240 ui.setconfig('ui', 'forcemerge', '')
3240 ui.setconfig('ui', 'forcemerge', '')
3241
3241
3242 # replace filemerge's .orig file with our resolve file
3242 # replace filemerge's .orig file with our resolve file
3243 util.rename(a + ".resolve", a + ".orig")
3243 util.rename(a + ".resolve", a + ".orig")
3244
3244
3245 ms.commit()
3245 ms.commit()
3246 return ret
3246 return ret
3247
3247
3248 def revert(ui, repo, *pats, **opts):
3248 def revert(ui, repo, *pats, **opts):
3249 """restore individual files or directories to an earlier state
3249 """restore individual files or directories to an earlier state
3250
3250
3251 .. note::
3251 .. note::
3252 This command is most likely not what you are looking for.
3252 This command is most likely not what you are looking for.
3253 Revert will partially overwrite content in the working
3253 Revert will partially overwrite content in the working
3254 directory without changing the working directory parents. Use
3254 directory without changing the working directory parents. Use
3255 :hg:`update -r rev` to check out earlier revisions, or
3255 :hg:`update -r rev` to check out earlier revisions, or
3256 :hg:`update --clean .` to undo a merge which has added another
3256 :hg:`update --clean .` to undo a merge which has added another
3257 parent.
3257 parent.
3258
3258
3259 With no revision specified, revert the named files or directories
3259 With no revision specified, revert the named files or directories
3260 to the contents they had in the parent of the working directory.
3260 to the contents they had in the parent of the working directory.
3261 This restores the contents of the affected files to an unmodified
3261 This restores the contents of the affected files to an unmodified
3262 state and unschedules adds, removes, copies, and renames. If the
3262 state and unschedules adds, removes, copies, and renames. If the
3263 working directory has two parents, you must explicitly specify a
3263 working directory has two parents, you must explicitly specify a
3264 revision.
3264 revision.
3265
3265
3266 Using the -r/--rev option, revert the given files or directories
3266 Using the -r/--rev option, revert the given files or directories
3267 to their contents as of a specific revision. This can be helpful
3267 to their contents as of a specific revision. This can be helpful
3268 to "roll back" some or all of an earlier change. See :hg:`help
3268 to "roll back" some or all of an earlier change. See :hg:`help
3269 dates` for a list of formats valid for -d/--date.
3269 dates` for a list of formats valid for -d/--date.
3270
3270
3271 Revert modifies the working directory. It does not commit any
3271 Revert modifies the working directory. It does not commit any
3272 changes, or change the parent of the working directory. If you
3272 changes, or change the parent of the working directory. If you
3273 revert to a revision other than the parent of the working
3273 revert to a revision other than the parent of the working
3274 directory, the reverted files will thus appear modified
3274 directory, the reverted files will thus appear modified
3275 afterwards.
3275 afterwards.
3276
3276
3277 If a file has been deleted, it is restored. If the executable mode
3277 If a file has been deleted, it is restored. If the executable mode
3278 of a file was changed, it is reset.
3278 of a file was changed, it is reset.
3279
3279
3280 If names are given, all files matching the names are reverted.
3280 If names are given, all files matching the names are reverted.
3281 If no arguments are given, no files are reverted.
3281 If no arguments are given, no files are reverted.
3282
3282
3283 Modified files are saved with a .orig suffix before reverting.
3283 Modified files are saved with a .orig suffix before reverting.
3284 To disable these backups, use --no-backup.
3284 To disable these backups, use --no-backup.
3285
3285
3286 Returns 0 on success.
3286 Returns 0 on success.
3287 """
3287 """
3288
3288
3289 if opts.get("date"):
3289 if opts.get("date"):
3290 if opts.get("rev"):
3290 if opts.get("rev"):
3291 raise util.Abort(_("you can't specify a revision and a date"))
3291 raise util.Abort(_("you can't specify a revision and a date"))
3292 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3292 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3293
3293
3294 parent, p2 = repo.dirstate.parents()
3294 parent, p2 = repo.dirstate.parents()
3295 if not opts.get('rev') and p2 != nullid:
3295 if not opts.get('rev') and p2 != nullid:
3296 raise util.Abort(_('uncommitted merge - '
3296 raise util.Abort(_('uncommitted merge - '
3297 'use "hg update", see "hg help revert"'))
3297 'use "hg update", see "hg help revert"'))
3298
3298
3299 if not pats and not opts.get('all'):
3299 if not pats and not opts.get('all'):
3300 raise util.Abort(_('no files or directories specified; '
3300 raise util.Abort(_('no files or directories specified; '
3301 'use --all to revert the whole repo'))
3301 'use --all to revert the whole repo'))
3302
3302
3303 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3303 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3304 node = ctx.node()
3304 node = ctx.node()
3305 mf = ctx.manifest()
3305 mf = ctx.manifest()
3306 if node == parent:
3306 if node == parent:
3307 pmf = mf
3307 pmf = mf
3308 else:
3308 else:
3309 pmf = None
3309 pmf = None
3310
3310
3311 # need all matching names in dirstate and manifest of target rev,
3311 # need all matching names in dirstate and manifest of target rev,
3312 # so have to walk both. do not print errors if files exist in one
3312 # so have to walk both. do not print errors if files exist in one
3313 # but not other.
3313 # but not other.
3314
3314
3315 names = {}
3315 names = {}
3316
3316
3317 wlock = repo.wlock()
3317 wlock = repo.wlock()
3318 try:
3318 try:
3319 # walk dirstate.
3319 # walk dirstate.
3320
3320
3321 m = cmdutil.match(repo, pats, opts)
3321 m = cmdutil.match(repo, pats, opts)
3322 m.bad = lambda x, y: False
3322 m.bad = lambda x, y: False
3323 for abs in repo.walk(m):
3323 for abs in repo.walk(m):
3324 names[abs] = m.rel(abs), m.exact(abs)
3324 names[abs] = m.rel(abs), m.exact(abs)
3325
3325
3326 # walk target manifest.
3326 # walk target manifest.
3327
3327
3328 def badfn(path, msg):
3328 def badfn(path, msg):
3329 if path in names:
3329 if path in names:
3330 return
3330 return
3331 path_ = path + '/'
3331 path_ = path + '/'
3332 for f in names:
3332 for f in names:
3333 if f.startswith(path_):
3333 if f.startswith(path_):
3334 return
3334 return
3335 ui.warn("%s: %s\n" % (m.rel(path), msg))
3335 ui.warn("%s: %s\n" % (m.rel(path), msg))
3336
3336
3337 m = cmdutil.match(repo, pats, opts)
3337 m = cmdutil.match(repo, pats, opts)
3338 m.bad = badfn
3338 m.bad = badfn
3339 for abs in repo[node].walk(m):
3339 for abs in repo[node].walk(m):
3340 if abs not in names:
3340 if abs not in names:
3341 names[abs] = m.rel(abs), m.exact(abs)
3341 names[abs] = m.rel(abs), m.exact(abs)
3342
3342
3343 m = cmdutil.matchfiles(repo, names)
3343 m = cmdutil.matchfiles(repo, names)
3344 changes = repo.status(match=m)[:4]
3344 changes = repo.status(match=m)[:4]
3345 modified, added, removed, deleted = map(set, changes)
3345 modified, added, removed, deleted = map(set, changes)
3346
3346
3347 # if f is a rename, also revert the source
3347 # if f is a rename, also revert the source
3348 cwd = repo.getcwd()
3348 cwd = repo.getcwd()
3349 for f in added:
3349 for f in added:
3350 src = repo.dirstate.copied(f)
3350 src = repo.dirstate.copied(f)
3351 if src and src not in names and repo.dirstate[src] == 'r':
3351 if src and src not in names and repo.dirstate[src] == 'r':
3352 removed.add(src)
3352 removed.add(src)
3353 names[src] = (repo.pathto(src, cwd), True)
3353 names[src] = (repo.pathto(src, cwd), True)
3354
3354
3355 def removeforget(abs):
3355 def removeforget(abs):
3356 if repo.dirstate[abs] == 'a':
3356 if repo.dirstate[abs] == 'a':
3357 return _('forgetting %s\n')
3357 return _('forgetting %s\n')
3358 return _('removing %s\n')
3358 return _('removing %s\n')
3359
3359
3360 revert = ([], _('reverting %s\n'))
3360 revert = ([], _('reverting %s\n'))
3361 add = ([], _('adding %s\n'))
3361 add = ([], _('adding %s\n'))
3362 remove = ([], removeforget)
3362 remove = ([], removeforget)
3363 undelete = ([], _('undeleting %s\n'))
3363 undelete = ([], _('undeleting %s\n'))
3364
3364
3365 disptable = (
3365 disptable = (
3366 # dispatch table:
3366 # dispatch table:
3367 # file state
3367 # file state
3368 # action if in target manifest
3368 # action if in target manifest
3369 # action if not in target manifest
3369 # action if not in target manifest
3370 # make backup if in target manifest
3370 # make backup if in target manifest
3371 # make backup if not in target manifest
3371 # make backup if not in target manifest
3372 (modified, revert, remove, True, True),
3372 (modified, revert, remove, True, True),
3373 (added, revert, remove, True, False),
3373 (added, revert, remove, True, False),
3374 (removed, undelete, None, False, False),
3374 (removed, undelete, None, False, False),
3375 (deleted, revert, remove, False, False),
3375 (deleted, revert, remove, False, False),
3376 )
3376 )
3377
3377
3378 for abs, (rel, exact) in sorted(names.items()):
3378 for abs, (rel, exact) in sorted(names.items()):
3379 mfentry = mf.get(abs)
3379 mfentry = mf.get(abs)
3380 target = repo.wjoin(abs)
3380 target = repo.wjoin(abs)
3381 def handle(xlist, dobackup):
3381 def handle(xlist, dobackup):
3382 xlist[0].append(abs)
3382 xlist[0].append(abs)
3383 if (dobackup and not opts.get('no_backup') and
3383 if (dobackup and not opts.get('no_backup') and
3384 os.path.lexists(target)):
3384 os.path.lexists(target)):
3385 bakname = "%s.orig" % rel
3385 bakname = "%s.orig" % rel
3386 ui.note(_('saving current version of %s as %s\n') %
3386 ui.note(_('saving current version of %s as %s\n') %
3387 (rel, bakname))
3387 (rel, bakname))
3388 if not opts.get('dry_run'):
3388 if not opts.get('dry_run'):
3389 util.rename(target, bakname)
3389 util.rename(target, bakname)
3390 if ui.verbose or not exact:
3390 if ui.verbose or not exact:
3391 msg = xlist[1]
3391 msg = xlist[1]
3392 if not isinstance(msg, basestring):
3392 if not isinstance(msg, basestring):
3393 msg = msg(abs)
3393 msg = msg(abs)
3394 ui.status(msg % rel)
3394 ui.status(msg % rel)
3395 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3395 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3396 if abs not in table:
3396 if abs not in table:
3397 continue
3397 continue
3398 # file has changed in dirstate
3398 # file has changed in dirstate
3399 if mfentry:
3399 if mfentry:
3400 handle(hitlist, backuphit)
3400 handle(hitlist, backuphit)
3401 elif misslist is not None:
3401 elif misslist is not None:
3402 handle(misslist, backupmiss)
3402 handle(misslist, backupmiss)
3403 break
3403 break
3404 else:
3404 else:
3405 if abs not in repo.dirstate:
3405 if abs not in repo.dirstate:
3406 if mfentry:
3406 if mfentry:
3407 handle(add, True)
3407 handle(add, True)
3408 elif exact:
3408 elif exact:
3409 ui.warn(_('file not managed: %s\n') % rel)
3409 ui.warn(_('file not managed: %s\n') % rel)
3410 continue
3410 continue
3411 # file has not changed in dirstate
3411 # file has not changed in dirstate
3412 if node == parent:
3412 if node == parent:
3413 if exact:
3413 if exact:
3414 ui.warn(_('no changes needed to %s\n') % rel)
3414 ui.warn(_('no changes needed to %s\n') % rel)
3415 continue
3415 continue
3416 if pmf is None:
3416 if pmf is None:
3417 # only need parent manifest in this unlikely case,
3417 # only need parent manifest in this unlikely case,
3418 # so do not read by default
3418 # so do not read by default
3419 pmf = repo[parent].manifest()
3419 pmf = repo[parent].manifest()
3420 if abs in pmf:
3420 if abs in pmf:
3421 if mfentry:
3421 if mfentry:
3422 # if version of file is same in parent and target
3422 # if version of file is same in parent and target
3423 # manifests, do nothing
3423 # manifests, do nothing
3424 if (pmf[abs] != mfentry or
3424 if (pmf[abs] != mfentry or
3425 pmf.flags(abs) != mf.flags(abs)):
3425 pmf.flags(abs) != mf.flags(abs)):
3426 handle(revert, False)
3426 handle(revert, False)
3427 else:
3427 else:
3428 handle(remove, False)
3428 handle(remove, False)
3429
3429
3430 if not opts.get('dry_run'):
3430 if not opts.get('dry_run'):
3431 def checkout(f):
3431 def checkout(f):
3432 fc = ctx[f]
3432 fc = ctx[f]
3433 repo.wwrite(f, fc.data(), fc.flags())
3433 repo.wwrite(f, fc.data(), fc.flags())
3434
3434
3435 audit_path = util.path_auditor(repo.root)
3435 audit_path = util.path_auditor(repo.root)
3436 for f in remove[0]:
3436 for f in remove[0]:
3437 if repo.dirstate[f] == 'a':
3437 if repo.dirstate[f] == 'a':
3438 repo.dirstate.forget(f)
3438 repo.dirstate.forget(f)
3439 continue
3439 continue
3440 audit_path(f)
3440 audit_path(f)
3441 try:
3441 try:
3442 util.unlinkpath(repo.wjoin(f))
3442 util.unlinkpath(repo.wjoin(f))
3443 except OSError:
3443 except OSError:
3444 pass
3444 pass
3445 repo.dirstate.remove(f)
3445 repo.dirstate.remove(f)
3446
3446
3447 normal = None
3447 normal = None
3448 if node == parent:
3448 if node == parent:
3449 # We're reverting to our parent. If possible, we'd like status
3449 # We're reverting to our parent. If possible, we'd like status
3450 # to report the file as clean. We have to use normallookup for
3450 # to report the file as clean. We have to use normallookup for
3451 # merges to avoid losing information about merged/dirty files.
3451 # merges to avoid losing information about merged/dirty files.
3452 if p2 != nullid:
3452 if p2 != nullid:
3453 normal = repo.dirstate.normallookup
3453 normal = repo.dirstate.normallookup
3454 else:
3454 else:
3455 normal = repo.dirstate.normal
3455 normal = repo.dirstate.normal
3456 for f in revert[0]:
3456 for f in revert[0]:
3457 checkout(f)
3457 checkout(f)
3458 if normal:
3458 if normal:
3459 normal(f)
3459 normal(f)
3460
3460
3461 for f in add[0]:
3461 for f in add[0]:
3462 checkout(f)
3462 checkout(f)
3463 repo.dirstate.add(f)
3463 repo.dirstate.add(f)
3464
3464
3465 normal = repo.dirstate.normallookup
3465 normal = repo.dirstate.normallookup
3466 if node == parent and p2 == nullid:
3466 if node == parent and p2 == nullid:
3467 normal = repo.dirstate.normal
3467 normal = repo.dirstate.normal
3468 for f in undelete[0]:
3468 for f in undelete[0]:
3469 checkout(f)
3469 checkout(f)
3470 normal(f)
3470 normal(f)
3471
3471
3472 finally:
3472 finally:
3473 wlock.release()
3473 wlock.release()
3474
3474
3475 def rollback(ui, repo, **opts):
3475 def rollback(ui, repo, **opts):
3476 """roll back the last transaction (dangerous)
3476 """roll back the last transaction (dangerous)
3477
3477
3478 This command should be used with care. There is only one level of
3478 This command should be used with care. There is only one level of
3479 rollback, and there is no way to undo a rollback. It will also
3479 rollback, and there is no way to undo a rollback. It will also
3480 restore the dirstate at the time of the last transaction, losing
3480 restore the dirstate at the time of the last transaction, losing
3481 any dirstate changes since that time. This command does not alter
3481 any dirstate changes since that time. This command does not alter
3482 the working directory.
3482 the working directory.
3483
3483
3484 Transactions are used to encapsulate the effects of all commands
3484 Transactions are used to encapsulate the effects of all commands
3485 that create new changesets or propagate existing changesets into a
3485 that create new changesets or propagate existing changesets into a
3486 repository. For example, the following commands are transactional,
3486 repository. For example, the following commands are transactional,
3487 and their effects can be rolled back:
3487 and their effects can be rolled back:
3488
3488
3489 - commit
3489 - commit
3490 - import
3490 - import
3491 - pull
3491 - pull
3492 - push (with this repository as the destination)
3492 - push (with this repository as the destination)
3493 - unbundle
3493 - unbundle
3494
3494
3495 This command is not intended for use on public repositories. Once
3495 This command is not intended for use on public repositories. Once
3496 changes are visible for pull by other users, rolling a transaction
3496 changes are visible for pull by other users, rolling a transaction
3497 back locally is ineffective (someone else may already have pulled
3497 back locally is ineffective (someone else may already have pulled
3498 the changes). Furthermore, a race is possible with readers of the
3498 the changes). Furthermore, a race is possible with readers of the
3499 repository; for example an in-progress pull from the repository
3499 repository; for example an in-progress pull from the repository
3500 may fail if a rollback is performed.
3500 may fail if a rollback is performed.
3501
3501
3502 Returns 0 on success, 1 if no rollback data is available.
3502 Returns 0 on success, 1 if no rollback data is available.
3503 """
3503 """
3504 return repo.rollback(opts.get('dry_run'))
3504 return repo.rollback(opts.get('dry_run'))
3505
3505
3506 def root(ui, repo):
3506 def root(ui, repo):
3507 """print the root (top) of the current working directory
3507 """print the root (top) of the current working directory
3508
3508
3509 Print the root directory of the current repository.
3509 Print the root directory of the current repository.
3510
3510
3511 Returns 0 on success.
3511 Returns 0 on success.
3512 """
3512 """
3513 ui.write(repo.root + "\n")
3513 ui.write(repo.root + "\n")
3514
3514
3515 def serve(ui, repo, **opts):
3515 def serve(ui, repo, **opts):
3516 """start stand-alone webserver
3516 """start stand-alone webserver
3517
3517
3518 Start a local HTTP repository browser and pull server. You can use
3518 Start a local HTTP repository browser and pull server. You can use
3519 this for ad-hoc sharing and browsing of repositories. It is
3519 this for ad-hoc sharing and browsing of repositories. It is
3520 recommended to use a real web server to serve a repository for
3520 recommended to use a real web server to serve a repository for
3521 longer periods of time.
3521 longer periods of time.
3522
3522
3523 Please note that the server does not implement access control.
3523 Please note that the server does not implement access control.
3524 This means that, by default, anybody can read from the server and
3524 This means that, by default, anybody can read from the server and
3525 nobody can write to it by default. Set the ``web.allow_push``
3525 nobody can write to it by default. Set the ``web.allow_push``
3526 option to ``*`` to allow everybody to push to the server. You
3526 option to ``*`` to allow everybody to push to the server. You
3527 should use a real web server if you need to authenticate users.
3527 should use a real web server if you need to authenticate users.
3528
3528
3529 By default, the server logs accesses to stdout and errors to
3529 By default, the server logs accesses to stdout and errors to
3530 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3530 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3531 files.
3531 files.
3532
3532
3533 To have the server choose a free port number to listen on, specify
3533 To have the server choose a free port number to listen on, specify
3534 a port number of 0; in this case, the server will print the port
3534 a port number of 0; in this case, the server will print the port
3535 number it uses.
3535 number it uses.
3536
3536
3537 Returns 0 on success.
3537 Returns 0 on success.
3538 """
3538 """
3539
3539
3540 if opts["stdio"]:
3540 if opts["stdio"]:
3541 if repo is None:
3541 if repo is None:
3542 raise error.RepoError(_("There is no Mercurial repository here"
3542 raise error.RepoError(_("There is no Mercurial repository here"
3543 " (.hg not found)"))
3543 " (.hg not found)"))
3544 s = sshserver.sshserver(ui, repo)
3544 s = sshserver.sshserver(ui, repo)
3545 s.serve_forever()
3545 s.serve_forever()
3546
3546
3547 # this way we can check if something was given in the command-line
3547 # this way we can check if something was given in the command-line
3548 if opts.get('port'):
3548 if opts.get('port'):
3549 opts['port'] = util.getport(opts.get('port'))
3549 opts['port'] = util.getport(opts.get('port'))
3550
3550
3551 baseui = repo and repo.baseui or ui
3551 baseui = repo and repo.baseui or ui
3552 optlist = ("name templates style address port prefix ipv6"
3552 optlist = ("name templates style address port prefix ipv6"
3553 " accesslog errorlog certificate encoding")
3553 " accesslog errorlog certificate encoding")
3554 for o in optlist.split():
3554 for o in optlist.split():
3555 val = opts.get(o, '')
3555 val = opts.get(o, '')
3556 if val in (None, ''): # should check against default options instead
3556 if val in (None, ''): # should check against default options instead
3557 continue
3557 continue
3558 baseui.setconfig("web", o, val)
3558 baseui.setconfig("web", o, val)
3559 if repo and repo.ui != baseui:
3559 if repo and repo.ui != baseui:
3560 repo.ui.setconfig("web", o, val)
3560 repo.ui.setconfig("web", o, val)
3561
3561
3562 o = opts.get('web_conf') or opts.get('webdir_conf')
3562 o = opts.get('web_conf') or opts.get('webdir_conf')
3563 if not o:
3563 if not o:
3564 if not repo:
3564 if not repo:
3565 raise error.RepoError(_("There is no Mercurial repository"
3565 raise error.RepoError(_("There is no Mercurial repository"
3566 " here (.hg not found)"))
3566 " here (.hg not found)"))
3567 o = repo.root
3567 o = repo.root
3568
3568
3569 app = hgweb.hgweb(o, baseui=ui)
3569 app = hgweb.hgweb(o, baseui=ui)
3570
3570
3571 class service(object):
3571 class service(object):
3572 def init(self):
3572 def init(self):
3573 util.set_signal_handler()
3573 util.set_signal_handler()
3574 self.httpd = hgweb.server.create_server(ui, app)
3574 self.httpd = hgweb.server.create_server(ui, app)
3575
3575
3576 if opts['port'] and not ui.verbose:
3576 if opts['port'] and not ui.verbose:
3577 return
3577 return
3578
3578
3579 if self.httpd.prefix:
3579 if self.httpd.prefix:
3580 prefix = self.httpd.prefix.strip('/') + '/'
3580 prefix = self.httpd.prefix.strip('/') + '/'
3581 else:
3581 else:
3582 prefix = ''
3582 prefix = ''
3583
3583
3584 port = ':%d' % self.httpd.port
3584 port = ':%d' % self.httpd.port
3585 if port == ':80':
3585 if port == ':80':
3586 port = ''
3586 port = ''
3587
3587
3588 bindaddr = self.httpd.addr
3588 bindaddr = self.httpd.addr
3589 if bindaddr == '0.0.0.0':
3589 if bindaddr == '0.0.0.0':
3590 bindaddr = '*'
3590 bindaddr = '*'
3591 elif ':' in bindaddr: # IPv6
3591 elif ':' in bindaddr: # IPv6
3592 bindaddr = '[%s]' % bindaddr
3592 bindaddr = '[%s]' % bindaddr
3593
3593
3594 fqaddr = self.httpd.fqaddr
3594 fqaddr = self.httpd.fqaddr
3595 if ':' in fqaddr:
3595 if ':' in fqaddr:
3596 fqaddr = '[%s]' % fqaddr
3596 fqaddr = '[%s]' % fqaddr
3597 if opts['port']:
3597 if opts['port']:
3598 write = ui.status
3598 write = ui.status
3599 else:
3599 else:
3600 write = ui.write
3600 write = ui.write
3601 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3601 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3602 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3602 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3603
3603
3604 def run(self):
3604 def run(self):
3605 self.httpd.serve_forever()
3605 self.httpd.serve_forever()
3606
3606
3607 service = service()
3607 service = service()
3608
3608
3609 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3609 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3610
3610
3611 def status(ui, repo, *pats, **opts):
3611 def status(ui, repo, *pats, **opts):
3612 """show changed files in the working directory
3612 """show changed files in the working directory
3613
3613
3614 Show status of files in the repository. If names are given, only
3614 Show status of files in the repository. If names are given, only
3615 files that match are shown. Files that are clean or ignored or
3615 files that match are shown. Files that are clean or ignored or
3616 the source of a copy/move operation, are not listed unless
3616 the source of a copy/move operation, are not listed unless
3617 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3617 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3618 Unless options described with "show only ..." are given, the
3618 Unless options described with "show only ..." are given, the
3619 options -mardu are used.
3619 options -mardu are used.
3620
3620
3621 Option -q/--quiet hides untracked (unknown and ignored) files
3621 Option -q/--quiet hides untracked (unknown and ignored) files
3622 unless explicitly requested with -u/--unknown or -i/--ignored.
3622 unless explicitly requested with -u/--unknown or -i/--ignored.
3623
3623
3624 .. note::
3624 .. note::
3625 status may appear to disagree with diff if permissions have
3625 status may appear to disagree with diff if permissions have
3626 changed or a merge has occurred. The standard diff format does
3626 changed or a merge has occurred. The standard diff format does
3627 not report permission changes and diff only reports changes
3627 not report permission changes and diff only reports changes
3628 relative to one merge parent.
3628 relative to one merge parent.
3629
3629
3630 If one revision is given, it is used as the base revision.
3630 If one revision is given, it is used as the base revision.
3631 If two revisions are given, the differences between them are
3631 If two revisions are given, the differences between them are
3632 shown. The --change option can also be used as a shortcut to list
3632 shown. The --change option can also be used as a shortcut to list
3633 the changed files of a revision from its first parent.
3633 the changed files of a revision from its first parent.
3634
3634
3635 The codes used to show the status of files are::
3635 The codes used to show the status of files are::
3636
3636
3637 M = modified
3637 M = modified
3638 A = added
3638 A = added
3639 R = removed
3639 R = removed
3640 C = clean
3640 C = clean
3641 ! = missing (deleted by non-hg command, but still tracked)
3641 ! = missing (deleted by non-hg command, but still tracked)
3642 ? = not tracked
3642 ? = not tracked
3643 I = ignored
3643 I = ignored
3644 = origin of the previous file listed as A (added)
3644 = origin of the previous file listed as A (added)
3645
3645
3646 Returns 0 on success.
3646 Returns 0 on success.
3647 """
3647 """
3648
3648
3649 revs = opts.get('rev')
3649 revs = opts.get('rev')
3650 change = opts.get('change')
3650 change = opts.get('change')
3651
3651
3652 if revs and change:
3652 if revs and change:
3653 msg = _('cannot specify --rev and --change at the same time')
3653 msg = _('cannot specify --rev and --change at the same time')
3654 raise util.Abort(msg)
3654 raise util.Abort(msg)
3655 elif change:
3655 elif change:
3656 node2 = repo.lookup(change)
3656 node2 = repo.lookup(change)
3657 node1 = repo[node2].parents()[0].node()
3657 node1 = repo[node2].parents()[0].node()
3658 else:
3658 else:
3659 node1, node2 = cmdutil.revpair(repo, revs)
3659 node1, node2 = cmdutil.revpair(repo, revs)
3660
3660
3661 cwd = (pats and repo.getcwd()) or ''
3661 cwd = (pats and repo.getcwd()) or ''
3662 end = opts.get('print0') and '\0' or '\n'
3662 end = opts.get('print0') and '\0' or '\n'
3663 copy = {}
3663 copy = {}
3664 states = 'modified added removed deleted unknown ignored clean'.split()
3664 states = 'modified added removed deleted unknown ignored clean'.split()
3665 show = [k for k in states if opts.get(k)]
3665 show = [k for k in states if opts.get(k)]
3666 if opts.get('all'):
3666 if opts.get('all'):
3667 show += ui.quiet and (states[:4] + ['clean']) or states
3667 show += ui.quiet and (states[:4] + ['clean']) or states
3668 if not show:
3668 if not show:
3669 show = ui.quiet and states[:4] or states[:5]
3669 show = ui.quiet and states[:4] or states[:5]
3670
3670
3671 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3671 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3672 'ignored' in show, 'clean' in show, 'unknown' in show,
3672 'ignored' in show, 'clean' in show, 'unknown' in show,
3673 opts.get('subrepos'))
3673 opts.get('subrepos'))
3674 changestates = zip(states, 'MAR!?IC', stat)
3674 changestates = zip(states, 'MAR!?IC', stat)
3675
3675
3676 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3676 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3677 ctxn = repo[nullid]
3677 ctxn = repo[nullid]
3678 ctx1 = repo[node1]
3678 ctx1 = repo[node1]
3679 ctx2 = repo[node2]
3679 ctx2 = repo[node2]
3680 added = stat[1]
3680 added = stat[1]
3681 if node2 is None:
3681 if node2 is None:
3682 added = stat[0] + stat[1] # merged?
3682 added = stat[0] + stat[1] # merged?
3683
3683
3684 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3684 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3685 if k in added:
3685 if k in added:
3686 copy[k] = v
3686 copy[k] = v
3687 elif v in added:
3687 elif v in added:
3688 copy[v] = k
3688 copy[v] = k
3689
3689
3690 for state, char, files in changestates:
3690 for state, char, files in changestates:
3691 if state in show:
3691 if state in show:
3692 format = "%s %%s%s" % (char, end)
3692 format = "%s %%s%s" % (char, end)
3693 if opts.get('no_status'):
3693 if opts.get('no_status'):
3694 format = "%%s%s" % end
3694 format = "%%s%s" % end
3695
3695
3696 for f in files:
3696 for f in files:
3697 ui.write(format % repo.pathto(f, cwd),
3697 ui.write(format % repo.pathto(f, cwd),
3698 label='status.' + state)
3698 label='status.' + state)
3699 if f in copy:
3699 if f in copy:
3700 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3700 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3701 label='status.copied')
3701 label='status.copied')
3702
3702
3703 def summary(ui, repo, **opts):
3703 def summary(ui, repo, **opts):
3704 """summarize working directory state
3704 """summarize working directory state
3705
3705
3706 This generates a brief summary of the working directory state,
3706 This generates a brief summary of the working directory state,
3707 including parents, branch, commit status, and available updates.
3707 including parents, branch, commit status, and available updates.
3708
3708
3709 With the --remote option, this will check the default paths for
3709 With the --remote option, this will check the default paths for
3710 incoming and outgoing changes. This can be time-consuming.
3710 incoming and outgoing changes. This can be time-consuming.
3711
3711
3712 Returns 0 on success.
3712 Returns 0 on success.
3713 """
3713 """
3714
3714
3715 ctx = repo[None]
3715 ctx = repo[None]
3716 parents = ctx.parents()
3716 parents = ctx.parents()
3717 pnode = parents[0].node()
3717 pnode = parents[0].node()
3718
3718
3719 for p in parents:
3719 for p in parents:
3720 # label with log.changeset (instead of log.parent) since this
3720 # label with log.changeset (instead of log.parent) since this
3721 # shows a working directory parent *changeset*:
3721 # shows a working directory parent *changeset*:
3722 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3722 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3723 label='log.changeset')
3723 label='log.changeset')
3724 ui.write(' '.join(p.tags()), label='log.tag')
3724 ui.write(' '.join(p.tags()), label='log.tag')
3725 if p.bookmarks():
3725 if p.bookmarks():
3726 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3726 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3727 if p.rev() == -1:
3727 if p.rev() == -1:
3728 if not len(repo):
3728 if not len(repo):
3729 ui.write(_(' (empty repository)'))
3729 ui.write(_(' (empty repository)'))
3730 else:
3730 else:
3731 ui.write(_(' (no revision checked out)'))
3731 ui.write(_(' (no revision checked out)'))
3732 ui.write('\n')
3732 ui.write('\n')
3733 if p.description():
3733 if p.description():
3734 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3734 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3735 label='log.summary')
3735 label='log.summary')
3736
3736
3737 branch = ctx.branch()
3737 branch = ctx.branch()
3738 bheads = repo.branchheads(branch)
3738 bheads = repo.branchheads(branch)
3739 m = _('branch: %s\n') % branch
3739 m = _('branch: %s\n') % branch
3740 if branch != 'default':
3740 if branch != 'default':
3741 ui.write(m, label='log.branch')
3741 ui.write(m, label='log.branch')
3742 else:
3742 else:
3743 ui.status(m, label='log.branch')
3743 ui.status(m, label='log.branch')
3744
3744
3745 st = list(repo.status(unknown=True))[:6]
3745 st = list(repo.status(unknown=True))[:6]
3746
3746
3747 c = repo.dirstate.copies()
3747 c = repo.dirstate.copies()
3748 copied, renamed = [], []
3748 copied, renamed = [], []
3749 for d, s in c.iteritems():
3749 for d, s in c.iteritems():
3750 if s in st[2]:
3750 if s in st[2]:
3751 st[2].remove(s)
3751 st[2].remove(s)
3752 renamed.append(d)
3752 renamed.append(d)
3753 else:
3753 else:
3754 copied.append(d)
3754 copied.append(d)
3755 if d in st[1]:
3755 if d in st[1]:
3756 st[1].remove(d)
3756 st[1].remove(d)
3757 st.insert(3, renamed)
3757 st.insert(3, renamed)
3758 st.insert(4, copied)
3758 st.insert(4, copied)
3759
3759
3760 ms = mergemod.mergestate(repo)
3760 ms = mergemod.mergestate(repo)
3761 st.append([f for f in ms if ms[f] == 'u'])
3761 st.append([f for f in ms if ms[f] == 'u'])
3762
3762
3763 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3763 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3764 st.append(subs)
3764 st.append(subs)
3765
3765
3766 labels = [ui.label(_('%d modified'), 'status.modified'),
3766 labels = [ui.label(_('%d modified'), 'status.modified'),
3767 ui.label(_('%d added'), 'status.added'),
3767 ui.label(_('%d added'), 'status.added'),
3768 ui.label(_('%d removed'), 'status.removed'),
3768 ui.label(_('%d removed'), 'status.removed'),
3769 ui.label(_('%d renamed'), 'status.copied'),
3769 ui.label(_('%d renamed'), 'status.copied'),
3770 ui.label(_('%d copied'), 'status.copied'),
3770 ui.label(_('%d copied'), 'status.copied'),
3771 ui.label(_('%d deleted'), 'status.deleted'),
3771 ui.label(_('%d deleted'), 'status.deleted'),
3772 ui.label(_('%d unknown'), 'status.unknown'),
3772 ui.label(_('%d unknown'), 'status.unknown'),
3773 ui.label(_('%d ignored'), 'status.ignored'),
3773 ui.label(_('%d ignored'), 'status.ignored'),
3774 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3774 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3775 ui.label(_('%d subrepos'), 'status.modified')]
3775 ui.label(_('%d subrepos'), 'status.modified')]
3776 t = []
3776 t = []
3777 for s, l in zip(st, labels):
3777 for s, l in zip(st, labels):
3778 if s:
3778 if s:
3779 t.append(l % len(s))
3779 t.append(l % len(s))
3780
3780
3781 t = ', '.join(t)
3781 t = ', '.join(t)
3782 cleanworkdir = False
3782 cleanworkdir = False
3783
3783
3784 if len(parents) > 1:
3784 if len(parents) > 1:
3785 t += _(' (merge)')
3785 t += _(' (merge)')
3786 elif branch != parents[0].branch():
3786 elif branch != parents[0].branch():
3787 t += _(' (new branch)')
3787 t += _(' (new branch)')
3788 elif (parents[0].extra().get('close') and
3788 elif (parents[0].extra().get('close') and
3789 pnode in repo.branchheads(branch, closed=True)):
3789 pnode in repo.branchheads(branch, closed=True)):
3790 t += _(' (head closed)')
3790 t += _(' (head closed)')
3791 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3791 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3792 t += _(' (clean)')
3792 t += _(' (clean)')
3793 cleanworkdir = True
3793 cleanworkdir = True
3794 elif pnode not in bheads:
3794 elif pnode not in bheads:
3795 t += _(' (new branch head)')
3795 t += _(' (new branch head)')
3796
3796
3797 if cleanworkdir:
3797 if cleanworkdir:
3798 ui.status(_('commit: %s\n') % t.strip())
3798 ui.status(_('commit: %s\n') % t.strip())
3799 else:
3799 else:
3800 ui.write(_('commit: %s\n') % t.strip())
3800 ui.write(_('commit: %s\n') % t.strip())
3801
3801
3802 # all ancestors of branch heads - all ancestors of parent = new csets
3802 # all ancestors of branch heads - all ancestors of parent = new csets
3803 new = [0] * len(repo)
3803 new = [0] * len(repo)
3804 cl = repo.changelog
3804 cl = repo.changelog
3805 for a in [cl.rev(n) for n in bheads]:
3805 for a in [cl.rev(n) for n in bheads]:
3806 new[a] = 1
3806 new[a] = 1
3807 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3807 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3808 new[a] = 1
3808 new[a] = 1
3809 for a in [p.rev() for p in parents]:
3809 for a in [p.rev() for p in parents]:
3810 if a >= 0:
3810 if a >= 0:
3811 new[a] = 0
3811 new[a] = 0
3812 for a in cl.ancestors(*[p.rev() for p in parents]):
3812 for a in cl.ancestors(*[p.rev() for p in parents]):
3813 new[a] = 0
3813 new[a] = 0
3814 new = sum(new)
3814 new = sum(new)
3815
3815
3816 if new == 0:
3816 if new == 0:
3817 ui.status(_('update: (current)\n'))
3817 ui.status(_('update: (current)\n'))
3818 elif pnode not in bheads:
3818 elif pnode not in bheads:
3819 ui.write(_('update: %d new changesets (update)\n') % new)
3819 ui.write(_('update: %d new changesets (update)\n') % new)
3820 else:
3820 else:
3821 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3821 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3822 (new, len(bheads)))
3822 (new, len(bheads)))
3823
3823
3824 if opts.get('remote'):
3824 if opts.get('remote'):
3825 t = []
3825 t = []
3826 source, branches = hg.parseurl(ui.expandpath('default'))
3826 source, branches = hg.parseurl(ui.expandpath('default'))
3827 other = hg.repository(hg.remoteui(repo, {}), source)
3827 other = hg.repository(hg.remoteui(repo, {}), source)
3828 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3828 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3829 ui.debug('comparing with %s\n' % url.hidepassword(source))
3829 ui.debug('comparing with %s\n' % url.hidepassword(source))
3830 repo.ui.pushbuffer()
3830 repo.ui.pushbuffer()
3831 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3831 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3832 repo.ui.popbuffer()
3832 repo.ui.popbuffer()
3833 if incoming:
3833 if incoming:
3834 t.append(_('1 or more incoming'))
3834 t.append(_('1 or more incoming'))
3835
3835
3836 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3836 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3837 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3837 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3838 other = hg.repository(hg.remoteui(repo, {}), dest)
3838 other = hg.repository(hg.remoteui(repo, {}), dest)
3839 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3839 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3840 repo.ui.pushbuffer()
3840 repo.ui.pushbuffer()
3841 o = discovery.findoutgoing(repo, other)
3841 o = discovery.findoutgoing(repo, other)
3842 repo.ui.popbuffer()
3842 repo.ui.popbuffer()
3843 o = repo.changelog.nodesbetween(o, None)[0]
3843 o = repo.changelog.nodesbetween(o, None)[0]
3844 if o:
3844 if o:
3845 t.append(_('%d outgoing') % len(o))
3845 t.append(_('%d outgoing') % len(o))
3846 if 'bookmarks' in other.listkeys('namespaces'):
3846 if 'bookmarks' in other.listkeys('namespaces'):
3847 lmarks = repo.listkeys('bookmarks')
3847 lmarks = repo.listkeys('bookmarks')
3848 rmarks = other.listkeys('bookmarks')
3848 rmarks = other.listkeys('bookmarks')
3849 diff = set(rmarks) - set(lmarks)
3849 diff = set(rmarks) - set(lmarks)
3850 if len(diff) > 0:
3850 if len(diff) > 0:
3851 t.append(_('%d incoming bookmarks') % len(diff))
3851 t.append(_('%d incoming bookmarks') % len(diff))
3852 diff = set(lmarks) - set(rmarks)
3852 diff = set(lmarks) - set(rmarks)
3853 if len(diff) > 0:
3853 if len(diff) > 0:
3854 t.append(_('%d outgoing bookmarks') % len(diff))
3854 t.append(_('%d outgoing bookmarks') % len(diff))
3855
3855
3856 if t:
3856 if t:
3857 ui.write(_('remote: %s\n') % (', '.join(t)))
3857 ui.write(_('remote: %s\n') % (', '.join(t)))
3858 else:
3858 else:
3859 ui.status(_('remote: (synced)\n'))
3859 ui.status(_('remote: (synced)\n'))
3860
3860
3861 def tag(ui, repo, name1, *names, **opts):
3861 def tag(ui, repo, name1, *names, **opts):
3862 """add one or more tags for the current or given revision
3862 """add one or more tags for the current or given revision
3863
3863
3864 Name a particular revision using <name>.
3864 Name a particular revision using <name>.
3865
3865
3866 Tags are used to name particular revisions of the repository and are
3866 Tags are used to name particular revisions of the repository and are
3867 very useful to compare different revisions, to go back to significant
3867 very useful to compare different revisions, to go back to significant
3868 earlier versions or to mark branch points as releases, etc. Changing
3868 earlier versions or to mark branch points as releases, etc. Changing
3869 an existing tag is normally disallowed; use -f/--force to override.
3869 an existing tag is normally disallowed; use -f/--force to override.
3870
3870
3871 If no revision is given, the parent of the working directory is
3871 If no revision is given, the parent of the working directory is
3872 used, or tip if no revision is checked out.
3872 used, or tip if no revision is checked out.
3873
3873
3874 To facilitate version control, distribution, and merging of tags,
3874 To facilitate version control, distribution, and merging of tags,
3875 they are stored as a file named ".hgtags" which is managed similarly
3875 they are stored as a file named ".hgtags" which is managed similarly
3876 to other project files and can be hand-edited if necessary. This
3876 to other project files and can be hand-edited if necessary. This
3877 also means that tagging creates a new commit. The file
3877 also means that tagging creates a new commit. The file
3878 ".hg/localtags" is used for local tags (not shared among
3878 ".hg/localtags" is used for local tags (not shared among
3879 repositories).
3879 repositories).
3880
3880
3881 Tag commits are usually made at the head of a branch. If the parent
3881 Tag commits are usually made at the head of a branch. If the parent
3882 of the working directory is not a branch head, :hg:`tag` aborts; use
3882 of the working directory is not a branch head, :hg:`tag` aborts; use
3883 -f/--force to force the tag commit to be based on a non-head
3883 -f/--force to force the tag commit to be based on a non-head
3884 changeset.
3884 changeset.
3885
3885
3886 See :hg:`help dates` for a list of formats valid for -d/--date.
3886 See :hg:`help dates` for a list of formats valid for -d/--date.
3887
3887
3888 Since tag names have priority over branch names during revision
3888 Since tag names have priority over branch names during revision
3889 lookup, using an existing branch name as a tag name is discouraged.
3889 lookup, using an existing branch name as a tag name is discouraged.
3890
3890
3891 Returns 0 on success.
3891 Returns 0 on success.
3892 """
3892 """
3893
3893
3894 rev_ = "."
3894 rev_ = "."
3895 names = [t.strip() for t in (name1,) + names]
3895 names = [t.strip() for t in (name1,) + names]
3896 if len(names) != len(set(names)):
3896 if len(names) != len(set(names)):
3897 raise util.Abort(_('tag names must be unique'))
3897 raise util.Abort(_('tag names must be unique'))
3898 for n in names:
3898 for n in names:
3899 if n in ['tip', '.', 'null']:
3899 if n in ['tip', '.', 'null']:
3900 raise util.Abort(_('the name \'%s\' is reserved') % n)
3900 raise util.Abort(_('the name \'%s\' is reserved') % n)
3901 if not n:
3901 if not n:
3902 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3902 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3903 if opts.get('rev') and opts.get('remove'):
3903 if opts.get('rev') and opts.get('remove'):
3904 raise util.Abort(_("--rev and --remove are incompatible"))
3904 raise util.Abort(_("--rev and --remove are incompatible"))
3905 if opts.get('rev'):
3905 if opts.get('rev'):
3906 rev_ = opts['rev']
3906 rev_ = opts['rev']
3907 message = opts.get('message')
3907 message = opts.get('message')
3908 if opts.get('remove'):
3908 if opts.get('remove'):
3909 expectedtype = opts.get('local') and 'local' or 'global'
3909 expectedtype = opts.get('local') and 'local' or 'global'
3910 for n in names:
3910 for n in names:
3911 if not repo.tagtype(n):
3911 if not repo.tagtype(n):
3912 raise util.Abort(_('tag \'%s\' does not exist') % n)
3912 raise util.Abort(_('tag \'%s\' does not exist') % n)
3913 if repo.tagtype(n) != expectedtype:
3913 if repo.tagtype(n) != expectedtype:
3914 if expectedtype == 'global':
3914 if expectedtype == 'global':
3915 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3915 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3916 else:
3916 else:
3917 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3917 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3918 rev_ = nullid
3918 rev_ = nullid
3919 if not message:
3919 if not message:
3920 # we don't translate commit messages
3920 # we don't translate commit messages
3921 message = 'Removed tag %s' % ', '.join(names)
3921 message = 'Removed tag %s' % ', '.join(names)
3922 elif not opts.get('force'):
3922 elif not opts.get('force'):
3923 for n in names:
3923 for n in names:
3924 if n in repo.tags():
3924 if n in repo.tags():
3925 raise util.Abort(_('tag \'%s\' already exists '
3925 raise util.Abort(_('tag \'%s\' already exists '
3926 '(use -f to force)') % n)
3926 '(use -f to force)') % n)
3927 if not opts.get('local'):
3927 if not opts.get('local'):
3928 p1, p2 = repo.dirstate.parents()
3928 p1, p2 = repo.dirstate.parents()
3929 if p2 != nullid:
3929 if p2 != nullid:
3930 raise util.Abort(_('uncommitted merge'))
3930 raise util.Abort(_('uncommitted merge'))
3931 bheads = repo.branchheads()
3931 bheads = repo.branchheads()
3932 if not opts.get('force') and bheads and p1 not in bheads:
3932 if not opts.get('force') and bheads and p1 not in bheads:
3933 raise util.Abort(_('not at a branch head (use -f to force)'))
3933 raise util.Abort(_('not at a branch head (use -f to force)'))
3934 r = cmdutil.revsingle(repo, rev_).node()
3934 r = cmdutil.revsingle(repo, rev_).node()
3935
3935
3936 if not message:
3936 if not message:
3937 # we don't translate commit messages
3937 # we don't translate commit messages
3938 message = ('Added tag %s for changeset %s' %
3938 message = ('Added tag %s for changeset %s' %
3939 (', '.join(names), short(r)))
3939 (', '.join(names), short(r)))
3940
3940
3941 date = opts.get('date')
3941 date = opts.get('date')
3942 if date:
3942 if date:
3943 date = util.parsedate(date)
3943 date = util.parsedate(date)
3944
3944
3945 if opts.get('edit'):
3945 if opts.get('edit'):
3946 message = ui.edit(message, ui.username())
3946 message = ui.edit(message, ui.username())
3947
3947
3948 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3948 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3949
3949
3950 def tags(ui, repo):
3950 def tags(ui, repo):
3951 """list repository tags
3951 """list repository tags
3952
3952
3953 This lists both regular and local tags. When the -v/--verbose
3953 This lists both regular and local tags. When the -v/--verbose
3954 switch is used, a third column "local" is printed for local tags.
3954 switch is used, a third column "local" is printed for local tags.
3955
3955
3956 Returns 0 on success.
3956 Returns 0 on success.
3957 """
3957 """
3958
3958
3959 hexfunc = ui.debugflag and hex or short
3959 hexfunc = ui.debugflag and hex or short
3960 tagtype = ""
3960 tagtype = ""
3961
3961
3962 for t, n in reversed(repo.tagslist()):
3962 for t, n in reversed(repo.tagslist()):
3963 if ui.quiet:
3963 if ui.quiet:
3964 ui.write("%s\n" % t)
3964 ui.write("%s\n" % t)
3965 continue
3965 continue
3966
3966
3967 try:
3967 try:
3968 hn = hexfunc(n)
3968 hn = hexfunc(n)
3969 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3969 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3970 except error.LookupError:
3970 except error.LookupError:
3971 r = " ?:%s" % hn
3971 r = " ?:%s" % hn
3972 else:
3972 else:
3973 spaces = " " * (30 - encoding.colwidth(t))
3973 spaces = " " * (30 - encoding.colwidth(t))
3974 if ui.verbose:
3974 if ui.verbose:
3975 if repo.tagtype(t) == 'local':
3975 if repo.tagtype(t) == 'local':
3976 tagtype = " local"
3976 tagtype = " local"
3977 else:
3977 else:
3978 tagtype = ""
3978 tagtype = ""
3979 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3979 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3980
3980
3981 def tip(ui, repo, **opts):
3981 def tip(ui, repo, **opts):
3982 """show the tip revision
3982 """show the tip revision
3983
3983
3984 The tip revision (usually just called the tip) is the changeset
3984 The tip revision (usually just called the tip) is the changeset
3985 most recently added to the repository (and therefore the most
3985 most recently added to the repository (and therefore the most
3986 recently changed head).
3986 recently changed head).
3987
3987
3988 If you have just made a commit, that commit will be the tip. If
3988 If you have just made a commit, that commit will be the tip. If
3989 you have just pulled changes from another repository, the tip of
3989 you have just pulled changes from another repository, the tip of
3990 that repository becomes the current tip. The "tip" tag is special
3990 that repository becomes the current tip. The "tip" tag is special
3991 and cannot be renamed or assigned to a different changeset.
3991 and cannot be renamed or assigned to a different changeset.
3992
3992
3993 Returns 0 on success.
3993 Returns 0 on success.
3994 """
3994 """
3995 displayer = cmdutil.show_changeset(ui, repo, opts)
3995 displayer = cmdutil.show_changeset(ui, repo, opts)
3996 displayer.show(repo[len(repo) - 1])
3996 displayer.show(repo[len(repo) - 1])
3997 displayer.close()
3997 displayer.close()
3998
3998
3999 def unbundle(ui, repo, fname1, *fnames, **opts):
3999 def unbundle(ui, repo, fname1, *fnames, **opts):
4000 """apply one or more changegroup files
4000 """apply one or more changegroup files
4001
4001
4002 Apply one or more compressed changegroup files generated by the
4002 Apply one or more compressed changegroup files generated by the
4003 bundle command.
4003 bundle command.
4004
4004
4005 Returns 0 on success, 1 if an update has unresolved files.
4005 Returns 0 on success, 1 if an update has unresolved files.
4006 """
4006 """
4007 fnames = (fname1,) + fnames
4007 fnames = (fname1,) + fnames
4008
4008
4009 lock = repo.lock()
4009 lock = repo.lock()
4010 try:
4010 try:
4011 for fname in fnames:
4011 for fname in fnames:
4012 f = url.open(ui, fname)
4012 f = url.open(ui, fname)
4013 gen = changegroup.readbundle(f, fname)
4013 gen = changegroup.readbundle(f, fname)
4014 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4014 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4015 lock=lock)
4015 lock=lock)
4016 finally:
4016 finally:
4017 lock.release()
4017 lock.release()
4018
4018
4019 return postincoming(ui, repo, modheads, opts.get('update'), None)
4019 return postincoming(ui, repo, modheads, opts.get('update'), None)
4020
4020
4021 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4021 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4022 """update working directory (or switch revisions)
4022 """update working directory (or switch revisions)
4023
4023
4024 Update the repository's working directory to the specified
4024 Update the repository's working directory to the specified
4025 changeset. If no changeset is specified, update to the tip of the
4025 changeset. If no changeset is specified, update to the tip of the
4026 current named branch.
4026 current named branch.
4027
4027
4028 If the changeset is not a descendant of the working directory's
4028 If the changeset is not a descendant of the working directory's
4029 parent, the update is aborted. With the -c/--check option, the
4029 parent, the update is aborted. With the -c/--check option, the
4030 working directory is checked for uncommitted changes; if none are
4030 working directory is checked for uncommitted changes; if none are
4031 found, the working directory is updated to the specified
4031 found, the working directory is updated to the specified
4032 changeset.
4032 changeset.
4033
4033
4034 The following rules apply when the working directory contains
4034 The following rules apply when the working directory contains
4035 uncommitted changes:
4035 uncommitted changes:
4036
4036
4037 1. If neither -c/--check nor -C/--clean is specified, and if
4037 1. If neither -c/--check nor -C/--clean is specified, and if
4038 the requested changeset is an ancestor or descendant of
4038 the requested changeset is an ancestor or descendant of
4039 the working directory's parent, the uncommitted changes
4039 the working directory's parent, the uncommitted changes
4040 are merged into the requested changeset and the merged
4040 are merged into the requested changeset and the merged
4041 result is left uncommitted. If the requested changeset is
4041 result is left uncommitted. If the requested changeset is
4042 not an ancestor or descendant (that is, it is on another
4042 not an ancestor or descendant (that is, it is on another
4043 branch), the update is aborted and the uncommitted changes
4043 branch), the update is aborted and the uncommitted changes
4044 are preserved.
4044 are preserved.
4045
4045
4046 2. With the -c/--check option, the update is aborted and the
4046 2. With the -c/--check option, the update is aborted and the
4047 uncommitted changes are preserved.
4047 uncommitted changes are preserved.
4048
4048
4049 3. With the -C/--clean option, uncommitted changes are discarded and
4049 3. With the -C/--clean option, uncommitted changes are discarded and
4050 the working directory is updated to the requested changeset.
4050 the working directory is updated to the requested changeset.
4051
4051
4052 Use null as the changeset to remove the working directory (like
4052 Use null as the changeset to remove the working directory (like
4053 :hg:`clone -U`).
4053 :hg:`clone -U`).
4054
4054
4055 If you want to update just one file to an older changeset, use
4055 If you want to update just one file to an older changeset, use
4056 :hg:`revert`.
4056 :hg:`revert`.
4057
4057
4058 See :hg:`help dates` for a list of formats valid for -d/--date.
4058 See :hg:`help dates` for a list of formats valid for -d/--date.
4059
4059
4060 Returns 0 on success, 1 if there are unresolved files.
4060 Returns 0 on success, 1 if there are unresolved files.
4061 """
4061 """
4062 if rev and node:
4062 if rev and node:
4063 raise util.Abort(_("please specify just one revision"))
4063 raise util.Abort(_("please specify just one revision"))
4064
4064
4065 if not rev:
4065 if not rev:
4066 rev = node
4066 rev = node
4067
4067
4068 # if we defined a bookmark, we have to remember the original bookmark name
4068 # if we defined a bookmark, we have to remember the original bookmark name
4069 brev = rev
4069 brev = rev
4070 rev = cmdutil.revsingle(repo, rev, rev).rev()
4070 rev = cmdutil.revsingle(repo, rev, rev).rev()
4071
4071
4072 if check and clean:
4072 if check and clean:
4073 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4073 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4074
4074
4075 if check:
4075 if check:
4076 # we could use dirty() but we can ignore merge and branch trivia
4076 # we could use dirty() but we can ignore merge and branch trivia
4077 c = repo[None]
4077 c = repo[None]
4078 if c.modified() or c.added() or c.removed():
4078 if c.modified() or c.added() or c.removed():
4079 raise util.Abort(_("uncommitted local changes"))
4079 raise util.Abort(_("uncommitted local changes"))
4080
4080
4081 if date:
4081 if date:
4082 if rev:
4082 if rev:
4083 raise util.Abort(_("you can't specify a revision and a date"))
4083 raise util.Abort(_("you can't specify a revision and a date"))
4084 rev = cmdutil.finddate(ui, repo, date)
4084 rev = cmdutil.finddate(ui, repo, date)
4085
4085
4086 if clean or check:
4086 if clean or check:
4087 ret = hg.clean(repo, rev)
4087 ret = hg.clean(repo, rev)
4088 else:
4088 else:
4089 ret = hg.update(repo, rev)
4089 ret = hg.update(repo, rev)
4090
4090
4091 if brev in repo._bookmarks:
4091 if brev in repo._bookmarks:
4092 bookmarks.setcurrent(repo, brev)
4092 bookmarks.setcurrent(repo, brev)
4093
4093
4094 return ret
4094 return ret
4095
4095
4096 def verify(ui, repo):
4096 def verify(ui, repo):
4097 """verify the integrity of the repository
4097 """verify the integrity of the repository
4098
4098
4099 Verify the integrity of the current repository.
4099 Verify the integrity of the current repository.
4100
4100
4101 This will perform an extensive check of the repository's
4101 This will perform an extensive check of the repository's
4102 integrity, validating the hashes and checksums of each entry in
4102 integrity, validating the hashes and checksums of each entry in
4103 the changelog, manifest, and tracked files, as well as the
4103 the changelog, manifest, and tracked files, as well as the
4104 integrity of their crosslinks and indices.
4104 integrity of their crosslinks and indices.
4105
4105
4106 Returns 0 on success, 1 if errors are encountered.
4106 Returns 0 on success, 1 if errors are encountered.
4107 """
4107 """
4108 return hg.verify(repo)
4108 return hg.verify(repo)
4109
4109
4110 def version_(ui):
4110 def version_(ui):
4111 """output version and copyright information"""
4111 """output version and copyright information"""
4112 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4112 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4113 % util.version())
4113 % util.version())
4114 ui.status(_(
4114 ui.status(_(
4115 "(see http://mercurial.selenic.com for more information)\n"
4115 "(see http://mercurial.selenic.com for more information)\n"
4116 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4116 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4117 "This is free software; see the source for copying conditions. "
4117 "This is free software; see the source for copying conditions. "
4118 "There is NO\nwarranty; "
4118 "There is NO\nwarranty; "
4119 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4119 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4120 ))
4120 ))
4121
4121
4122 # Command options and aliases are listed here, alphabetically
4122 # Command options and aliases are listed here, alphabetically
4123
4123
4124 globalopts = [
4124 globalopts = [
4125 ('R', 'repository', '',
4125 ('R', 'repository', '',
4126 _('repository root directory or name of overlay bundle file'),
4126 _('repository root directory or name of overlay bundle file'),
4127 _('REPO')),
4127 _('REPO')),
4128 ('', 'cwd', '',
4128 ('', 'cwd', '',
4129 _('change working directory'), _('DIR')),
4129 _('change working directory'), _('DIR')),
4130 ('y', 'noninteractive', None,
4130 ('y', 'noninteractive', None,
4131 _('do not prompt, assume \'yes\' for any required answers')),
4131 _('do not prompt, assume \'yes\' for any required answers')),
4132 ('q', 'quiet', None, _('suppress output')),
4132 ('q', 'quiet', None, _('suppress output')),
4133 ('v', 'verbose', None, _('enable additional output')),
4133 ('v', 'verbose', None, _('enable additional output')),
4134 ('', 'config', [],
4134 ('', 'config', [],
4135 _('set/override config option (use \'section.name=value\')'),
4135 _('set/override config option (use \'section.name=value\')'),
4136 _('CONFIG')),
4136 _('CONFIG')),
4137 ('', 'debug', None, _('enable debugging output')),
4137 ('', 'debug', None, _('enable debugging output')),
4138 ('', 'debugger', None, _('start debugger')),
4138 ('', 'debugger', None, _('start debugger')),
4139 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4139 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4140 _('ENCODE')),
4140 _('ENCODE')),
4141 ('', 'encodingmode', encoding.encodingmode,
4141 ('', 'encodingmode', encoding.encodingmode,
4142 _('set the charset encoding mode'), _('MODE')),
4142 _('set the charset encoding mode'), _('MODE')),
4143 ('', 'traceback', None, _('always print a traceback on exception')),
4143 ('', 'traceback', None, _('always print a traceback on exception')),
4144 ('', 'time', None, _('time how long the command takes')),
4144 ('', 'time', None, _('time how long the command takes')),
4145 ('', 'profile', None, _('print command execution profile')),
4145 ('', 'profile', None, _('print command execution profile')),
4146 ('', 'version', None, _('output version information and exit')),
4146 ('', 'version', None, _('output version information and exit')),
4147 ('h', 'help', None, _('display help and exit')),
4147 ('h', 'help', None, _('display help and exit')),
4148 ]
4148 ]
4149
4149
4150 dryrunopts = [('n', 'dry-run', None,
4150 dryrunopts = [('n', 'dry-run', None,
4151 _('do not perform actions, just print output'))]
4151 _('do not perform actions, just print output'))]
4152
4152
4153 remoteopts = [
4153 remoteopts = [
4154 ('e', 'ssh', '',
4154 ('e', 'ssh', '',
4155 _('specify ssh command to use'), _('CMD')),
4155 _('specify ssh command to use'), _('CMD')),
4156 ('', 'remotecmd', '',
4156 ('', 'remotecmd', '',
4157 _('specify hg command to run on the remote side'), _('CMD')),
4157 _('specify hg command to run on the remote side'), _('CMD')),
4158 ('', 'insecure', None,
4158 ('', 'insecure', None,
4159 _('do not verify server certificate (ignoring web.cacerts config)')),
4159 _('do not verify server certificate (ignoring web.cacerts config)')),
4160 ]
4160 ]
4161
4161
4162 walkopts = [
4162 walkopts = [
4163 ('I', 'include', [],
4163 ('I', 'include', [],
4164 _('include names matching the given patterns'), _('PATTERN')),
4164 _('include names matching the given patterns'), _('PATTERN')),
4165 ('X', 'exclude', [],
4165 ('X', 'exclude', [],
4166 _('exclude names matching the given patterns'), _('PATTERN')),
4166 _('exclude names matching the given patterns'), _('PATTERN')),
4167 ]
4167 ]
4168
4168
4169 commitopts = [
4169 commitopts = [
4170 ('m', 'message', '',
4170 ('m', 'message', '',
4171 _('use text as commit message'), _('TEXT')),
4171 _('use text as commit message'), _('TEXT')),
4172 ('l', 'logfile', '',
4172 ('l', 'logfile', '',
4173 _('read commit message from file'), _('FILE')),
4173 _('read commit message from file'), _('FILE')),
4174 ]
4174 ]
4175
4175
4176 commitopts2 = [
4176 commitopts2 = [
4177 ('d', 'date', '',
4177 ('d', 'date', '',
4178 _('record the specified date as commit date'), _('DATE')),
4178 _('record the specified date as commit date'), _('DATE')),
4179 ('u', 'user', '',
4179 ('u', 'user', '',
4180 _('record the specified user as committer'), _('USER')),
4180 _('record the specified user as committer'), _('USER')),
4181 ]
4181 ]
4182
4182
4183 templateopts = [
4183 templateopts = [
4184 ('', 'style', '',
4184 ('', 'style', '',
4185 _('display using template map file'), _('STYLE')),
4185 _('display using template map file'), _('STYLE')),
4186 ('', 'template', '',
4186 ('', 'template', '',
4187 _('display with template'), _('TEMPLATE')),
4187 _('display with template'), _('TEMPLATE')),
4188 ]
4188 ]
4189
4189
4190 logopts = [
4190 logopts = [
4191 ('p', 'patch', None, _('show patch')),
4191 ('p', 'patch', None, _('show patch')),
4192 ('g', 'git', None, _('use git extended diff format')),
4192 ('g', 'git', None, _('use git extended diff format')),
4193 ('l', 'limit', '',
4193 ('l', 'limit', '',
4194 _('limit number of changes displayed'), _('NUM')),
4194 _('limit number of changes displayed'), _('NUM')),
4195 ('M', 'no-merges', None, _('do not show merges')),
4195 ('M', 'no-merges', None, _('do not show merges')),
4196 ('', 'stat', None, _('output diffstat-style summary of changes')),
4196 ('', 'stat', None, _('output diffstat-style summary of changes')),
4197 ] + templateopts
4197 ] + templateopts
4198
4198
4199 diffopts = [
4199 diffopts = [
4200 ('a', 'text', None, _('treat all files as text')),
4200 ('a', 'text', None, _('treat all files as text')),
4201 ('g', 'git', None, _('use git extended diff format')),
4201 ('g', 'git', None, _('use git extended diff format')),
4202 ('', 'nodates', None, _('omit dates from diff headers'))
4202 ('', 'nodates', None, _('omit dates from diff headers'))
4203 ]
4203 ]
4204
4204
4205 diffopts2 = [
4205 diffopts2 = [
4206 ('p', 'show-function', None, _('show which function each change is in')),
4206 ('p', 'show-function', None, _('show which function each change is in')),
4207 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4207 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4208 ('w', 'ignore-all-space', None,
4208 ('w', 'ignore-all-space', None,
4209 _('ignore white space when comparing lines')),
4209 _('ignore white space when comparing lines')),
4210 ('b', 'ignore-space-change', None,
4210 ('b', 'ignore-space-change', None,
4211 _('ignore changes in the amount of white space')),
4211 _('ignore changes in the amount of white space')),
4212 ('B', 'ignore-blank-lines', None,
4212 ('B', 'ignore-blank-lines', None,
4213 _('ignore changes whose lines are all blank')),
4213 _('ignore changes whose lines are all blank')),
4214 ('U', 'unified', '',
4214 ('U', 'unified', '',
4215 _('number of lines of context to show'), _('NUM')),
4215 _('number of lines of context to show'), _('NUM')),
4216 ('', 'stat', None, _('output diffstat-style summary of changes')),
4216 ('', 'stat', None, _('output diffstat-style summary of changes')),
4217 ]
4217 ]
4218
4218
4219 similarityopts = [
4219 similarityopts = [
4220 ('s', 'similarity', '',
4220 ('s', 'similarity', '',
4221 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4221 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4222 ]
4222 ]
4223
4223
4224 subrepoopts = [
4224 subrepoopts = [
4225 ('S', 'subrepos', None,
4225 ('S', 'subrepos', None,
4226 _('recurse into subrepositories'))
4226 _('recurse into subrepositories'))
4227 ]
4227 ]
4228
4228
4229 table = {
4229 table = {
4230 "^add": (add, walkopts + subrepoopts + dryrunopts,
4230 "^add": (add, walkopts + subrepoopts + dryrunopts,
4231 _('[OPTION]... [FILE]...')),
4231 _('[OPTION]... [FILE]...')),
4232 "addremove":
4232 "addremove":
4233 (addremove, similarityopts + walkopts + dryrunopts,
4233 (addremove, similarityopts + walkopts + dryrunopts,
4234 _('[OPTION]... [FILE]...')),
4234 _('[OPTION]... [FILE]...')),
4235 "^annotate|blame":
4235 "^annotate|blame":
4236 (annotate,
4236 (annotate,
4237 [('r', 'rev', '',
4237 [('r', 'rev', '',
4238 _('annotate the specified revision'), _('REV')),
4238 _('annotate the specified revision'), _('REV')),
4239 ('', 'follow', None,
4239 ('', 'follow', None,
4240 _('follow copies/renames and list the filename (DEPRECATED)')),
4240 _('follow copies/renames and list the filename (DEPRECATED)')),
4241 ('', 'no-follow', None, _("don't follow copies and renames")),
4241 ('', 'no-follow', None, _("don't follow copies and renames")),
4242 ('a', 'text', None, _('treat all files as text')),
4242 ('a', 'text', None, _('treat all files as text')),
4243 ('u', 'user', None, _('list the author (long with -v)')),
4243 ('u', 'user', None, _('list the author (long with -v)')),
4244 ('f', 'file', None, _('list the filename')),
4244 ('f', 'file', None, _('list the filename')),
4245 ('d', 'date', None, _('list the date (short with -q)')),
4245 ('d', 'date', None, _('list the date (short with -q)')),
4246 ('n', 'number', None, _('list the revision number (default)')),
4246 ('n', 'number', None, _('list the revision number (default)')),
4247 ('c', 'changeset', None, _('list the changeset')),
4247 ('c', 'changeset', None, _('list the changeset')),
4248 ('l', 'line-number', None,
4248 ('l', 'line-number', None,
4249 _('show line number at the first appearance'))
4249 _('show line number at the first appearance'))
4250 ] + walkopts,
4250 ] + walkopts,
4251 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4251 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4252 "archive":
4252 "archive":
4253 (archive,
4253 (archive,
4254 [('', 'no-decode', None, _('do not pass files through decoders')),
4254 [('', 'no-decode', None, _('do not pass files through decoders')),
4255 ('p', 'prefix', '',
4255 ('p', 'prefix', '',
4256 _('directory prefix for files in archive'), _('PREFIX')),
4256 _('directory prefix for files in archive'), _('PREFIX')),
4257 ('r', 'rev', '',
4257 ('r', 'rev', '',
4258 _('revision to distribute'), _('REV')),
4258 _('revision to distribute'), _('REV')),
4259 ('t', 'type', '',
4259 ('t', 'type', '',
4260 _('type of distribution to create'), _('TYPE')),
4260 _('type of distribution to create'), _('TYPE')),
4261 ] + subrepoopts + walkopts,
4261 ] + subrepoopts + walkopts,
4262 _('[OPTION]... DEST')),
4262 _('[OPTION]... DEST')),
4263 "backout":
4263 "backout":
4264 (backout,
4264 (backout,
4265 [('', 'merge', None,
4265 [('', 'merge', None,
4266 _('merge with old dirstate parent after backout')),
4266 _('merge with old dirstate parent after backout')),
4267 ('', 'parent', '',
4267 ('', 'parent', '',
4268 _('parent to choose when backing out merge'), _('REV')),
4268 _('parent to choose when backing out merge'), _('REV')),
4269 ('t', 'tool', '',
4269 ('t', 'tool', '',
4270 _('specify merge tool')),
4270 _('specify merge tool')),
4271 ('r', 'rev', '',
4271 ('r', 'rev', '',
4272 _('revision to backout'), _('REV')),
4272 _('revision to backout'), _('REV')),
4273 ] + walkopts + commitopts + commitopts2,
4273 ] + walkopts + commitopts + commitopts2,
4274 _('[OPTION]... [-r] REV')),
4274 _('[OPTION]... [-r] REV')),
4275 "bisect":
4275 "bisect":
4276 (bisect,
4276 (bisect,
4277 [('r', 'reset', False, _('reset bisect state')),
4277 [('r', 'reset', False, _('reset bisect state')),
4278 ('g', 'good', False, _('mark changeset good')),
4278 ('g', 'good', False, _('mark changeset good')),
4279 ('b', 'bad', False, _('mark changeset bad')),
4279 ('b', 'bad', False, _('mark changeset bad')),
4280 ('s', 'skip', False, _('skip testing changeset')),
4280 ('s', 'skip', False, _('skip testing changeset')),
4281 ('c', 'command', '',
4281 ('c', 'command', '',
4282 _('use command to check changeset state'), _('CMD')),
4282 _('use command to check changeset state'), _('CMD')),
4283 ('U', 'noupdate', False, _('do not update to target'))],
4283 ('U', 'noupdate', False, _('do not update to target'))],
4284 _("[-gbsr] [-U] [-c CMD] [REV]")),
4284 _("[-gbsr] [-U] [-c CMD] [REV]")),
4285 "bookmarks":
4285 "bookmarks":
4286 (bookmark,
4286 (bookmark,
4287 [('f', 'force', False, _('force')),
4287 [('f', 'force', False, _('force')),
4288 ('r', 'rev', '', _('revision'), _('REV')),
4288 ('r', 'rev', '', _('revision'), _('REV')),
4289 ('d', 'delete', False, _('delete a given bookmark')),
4289 ('d', 'delete', False, _('delete a given bookmark')),
4290 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
4290 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
4291 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
4291 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
4292 "branch":
4292 "branch":
4293 (branch,
4293 (branch,
4294 [('f', 'force', None,
4294 [('f', 'force', None,
4295 _('set branch name even if it shadows an existing branch')),
4295 _('set branch name even if it shadows an existing branch')),
4296 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4296 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4297 _('[-fC] [NAME]')),
4297 _('[-fC] [NAME]')),
4298 "branches":
4298 "branches":
4299 (branches,
4299 (branches,
4300 [('a', 'active', False,
4300 [('a', 'active', False,
4301 _('show only branches that have unmerged heads')),
4301 _('show only branches that have unmerged heads')),
4302 ('c', 'closed', False,
4302 ('c', 'closed', False,
4303 _('show normal and closed branches'))],
4303 _('show normal and closed branches'))],
4304 _('[-ac]')),
4304 _('[-ac]')),
4305 "bundle":
4305 "bundle":
4306 (bundle,
4306 (bundle,
4307 [('f', 'force', None,
4307 [('f', 'force', None,
4308 _('run even when the destination is unrelated')),
4308 _('run even when the destination is unrelated')),
4309 ('r', 'rev', [],
4309 ('r', 'rev', [],
4310 _('a changeset intended to be added to the destination'),
4310 _('a changeset intended to be added to the destination'),
4311 _('REV')),
4311 _('REV')),
4312 ('b', 'branch', [],
4312 ('b', 'branch', [],
4313 _('a specific branch you would like to bundle'),
4313 _('a specific branch you would like to bundle'),
4314 _('BRANCH')),
4314 _('BRANCH')),
4315 ('', 'base', [],
4315 ('', 'base', [],
4316 _('a base changeset assumed to be available at the destination'),
4316 _('a base changeset assumed to be available at the destination'),
4317 _('REV')),
4317 _('REV')),
4318 ('a', 'all', None, _('bundle all changesets in the repository')),
4318 ('a', 'all', None, _('bundle all changesets in the repository')),
4319 ('t', 'type', 'bzip2',
4319 ('t', 'type', 'bzip2',
4320 _('bundle compression type to use'), _('TYPE')),
4320 _('bundle compression type to use'), _('TYPE')),
4321 ] + remoteopts,
4321 ] + remoteopts,
4322 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4322 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4323 "cat":
4323 "cat":
4324 (cat,
4324 (cat,
4325 [('o', 'output', '',
4325 [('o', 'output', '',
4326 _('print output to file with formatted name'), _('FORMAT')),
4326 _('print output to file with formatted name'), _('FORMAT')),
4327 ('r', 'rev', '',
4327 ('r', 'rev', '',
4328 _('print the given revision'), _('REV')),
4328 _('print the given revision'), _('REV')),
4329 ('', 'decode', None, _('apply any matching decode filter')),
4329 ('', 'decode', None, _('apply any matching decode filter')),
4330 ] + walkopts,
4330 ] + walkopts,
4331 _('[OPTION]... FILE...')),
4331 _('[OPTION]... FILE...')),
4332 "^clone":
4332 "^clone":
4333 (clone,
4333 (clone,
4334 [('U', 'noupdate', None,
4334 [('U', 'noupdate', None,
4335 _('the clone will include an empty working copy (only a repository)')),
4335 _('the clone will include an empty working copy (only a repository)')),
4336 ('u', 'updaterev', '',
4336 ('u', 'updaterev', '',
4337 _('revision, tag or branch to check out'), _('REV')),
4337 _('revision, tag or branch to check out'), _('REV')),
4338 ('r', 'rev', [],
4338 ('r', 'rev', [],
4339 _('include the specified changeset'), _('REV')),
4339 _('include the specified changeset'), _('REV')),
4340 ('b', 'branch', [],
4340 ('b', 'branch', [],
4341 _('clone only the specified branch'), _('BRANCH')),
4341 _('clone only the specified branch'), _('BRANCH')),
4342 ('', 'pull', None, _('use pull protocol to copy metadata')),
4342 ('', 'pull', None, _('use pull protocol to copy metadata')),
4343 ('', 'uncompressed', None,
4343 ('', 'uncompressed', None,
4344 _('use uncompressed transfer (fast over LAN)')),
4344 _('use uncompressed transfer (fast over LAN)')),
4345 ] + remoteopts,
4345 ] + remoteopts,
4346 _('[OPTION]... SOURCE [DEST]')),
4346 _('[OPTION]... SOURCE [DEST]')),
4347 "^commit|ci":
4347 "^commit|ci":
4348 (commit,
4348 (commit,
4349 [('A', 'addremove', None,
4349 [('A', 'addremove', None,
4350 _('mark new/missing files as added/removed before committing')),
4350 _('mark new/missing files as added/removed before committing')),
4351 ('', 'close-branch', None,
4351 ('', 'close-branch', None,
4352 _('mark a branch as closed, hiding it from the branch list')),
4352 _('mark a branch as closed, hiding it from the branch list')),
4353 ] + walkopts + commitopts + commitopts2,
4353 ] + walkopts + commitopts + commitopts2,
4354 _('[OPTION]... [FILE]...')),
4354 _('[OPTION]... [FILE]...')),
4355 "copy|cp":
4355 "copy|cp":
4356 (copy,
4356 (copy,
4357 [('A', 'after', None, _('record a copy that has already occurred')),
4357 [('A', 'after', None, _('record a copy that has already occurred')),
4358 ('f', 'force', None,
4358 ('f', 'force', None,
4359 _('forcibly copy over an existing managed file')),
4359 _('forcibly copy over an existing managed file')),
4360 ] + walkopts + dryrunopts,
4360 ] + walkopts + dryrunopts,
4361 _('[OPTION]... [SOURCE]... DEST')),
4361 _('[OPTION]... [SOURCE]... DEST')),
4362 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4362 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4363 "debugbuilddag":
4363 "debugbuilddag":
4364 (debugbuilddag,
4364 (debugbuilddag,
4365 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4365 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4366 ('a', 'appended-file', None, _('add single file all revs append to')),
4366 ('a', 'appended-file', None, _('add single file all revs append to')),
4367 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4367 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4368 ('n', 'new-file', None, _('add new file at each rev')),
4368 ('n', 'new-file', None, _('add new file at each rev')),
4369 ],
4369 ],
4370 _('[OPTION]... TEXT')),
4370 _('[OPTION]... TEXT')),
4371 "debugcheckstate": (debugcheckstate, [], ''),
4371 "debugcheckstate": (debugcheckstate, [], ''),
4372 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4372 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4373 "debugcomplete":
4373 "debugcomplete":
4374 (debugcomplete,
4374 (debugcomplete,
4375 [('o', 'options', None, _('show the command options'))],
4375 [('o', 'options', None, _('show the command options'))],
4376 _('[-o] CMD')),
4376 _('[-o] CMD')),
4377 "debugdag":
4377 "debugdag":
4378 (debugdag,
4378 (debugdag,
4379 [('t', 'tags', None, _('use tags as labels')),
4379 [('t', 'tags', None, _('use tags as labels')),
4380 ('b', 'branches', None, _('annotate with branch names')),
4380 ('b', 'branches', None, _('annotate with branch names')),
4381 ('', 'dots', None, _('use dots for runs')),
4381 ('', 'dots', None, _('use dots for runs')),
4382 ('s', 'spaces', None, _('separate elements by spaces')),
4382 ('s', 'spaces', None, _('separate elements by spaces')),
4383 ],
4383 ],
4384 _('[OPTION]... [FILE [REV]...]')),
4384 _('[OPTION]... [FILE [REV]...]')),
4385 "debugdate":
4385 "debugdate":
4386 (debugdate,
4386 (debugdate,
4387 [('e', 'extended', None, _('try extended date formats'))],
4387 [('e', 'extended', None, _('try extended date formats'))],
4388 _('[-e] DATE [RANGE]')),
4388 _('[-e] DATE [RANGE]')),
4389 "debugdata": (debugdata, [], _('FILE REV')),
4389 "debugdata": (debugdata, [], _('FILE REV')),
4390 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4390 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4391 "debugignore": (debugignore, [], ''),
4391 "debugignore": (debugignore, [], ''),
4392 "debugindex": (debugindex,
4392 "debugindex": (debugindex,
4393 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4393 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4394 _('FILE')),
4394 _('FILE')),
4395 "debugindexdot": (debugindexdot, [], _('FILE')),
4395 "debugindexdot": (debugindexdot, [], _('FILE')),
4396 "debuginstall": (debuginstall, [], ''),
4396 "debuginstall": (debuginstall, [], ''),
4397 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4397 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4398 "debugrebuildstate":
4398 "debugrebuildstate":
4399 (debugrebuildstate,
4399 (debugrebuildstate,
4400 [('r', 'rev', '',
4400 [('r', 'rev', '',
4401 _('revision to rebuild to'), _('REV'))],
4401 _('revision to rebuild to'), _('REV'))],
4402 _('[-r REV] [REV]')),
4402 _('[-r REV] [REV]')),
4403 "debugrename":
4403 "debugrename":
4404 (debugrename,
4404 (debugrename,
4405 [('r', 'rev', '',
4405 [('r', 'rev', '',
4406 _('revision to debug'), _('REV'))],
4406 _('revision to debug'), _('REV'))],
4407 _('[-r REV] FILE')),
4407 _('[-r REV] FILE')),
4408 "debugrevspec":
4408 "debugrevspec":
4409 (debugrevspec, [], ('REVSPEC')),
4409 (debugrevspec, [], ('REVSPEC')),
4410 "debugsetparents":
4410 "debugsetparents":
4411 (debugsetparents, [], _('REV1 [REV2]')),
4411 (debugsetparents, [], _('REV1 [REV2]')),
4412 "debugstate":
4412 "debugstate":
4413 (debugstate,
4413 (debugstate,
4414 [('', 'nodates', None, _('do not display the saved mtime'))],
4414 [('', 'nodates', None, _('do not display the saved mtime'))],
4415 _('[OPTION]...')),
4415 _('[OPTION]...')),
4416 "debugsub":
4416 "debugsub":
4417 (debugsub,
4417 (debugsub,
4418 [('r', 'rev', '',
4418 [('r', 'rev', '',
4419 _('revision to check'), _('REV'))],
4419 _('revision to check'), _('REV'))],
4420 _('[-r REV] [REV]')),
4420 _('[-r REV] [REV]')),
4421 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4421 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4422 "^diff":
4422 "^diff":
4423 (diff,
4423 (diff,
4424 [('r', 'rev', [],
4424 [('r', 'rev', [],
4425 _('revision'), _('REV')),
4425 _('revision'), _('REV')),
4426 ('c', 'change', '',
4426 ('c', 'change', '',
4427 _('change made by revision'), _('REV'))
4427 _('change made by revision'), _('REV'))
4428 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4428 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4429 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4429 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4430 "^export":
4430 "^export":
4431 (export,
4431 (export,
4432 [('o', 'output', '',
4432 [('o', 'output', '',
4433 _('print output to file with formatted name'), _('FORMAT')),
4433 _('print output to file with formatted name'), _('FORMAT')),
4434 ('', 'switch-parent', None, _('diff against the second parent')),
4434 ('', 'switch-parent', None, _('diff against the second parent')),
4435 ('r', 'rev', [],
4435 ('r', 'rev', [],
4436 _('revisions to export'), _('REV')),
4436 _('revisions to export'), _('REV')),
4437 ] + diffopts,
4437 ] + diffopts,
4438 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4438 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4439 "^forget":
4439 "^forget":
4440 (forget,
4440 (forget,
4441 [] + walkopts,
4441 [] + walkopts,
4442 _('[OPTION]... FILE...')),
4442 _('[OPTION]... FILE...')),
4443 "grep":
4443 "grep":
4444 (grep,
4444 (grep,
4445 [('0', 'print0', None, _('end fields with NUL')),
4445 [('0', 'print0', None, _('end fields with NUL')),
4446 ('', 'all', None, _('print all revisions that match')),
4446 ('', 'all', None, _('print all revisions that match')),
4447 ('f', 'follow', None,
4447 ('f', 'follow', None,
4448 _('follow changeset history,'
4448 _('follow changeset history,'
4449 ' or file history across copies and renames')),
4449 ' or file history across copies and renames')),
4450 ('i', 'ignore-case', None, _('ignore case when matching')),
4450 ('i', 'ignore-case', None, _('ignore case when matching')),
4451 ('l', 'files-with-matches', None,
4451 ('l', 'files-with-matches', None,
4452 _('print only filenames and revisions that match')),
4452 _('print only filenames and revisions that match')),
4453 ('n', 'line-number', None, _('print matching line numbers')),
4453 ('n', 'line-number', None, _('print matching line numbers')),
4454 ('r', 'rev', [],
4454 ('r', 'rev', [],
4455 _('only search files changed within revision range'), _('REV')),
4455 _('only search files changed within revision range'), _('REV')),
4456 ('u', 'user', None, _('list the author (long with -v)')),
4456 ('u', 'user', None, _('list the author (long with -v)')),
4457 ('d', 'date', None, _('list the date (short with -q)')),
4457 ('d', 'date', None, _('list the date (short with -q)')),
4458 ] + walkopts,
4458 ] + walkopts,
4459 _('[OPTION]... PATTERN [FILE]...')),
4459 _('[OPTION]... PATTERN [FILE]...')),
4460 "heads":
4460 "heads":
4461 (heads,
4461 (heads,
4462 [('r', 'rev', '',
4462 [('r', 'rev', '',
4463 _('show only heads which are descendants of STARTREV'),
4463 _('show only heads which are descendants of STARTREV'),
4464 _('STARTREV')),
4464 _('STARTREV')),
4465 ('t', 'topo', False, _('show topological heads only')),
4465 ('t', 'topo', False, _('show topological heads only')),
4466 ('a', 'active', False,
4466 ('a', 'active', False,
4467 _('show active branchheads only (DEPRECATED)')),
4467 _('show active branchheads only (DEPRECATED)')),
4468 ('c', 'closed', False,
4468 ('c', 'closed', False,
4469 _('show normal and closed branch heads')),
4469 _('show normal and closed branch heads')),
4470 ] + templateopts,
4470 ] + templateopts,
4471 _('[-ac] [-r STARTREV] [REV]...')),
4471 _('[-ac] [-r STARTREV] [REV]...')),
4472 "help": (help_, [], _('[TOPIC]')),
4472 "help": (help_, [], _('[TOPIC]')),
4473 "identify|id":
4473 "identify|id":
4474 (identify,
4474 (identify,
4475 [('r', 'rev', '',
4475 [('r', 'rev', '',
4476 _('identify the specified revision'), _('REV')),
4476 _('identify the specified revision'), _('REV')),
4477 ('n', 'num', None, _('show local revision number')),
4477 ('n', 'num', None, _('show local revision number')),
4478 ('i', 'id', None, _('show global revision id')),
4478 ('i', 'id', None, _('show global revision id')),
4479 ('b', 'branch', None, _('show branch')),
4479 ('b', 'branch', None, _('show branch')),
4480 ('t', 'tags', None, _('show tags')),
4480 ('t', 'tags', None, _('show tags')),
4481 ('B', 'bookmarks', None, _('show bookmarks'))],
4481 ('B', 'bookmarks', None, _('show bookmarks'))],
4482 _('[-nibtB] [-r REV] [SOURCE]')),
4482 _('[-nibtB] [-r REV] [SOURCE]')),
4483 "import|patch":
4483 "import|patch":
4484 (import_,
4484 (import_,
4485 [('p', 'strip', 1,
4485 [('p', 'strip', 1,
4486 _('directory strip option for patch. This has the same '
4486 _('directory strip option for patch. This has the same '
4487 'meaning as the corresponding patch option'),
4487 'meaning as the corresponding patch option'),
4488 _('NUM')),
4488 _('NUM')),
4489 ('b', 'base', '',
4489 ('b', 'base', '',
4490 _('base path'), _('PATH')),
4490 _('base path'), _('PATH')),
4491 ('f', 'force', None,
4491 ('f', 'force', None,
4492 _('skip check for outstanding uncommitted changes')),
4492 _('skip check for outstanding uncommitted changes')),
4493 ('', 'no-commit', None,
4493 ('', 'no-commit', None,
4494 _("don't commit, just update the working directory")),
4494 _("don't commit, just update the working directory")),
4495 ('', 'exact', None,
4495 ('', 'exact', None,
4496 _('apply patch to the nodes from which it was generated')),
4496 _('apply patch to the nodes from which it was generated')),
4497 ('', 'import-branch', None,
4497 ('', 'import-branch', None,
4498 _('use any branch information in patch (implied by --exact)'))] +
4498 _('use any branch information in patch (implied by --exact)'))] +
4499 commitopts + commitopts2 + similarityopts,
4499 commitopts + commitopts2 + similarityopts,
4500 _('[OPTION]... PATCH...')),
4500 _('[OPTION]... PATCH...')),
4501 "incoming|in":
4501 "incoming|in":
4502 (incoming,
4502 (incoming,
4503 [('f', 'force', None,
4503 [('f', 'force', None,
4504 _('run even if remote repository is unrelated')),
4504 _('run even if remote repository is unrelated')),
4505 ('n', 'newest-first', None, _('show newest record first')),
4505 ('n', 'newest-first', None, _('show newest record first')),
4506 ('', 'bundle', '',
4506 ('', 'bundle', '',
4507 _('file to store the bundles into'), _('FILE')),
4507 _('file to store the bundles into'), _('FILE')),
4508 ('r', 'rev', [],
4508 ('r', 'rev', [],
4509 _('a remote changeset intended to be added'), _('REV')),
4509 _('a remote changeset intended to be added'), _('REV')),
4510 ('B', 'bookmarks', False, _("compare bookmarks")),
4510 ('B', 'bookmarks', False, _("compare bookmarks")),
4511 ('b', 'branch', [],
4511 ('b', 'branch', [],
4512 _('a specific branch you would like to pull'), _('BRANCH')),
4512 _('a specific branch you would like to pull'), _('BRANCH')),
4513 ] + logopts + remoteopts + subrepoopts,
4513 ] + logopts + remoteopts + subrepoopts,
4514 _('[-p] [-n] [-M] [-f] [-r REV]...'
4514 _('[-p] [-n] [-M] [-f] [-r REV]...'
4515 ' [--bundle FILENAME] [SOURCE]')),
4515 ' [--bundle FILENAME] [SOURCE]')),
4516 "^init":
4516 "^init":
4517 (init,
4517 (init,
4518 remoteopts,
4518 remoteopts,
4519 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4519 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4520 "locate":
4520 "locate":
4521 (locate,
4521 (locate,
4522 [('r', 'rev', '',
4522 [('r', 'rev', '',
4523 _('search the repository as it is in REV'), _('REV')),
4523 _('search the repository as it is in REV'), _('REV')),
4524 ('0', 'print0', None,
4524 ('0', 'print0', None,
4525 _('end filenames with NUL, for use with xargs')),
4525 _('end filenames with NUL, for use with xargs')),
4526 ('f', 'fullpath', None,
4526 ('f', 'fullpath', None,
4527 _('print complete paths from the filesystem root')),
4527 _('print complete paths from the filesystem root')),
4528 ] + walkopts,
4528 ] + walkopts,
4529 _('[OPTION]... [PATTERN]...')),
4529 _('[OPTION]... [PATTERN]...')),
4530 "^log|history":
4530 "^log|history":
4531 (log,
4531 (log,
4532 [('f', 'follow', None,
4532 [('f', 'follow', None,
4533 _('follow changeset history,'
4533 _('follow changeset history,'
4534 ' or file history across copies and renames')),
4534 ' or file history across copies and renames')),
4535 ('', 'follow-first', None,
4535 ('', 'follow-first', None,
4536 _('only follow the first parent of merge changesets')),
4536 _('only follow the first parent of merge changesets')),
4537 ('d', 'date', '',
4537 ('d', 'date', '',
4538 _('show revisions matching date spec'), _('DATE')),
4538 _('show revisions matching date spec'), _('DATE')),
4539 ('C', 'copies', None, _('show copied files')),
4539 ('C', 'copies', None, _('show copied files')),
4540 ('k', 'keyword', [],
4540 ('k', 'keyword', [],
4541 _('do case-insensitive search for a given text'), _('TEXT')),
4541 _('do case-insensitive search for a given text'), _('TEXT')),
4542 ('r', 'rev', [],
4542 ('r', 'rev', [],
4543 _('show the specified revision or range'), _('REV')),
4543 _('show the specified revision or range'), _('REV')),
4544 ('', 'removed', None, _('include revisions where files were removed')),
4544 ('', 'removed', None, _('include revisions where files were removed')),
4545 ('m', 'only-merges', None, _('show only merges')),
4545 ('m', 'only-merges', None, _('show only merges')),
4546 ('u', 'user', [],
4546 ('u', 'user', [],
4547 _('revisions committed by user'), _('USER')),
4547 _('revisions committed by user'), _('USER')),
4548 ('', 'only-branch', [],
4548 ('', 'only-branch', [],
4549 _('show only changesets within the given named branch (DEPRECATED)'),
4549 _('show only changesets within the given named branch (DEPRECATED)'),
4550 _('BRANCH')),
4550 _('BRANCH')),
4551 ('b', 'branch', [],
4551 ('b', 'branch', [],
4552 _('show changesets within the given named branch'), _('BRANCH')),
4552 _('show changesets within the given named branch'), _('BRANCH')),
4553 ('P', 'prune', [],
4553 ('P', 'prune', [],
4554 _('do not display revision or any of its ancestors'), _('REV')),
4554 _('do not display revision or any of its ancestors'), _('REV')),
4555 ] + logopts + walkopts,
4555 ] + logopts + walkopts,
4556 _('[OPTION]... [FILE]')),
4556 _('[OPTION]... [FILE]')),
4557 "manifest":
4557 "manifest":
4558 (manifest,
4558 (manifest,
4559 [('r', 'rev', '',
4559 [('r', 'rev', '',
4560 _('revision to display'), _('REV'))],
4560 _('revision to display'), _('REV'))],
4561 _('[-r REV]')),
4561 _('[-r REV]')),
4562 "^merge":
4562 "^merge":
4563 (merge,
4563 (merge,
4564 [('f', 'force', None, _('force a merge with outstanding changes')),
4564 [('f', 'force', None, _('force a merge with outstanding changes')),
4565 ('t', 'tool', '', _('specify merge tool')),
4565 ('t', 'tool', '', _('specify merge tool')),
4566 ('r', 'rev', '',
4566 ('r', 'rev', '',
4567 _('revision to merge'), _('REV')),
4567 _('revision to merge'), _('REV')),
4568 ('P', 'preview', None,
4568 ('P', 'preview', None,
4569 _('review revisions to merge (no merge is performed)'))],
4569 _('review revisions to merge (no merge is performed)'))],
4570 _('[-P] [-f] [[-r] REV]')),
4570 _('[-P] [-f] [[-r] REV]')),
4571 "outgoing|out":
4571 "outgoing|out":
4572 (outgoing,
4572 (outgoing,
4573 [('f', 'force', None,
4573 [('f', 'force', None,
4574 _('run even when the destination is unrelated')),
4574 _('run even when the destination is unrelated')),
4575 ('r', 'rev', [],
4575 ('r', 'rev', [],
4576 _('a changeset intended to be included in the destination'),
4576 _('a changeset intended to be included in the destination'),
4577 _('REV')),
4577 _('REV')),
4578 ('n', 'newest-first', None, _('show newest record first')),
4578 ('n', 'newest-first', None, _('show newest record first')),
4579 ('B', 'bookmarks', False, _("compare bookmarks")),
4579 ('B', 'bookmarks', False, _("compare bookmarks")),
4580 ('b', 'branch', [],
4580 ('b', 'branch', [],
4581 _('a specific branch you would like to push'), _('BRANCH')),
4581 _('a specific branch you would like to push'), _('BRANCH')),
4582 ] + logopts + remoteopts + subrepoopts,
4582 ] + logopts + remoteopts + subrepoopts,
4583 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4583 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4584 "parents":
4584 "parents":
4585 (parents,
4585 (parents,
4586 [('r', 'rev', '',
4586 [('r', 'rev', '',
4587 _('show parents of the specified revision'), _('REV')),
4587 _('show parents of the specified revision'), _('REV')),
4588 ] + templateopts,
4588 ] + templateopts,
4589 _('[-r REV] [FILE]')),
4589 _('[-r REV] [FILE]')),
4590 "paths": (paths, [], _('[NAME]')),
4590 "paths": (paths, [], _('[NAME]')),
4591 "^pull":
4591 "^pull":
4592 (pull,
4592 (pull,
4593 [('u', 'update', None,
4593 [('u', 'update', None,
4594 _('update to new branch head if changesets were pulled')),
4594 _('update to new branch head if changesets were pulled')),
4595 ('f', 'force', None,
4595 ('f', 'force', None,
4596 _('run even when remote repository is unrelated')),
4596 _('run even when remote repository is unrelated')),
4597 ('r', 'rev', [],
4597 ('r', 'rev', [],
4598 _('a remote changeset intended to be added'), _('REV')),
4598 _('a remote changeset intended to be added'), _('REV')),
4599 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4599 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4600 ('b', 'branch', [],
4600 ('b', 'branch', [],
4601 _('a specific branch you would like to pull'), _('BRANCH')),
4601 _('a specific branch you would like to pull'), _('BRANCH')),
4602 ] + remoteopts,
4602 ] + remoteopts,
4603 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4603 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4604 "^push":
4604 "^push":
4605 (push,
4605 (push,
4606 [('f', 'force', None, _('force push')),
4606 [('f', 'force', None, _('force push')),
4607 ('r', 'rev', [],
4607 ('r', 'rev', [],
4608 _('a changeset intended to be included in the destination'),
4608 _('a changeset intended to be included in the destination'),
4609 _('REV')),
4609 _('REV')),
4610 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4610 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4611 ('b', 'branch', [],
4611 ('b', 'branch', [],
4612 _('a specific branch you would like to push'), _('BRANCH')),
4612 _('a specific branch you would like to push'), _('BRANCH')),
4613 ('', 'new-branch', False, _('allow pushing a new branch')),
4613 ('', 'new-branch', False, _('allow pushing a new branch')),
4614 ] + remoteopts,
4614 ] + remoteopts,
4615 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4615 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4616 "recover": (recover, []),
4616 "recover": (recover, []),
4617 "^remove|rm":
4617 "^remove|rm":
4618 (remove,
4618 (remove,
4619 [('A', 'after', None, _('record delete for missing files')),
4619 [('A', 'after', None, _('record delete for missing files')),
4620 ('f', 'force', None,
4620 ('f', 'force', None,
4621 _('remove (and delete) file even if added or modified')),
4621 _('remove (and delete) file even if added or modified')),
4622 ] + walkopts,
4622 ] + walkopts,
4623 _('[OPTION]... FILE...')),
4623 _('[OPTION]... FILE...')),
4624 "rename|move|mv":
4624 "rename|move|mv":
4625 (rename,
4625 (rename,
4626 [('A', 'after', None, _('record a rename that has already occurred')),
4626 [('A', 'after', None, _('record a rename that has already occurred')),
4627 ('f', 'force', None,
4627 ('f', 'force', None,
4628 _('forcibly copy over an existing managed file')),
4628 _('forcibly copy over an existing managed file')),
4629 ] + walkopts + dryrunopts,
4629 ] + walkopts + dryrunopts,
4630 _('[OPTION]... SOURCE... DEST')),
4630 _('[OPTION]... SOURCE... DEST')),
4631 "resolve":
4631 "resolve":
4632 (resolve,
4632 (resolve,
4633 [('a', 'all', None, _('select all unresolved files')),
4633 [('a', 'all', None, _('select all unresolved files')),
4634 ('l', 'list', None, _('list state of files needing merge')),
4634 ('l', 'list', None, _('list state of files needing merge')),
4635 ('m', 'mark', None, _('mark files as resolved')),
4635 ('m', 'mark', None, _('mark files as resolved')),
4636 ('u', 'unmark', None, _('mark files as unresolved')),
4636 ('u', 'unmark', None, _('mark files as unresolved')),
4637 ('t', 'tool', '', _('specify merge tool')),
4637 ('t', 'tool', '', _('specify merge tool')),
4638 ('n', 'no-status', None, _('hide status prefix'))]
4638 ('n', 'no-status', None, _('hide status prefix'))]
4639 + walkopts,
4639 + walkopts,
4640 _('[OPTION]... [FILE]...')),
4640 _('[OPTION]... [FILE]...')),
4641 "revert":
4641 "revert":
4642 (revert,
4642 (revert,
4643 [('a', 'all', None, _('revert all changes when no arguments given')),
4643 [('a', 'all', None, _('revert all changes when no arguments given')),
4644 ('d', 'date', '',
4644 ('d', 'date', '',
4645 _('tipmost revision matching date'), _('DATE')),
4645 _('tipmost revision matching date'), _('DATE')),
4646 ('r', 'rev', '',
4646 ('r', 'rev', '',
4647 _('revert to the specified revision'), _('REV')),
4647 _('revert to the specified revision'), _('REV')),
4648 ('', 'no-backup', None, _('do not save backup copies of files')),
4648 ('', 'no-backup', None, _('do not save backup copies of files')),
4649 ] + walkopts + dryrunopts,
4649 ] + walkopts + dryrunopts,
4650 _('[OPTION]... [-r REV] [NAME]...')),
4650 _('[OPTION]... [-r REV] [NAME]...')),
4651 "rollback": (rollback, dryrunopts),
4651 "rollback": (rollback, dryrunopts),
4652 "root": (root, []),
4652 "root": (root, []),
4653 "^serve":
4653 "^serve":
4654 (serve,
4654 (serve,
4655 [('A', 'accesslog', '',
4655 [('A', 'accesslog', '',
4656 _('name of access log file to write to'), _('FILE')),
4656 _('name of access log file to write to'), _('FILE')),
4657 ('d', 'daemon', None, _('run server in background')),
4657 ('d', 'daemon', None, _('run server in background')),
4658 ('', 'daemon-pipefds', '',
4658 ('', 'daemon-pipefds', '',
4659 _('used internally by daemon mode'), _('NUM')),
4659 _('used internally by daemon mode'), _('NUM')),
4660 ('E', 'errorlog', '',
4660 ('E', 'errorlog', '',
4661 _('name of error log file to write to'), _('FILE')),
4661 _('name of error log file to write to'), _('FILE')),
4662 # use string type, then we can check if something was passed
4662 # use string type, then we can check if something was passed
4663 ('p', 'port', '',
4663 ('p', 'port', '',
4664 _('port to listen on (default: 8000)'), _('PORT')),
4664 _('port to listen on (default: 8000)'), _('PORT')),
4665 ('a', 'address', '',
4665 ('a', 'address', '',
4666 _('address to listen on (default: all interfaces)'), _('ADDR')),
4666 _('address to listen on (default: all interfaces)'), _('ADDR')),
4667 ('', 'prefix', '',
4667 ('', 'prefix', '',
4668 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4668 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4669 ('n', 'name', '',
4669 ('n', 'name', '',
4670 _('name to show in web pages (default: working directory)'),
4670 _('name to show in web pages (default: working directory)'),
4671 _('NAME')),
4671 _('NAME')),
4672 ('', 'web-conf', '',
4672 ('', 'web-conf', '',
4673 _('name of the hgweb config file (see "hg help hgweb")'),
4673 _('name of the hgweb config file (see "hg help hgweb")'),
4674 _('FILE')),
4674 _('FILE')),
4675 ('', 'webdir-conf', '',
4675 ('', 'webdir-conf', '',
4676 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4676 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4677 ('', 'pid-file', '',
4677 ('', 'pid-file', '',
4678 _('name of file to write process ID to'), _('FILE')),
4678 _('name of file to write process ID to'), _('FILE')),
4679 ('', 'stdio', None, _('for remote clients')),
4679 ('', 'stdio', None, _('for remote clients')),
4680 ('t', 'templates', '',
4680 ('t', 'templates', '',
4681 _('web templates to use'), _('TEMPLATE')),
4681 _('web templates to use'), _('TEMPLATE')),
4682 ('', 'style', '',
4682 ('', 'style', '',
4683 _('template style to use'), _('STYLE')),
4683 _('template style to use'), _('STYLE')),
4684 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4684 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4685 ('', 'certificate', '',
4685 ('', 'certificate', '',
4686 _('SSL certificate file'), _('FILE'))],
4686 _('SSL certificate file'), _('FILE'))],
4687 _('[OPTION]...')),
4687 _('[OPTION]...')),
4688 "showconfig|debugconfig":
4688 "showconfig|debugconfig":
4689 (showconfig,
4689 (showconfig,
4690 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4690 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4691 _('[-u] [NAME]...')),
4691 _('[-u] [NAME]...')),
4692 "^summary|sum":
4692 "^summary|sum":
4693 (summary,
4693 (summary,
4694 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4694 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4695 "^status|st":
4695 "^status|st":
4696 (status,
4696 (status,
4697 [('A', 'all', None, _('show status of all files')),
4697 [('A', 'all', None, _('show status of all files')),
4698 ('m', 'modified', None, _('show only modified files')),
4698 ('m', 'modified', None, _('show only modified files')),
4699 ('a', 'added', None, _('show only added files')),
4699 ('a', 'added', None, _('show only added files')),
4700 ('r', 'removed', None, _('show only removed files')),
4700 ('r', 'removed', None, _('show only removed files')),
4701 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4701 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4702 ('c', 'clean', None, _('show only files without changes')),
4702 ('c', 'clean', None, _('show only files without changes')),
4703 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4703 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4704 ('i', 'ignored', None, _('show only ignored files')),
4704 ('i', 'ignored', None, _('show only ignored files')),
4705 ('n', 'no-status', None, _('hide status prefix')),
4705 ('n', 'no-status', None, _('hide status prefix')),
4706 ('C', 'copies', None, _('show source of copied files')),
4706 ('C', 'copies', None, _('show source of copied files')),
4707 ('0', 'print0', None,
4707 ('0', 'print0', None,
4708 _('end filenames with NUL, for use with xargs')),
4708 _('end filenames with NUL, for use with xargs')),
4709 ('', 'rev', [],
4709 ('', 'rev', [],
4710 _('show difference from revision'), _('REV')),
4710 _('show difference from revision'), _('REV')),
4711 ('', 'change', '',
4711 ('', 'change', '',
4712 _('list the changed files of a revision'), _('REV')),
4712 _('list the changed files of a revision'), _('REV')),
4713 ] + walkopts + subrepoopts,
4713 ] + walkopts + subrepoopts,
4714 _('[OPTION]... [FILE]...')),
4714 _('[OPTION]... [FILE]...')),
4715 "tag":
4715 "tag":
4716 (tag,
4716 (tag,
4717 [('f', 'force', None, _('force tag')),
4717 [('f', 'force', None, _('force tag')),
4718 ('l', 'local', None, _('make the tag local')),
4718 ('l', 'local', None, _('make the tag local')),
4719 ('r', 'rev', '',
4719 ('r', 'rev', '',
4720 _('revision to tag'), _('REV')),
4720 _('revision to tag'), _('REV')),
4721 ('', 'remove', None, _('remove a tag')),
4721 ('', 'remove', None, _('remove a tag')),
4722 # -l/--local is already there, commitopts cannot be used
4722 # -l/--local is already there, commitopts cannot be used
4723 ('e', 'edit', None, _('edit commit message')),
4723 ('e', 'edit', None, _('edit commit message')),
4724 ('m', 'message', '',
4724 ('m', 'message', '',
4725 _('use <text> as commit message'), _('TEXT')),
4725 _('use <text> as commit message'), _('TEXT')),
4726 ] + commitopts2,
4726 ] + commitopts2,
4727 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4727 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4728 "tags": (tags, [], ''),
4728 "tags": (tags, [], ''),
4729 "tip":
4729 "tip":
4730 (tip,
4730 (tip,
4731 [('p', 'patch', None, _('show patch')),
4731 [('p', 'patch', None, _('show patch')),
4732 ('g', 'git', None, _('use git extended diff format')),
4732 ('g', 'git', None, _('use git extended diff format')),
4733 ] + templateopts,
4733 ] + templateopts,
4734 _('[-p] [-g]')),
4734 _('[-p] [-g]')),
4735 "unbundle":
4735 "unbundle":
4736 (unbundle,
4736 (unbundle,
4737 [('u', 'update', None,
4737 [('u', 'update', None,
4738 _('update to new branch head if changesets were unbundled'))],
4738 _('update to new branch head if changesets were unbundled'))],
4739 _('[-u] FILE...')),
4739 _('[-u] FILE...')),
4740 "^update|up|checkout|co":
4740 "^update|up|checkout|co":
4741 (update,
4741 (update,
4742 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4742 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4743 ('c', 'check', None,
4743 ('c', 'check', None,
4744 _('update across branches if no uncommitted changes')),
4744 _('update across branches if no uncommitted changes')),
4745 ('d', 'date', '',
4745 ('d', 'date', '',
4746 _('tipmost revision matching date'), _('DATE')),
4746 _('tipmost revision matching date'), _('DATE')),
4747 ('r', 'rev', '',
4747 ('r', 'rev', '',
4748 _('revision'), _('REV'))],
4748 _('revision'), _('REV'))],
4749 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4749 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4750 "verify": (verify, []),
4750 "verify": (verify, []),
4751 "version": (version_, []),
4751 "version": (version_, []),
4752 }
4752 }
4753
4753
4754 norepo = ("clone init version help debugcommands debugcomplete"
4754 norepo = ("clone init version help debugcommands debugcomplete"
4755 " debugdate debuginstall debugfsinfo debugpushkey")
4755 " debugdate debuginstall debugfsinfo debugpushkey")
4756 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4756 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4757 " debugdata debugindex debugindexdot")
4757 " debugdata debugindex debugindexdot")
@@ -1,92 +1,94 b''
1 # parser.py - simple top-down operator precedence parser for mercurial
1 # parser.py - simple top-down operator precedence parser for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 # see http://effbot.org/zone/simple-top-down-parsing.htm and
8 # see http://effbot.org/zone/simple-top-down-parsing.htm and
9 # http://eli.thegreenplace.net/2010/01/02/top-down-operator-precedence-parsing/
9 # http://eli.thegreenplace.net/2010/01/02/top-down-operator-precedence-parsing/
10 # for background
10 # for background
11
11
12 # takes a tokenizer and elements
12 # takes a tokenizer and elements
13 # tokenizer is an iterator that returns type, value pairs
13 # tokenizer is an iterator that returns type, value pairs
14 # elements is a mapping of types to binding strength, prefix and infix actions
14 # elements is a mapping of types to binding strength, prefix and infix actions
15 # an action is a tree node name, a tree label, and an optional match
15 # an action is a tree node name, a tree label, and an optional match
16 # __call__(program) parses program into a labelled tree
16 # __call__(program) parses program into a labelled tree
17
17
18 import error
18 import error
19
19
20 class parser(object):
20 class parser(object):
21 def __init__(self, tokenizer, elements, methods=None):
21 def __init__(self, tokenizer, elements, methods=None):
22 self._tokenizer = tokenizer
22 self._tokenizer = tokenizer
23 self._elements = elements
23 self._elements = elements
24 self._methods = methods
24 self._methods = methods
25 self.current = None
25 self.current = None
26 def _advance(self):
26 def _advance(self):
27 'advance the tokenizer'
27 'advance the tokenizer'
28 t = self.current
28 t = self.current
29 try:
29 try:
30 self.current = self._iter.next()
30 self.current = self._iter.next()
31 except StopIteration:
31 except StopIteration:
32 pass
32 pass
33 return t
33 return t
34 def _match(self, m, pos):
34 def _match(self, m, pos):
35 'make sure the tokenizer matches an end condition'
35 'make sure the tokenizer matches an end condition'
36 if self.current[0] != m:
36 if self.current[0] != m:
37 raise error.ParseError("unexpected token: %s" % self.current[0],
37 raise error.ParseError("unexpected token: %s" % self.current[0],
38 self.current[2])
38 self.current[2])
39 self._advance()
39 self._advance()
40 def _parse(self, bind=0):
40 def _parse(self, bind=0):
41 token, value, pos = self._advance()
41 token, value, pos = self._advance()
42 # handle prefix rules on current token
42 # handle prefix rules on current token
43 prefix = self._elements[token][1]
43 prefix = self._elements[token][1]
44 if not prefix:
44 if not prefix:
45 raise error.ParseError("not a prefix: %s" % token, pos)
45 raise error.ParseError("not a prefix: %s" % token, pos)
46 if len(prefix) == 1:
46 if len(prefix) == 1:
47 expr = (prefix[0], value)
47 expr = (prefix[0], value)
48 else:
48 else:
49 if len(prefix) > 2 and prefix[2] == self.current[0]:
49 if len(prefix) > 2 and prefix[2] == self.current[0]:
50 self._match(prefix[2], pos)
50 self._match(prefix[2], pos)
51 expr = (prefix[0], None)
51 expr = (prefix[0], None)
52 else:
52 else:
53 expr = (prefix[0], self._parse(prefix[1]))
53 expr = (prefix[0], self._parse(prefix[1]))
54 if len(prefix) > 2:
54 if len(prefix) > 2:
55 self._match(prefix[2], pos)
55 self._match(prefix[2], pos)
56 # gather tokens until we meet a lower binding strength
56 # gather tokens until we meet a lower binding strength
57 while bind < self._elements[self.current[0]][0]:
57 while bind < self._elements[self.current[0]][0]:
58 token, value, pos = self._advance()
58 token, value, pos = self._advance()
59 e = self._elements[token]
59 e = self._elements[token]
60 # check for suffix - next token isn't a valid prefix
60 # check for suffix - next token isn't a valid prefix
61 if len(e) == 4 and not self._elements[self.current[0]][1]:
61 if len(e) == 4 and not self._elements[self.current[0]][1]:
62 suffix = e[3]
62 suffix = e[3]
63 expr = (suffix[0], expr)
63 expr = (suffix[0], expr)
64 else:
64 else:
65 # handle infix rules
65 # handle infix rules
66 if len(e) < 3 or not e[2]:
66 if len(e) < 3 or not e[2]:
67 raise error.ParseError("not an infix: %s" % token, pos)
67 raise error.ParseError("not an infix: %s" % token, pos)
68 infix = e[2]
68 infix = e[2]
69 if len(infix) == 3 and infix[2] == self.current[0]:
69 if len(infix) == 3 and infix[2] == self.current[0]:
70 self._match(infix[2], pos)
70 self._match(infix[2], pos)
71 expr = (infix[0], expr, (None))
71 expr = (infix[0], expr, (None))
72 else:
72 else:
73 expr = (infix[0], expr, self._parse(infix[1]))
73 expr = (infix[0], expr, self._parse(infix[1]))
74 if len(infix) == 3:
74 if len(infix) == 3:
75 self._match(infix[2], pos)
75 self._match(infix[2], pos)
76 return expr
76 return expr
77 def parse(self, message):
77 def parse(self, message):
78 'generate a parse tree from a message'
78 'generate a parse tree from a message'
79 self._iter = self._tokenizer(message)
79 self._iter = self._tokenizer(message)
80 self._advance()
80 self._advance()
81 return self._parse()
81 res = self._parse()
82 token, value, pos = self.current
83 return res, pos
82 def eval(self, tree):
84 def eval(self, tree):
83 'recursively evaluate a parse tree using node methods'
85 'recursively evaluate a parse tree using node methods'
84 if not isinstance(tree, tuple):
86 if not isinstance(tree, tuple):
85 return tree
87 return tree
86 return self._methods[tree[0]](*[self.eval(t) for t in tree[1:]])
88 return self._methods[tree[0]](*[self.eval(t) for t in tree[1:]])
87 def __call__(self, message):
89 def __call__(self, message):
88 'parse a message into a parse tree and evaluate if methods given'
90 'parse a message into a parse tree and evaluate if methods given'
89 t = self.parse(message)
91 t = self.parse(message)
90 if self._methods:
92 if self._methods:
91 return self.eval(t)
93 return self.eval(t)
92 return t
94 return t
@@ -1,835 +1,837 b''
1 # revset.py - revision set queries for mercurial
1 # revset.py - revision set queries for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import re
8 import re
9 import parser, util, error, discovery
9 import parser, util, error, discovery
10 import bookmarks as bookmarksmod
10 import bookmarks as bookmarksmod
11 import match as matchmod
11 import match as matchmod
12 from i18n import _, gettext
12 from i18n import _, gettext
13
13
14 elements = {
14 elements = {
15 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
15 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
16 "-": (5, ("negate", 19), ("minus", 5)),
16 "-": (5, ("negate", 19), ("minus", 5)),
17 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
17 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
18 ("dagrangepost", 17)),
18 ("dagrangepost", 17)),
19 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
19 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
20 ("dagrangepost", 17)),
20 ("dagrangepost", 17)),
21 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
21 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
22 "not": (10, ("not", 10)),
22 "not": (10, ("not", 10)),
23 "!": (10, ("not", 10)),
23 "!": (10, ("not", 10)),
24 "and": (5, None, ("and", 5)),
24 "and": (5, None, ("and", 5)),
25 "&": (5, None, ("and", 5)),
25 "&": (5, None, ("and", 5)),
26 "or": (4, None, ("or", 4)),
26 "or": (4, None, ("or", 4)),
27 "|": (4, None, ("or", 4)),
27 "|": (4, None, ("or", 4)),
28 "+": (4, None, ("or", 4)),
28 "+": (4, None, ("or", 4)),
29 ",": (2, None, ("list", 2)),
29 ",": (2, None, ("list", 2)),
30 ")": (0, None, None),
30 ")": (0, None, None),
31 "symbol": (0, ("symbol",), None),
31 "symbol": (0, ("symbol",), None),
32 "string": (0, ("string",), None),
32 "string": (0, ("string",), None),
33 "end": (0, None, None),
33 "end": (0, None, None),
34 }
34 }
35
35
36 keywords = set(['and', 'or', 'not'])
36 keywords = set(['and', 'or', 'not'])
37
37
38 def tokenize(program):
38 def tokenize(program):
39 pos, l = 0, len(program)
39 pos, l = 0, len(program)
40 while pos < l:
40 while pos < l:
41 c = program[pos]
41 c = program[pos]
42 if c.isspace(): # skip inter-token whitespace
42 if c.isspace(): # skip inter-token whitespace
43 pass
43 pass
44 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
44 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
45 yield ('::', None, pos)
45 yield ('::', None, pos)
46 pos += 1 # skip ahead
46 pos += 1 # skip ahead
47 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
47 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
48 yield ('..', None, pos)
48 yield ('..', None, pos)
49 pos += 1 # skip ahead
49 pos += 1 # skip ahead
50 elif c in "():,-|&+!": # handle simple operators
50 elif c in "():,-|&+!": # handle simple operators
51 yield (c, None, pos)
51 yield (c, None, pos)
52 elif (c in '"\'' or c == 'r' and
52 elif (c in '"\'' or c == 'r' and
53 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
53 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
54 if c == 'r':
54 if c == 'r':
55 pos += 1
55 pos += 1
56 c = program[pos]
56 c = program[pos]
57 decode = lambda x: x
57 decode = lambda x: x
58 else:
58 else:
59 decode = lambda x: x.decode('string-escape')
59 decode = lambda x: x.decode('string-escape')
60 pos += 1
60 pos += 1
61 s = pos
61 s = pos
62 while pos < l: # find closing quote
62 while pos < l: # find closing quote
63 d = program[pos]
63 d = program[pos]
64 if d == '\\': # skip over escaped characters
64 if d == '\\': # skip over escaped characters
65 pos += 2
65 pos += 2
66 continue
66 continue
67 if d == c:
67 if d == c:
68 yield ('string', decode(program[s:pos]), s)
68 yield ('string', decode(program[s:pos]), s)
69 break
69 break
70 pos += 1
70 pos += 1
71 else:
71 else:
72 raise error.ParseError(_("unterminated string"), s)
72 raise error.ParseError(_("unterminated string"), s)
73 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
73 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
74 s = pos
74 s = pos
75 pos += 1
75 pos += 1
76 while pos < l: # find end of symbol
76 while pos < l: # find end of symbol
77 d = program[pos]
77 d = program[pos]
78 if not (d.isalnum() or d in "._" or ord(d) > 127):
78 if not (d.isalnum() or d in "._" or ord(d) > 127):
79 break
79 break
80 if d == '.' and program[pos - 1] == '.': # special case for ..
80 if d == '.' and program[pos - 1] == '.': # special case for ..
81 pos -= 1
81 pos -= 1
82 break
82 break
83 pos += 1
83 pos += 1
84 sym = program[s:pos]
84 sym = program[s:pos]
85 if sym in keywords: # operator keywords
85 if sym in keywords: # operator keywords
86 yield (sym, None, s)
86 yield (sym, None, s)
87 else:
87 else:
88 yield ('symbol', sym, s)
88 yield ('symbol', sym, s)
89 pos -= 1
89 pos -= 1
90 else:
90 else:
91 raise error.ParseError(_("syntax error"), pos)
91 raise error.ParseError(_("syntax error"), pos)
92 pos += 1
92 pos += 1
93 yield ('end', None, pos)
93 yield ('end', None, pos)
94
94
95 # helpers
95 # helpers
96
96
97 def getstring(x, err):
97 def getstring(x, err):
98 if x and (x[0] == 'string' or x[0] == 'symbol'):
98 if x and (x[0] == 'string' or x[0] == 'symbol'):
99 return x[1]
99 return x[1]
100 raise error.ParseError(err)
100 raise error.ParseError(err)
101
101
102 def getlist(x):
102 def getlist(x):
103 if not x:
103 if not x:
104 return []
104 return []
105 if x[0] == 'list':
105 if x[0] == 'list':
106 return getlist(x[1]) + [x[2]]
106 return getlist(x[1]) + [x[2]]
107 return [x]
107 return [x]
108
108
109 def getargs(x, min, max, err):
109 def getargs(x, min, max, err):
110 l = getlist(x)
110 l = getlist(x)
111 if len(l) < min or len(l) > max:
111 if len(l) < min or len(l) > max:
112 raise error.ParseError(err)
112 raise error.ParseError(err)
113 return l
113 return l
114
114
115 def getset(repo, subset, x):
115 def getset(repo, subset, x):
116 if not x:
116 if not x:
117 raise error.ParseError(_("missing argument"))
117 raise error.ParseError(_("missing argument"))
118 return methods[x[0]](repo, subset, *x[1:])
118 return methods[x[0]](repo, subset, *x[1:])
119
119
120 # operator methods
120 # operator methods
121
121
122 def stringset(repo, subset, x):
122 def stringset(repo, subset, x):
123 x = repo[x].rev()
123 x = repo[x].rev()
124 if x == -1 and len(subset) == len(repo):
124 if x == -1 and len(subset) == len(repo):
125 return [-1]
125 return [-1]
126 if x in subset:
126 if x in subset:
127 return [x]
127 return [x]
128 return []
128 return []
129
129
130 def symbolset(repo, subset, x):
130 def symbolset(repo, subset, x):
131 if x in symbols:
131 if x in symbols:
132 raise error.ParseError(_("can't use %s here") % x)
132 raise error.ParseError(_("can't use %s here") % x)
133 return stringset(repo, subset, x)
133 return stringset(repo, subset, x)
134
134
135 def rangeset(repo, subset, x, y):
135 def rangeset(repo, subset, x, y):
136 m = getset(repo, subset, x)
136 m = getset(repo, subset, x)
137 if not m:
137 if not m:
138 m = getset(repo, range(len(repo)), x)
138 m = getset(repo, range(len(repo)), x)
139
139
140 n = getset(repo, subset, y)
140 n = getset(repo, subset, y)
141 if not n:
141 if not n:
142 n = getset(repo, range(len(repo)), y)
142 n = getset(repo, range(len(repo)), y)
143
143
144 if not m or not n:
144 if not m or not n:
145 return []
145 return []
146 m, n = m[0], n[-1]
146 m, n = m[0], n[-1]
147
147
148 if m < n:
148 if m < n:
149 r = range(m, n + 1)
149 r = range(m, n + 1)
150 else:
150 else:
151 r = range(m, n - 1, -1)
151 r = range(m, n - 1, -1)
152 s = set(subset)
152 s = set(subset)
153 return [x for x in r if x in s]
153 return [x for x in r if x in s]
154
154
155 def andset(repo, subset, x, y):
155 def andset(repo, subset, x, y):
156 return getset(repo, getset(repo, subset, x), y)
156 return getset(repo, getset(repo, subset, x), y)
157
157
158 def orset(repo, subset, x, y):
158 def orset(repo, subset, x, y):
159 s = set(getset(repo, subset, x))
159 s = set(getset(repo, subset, x))
160 s |= set(getset(repo, [r for r in subset if r not in s], y))
160 s |= set(getset(repo, [r for r in subset if r not in s], y))
161 return [r for r in subset if r in s]
161 return [r for r in subset if r in s]
162
162
163 def notset(repo, subset, x):
163 def notset(repo, subset, x):
164 s = set(getset(repo, subset, x))
164 s = set(getset(repo, subset, x))
165 return [r for r in subset if r not in s]
165 return [r for r in subset if r not in s]
166
166
167 def listset(repo, subset, a, b):
167 def listset(repo, subset, a, b):
168 raise error.ParseError(_("can't use a list in this context"))
168 raise error.ParseError(_("can't use a list in this context"))
169
169
170 def func(repo, subset, a, b):
170 def func(repo, subset, a, b):
171 if a[0] == 'symbol' and a[1] in symbols:
171 if a[0] == 'symbol' and a[1] in symbols:
172 return symbols[a[1]](repo, subset, b)
172 return symbols[a[1]](repo, subset, b)
173 raise error.ParseError(_("not a function: %s") % a[1])
173 raise error.ParseError(_("not a function: %s") % a[1])
174
174
175 # functions
175 # functions
176
176
177 def node(repo, subset, x):
177 def node(repo, subset, x):
178 """``id(string)``
178 """``id(string)``
179 Revision non-ambiguously specified by the given hex string prefix.
179 Revision non-ambiguously specified by the given hex string prefix.
180 """
180 """
181 # i18n: "id" is a keyword
181 # i18n: "id" is a keyword
182 l = getargs(x, 1, 1, _("id requires one argument"))
182 l = getargs(x, 1, 1, _("id requires one argument"))
183 # i18n: "id" is a keyword
183 # i18n: "id" is a keyword
184 n = getstring(l[0], _("id requires a string"))
184 n = getstring(l[0], _("id requires a string"))
185 if len(n) == 40:
185 if len(n) == 40:
186 rn = repo[n].rev()
186 rn = repo[n].rev()
187 else:
187 else:
188 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
188 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
189 return [r for r in subset if r == rn]
189 return [r for r in subset if r == rn]
190
190
191 def rev(repo, subset, x):
191 def rev(repo, subset, x):
192 """``rev(number)``
192 """``rev(number)``
193 Revision with the given numeric identifier.
193 Revision with the given numeric identifier.
194 """
194 """
195 # i18n: "rev" is a keyword
195 # i18n: "rev" is a keyword
196 l = getargs(x, 1, 1, _("rev requires one argument"))
196 l = getargs(x, 1, 1, _("rev requires one argument"))
197 try:
197 try:
198 # i18n: "rev" is a keyword
198 # i18n: "rev" is a keyword
199 l = int(getstring(l[0], _("rev requires a number")))
199 l = int(getstring(l[0], _("rev requires a number")))
200 except ValueError:
200 except ValueError:
201 # i18n: "rev" is a keyword
201 # i18n: "rev" is a keyword
202 raise error.ParseError(_("rev expects a number"))
202 raise error.ParseError(_("rev expects a number"))
203 return [r for r in subset if r == l]
203 return [r for r in subset if r == l]
204
204
205 def p1(repo, subset, x):
205 def p1(repo, subset, x):
206 """``p1([set])``
206 """``p1([set])``
207 First parent of changesets in set, or the working directory.
207 First parent of changesets in set, or the working directory.
208 """
208 """
209 if x is None:
209 if x is None:
210 p = repo[x].parents()[0].rev()
210 p = repo[x].parents()[0].rev()
211 return [r for r in subset if r == p]
211 return [r for r in subset if r == p]
212
212
213 ps = set()
213 ps = set()
214 cl = repo.changelog
214 cl = repo.changelog
215 for r in getset(repo, range(len(repo)), x):
215 for r in getset(repo, range(len(repo)), x):
216 ps.add(cl.parentrevs(r)[0])
216 ps.add(cl.parentrevs(r)[0])
217 return [r for r in subset if r in ps]
217 return [r for r in subset if r in ps]
218
218
219 def p2(repo, subset, x):
219 def p2(repo, subset, x):
220 """``p2([set])``
220 """``p2([set])``
221 Second parent of changesets in set, or the working directory.
221 Second parent of changesets in set, or the working directory.
222 """
222 """
223 if x is None:
223 if x is None:
224 ps = repo[x].parents()
224 ps = repo[x].parents()
225 try:
225 try:
226 p = ps[1].rev()
226 p = ps[1].rev()
227 return [r for r in subset if r == p]
227 return [r for r in subset if r == p]
228 except IndexError:
228 except IndexError:
229 return []
229 return []
230
230
231 ps = set()
231 ps = set()
232 cl = repo.changelog
232 cl = repo.changelog
233 for r in getset(repo, range(len(repo)), x):
233 for r in getset(repo, range(len(repo)), x):
234 ps.add(cl.parentrevs(r)[1])
234 ps.add(cl.parentrevs(r)[1])
235 return [r for r in subset if r in ps]
235 return [r for r in subset if r in ps]
236
236
237 def parents(repo, subset, x):
237 def parents(repo, subset, x):
238 """``parents([set])``
238 """``parents([set])``
239 The set of all parents for all changesets in set, or the working directory.
239 The set of all parents for all changesets in set, or the working directory.
240 """
240 """
241 if x is None:
241 if x is None:
242 ps = tuple(p.rev() for p in repo[x].parents())
242 ps = tuple(p.rev() for p in repo[x].parents())
243 return [r for r in subset if r in ps]
243 return [r for r in subset if r in ps]
244
244
245 ps = set()
245 ps = set()
246 cl = repo.changelog
246 cl = repo.changelog
247 for r in getset(repo, range(len(repo)), x):
247 for r in getset(repo, range(len(repo)), x):
248 ps.update(cl.parentrevs(r))
248 ps.update(cl.parentrevs(r))
249 return [r for r in subset if r in ps]
249 return [r for r in subset if r in ps]
250
250
251 def maxrev(repo, subset, x):
251 def maxrev(repo, subset, x):
252 """``max(set)``
252 """``max(set)``
253 Changeset with highest revision number in set.
253 Changeset with highest revision number in set.
254 """
254 """
255 s = getset(repo, subset, x)
255 s = getset(repo, subset, x)
256 if s:
256 if s:
257 m = max(s)
257 m = max(s)
258 if m in subset:
258 if m in subset:
259 return [m]
259 return [m]
260 return []
260 return []
261
261
262 def minrev(repo, subset, x):
262 def minrev(repo, subset, x):
263 """``min(set)``
263 """``min(set)``
264 Changeset with lowest revision number in set.
264 Changeset with lowest revision number in set.
265 """
265 """
266 s = getset(repo, subset, x)
266 s = getset(repo, subset, x)
267 if s:
267 if s:
268 m = min(s)
268 m = min(s)
269 if m in subset:
269 if m in subset:
270 return [m]
270 return [m]
271 return []
271 return []
272
272
273 def limit(repo, subset, x):
273 def limit(repo, subset, x):
274 """``limit(set, n)``
274 """``limit(set, n)``
275 First n members of set.
275 First n members of set.
276 """
276 """
277 # i18n: "limit" is a keyword
277 # i18n: "limit" is a keyword
278 l = getargs(x, 2, 2, _("limit requires two arguments"))
278 l = getargs(x, 2, 2, _("limit requires two arguments"))
279 try:
279 try:
280 # i18n: "limit" is a keyword
280 # i18n: "limit" is a keyword
281 lim = int(getstring(l[1], _("limit requires a number")))
281 lim = int(getstring(l[1], _("limit requires a number")))
282 except ValueError:
282 except ValueError:
283 # i18n: "limit" is a keyword
283 # i18n: "limit" is a keyword
284 raise error.ParseError(_("limit expects a number"))
284 raise error.ParseError(_("limit expects a number"))
285 return getset(repo, subset, l[0])[:lim]
285 return getset(repo, subset, l[0])[:lim]
286
286
287 def children(repo, subset, x):
287 def children(repo, subset, x):
288 """``children(set)``
288 """``children(set)``
289 Child changesets of changesets in set.
289 Child changesets of changesets in set.
290 """
290 """
291 cs = set()
291 cs = set()
292 cl = repo.changelog
292 cl = repo.changelog
293 s = set(getset(repo, range(len(repo)), x))
293 s = set(getset(repo, range(len(repo)), x))
294 for r in xrange(0, len(repo)):
294 for r in xrange(0, len(repo)):
295 for p in cl.parentrevs(r):
295 for p in cl.parentrevs(r):
296 if p in s:
296 if p in s:
297 cs.add(r)
297 cs.add(r)
298 return [r for r in subset if r in cs]
298 return [r for r in subset if r in cs]
299
299
300 def branch(repo, subset, x):
300 def branch(repo, subset, x):
301 """``branch(set)``
301 """``branch(set)``
302 All changesets belonging to the branches of changesets in set.
302 All changesets belonging to the branches of changesets in set.
303 """
303 """
304 s = getset(repo, range(len(repo)), x)
304 s = getset(repo, range(len(repo)), x)
305 b = set()
305 b = set()
306 for r in s:
306 for r in s:
307 b.add(repo[r].branch())
307 b.add(repo[r].branch())
308 s = set(s)
308 s = set(s)
309 return [r for r in subset if r in s or repo[r].branch() in b]
309 return [r for r in subset if r in s or repo[r].branch() in b]
310
310
311 def ancestor(repo, subset, x):
311 def ancestor(repo, subset, x):
312 """``ancestor(single, single)``
312 """``ancestor(single, single)``
313 Greatest common ancestor of the two changesets.
313 Greatest common ancestor of the two changesets.
314 """
314 """
315 # i18n: "ancestor" is a keyword
315 # i18n: "ancestor" is a keyword
316 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
316 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
317 r = range(len(repo))
317 r = range(len(repo))
318 a = getset(repo, r, l[0])
318 a = getset(repo, r, l[0])
319 b = getset(repo, r, l[1])
319 b = getset(repo, r, l[1])
320 if len(a) != 1 or len(b) != 1:
320 if len(a) != 1 or len(b) != 1:
321 # i18n: "ancestor" is a keyword
321 # i18n: "ancestor" is a keyword
322 raise error.ParseError(_("ancestor arguments must be single revisions"))
322 raise error.ParseError(_("ancestor arguments must be single revisions"))
323 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
323 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
324
324
325 return [r for r in an if r in subset]
325 return [r for r in an if r in subset]
326
326
327 def ancestors(repo, subset, x):
327 def ancestors(repo, subset, x):
328 """``ancestors(set)``
328 """``ancestors(set)``
329 Changesets that are ancestors of a changeset in set.
329 Changesets that are ancestors of a changeset in set.
330 """
330 """
331 args = getset(repo, range(len(repo)), x)
331 args = getset(repo, range(len(repo)), x)
332 if not args:
332 if not args:
333 return []
333 return []
334 s = set(repo.changelog.ancestors(*args)) | set(args)
334 s = set(repo.changelog.ancestors(*args)) | set(args)
335 return [r for r in subset if r in s]
335 return [r for r in subset if r in s]
336
336
337 def descendants(repo, subset, x):
337 def descendants(repo, subset, x):
338 """``descendants(set)``
338 """``descendants(set)``
339 Changesets which are descendants of changesets in set.
339 Changesets which are descendants of changesets in set.
340 """
340 """
341 args = getset(repo, range(len(repo)), x)
341 args = getset(repo, range(len(repo)), x)
342 if not args:
342 if not args:
343 return []
343 return []
344 s = set(repo.changelog.descendants(*args)) | set(args)
344 s = set(repo.changelog.descendants(*args)) | set(args)
345 return [r for r in subset if r in s]
345 return [r for r in subset if r in s]
346
346
347 def follow(repo, subset, x):
347 def follow(repo, subset, x):
348 """``follow()``
348 """``follow()``
349 An alias for ``::.`` (ancestors of the working copy's first parent).
349 An alias for ``::.`` (ancestors of the working copy's first parent).
350 """
350 """
351 # i18n: "follow" is a keyword
351 # i18n: "follow" is a keyword
352 getargs(x, 0, 0, _("follow takes no arguments"))
352 getargs(x, 0, 0, _("follow takes no arguments"))
353 p = repo['.'].rev()
353 p = repo['.'].rev()
354 s = set(repo.changelog.ancestors(p)) | set([p])
354 s = set(repo.changelog.ancestors(p)) | set([p])
355 return [r for r in subset if r in s]
355 return [r for r in subset if r in s]
356
356
357 def date(repo, subset, x):
357 def date(repo, subset, x):
358 """``date(interval)``
358 """``date(interval)``
359 Changesets within the interval, see :hg:`help dates`.
359 Changesets within the interval, see :hg:`help dates`.
360 """
360 """
361 # i18n: "date" is a keyword
361 # i18n: "date" is a keyword
362 ds = getstring(x, _("date requires a string"))
362 ds = getstring(x, _("date requires a string"))
363 dm = util.matchdate(ds)
363 dm = util.matchdate(ds)
364 return [r for r in subset if dm(repo[r].date()[0])]
364 return [r for r in subset if dm(repo[r].date()[0])]
365
365
366 def keyword(repo, subset, x):
366 def keyword(repo, subset, x):
367 """``keyword(string)``
367 """``keyword(string)``
368 Search commit message, user name, and names of changed files for
368 Search commit message, user name, and names of changed files for
369 string. The match is case-insensitive.
369 string. The match is case-insensitive.
370 """
370 """
371 # i18n: "keyword" is a keyword
371 # i18n: "keyword" is a keyword
372 kw = getstring(x, _("keyword requires a string")).lower()
372 kw = getstring(x, _("keyword requires a string")).lower()
373 l = []
373 l = []
374 for r in subset:
374 for r in subset:
375 c = repo[r]
375 c = repo[r]
376 t = " ".join(c.files() + [c.user(), c.description()])
376 t = " ".join(c.files() + [c.user(), c.description()])
377 if kw in t.lower():
377 if kw in t.lower():
378 l.append(r)
378 l.append(r)
379 return l
379 return l
380
380
381 def grep(repo, subset, x):
381 def grep(repo, subset, x):
382 """``grep(regex)``
382 """``grep(regex)``
383 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
383 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
384 to ensure special escape characters are handled correctly. Unlike
384 to ensure special escape characters are handled correctly. Unlike
385 ``keyword(string)``, the match is case-sensitive.
385 ``keyword(string)``, the match is case-sensitive.
386 """
386 """
387 try:
387 try:
388 # i18n: "grep" is a keyword
388 # i18n: "grep" is a keyword
389 gr = re.compile(getstring(x, _("grep requires a string")))
389 gr = re.compile(getstring(x, _("grep requires a string")))
390 except re.error, e:
390 except re.error, e:
391 raise error.ParseError(_('invalid match pattern: %s') % e)
391 raise error.ParseError(_('invalid match pattern: %s') % e)
392 l = []
392 l = []
393 for r in subset:
393 for r in subset:
394 c = repo[r]
394 c = repo[r]
395 for e in c.files() + [c.user(), c.description()]:
395 for e in c.files() + [c.user(), c.description()]:
396 if gr.search(e):
396 if gr.search(e):
397 l.append(r)
397 l.append(r)
398 continue
398 continue
399 return l
399 return l
400
400
401 def author(repo, subset, x):
401 def author(repo, subset, x):
402 """``author(string)``
402 """``author(string)``
403 Alias for ``user(string)``.
403 Alias for ``user(string)``.
404 """
404 """
405 # i18n: "author" is a keyword
405 # i18n: "author" is a keyword
406 n = getstring(x, _("author requires a string")).lower()
406 n = getstring(x, _("author requires a string")).lower()
407 return [r for r in subset if n in repo[r].user().lower()]
407 return [r for r in subset if n in repo[r].user().lower()]
408
408
409 def user(repo, subset, x):
409 def user(repo, subset, x):
410 """``user(string)``
410 """``user(string)``
411 User name contains string. The match is case-insensitive.
411 User name contains string. The match is case-insensitive.
412 """
412 """
413 return author(repo, subset, x)
413 return author(repo, subset, x)
414
414
415 def hasfile(repo, subset, x):
415 def hasfile(repo, subset, x):
416 """``file(pattern)``
416 """``file(pattern)``
417 Changesets affecting files matched by pattern.
417 Changesets affecting files matched by pattern.
418 """
418 """
419 # i18n: "file" is a keyword
419 # i18n: "file" is a keyword
420 pat = getstring(x, _("file requires a pattern"))
420 pat = getstring(x, _("file requires a pattern"))
421 m = matchmod.match(repo.root, repo.getcwd(), [pat])
421 m = matchmod.match(repo.root, repo.getcwd(), [pat])
422 s = []
422 s = []
423 for r in subset:
423 for r in subset:
424 for f in repo[r].files():
424 for f in repo[r].files():
425 if m(f):
425 if m(f):
426 s.append(r)
426 s.append(r)
427 continue
427 continue
428 return s
428 return s
429
429
430 def contains(repo, subset, x):
430 def contains(repo, subset, x):
431 """``contains(pattern)``
431 """``contains(pattern)``
432 Revision contains a file matching pattern. See :hg:`help patterns`
432 Revision contains a file matching pattern. See :hg:`help patterns`
433 for information about file patterns.
433 for information about file patterns.
434 """
434 """
435 # i18n: "contains" is a keyword
435 # i18n: "contains" is a keyword
436 pat = getstring(x, _("contains requires a pattern"))
436 pat = getstring(x, _("contains requires a pattern"))
437 m = matchmod.match(repo.root, repo.getcwd(), [pat])
437 m = matchmod.match(repo.root, repo.getcwd(), [pat])
438 s = []
438 s = []
439 if m.files() == [pat]:
439 if m.files() == [pat]:
440 for r in subset:
440 for r in subset:
441 if pat in repo[r]:
441 if pat in repo[r]:
442 s.append(r)
442 s.append(r)
443 continue
443 continue
444 else:
444 else:
445 for r in subset:
445 for r in subset:
446 for f in repo[r].manifest():
446 for f in repo[r].manifest():
447 if m(f):
447 if m(f):
448 s.append(r)
448 s.append(r)
449 continue
449 continue
450 return s
450 return s
451
451
452 def checkstatus(repo, subset, pat, field):
452 def checkstatus(repo, subset, pat, field):
453 m = matchmod.match(repo.root, repo.getcwd(), [pat])
453 m = matchmod.match(repo.root, repo.getcwd(), [pat])
454 s = []
454 s = []
455 fast = (m.files() == [pat])
455 fast = (m.files() == [pat])
456 for r in subset:
456 for r in subset:
457 c = repo[r]
457 c = repo[r]
458 if fast:
458 if fast:
459 if pat not in c.files():
459 if pat not in c.files():
460 continue
460 continue
461 else:
461 else:
462 for f in c.files():
462 for f in c.files():
463 if m(f):
463 if m(f):
464 break
464 break
465 else:
465 else:
466 continue
466 continue
467 files = repo.status(c.p1().node(), c.node())[field]
467 files = repo.status(c.p1().node(), c.node())[field]
468 if fast:
468 if fast:
469 if pat in files:
469 if pat in files:
470 s.append(r)
470 s.append(r)
471 continue
471 continue
472 else:
472 else:
473 for f in files:
473 for f in files:
474 if m(f):
474 if m(f):
475 s.append(r)
475 s.append(r)
476 continue
476 continue
477 return s
477 return s
478
478
479 def modifies(repo, subset, x):
479 def modifies(repo, subset, x):
480 """``modifies(pattern)``
480 """``modifies(pattern)``
481 Changesets modifying files matched by pattern.
481 Changesets modifying files matched by pattern.
482 """
482 """
483 # i18n: "modifies" is a keyword
483 # i18n: "modifies" is a keyword
484 pat = getstring(x, _("modifies requires a pattern"))
484 pat = getstring(x, _("modifies requires a pattern"))
485 return checkstatus(repo, subset, pat, 0)
485 return checkstatus(repo, subset, pat, 0)
486
486
487 def adds(repo, subset, x):
487 def adds(repo, subset, x):
488 """``adds(pattern)``
488 """``adds(pattern)``
489 Changesets that add a file matching pattern.
489 Changesets that add a file matching pattern.
490 """
490 """
491 # i18n: "adds" is a keyword
491 # i18n: "adds" is a keyword
492 pat = getstring(x, _("adds requires a pattern"))
492 pat = getstring(x, _("adds requires a pattern"))
493 return checkstatus(repo, subset, pat, 1)
493 return checkstatus(repo, subset, pat, 1)
494
494
495 def removes(repo, subset, x):
495 def removes(repo, subset, x):
496 """``removes(pattern)``
496 """``removes(pattern)``
497 Changesets which remove files matching pattern.
497 Changesets which remove files matching pattern.
498 """
498 """
499 # i18n: "removes" is a keyword
499 # i18n: "removes" is a keyword
500 pat = getstring(x, _("removes requires a pattern"))
500 pat = getstring(x, _("removes requires a pattern"))
501 return checkstatus(repo, subset, pat, 2)
501 return checkstatus(repo, subset, pat, 2)
502
502
503 def merge(repo, subset, x):
503 def merge(repo, subset, x):
504 """``merge()``
504 """``merge()``
505 Changeset is a merge changeset.
505 Changeset is a merge changeset.
506 """
506 """
507 # i18n: "merge" is a keyword
507 # i18n: "merge" is a keyword
508 getargs(x, 0, 0, _("merge takes no arguments"))
508 getargs(x, 0, 0, _("merge takes no arguments"))
509 cl = repo.changelog
509 cl = repo.changelog
510 return [r for r in subset if cl.parentrevs(r)[1] != -1]
510 return [r for r in subset if cl.parentrevs(r)[1] != -1]
511
511
512 def closed(repo, subset, x):
512 def closed(repo, subset, x):
513 """``closed()``
513 """``closed()``
514 Changeset is closed.
514 Changeset is closed.
515 """
515 """
516 # i18n: "closed" is a keyword
516 # i18n: "closed" is a keyword
517 getargs(x, 0, 0, _("closed takes no arguments"))
517 getargs(x, 0, 0, _("closed takes no arguments"))
518 return [r for r in subset if repo[r].extra().get('close')]
518 return [r for r in subset if repo[r].extra().get('close')]
519
519
520 def head(repo, subset, x):
520 def head(repo, subset, x):
521 """``head()``
521 """``head()``
522 Changeset is a named branch head.
522 Changeset is a named branch head.
523 """
523 """
524 # i18n: "head" is a keyword
524 # i18n: "head" is a keyword
525 getargs(x, 0, 0, _("head takes no arguments"))
525 getargs(x, 0, 0, _("head takes no arguments"))
526 hs = set()
526 hs = set()
527 for b, ls in repo.branchmap().iteritems():
527 for b, ls in repo.branchmap().iteritems():
528 hs.update(repo[h].rev() for h in ls)
528 hs.update(repo[h].rev() for h in ls)
529 return [r for r in subset if r in hs]
529 return [r for r in subset if r in hs]
530
530
531 def reverse(repo, subset, x):
531 def reverse(repo, subset, x):
532 """``reverse(set)``
532 """``reverse(set)``
533 Reverse order of set.
533 Reverse order of set.
534 """
534 """
535 l = getset(repo, subset, x)
535 l = getset(repo, subset, x)
536 l.reverse()
536 l.reverse()
537 return l
537 return l
538
538
539 def present(repo, subset, x):
539 def present(repo, subset, x):
540 """``present(set)``
540 """``present(set)``
541 An empty set, if any revision in set isn't found; otherwise,
541 An empty set, if any revision in set isn't found; otherwise,
542 all revisions in set.
542 all revisions in set.
543 """
543 """
544 try:
544 try:
545 return getset(repo, subset, x)
545 return getset(repo, subset, x)
546 except error.RepoLookupError:
546 except error.RepoLookupError:
547 return []
547 return []
548
548
549 def sort(repo, subset, x):
549 def sort(repo, subset, x):
550 """``sort(set[, [-]key...])``
550 """``sort(set[, [-]key...])``
551 Sort set by keys. The default sort order is ascending, specify a key
551 Sort set by keys. The default sort order is ascending, specify a key
552 as ``-key`` to sort in descending order.
552 as ``-key`` to sort in descending order.
553
553
554 The keys can be:
554 The keys can be:
555
555
556 - ``rev`` for the revision number,
556 - ``rev`` for the revision number,
557 - ``branch`` for the branch name,
557 - ``branch`` for the branch name,
558 - ``desc`` for the commit message (description),
558 - ``desc`` for the commit message (description),
559 - ``user`` for user name (``author`` can be used as an alias),
559 - ``user`` for user name (``author`` can be used as an alias),
560 - ``date`` for the commit date
560 - ``date`` for the commit date
561 """
561 """
562 # i18n: "sort" is a keyword
562 # i18n: "sort" is a keyword
563 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
563 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
564 keys = "rev"
564 keys = "rev"
565 if len(l) == 2:
565 if len(l) == 2:
566 keys = getstring(l[1], _("sort spec must be a string"))
566 keys = getstring(l[1], _("sort spec must be a string"))
567
567
568 s = l[0]
568 s = l[0]
569 keys = keys.split()
569 keys = keys.split()
570 l = []
570 l = []
571 def invert(s):
571 def invert(s):
572 return "".join(chr(255 - ord(c)) for c in s)
572 return "".join(chr(255 - ord(c)) for c in s)
573 for r in getset(repo, subset, s):
573 for r in getset(repo, subset, s):
574 c = repo[r]
574 c = repo[r]
575 e = []
575 e = []
576 for k in keys:
576 for k in keys:
577 if k == 'rev':
577 if k == 'rev':
578 e.append(r)
578 e.append(r)
579 elif k == '-rev':
579 elif k == '-rev':
580 e.append(-r)
580 e.append(-r)
581 elif k == 'branch':
581 elif k == 'branch':
582 e.append(c.branch())
582 e.append(c.branch())
583 elif k == '-branch':
583 elif k == '-branch':
584 e.append(invert(c.branch()))
584 e.append(invert(c.branch()))
585 elif k == 'desc':
585 elif k == 'desc':
586 e.append(c.description())
586 e.append(c.description())
587 elif k == '-desc':
587 elif k == '-desc':
588 e.append(invert(c.description()))
588 e.append(invert(c.description()))
589 elif k in 'user author':
589 elif k in 'user author':
590 e.append(c.user())
590 e.append(c.user())
591 elif k in '-user -author':
591 elif k in '-user -author':
592 e.append(invert(c.user()))
592 e.append(invert(c.user()))
593 elif k == 'date':
593 elif k == 'date':
594 e.append(c.date()[0])
594 e.append(c.date()[0])
595 elif k == '-date':
595 elif k == '-date':
596 e.append(-c.date()[0])
596 e.append(-c.date()[0])
597 else:
597 else:
598 raise error.ParseError(_("unknown sort key %r") % k)
598 raise error.ParseError(_("unknown sort key %r") % k)
599 e.append(r)
599 e.append(r)
600 l.append(e)
600 l.append(e)
601 l.sort()
601 l.sort()
602 return [e[-1] for e in l]
602 return [e[-1] for e in l]
603
603
604 def getall(repo, subset, x):
604 def getall(repo, subset, x):
605 """``all()``
605 """``all()``
606 All changesets, the same as ``0:tip``.
606 All changesets, the same as ``0:tip``.
607 """
607 """
608 # i18n: "all" is a keyword
608 # i18n: "all" is a keyword
609 getargs(x, 0, 0, _("all takes no arguments"))
609 getargs(x, 0, 0, _("all takes no arguments"))
610 return subset
610 return subset
611
611
612 def heads(repo, subset, x):
612 def heads(repo, subset, x):
613 """``heads(set)``
613 """``heads(set)``
614 Members of set with no children in set.
614 Members of set with no children in set.
615 """
615 """
616 s = getset(repo, subset, x)
616 s = getset(repo, subset, x)
617 ps = set(parents(repo, subset, x))
617 ps = set(parents(repo, subset, x))
618 return [r for r in s if r not in ps]
618 return [r for r in s if r not in ps]
619
619
620 def roots(repo, subset, x):
620 def roots(repo, subset, x):
621 """``roots(set)``
621 """``roots(set)``
622 Changesets with no parent changeset in set.
622 Changesets with no parent changeset in set.
623 """
623 """
624 s = getset(repo, subset, x)
624 s = getset(repo, subset, x)
625 cs = set(children(repo, subset, x))
625 cs = set(children(repo, subset, x))
626 return [r for r in s if r not in cs]
626 return [r for r in s if r not in cs]
627
627
628 def outgoing(repo, subset, x):
628 def outgoing(repo, subset, x):
629 """``outgoing([path])``
629 """``outgoing([path])``
630 Changesets not found in the specified destination repository, or the
630 Changesets not found in the specified destination repository, or the
631 default push location.
631 default push location.
632 """
632 """
633 import hg # avoid start-up nasties
633 import hg # avoid start-up nasties
634 # i18n: "outgoing" is a keyword
634 # i18n: "outgoing" is a keyword
635 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
635 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
636 # i18n: "outgoing" is a keyword
636 # i18n: "outgoing" is a keyword
637 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
637 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
638 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
638 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
639 dest, branches = hg.parseurl(dest)
639 dest, branches = hg.parseurl(dest)
640 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
640 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
641 if revs:
641 if revs:
642 revs = [repo.lookup(rev) for rev in revs]
642 revs = [repo.lookup(rev) for rev in revs]
643 other = hg.repository(hg.remoteui(repo, {}), dest)
643 other = hg.repository(hg.remoteui(repo, {}), dest)
644 repo.ui.pushbuffer()
644 repo.ui.pushbuffer()
645 o = discovery.findoutgoing(repo, other)
645 o = discovery.findoutgoing(repo, other)
646 repo.ui.popbuffer()
646 repo.ui.popbuffer()
647 cl = repo.changelog
647 cl = repo.changelog
648 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
648 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
649 return [r for r in subset if r in o]
649 return [r for r in subset if r in o]
650
650
651 def tag(repo, subset, x):
651 def tag(repo, subset, x):
652 """``tag([name])``
652 """``tag([name])``
653 The specified tag by name, or all tagged revisions if no name is given.
653 The specified tag by name, or all tagged revisions if no name is given.
654 """
654 """
655 # i18n: "tag" is a keyword
655 # i18n: "tag" is a keyword
656 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
656 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
657 cl = repo.changelog
657 cl = repo.changelog
658 if args:
658 if args:
659 tn = getstring(args[0],
659 tn = getstring(args[0],
660 # i18n: "tag" is a keyword
660 # i18n: "tag" is a keyword
661 _('the argument to tag must be a string'))
661 _('the argument to tag must be a string'))
662 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
662 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
663 else:
663 else:
664 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
664 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
665 return [r for r in subset if r in s]
665 return [r for r in subset if r in s]
666
666
667 def tagged(repo, subset, x):
667 def tagged(repo, subset, x):
668 return tag(repo, subset, x)
668 return tag(repo, subset, x)
669
669
670 def bookmark(repo, subset, x):
670 def bookmark(repo, subset, x):
671 """``bookmark([name])``
671 """``bookmark([name])``
672 The named bookmark or all bookmarks.
672 The named bookmark or all bookmarks.
673 """
673 """
674 # i18n: "bookmark" is a keyword
674 # i18n: "bookmark" is a keyword
675 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
675 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
676 if args:
676 if args:
677 bm = getstring(args[0],
677 bm = getstring(args[0],
678 # i18n: "bookmark" is a keyword
678 # i18n: "bookmark" is a keyword
679 _('the argument to bookmark must be a string'))
679 _('the argument to bookmark must be a string'))
680 bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
680 bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
681 if bmrev:
681 if bmrev:
682 bmrev = repo[bmrev].rev()
682 bmrev = repo[bmrev].rev()
683 return [r for r in subset if r == bmrev]
683 return [r for r in subset if r == bmrev]
684 bms = set([repo[r].rev()
684 bms = set([repo[r].rev()
685 for r in bookmarksmod.listbookmarks(repo).values()])
685 for r in bookmarksmod.listbookmarks(repo).values()])
686 return [r for r in subset if r in bms]
686 return [r for r in subset if r in bms]
687
687
688 symbols = {
688 symbols = {
689 "adds": adds,
689 "adds": adds,
690 "all": getall,
690 "all": getall,
691 "ancestor": ancestor,
691 "ancestor": ancestor,
692 "ancestors": ancestors,
692 "ancestors": ancestors,
693 "author": author,
693 "author": author,
694 "bookmark": bookmark,
694 "bookmark": bookmark,
695 "branch": branch,
695 "branch": branch,
696 "children": children,
696 "children": children,
697 "closed": closed,
697 "closed": closed,
698 "contains": contains,
698 "contains": contains,
699 "date": date,
699 "date": date,
700 "descendants": descendants,
700 "descendants": descendants,
701 "file": hasfile,
701 "file": hasfile,
702 "follow": follow,
702 "follow": follow,
703 "grep": grep,
703 "grep": grep,
704 "head": head,
704 "head": head,
705 "heads": heads,
705 "heads": heads,
706 "keyword": keyword,
706 "keyword": keyword,
707 "limit": limit,
707 "limit": limit,
708 "max": maxrev,
708 "max": maxrev,
709 "min": minrev,
709 "min": minrev,
710 "merge": merge,
710 "merge": merge,
711 "modifies": modifies,
711 "modifies": modifies,
712 "id": node,
712 "id": node,
713 "outgoing": outgoing,
713 "outgoing": outgoing,
714 "p1": p1,
714 "p1": p1,
715 "p2": p2,
715 "p2": p2,
716 "parents": parents,
716 "parents": parents,
717 "present": present,
717 "present": present,
718 "removes": removes,
718 "removes": removes,
719 "reverse": reverse,
719 "reverse": reverse,
720 "rev": rev,
720 "rev": rev,
721 "roots": roots,
721 "roots": roots,
722 "sort": sort,
722 "sort": sort,
723 "tag": tag,
723 "tag": tag,
724 "tagged": tagged,
724 "tagged": tagged,
725 "user": user,
725 "user": user,
726 }
726 }
727
727
728 methods = {
728 methods = {
729 "range": rangeset,
729 "range": rangeset,
730 "string": stringset,
730 "string": stringset,
731 "symbol": symbolset,
731 "symbol": symbolset,
732 "and": andset,
732 "and": andset,
733 "or": orset,
733 "or": orset,
734 "not": notset,
734 "not": notset,
735 "list": listset,
735 "list": listset,
736 "func": func,
736 "func": func,
737 }
737 }
738
738
739 def optimize(x, small):
739 def optimize(x, small):
740 if x is None:
740 if x is None:
741 return 0, x
741 return 0, x
742
742
743 smallbonus = 1
743 smallbonus = 1
744 if small:
744 if small:
745 smallbonus = .5
745 smallbonus = .5
746
746
747 op = x[0]
747 op = x[0]
748 if op == 'minus':
748 if op == 'minus':
749 return optimize(('and', x[1], ('not', x[2])), small)
749 return optimize(('and', x[1], ('not', x[2])), small)
750 elif op == 'dagrange':
750 elif op == 'dagrange':
751 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
751 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
752 ('func', ('symbol', 'ancestors'), x[2])), small)
752 ('func', ('symbol', 'ancestors'), x[2])), small)
753 elif op == 'dagrangepre':
753 elif op == 'dagrangepre':
754 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
754 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
755 elif op == 'dagrangepost':
755 elif op == 'dagrangepost':
756 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
756 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
757 elif op == 'rangepre':
757 elif op == 'rangepre':
758 return optimize(('range', ('string', '0'), x[1]), small)
758 return optimize(('range', ('string', '0'), x[1]), small)
759 elif op == 'rangepost':
759 elif op == 'rangepost':
760 return optimize(('range', x[1], ('string', 'tip')), small)
760 return optimize(('range', x[1], ('string', 'tip')), small)
761 elif op == 'negate':
761 elif op == 'negate':
762 return optimize(('string',
762 return optimize(('string',
763 '-' + getstring(x[1], _("can't negate that"))), small)
763 '-' + getstring(x[1], _("can't negate that"))), small)
764 elif op in 'string symbol negate':
764 elif op in 'string symbol negate':
765 return smallbonus, x # single revisions are small
765 return smallbonus, x # single revisions are small
766 elif op == 'and' or op == 'dagrange':
766 elif op == 'and' or op == 'dagrange':
767 wa, ta = optimize(x[1], True)
767 wa, ta = optimize(x[1], True)
768 wb, tb = optimize(x[2], True)
768 wb, tb = optimize(x[2], True)
769 w = min(wa, wb)
769 w = min(wa, wb)
770 if wa > wb:
770 if wa > wb:
771 return w, (op, tb, ta)
771 return w, (op, tb, ta)
772 return w, (op, ta, tb)
772 return w, (op, ta, tb)
773 elif op == 'or':
773 elif op == 'or':
774 wa, ta = optimize(x[1], False)
774 wa, ta = optimize(x[1], False)
775 wb, tb = optimize(x[2], False)
775 wb, tb = optimize(x[2], False)
776 if wb < wa:
776 if wb < wa:
777 wb, wa = wa, wb
777 wb, wa = wa, wb
778 return max(wa, wb), (op, ta, tb)
778 return max(wa, wb), (op, ta, tb)
779 elif op == 'not':
779 elif op == 'not':
780 o = optimize(x[1], not small)
780 o = optimize(x[1], not small)
781 return o[0], (op, o[1])
781 return o[0], (op, o[1])
782 elif op == 'group':
782 elif op == 'group':
783 return optimize(x[1], small)
783 return optimize(x[1], small)
784 elif op in 'range list':
784 elif op in 'range list':
785 wa, ta = optimize(x[1], small)
785 wa, ta = optimize(x[1], small)
786 wb, tb = optimize(x[2], small)
786 wb, tb = optimize(x[2], small)
787 return wa + wb, (op, ta, tb)
787 return wa + wb, (op, ta, tb)
788 elif op == 'func':
788 elif op == 'func':
789 f = getstring(x[1], _("not a symbol"))
789 f = getstring(x[1], _("not a symbol"))
790 wa, ta = optimize(x[2], small)
790 wa, ta = optimize(x[2], small)
791 if f in "grep date user author keyword branch file outgoing":
791 if f in "grep date user author keyword branch file outgoing":
792 w = 10 # slow
792 w = 10 # slow
793 elif f in "modifies adds removes":
793 elif f in "modifies adds removes":
794 w = 30 # slower
794 w = 30 # slower
795 elif f == "contains":
795 elif f == "contains":
796 w = 100 # very slow
796 w = 100 # very slow
797 elif f == "ancestor":
797 elif f == "ancestor":
798 w = 1 * smallbonus
798 w = 1 * smallbonus
799 elif f in "reverse limit":
799 elif f in "reverse limit":
800 w = 0
800 w = 0
801 elif f in "sort":
801 elif f in "sort":
802 w = 10 # assume most sorts look at changelog
802 w = 10 # assume most sorts look at changelog
803 else:
803 else:
804 w = 1
804 w = 1
805 return w + wa, (op, x[1], ta)
805 return w + wa, (op, x[1], ta)
806 return 1, x
806 return 1, x
807
807
808 parse = parser.parser(tokenize, elements).parse
808 parse = parser.parser(tokenize, elements).parse
809
809
810 def match(spec):
810 def match(spec):
811 if not spec:
811 if not spec:
812 raise error.ParseError(_("empty query"))
812 raise error.ParseError(_("empty query"))
813 tree = parse(spec)
813 tree, pos = parse(spec)
814 if (pos != len(spec)):
815 raise error.ParseError("invalid token", pos)
814 weight, tree = optimize(tree, True)
816 weight, tree = optimize(tree, True)
815 def mfunc(repo, subset):
817 def mfunc(repo, subset):
816 return getset(repo, subset, tree)
818 return getset(repo, subset, tree)
817 return mfunc
819 return mfunc
818
820
819 def makedoc(topic, doc):
821 def makedoc(topic, doc):
820 """Generate and include predicates help in revsets topic."""
822 """Generate and include predicates help in revsets topic."""
821 predicates = []
823 predicates = []
822 for name in sorted(symbols):
824 for name in sorted(symbols):
823 text = symbols[name].__doc__
825 text = symbols[name].__doc__
824 if not text:
826 if not text:
825 continue
827 continue
826 text = gettext(text.rstrip())
828 text = gettext(text.rstrip())
827 lines = text.splitlines()
829 lines = text.splitlines()
828 lines[1:] = [(' ' + l.strip()) for l in lines[1:]]
830 lines[1:] = [(' ' + l.strip()) for l in lines[1:]]
829 predicates.append('\n'.join(lines))
831 predicates.append('\n'.join(lines))
830 predicates = '\n\n'.join(predicates)
832 predicates = '\n\n'.join(predicates)
831 doc = doc.replace('.. predicatesmarker', predicates)
833 doc = doc.replace('.. predicatesmarker', predicates)
832 return doc
834 return doc
833
835
834 # tell hggettext to extract docstrings from these functions:
836 # tell hggettext to extract docstrings from these functions:
835 i18nfunctions = symbols.values()
837 i18nfunctions = symbols.values()
@@ -1,390 +1,389 b''
1 # templater.py - template expansion for output
1 # templater.py - template expansion for output
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 of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import sys, os
9 import sys, os
10 import util, config, templatefilters, parser, error
10 import util, config, templatefilters, parser, error
11
11
12 # template parsing
12 # template parsing
13
13
14 elements = {
14 elements = {
15 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
15 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
16 ",": (2, None, ("list", 2)),
16 ",": (2, None, ("list", 2)),
17 "|": (5, None, ("|", 5)),
17 "|": (5, None, ("|", 5)),
18 "%": (6, None, ("%", 6)),
18 "%": (6, None, ("%", 6)),
19 ")": (0, None, None),
19 ")": (0, None, None),
20 "symbol": (0, ("symbol",), None),
20 "symbol": (0, ("symbol",), None),
21 "string": (0, ("string",), None),
21 "string": (0, ("string",), None),
22 "end": (0, None, None),
22 "end": (0, None, None),
23 }
23 }
24
24
25 def tokenizer(data):
25 def tokenizer(data):
26 program, start, end = data
26 program, start, end = data
27 pos = start
27 pos = start
28 while pos < end:
28 while pos < end:
29 c = program[pos]
29 c = program[pos]
30 if c.isspace(): # skip inter-token whitespace
30 if c.isspace(): # skip inter-token whitespace
31 pass
31 pass
32 elif c in "(,)%|": # handle simple operators
32 elif c in "(,)%|": # handle simple operators
33 yield (c, None, pos)
33 yield (c, None, pos)
34 elif (c in '"\'' or c == 'r' and
34 elif (c in '"\'' or c == 'r' and
35 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
35 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
36 if c == 'r':
36 if c == 'r':
37 pos += 1
37 pos += 1
38 c = program[pos]
38 c = program[pos]
39 decode = lambda x: x
39 decode = lambda x: x
40 else:
40 else:
41 decode = lambda x: x.decode('string-escape')
41 decode = lambda x: x.decode('string-escape')
42 pos += 1
42 pos += 1
43 s = pos
43 s = pos
44 while pos < end: # find closing quote
44 while pos < end: # find closing quote
45 d = program[pos]
45 d = program[pos]
46 if d == '\\': # skip over escaped characters
46 if d == '\\': # skip over escaped characters
47 pos += 2
47 pos += 2
48 continue
48 continue
49 if d == c:
49 if d == c:
50 yield ('string', decode(program[s:pos]), s)
50 yield ('string', decode(program[s:pos]), s)
51 break
51 break
52 pos += 1
52 pos += 1
53 else:
53 else:
54 raise error.ParseError(_("unterminated string"), s)
54 raise error.ParseError(_("unterminated string"), s)
55 elif c.isalnum() or c in '_':
55 elif c.isalnum() or c in '_':
56 s = pos
56 s = pos
57 pos += 1
57 pos += 1
58 while pos < end: # find end of symbol
58 while pos < end: # find end of symbol
59 d = program[pos]
59 d = program[pos]
60 if not (d.isalnum() or d == "_"):
60 if not (d.isalnum() or d == "_"):
61 break
61 break
62 pos += 1
62 pos += 1
63 sym = program[s:pos]
63 sym = program[s:pos]
64 yield ('symbol', sym, s)
64 yield ('symbol', sym, s)
65 pos -= 1
65 pos -= 1
66 elif c == '}':
66 elif c == '}':
67 pos += 1
67 pos += 1
68 break
68 break
69 else:
69 else:
70 raise error.ParseError(_("syntax error"), pos)
70 raise error.ParseError(_("syntax error"), pos)
71 pos += 1
71 pos += 1
72 data[2] = pos
73 yield ('end', None, pos)
72 yield ('end', None, pos)
74
73
75 def compiletemplate(tmpl, context):
74 def compiletemplate(tmpl, context):
76 parsed = []
75 parsed = []
77 pos, stop = 0, len(tmpl)
76 pos, stop = 0, len(tmpl)
78 p = parser.parser(tokenizer, elements)
77 p = parser.parser(tokenizer, elements)
79
78
80 while pos < stop:
79 while pos < stop:
81 n = tmpl.find('{', pos)
80 n = tmpl.find('{', pos)
82 if n < 0:
81 if n < 0:
83 parsed.append(("string", tmpl[pos:]))
82 parsed.append(("string", tmpl[pos:]))
84 break
83 break
85 if n > 0 and tmpl[n - 1] == '\\':
84 if n > 0 and tmpl[n - 1] == '\\':
86 # escaped
85 # escaped
87 parsed.append(("string", tmpl[pos:n - 1] + "{"))
86 parsed.append(("string", tmpl[pos:n - 1] + "{"))
88 pos = n + 1
87 pos = n + 1
89 continue
88 continue
90 if n > pos:
89 if n > pos:
91 parsed.append(("string", tmpl[pos:n]))
90 parsed.append(("string", tmpl[pos:n]))
92
91
93 pd = [tmpl, n + 1, stop]
92 pd = [tmpl, n + 1, stop]
94 parsed.append(p.parse(pd))
93 parseres, pos = p.parse(pd)
95 pos = pd[2]
94 parsed.append(parseres)
96
95
97 return [compileexp(e, context) for e in parsed]
96 return [compileexp(e, context) for e in parsed]
98
97
99 def compileexp(exp, context):
98 def compileexp(exp, context):
100 t = exp[0]
99 t = exp[0]
101 if t in methods:
100 if t in methods:
102 return methods[t](exp, context)
101 return methods[t](exp, context)
103 raise error.ParseError(_("unknown method '%s'") % t)
102 raise error.ParseError(_("unknown method '%s'") % t)
104
103
105 # template evaluation
104 # template evaluation
106
105
107 def getsymbol(exp):
106 def getsymbol(exp):
108 if exp[0] == 'symbol':
107 if exp[0] == 'symbol':
109 return exp[1]
108 return exp[1]
110 raise error.ParseError(_("expected a symbol"))
109 raise error.ParseError(_("expected a symbol"))
111
110
112 def getlist(x):
111 def getlist(x):
113 if not x:
112 if not x:
114 return []
113 return []
115 if x[0] == 'list':
114 if x[0] == 'list':
116 return getlist(x[1]) + [x[2]]
115 return getlist(x[1]) + [x[2]]
117 return [x]
116 return [x]
118
117
119 def getfilter(exp, context):
118 def getfilter(exp, context):
120 f = getsymbol(exp)
119 f = getsymbol(exp)
121 if f not in context._filters:
120 if f not in context._filters:
122 raise error.ParseError(_("unknown function '%s'") % f)
121 raise error.ParseError(_("unknown function '%s'") % f)
123 return context._filters[f]
122 return context._filters[f]
124
123
125 def gettemplate(exp, context):
124 def gettemplate(exp, context):
126 if exp[0] == 'string':
125 if exp[0] == 'string':
127 return compiletemplate(exp[1], context)
126 return compiletemplate(exp[1], context)
128 if exp[0] == 'symbol':
127 if exp[0] == 'symbol':
129 return context._load(exp[1])
128 return context._load(exp[1])
130 raise error.ParseError(_("expected template specifier"))
129 raise error.ParseError(_("expected template specifier"))
131
130
132 def runstring(context, mapping, data):
131 def runstring(context, mapping, data):
133 return data
132 return data
134
133
135 def runsymbol(context, mapping, key):
134 def runsymbol(context, mapping, key):
136 v = mapping.get(key)
135 v = mapping.get(key)
137 if v is None:
136 if v is None:
138 v = context._defaults.get(key, '')
137 v = context._defaults.get(key, '')
139 if hasattr(v, '__call__'):
138 if hasattr(v, '__call__'):
140 return v(**mapping)
139 return v(**mapping)
141 return v
140 return v
142
141
143 def buildfilter(exp, context):
142 def buildfilter(exp, context):
144 func, data = compileexp(exp[1], context)
143 func, data = compileexp(exp[1], context)
145 filt = getfilter(exp[2], context)
144 filt = getfilter(exp[2], context)
146 return (runfilter, (func, data, filt))
145 return (runfilter, (func, data, filt))
147
146
148 def runfilter(context, mapping, data):
147 def runfilter(context, mapping, data):
149 func, data, filt = data
148 func, data, filt = data
150 return filt(func(context, mapping, data))
149 return filt(func(context, mapping, data))
151
150
152 def buildmap(exp, context):
151 def buildmap(exp, context):
153 func, data = compileexp(exp[1], context)
152 func, data = compileexp(exp[1], context)
154 ctmpl = gettemplate(exp[2], context)
153 ctmpl = gettemplate(exp[2], context)
155 return (runmap, (func, data, ctmpl))
154 return (runmap, (func, data, ctmpl))
156
155
157 def runmap(context, mapping, data):
156 def runmap(context, mapping, data):
158 func, data, ctmpl = data
157 func, data, ctmpl = data
159 d = func(context, mapping, data)
158 d = func(context, mapping, data)
160 lm = mapping.copy()
159 lm = mapping.copy()
161
160
162 for i in d:
161 for i in d:
163 if isinstance(i, dict):
162 if isinstance(i, dict):
164 lm.update(i)
163 lm.update(i)
165 for f, d in ctmpl:
164 for f, d in ctmpl:
166 yield f(context, lm, d)
165 yield f(context, lm, d)
167 else:
166 else:
168 # v is not an iterable of dicts, this happen when 'key'
167 # v is not an iterable of dicts, this happen when 'key'
169 # has been fully expanded already and format is useless.
168 # has been fully expanded already and format is useless.
170 # If so, return the expanded value.
169 # If so, return the expanded value.
171 yield i
170 yield i
172
171
173 def buildfunc(exp, context):
172 def buildfunc(exp, context):
174 n = getsymbol(exp[1])
173 n = getsymbol(exp[1])
175 args = [compileexp(x, context) for x in getlist(exp[2])]
174 args = [compileexp(x, context) for x in getlist(exp[2])]
176 if n in context._filters:
175 if n in context._filters:
177 if len(args) != 1:
176 if len(args) != 1:
178 raise error.ParseError(_("filter %s expects one argument") % n)
177 raise error.ParseError(_("filter %s expects one argument") % n)
179 f = context._filters[n]
178 f = context._filters[n]
180 return (runfilter, (args[0][0], args[0][1], f))
179 return (runfilter, (args[0][0], args[0][1], f))
181 elif n in context._funcs:
180 elif n in context._funcs:
182 f = context._funcs[n]
181 f = context._funcs[n]
183 return (f, args)
182 return (f, args)
184
183
185 methods = {
184 methods = {
186 "string": lambda e, c: (runstring, e[1]),
185 "string": lambda e, c: (runstring, e[1]),
187 "symbol": lambda e, c: (runsymbol, e[1]),
186 "symbol": lambda e, c: (runsymbol, e[1]),
188 "group": lambda e, c: compileexp(e[1], c),
187 "group": lambda e, c: compileexp(e[1], c),
189 # ".": buildmember,
188 # ".": buildmember,
190 "|": buildfilter,
189 "|": buildfilter,
191 "%": buildmap,
190 "%": buildmap,
192 "func": buildfunc,
191 "func": buildfunc,
193 }
192 }
194
193
195 # template engine
194 # template engine
196
195
197 path = ['templates', '../templates']
196 path = ['templates', '../templates']
198 stringify = templatefilters.stringify
197 stringify = templatefilters.stringify
199
198
200 def _flatten(thing):
199 def _flatten(thing):
201 '''yield a single stream from a possibly nested set of iterators'''
200 '''yield a single stream from a possibly nested set of iterators'''
202 if isinstance(thing, str):
201 if isinstance(thing, str):
203 yield thing
202 yield thing
204 elif not hasattr(thing, '__iter__'):
203 elif not hasattr(thing, '__iter__'):
205 if thing is not None:
204 if thing is not None:
206 yield str(thing)
205 yield str(thing)
207 else:
206 else:
208 for i in thing:
207 for i in thing:
209 if isinstance(i, str):
208 if isinstance(i, str):
210 yield i
209 yield i
211 elif not hasattr(i, '__iter__'):
210 elif not hasattr(i, '__iter__'):
212 if i is not None:
211 if i is not None:
213 yield str(i)
212 yield str(i)
214 elif i is not None:
213 elif i is not None:
215 for j in _flatten(i):
214 for j in _flatten(i):
216 yield j
215 yield j
217
216
218 def parsestring(s, quoted=True):
217 def parsestring(s, quoted=True):
219 '''parse a string using simple c-like syntax.
218 '''parse a string using simple c-like syntax.
220 string must be in quotes if quoted is True.'''
219 string must be in quotes if quoted is True.'''
221 if quoted:
220 if quoted:
222 if len(s) < 2 or s[0] != s[-1]:
221 if len(s) < 2 or s[0] != s[-1]:
223 raise SyntaxError(_('unmatched quotes'))
222 raise SyntaxError(_('unmatched quotes'))
224 return s[1:-1].decode('string_escape')
223 return s[1:-1].decode('string_escape')
225
224
226 return s.decode('string_escape')
225 return s.decode('string_escape')
227
226
228 class engine(object):
227 class engine(object):
229 '''template expansion engine.
228 '''template expansion engine.
230
229
231 template expansion works like this. a map file contains key=value
230 template expansion works like this. a map file contains key=value
232 pairs. if value is quoted, it is treated as string. otherwise, it
231 pairs. if value is quoted, it is treated as string. otherwise, it
233 is treated as name of template file.
232 is treated as name of template file.
234
233
235 templater is asked to expand a key in map. it looks up key, and
234 templater is asked to expand a key in map. it looks up key, and
236 looks for strings like this: {foo}. it expands {foo} by looking up
235 looks for strings like this: {foo}. it expands {foo} by looking up
237 foo in map, and substituting it. expansion is recursive: it stops
236 foo in map, and substituting it. expansion is recursive: it stops
238 when there is no more {foo} to replace.
237 when there is no more {foo} to replace.
239
238
240 expansion also allows formatting and filtering.
239 expansion also allows formatting and filtering.
241
240
242 format uses key to expand each item in list. syntax is
241 format uses key to expand each item in list. syntax is
243 {key%format}.
242 {key%format}.
244
243
245 filter uses function to transform value. syntax is
244 filter uses function to transform value. syntax is
246 {key|filter1|filter2|...}.'''
245 {key|filter1|filter2|...}.'''
247
246
248 def __init__(self, loader, filters={}, defaults={}):
247 def __init__(self, loader, filters={}, defaults={}):
249 self._loader = loader
248 self._loader = loader
250 self._filters = filters
249 self._filters = filters
251 self._defaults = defaults
250 self._defaults = defaults
252 self._cache = {}
251 self._cache = {}
253
252
254 def _load(self, t):
253 def _load(self, t):
255 '''load, parse, and cache a template'''
254 '''load, parse, and cache a template'''
256 if t not in self._cache:
255 if t not in self._cache:
257 self._cache[t] = compiletemplate(self._loader(t), self)
256 self._cache[t] = compiletemplate(self._loader(t), self)
258 return self._cache[t]
257 return self._cache[t]
259
258
260 def process(self, t, mapping):
259 def process(self, t, mapping):
261 '''Perform expansion. t is name of map element to expand.
260 '''Perform expansion. t is name of map element to expand.
262 mapping contains added elements for use during expansion. Is a
261 mapping contains added elements for use during expansion. Is a
263 generator.'''
262 generator.'''
264 return _flatten(func(self, mapping, data) for func, data in
263 return _flatten(func(self, mapping, data) for func, data in
265 self._load(t))
264 self._load(t))
266
265
267 engines = {'default': engine}
266 engines = {'default': engine}
268
267
269 class templater(object):
268 class templater(object):
270
269
271 def __init__(self, mapfile, filters={}, defaults={}, cache={},
270 def __init__(self, mapfile, filters={}, defaults={}, cache={},
272 minchunk=1024, maxchunk=65536):
271 minchunk=1024, maxchunk=65536):
273 '''set up template engine.
272 '''set up template engine.
274 mapfile is name of file to read map definitions from.
273 mapfile is name of file to read map definitions from.
275 filters is dict of functions. each transforms a value into another.
274 filters is dict of functions. each transforms a value into another.
276 defaults is dict of default map definitions.'''
275 defaults is dict of default map definitions.'''
277 self.mapfile = mapfile or 'template'
276 self.mapfile = mapfile or 'template'
278 self.cache = cache.copy()
277 self.cache = cache.copy()
279 self.map = {}
278 self.map = {}
280 self.base = (mapfile and os.path.dirname(mapfile)) or ''
279 self.base = (mapfile and os.path.dirname(mapfile)) or ''
281 self.filters = templatefilters.filters.copy()
280 self.filters = templatefilters.filters.copy()
282 self.filters.update(filters)
281 self.filters.update(filters)
283 self.defaults = defaults
282 self.defaults = defaults
284 self.minchunk, self.maxchunk = minchunk, maxchunk
283 self.minchunk, self.maxchunk = minchunk, maxchunk
285 self.ecache = {}
284 self.ecache = {}
286
285
287 if not mapfile:
286 if not mapfile:
288 return
287 return
289 if not os.path.exists(mapfile):
288 if not os.path.exists(mapfile):
290 raise util.Abort(_('style not found: %s') % mapfile)
289 raise util.Abort(_('style not found: %s') % mapfile)
291
290
292 conf = config.config()
291 conf = config.config()
293 conf.read(mapfile)
292 conf.read(mapfile)
294
293
295 for key, val in conf[''].items():
294 for key, val in conf[''].items():
296 if val[0] in "'\"":
295 if val[0] in "'\"":
297 try:
296 try:
298 self.cache[key] = parsestring(val)
297 self.cache[key] = parsestring(val)
299 except SyntaxError, inst:
298 except SyntaxError, inst:
300 raise SyntaxError('%s: %s' %
299 raise SyntaxError('%s: %s' %
301 (conf.source('', key), inst.args[0]))
300 (conf.source('', key), inst.args[0]))
302 else:
301 else:
303 val = 'default', val
302 val = 'default', val
304 if ':' in val[1]:
303 if ':' in val[1]:
305 val = val[1].split(':', 1)
304 val = val[1].split(':', 1)
306 self.map[key] = val[0], os.path.join(self.base, val[1])
305 self.map[key] = val[0], os.path.join(self.base, val[1])
307
306
308 def __contains__(self, key):
307 def __contains__(self, key):
309 return key in self.cache or key in self.map
308 return key in self.cache or key in self.map
310
309
311 def load(self, t):
310 def load(self, t):
312 '''Get the template for the given template name. Use a local cache.'''
311 '''Get the template for the given template name. Use a local cache.'''
313 if not t in self.cache:
312 if not t in self.cache:
314 try:
313 try:
315 self.cache[t] = open(self.map[t][1]).read()
314 self.cache[t] = open(self.map[t][1]).read()
316 except KeyError, inst:
315 except KeyError, inst:
317 raise util.Abort(_('"%s" not in template map') % inst.args[0])
316 raise util.Abort(_('"%s" not in template map') % inst.args[0])
318 except IOError, inst:
317 except IOError, inst:
319 raise IOError(inst.args[0], _('template file %s: %s') %
318 raise IOError(inst.args[0], _('template file %s: %s') %
320 (self.map[t][1], inst.args[1]))
319 (self.map[t][1], inst.args[1]))
321 return self.cache[t]
320 return self.cache[t]
322
321
323 def __call__(self, t, **mapping):
322 def __call__(self, t, **mapping):
324 ttype = t in self.map and self.map[t][0] or 'default'
323 ttype = t in self.map and self.map[t][0] or 'default'
325 if ttype not in self.ecache:
324 if ttype not in self.ecache:
326 self.ecache[ttype] = engines[ttype](self.load,
325 self.ecache[ttype] = engines[ttype](self.load,
327 self.filters, self.defaults)
326 self.filters, self.defaults)
328 proc = self.ecache[ttype]
327 proc = self.ecache[ttype]
329
328
330 stream = proc.process(t, mapping)
329 stream = proc.process(t, mapping)
331 if self.minchunk:
330 if self.minchunk:
332 stream = util.increasingchunks(stream, min=self.minchunk,
331 stream = util.increasingchunks(stream, min=self.minchunk,
333 max=self.maxchunk)
332 max=self.maxchunk)
334 return stream
333 return stream
335
334
336 def templatepath(name=None):
335 def templatepath(name=None):
337 '''return location of template file or directory (if no name).
336 '''return location of template file or directory (if no name).
338 returns None if not found.'''
337 returns None if not found.'''
339 normpaths = []
338 normpaths = []
340
339
341 # executable version (py2exe) doesn't support __file__
340 # executable version (py2exe) doesn't support __file__
342 if hasattr(sys, 'frozen'):
341 if hasattr(sys, 'frozen'):
343 module = sys.executable
342 module = sys.executable
344 else:
343 else:
345 module = __file__
344 module = __file__
346 for f in path:
345 for f in path:
347 if f.startswith('/'):
346 if f.startswith('/'):
348 p = f
347 p = f
349 else:
348 else:
350 fl = f.split('/')
349 fl = f.split('/')
351 p = os.path.join(os.path.dirname(module), *fl)
350 p = os.path.join(os.path.dirname(module), *fl)
352 if name:
351 if name:
353 p = os.path.join(p, name)
352 p = os.path.join(p, name)
354 if name and os.path.exists(p):
353 if name and os.path.exists(p):
355 return os.path.normpath(p)
354 return os.path.normpath(p)
356 elif os.path.isdir(p):
355 elif os.path.isdir(p):
357 normpaths.append(os.path.normpath(p))
356 normpaths.append(os.path.normpath(p))
358
357
359 return normpaths
358 return normpaths
360
359
361 def stylemap(styles, paths=None):
360 def stylemap(styles, paths=None):
362 """Return path to mapfile for a given style.
361 """Return path to mapfile for a given style.
363
362
364 Searches mapfile in the following locations:
363 Searches mapfile in the following locations:
365 1. templatepath/style/map
364 1. templatepath/style/map
366 2. templatepath/map-style
365 2. templatepath/map-style
367 3. templatepath/map
366 3. templatepath/map
368 """
367 """
369
368
370 if paths is None:
369 if paths is None:
371 paths = templatepath()
370 paths = templatepath()
372 elif isinstance(paths, str):
371 elif isinstance(paths, str):
373 paths = [paths]
372 paths = [paths]
374
373
375 if isinstance(styles, str):
374 if isinstance(styles, str):
376 styles = [styles]
375 styles = [styles]
377
376
378 for style in styles:
377 for style in styles:
379 if not style:
378 if not style:
380 continue
379 continue
381 locations = [os.path.join(style, 'map'), 'map-' + style]
380 locations = [os.path.join(style, 'map'), 'map-' + style]
382 locations.append('map')
381 locations.append('map')
383
382
384 for path in paths:
383 for path in paths:
385 for location in locations:
384 for location in locations:
386 mapfile = os.path.join(path, location)
385 mapfile = os.path.join(path, location)
387 if os.path.isfile(mapfile):
386 if os.path.isfile(mapfile):
388 return style, mapfile
387 return style, mapfile
389
388
390 raise RuntimeError("No hgweb templates found in %r" % paths)
389 raise RuntimeError("No hgweb templates found in %r" % paths)
@@ -1,358 +1,365 b''
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3
3
4 $ try() {
4 $ try() {
5 > hg debugrevspec --debug $@
5 > hg debugrevspec --debug $@
6 > }
6 > }
7
7
8 $ log() {
8 $ log() {
9 > hg log --template '{rev}\n' -r "$1"
9 > hg log --template '{rev}\n' -r "$1"
10 > }
10 > }
11
11
12 $ hg init repo
12 $ hg init repo
13 $ cd repo
13 $ cd repo
14
14
15 $ echo a > a
15 $ echo a > a
16 $ hg branch a
16 $ hg branch a
17 marked working directory as branch a
17 marked working directory as branch a
18 $ hg ci -Aqm0
18 $ hg ci -Aqm0
19
19
20 $ echo b > b
20 $ echo b > b
21 $ hg branch b
21 $ hg branch b
22 marked working directory as branch b
22 marked working directory as branch b
23 $ hg ci -Aqm1
23 $ hg ci -Aqm1
24
24
25 $ rm a
25 $ rm a
26 $ hg branch a-b-c-
26 $ hg branch a-b-c-
27 marked working directory as branch a-b-c-
27 marked working directory as branch a-b-c-
28 $ hg ci -Aqm2 -u Bob
28 $ hg ci -Aqm2 -u Bob
29
29
30 $ hg co 1
30 $ hg co 1
31 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
32 $ hg branch +a+b+c+
32 $ hg branch +a+b+c+
33 marked working directory as branch +a+b+c+
33 marked working directory as branch +a+b+c+
34 $ hg ci -Aqm3
34 $ hg ci -Aqm3
35
35
36 $ hg co 2 # interleave
36 $ hg co 2 # interleave
37 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
37 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
38 $ echo bb > b
38 $ echo bb > b
39 $ hg branch -- -a-b-c-
39 $ hg branch -- -a-b-c-
40 marked working directory as branch -a-b-c-
40 marked working directory as branch -a-b-c-
41 $ hg ci -Aqm4 -d "May 12 2005"
41 $ hg ci -Aqm4 -d "May 12 2005"
42
42
43 $ hg co 3
43 $ hg co 3
44 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 $ hg branch /a/b/c/
45 $ hg branch /a/b/c/
46 marked working directory as branch /a/b/c/
46 marked working directory as branch /a/b/c/
47 $ hg ci -Aqm"5 bug"
47 $ hg ci -Aqm"5 bug"
48
48
49 $ hg merge 4
49 $ hg merge 4
50 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
50 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
51 (branch merge, don't forget to commit)
51 (branch merge, don't forget to commit)
52 $ hg branch _a_b_c_
52 $ hg branch _a_b_c_
53 marked working directory as branch _a_b_c_
53 marked working directory as branch _a_b_c_
54 $ hg ci -Aqm"6 issue619"
54 $ hg ci -Aqm"6 issue619"
55
55
56 $ hg branch .a.b.c.
56 $ hg branch .a.b.c.
57 marked working directory as branch .a.b.c.
57 marked working directory as branch .a.b.c.
58 $ hg ci -Aqm7
58 $ hg ci -Aqm7
59
59
60 $ hg branch all
60 $ hg branch all
61 marked working directory as branch all
61 marked working directory as branch all
62 $ hg ci --close-branch -Aqm8
62 $ hg ci --close-branch -Aqm8
63 abort: can only close branch heads
63 abort: can only close branch heads
64 [255]
64 [255]
65
65
66 $ hg co 4
66 $ hg co 4
67 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
68 $ hg branch é
68 $ hg branch é
69 marked working directory as branch \xc3\xa9 (esc)
69 marked working directory as branch \xc3\xa9 (esc)
70 $ hg ci -Aqm9
70 $ hg ci -Aqm9
71
71
72 $ hg tag -r6 1.0
72 $ hg tag -r6 1.0
73
73
74 $ hg clone --quiet -U -r 7 . ../remote1
74 $ hg clone --quiet -U -r 7 . ../remote1
75 $ hg clone --quiet -U -r 8 . ../remote2
75 $ hg clone --quiet -U -r 8 . ../remote2
76 $ echo "[paths]" >> .hg/hgrc
76 $ echo "[paths]" >> .hg/hgrc
77 $ echo "default = ../remote1" >> .hg/hgrc
77 $ echo "default = ../remote1" >> .hg/hgrc
78
78
79 names that should work without quoting
79 names that should work without quoting
80
80
81 $ try a
81 $ try a
82 ('symbol', 'a')
82 ('symbol', 'a')
83 0
83 0
84 $ try b-a
84 $ try b-a
85 ('minus', ('symbol', 'b'), ('symbol', 'a'))
85 ('minus', ('symbol', 'b'), ('symbol', 'a'))
86 1
86 1
87 $ try _a_b_c_
87 $ try _a_b_c_
88 ('symbol', '_a_b_c_')
88 ('symbol', '_a_b_c_')
89 6
89 6
90 $ try _a_b_c_-a
90 $ try _a_b_c_-a
91 ('minus', ('symbol', '_a_b_c_'), ('symbol', 'a'))
91 ('minus', ('symbol', '_a_b_c_'), ('symbol', 'a'))
92 6
92 6
93 $ try .a.b.c.
93 $ try .a.b.c.
94 ('symbol', '.a.b.c.')
94 ('symbol', '.a.b.c.')
95 7
95 7
96 $ try .a.b.c.-a
96 $ try .a.b.c.-a
97 ('minus', ('symbol', '.a.b.c.'), ('symbol', 'a'))
97 ('minus', ('symbol', '.a.b.c.'), ('symbol', 'a'))
98 7
98 7
99 $ try -- '-a-b-c-' # complains
99 $ try -- '-a-b-c-' # complains
100 hg: parse error at 7: not a prefix: end
100 hg: parse error at 7: not a prefix: end
101 [255]
101 [255]
102 $ log -a-b-c- # succeeds with fallback
102 $ log -a-b-c- # succeeds with fallback
103 4
103 4
104 $ try -- -a-b-c--a # complains
104 $ try -- -a-b-c--a # complains
105 ('minus', ('minus', ('minus', ('negate', ('symbol', 'a')), ('symbol', 'b')), ('symbol', 'c')), ('negate', ('symbol', 'a')))
105 ('minus', ('minus', ('minus', ('negate', ('symbol', 'a')), ('symbol', 'b')), ('symbol', 'c')), ('negate', ('symbol', 'a')))
106 abort: unknown revision '-a'!
106 abort: unknown revision '-a'!
107 [255]
107 [255]
108 $ try é
108 $ try é
109 ('symbol', '\xc3\xa9')
109 ('symbol', '\xc3\xa9')
110 9
110 9
111
111
112 quoting needed
112 quoting needed
113
113
114 $ try '"-a-b-c-"-a'
114 $ try '"-a-b-c-"-a'
115 ('minus', ('string', '-a-b-c-'), ('symbol', 'a'))
115 ('minus', ('string', '-a-b-c-'), ('symbol', 'a'))
116 4
116 4
117
117
118 $ log '1 or 2'
118 $ log '1 or 2'
119 1
119 1
120 2
120 2
121 $ log '1|2'
121 $ log '1|2'
122 1
122 1
123 2
123 2
124 $ log '1 and 2'
124 $ log '1 and 2'
125 $ log '1&2'
125 $ log '1&2'
126 $ try '1&2|3' # precedence - and is higher
126 $ try '1&2|3' # precedence - and is higher
127 ('or', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
127 ('or', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
128 3
128 3
129 $ try '1|2&3'
129 $ try '1|2&3'
130 ('or', ('symbol', '1'), ('and', ('symbol', '2'), ('symbol', '3')))
130 ('or', ('symbol', '1'), ('and', ('symbol', '2'), ('symbol', '3')))
131 1
131 1
132 $ try '1&2&3' # associativity
132 $ try '1&2&3' # associativity
133 ('and', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
133 ('and', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
134 $ try '1|(2|3)'
134 $ try '1|(2|3)'
135 ('or', ('symbol', '1'), ('group', ('or', ('symbol', '2'), ('symbol', '3'))))
135 ('or', ('symbol', '1'), ('group', ('or', ('symbol', '2'), ('symbol', '3'))))
136 1
136 1
137 2
137 2
138 3
138 3
139 $ log '1.0' # tag
139 $ log '1.0' # tag
140 6
140 6
141 $ log 'a' # branch
141 $ log 'a' # branch
142 0
142 0
143 $ log '2785f51ee'
143 $ log '2785f51ee'
144 0
144 0
145 $ log 'date(2005)'
145 $ log 'date(2005)'
146 4
146 4
147 $ log 'date(this is a test)'
147 $ log 'date(this is a test)'
148 hg: parse error at 10: unexpected token: symbol
148 hg: parse error at 10: unexpected token: symbol
149 [255]
149 [255]
150 $ log 'date()'
150 $ log 'date()'
151 hg: parse error: date requires a string
151 hg: parse error: date requires a string
152 [255]
152 [255]
153 $ log 'date'
153 $ log 'date'
154 hg: parse error: can't use date here
154 hg: parse error: can't use date here
155 [255]
155 [255]
156 $ log 'date('
156 $ log 'date('
157 hg: parse error at 5: not a prefix: end
157 hg: parse error at 5: not a prefix: end
158 [255]
158 [255]
159 $ log 'date(tip)'
159 $ log 'date(tip)'
160 abort: invalid date: 'tip'
160 abort: invalid date: 'tip'
161 [255]
161 [255]
162 $ log '"date"'
162 $ log '"date"'
163 abort: unknown revision 'date'!
163 abort: unknown revision 'date'!
164 [255]
164 [255]
165 $ log 'date(2005) and 1::'
165 $ log 'date(2005) and 1::'
166 4
166 4
167
167
168 $ log 'ancestor(1)'
168 $ log 'ancestor(1)'
169 hg: parse error: ancestor requires two arguments
169 hg: parse error: ancestor requires two arguments
170 [255]
170 [255]
171 $ log 'ancestor(4,5)'
171 $ log 'ancestor(4,5)'
172 1
172 1
173 $ log 'ancestor(4,5) and 4'
173 $ log 'ancestor(4,5) and 4'
174 $ log 'ancestors(5)'
174 $ log 'ancestors(5)'
175 0
175 0
176 1
176 1
177 3
177 3
178 5
178 5
179 $ log 'author(bob)'
179 $ log 'author(bob)'
180 2
180 2
181 $ log 'branch(é)'
181 $ log 'branch(é)'
182 8
182 8
183 9
183 9
184 $ log 'children(ancestor(4,5))'
184 $ log 'children(ancestor(4,5))'
185 2
185 2
186 3
186 3
187 $ log 'closed()'
187 $ log 'closed()'
188 $ log 'contains(a)'
188 $ log 'contains(a)'
189 0
189 0
190 1
190 1
191 3
191 3
192 5
192 5
193 $ log 'descendants(2 or 3)'
193 $ log 'descendants(2 or 3)'
194 2
194 2
195 3
195 3
196 4
196 4
197 5
197 5
198 6
198 6
199 7
199 7
200 8
200 8
201 9
201 9
202 $ log 'file(b)'
202 $ log 'file(b)'
203 1
203 1
204 4
204 4
205 $ log 'follow()'
205 $ log 'follow()'
206 0
206 0
207 1
207 1
208 2
208 2
209 4
209 4
210 8
210 8
211 9
211 9
212 $ log 'grep("issue\d+")'
212 $ log 'grep("issue\d+")'
213 6
213 6
214 $ try 'grep("(")' # invalid regular expression
214 $ try 'grep("(")' # invalid regular expression
215 ('func', ('symbol', 'grep'), ('string', '('))
215 ('func', ('symbol', 'grep'), ('string', '('))
216 hg: parse error: invalid match pattern: unbalanced parenthesis
216 hg: parse error: invalid match pattern: unbalanced parenthesis
217 [255]
217 [255]
218 $ try 'grep("\bissue\d+")'
218 $ try 'grep("\bissue\d+")'
219 ('func', ('symbol', 'grep'), ('string', '\x08issue\\d+'))
219 ('func', ('symbol', 'grep'), ('string', '\x08issue\\d+'))
220 $ try 'grep(r"\bissue\d+")'
220 $ try 'grep(r"\bissue\d+")'
221 ('func', ('symbol', 'grep'), ('string', '\\bissue\\d+'))
221 ('func', ('symbol', 'grep'), ('string', '\\bissue\\d+'))
222 6
222 6
223 $ try 'grep(r"\")'
223 $ try 'grep(r"\")'
224 hg: parse error at 7: unterminated string
224 hg: parse error at 7: unterminated string
225 [255]
225 [255]
226 $ log 'head()'
226 $ log 'head()'
227 0
227 0
228 1
228 1
229 2
229 2
230 3
230 3
231 4
231 4
232 5
232 5
233 6
233 6
234 7
234 7
235 9
235 9
236 $ log 'heads(6::)'
236 $ log 'heads(6::)'
237 7
237 7
238 $ log 'keyword(issue)'
238 $ log 'keyword(issue)'
239 6
239 6
240 $ log 'limit(head(), 1)'
240 $ log 'limit(head(), 1)'
241 0
241 0
242 $ log 'max(contains(a))'
242 $ log 'max(contains(a))'
243 5
243 5
244 $ log 'min(contains(a))'
244 $ log 'min(contains(a))'
245 0
245 0
246 $ log 'merge()'
246 $ log 'merge()'
247 6
247 6
248 $ log 'modifies(b)'
248 $ log 'modifies(b)'
249 4
249 4
250 $ log 'id(5)'
250 $ log 'id(5)'
251 2
251 2
252 $ log 'outgoing()'
252 $ log 'outgoing()'
253 8
253 8
254 9
254 9
255 $ log 'outgoing("../remote1")'
255 $ log 'outgoing("../remote1")'
256 8
256 8
257 9
257 9
258 $ log 'outgoing("../remote2")'
258 $ log 'outgoing("../remote2")'
259 3
259 3
260 5
260 5
261 6
261 6
262 7
262 7
263 9
263 9
264 $ log 'p1(merge())'
264 $ log 'p1(merge())'
265 5
265 5
266 $ log 'p2(merge())'
266 $ log 'p2(merge())'
267 4
267 4
268 $ log 'parents(merge())'
268 $ log 'parents(merge())'
269 4
269 4
270 5
270 5
271 $ log 'removes(a)'
271 $ log 'removes(a)'
272 2
272 2
273 6
273 6
274 $ log 'roots(all())'
274 $ log 'roots(all())'
275 0
275 0
276 $ log 'reverse(2 or 3 or 4 or 5)'
276 $ log 'reverse(2 or 3 or 4 or 5)'
277 5
277 5
278 4
278 4
279 3
279 3
280 2
280 2
281 $ log 'rev(5)'
281 $ log 'rev(5)'
282 5
282 5
283 $ log 'sort(limit(reverse(all()), 3))'
283 $ log 'sort(limit(reverse(all()), 3))'
284 7
284 7
285 8
285 8
286 9
286 9
287 $ log 'sort(2 or 3 or 4 or 5, date)'
287 $ log 'sort(2 or 3 or 4 or 5, date)'
288 2
288 2
289 3
289 3
290 5
290 5
291 4
291 4
292 $ log 'tagged()'
292 $ log 'tagged()'
293 6
293 6
294 $ log 'tag()'
294 $ log 'tag()'
295 6
295 6
296 $ log 'tag(1.0)'
296 $ log 'tag(1.0)'
297 6
297 6
298 $ log 'tag(tip)'
298 $ log 'tag(tip)'
299 9
299 9
300 $ log 'user(bob)'
300 $ log 'user(bob)'
301 2
301 2
302
302
303 $ log '4::8'
303 $ log '4::8'
304 4
304 4
305 8
305 8
306 $ log '4:8'
306 $ log '4:8'
307 4
307 4
308 5
308 5
309 6
309 6
310 7
310 7
311 8
311 8
312
312
313 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
313 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
314 4
314 4
315 2
315 2
316 5
316 5
317
317
318 $ log 'not 0 and 0:2'
318 $ log 'not 0 and 0:2'
319 1
319 1
320 2
320 2
321 $ log 'not 1 and 0:2'
321 $ log 'not 1 and 0:2'
322 0
322 0
323 2
323 2
324 $ log 'not 2 and 0:2'
324 $ log 'not 2 and 0:2'
325 0
325 0
326 1
326 1
327 $ log '(1 and 2)::'
327 $ log '(1 and 2)::'
328 $ log '(1 and 2):'
328 $ log '(1 and 2):'
329 $ log '(1 and 2):3'
329 $ log '(1 and 2):3'
330 $ log 'sort(head(), -rev)'
330 $ log 'sort(head(), -rev)'
331 9
331 9
332 7
332 7
333 6
333 6
334 5
334 5
335 4
335 4
336 3
336 3
337 2
337 2
338 1
338 1
339 0
339 0
340 $ log '4::8 - 8'
340 $ log '4::8 - 8'
341 4
341 4
342
342
343 issue2437
343 issue2437
344
344
345 $ log '3 and p1(5)'
345 $ log '3 and p1(5)'
346 3
346 3
347 $ log '4 and p2(6)'
347 $ log '4 and p2(6)'
348 4
348 4
349 $ log '1 and parents(:2)'
349 $ log '1 and parents(:2)'
350 1
350 1
351 $ log '2 and children(1:)'
351 $ log '2 and children(1:)'
352 2
352 2
353 $ log 'roots(all()) or roots(all())'
353 $ log 'roots(all()) or roots(all())'
354 0
354 0
355 $ log 'heads(branch(é)) or heads(branch(é))'
355 $ log 'heads(branch(é)) or heads(branch(é))'
356 9
356 9
357 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(é)))'
357 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(é)))'
358 4
358 4
359
360 issue2654: report a parse error if the revset was not completely parsed
361
362 $ log '1 OR 2'
363 hg: parse error at 2: invalid token
364 [255]
365
General Comments 0
You need to be logged in to leave comments. Login now