##// END OF EJS Templates
rename util.set_signal_handler to setsignalhandler
Adrian Buehlmann -
r14237:4d684d82 default
parent child Browse files
Show More
@@ -1,4973 +1,4973
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, bin, nullid, nullrev, short
8 from node import hex, bin, 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, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, 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, templatefilters
16 import minirst, revset, templatefilters
17 import dagparser, context, simplemerge
17 import dagparser, context, simplemerge
18 import random, setdiscovery, treediscovery, dagutil
18 import random, setdiscovery, treediscovery, dagutil
19
19
20 # Commands start here, listed alphabetically
20 # Commands start here, listed alphabetically
21
21
22 def add(ui, repo, *pats, **opts):
22 def add(ui, repo, *pats, **opts):
23 """add the specified files on the next commit
23 """add the specified files on the next commit
24
24
25 Schedule files to be version controlled and added to the
25 Schedule files to be version controlled and added to the
26 repository.
26 repository.
27
27
28 The files will be added to the repository at the next commit. To
28 The files will be added to the repository at the next commit. To
29 undo an add before that, see :hg:`forget`.
29 undo an add before that, see :hg:`forget`.
30
30
31 If no names are given, add all files to the repository.
31 If no names are given, add all files to the repository.
32
32
33 .. container:: verbose
33 .. container:: verbose
34
34
35 An example showing how new (unknown) files are added
35 An example showing how new (unknown) files are added
36 automatically by :hg:`add`::
36 automatically by :hg:`add`::
37
37
38 $ ls
38 $ ls
39 foo.c
39 foo.c
40 $ hg status
40 $ hg status
41 ? foo.c
41 ? foo.c
42 $ hg add
42 $ hg add
43 adding foo.c
43 adding foo.c
44 $ hg status
44 $ hg status
45 A foo.c
45 A foo.c
46
46
47 Returns 0 if all files are successfully added.
47 Returns 0 if all files are successfully added.
48 """
48 """
49
49
50 m = cmdutil.match(repo, pats, opts)
50 m = cmdutil.match(repo, pats, opts)
51 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
51 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
52 opts.get('subrepos'), prefix="")
52 opts.get('subrepos'), prefix="")
53 return rejected and 1 or 0
53 return rejected and 1 or 0
54
54
55 def addremove(ui, repo, *pats, **opts):
55 def addremove(ui, repo, *pats, **opts):
56 """add all new files, delete all missing files
56 """add all new files, delete all missing files
57
57
58 Add all new files and remove all missing files from the
58 Add all new files and remove all missing files from the
59 repository.
59 repository.
60
60
61 New files are ignored if they match any of the patterns in
61 New files are ignored if they match any of the patterns in
62 ``.hgignore``. As with add, these changes take effect at the next
62 ``.hgignore``. As with add, these changes take effect at the next
63 commit.
63 commit.
64
64
65 Use the -s/--similarity option to detect renamed files. With a
65 Use the -s/--similarity option to detect renamed files. With a
66 parameter greater than 0, this compares every removed file with
66 parameter greater than 0, this compares every removed file with
67 every added file and records those similar enough as renames. This
67 every added file and records those similar enough as renames. This
68 option takes a percentage between 0 (disabled) and 100 (files must
68 option takes a percentage between 0 (disabled) and 100 (files must
69 be identical) as its parameter. Detecting renamed files this way
69 be identical) as its parameter. Detecting renamed files this way
70 can be expensive. After using this option, :hg:`status -C` can be
70 can be expensive. After using this option, :hg:`status -C` can be
71 used to check which files were identified as moved or renamed.
71 used to check which files were identified as moved or renamed.
72
72
73 Returns 0 if all files are successfully added.
73 Returns 0 if all files are successfully added.
74 """
74 """
75 try:
75 try:
76 sim = float(opts.get('similarity') or 100)
76 sim = float(opts.get('similarity') or 100)
77 except ValueError:
77 except ValueError:
78 raise util.Abort(_('similarity must be a number'))
78 raise util.Abort(_('similarity must be a number'))
79 if sim < 0 or sim > 100:
79 if sim < 0 or sim > 100:
80 raise util.Abort(_('similarity must be between 0 and 100'))
80 raise util.Abort(_('similarity must be between 0 and 100'))
81 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
81 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
82
82
83 def annotate(ui, repo, *pats, **opts):
83 def annotate(ui, repo, *pats, **opts):
84 """show changeset information by line for each file
84 """show changeset information by line for each file
85
85
86 List changes in files, showing the revision id responsible for
86 List changes in files, showing the revision id responsible for
87 each line
87 each line
88
88
89 This command is useful for discovering when a change was made and
89 This command is useful for discovering when a change was made and
90 by whom.
90 by whom.
91
91
92 Without the -a/--text option, annotate will avoid processing files
92 Without the -a/--text option, annotate will avoid processing files
93 it detects as binary. With -a, annotate will annotate the file
93 it detects as binary. With -a, annotate will annotate the file
94 anyway, although the results will probably be neither useful
94 anyway, although the results will probably be neither useful
95 nor desirable.
95 nor desirable.
96
96
97 Returns 0 on success.
97 Returns 0 on success.
98 """
98 """
99 if opts.get('follow'):
99 if opts.get('follow'):
100 # --follow is deprecated and now just an alias for -f/--file
100 # --follow is deprecated and now just an alias for -f/--file
101 # to mimic the behavior of Mercurial before version 1.5
101 # to mimic the behavior of Mercurial before version 1.5
102 opts['file'] = True
102 opts['file'] = True
103
103
104 datefunc = ui.quiet and util.shortdate or util.datestr
104 datefunc = ui.quiet and util.shortdate or util.datestr
105 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
105 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
106
106
107 if not pats:
107 if not pats:
108 raise util.Abort(_('at least one filename or pattern is required'))
108 raise util.Abort(_('at least one filename or pattern is required'))
109
109
110 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
110 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
111 ('number', lambda x: str(x[0].rev())),
111 ('number', lambda x: str(x[0].rev())),
112 ('changeset', lambda x: short(x[0].node())),
112 ('changeset', lambda x: short(x[0].node())),
113 ('date', getdate),
113 ('date', getdate),
114 ('file', lambda x: x[0].path()),
114 ('file', lambda x: x[0].path()),
115 ]
115 ]
116
116
117 if (not opts.get('user') and not opts.get('changeset')
117 if (not opts.get('user') and not opts.get('changeset')
118 and not opts.get('date') and not opts.get('file')):
118 and not opts.get('date') and not opts.get('file')):
119 opts['number'] = True
119 opts['number'] = True
120
120
121 linenumber = opts.get('line_number') is not None
121 linenumber = opts.get('line_number') is not None
122 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
122 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
123 raise util.Abort(_('at least one of -n/-c is required for -l'))
123 raise util.Abort(_('at least one of -n/-c is required for -l'))
124
124
125 funcmap = [func for op, func in opmap if opts.get(op)]
125 funcmap = [func for op, func in opmap if opts.get(op)]
126 if linenumber:
126 if linenumber:
127 lastfunc = funcmap[-1]
127 lastfunc = funcmap[-1]
128 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
128 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
129
129
130 def bad(x, y):
130 def bad(x, y):
131 raise util.Abort("%s: %s" % (x, y))
131 raise util.Abort("%s: %s" % (x, y))
132
132
133 ctx = cmdutil.revsingle(repo, opts.get('rev'))
133 ctx = cmdutil.revsingle(repo, opts.get('rev'))
134 m = cmdutil.match(repo, pats, opts)
134 m = cmdutil.match(repo, pats, opts)
135 m.bad = bad
135 m.bad = bad
136 follow = not opts.get('no_follow')
136 follow = not opts.get('no_follow')
137 for abs in ctx.walk(m):
137 for abs in ctx.walk(m):
138 fctx = ctx[abs]
138 fctx = ctx[abs]
139 if not opts.get('text') and util.binary(fctx.data()):
139 if not opts.get('text') and util.binary(fctx.data()):
140 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
140 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
141 continue
141 continue
142
142
143 lines = fctx.annotate(follow=follow, linenumber=linenumber)
143 lines = fctx.annotate(follow=follow, linenumber=linenumber)
144 pieces = []
144 pieces = []
145
145
146 for f in funcmap:
146 for f in funcmap:
147 l = [f(n) for n, dummy in lines]
147 l = [f(n) for n, dummy in lines]
148 if l:
148 if l:
149 sized = [(x, encoding.colwidth(x)) for x in l]
149 sized = [(x, encoding.colwidth(x)) for x in l]
150 ml = max([w for x, w in sized])
150 ml = max([w for x, w in sized])
151 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
151 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
152
152
153 if pieces:
153 if pieces:
154 for p, l in zip(zip(*pieces), lines):
154 for p, l in zip(zip(*pieces), lines):
155 ui.write("%s: %s" % (" ".join(p), l[1]))
155 ui.write("%s: %s" % (" ".join(p), l[1]))
156
156
157 def archive(ui, repo, dest, **opts):
157 def archive(ui, repo, dest, **opts):
158 '''create an unversioned archive of a repository revision
158 '''create an unversioned archive of a repository revision
159
159
160 By default, the revision used is the parent of the working
160 By default, the revision used is the parent of the working
161 directory; use -r/--rev to specify a different revision.
161 directory; use -r/--rev to specify a different revision.
162
162
163 The archive type is automatically detected based on file
163 The archive type is automatically detected based on file
164 extension (or override using -t/--type).
164 extension (or override using -t/--type).
165
165
166 Valid types are:
166 Valid types are:
167
167
168 :``files``: a directory full of files (default)
168 :``files``: a directory full of files (default)
169 :``tar``: tar archive, uncompressed
169 :``tar``: tar archive, uncompressed
170 :``tbz2``: tar archive, compressed using bzip2
170 :``tbz2``: tar archive, compressed using bzip2
171 :``tgz``: tar archive, compressed using gzip
171 :``tgz``: tar archive, compressed using gzip
172 :``uzip``: zip archive, uncompressed
172 :``uzip``: zip archive, uncompressed
173 :``zip``: zip archive, compressed using deflate
173 :``zip``: zip archive, compressed using deflate
174
174
175 The exact name of the destination archive or directory is given
175 The exact name of the destination archive or directory is given
176 using a format string; see :hg:`help export` for details.
176 using a format string; see :hg:`help export` for details.
177
177
178 Each member added to an archive file has a directory prefix
178 Each member added to an archive file has a directory prefix
179 prepended. Use -p/--prefix to specify a format string for the
179 prepended. Use -p/--prefix to specify a format string for the
180 prefix. The default is the basename of the archive, with suffixes
180 prefix. The default is the basename of the archive, with suffixes
181 removed.
181 removed.
182
182
183 Returns 0 on success.
183 Returns 0 on success.
184 '''
184 '''
185
185
186 ctx = cmdutil.revsingle(repo, opts.get('rev'))
186 ctx = cmdutil.revsingle(repo, opts.get('rev'))
187 if not ctx:
187 if not ctx:
188 raise util.Abort(_('no working directory: please specify a revision'))
188 raise util.Abort(_('no working directory: please specify a revision'))
189 node = ctx.node()
189 node = ctx.node()
190 dest = cmdutil.make_filename(repo, dest, node)
190 dest = cmdutil.make_filename(repo, dest, node)
191 if os.path.realpath(dest) == repo.root:
191 if os.path.realpath(dest) == repo.root:
192 raise util.Abort(_('repository root cannot be destination'))
192 raise util.Abort(_('repository root cannot be destination'))
193
193
194 kind = opts.get('type') or archival.guesskind(dest) or 'files'
194 kind = opts.get('type') or archival.guesskind(dest) or 'files'
195 prefix = opts.get('prefix')
195 prefix = opts.get('prefix')
196
196
197 if dest == '-':
197 if dest == '-':
198 if kind == 'files':
198 if kind == 'files':
199 raise util.Abort(_('cannot archive plain files to stdout'))
199 raise util.Abort(_('cannot archive plain files to stdout'))
200 dest = sys.stdout
200 dest = sys.stdout
201 if not prefix:
201 if not prefix:
202 prefix = os.path.basename(repo.root) + '-%h'
202 prefix = os.path.basename(repo.root) + '-%h'
203
203
204 prefix = cmdutil.make_filename(repo, prefix, node)
204 prefix = cmdutil.make_filename(repo, prefix, node)
205 matchfn = cmdutil.match(repo, [], opts)
205 matchfn = cmdutil.match(repo, [], opts)
206 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
206 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
207 matchfn, prefix, subrepos=opts.get('subrepos'))
207 matchfn, prefix, subrepos=opts.get('subrepos'))
208
208
209 def backout(ui, repo, node=None, rev=None, **opts):
209 def backout(ui, repo, node=None, rev=None, **opts):
210 '''reverse effect of earlier changeset
210 '''reverse effect of earlier changeset
211
211
212 Prepare a new changeset with the effect of REV undone in the
212 Prepare a new changeset with the effect of REV undone in the
213 current working directory.
213 current working directory.
214
214
215 If REV is the parent of the working directory, then this new changeset
215 If REV is the parent of the working directory, then this new changeset
216 is committed automatically. Otherwise, hg needs to merge the
216 is committed automatically. Otherwise, hg needs to merge the
217 changes and the merged result is left uncommitted.
217 changes and the merged result is left uncommitted.
218
218
219 By default, the pending changeset will have one parent,
219 By default, the pending changeset will have one parent,
220 maintaining a linear history. With --merge, the pending changeset
220 maintaining a linear history. With --merge, the pending changeset
221 will instead have two parents: the old parent of the working
221 will instead have two parents: the old parent of the working
222 directory and a new child of REV that simply undoes REV.
222 directory and a new child of REV that simply undoes REV.
223
223
224 Before version 1.7, the behavior without --merge was equivalent to
224 Before version 1.7, the behavior without --merge was equivalent to
225 specifying --merge followed by :hg:`update --clean .` to cancel
225 specifying --merge followed by :hg:`update --clean .` to cancel
226 the merge and leave the child of REV as a head to be merged
226 the merge and leave the child of REV as a head to be merged
227 separately.
227 separately.
228
228
229 See :hg:`help dates` for a list of formats valid for -d/--date.
229 See :hg:`help dates` for a list of formats valid for -d/--date.
230
230
231 Returns 0 on success.
231 Returns 0 on success.
232 '''
232 '''
233 if rev and node:
233 if rev and node:
234 raise util.Abort(_("please specify just one revision"))
234 raise util.Abort(_("please specify just one revision"))
235
235
236 if not rev:
236 if not rev:
237 rev = node
237 rev = node
238
238
239 if not rev:
239 if not rev:
240 raise util.Abort(_("please specify a revision to backout"))
240 raise util.Abort(_("please specify a revision to backout"))
241
241
242 date = opts.get('date')
242 date = opts.get('date')
243 if date:
243 if date:
244 opts['date'] = util.parsedate(date)
244 opts['date'] = util.parsedate(date)
245
245
246 cmdutil.bail_if_changed(repo)
246 cmdutil.bail_if_changed(repo)
247 node = cmdutil.revsingle(repo, rev).node()
247 node = cmdutil.revsingle(repo, rev).node()
248
248
249 op1, op2 = repo.dirstate.parents()
249 op1, op2 = repo.dirstate.parents()
250 a = repo.changelog.ancestor(op1, node)
250 a = repo.changelog.ancestor(op1, node)
251 if a != node:
251 if a != node:
252 raise util.Abort(_('cannot backout change on a different branch'))
252 raise util.Abort(_('cannot backout change on a different branch'))
253
253
254 p1, p2 = repo.changelog.parents(node)
254 p1, p2 = repo.changelog.parents(node)
255 if p1 == nullid:
255 if p1 == nullid:
256 raise util.Abort(_('cannot backout a change with no parents'))
256 raise util.Abort(_('cannot backout a change with no parents'))
257 if p2 != nullid:
257 if p2 != nullid:
258 if not opts.get('parent'):
258 if not opts.get('parent'):
259 raise util.Abort(_('cannot backout a merge changeset without '
259 raise util.Abort(_('cannot backout a merge changeset without '
260 '--parent'))
260 '--parent'))
261 p = repo.lookup(opts['parent'])
261 p = repo.lookup(opts['parent'])
262 if p not in (p1, p2):
262 if p not in (p1, p2):
263 raise util.Abort(_('%s is not a parent of %s') %
263 raise util.Abort(_('%s is not a parent of %s') %
264 (short(p), short(node)))
264 (short(p), short(node)))
265 parent = p
265 parent = p
266 else:
266 else:
267 if opts.get('parent'):
267 if opts.get('parent'):
268 raise util.Abort(_('cannot use --parent on non-merge changeset'))
268 raise util.Abort(_('cannot use --parent on non-merge changeset'))
269 parent = p1
269 parent = p1
270
270
271 # the backout should appear on the same branch
271 # the backout should appear on the same branch
272 branch = repo.dirstate.branch()
272 branch = repo.dirstate.branch()
273 hg.clean(repo, node, show_stats=False)
273 hg.clean(repo, node, show_stats=False)
274 repo.dirstate.setbranch(branch)
274 repo.dirstate.setbranch(branch)
275 revert_opts = opts.copy()
275 revert_opts = opts.copy()
276 revert_opts['date'] = None
276 revert_opts['date'] = None
277 revert_opts['all'] = True
277 revert_opts['all'] = True
278 revert_opts['rev'] = hex(parent)
278 revert_opts['rev'] = hex(parent)
279 revert_opts['no_backup'] = None
279 revert_opts['no_backup'] = None
280 revert(ui, repo, **revert_opts)
280 revert(ui, repo, **revert_opts)
281 if not opts.get('merge') and op1 != node:
281 if not opts.get('merge') and op1 != node:
282 try:
282 try:
283 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
283 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
284 return hg.update(repo, op1)
284 return hg.update(repo, op1)
285 finally:
285 finally:
286 ui.setconfig('ui', 'forcemerge', '')
286 ui.setconfig('ui', 'forcemerge', '')
287
287
288 commit_opts = opts.copy()
288 commit_opts = opts.copy()
289 commit_opts['addremove'] = False
289 commit_opts['addremove'] = False
290 if not commit_opts['message'] and not commit_opts['logfile']:
290 if not commit_opts['message'] and not commit_opts['logfile']:
291 # we don't translate commit messages
291 # we don't translate commit messages
292 commit_opts['message'] = "Backed out changeset %s" % short(node)
292 commit_opts['message'] = "Backed out changeset %s" % short(node)
293 commit_opts['force_editor'] = True
293 commit_opts['force_editor'] = True
294 commit(ui, repo, **commit_opts)
294 commit(ui, repo, **commit_opts)
295 def nice(node):
295 def nice(node):
296 return '%d:%s' % (repo.changelog.rev(node), short(node))
296 return '%d:%s' % (repo.changelog.rev(node), short(node))
297 ui.status(_('changeset %s backs out changeset %s\n') %
297 ui.status(_('changeset %s backs out changeset %s\n') %
298 (nice(repo.changelog.tip()), nice(node)))
298 (nice(repo.changelog.tip()), nice(node)))
299 if opts.get('merge') and op1 != node:
299 if opts.get('merge') and op1 != node:
300 hg.clean(repo, op1, show_stats=False)
300 hg.clean(repo, op1, show_stats=False)
301 ui.status(_('merging with changeset %s\n')
301 ui.status(_('merging with changeset %s\n')
302 % nice(repo.changelog.tip()))
302 % nice(repo.changelog.tip()))
303 try:
303 try:
304 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
304 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
305 return hg.merge(repo, hex(repo.changelog.tip()))
305 return hg.merge(repo, hex(repo.changelog.tip()))
306 finally:
306 finally:
307 ui.setconfig('ui', 'forcemerge', '')
307 ui.setconfig('ui', 'forcemerge', '')
308 return 0
308 return 0
309
309
310 def bisect(ui, repo, rev=None, extra=None, command=None,
310 def bisect(ui, repo, rev=None, extra=None, command=None,
311 reset=None, good=None, bad=None, skip=None, extend=None,
311 reset=None, good=None, bad=None, skip=None, extend=None,
312 noupdate=None):
312 noupdate=None):
313 """subdivision search of changesets
313 """subdivision search of changesets
314
314
315 This command helps to find changesets which introduce problems. To
315 This command helps to find changesets which introduce problems. To
316 use, mark the earliest changeset you know exhibits the problem as
316 use, mark the earliest changeset you know exhibits the problem as
317 bad, then mark the latest changeset which is free from the problem
317 bad, then mark the latest changeset which is free from the problem
318 as good. Bisect will update your working directory to a revision
318 as good. Bisect will update your working directory to a revision
319 for testing (unless the -U/--noupdate option is specified). Once
319 for testing (unless the -U/--noupdate option is specified). Once
320 you have performed tests, mark the working directory as good or
320 you have performed tests, mark the working directory as good or
321 bad, and bisect will either update to another candidate changeset
321 bad, and bisect will either update to another candidate changeset
322 or announce that it has found the bad revision.
322 or announce that it has found the bad revision.
323
323
324 As a shortcut, you can also use the revision argument to mark a
324 As a shortcut, you can also use the revision argument to mark a
325 revision as good or bad without checking it out first.
325 revision as good or bad without checking it out first.
326
326
327 If you supply a command, it will be used for automatic bisection.
327 If you supply a command, it will be used for automatic bisection.
328 Its exit status will be used to mark revisions as good or bad:
328 Its exit status will be used to mark revisions as good or bad:
329 status 0 means good, 125 means to skip the revision, 127
329 status 0 means good, 125 means to skip the revision, 127
330 (command not found) will abort the bisection, and any other
330 (command not found) will abort the bisection, and any other
331 non-zero exit status means the revision is bad.
331 non-zero exit status means the revision is bad.
332
332
333 Returns 0 on success.
333 Returns 0 on success.
334 """
334 """
335 def extendbisectrange(nodes, good):
335 def extendbisectrange(nodes, good):
336 # bisect is incomplete when it ends on a merge node and
336 # bisect is incomplete when it ends on a merge node and
337 # one of the parent was not checked.
337 # one of the parent was not checked.
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 return parents[0].ancestor(parents[1])
343 return parents[0].ancestor(parents[1])
344 return None
344 return None
345
345
346 def print_result(nodes, good):
346 def print_result(nodes, good):
347 displayer = cmdutil.show_changeset(ui, repo, {})
347 displayer = cmdutil.show_changeset(ui, repo, {})
348 if len(nodes) == 1:
348 if len(nodes) == 1:
349 # narrowed it down to a single revision
349 # narrowed it down to a single revision
350 if good:
350 if good:
351 ui.write(_("The first good revision is:\n"))
351 ui.write(_("The first good revision is:\n"))
352 else:
352 else:
353 ui.write(_("The first bad revision is:\n"))
353 ui.write(_("The first bad revision is:\n"))
354 displayer.show(repo[nodes[0]])
354 displayer.show(repo[nodes[0]])
355 extendnode = extendbisectrange(nodes, good)
355 extendnode = extendbisectrange(nodes, good)
356 if extendnode is not None:
356 if extendnode is not None:
357 ui.write(_('Not all ancestors of this changeset have been'
357 ui.write(_('Not all ancestors of this changeset have been'
358 ' checked.\nUse bisect --extend to continue the '
358 ' checked.\nUse bisect --extend to continue the '
359 'bisection from\nthe common ancestor, %s.\n')
359 'bisection from\nthe common ancestor, %s.\n')
360 % extendnode)
360 % extendnode)
361 else:
361 else:
362 # multiple possible revisions
362 # multiple possible revisions
363 if good:
363 if good:
364 ui.write(_("Due to skipped revisions, the first "
364 ui.write(_("Due to skipped revisions, the first "
365 "good revision could be any of:\n"))
365 "good revision could be any of:\n"))
366 else:
366 else:
367 ui.write(_("Due to skipped revisions, the first "
367 ui.write(_("Due to skipped revisions, the first "
368 "bad revision could be any of:\n"))
368 "bad revision could be any of:\n"))
369 for n in nodes:
369 for n in nodes:
370 displayer.show(repo[n])
370 displayer.show(repo[n])
371 displayer.close()
371 displayer.close()
372
372
373 def check_state(state, interactive=True):
373 def check_state(state, interactive=True):
374 if not state['good'] or not state['bad']:
374 if not state['good'] or not state['bad']:
375 if (good or bad or skip or reset) and interactive:
375 if (good or bad or skip or reset) and interactive:
376 return
376 return
377 if not state['good']:
377 if not state['good']:
378 raise util.Abort(_('cannot bisect (no known good revisions)'))
378 raise util.Abort(_('cannot bisect (no known good revisions)'))
379 else:
379 else:
380 raise util.Abort(_('cannot bisect (no known bad revisions)'))
380 raise util.Abort(_('cannot bisect (no known bad revisions)'))
381 return True
381 return True
382
382
383 # backward compatibility
383 # backward compatibility
384 if rev in "good bad reset init".split():
384 if rev in "good bad reset init".split():
385 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
385 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
386 cmd, rev, extra = rev, extra, None
386 cmd, rev, extra = rev, extra, None
387 if cmd == "good":
387 if cmd == "good":
388 good = True
388 good = True
389 elif cmd == "bad":
389 elif cmd == "bad":
390 bad = True
390 bad = True
391 else:
391 else:
392 reset = True
392 reset = True
393 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
393 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
394 raise util.Abort(_('incompatible arguments'))
394 raise util.Abort(_('incompatible arguments'))
395
395
396 if reset:
396 if reset:
397 p = repo.join("bisect.state")
397 p = repo.join("bisect.state")
398 if os.path.exists(p):
398 if os.path.exists(p):
399 os.unlink(p)
399 os.unlink(p)
400 return
400 return
401
401
402 state = hbisect.load_state(repo)
402 state = hbisect.load_state(repo)
403
403
404 if command:
404 if command:
405 changesets = 1
405 changesets = 1
406 try:
406 try:
407 while changesets:
407 while changesets:
408 # update state
408 # update state
409 status = util.system(command)
409 status = util.system(command)
410 if status == 125:
410 if status == 125:
411 transition = "skip"
411 transition = "skip"
412 elif status == 0:
412 elif status == 0:
413 transition = "good"
413 transition = "good"
414 # status < 0 means process was killed
414 # status < 0 means process was killed
415 elif status == 127:
415 elif status == 127:
416 raise util.Abort(_("failed to execute %s") % command)
416 raise util.Abort(_("failed to execute %s") % command)
417 elif status < 0:
417 elif status < 0:
418 raise util.Abort(_("%s killed") % command)
418 raise util.Abort(_("%s killed") % command)
419 else:
419 else:
420 transition = "bad"
420 transition = "bad"
421 ctx = cmdutil.revsingle(repo, rev)
421 ctx = cmdutil.revsingle(repo, rev)
422 rev = None # clear for future iterations
422 rev = None # clear for future iterations
423 state[transition].append(ctx.node())
423 state[transition].append(ctx.node())
424 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
424 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
425 check_state(state, interactive=False)
425 check_state(state, interactive=False)
426 # bisect
426 # bisect
427 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
427 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
428 # update to next check
428 # update to next check
429 cmdutil.bail_if_changed(repo)
429 cmdutil.bail_if_changed(repo)
430 hg.clean(repo, nodes[0], show_stats=False)
430 hg.clean(repo, nodes[0], show_stats=False)
431 finally:
431 finally:
432 hbisect.save_state(repo, state)
432 hbisect.save_state(repo, state)
433 print_result(nodes, good)
433 print_result(nodes, good)
434 return
434 return
435
435
436 # update state
436 # update state
437
437
438 if rev:
438 if rev:
439 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
439 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
440 else:
440 else:
441 nodes = [repo.lookup('.')]
441 nodes = [repo.lookup('.')]
442
442
443 if good or bad or skip:
443 if good or bad or skip:
444 if good:
444 if good:
445 state['good'] += nodes
445 state['good'] += nodes
446 elif bad:
446 elif bad:
447 state['bad'] += nodes
447 state['bad'] += nodes
448 elif skip:
448 elif skip:
449 state['skip'] += nodes
449 state['skip'] += nodes
450 hbisect.save_state(repo, state)
450 hbisect.save_state(repo, state)
451
451
452 if not check_state(state):
452 if not check_state(state):
453 return
453 return
454
454
455 # actually bisect
455 # actually bisect
456 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
456 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
457 if extend:
457 if extend:
458 if not changesets:
458 if not changesets:
459 extendnode = extendbisectrange(nodes, good)
459 extendnode = extendbisectrange(nodes, good)
460 if extendnode is not None:
460 if extendnode is not None:
461 ui.write(_("Extending search to changeset %d:%s\n"
461 ui.write(_("Extending search to changeset %d:%s\n"
462 % (extendnode.rev(), extendnode)))
462 % (extendnode.rev(), extendnode)))
463 if noupdate:
463 if noupdate:
464 return
464 return
465 cmdutil.bail_if_changed(repo)
465 cmdutil.bail_if_changed(repo)
466 return hg.clean(repo, extendnode.node())
466 return hg.clean(repo, extendnode.node())
467 raise util.Abort(_("nothing to extend"))
467 raise util.Abort(_("nothing to extend"))
468
468
469 if changesets == 0:
469 if changesets == 0:
470 print_result(nodes, good)
470 print_result(nodes, good)
471 else:
471 else:
472 assert len(nodes) == 1 # only a single node can be tested next
472 assert len(nodes) == 1 # only a single node can be tested next
473 node = nodes[0]
473 node = nodes[0]
474 # compute the approximate number of remaining tests
474 # compute the approximate number of remaining tests
475 tests, size = 0, 2
475 tests, size = 0, 2
476 while size <= changesets:
476 while size <= changesets:
477 tests, size = tests + 1, size * 2
477 tests, size = tests + 1, size * 2
478 rev = repo.changelog.rev(node)
478 rev = repo.changelog.rev(node)
479 ui.write(_("Testing changeset %d:%s "
479 ui.write(_("Testing changeset %d:%s "
480 "(%d changesets remaining, ~%d tests)\n")
480 "(%d changesets remaining, ~%d tests)\n")
481 % (rev, short(node), changesets, tests))
481 % (rev, short(node), changesets, tests))
482 if not noupdate:
482 if not noupdate:
483 cmdutil.bail_if_changed(repo)
483 cmdutil.bail_if_changed(repo)
484 return hg.clean(repo, node)
484 return hg.clean(repo, node)
485
485
486 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
486 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
487 rename=None, inactive=False):
487 rename=None, inactive=False):
488 '''track a line of development with movable markers
488 '''track a line of development with movable markers
489
489
490 Bookmarks are pointers to certain commits that move when
490 Bookmarks are pointers to certain commits that move when
491 committing. Bookmarks are local. They can be renamed, copied and
491 committing. Bookmarks are local. They can be renamed, copied and
492 deleted. It is possible to use bookmark names in :hg:`merge` and
492 deleted. It is possible to use bookmark names in :hg:`merge` and
493 :hg:`update` to merge and update respectively to a given bookmark.
493 :hg:`update` to merge and update respectively to a given bookmark.
494
494
495 You can use :hg:`bookmark NAME` to set a bookmark on the working
495 You can use :hg:`bookmark NAME` to set a bookmark on the working
496 directory's parent revision with the given name. If you specify
496 directory's parent revision with the given name. If you specify
497 a revision using -r REV (where REV may be an existing bookmark),
497 a revision using -r REV (where REV may be an existing bookmark),
498 the bookmark is assigned to that revision.
498 the bookmark is assigned to that revision.
499
499
500 Bookmarks can be pushed and pulled between repositories (see :hg:`help
500 Bookmarks can be pushed and pulled between repositories (see :hg:`help
501 push` and :hg:`help pull`). This requires both the local and remote
501 push` and :hg:`help pull`). This requires both the local and remote
502 repositories to support bookmarks. For versions prior to 1.8, this means
502 repositories to support bookmarks. For versions prior to 1.8, this means
503 the bookmarks extension must be enabled.
503 the bookmarks extension must be enabled.
504 '''
504 '''
505 hexfn = ui.debugflag and hex or short
505 hexfn = ui.debugflag and hex or short
506 marks = repo._bookmarks
506 marks = repo._bookmarks
507 cur = repo.changectx('.').node()
507 cur = repo.changectx('.').node()
508
508
509 if rename:
509 if rename:
510 if rename not in marks:
510 if rename not in marks:
511 raise util.Abort(_("bookmark '%s' does not exist") % rename)
511 raise util.Abort(_("bookmark '%s' does not exist") % rename)
512 if mark in marks and not force:
512 if mark in marks and not force:
513 raise util.Abort(_("bookmark '%s' already exists "
513 raise util.Abort(_("bookmark '%s' already exists "
514 "(use -f to force)") % mark)
514 "(use -f to force)") % mark)
515 if mark is None:
515 if mark is None:
516 raise util.Abort(_("new bookmark name required"))
516 raise util.Abort(_("new bookmark name required"))
517 marks[mark] = marks[rename]
517 marks[mark] = marks[rename]
518 if repo._bookmarkcurrent == rename and not inactive:
518 if repo._bookmarkcurrent == rename and not inactive:
519 bookmarks.setcurrent(repo, mark)
519 bookmarks.setcurrent(repo, mark)
520 del marks[rename]
520 del marks[rename]
521 bookmarks.write(repo)
521 bookmarks.write(repo)
522 return
522 return
523
523
524 if delete:
524 if delete:
525 if mark is None:
525 if mark is None:
526 raise util.Abort(_("bookmark name required"))
526 raise util.Abort(_("bookmark name required"))
527 if mark not in marks:
527 if mark not in marks:
528 raise util.Abort(_("bookmark '%s' does not exist") % mark)
528 raise util.Abort(_("bookmark '%s' does not exist") % mark)
529 if mark == repo._bookmarkcurrent:
529 if mark == repo._bookmarkcurrent:
530 bookmarks.setcurrent(repo, None)
530 bookmarks.setcurrent(repo, None)
531 del marks[mark]
531 del marks[mark]
532 bookmarks.write(repo)
532 bookmarks.write(repo)
533 return
533 return
534
534
535 if mark is not None:
535 if mark is not None:
536 if "\n" in mark:
536 if "\n" in mark:
537 raise util.Abort(_("bookmark name cannot contain newlines"))
537 raise util.Abort(_("bookmark name cannot contain newlines"))
538 mark = mark.strip()
538 mark = mark.strip()
539 if not mark:
539 if not mark:
540 raise util.Abort(_("bookmark names cannot consist entirely of "
540 raise util.Abort(_("bookmark names cannot consist entirely of "
541 "whitespace"))
541 "whitespace"))
542 if inactive and mark == repo._bookmarkcurrent:
542 if inactive and mark == repo._bookmarkcurrent:
543 bookmarks.setcurrent(repo, None)
543 bookmarks.setcurrent(repo, None)
544 return
544 return
545 if mark in marks and not force:
545 if mark in marks and not force:
546 raise util.Abort(_("bookmark '%s' already exists "
546 raise util.Abort(_("bookmark '%s' already exists "
547 "(use -f to force)") % mark)
547 "(use -f to force)") % mark)
548 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
548 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
549 and not force):
549 and not force):
550 raise util.Abort(
550 raise util.Abort(
551 _("a bookmark cannot have the name of an existing branch"))
551 _("a bookmark cannot have the name of an existing branch"))
552 if rev:
552 if rev:
553 marks[mark] = repo.lookup(rev)
553 marks[mark] = repo.lookup(rev)
554 else:
554 else:
555 marks[mark] = repo.changectx('.').node()
555 marks[mark] = repo.changectx('.').node()
556 if not inactive and repo.changectx('.').node() == marks[mark]:
556 if not inactive and repo.changectx('.').node() == marks[mark]:
557 bookmarks.setcurrent(repo, mark)
557 bookmarks.setcurrent(repo, mark)
558 bookmarks.write(repo)
558 bookmarks.write(repo)
559 return
559 return
560
560
561 if mark is None:
561 if mark is None:
562 if rev:
562 if rev:
563 raise util.Abort(_("bookmark name required"))
563 raise util.Abort(_("bookmark name required"))
564 if len(marks) == 0:
564 if len(marks) == 0:
565 ui.status(_("no bookmarks set\n"))
565 ui.status(_("no bookmarks set\n"))
566 else:
566 else:
567 for bmark, n in sorted(marks.iteritems()):
567 for bmark, n in sorted(marks.iteritems()):
568 current = repo._bookmarkcurrent
568 current = repo._bookmarkcurrent
569 if bmark == current and n == cur:
569 if bmark == current and n == cur:
570 prefix, label = '*', 'bookmarks.current'
570 prefix, label = '*', 'bookmarks.current'
571 else:
571 else:
572 prefix, label = ' ', ''
572 prefix, label = ' ', ''
573
573
574 if ui.quiet:
574 if ui.quiet:
575 ui.write("%s\n" % bmark, label=label)
575 ui.write("%s\n" % bmark, label=label)
576 else:
576 else:
577 ui.write(" %s %-25s %d:%s\n" % (
577 ui.write(" %s %-25s %d:%s\n" % (
578 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
578 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
579 label=label)
579 label=label)
580 return
580 return
581
581
582 def branch(ui, repo, label=None, **opts):
582 def branch(ui, repo, label=None, **opts):
583 """set or show the current branch name
583 """set or show the current branch name
584
584
585 With no argument, show the current branch name. With one argument,
585 With no argument, show the current branch name. With one argument,
586 set the working directory branch name (the branch will not exist
586 set the working directory branch name (the branch will not exist
587 in the repository until the next commit). Standard practice
587 in the repository until the next commit). Standard practice
588 recommends that primary development take place on the 'default'
588 recommends that primary development take place on the 'default'
589 branch.
589 branch.
590
590
591 Unless -f/--force is specified, branch will not let you set a
591 Unless -f/--force is specified, branch will not let you set a
592 branch name that already exists, even if it's inactive.
592 branch name that already exists, even if it's inactive.
593
593
594 Use -C/--clean to reset the working directory branch to that of
594 Use -C/--clean to reset the working directory branch to that of
595 the parent of the working directory, negating a previous branch
595 the parent of the working directory, negating a previous branch
596 change.
596 change.
597
597
598 Use the command :hg:`update` to switch to an existing branch. Use
598 Use the command :hg:`update` to switch to an existing branch. Use
599 :hg:`commit --close-branch` to mark this branch as closed.
599 :hg:`commit --close-branch` to mark this branch as closed.
600
600
601 Returns 0 on success.
601 Returns 0 on success.
602 """
602 """
603
603
604 if opts.get('clean'):
604 if opts.get('clean'):
605 label = repo[None].p1().branch()
605 label = repo[None].p1().branch()
606 repo.dirstate.setbranch(label)
606 repo.dirstate.setbranch(label)
607 ui.status(_('reset working directory to branch %s\n') % label)
607 ui.status(_('reset working directory to branch %s\n') % label)
608 elif label:
608 elif label:
609 if not opts.get('force') and label in repo.branchtags():
609 if not opts.get('force') and label in repo.branchtags():
610 if label not in [p.branch() for p in repo.parents()]:
610 if label not in [p.branch() for p in repo.parents()]:
611 raise util.Abort(_('a branch of the same name already exists'),
611 raise util.Abort(_('a branch of the same name already exists'),
612 hint=_("use 'hg update' to switch to it"))
612 hint=_("use 'hg update' to switch to it"))
613 repo.dirstate.setbranch(label)
613 repo.dirstate.setbranch(label)
614 ui.status(_('marked working directory as branch %s\n') % label)
614 ui.status(_('marked working directory as branch %s\n') % label)
615 else:
615 else:
616 ui.write("%s\n" % repo.dirstate.branch())
616 ui.write("%s\n" % repo.dirstate.branch())
617
617
618 def branches(ui, repo, active=False, closed=False):
618 def branches(ui, repo, active=False, closed=False):
619 """list repository named branches
619 """list repository named branches
620
620
621 List the repository's named branches, indicating which ones are
621 List the repository's named branches, indicating which ones are
622 inactive. If -c/--closed is specified, also list branches which have
622 inactive. If -c/--closed is specified, also list branches which have
623 been marked closed (see :hg:`commit --close-branch`).
623 been marked closed (see :hg:`commit --close-branch`).
624
624
625 If -a/--active is specified, only show active branches. A branch
625 If -a/--active is specified, only show active branches. A branch
626 is considered active if it contains repository heads.
626 is considered active if it contains repository heads.
627
627
628 Use the command :hg:`update` to switch to an existing branch.
628 Use the command :hg:`update` to switch to an existing branch.
629
629
630 Returns 0.
630 Returns 0.
631 """
631 """
632
632
633 hexfunc = ui.debugflag and hex or short
633 hexfunc = ui.debugflag and hex or short
634 activebranches = [repo[n].branch() for n in repo.heads()]
634 activebranches = [repo[n].branch() for n in repo.heads()]
635 def testactive(tag, node):
635 def testactive(tag, node):
636 realhead = tag in activebranches
636 realhead = tag in activebranches
637 open = node in repo.branchheads(tag, closed=False)
637 open = node in repo.branchheads(tag, closed=False)
638 return realhead and open
638 return realhead and open
639 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
639 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
640 for tag, node in repo.branchtags().items()],
640 for tag, node in repo.branchtags().items()],
641 reverse=True)
641 reverse=True)
642
642
643 for isactive, node, tag in branches:
643 for isactive, node, tag in branches:
644 if (not active) or isactive:
644 if (not active) or isactive:
645 if ui.quiet:
645 if ui.quiet:
646 ui.write("%s\n" % tag)
646 ui.write("%s\n" % tag)
647 else:
647 else:
648 hn = repo.lookup(node)
648 hn = repo.lookup(node)
649 if isactive:
649 if isactive:
650 label = 'branches.active'
650 label = 'branches.active'
651 notice = ''
651 notice = ''
652 elif hn not in repo.branchheads(tag, closed=False):
652 elif hn not in repo.branchheads(tag, closed=False):
653 if not closed:
653 if not closed:
654 continue
654 continue
655 label = 'branches.closed'
655 label = 'branches.closed'
656 notice = _(' (closed)')
656 notice = _(' (closed)')
657 else:
657 else:
658 label = 'branches.inactive'
658 label = 'branches.inactive'
659 notice = _(' (inactive)')
659 notice = _(' (inactive)')
660 if tag == repo.dirstate.branch():
660 if tag == repo.dirstate.branch():
661 label = 'branches.current'
661 label = 'branches.current'
662 rev = str(node).rjust(31 - encoding.colwidth(tag))
662 rev = str(node).rjust(31 - encoding.colwidth(tag))
663 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
663 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
664 tag = ui.label(tag, label)
664 tag = ui.label(tag, label)
665 ui.write("%s %s%s\n" % (tag, rev, notice))
665 ui.write("%s %s%s\n" % (tag, rev, notice))
666
666
667 def bundle(ui, repo, fname, dest=None, **opts):
667 def bundle(ui, repo, fname, dest=None, **opts):
668 """create a changegroup file
668 """create a changegroup file
669
669
670 Generate a compressed changegroup file collecting changesets not
670 Generate a compressed changegroup file collecting changesets not
671 known to be in another repository.
671 known to be in another repository.
672
672
673 If you omit the destination repository, then hg assumes the
673 If you omit the destination repository, then hg assumes the
674 destination will have all the nodes you specify with --base
674 destination will have all the nodes you specify with --base
675 parameters. To create a bundle containing all changesets, use
675 parameters. To create a bundle containing all changesets, use
676 -a/--all (or --base null).
676 -a/--all (or --base null).
677
677
678 You can change compression method with the -t/--type option.
678 You can change compression method with the -t/--type option.
679 The available compression methods are: none, bzip2, and
679 The available compression methods are: none, bzip2, and
680 gzip (by default, bundles are compressed using bzip2).
680 gzip (by default, bundles are compressed using bzip2).
681
681
682 The bundle file can then be transferred using conventional means
682 The bundle file can then be transferred using conventional means
683 and applied to another repository with the unbundle or pull
683 and applied to another repository with the unbundle or pull
684 command. This is useful when direct push and pull are not
684 command. This is useful when direct push and pull are not
685 available or when exporting an entire repository is undesirable.
685 available or when exporting an entire repository is undesirable.
686
686
687 Applying bundles preserves all changeset contents including
687 Applying bundles preserves all changeset contents including
688 permissions, copy/rename information, and revision history.
688 permissions, copy/rename information, and revision history.
689
689
690 Returns 0 on success, 1 if no changes found.
690 Returns 0 on success, 1 if no changes found.
691 """
691 """
692 revs = None
692 revs = None
693 if 'rev' in opts:
693 if 'rev' in opts:
694 revs = cmdutil.revrange(repo, opts['rev'])
694 revs = cmdutil.revrange(repo, opts['rev'])
695
695
696 if opts.get('all'):
696 if opts.get('all'):
697 base = ['null']
697 base = ['null']
698 else:
698 else:
699 base = cmdutil.revrange(repo, opts.get('base'))
699 base = cmdutil.revrange(repo, opts.get('base'))
700 if base:
700 if base:
701 if dest:
701 if dest:
702 raise util.Abort(_("--base is incompatible with specifying "
702 raise util.Abort(_("--base is incompatible with specifying "
703 "a destination"))
703 "a destination"))
704 common = [repo.lookup(rev) for rev in base]
704 common = [repo.lookup(rev) for rev in base]
705 else:
705 else:
706 dest = ui.expandpath(dest or 'default-push', dest or 'default')
706 dest = ui.expandpath(dest or 'default-push', dest or 'default')
707 dest, branches = hg.parseurl(dest, opts.get('branch'))
707 dest, branches = hg.parseurl(dest, opts.get('branch'))
708 other = hg.repository(hg.remoteui(repo, opts), dest)
708 other = hg.repository(hg.remoteui(repo, opts), dest)
709 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
709 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
710 inc = discovery.findcommonincoming(repo, other, force=opts.get('force'))
710 inc = discovery.findcommonincoming(repo, other, force=opts.get('force'))
711 common, _anyinc, _heads = inc
711 common, _anyinc, _heads = inc
712
712
713 nodes = revs and map(repo.lookup, revs) or revs
713 nodes = revs and map(repo.lookup, revs) or revs
714 cg = repo.getbundle('bundle', common=common, heads=nodes)
714 cg = repo.getbundle('bundle', common=common, heads=nodes)
715 if not cg:
715 if not cg:
716 ui.status(_("no changes found\n"))
716 ui.status(_("no changes found\n"))
717 return 1
717 return 1
718
718
719 bundletype = opts.get('type', 'bzip2').lower()
719 bundletype = opts.get('type', 'bzip2').lower()
720 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
720 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
721 bundletype = btypes.get(bundletype)
721 bundletype = btypes.get(bundletype)
722 if bundletype not in changegroup.bundletypes:
722 if bundletype not in changegroup.bundletypes:
723 raise util.Abort(_('unknown bundle type specified with --type'))
723 raise util.Abort(_('unknown bundle type specified with --type'))
724
724
725 changegroup.writebundle(cg, fname, bundletype)
725 changegroup.writebundle(cg, fname, bundletype)
726
726
727 def cat(ui, repo, file1, *pats, **opts):
727 def cat(ui, repo, file1, *pats, **opts):
728 """output the current or given revision of files
728 """output the current or given revision of files
729
729
730 Print the specified files as they were at the given revision. If
730 Print the specified files as they were at the given revision. If
731 no revision is given, the parent of the working directory is used,
731 no revision is given, the parent of the working directory is used,
732 or tip if no revision is checked out.
732 or tip if no revision is checked out.
733
733
734 Output may be to a file, in which case the name of the file is
734 Output may be to a file, in which case the name of the file is
735 given using a format string. The formatting rules are the same as
735 given using a format string. The formatting rules are the same as
736 for the export command, with the following additions:
736 for the export command, with the following additions:
737
737
738 :``%s``: basename of file being printed
738 :``%s``: basename of file being printed
739 :``%d``: dirname of file being printed, or '.' if in repository root
739 :``%d``: dirname of file being printed, or '.' if in repository root
740 :``%p``: root-relative path name of file being printed
740 :``%p``: root-relative path name of file being printed
741
741
742 Returns 0 on success.
742 Returns 0 on success.
743 """
743 """
744 ctx = cmdutil.revsingle(repo, opts.get('rev'))
744 ctx = cmdutil.revsingle(repo, opts.get('rev'))
745 err = 1
745 err = 1
746 m = cmdutil.match(repo, (file1,) + pats, opts)
746 m = cmdutil.match(repo, (file1,) + pats, opts)
747 for abs in ctx.walk(m):
747 for abs in ctx.walk(m):
748 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
748 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
749 data = ctx[abs].data()
749 data = ctx[abs].data()
750 if opts.get('decode'):
750 if opts.get('decode'):
751 data = repo.wwritedata(abs, data)
751 data = repo.wwritedata(abs, data)
752 fp.write(data)
752 fp.write(data)
753 fp.close()
753 fp.close()
754 err = 0
754 err = 0
755 return err
755 return err
756
756
757 def clone(ui, source, dest=None, **opts):
757 def clone(ui, source, dest=None, **opts):
758 """make a copy of an existing repository
758 """make a copy of an existing repository
759
759
760 Create a copy of an existing repository in a new directory.
760 Create a copy of an existing repository in a new directory.
761
761
762 If no destination directory name is specified, it defaults to the
762 If no destination directory name is specified, it defaults to the
763 basename of the source.
763 basename of the source.
764
764
765 The location of the source is added to the new repository's
765 The location of the source is added to the new repository's
766 ``.hg/hgrc`` file, as the default to be used for future pulls.
766 ``.hg/hgrc`` file, as the default to be used for future pulls.
767
767
768 See :hg:`help urls` for valid source format details.
768 See :hg:`help urls` for valid source format details.
769
769
770 It is possible to specify an ``ssh://`` URL as the destination, but no
770 It is possible to specify an ``ssh://`` URL as the destination, but no
771 ``.hg/hgrc`` and working directory will be created on the remote side.
771 ``.hg/hgrc`` and working directory will be created on the remote side.
772 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
772 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
773
773
774 A set of changesets (tags, or branch names) to pull may be specified
774 A set of changesets (tags, or branch names) to pull may be specified
775 by listing each changeset (tag, or branch name) with -r/--rev.
775 by listing each changeset (tag, or branch name) with -r/--rev.
776 If -r/--rev is used, the cloned repository will contain only a subset
776 If -r/--rev is used, the cloned repository will contain only a subset
777 of the changesets of the source repository. Only the set of changesets
777 of the changesets of the source repository. Only the set of changesets
778 defined by all -r/--rev options (including all their ancestors)
778 defined by all -r/--rev options (including all their ancestors)
779 will be pulled into the destination repository.
779 will be pulled into the destination repository.
780 No subsequent changesets (including subsequent tags) will be present
780 No subsequent changesets (including subsequent tags) will be present
781 in the destination.
781 in the destination.
782
782
783 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
783 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
784 local source repositories.
784 local source repositories.
785
785
786 For efficiency, hardlinks are used for cloning whenever the source
786 For efficiency, hardlinks are used for cloning whenever the source
787 and destination are on the same filesystem (note this applies only
787 and destination are on the same filesystem (note this applies only
788 to the repository data, not to the working directory). Some
788 to the repository data, not to the working directory). Some
789 filesystems, such as AFS, implement hardlinking incorrectly, but
789 filesystems, such as AFS, implement hardlinking incorrectly, but
790 do not report errors. In these cases, use the --pull option to
790 do not report errors. In these cases, use the --pull option to
791 avoid hardlinking.
791 avoid hardlinking.
792
792
793 In some cases, you can clone repositories and the working directory
793 In some cases, you can clone repositories and the working directory
794 using full hardlinks with ::
794 using full hardlinks with ::
795
795
796 $ cp -al REPO REPOCLONE
796 $ cp -al REPO REPOCLONE
797
797
798 This is the fastest way to clone, but it is not always safe. The
798 This is the fastest way to clone, but it is not always safe. The
799 operation is not atomic (making sure REPO is not modified during
799 operation is not atomic (making sure REPO is not modified during
800 the operation is up to you) and you have to make sure your editor
800 the operation is up to you) and you have to make sure your editor
801 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
801 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
802 this is not compatible with certain extensions that place their
802 this is not compatible with certain extensions that place their
803 metadata under the .hg directory, such as mq.
803 metadata under the .hg directory, such as mq.
804
804
805 Mercurial will update the working directory to the first applicable
805 Mercurial will update the working directory to the first applicable
806 revision from this list:
806 revision from this list:
807
807
808 a) null if -U or the source repository has no changesets
808 a) null if -U or the source repository has no changesets
809 b) if -u . and the source repository is local, the first parent of
809 b) if -u . and the source repository is local, the first parent of
810 the source repository's working directory
810 the source repository's working directory
811 c) the changeset specified with -u (if a branch name, this means the
811 c) the changeset specified with -u (if a branch name, this means the
812 latest head of that branch)
812 latest head of that branch)
813 d) the changeset specified with -r
813 d) the changeset specified with -r
814 e) the tipmost head specified with -b
814 e) the tipmost head specified with -b
815 f) the tipmost head specified with the url#branch source syntax
815 f) the tipmost head specified with the url#branch source syntax
816 g) the tipmost head of the default branch
816 g) the tipmost head of the default branch
817 h) tip
817 h) tip
818
818
819 Returns 0 on success.
819 Returns 0 on success.
820 """
820 """
821 if opts.get('noupdate') and opts.get('updaterev'):
821 if opts.get('noupdate') and opts.get('updaterev'):
822 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
822 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
823
823
824 r = hg.clone(hg.remoteui(ui, opts), source, dest,
824 r = hg.clone(hg.remoteui(ui, opts), source, dest,
825 pull=opts.get('pull'),
825 pull=opts.get('pull'),
826 stream=opts.get('uncompressed'),
826 stream=opts.get('uncompressed'),
827 rev=opts.get('rev'),
827 rev=opts.get('rev'),
828 update=opts.get('updaterev') or not opts.get('noupdate'),
828 update=opts.get('updaterev') or not opts.get('noupdate'),
829 branch=opts.get('branch'))
829 branch=opts.get('branch'))
830
830
831 return r is None
831 return r is None
832
832
833 def commit(ui, repo, *pats, **opts):
833 def commit(ui, repo, *pats, **opts):
834 """commit the specified files or all outstanding changes
834 """commit the specified files or all outstanding changes
835
835
836 Commit changes to the given files into the repository. Unlike a
836 Commit changes to the given files into the repository. Unlike a
837 centralized SCM, this operation is a local operation. See
837 centralized SCM, this operation is a local operation. See
838 :hg:`push` for a way to actively distribute your changes.
838 :hg:`push` for a way to actively distribute your changes.
839
839
840 If a list of files is omitted, all changes reported by :hg:`status`
840 If a list of files is omitted, all changes reported by :hg:`status`
841 will be committed.
841 will be committed.
842
842
843 If you are committing the result of a merge, do not provide any
843 If you are committing the result of a merge, do not provide any
844 filenames or -I/-X filters.
844 filenames or -I/-X filters.
845
845
846 If no commit message is specified, Mercurial starts your
846 If no commit message is specified, Mercurial starts your
847 configured editor where you can enter a message. In case your
847 configured editor where you can enter a message. In case your
848 commit fails, you will find a backup of your message in
848 commit fails, you will find a backup of your message in
849 ``.hg/last-message.txt``.
849 ``.hg/last-message.txt``.
850
850
851 See :hg:`help dates` for a list of formats valid for -d/--date.
851 See :hg:`help dates` for a list of formats valid for -d/--date.
852
852
853 Returns 0 on success, 1 if nothing changed.
853 Returns 0 on success, 1 if nothing changed.
854 """
854 """
855 extra = {}
855 extra = {}
856 if opts.get('close_branch'):
856 if opts.get('close_branch'):
857 if repo['.'].node() not in repo.branchheads():
857 if repo['.'].node() not in repo.branchheads():
858 # The topo heads set is included in the branch heads set of the
858 # The topo heads set is included in the branch heads set of the
859 # current branch, so it's sufficient to test branchheads
859 # current branch, so it's sufficient to test branchheads
860 raise util.Abort(_('can only close branch heads'))
860 raise util.Abort(_('can only close branch heads'))
861 extra['close'] = 1
861 extra['close'] = 1
862 e = cmdutil.commiteditor
862 e = cmdutil.commiteditor
863 if opts.get('force_editor'):
863 if opts.get('force_editor'):
864 e = cmdutil.commitforceeditor
864 e = cmdutil.commitforceeditor
865
865
866 def commitfunc(ui, repo, message, match, opts):
866 def commitfunc(ui, repo, message, match, opts):
867 return repo.commit(message, opts.get('user'), opts.get('date'), match,
867 return repo.commit(message, opts.get('user'), opts.get('date'), match,
868 editor=e, extra=extra)
868 editor=e, extra=extra)
869
869
870 branch = repo[None].branch()
870 branch = repo[None].branch()
871 bheads = repo.branchheads(branch)
871 bheads = repo.branchheads(branch)
872
872
873 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
873 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
874 if not node:
874 if not node:
875 stat = repo.status(match=cmdutil.match(repo, pats, opts))
875 stat = repo.status(match=cmdutil.match(repo, pats, opts))
876 if stat[3]:
876 if stat[3]:
877 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
877 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
878 % len(stat[3]))
878 % len(stat[3]))
879 else:
879 else:
880 ui.status(_("nothing changed\n"))
880 ui.status(_("nothing changed\n"))
881 return 1
881 return 1
882
882
883 ctx = repo[node]
883 ctx = repo[node]
884 parents = ctx.parents()
884 parents = ctx.parents()
885
885
886 if bheads and not [x for x in parents
886 if bheads and not [x for x in parents
887 if x.node() in bheads and x.branch() == branch]:
887 if x.node() in bheads and x.branch() == branch]:
888 ui.status(_('created new head\n'))
888 ui.status(_('created new head\n'))
889 # The message is not printed for initial roots. For the other
889 # The message is not printed for initial roots. For the other
890 # changesets, it is printed in the following situations:
890 # changesets, it is printed in the following situations:
891 #
891 #
892 # Par column: for the 2 parents with ...
892 # Par column: for the 2 parents with ...
893 # N: null or no parent
893 # N: null or no parent
894 # B: parent is on another named branch
894 # B: parent is on another named branch
895 # C: parent is a regular non head changeset
895 # C: parent is a regular non head changeset
896 # H: parent was a branch head of the current branch
896 # H: parent was a branch head of the current branch
897 # Msg column: whether we print "created new head" message
897 # Msg column: whether we print "created new head" message
898 # In the following, it is assumed that there already exists some
898 # In the following, it is assumed that there already exists some
899 # initial branch heads of the current branch, otherwise nothing is
899 # initial branch heads of the current branch, otherwise nothing is
900 # printed anyway.
900 # printed anyway.
901 #
901 #
902 # Par Msg Comment
902 # Par Msg Comment
903 # NN y additional topo root
903 # NN y additional topo root
904 #
904 #
905 # BN y additional branch root
905 # BN y additional branch root
906 # CN y additional topo head
906 # CN y additional topo head
907 # HN n usual case
907 # HN n usual case
908 #
908 #
909 # BB y weird additional branch root
909 # BB y weird additional branch root
910 # CB y branch merge
910 # CB y branch merge
911 # HB n merge with named branch
911 # HB n merge with named branch
912 #
912 #
913 # CC y additional head from merge
913 # CC y additional head from merge
914 # CH n merge with a head
914 # CH n merge with a head
915 #
915 #
916 # HH n head merge: head count decreases
916 # HH n head merge: head count decreases
917
917
918 if not opts.get('close_branch'):
918 if not opts.get('close_branch'):
919 for r in parents:
919 for r in parents:
920 if r.extra().get('close') and r.branch() == branch:
920 if r.extra().get('close') and r.branch() == branch:
921 ui.status(_('reopening closed branch head %d\n') % r)
921 ui.status(_('reopening closed branch head %d\n') % r)
922
922
923 if ui.debugflag:
923 if ui.debugflag:
924 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
924 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
925 elif ui.verbose:
925 elif ui.verbose:
926 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
926 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
927
927
928 def copy(ui, repo, *pats, **opts):
928 def copy(ui, repo, *pats, **opts):
929 """mark files as copied for the next commit
929 """mark files as copied for the next commit
930
930
931 Mark dest as having copies of source files. If dest is a
931 Mark dest as having copies of source files. If dest is a
932 directory, copies are put in that directory. If dest is a file,
932 directory, copies are put in that directory. If dest is a file,
933 the source must be a single file.
933 the source must be a single file.
934
934
935 By default, this command copies the contents of files as they
935 By default, this command copies the contents of files as they
936 exist in the working directory. If invoked with -A/--after, the
936 exist in the working directory. If invoked with -A/--after, the
937 operation is recorded, but no copying is performed.
937 operation is recorded, but no copying is performed.
938
938
939 This command takes effect with the next commit. To undo a copy
939 This command takes effect with the next commit. To undo a copy
940 before that, see :hg:`revert`.
940 before that, see :hg:`revert`.
941
941
942 Returns 0 on success, 1 if errors are encountered.
942 Returns 0 on success, 1 if errors are encountered.
943 """
943 """
944 wlock = repo.wlock(False)
944 wlock = repo.wlock(False)
945 try:
945 try:
946 return cmdutil.copy(ui, repo, pats, opts)
946 return cmdutil.copy(ui, repo, pats, opts)
947 finally:
947 finally:
948 wlock.release()
948 wlock.release()
949
949
950 def debugancestor(ui, repo, *args):
950 def debugancestor(ui, repo, *args):
951 """find the ancestor revision of two revisions in a given index"""
951 """find the ancestor revision of two revisions in a given index"""
952 if len(args) == 3:
952 if len(args) == 3:
953 index, rev1, rev2 = args
953 index, rev1, rev2 = args
954 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
954 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
955 lookup = r.lookup
955 lookup = r.lookup
956 elif len(args) == 2:
956 elif len(args) == 2:
957 if not repo:
957 if not repo:
958 raise util.Abort(_("there is no Mercurial repository here "
958 raise util.Abort(_("there is no Mercurial repository here "
959 "(.hg not found)"))
959 "(.hg not found)"))
960 rev1, rev2 = args
960 rev1, rev2 = args
961 r = repo.changelog
961 r = repo.changelog
962 lookup = repo.lookup
962 lookup = repo.lookup
963 else:
963 else:
964 raise util.Abort(_('either two or three arguments required'))
964 raise util.Abort(_('either two or three arguments required'))
965 a = r.ancestor(lookup(rev1), lookup(rev2))
965 a = r.ancestor(lookup(rev1), lookup(rev2))
966 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
966 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
967
967
968 def debugbuilddag(ui, repo, text,
968 def debugbuilddag(ui, repo, text,
969 mergeable_file=False,
969 mergeable_file=False,
970 overwritten_file=False,
970 overwritten_file=False,
971 new_file=False):
971 new_file=False):
972 """builds a repo with a given dag from scratch in the current empty repo
972 """builds a repo with a given dag from scratch in the current empty repo
973
973
974 Elements:
974 Elements:
975
975
976 - "+n" is a linear run of n nodes based on the current default parent
976 - "+n" is a linear run of n nodes based on the current default parent
977 - "." is a single node based on the current default parent
977 - "." is a single node based on the current default parent
978 - "$" resets the default parent to null (implied at the start);
978 - "$" resets the default parent to null (implied at the start);
979 otherwise the default parent is always the last node created
979 otherwise the default parent is always the last node created
980 - "<p" sets the default parent to the backref p
980 - "<p" sets the default parent to the backref p
981 - "*p" is a fork at parent p, which is a backref
981 - "*p" is a fork at parent p, which is a backref
982 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
982 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
983 - "/p2" is a merge of the preceding node and p2
983 - "/p2" is a merge of the preceding node and p2
984 - ":tag" defines a local tag for the preceding node
984 - ":tag" defines a local tag for the preceding node
985 - "@branch" sets the named branch for subsequent nodes
985 - "@branch" sets the named branch for subsequent nodes
986 - "#...\\n" is a comment up to the end of the line
986 - "#...\\n" is a comment up to the end of the line
987
987
988 Whitespace between the above elements is ignored.
988 Whitespace between the above elements is ignored.
989
989
990 A backref is either
990 A backref is either
991
991
992 - a number n, which references the node curr-n, where curr is the current
992 - a number n, which references the node curr-n, where curr is the current
993 node, or
993 node, or
994 - the name of a local tag you placed earlier using ":tag", or
994 - the name of a local tag you placed earlier using ":tag", or
995 - empty to denote the default parent.
995 - empty to denote the default parent.
996
996
997 All string valued-elements are either strictly alphanumeric, or must
997 All string valued-elements are either strictly alphanumeric, or must
998 be enclosed in double quotes ("..."), with "\\" as escape character.
998 be enclosed in double quotes ("..."), with "\\" as escape character.
999 """
999 """
1000
1000
1001 cl = repo.changelog
1001 cl = repo.changelog
1002 if len(cl) > 0:
1002 if len(cl) > 0:
1003 raise util.Abort(_('repository is not empty'))
1003 raise util.Abort(_('repository is not empty'))
1004
1004
1005 if mergeable_file:
1005 if mergeable_file:
1006 linesperrev = 2
1006 linesperrev = 2
1007 # determine number of revs in DAG
1007 # determine number of revs in DAG
1008 n = 0
1008 n = 0
1009 for type, data in dagparser.parsedag(text):
1009 for type, data in dagparser.parsedag(text):
1010 if type == 'n':
1010 if type == 'n':
1011 n += 1
1011 n += 1
1012 # make a file with k lines per rev
1012 # make a file with k lines per rev
1013 initialmergedlines = [str(i) for i in xrange(0, n * linesperrev)]
1013 initialmergedlines = [str(i) for i in xrange(0, n * linesperrev)]
1014 initialmergedlines.append("")
1014 initialmergedlines.append("")
1015
1015
1016 tags = []
1016 tags = []
1017
1017
1018 tr = repo.transaction("builddag")
1018 tr = repo.transaction("builddag")
1019 try:
1019 try:
1020
1020
1021 at = -1
1021 at = -1
1022 atbranch = 'default'
1022 atbranch = 'default'
1023 nodeids = []
1023 nodeids = []
1024 for type, data in dagparser.parsedag(text):
1024 for type, data in dagparser.parsedag(text):
1025 if type == 'n':
1025 if type == 'n':
1026 ui.note('node %s\n' % str(data))
1026 ui.note('node %s\n' % str(data))
1027 id, ps = data
1027 id, ps = data
1028
1028
1029 files = []
1029 files = []
1030 fctxs = {}
1030 fctxs = {}
1031
1031
1032 p2 = None
1032 p2 = None
1033 if mergeable_file:
1033 if mergeable_file:
1034 fn = "mf"
1034 fn = "mf"
1035 p1 = repo[ps[0]]
1035 p1 = repo[ps[0]]
1036 if len(ps) > 1:
1036 if len(ps) > 1:
1037 p2 = repo[ps[1]]
1037 p2 = repo[ps[1]]
1038 pa = p1.ancestor(p2)
1038 pa = p1.ancestor(p2)
1039 base, local, other = [x[fn].data() for x in pa, p1, p2]
1039 base, local, other = [x[fn].data() for x in pa, p1, p2]
1040 m3 = simplemerge.Merge3Text(base, local, other)
1040 m3 = simplemerge.Merge3Text(base, local, other)
1041 ml = [l.strip() for l in m3.merge_lines()]
1041 ml = [l.strip() for l in m3.merge_lines()]
1042 ml.append("")
1042 ml.append("")
1043 elif at > 0:
1043 elif at > 0:
1044 ml = p1[fn].data().split("\n")
1044 ml = p1[fn].data().split("\n")
1045 else:
1045 else:
1046 ml = initialmergedlines
1046 ml = initialmergedlines
1047 ml[id * linesperrev] += " r%i" % id
1047 ml[id * linesperrev] += " r%i" % id
1048 mergedtext = "\n".join(ml)
1048 mergedtext = "\n".join(ml)
1049 files.append(fn)
1049 files.append(fn)
1050 fctxs[fn] = context.memfilectx(fn, mergedtext)
1050 fctxs[fn] = context.memfilectx(fn, mergedtext)
1051
1051
1052 if overwritten_file:
1052 if overwritten_file:
1053 fn = "of"
1053 fn = "of"
1054 files.append(fn)
1054 files.append(fn)
1055 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1055 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1056
1056
1057 if new_file:
1057 if new_file:
1058 fn = "nf%i" % id
1058 fn = "nf%i" % id
1059 files.append(fn)
1059 files.append(fn)
1060 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1060 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1061 if len(ps) > 1:
1061 if len(ps) > 1:
1062 if not p2:
1062 if not p2:
1063 p2 = repo[ps[1]]
1063 p2 = repo[ps[1]]
1064 for fn in p2:
1064 for fn in p2:
1065 if fn.startswith("nf"):
1065 if fn.startswith("nf"):
1066 files.append(fn)
1066 files.append(fn)
1067 fctxs[fn] = p2[fn]
1067 fctxs[fn] = p2[fn]
1068
1068
1069 def fctxfn(repo, cx, path):
1069 def fctxfn(repo, cx, path):
1070 return fctxs.get(path)
1070 return fctxs.get(path)
1071
1071
1072 if len(ps) == 0 or ps[0] < 0:
1072 if len(ps) == 0 or ps[0] < 0:
1073 pars = [None, None]
1073 pars = [None, None]
1074 elif len(ps) == 1:
1074 elif len(ps) == 1:
1075 pars = [nodeids[ps[0]], None]
1075 pars = [nodeids[ps[0]], None]
1076 else:
1076 else:
1077 pars = [nodeids[p] for p in ps]
1077 pars = [nodeids[p] for p in ps]
1078 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1078 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1079 date=(id, 0),
1079 date=(id, 0),
1080 user="debugbuilddag",
1080 user="debugbuilddag",
1081 extra={'branch': atbranch})
1081 extra={'branch': atbranch})
1082 nodeid = repo.commitctx(cx)
1082 nodeid = repo.commitctx(cx)
1083 nodeids.append(nodeid)
1083 nodeids.append(nodeid)
1084 at = id
1084 at = id
1085 elif type == 'l':
1085 elif type == 'l':
1086 id, name = data
1086 id, name = data
1087 ui.note('tag %s\n' % name)
1087 ui.note('tag %s\n' % name)
1088 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1088 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1089 elif type == 'a':
1089 elif type == 'a':
1090 ui.note('branch %s\n' % data)
1090 ui.note('branch %s\n' % data)
1091 atbranch = data
1091 atbranch = data
1092 tr.close()
1092 tr.close()
1093 finally:
1093 finally:
1094 tr.release()
1094 tr.release()
1095
1095
1096 if tags:
1096 if tags:
1097 tagsf = repo.opener("localtags", "w")
1097 tagsf = repo.opener("localtags", "w")
1098 try:
1098 try:
1099 tagsf.write("".join(tags))
1099 tagsf.write("".join(tags))
1100 finally:
1100 finally:
1101 tagsf.close()
1101 tagsf.close()
1102
1102
1103 def debugcommands(ui, cmd='', *args):
1103 def debugcommands(ui, cmd='', *args):
1104 """list all available commands and options"""
1104 """list all available commands and options"""
1105 for cmd, vals in sorted(table.iteritems()):
1105 for cmd, vals in sorted(table.iteritems()):
1106 cmd = cmd.split('|')[0].strip('^')
1106 cmd = cmd.split('|')[0].strip('^')
1107 opts = ', '.join([i[1] for i in vals[1]])
1107 opts = ', '.join([i[1] for i in vals[1]])
1108 ui.write('%s: %s\n' % (cmd, opts))
1108 ui.write('%s: %s\n' % (cmd, opts))
1109
1109
1110 def debugcomplete(ui, cmd='', **opts):
1110 def debugcomplete(ui, cmd='', **opts):
1111 """returns the completion list associated with the given command"""
1111 """returns the completion list associated with the given command"""
1112
1112
1113 if opts.get('options'):
1113 if opts.get('options'):
1114 options = []
1114 options = []
1115 otables = [globalopts]
1115 otables = [globalopts]
1116 if cmd:
1116 if cmd:
1117 aliases, entry = cmdutil.findcmd(cmd, table, False)
1117 aliases, entry = cmdutil.findcmd(cmd, table, False)
1118 otables.append(entry[1])
1118 otables.append(entry[1])
1119 for t in otables:
1119 for t in otables:
1120 for o in t:
1120 for o in t:
1121 if "(DEPRECATED)" in o[3]:
1121 if "(DEPRECATED)" in o[3]:
1122 continue
1122 continue
1123 if o[0]:
1123 if o[0]:
1124 options.append('-%s' % o[0])
1124 options.append('-%s' % o[0])
1125 options.append('--%s' % o[1])
1125 options.append('--%s' % o[1])
1126 ui.write("%s\n" % "\n".join(options))
1126 ui.write("%s\n" % "\n".join(options))
1127 return
1127 return
1128
1128
1129 cmdlist = cmdutil.findpossible(cmd, table)
1129 cmdlist = cmdutil.findpossible(cmd, table)
1130 if ui.verbose:
1130 if ui.verbose:
1131 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1131 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1132 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1132 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1133
1133
1134 def debugfsinfo(ui, path = "."):
1134 def debugfsinfo(ui, path = "."):
1135 """show information detected about current filesystem"""
1135 """show information detected about current filesystem"""
1136 util.writefile('.debugfsinfo', '')
1136 util.writefile('.debugfsinfo', '')
1137 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1137 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1138 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1138 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1139 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1139 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1140 and 'yes' or 'no'))
1140 and 'yes' or 'no'))
1141 os.unlink('.debugfsinfo')
1141 os.unlink('.debugfsinfo')
1142
1142
1143 def debugrebuildstate(ui, repo, rev="tip"):
1143 def debugrebuildstate(ui, repo, rev="tip"):
1144 """rebuild the dirstate as it would look like for the given revision"""
1144 """rebuild the dirstate as it would look like for the given revision"""
1145 ctx = cmdutil.revsingle(repo, rev)
1145 ctx = cmdutil.revsingle(repo, rev)
1146 wlock = repo.wlock()
1146 wlock = repo.wlock()
1147 try:
1147 try:
1148 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1148 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1149 finally:
1149 finally:
1150 wlock.release()
1150 wlock.release()
1151
1151
1152 def debugcheckstate(ui, repo):
1152 def debugcheckstate(ui, repo):
1153 """validate the correctness of the current dirstate"""
1153 """validate the correctness of the current dirstate"""
1154 parent1, parent2 = repo.dirstate.parents()
1154 parent1, parent2 = repo.dirstate.parents()
1155 m1 = repo[parent1].manifest()
1155 m1 = repo[parent1].manifest()
1156 m2 = repo[parent2].manifest()
1156 m2 = repo[parent2].manifest()
1157 errors = 0
1157 errors = 0
1158 for f in repo.dirstate:
1158 for f in repo.dirstate:
1159 state = repo.dirstate[f]
1159 state = repo.dirstate[f]
1160 if state in "nr" and f not in m1:
1160 if state in "nr" and f not in m1:
1161 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1161 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1162 errors += 1
1162 errors += 1
1163 if state in "a" and f in m1:
1163 if state in "a" and f in m1:
1164 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1164 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1165 errors += 1
1165 errors += 1
1166 if state in "m" and f not in m1 and f not in m2:
1166 if state in "m" and f not in m1 and f not in m2:
1167 ui.warn(_("%s in state %s, but not in either manifest\n") %
1167 ui.warn(_("%s in state %s, but not in either manifest\n") %
1168 (f, state))
1168 (f, state))
1169 errors += 1
1169 errors += 1
1170 for f in m1:
1170 for f in m1:
1171 state = repo.dirstate[f]
1171 state = repo.dirstate[f]
1172 if state not in "nrm":
1172 if state not in "nrm":
1173 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1173 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1174 errors += 1
1174 errors += 1
1175 if errors:
1175 if errors:
1176 error = _(".hg/dirstate inconsistent with current parent's manifest")
1176 error = _(".hg/dirstate inconsistent with current parent's manifest")
1177 raise util.Abort(error)
1177 raise util.Abort(error)
1178
1178
1179 def showconfig(ui, repo, *values, **opts):
1179 def showconfig(ui, repo, *values, **opts):
1180 """show combined config settings from all hgrc files
1180 """show combined config settings from all hgrc files
1181
1181
1182 With no arguments, print names and values of all config items.
1182 With no arguments, print names and values of all config items.
1183
1183
1184 With one argument of the form section.name, print just the value
1184 With one argument of the form section.name, print just the value
1185 of that config item.
1185 of that config item.
1186
1186
1187 With multiple arguments, print names and values of all config
1187 With multiple arguments, print names and values of all config
1188 items with matching section names.
1188 items with matching section names.
1189
1189
1190 With --debug, the source (filename and line number) is printed
1190 With --debug, the source (filename and line number) is printed
1191 for each config item.
1191 for each config item.
1192
1192
1193 Returns 0 on success.
1193 Returns 0 on success.
1194 """
1194 """
1195
1195
1196 for f in scmutil.rcpath():
1196 for f in scmutil.rcpath():
1197 ui.debug(_('read config from: %s\n') % f)
1197 ui.debug(_('read config from: %s\n') % f)
1198 untrusted = bool(opts.get('untrusted'))
1198 untrusted = bool(opts.get('untrusted'))
1199 if values:
1199 if values:
1200 sections = [v for v in values if '.' not in v]
1200 sections = [v for v in values if '.' not in v]
1201 items = [v for v in values if '.' in v]
1201 items = [v for v in values if '.' in v]
1202 if len(items) > 1 or items and sections:
1202 if len(items) > 1 or items and sections:
1203 raise util.Abort(_('only one config item permitted'))
1203 raise util.Abort(_('only one config item permitted'))
1204 for section, name, value in ui.walkconfig(untrusted=untrusted):
1204 for section, name, value in ui.walkconfig(untrusted=untrusted):
1205 value = str(value).replace('\n', '\\n')
1205 value = str(value).replace('\n', '\\n')
1206 sectname = section + '.' + name
1206 sectname = section + '.' + name
1207 if values:
1207 if values:
1208 for v in values:
1208 for v in values:
1209 if v == section:
1209 if v == section:
1210 ui.debug('%s: ' %
1210 ui.debug('%s: ' %
1211 ui.configsource(section, name, untrusted))
1211 ui.configsource(section, name, untrusted))
1212 ui.write('%s=%s\n' % (sectname, value))
1212 ui.write('%s=%s\n' % (sectname, value))
1213 elif v == sectname:
1213 elif v == sectname:
1214 ui.debug('%s: ' %
1214 ui.debug('%s: ' %
1215 ui.configsource(section, name, untrusted))
1215 ui.configsource(section, name, untrusted))
1216 ui.write(value, '\n')
1216 ui.write(value, '\n')
1217 else:
1217 else:
1218 ui.debug('%s: ' %
1218 ui.debug('%s: ' %
1219 ui.configsource(section, name, untrusted))
1219 ui.configsource(section, name, untrusted))
1220 ui.write('%s=%s\n' % (sectname, value))
1220 ui.write('%s=%s\n' % (sectname, value))
1221
1221
1222 def debugknown(ui, repopath, *ids, **opts):
1222 def debugknown(ui, repopath, *ids, **opts):
1223 """test whether node ids are known to a repo
1223 """test whether node ids are known to a repo
1224
1224
1225 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1225 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1226 indicating unknown/known.
1226 indicating unknown/known.
1227 """
1227 """
1228 repo = hg.repository(ui, repopath)
1228 repo = hg.repository(ui, repopath)
1229 if not repo.capable('known'):
1229 if not repo.capable('known'):
1230 raise util.Abort("known() not supported by target repository")
1230 raise util.Abort("known() not supported by target repository")
1231 flags = repo.known([bin(s) for s in ids])
1231 flags = repo.known([bin(s) for s in ids])
1232 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1232 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1233
1233
1234 def debugbundle(ui, bundlepath, all=None, **opts):
1234 def debugbundle(ui, bundlepath, all=None, **opts):
1235 """lists the contents of a bundle"""
1235 """lists the contents of a bundle"""
1236 f = url.open(ui, bundlepath)
1236 f = url.open(ui, bundlepath)
1237 try:
1237 try:
1238 gen = changegroup.readbundle(f, bundlepath)
1238 gen = changegroup.readbundle(f, bundlepath)
1239 if all:
1239 if all:
1240 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1240 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1241
1241
1242 def showchunks(named):
1242 def showchunks(named):
1243 ui.write("\n%s\n" % named)
1243 ui.write("\n%s\n" % named)
1244 chain = None
1244 chain = None
1245 while 1:
1245 while 1:
1246 chunkdata = gen.deltachunk(chain)
1246 chunkdata = gen.deltachunk(chain)
1247 if not chunkdata:
1247 if not chunkdata:
1248 break
1248 break
1249 node = chunkdata['node']
1249 node = chunkdata['node']
1250 p1 = chunkdata['p1']
1250 p1 = chunkdata['p1']
1251 p2 = chunkdata['p2']
1251 p2 = chunkdata['p2']
1252 cs = chunkdata['cs']
1252 cs = chunkdata['cs']
1253 deltabase = chunkdata['deltabase']
1253 deltabase = chunkdata['deltabase']
1254 delta = chunkdata['delta']
1254 delta = chunkdata['delta']
1255 ui.write("%s %s %s %s %s %s\n" %
1255 ui.write("%s %s %s %s %s %s\n" %
1256 (hex(node), hex(p1), hex(p2),
1256 (hex(node), hex(p1), hex(p2),
1257 hex(cs), hex(deltabase), len(delta)))
1257 hex(cs), hex(deltabase), len(delta)))
1258 chain = node
1258 chain = node
1259
1259
1260 chunkdata = gen.changelogheader()
1260 chunkdata = gen.changelogheader()
1261 showchunks("changelog")
1261 showchunks("changelog")
1262 chunkdata = gen.manifestheader()
1262 chunkdata = gen.manifestheader()
1263 showchunks("manifest")
1263 showchunks("manifest")
1264 while 1:
1264 while 1:
1265 chunkdata = gen.filelogheader()
1265 chunkdata = gen.filelogheader()
1266 if not chunkdata:
1266 if not chunkdata:
1267 break
1267 break
1268 fname = chunkdata['filename']
1268 fname = chunkdata['filename']
1269 showchunks(fname)
1269 showchunks(fname)
1270 else:
1270 else:
1271 chunkdata = gen.changelogheader()
1271 chunkdata = gen.changelogheader()
1272 chain = None
1272 chain = None
1273 while 1:
1273 while 1:
1274 chunkdata = gen.deltachunk(chain)
1274 chunkdata = gen.deltachunk(chain)
1275 if not chunkdata:
1275 if not chunkdata:
1276 break
1276 break
1277 node = chunkdata['node']
1277 node = chunkdata['node']
1278 ui.write("%s\n" % hex(node))
1278 ui.write("%s\n" % hex(node))
1279 chain = node
1279 chain = node
1280 finally:
1280 finally:
1281 f.close()
1281 f.close()
1282
1282
1283 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1283 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1284 """retrieves a bundle from a repo
1284 """retrieves a bundle from a repo
1285
1285
1286 Every ID must be a full-length hex node id string. Saves the bundle to the
1286 Every ID must be a full-length hex node id string. Saves the bundle to the
1287 given file.
1287 given file.
1288 """
1288 """
1289 repo = hg.repository(ui, repopath)
1289 repo = hg.repository(ui, repopath)
1290 if not repo.capable('getbundle'):
1290 if not repo.capable('getbundle'):
1291 raise util.Abort("getbundle() not supported by target repository")
1291 raise util.Abort("getbundle() not supported by target repository")
1292 args = {}
1292 args = {}
1293 if common:
1293 if common:
1294 args['common'] = [bin(s) for s in common]
1294 args['common'] = [bin(s) for s in common]
1295 if head:
1295 if head:
1296 args['heads'] = [bin(s) for s in head]
1296 args['heads'] = [bin(s) for s in head]
1297 bundle = repo.getbundle('debug', **args)
1297 bundle = repo.getbundle('debug', **args)
1298
1298
1299 bundletype = opts.get('type', 'bzip2').lower()
1299 bundletype = opts.get('type', 'bzip2').lower()
1300 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1300 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1301 bundletype = btypes.get(bundletype)
1301 bundletype = btypes.get(bundletype)
1302 if bundletype not in changegroup.bundletypes:
1302 if bundletype not in changegroup.bundletypes:
1303 raise util.Abort(_('unknown bundle type specified with --type'))
1303 raise util.Abort(_('unknown bundle type specified with --type'))
1304 changegroup.writebundle(bundle, bundlepath, bundletype)
1304 changegroup.writebundle(bundle, bundlepath, bundletype)
1305
1305
1306 def debugpushkey(ui, repopath, namespace, *keyinfo):
1306 def debugpushkey(ui, repopath, namespace, *keyinfo):
1307 '''access the pushkey key/value protocol
1307 '''access the pushkey key/value protocol
1308
1308
1309 With two args, list the keys in the given namespace.
1309 With two args, list the keys in the given namespace.
1310
1310
1311 With five args, set a key to new if it currently is set to old.
1311 With five args, set a key to new if it currently is set to old.
1312 Reports success or failure.
1312 Reports success or failure.
1313 '''
1313 '''
1314
1314
1315 target = hg.repository(ui, repopath)
1315 target = hg.repository(ui, repopath)
1316 if keyinfo:
1316 if keyinfo:
1317 key, old, new = keyinfo
1317 key, old, new = keyinfo
1318 r = target.pushkey(namespace, key, old, new)
1318 r = target.pushkey(namespace, key, old, new)
1319 ui.status(str(r) + '\n')
1319 ui.status(str(r) + '\n')
1320 return not r
1320 return not r
1321 else:
1321 else:
1322 for k, v in target.listkeys(namespace).iteritems():
1322 for k, v in target.listkeys(namespace).iteritems():
1323 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1323 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1324 v.encode('string-escape')))
1324 v.encode('string-escape')))
1325
1325
1326 def debugrevspec(ui, repo, expr):
1326 def debugrevspec(ui, repo, expr):
1327 '''parse and apply a revision specification'''
1327 '''parse and apply a revision specification'''
1328 if ui.verbose:
1328 if ui.verbose:
1329 tree = revset.parse(expr)[0]
1329 tree = revset.parse(expr)[0]
1330 ui.note(tree, "\n")
1330 ui.note(tree, "\n")
1331 newtree = revset.findaliases(ui, tree)
1331 newtree = revset.findaliases(ui, tree)
1332 if newtree != tree:
1332 if newtree != tree:
1333 ui.note(newtree, "\n")
1333 ui.note(newtree, "\n")
1334 func = revset.match(ui, expr)
1334 func = revset.match(ui, expr)
1335 for c in func(repo, range(len(repo))):
1335 for c in func(repo, range(len(repo))):
1336 ui.write("%s\n" % c)
1336 ui.write("%s\n" % c)
1337
1337
1338 def debugsetparents(ui, repo, rev1, rev2=None):
1338 def debugsetparents(ui, repo, rev1, rev2=None):
1339 """manually set the parents of the current working directory
1339 """manually set the parents of the current working directory
1340
1340
1341 This is useful for writing repository conversion tools, but should
1341 This is useful for writing repository conversion tools, but should
1342 be used with care.
1342 be used with care.
1343
1343
1344 Returns 0 on success.
1344 Returns 0 on success.
1345 """
1345 """
1346
1346
1347 r1 = cmdutil.revsingle(repo, rev1).node()
1347 r1 = cmdutil.revsingle(repo, rev1).node()
1348 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1348 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1349
1349
1350 wlock = repo.wlock()
1350 wlock = repo.wlock()
1351 try:
1351 try:
1352 repo.dirstate.setparents(r1, r2)
1352 repo.dirstate.setparents(r1, r2)
1353 finally:
1353 finally:
1354 wlock.release()
1354 wlock.release()
1355
1355
1356 def debugstate(ui, repo, nodates=None, datesort=None):
1356 def debugstate(ui, repo, nodates=None, datesort=None):
1357 """show the contents of the current dirstate"""
1357 """show the contents of the current dirstate"""
1358 timestr = ""
1358 timestr = ""
1359 showdate = not nodates
1359 showdate = not nodates
1360 if datesort:
1360 if datesort:
1361 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1361 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1362 else:
1362 else:
1363 keyfunc = None # sort by filename
1363 keyfunc = None # sort by filename
1364 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1364 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1365 if showdate:
1365 if showdate:
1366 if ent[3] == -1:
1366 if ent[3] == -1:
1367 # Pad or slice to locale representation
1367 # Pad or slice to locale representation
1368 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1368 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1369 time.localtime(0)))
1369 time.localtime(0)))
1370 timestr = 'unset'
1370 timestr = 'unset'
1371 timestr = (timestr[:locale_len] +
1371 timestr = (timestr[:locale_len] +
1372 ' ' * (locale_len - len(timestr)))
1372 ' ' * (locale_len - len(timestr)))
1373 else:
1373 else:
1374 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1374 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1375 time.localtime(ent[3]))
1375 time.localtime(ent[3]))
1376 if ent[1] & 020000:
1376 if ent[1] & 020000:
1377 mode = 'lnk'
1377 mode = 'lnk'
1378 else:
1378 else:
1379 mode = '%3o' % (ent[1] & 0777)
1379 mode = '%3o' % (ent[1] & 0777)
1380 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1380 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1381 for f in repo.dirstate.copies():
1381 for f in repo.dirstate.copies():
1382 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1382 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1383
1383
1384 def debugsub(ui, repo, rev=None):
1384 def debugsub(ui, repo, rev=None):
1385 ctx = cmdutil.revsingle(repo, rev, None)
1385 ctx = cmdutil.revsingle(repo, rev, None)
1386 for k, v in sorted(ctx.substate.items()):
1386 for k, v in sorted(ctx.substate.items()):
1387 ui.write('path %s\n' % k)
1387 ui.write('path %s\n' % k)
1388 ui.write(' source %s\n' % v[0])
1388 ui.write(' source %s\n' % v[0])
1389 ui.write(' revision %s\n' % v[1])
1389 ui.write(' revision %s\n' % v[1])
1390
1390
1391 def debugdag(ui, repo, file_=None, *revs, **opts):
1391 def debugdag(ui, repo, file_=None, *revs, **opts):
1392 """format the changelog or an index DAG as a concise textual description
1392 """format the changelog or an index DAG as a concise textual description
1393
1393
1394 If you pass a revlog index, the revlog's DAG is emitted. If you list
1394 If you pass a revlog index, the revlog's DAG is emitted. If you list
1395 revision numbers, they get labelled in the output as rN.
1395 revision numbers, they get labelled in the output as rN.
1396
1396
1397 Otherwise, the changelog DAG of the current repo is emitted.
1397 Otherwise, the changelog DAG of the current repo is emitted.
1398 """
1398 """
1399 spaces = opts.get('spaces')
1399 spaces = opts.get('spaces')
1400 dots = opts.get('dots')
1400 dots = opts.get('dots')
1401 if file_:
1401 if file_:
1402 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1402 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1403 revs = set((int(r) for r in revs))
1403 revs = set((int(r) for r in revs))
1404 def events():
1404 def events():
1405 for r in rlog:
1405 for r in rlog:
1406 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1406 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1407 if r in revs:
1407 if r in revs:
1408 yield 'l', (r, "r%i" % r)
1408 yield 'l', (r, "r%i" % r)
1409 elif repo:
1409 elif repo:
1410 cl = repo.changelog
1410 cl = repo.changelog
1411 tags = opts.get('tags')
1411 tags = opts.get('tags')
1412 branches = opts.get('branches')
1412 branches = opts.get('branches')
1413 if tags:
1413 if tags:
1414 labels = {}
1414 labels = {}
1415 for l, n in repo.tags().items():
1415 for l, n in repo.tags().items():
1416 labels.setdefault(cl.rev(n), []).append(l)
1416 labels.setdefault(cl.rev(n), []).append(l)
1417 def events():
1417 def events():
1418 b = "default"
1418 b = "default"
1419 for r in cl:
1419 for r in cl:
1420 if branches:
1420 if branches:
1421 newb = cl.read(cl.node(r))[5]['branch']
1421 newb = cl.read(cl.node(r))[5]['branch']
1422 if newb != b:
1422 if newb != b:
1423 yield 'a', newb
1423 yield 'a', newb
1424 b = newb
1424 b = newb
1425 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1425 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1426 if tags:
1426 if tags:
1427 ls = labels.get(r)
1427 ls = labels.get(r)
1428 if ls:
1428 if ls:
1429 for l in ls:
1429 for l in ls:
1430 yield 'l', (r, l)
1430 yield 'l', (r, l)
1431 else:
1431 else:
1432 raise util.Abort(_('need repo for changelog dag'))
1432 raise util.Abort(_('need repo for changelog dag'))
1433
1433
1434 for line in dagparser.dagtextlines(events(),
1434 for line in dagparser.dagtextlines(events(),
1435 addspaces=spaces,
1435 addspaces=spaces,
1436 wraplabels=True,
1436 wraplabels=True,
1437 wrapannotations=True,
1437 wrapannotations=True,
1438 wrapnonlinear=dots,
1438 wrapnonlinear=dots,
1439 usedots=dots,
1439 usedots=dots,
1440 maxlinewidth=70):
1440 maxlinewidth=70):
1441 ui.write(line)
1441 ui.write(line)
1442 ui.write("\n")
1442 ui.write("\n")
1443
1443
1444 def debugdata(ui, repo, file_, rev):
1444 def debugdata(ui, repo, file_, rev):
1445 """dump the contents of a data file revision"""
1445 """dump the contents of a data file revision"""
1446 r = None
1446 r = None
1447 if repo:
1447 if repo:
1448 filelog = repo.file(file_)
1448 filelog = repo.file(file_)
1449 if len(filelog):
1449 if len(filelog):
1450 r = filelog
1450 r = filelog
1451 if not r:
1451 if not r:
1452 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
1452 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
1453 file_[:-2] + ".i")
1453 file_[:-2] + ".i")
1454 try:
1454 try:
1455 ui.write(r.revision(r.lookup(rev)))
1455 ui.write(r.revision(r.lookup(rev)))
1456 except KeyError:
1456 except KeyError:
1457 raise util.Abort(_('invalid revision identifier %s') % rev)
1457 raise util.Abort(_('invalid revision identifier %s') % rev)
1458
1458
1459 def debugdate(ui, date, range=None, **opts):
1459 def debugdate(ui, date, range=None, **opts):
1460 """parse and display a date"""
1460 """parse and display a date"""
1461 if opts["extended"]:
1461 if opts["extended"]:
1462 d = util.parsedate(date, util.extendeddateformats)
1462 d = util.parsedate(date, util.extendeddateformats)
1463 else:
1463 else:
1464 d = util.parsedate(date)
1464 d = util.parsedate(date)
1465 ui.write("internal: %s %s\n" % d)
1465 ui.write("internal: %s %s\n" % d)
1466 ui.write("standard: %s\n" % util.datestr(d))
1466 ui.write("standard: %s\n" % util.datestr(d))
1467 if range:
1467 if range:
1468 m = util.matchdate(range)
1468 m = util.matchdate(range)
1469 ui.write("match: %s\n" % m(d[0]))
1469 ui.write("match: %s\n" % m(d[0]))
1470
1470
1471 def debugignore(ui, repo, *values, **opts):
1471 def debugignore(ui, repo, *values, **opts):
1472 """display the combined ignore pattern"""
1472 """display the combined ignore pattern"""
1473 ignore = repo.dirstate._ignore
1473 ignore = repo.dirstate._ignore
1474 if hasattr(ignore, 'includepat'):
1474 if hasattr(ignore, 'includepat'):
1475 ui.write("%s\n" % ignore.includepat)
1475 ui.write("%s\n" % ignore.includepat)
1476 else:
1476 else:
1477 raise util.Abort(_("no ignore patterns found"))
1477 raise util.Abort(_("no ignore patterns found"))
1478
1478
1479 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1479 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1480 """runs the changeset discovery protocol in isolation"""
1480 """runs the changeset discovery protocol in isolation"""
1481 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1481 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1482 remote = hg.repository(hg.remoteui(repo, opts), remoteurl)
1482 remote = hg.repository(hg.remoteui(repo, opts), remoteurl)
1483 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1483 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1484
1484
1485 # make sure tests are repeatable
1485 # make sure tests are repeatable
1486 random.seed(12323)
1486 random.seed(12323)
1487
1487
1488 def doit(localheads, remoteheads):
1488 def doit(localheads, remoteheads):
1489 if opts.get('old'):
1489 if opts.get('old'):
1490 if localheads:
1490 if localheads:
1491 raise util.Abort('cannot use localheads with old style discovery')
1491 raise util.Abort('cannot use localheads with old style discovery')
1492 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1492 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1493 force=True)
1493 force=True)
1494 common = set(common)
1494 common = set(common)
1495 if not opts.get('nonheads'):
1495 if not opts.get('nonheads'):
1496 ui.write("unpruned common: %s\n" % " ".join([short(n)
1496 ui.write("unpruned common: %s\n" % " ".join([short(n)
1497 for n in common]))
1497 for n in common]))
1498 dag = dagutil.revlogdag(repo.changelog)
1498 dag = dagutil.revlogdag(repo.changelog)
1499 all = dag.ancestorset(dag.internalizeall(common))
1499 all = dag.ancestorset(dag.internalizeall(common))
1500 common = dag.externalizeall(dag.headsetofconnecteds(all))
1500 common = dag.externalizeall(dag.headsetofconnecteds(all))
1501 else:
1501 else:
1502 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1502 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1503 common = set(common)
1503 common = set(common)
1504 rheads = set(hds)
1504 rheads = set(hds)
1505 lheads = set(repo.heads())
1505 lheads = set(repo.heads())
1506 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1506 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1507 if lheads <= common:
1507 if lheads <= common:
1508 ui.write("local is subset\n")
1508 ui.write("local is subset\n")
1509 elif rheads <= common:
1509 elif rheads <= common:
1510 ui.write("remote is subset\n")
1510 ui.write("remote is subset\n")
1511
1511
1512 serverlogs = opts.get('serverlog')
1512 serverlogs = opts.get('serverlog')
1513 if serverlogs:
1513 if serverlogs:
1514 for filename in serverlogs:
1514 for filename in serverlogs:
1515 logfile = open(filename, 'r')
1515 logfile = open(filename, 'r')
1516 try:
1516 try:
1517 line = logfile.readline()
1517 line = logfile.readline()
1518 while line:
1518 while line:
1519 parts = line.strip().split(';')
1519 parts = line.strip().split(';')
1520 op = parts[1]
1520 op = parts[1]
1521 if op == 'cg':
1521 if op == 'cg':
1522 pass
1522 pass
1523 elif op == 'cgss':
1523 elif op == 'cgss':
1524 doit(parts[2].split(' '), parts[3].split(' '))
1524 doit(parts[2].split(' '), parts[3].split(' '))
1525 elif op == 'unb':
1525 elif op == 'unb':
1526 doit(parts[3].split(' '), parts[2].split(' '))
1526 doit(parts[3].split(' '), parts[2].split(' '))
1527 line = logfile.readline()
1527 line = logfile.readline()
1528 finally:
1528 finally:
1529 logfile.close()
1529 logfile.close()
1530
1530
1531 else:
1531 else:
1532 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1532 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1533 opts.get('remote_head'))
1533 opts.get('remote_head'))
1534 localrevs = opts.get('local_head')
1534 localrevs = opts.get('local_head')
1535 doit(localrevs, remoterevs)
1535 doit(localrevs, remoterevs)
1536
1536
1537
1537
1538 def debugindex(ui, repo, file_, **opts):
1538 def debugindex(ui, repo, file_, **opts):
1539 """dump the contents of an index file"""
1539 """dump the contents of an index file"""
1540 r = None
1540 r = None
1541 if repo:
1541 if repo:
1542 filelog = repo.file(file_)
1542 filelog = repo.file(file_)
1543 if len(filelog):
1543 if len(filelog):
1544 r = filelog
1544 r = filelog
1545
1545
1546 format = opts.get('format', 0)
1546 format = opts.get('format', 0)
1547 if format not in (0, 1):
1547 if format not in (0, 1):
1548 raise util.Abort(_("unknown format %d") % format)
1548 raise util.Abort(_("unknown format %d") % format)
1549
1549
1550 if not r:
1550 if not r:
1551 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1551 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1552
1552
1553 if format == 0:
1553 if format == 0:
1554 ui.write(" rev offset length base linkrev"
1554 ui.write(" rev offset length base linkrev"
1555 " nodeid p1 p2\n")
1555 " nodeid p1 p2\n")
1556 elif format == 1:
1556 elif format == 1:
1557 ui.write(" rev flag offset length"
1557 ui.write(" rev flag offset length"
1558 " size base link p1 p2 nodeid\n")
1558 " size base link p1 p2 nodeid\n")
1559
1559
1560 for i in r:
1560 for i in r:
1561 node = r.node(i)
1561 node = r.node(i)
1562 if format == 0:
1562 if format == 0:
1563 try:
1563 try:
1564 pp = r.parents(node)
1564 pp = r.parents(node)
1565 except:
1565 except:
1566 pp = [nullid, nullid]
1566 pp = [nullid, nullid]
1567 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1567 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1568 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1568 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1569 short(node), short(pp[0]), short(pp[1])))
1569 short(node), short(pp[0]), short(pp[1])))
1570 elif format == 1:
1570 elif format == 1:
1571 pr = r.parentrevs(i)
1571 pr = r.parentrevs(i)
1572 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1572 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1573 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1573 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1574 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1574 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1575
1575
1576 def debugindexdot(ui, repo, file_):
1576 def debugindexdot(ui, repo, file_):
1577 """dump an index DAG as a graphviz dot file"""
1577 """dump an index DAG as a graphviz dot file"""
1578 r = None
1578 r = None
1579 if repo:
1579 if repo:
1580 filelog = repo.file(file_)
1580 filelog = repo.file(file_)
1581 if len(filelog):
1581 if len(filelog):
1582 r = filelog
1582 r = filelog
1583 if not r:
1583 if not r:
1584 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1584 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1585 ui.write("digraph G {\n")
1585 ui.write("digraph G {\n")
1586 for i in r:
1586 for i in r:
1587 node = r.node(i)
1587 node = r.node(i)
1588 pp = r.parents(node)
1588 pp = r.parents(node)
1589 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1589 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1590 if pp[1] != nullid:
1590 if pp[1] != nullid:
1591 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1591 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1592 ui.write("}\n")
1592 ui.write("}\n")
1593
1593
1594 def debuginstall(ui):
1594 def debuginstall(ui):
1595 '''test Mercurial installation
1595 '''test Mercurial installation
1596
1596
1597 Returns 0 on success.
1597 Returns 0 on success.
1598 '''
1598 '''
1599
1599
1600 def writetemp(contents):
1600 def writetemp(contents):
1601 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1601 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1602 f = os.fdopen(fd, "wb")
1602 f = os.fdopen(fd, "wb")
1603 f.write(contents)
1603 f.write(contents)
1604 f.close()
1604 f.close()
1605 return name
1605 return name
1606
1606
1607 problems = 0
1607 problems = 0
1608
1608
1609 # encoding
1609 # encoding
1610 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1610 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1611 try:
1611 try:
1612 encoding.fromlocal("test")
1612 encoding.fromlocal("test")
1613 except util.Abort, inst:
1613 except util.Abort, inst:
1614 ui.write(" %s\n" % inst)
1614 ui.write(" %s\n" % inst)
1615 ui.write(_(" (check that your locale is properly set)\n"))
1615 ui.write(_(" (check that your locale is properly set)\n"))
1616 problems += 1
1616 problems += 1
1617
1617
1618 # compiled modules
1618 # compiled modules
1619 ui.status(_("Checking installed modules (%s)...\n")
1619 ui.status(_("Checking installed modules (%s)...\n")
1620 % os.path.dirname(__file__))
1620 % os.path.dirname(__file__))
1621 try:
1621 try:
1622 import bdiff, mpatch, base85, osutil
1622 import bdiff, mpatch, base85, osutil
1623 except Exception, inst:
1623 except Exception, inst:
1624 ui.write(" %s\n" % inst)
1624 ui.write(" %s\n" % inst)
1625 ui.write(_(" One or more extensions could not be found"))
1625 ui.write(_(" One or more extensions could not be found"))
1626 ui.write(_(" (check that you compiled the extensions)\n"))
1626 ui.write(_(" (check that you compiled the extensions)\n"))
1627 problems += 1
1627 problems += 1
1628
1628
1629 # templates
1629 # templates
1630 ui.status(_("Checking templates...\n"))
1630 ui.status(_("Checking templates...\n"))
1631 try:
1631 try:
1632 import templater
1632 import templater
1633 templater.templater(templater.templatepath("map-cmdline.default"))
1633 templater.templater(templater.templatepath("map-cmdline.default"))
1634 except Exception, inst:
1634 except Exception, inst:
1635 ui.write(" %s\n" % inst)
1635 ui.write(" %s\n" % inst)
1636 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1636 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1637 problems += 1
1637 problems += 1
1638
1638
1639 # editor
1639 # editor
1640 ui.status(_("Checking commit editor...\n"))
1640 ui.status(_("Checking commit editor...\n"))
1641 editor = ui.geteditor()
1641 editor = ui.geteditor()
1642 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1642 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1643 if not cmdpath:
1643 if not cmdpath:
1644 if editor == 'vi':
1644 if editor == 'vi':
1645 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1645 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1646 ui.write(_(" (specify a commit editor in your configuration"
1646 ui.write(_(" (specify a commit editor in your configuration"
1647 " file)\n"))
1647 " file)\n"))
1648 else:
1648 else:
1649 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1649 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1650 ui.write(_(" (specify a commit editor in your configuration"
1650 ui.write(_(" (specify a commit editor in your configuration"
1651 " file)\n"))
1651 " file)\n"))
1652 problems += 1
1652 problems += 1
1653
1653
1654 # check username
1654 # check username
1655 ui.status(_("Checking username...\n"))
1655 ui.status(_("Checking username...\n"))
1656 try:
1656 try:
1657 ui.username()
1657 ui.username()
1658 except util.Abort, e:
1658 except util.Abort, e:
1659 ui.write(" %s\n" % e)
1659 ui.write(" %s\n" % e)
1660 ui.write(_(" (specify a username in your configuration file)\n"))
1660 ui.write(_(" (specify a username in your configuration file)\n"))
1661 problems += 1
1661 problems += 1
1662
1662
1663 if not problems:
1663 if not problems:
1664 ui.status(_("No problems detected\n"))
1664 ui.status(_("No problems detected\n"))
1665 else:
1665 else:
1666 ui.write(_("%s problems detected,"
1666 ui.write(_("%s problems detected,"
1667 " please check your install!\n") % problems)
1667 " please check your install!\n") % problems)
1668
1668
1669 return problems
1669 return problems
1670
1670
1671 def debugrename(ui, repo, file1, *pats, **opts):
1671 def debugrename(ui, repo, file1, *pats, **opts):
1672 """dump rename information"""
1672 """dump rename information"""
1673
1673
1674 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1674 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1675 m = cmdutil.match(repo, (file1,) + pats, opts)
1675 m = cmdutil.match(repo, (file1,) + pats, opts)
1676 for abs in ctx.walk(m):
1676 for abs in ctx.walk(m):
1677 fctx = ctx[abs]
1677 fctx = ctx[abs]
1678 o = fctx.filelog().renamed(fctx.filenode())
1678 o = fctx.filelog().renamed(fctx.filenode())
1679 rel = m.rel(abs)
1679 rel = m.rel(abs)
1680 if o:
1680 if o:
1681 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1681 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1682 else:
1682 else:
1683 ui.write(_("%s not renamed\n") % rel)
1683 ui.write(_("%s not renamed\n") % rel)
1684
1684
1685 def debugwalk(ui, repo, *pats, **opts):
1685 def debugwalk(ui, repo, *pats, **opts):
1686 """show how files match on given patterns"""
1686 """show how files match on given patterns"""
1687 m = cmdutil.match(repo, pats, opts)
1687 m = cmdutil.match(repo, pats, opts)
1688 items = list(repo.walk(m))
1688 items = list(repo.walk(m))
1689 if not items:
1689 if not items:
1690 return
1690 return
1691 fmt = 'f %%-%ds %%-%ds %%s' % (
1691 fmt = 'f %%-%ds %%-%ds %%s' % (
1692 max([len(abs) for abs in items]),
1692 max([len(abs) for abs in items]),
1693 max([len(m.rel(abs)) for abs in items]))
1693 max([len(m.rel(abs)) for abs in items]))
1694 for abs in items:
1694 for abs in items:
1695 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1695 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1696 ui.write("%s\n" % line.rstrip())
1696 ui.write("%s\n" % line.rstrip())
1697
1697
1698 def debugwireargs(ui, repopath, *vals, **opts):
1698 def debugwireargs(ui, repopath, *vals, **opts):
1699 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1699 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1700 for opt in remoteopts:
1700 for opt in remoteopts:
1701 del opts[opt[1]]
1701 del opts[opt[1]]
1702 args = {}
1702 args = {}
1703 for k, v in opts.iteritems():
1703 for k, v in opts.iteritems():
1704 if v:
1704 if v:
1705 args[k] = v
1705 args[k] = v
1706 # run twice to check that we don't mess up the stream for the next command
1706 # run twice to check that we don't mess up the stream for the next command
1707 res1 = repo.debugwireargs(*vals, **args)
1707 res1 = repo.debugwireargs(*vals, **args)
1708 res2 = repo.debugwireargs(*vals, **args)
1708 res2 = repo.debugwireargs(*vals, **args)
1709 ui.write("%s\n" % res1)
1709 ui.write("%s\n" % res1)
1710 if res1 != res2:
1710 if res1 != res2:
1711 ui.warn("%s\n" % res2)
1711 ui.warn("%s\n" % res2)
1712
1712
1713 def diff(ui, repo, *pats, **opts):
1713 def diff(ui, repo, *pats, **opts):
1714 """diff repository (or selected files)
1714 """diff repository (or selected files)
1715
1715
1716 Show differences between revisions for the specified files.
1716 Show differences between revisions for the specified files.
1717
1717
1718 Differences between files are shown using the unified diff format.
1718 Differences between files are shown using the unified diff format.
1719
1719
1720 .. note::
1720 .. note::
1721 diff may generate unexpected results for merges, as it will
1721 diff may generate unexpected results for merges, as it will
1722 default to comparing against the working directory's first
1722 default to comparing against the working directory's first
1723 parent changeset if no revisions are specified.
1723 parent changeset if no revisions are specified.
1724
1724
1725 When two revision arguments are given, then changes are shown
1725 When two revision arguments are given, then changes are shown
1726 between those revisions. If only one revision is specified then
1726 between those revisions. If only one revision is specified then
1727 that revision is compared to the working directory, and, when no
1727 that revision is compared to the working directory, and, when no
1728 revisions are specified, the working directory files are compared
1728 revisions are specified, the working directory files are compared
1729 to its parent.
1729 to its parent.
1730
1730
1731 Alternatively you can specify -c/--change with a revision to see
1731 Alternatively you can specify -c/--change with a revision to see
1732 the changes in that changeset relative to its first parent.
1732 the changes in that changeset relative to its first parent.
1733
1733
1734 Without the -a/--text option, diff will avoid generating diffs of
1734 Without the -a/--text option, diff will avoid generating diffs of
1735 files it detects as binary. With -a, diff will generate a diff
1735 files it detects as binary. With -a, diff will generate a diff
1736 anyway, probably with undesirable results.
1736 anyway, probably with undesirable results.
1737
1737
1738 Use the -g/--git option to generate diffs in the git extended diff
1738 Use the -g/--git option to generate diffs in the git extended diff
1739 format. For more information, read :hg:`help diffs`.
1739 format. For more information, read :hg:`help diffs`.
1740
1740
1741 Returns 0 on success.
1741 Returns 0 on success.
1742 """
1742 """
1743
1743
1744 revs = opts.get('rev')
1744 revs = opts.get('rev')
1745 change = opts.get('change')
1745 change = opts.get('change')
1746 stat = opts.get('stat')
1746 stat = opts.get('stat')
1747 reverse = opts.get('reverse')
1747 reverse = opts.get('reverse')
1748
1748
1749 if revs and change:
1749 if revs and change:
1750 msg = _('cannot specify --rev and --change at the same time')
1750 msg = _('cannot specify --rev and --change at the same time')
1751 raise util.Abort(msg)
1751 raise util.Abort(msg)
1752 elif change:
1752 elif change:
1753 node2 = cmdutil.revsingle(repo, change, None).node()
1753 node2 = cmdutil.revsingle(repo, change, None).node()
1754 node1 = repo[node2].p1().node()
1754 node1 = repo[node2].p1().node()
1755 else:
1755 else:
1756 node1, node2 = cmdutil.revpair(repo, revs)
1756 node1, node2 = cmdutil.revpair(repo, revs)
1757
1757
1758 if reverse:
1758 if reverse:
1759 node1, node2 = node2, node1
1759 node1, node2 = node2, node1
1760
1760
1761 diffopts = patch.diffopts(ui, opts)
1761 diffopts = patch.diffopts(ui, opts)
1762 m = cmdutil.match(repo, pats, opts)
1762 m = cmdutil.match(repo, pats, opts)
1763 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1763 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1764 listsubrepos=opts.get('subrepos'))
1764 listsubrepos=opts.get('subrepos'))
1765
1765
1766 def export(ui, repo, *changesets, **opts):
1766 def export(ui, repo, *changesets, **opts):
1767 """dump the header and diffs for one or more changesets
1767 """dump the header and diffs for one or more changesets
1768
1768
1769 Print the changeset header and diffs for one or more revisions.
1769 Print the changeset header and diffs for one or more revisions.
1770
1770
1771 The information shown in the changeset header is: author, date,
1771 The information shown in the changeset header is: author, date,
1772 branch name (if non-default), changeset hash, parent(s) and commit
1772 branch name (if non-default), changeset hash, parent(s) and commit
1773 comment.
1773 comment.
1774
1774
1775 .. note::
1775 .. note::
1776 export may generate unexpected diff output for merge
1776 export may generate unexpected diff output for merge
1777 changesets, as it will compare the merge changeset against its
1777 changesets, as it will compare the merge changeset against its
1778 first parent only.
1778 first parent only.
1779
1779
1780 Output may be to a file, in which case the name of the file is
1780 Output may be to a file, in which case the name of the file is
1781 given using a format string. The formatting rules are as follows:
1781 given using a format string. The formatting rules are as follows:
1782
1782
1783 :``%%``: literal "%" character
1783 :``%%``: literal "%" character
1784 :``%H``: changeset hash (40 hexadecimal digits)
1784 :``%H``: changeset hash (40 hexadecimal digits)
1785 :``%N``: number of patches being generated
1785 :``%N``: number of patches being generated
1786 :``%R``: changeset revision number
1786 :``%R``: changeset revision number
1787 :``%b``: basename of the exporting repository
1787 :``%b``: basename of the exporting repository
1788 :``%h``: short-form changeset hash (12 hexadecimal digits)
1788 :``%h``: short-form changeset hash (12 hexadecimal digits)
1789 :``%n``: zero-padded sequence number, starting at 1
1789 :``%n``: zero-padded sequence number, starting at 1
1790 :``%r``: zero-padded changeset revision number
1790 :``%r``: zero-padded changeset revision number
1791
1791
1792 Without the -a/--text option, export will avoid generating diffs
1792 Without the -a/--text option, export will avoid generating diffs
1793 of files it detects as binary. With -a, export will generate a
1793 of files it detects as binary. With -a, export will generate a
1794 diff anyway, probably with undesirable results.
1794 diff anyway, probably with undesirable results.
1795
1795
1796 Use the -g/--git option to generate diffs in the git extended diff
1796 Use the -g/--git option to generate diffs in the git extended diff
1797 format. See :hg:`help diffs` for more information.
1797 format. See :hg:`help diffs` for more information.
1798
1798
1799 With the --switch-parent option, the diff will be against the
1799 With the --switch-parent option, the diff will be against the
1800 second parent. It can be useful to review a merge.
1800 second parent. It can be useful to review a merge.
1801
1801
1802 Returns 0 on success.
1802 Returns 0 on success.
1803 """
1803 """
1804 changesets += tuple(opts.get('rev', []))
1804 changesets += tuple(opts.get('rev', []))
1805 if not changesets:
1805 if not changesets:
1806 raise util.Abort(_("export requires at least one changeset"))
1806 raise util.Abort(_("export requires at least one changeset"))
1807 revs = cmdutil.revrange(repo, changesets)
1807 revs = cmdutil.revrange(repo, changesets)
1808 if len(revs) > 1:
1808 if len(revs) > 1:
1809 ui.note(_('exporting patches:\n'))
1809 ui.note(_('exporting patches:\n'))
1810 else:
1810 else:
1811 ui.note(_('exporting patch:\n'))
1811 ui.note(_('exporting patch:\n'))
1812 cmdutil.export(repo, revs, template=opts.get('output'),
1812 cmdutil.export(repo, revs, template=opts.get('output'),
1813 switch_parent=opts.get('switch_parent'),
1813 switch_parent=opts.get('switch_parent'),
1814 opts=patch.diffopts(ui, opts))
1814 opts=patch.diffopts(ui, opts))
1815
1815
1816 def forget(ui, repo, *pats, **opts):
1816 def forget(ui, repo, *pats, **opts):
1817 """forget the specified files on the next commit
1817 """forget the specified files on the next commit
1818
1818
1819 Mark the specified files so they will no longer be tracked
1819 Mark the specified files so they will no longer be tracked
1820 after the next commit.
1820 after the next commit.
1821
1821
1822 This only removes files from the current branch, not from the
1822 This only removes files from the current branch, not from the
1823 entire project history, and it does not delete them from the
1823 entire project history, and it does not delete them from the
1824 working directory.
1824 working directory.
1825
1825
1826 To undo a forget before the next commit, see :hg:`add`.
1826 To undo a forget before the next commit, see :hg:`add`.
1827
1827
1828 Returns 0 on success.
1828 Returns 0 on success.
1829 """
1829 """
1830
1830
1831 if not pats:
1831 if not pats:
1832 raise util.Abort(_('no files specified'))
1832 raise util.Abort(_('no files specified'))
1833
1833
1834 m = cmdutil.match(repo, pats, opts)
1834 m = cmdutil.match(repo, pats, opts)
1835 s = repo.status(match=m, clean=True)
1835 s = repo.status(match=m, clean=True)
1836 forget = sorted(s[0] + s[1] + s[3] + s[6])
1836 forget = sorted(s[0] + s[1] + s[3] + s[6])
1837 errs = 0
1837 errs = 0
1838
1838
1839 for f in m.files():
1839 for f in m.files():
1840 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1840 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1841 ui.warn(_('not removing %s: file is already untracked\n')
1841 ui.warn(_('not removing %s: file is already untracked\n')
1842 % m.rel(f))
1842 % m.rel(f))
1843 errs = 1
1843 errs = 1
1844
1844
1845 for f in forget:
1845 for f in forget:
1846 if ui.verbose or not m.exact(f):
1846 if ui.verbose or not m.exact(f):
1847 ui.status(_('removing %s\n') % m.rel(f))
1847 ui.status(_('removing %s\n') % m.rel(f))
1848
1848
1849 repo[None].remove(forget, unlink=False)
1849 repo[None].remove(forget, unlink=False)
1850 return errs
1850 return errs
1851
1851
1852 def grep(ui, repo, pattern, *pats, **opts):
1852 def grep(ui, repo, pattern, *pats, **opts):
1853 """search for a pattern in specified files and revisions
1853 """search for a pattern in specified files and revisions
1854
1854
1855 Search revisions of files for a regular expression.
1855 Search revisions of files for a regular expression.
1856
1856
1857 This command behaves differently than Unix grep. It only accepts
1857 This command behaves differently than Unix grep. It only accepts
1858 Python/Perl regexps. It searches repository history, not the
1858 Python/Perl regexps. It searches repository history, not the
1859 working directory. It always prints the revision number in which a
1859 working directory. It always prints the revision number in which a
1860 match appears.
1860 match appears.
1861
1861
1862 By default, grep only prints output for the first revision of a
1862 By default, grep only prints output for the first revision of a
1863 file in which it finds a match. To get it to print every revision
1863 file in which it finds a match. To get it to print every revision
1864 that contains a change in match status ("-" for a match that
1864 that contains a change in match status ("-" for a match that
1865 becomes a non-match, or "+" for a non-match that becomes a match),
1865 becomes a non-match, or "+" for a non-match that becomes a match),
1866 use the --all flag.
1866 use the --all flag.
1867
1867
1868 Returns 0 if a match is found, 1 otherwise.
1868 Returns 0 if a match is found, 1 otherwise.
1869 """
1869 """
1870 reflags = 0
1870 reflags = 0
1871 if opts.get('ignore_case'):
1871 if opts.get('ignore_case'):
1872 reflags |= re.I
1872 reflags |= re.I
1873 try:
1873 try:
1874 regexp = re.compile(pattern, reflags)
1874 regexp = re.compile(pattern, reflags)
1875 except re.error, inst:
1875 except re.error, inst:
1876 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1876 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1877 return 1
1877 return 1
1878 sep, eol = ':', '\n'
1878 sep, eol = ':', '\n'
1879 if opts.get('print0'):
1879 if opts.get('print0'):
1880 sep = eol = '\0'
1880 sep = eol = '\0'
1881
1881
1882 getfile = util.lrucachefunc(repo.file)
1882 getfile = util.lrucachefunc(repo.file)
1883
1883
1884 def matchlines(body):
1884 def matchlines(body):
1885 begin = 0
1885 begin = 0
1886 linenum = 0
1886 linenum = 0
1887 while True:
1887 while True:
1888 match = regexp.search(body, begin)
1888 match = regexp.search(body, begin)
1889 if not match:
1889 if not match:
1890 break
1890 break
1891 mstart, mend = match.span()
1891 mstart, mend = match.span()
1892 linenum += body.count('\n', begin, mstart) + 1
1892 linenum += body.count('\n', begin, mstart) + 1
1893 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1893 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1894 begin = body.find('\n', mend) + 1 or len(body)
1894 begin = body.find('\n', mend) + 1 or len(body)
1895 lend = begin - 1
1895 lend = begin - 1
1896 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1896 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1897
1897
1898 class linestate(object):
1898 class linestate(object):
1899 def __init__(self, line, linenum, colstart, colend):
1899 def __init__(self, line, linenum, colstart, colend):
1900 self.line = line
1900 self.line = line
1901 self.linenum = linenum
1901 self.linenum = linenum
1902 self.colstart = colstart
1902 self.colstart = colstart
1903 self.colend = colend
1903 self.colend = colend
1904
1904
1905 def __hash__(self):
1905 def __hash__(self):
1906 return hash((self.linenum, self.line))
1906 return hash((self.linenum, self.line))
1907
1907
1908 def __eq__(self, other):
1908 def __eq__(self, other):
1909 return self.line == other.line
1909 return self.line == other.line
1910
1910
1911 matches = {}
1911 matches = {}
1912 copies = {}
1912 copies = {}
1913 def grepbody(fn, rev, body):
1913 def grepbody(fn, rev, body):
1914 matches[rev].setdefault(fn, [])
1914 matches[rev].setdefault(fn, [])
1915 m = matches[rev][fn]
1915 m = matches[rev][fn]
1916 for lnum, cstart, cend, line in matchlines(body):
1916 for lnum, cstart, cend, line in matchlines(body):
1917 s = linestate(line, lnum, cstart, cend)
1917 s = linestate(line, lnum, cstart, cend)
1918 m.append(s)
1918 m.append(s)
1919
1919
1920 def difflinestates(a, b):
1920 def difflinestates(a, b):
1921 sm = difflib.SequenceMatcher(None, a, b)
1921 sm = difflib.SequenceMatcher(None, a, b)
1922 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1922 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1923 if tag == 'insert':
1923 if tag == 'insert':
1924 for i in xrange(blo, bhi):
1924 for i in xrange(blo, bhi):
1925 yield ('+', b[i])
1925 yield ('+', b[i])
1926 elif tag == 'delete':
1926 elif tag == 'delete':
1927 for i in xrange(alo, ahi):
1927 for i in xrange(alo, ahi):
1928 yield ('-', a[i])
1928 yield ('-', a[i])
1929 elif tag == 'replace':
1929 elif tag == 'replace':
1930 for i in xrange(alo, ahi):
1930 for i in xrange(alo, ahi):
1931 yield ('-', a[i])
1931 yield ('-', a[i])
1932 for i in xrange(blo, bhi):
1932 for i in xrange(blo, bhi):
1933 yield ('+', b[i])
1933 yield ('+', b[i])
1934
1934
1935 def display(fn, ctx, pstates, states):
1935 def display(fn, ctx, pstates, states):
1936 rev = ctx.rev()
1936 rev = ctx.rev()
1937 datefunc = ui.quiet and util.shortdate or util.datestr
1937 datefunc = ui.quiet and util.shortdate or util.datestr
1938 found = False
1938 found = False
1939 filerevmatches = {}
1939 filerevmatches = {}
1940 def binary():
1940 def binary():
1941 flog = getfile(fn)
1941 flog = getfile(fn)
1942 return util.binary(flog.read(ctx.filenode(fn)))
1942 return util.binary(flog.read(ctx.filenode(fn)))
1943
1943
1944 if opts.get('all'):
1944 if opts.get('all'):
1945 iter = difflinestates(pstates, states)
1945 iter = difflinestates(pstates, states)
1946 else:
1946 else:
1947 iter = [('', l) for l in states]
1947 iter = [('', l) for l in states]
1948 for change, l in iter:
1948 for change, l in iter:
1949 cols = [fn, str(rev)]
1949 cols = [fn, str(rev)]
1950 before, match, after = None, None, None
1950 before, match, after = None, None, None
1951 if opts.get('line_number'):
1951 if opts.get('line_number'):
1952 cols.append(str(l.linenum))
1952 cols.append(str(l.linenum))
1953 if opts.get('all'):
1953 if opts.get('all'):
1954 cols.append(change)
1954 cols.append(change)
1955 if opts.get('user'):
1955 if opts.get('user'):
1956 cols.append(ui.shortuser(ctx.user()))
1956 cols.append(ui.shortuser(ctx.user()))
1957 if opts.get('date'):
1957 if opts.get('date'):
1958 cols.append(datefunc(ctx.date()))
1958 cols.append(datefunc(ctx.date()))
1959 if opts.get('files_with_matches'):
1959 if opts.get('files_with_matches'):
1960 c = (fn, rev)
1960 c = (fn, rev)
1961 if c in filerevmatches:
1961 if c in filerevmatches:
1962 continue
1962 continue
1963 filerevmatches[c] = 1
1963 filerevmatches[c] = 1
1964 else:
1964 else:
1965 before = l.line[:l.colstart]
1965 before = l.line[:l.colstart]
1966 match = l.line[l.colstart:l.colend]
1966 match = l.line[l.colstart:l.colend]
1967 after = l.line[l.colend:]
1967 after = l.line[l.colend:]
1968 ui.write(sep.join(cols))
1968 ui.write(sep.join(cols))
1969 if before is not None:
1969 if before is not None:
1970 if not opts.get('text') and binary():
1970 if not opts.get('text') and binary():
1971 ui.write(sep + " Binary file matches")
1971 ui.write(sep + " Binary file matches")
1972 else:
1972 else:
1973 ui.write(sep + before)
1973 ui.write(sep + before)
1974 ui.write(match, label='grep.match')
1974 ui.write(match, label='grep.match')
1975 ui.write(after)
1975 ui.write(after)
1976 ui.write(eol)
1976 ui.write(eol)
1977 found = True
1977 found = True
1978 return found
1978 return found
1979
1979
1980 skip = {}
1980 skip = {}
1981 revfiles = {}
1981 revfiles = {}
1982 matchfn = cmdutil.match(repo, pats, opts)
1982 matchfn = cmdutil.match(repo, pats, opts)
1983 found = False
1983 found = False
1984 follow = opts.get('follow')
1984 follow = opts.get('follow')
1985
1985
1986 def prep(ctx, fns):
1986 def prep(ctx, fns):
1987 rev = ctx.rev()
1987 rev = ctx.rev()
1988 pctx = ctx.p1()
1988 pctx = ctx.p1()
1989 parent = pctx.rev()
1989 parent = pctx.rev()
1990 matches.setdefault(rev, {})
1990 matches.setdefault(rev, {})
1991 matches.setdefault(parent, {})
1991 matches.setdefault(parent, {})
1992 files = revfiles.setdefault(rev, [])
1992 files = revfiles.setdefault(rev, [])
1993 for fn in fns:
1993 for fn in fns:
1994 flog = getfile(fn)
1994 flog = getfile(fn)
1995 try:
1995 try:
1996 fnode = ctx.filenode(fn)
1996 fnode = ctx.filenode(fn)
1997 except error.LookupError:
1997 except error.LookupError:
1998 continue
1998 continue
1999
1999
2000 copied = flog.renamed(fnode)
2000 copied = flog.renamed(fnode)
2001 copy = follow and copied and copied[0]
2001 copy = follow and copied and copied[0]
2002 if copy:
2002 if copy:
2003 copies.setdefault(rev, {})[fn] = copy
2003 copies.setdefault(rev, {})[fn] = copy
2004 if fn in skip:
2004 if fn in skip:
2005 if copy:
2005 if copy:
2006 skip[copy] = True
2006 skip[copy] = True
2007 continue
2007 continue
2008 files.append(fn)
2008 files.append(fn)
2009
2009
2010 if fn not in matches[rev]:
2010 if fn not in matches[rev]:
2011 grepbody(fn, rev, flog.read(fnode))
2011 grepbody(fn, rev, flog.read(fnode))
2012
2012
2013 pfn = copy or fn
2013 pfn = copy or fn
2014 if pfn not in matches[parent]:
2014 if pfn not in matches[parent]:
2015 try:
2015 try:
2016 fnode = pctx.filenode(pfn)
2016 fnode = pctx.filenode(pfn)
2017 grepbody(pfn, parent, flog.read(fnode))
2017 grepbody(pfn, parent, flog.read(fnode))
2018 except error.LookupError:
2018 except error.LookupError:
2019 pass
2019 pass
2020
2020
2021 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2021 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2022 rev = ctx.rev()
2022 rev = ctx.rev()
2023 parent = ctx.p1().rev()
2023 parent = ctx.p1().rev()
2024 for fn in sorted(revfiles.get(rev, [])):
2024 for fn in sorted(revfiles.get(rev, [])):
2025 states = matches[rev][fn]
2025 states = matches[rev][fn]
2026 copy = copies.get(rev, {}).get(fn)
2026 copy = copies.get(rev, {}).get(fn)
2027 if fn in skip:
2027 if fn in skip:
2028 if copy:
2028 if copy:
2029 skip[copy] = True
2029 skip[copy] = True
2030 continue
2030 continue
2031 pstates = matches.get(parent, {}).get(copy or fn, [])
2031 pstates = matches.get(parent, {}).get(copy or fn, [])
2032 if pstates or states:
2032 if pstates or states:
2033 r = display(fn, ctx, pstates, states)
2033 r = display(fn, ctx, pstates, states)
2034 found = found or r
2034 found = found or r
2035 if r and not opts.get('all'):
2035 if r and not opts.get('all'):
2036 skip[fn] = True
2036 skip[fn] = True
2037 if copy:
2037 if copy:
2038 skip[copy] = True
2038 skip[copy] = True
2039 del matches[rev]
2039 del matches[rev]
2040 del revfiles[rev]
2040 del revfiles[rev]
2041
2041
2042 return not found
2042 return not found
2043
2043
2044 def heads(ui, repo, *branchrevs, **opts):
2044 def heads(ui, repo, *branchrevs, **opts):
2045 """show current repository heads or show branch heads
2045 """show current repository heads or show branch heads
2046
2046
2047 With no arguments, show all repository branch heads.
2047 With no arguments, show all repository branch heads.
2048
2048
2049 Repository "heads" are changesets with no child changesets. They are
2049 Repository "heads" are changesets with no child changesets. They are
2050 where development generally takes place and are the usual targets
2050 where development generally takes place and are the usual targets
2051 for update and merge operations. Branch heads are changesets that have
2051 for update and merge operations. Branch heads are changesets that have
2052 no child changeset on the same branch.
2052 no child changeset on the same branch.
2053
2053
2054 If one or more REVs are given, only branch heads on the branches
2054 If one or more REVs are given, only branch heads on the branches
2055 associated with the specified changesets are shown.
2055 associated with the specified changesets are shown.
2056
2056
2057 If -c/--closed is specified, also show branch heads marked closed
2057 If -c/--closed is specified, also show branch heads marked closed
2058 (see :hg:`commit --close-branch`).
2058 (see :hg:`commit --close-branch`).
2059
2059
2060 If STARTREV is specified, only those heads that are descendants of
2060 If STARTREV is specified, only those heads that are descendants of
2061 STARTREV will be displayed.
2061 STARTREV will be displayed.
2062
2062
2063 If -t/--topo is specified, named branch mechanics will be ignored and only
2063 If -t/--topo is specified, named branch mechanics will be ignored and only
2064 changesets without children will be shown.
2064 changesets without children will be shown.
2065
2065
2066 Returns 0 if matching heads are found, 1 if not.
2066 Returns 0 if matching heads are found, 1 if not.
2067 """
2067 """
2068
2068
2069 start = None
2069 start = None
2070 if 'rev' in opts:
2070 if 'rev' in opts:
2071 start = cmdutil.revsingle(repo, opts['rev'], None).node()
2071 start = cmdutil.revsingle(repo, opts['rev'], None).node()
2072
2072
2073 if opts.get('topo'):
2073 if opts.get('topo'):
2074 heads = [repo[h] for h in repo.heads(start)]
2074 heads = [repo[h] for h in repo.heads(start)]
2075 else:
2075 else:
2076 heads = []
2076 heads = []
2077 for b, ls in repo.branchmap().iteritems():
2077 for b, ls in repo.branchmap().iteritems():
2078 if start is None:
2078 if start is None:
2079 heads += [repo[h] for h in ls]
2079 heads += [repo[h] for h in ls]
2080 continue
2080 continue
2081 startrev = repo.changelog.rev(start)
2081 startrev = repo.changelog.rev(start)
2082 descendants = set(repo.changelog.descendants(startrev))
2082 descendants = set(repo.changelog.descendants(startrev))
2083 descendants.add(startrev)
2083 descendants.add(startrev)
2084 rev = repo.changelog.rev
2084 rev = repo.changelog.rev
2085 heads += [repo[h] for h in ls if rev(h) in descendants]
2085 heads += [repo[h] for h in ls if rev(h) in descendants]
2086
2086
2087 if branchrevs:
2087 if branchrevs:
2088 branches = set(repo[br].branch() for br in branchrevs)
2088 branches = set(repo[br].branch() for br in branchrevs)
2089 heads = [h for h in heads if h.branch() in branches]
2089 heads = [h for h in heads if h.branch() in branches]
2090
2090
2091 if not opts.get('closed'):
2091 if not opts.get('closed'):
2092 heads = [h for h in heads if not h.extra().get('close')]
2092 heads = [h for h in heads if not h.extra().get('close')]
2093
2093
2094 if opts.get('active') and branchrevs:
2094 if opts.get('active') and branchrevs:
2095 dagheads = repo.heads(start)
2095 dagheads = repo.heads(start)
2096 heads = [h for h in heads if h.node() in dagheads]
2096 heads = [h for h in heads if h.node() in dagheads]
2097
2097
2098 if branchrevs:
2098 if branchrevs:
2099 haveheads = set(h.branch() for h in heads)
2099 haveheads = set(h.branch() for h in heads)
2100 if branches - haveheads:
2100 if branches - haveheads:
2101 headless = ', '.join(b for b in branches - haveheads)
2101 headless = ', '.join(b for b in branches - haveheads)
2102 msg = _('no open branch heads found on branches %s')
2102 msg = _('no open branch heads found on branches %s')
2103 if opts.get('rev'):
2103 if opts.get('rev'):
2104 msg += _(' (started at %s)' % opts['rev'])
2104 msg += _(' (started at %s)' % opts['rev'])
2105 ui.warn((msg + '\n') % headless)
2105 ui.warn((msg + '\n') % headless)
2106
2106
2107 if not heads:
2107 if not heads:
2108 return 1
2108 return 1
2109
2109
2110 heads = sorted(heads, key=lambda x: -x.rev())
2110 heads = sorted(heads, key=lambda x: -x.rev())
2111 displayer = cmdutil.show_changeset(ui, repo, opts)
2111 displayer = cmdutil.show_changeset(ui, repo, opts)
2112 for ctx in heads:
2112 for ctx in heads:
2113 displayer.show(ctx)
2113 displayer.show(ctx)
2114 displayer.close()
2114 displayer.close()
2115
2115
2116 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True):
2116 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True):
2117 """show help for a given topic or a help overview
2117 """show help for a given topic or a help overview
2118
2118
2119 With no arguments, print a list of commands with short help messages.
2119 With no arguments, print a list of commands with short help messages.
2120
2120
2121 Given a topic, extension, or command name, print help for that
2121 Given a topic, extension, or command name, print help for that
2122 topic.
2122 topic.
2123
2123
2124 Returns 0 if successful.
2124 Returns 0 if successful.
2125 """
2125 """
2126 option_lists = []
2126 option_lists = []
2127 textwidth = min(ui.termwidth(), 80) - 2
2127 textwidth = min(ui.termwidth(), 80) - 2
2128
2128
2129 def addglobalopts(aliases):
2129 def addglobalopts(aliases):
2130 if ui.verbose:
2130 if ui.verbose:
2131 option_lists.append((_("global options:"), globalopts))
2131 option_lists.append((_("global options:"), globalopts))
2132 if name == 'shortlist':
2132 if name == 'shortlist':
2133 option_lists.append((_('use "hg help" for the full list '
2133 option_lists.append((_('use "hg help" for the full list '
2134 'of commands'), ()))
2134 'of commands'), ()))
2135 else:
2135 else:
2136 if name == 'shortlist':
2136 if name == 'shortlist':
2137 msg = _('use "hg help" for the full list of commands '
2137 msg = _('use "hg help" for the full list of commands '
2138 'or "hg -v" for details')
2138 'or "hg -v" for details')
2139 elif name and not full:
2139 elif name and not full:
2140 msg = _('use "hg help %s" to show the full help text' % name)
2140 msg = _('use "hg help %s" to show the full help text' % name)
2141 elif aliases:
2141 elif aliases:
2142 msg = _('use "hg -v help%s" to show builtin aliases and '
2142 msg = _('use "hg -v help%s" to show builtin aliases and '
2143 'global options') % (name and " " + name or "")
2143 'global options') % (name and " " + name or "")
2144 else:
2144 else:
2145 msg = _('use "hg -v help %s" to show global options') % name
2145 msg = _('use "hg -v help %s" to show global options') % name
2146 option_lists.append((msg, ()))
2146 option_lists.append((msg, ()))
2147
2147
2148 def helpcmd(name):
2148 def helpcmd(name):
2149 if with_version:
2149 if with_version:
2150 version_(ui)
2150 version_(ui)
2151 ui.write('\n')
2151 ui.write('\n')
2152
2152
2153 try:
2153 try:
2154 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2154 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2155 except error.AmbiguousCommand, inst:
2155 except error.AmbiguousCommand, inst:
2156 # py3k fix: except vars can't be used outside the scope of the
2156 # py3k fix: except vars can't be used outside the scope of the
2157 # except block, nor can be used inside a lambda. python issue4617
2157 # except block, nor can be used inside a lambda. python issue4617
2158 prefix = inst.args[0]
2158 prefix = inst.args[0]
2159 select = lambda c: c.lstrip('^').startswith(prefix)
2159 select = lambda c: c.lstrip('^').startswith(prefix)
2160 helplist(_('list of commands:\n\n'), select)
2160 helplist(_('list of commands:\n\n'), select)
2161 return
2161 return
2162
2162
2163 # check if it's an invalid alias and display its error if it is
2163 # check if it's an invalid alias and display its error if it is
2164 if getattr(entry[0], 'badalias', False):
2164 if getattr(entry[0], 'badalias', False):
2165 if not unknowncmd:
2165 if not unknowncmd:
2166 entry[0](ui)
2166 entry[0](ui)
2167 return
2167 return
2168
2168
2169 # synopsis
2169 # synopsis
2170 if len(entry) > 2:
2170 if len(entry) > 2:
2171 if entry[2].startswith('hg'):
2171 if entry[2].startswith('hg'):
2172 ui.write("%s\n" % entry[2])
2172 ui.write("%s\n" % entry[2])
2173 else:
2173 else:
2174 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2174 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2175 else:
2175 else:
2176 ui.write('hg %s\n' % aliases[0])
2176 ui.write('hg %s\n' % aliases[0])
2177
2177
2178 # aliases
2178 # aliases
2179 if full and not ui.quiet and len(aliases) > 1:
2179 if full and not ui.quiet and len(aliases) > 1:
2180 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2180 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2181
2181
2182 # description
2182 # description
2183 doc = gettext(entry[0].__doc__)
2183 doc = gettext(entry[0].__doc__)
2184 if not doc:
2184 if not doc:
2185 doc = _("(no help text available)")
2185 doc = _("(no help text available)")
2186 if hasattr(entry[0], 'definition'): # aliased command
2186 if hasattr(entry[0], 'definition'): # aliased command
2187 if entry[0].definition.startswith('!'): # shell alias
2187 if entry[0].definition.startswith('!'): # shell alias
2188 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2188 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2189 else:
2189 else:
2190 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2190 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2191 if ui.quiet or not full:
2191 if ui.quiet or not full:
2192 doc = doc.splitlines()[0]
2192 doc = doc.splitlines()[0]
2193 keep = ui.verbose and ['verbose'] or []
2193 keep = ui.verbose and ['verbose'] or []
2194 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2194 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2195 ui.write("\n%s\n" % formatted)
2195 ui.write("\n%s\n" % formatted)
2196 if pruned:
2196 if pruned:
2197 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2197 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2198
2198
2199 if not ui.quiet:
2199 if not ui.quiet:
2200 # options
2200 # options
2201 if entry[1]:
2201 if entry[1]:
2202 option_lists.append((_("options:\n"), entry[1]))
2202 option_lists.append((_("options:\n"), entry[1]))
2203
2203
2204 addglobalopts(False)
2204 addglobalopts(False)
2205
2205
2206 def helplist(header, select=None):
2206 def helplist(header, select=None):
2207 h = {}
2207 h = {}
2208 cmds = {}
2208 cmds = {}
2209 for c, e in table.iteritems():
2209 for c, e in table.iteritems():
2210 f = c.split("|", 1)[0]
2210 f = c.split("|", 1)[0]
2211 if select and not select(f):
2211 if select and not select(f):
2212 continue
2212 continue
2213 if (not select and name != 'shortlist' and
2213 if (not select and name != 'shortlist' and
2214 e[0].__module__ != __name__):
2214 e[0].__module__ != __name__):
2215 continue
2215 continue
2216 if name == "shortlist" and not f.startswith("^"):
2216 if name == "shortlist" and not f.startswith("^"):
2217 continue
2217 continue
2218 f = f.lstrip("^")
2218 f = f.lstrip("^")
2219 if not ui.debugflag and f.startswith("debug"):
2219 if not ui.debugflag and f.startswith("debug"):
2220 continue
2220 continue
2221 doc = e[0].__doc__
2221 doc = e[0].__doc__
2222 if doc and 'DEPRECATED' in doc and not ui.verbose:
2222 if doc and 'DEPRECATED' in doc and not ui.verbose:
2223 continue
2223 continue
2224 doc = gettext(doc)
2224 doc = gettext(doc)
2225 if not doc:
2225 if not doc:
2226 doc = _("(no help text available)")
2226 doc = _("(no help text available)")
2227 h[f] = doc.splitlines()[0].rstrip()
2227 h[f] = doc.splitlines()[0].rstrip()
2228 cmds[f] = c.lstrip("^")
2228 cmds[f] = c.lstrip("^")
2229
2229
2230 if not h:
2230 if not h:
2231 ui.status(_('no commands defined\n'))
2231 ui.status(_('no commands defined\n'))
2232 return
2232 return
2233
2233
2234 ui.status(header)
2234 ui.status(header)
2235 fns = sorted(h)
2235 fns = sorted(h)
2236 m = max(map(len, fns))
2236 m = max(map(len, fns))
2237 for f in fns:
2237 for f in fns:
2238 if ui.verbose:
2238 if ui.verbose:
2239 commands = cmds[f].replace("|",", ")
2239 commands = cmds[f].replace("|",", ")
2240 ui.write(" %s:\n %s\n"%(commands, h[f]))
2240 ui.write(" %s:\n %s\n"%(commands, h[f]))
2241 else:
2241 else:
2242 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2242 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2243 initindent=' %-*s ' % (m, f),
2243 initindent=' %-*s ' % (m, f),
2244 hangindent=' ' * (m + 4))))
2244 hangindent=' ' * (m + 4))))
2245
2245
2246 if not ui.quiet:
2246 if not ui.quiet:
2247 addglobalopts(True)
2247 addglobalopts(True)
2248
2248
2249 def helptopic(name):
2249 def helptopic(name):
2250 for names, header, doc in help.helptable:
2250 for names, header, doc in help.helptable:
2251 if name in names:
2251 if name in names:
2252 break
2252 break
2253 else:
2253 else:
2254 raise error.UnknownCommand(name)
2254 raise error.UnknownCommand(name)
2255
2255
2256 # description
2256 # description
2257 if not doc:
2257 if not doc:
2258 doc = _("(no help text available)")
2258 doc = _("(no help text available)")
2259 if hasattr(doc, '__call__'):
2259 if hasattr(doc, '__call__'):
2260 doc = doc()
2260 doc = doc()
2261
2261
2262 ui.write("%s\n\n" % header)
2262 ui.write("%s\n\n" % header)
2263 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2263 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2264
2264
2265 def helpext(name):
2265 def helpext(name):
2266 try:
2266 try:
2267 mod = extensions.find(name)
2267 mod = extensions.find(name)
2268 doc = gettext(mod.__doc__) or _('no help text available')
2268 doc = gettext(mod.__doc__) or _('no help text available')
2269 except KeyError:
2269 except KeyError:
2270 mod = None
2270 mod = None
2271 doc = extensions.disabledext(name)
2271 doc = extensions.disabledext(name)
2272 if not doc:
2272 if not doc:
2273 raise error.UnknownCommand(name)
2273 raise error.UnknownCommand(name)
2274
2274
2275 if '\n' not in doc:
2275 if '\n' not in doc:
2276 head, tail = doc, ""
2276 head, tail = doc, ""
2277 else:
2277 else:
2278 head, tail = doc.split('\n', 1)
2278 head, tail = doc.split('\n', 1)
2279 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2279 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2280 if tail:
2280 if tail:
2281 ui.write(minirst.format(tail, textwidth))
2281 ui.write(minirst.format(tail, textwidth))
2282 ui.status('\n\n')
2282 ui.status('\n\n')
2283
2283
2284 if mod:
2284 if mod:
2285 try:
2285 try:
2286 ct = mod.cmdtable
2286 ct = mod.cmdtable
2287 except AttributeError:
2287 except AttributeError:
2288 ct = {}
2288 ct = {}
2289 modcmds = set([c.split('|', 1)[0] for c in ct])
2289 modcmds = set([c.split('|', 1)[0] for c in ct])
2290 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2290 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2291 else:
2291 else:
2292 ui.write(_('use "hg help extensions" for information on enabling '
2292 ui.write(_('use "hg help extensions" for information on enabling '
2293 'extensions\n'))
2293 'extensions\n'))
2294
2294
2295 def helpextcmd(name):
2295 def helpextcmd(name):
2296 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2296 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2297 doc = gettext(mod.__doc__).splitlines()[0]
2297 doc = gettext(mod.__doc__).splitlines()[0]
2298
2298
2299 msg = help.listexts(_("'%s' is provided by the following "
2299 msg = help.listexts(_("'%s' is provided by the following "
2300 "extension:") % cmd, {ext: doc}, len(ext),
2300 "extension:") % cmd, {ext: doc}, len(ext),
2301 indent=4)
2301 indent=4)
2302 ui.write(minirst.format(msg, textwidth))
2302 ui.write(minirst.format(msg, textwidth))
2303 ui.write('\n\n')
2303 ui.write('\n\n')
2304 ui.write(_('use "hg help extensions" for information on enabling '
2304 ui.write(_('use "hg help extensions" for information on enabling '
2305 'extensions\n'))
2305 'extensions\n'))
2306
2306
2307 help.addtopichook('revsets', revset.makedoc)
2307 help.addtopichook('revsets', revset.makedoc)
2308 help.addtopichook('templates', templatekw.makedoc)
2308 help.addtopichook('templates', templatekw.makedoc)
2309 help.addtopichook('templates', templatefilters.makedoc)
2309 help.addtopichook('templates', templatefilters.makedoc)
2310
2310
2311 if name and name != 'shortlist':
2311 if name and name != 'shortlist':
2312 i = None
2312 i = None
2313 if unknowncmd:
2313 if unknowncmd:
2314 queries = (helpextcmd,)
2314 queries = (helpextcmd,)
2315 else:
2315 else:
2316 queries = (helptopic, helpcmd, helpext, helpextcmd)
2316 queries = (helptopic, helpcmd, helpext, helpextcmd)
2317 for f in queries:
2317 for f in queries:
2318 try:
2318 try:
2319 f(name)
2319 f(name)
2320 i = None
2320 i = None
2321 break
2321 break
2322 except error.UnknownCommand, inst:
2322 except error.UnknownCommand, inst:
2323 i = inst
2323 i = inst
2324 if i:
2324 if i:
2325 raise i
2325 raise i
2326
2326
2327 else:
2327 else:
2328 # program name
2328 # program name
2329 if ui.verbose or with_version:
2329 if ui.verbose or with_version:
2330 version_(ui)
2330 version_(ui)
2331 else:
2331 else:
2332 ui.status(_("Mercurial Distributed SCM\n"))
2332 ui.status(_("Mercurial Distributed SCM\n"))
2333 ui.status('\n')
2333 ui.status('\n')
2334
2334
2335 # list of commands
2335 # list of commands
2336 if name == "shortlist":
2336 if name == "shortlist":
2337 header = _('basic commands:\n\n')
2337 header = _('basic commands:\n\n')
2338 else:
2338 else:
2339 header = _('list of commands:\n\n')
2339 header = _('list of commands:\n\n')
2340
2340
2341 helplist(header)
2341 helplist(header)
2342 if name != 'shortlist':
2342 if name != 'shortlist':
2343 exts, maxlength = extensions.enabled()
2343 exts, maxlength = extensions.enabled()
2344 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2344 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2345 if text:
2345 if text:
2346 ui.write("\n%s\n" % minirst.format(text, textwidth))
2346 ui.write("\n%s\n" % minirst.format(text, textwidth))
2347
2347
2348 # list all option lists
2348 # list all option lists
2349 opt_output = []
2349 opt_output = []
2350 multioccur = False
2350 multioccur = False
2351 for title, options in option_lists:
2351 for title, options in option_lists:
2352 opt_output.append(("\n%s" % title, None))
2352 opt_output.append(("\n%s" % title, None))
2353 for option in options:
2353 for option in options:
2354 if len(option) == 5:
2354 if len(option) == 5:
2355 shortopt, longopt, default, desc, optlabel = option
2355 shortopt, longopt, default, desc, optlabel = option
2356 else:
2356 else:
2357 shortopt, longopt, default, desc = option
2357 shortopt, longopt, default, desc = option
2358 optlabel = _("VALUE") # default label
2358 optlabel = _("VALUE") # default label
2359
2359
2360 if _("DEPRECATED") in desc and not ui.verbose:
2360 if _("DEPRECATED") in desc and not ui.verbose:
2361 continue
2361 continue
2362 if isinstance(default, list):
2362 if isinstance(default, list):
2363 numqualifier = " %s [+]" % optlabel
2363 numqualifier = " %s [+]" % optlabel
2364 multioccur = True
2364 multioccur = True
2365 elif (default is not None) and not isinstance(default, bool):
2365 elif (default is not None) and not isinstance(default, bool):
2366 numqualifier = " %s" % optlabel
2366 numqualifier = " %s" % optlabel
2367 else:
2367 else:
2368 numqualifier = ""
2368 numqualifier = ""
2369 opt_output.append(("%2s%s" %
2369 opt_output.append(("%2s%s" %
2370 (shortopt and "-%s" % shortopt,
2370 (shortopt and "-%s" % shortopt,
2371 longopt and " --%s%s" %
2371 longopt and " --%s%s" %
2372 (longopt, numqualifier)),
2372 (longopt, numqualifier)),
2373 "%s%s" % (desc,
2373 "%s%s" % (desc,
2374 default
2374 default
2375 and _(" (default: %s)") % default
2375 and _(" (default: %s)") % default
2376 or "")))
2376 or "")))
2377 if multioccur:
2377 if multioccur:
2378 msg = _("\n[+] marked option can be specified multiple times")
2378 msg = _("\n[+] marked option can be specified multiple times")
2379 if ui.verbose and name != 'shortlist':
2379 if ui.verbose and name != 'shortlist':
2380 opt_output.append((msg, None))
2380 opt_output.append((msg, None))
2381 else:
2381 else:
2382 opt_output.insert(-1, (msg, None))
2382 opt_output.insert(-1, (msg, None))
2383
2383
2384 if not name:
2384 if not name:
2385 ui.write(_("\nadditional help topics:\n\n"))
2385 ui.write(_("\nadditional help topics:\n\n"))
2386 topics = []
2386 topics = []
2387 for names, header, doc in help.helptable:
2387 for names, header, doc in help.helptable:
2388 topics.append((sorted(names, key=len, reverse=True)[0], header))
2388 topics.append((sorted(names, key=len, reverse=True)[0], header))
2389 topics_len = max([len(s[0]) for s in topics])
2389 topics_len = max([len(s[0]) for s in topics])
2390 for t, desc in topics:
2390 for t, desc in topics:
2391 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2391 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2392
2392
2393 if opt_output:
2393 if opt_output:
2394 colwidth = encoding.colwidth
2394 colwidth = encoding.colwidth
2395 # normalize: (opt or message, desc or None, width of opt)
2395 # normalize: (opt or message, desc or None, width of opt)
2396 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2396 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2397 for opt, desc in opt_output]
2397 for opt, desc in opt_output]
2398 hanging = max([e[2] for e in entries])
2398 hanging = max([e[2] for e in entries])
2399 for opt, desc, width in entries:
2399 for opt, desc, width in entries:
2400 if desc:
2400 if desc:
2401 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2401 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2402 hangindent = ' ' * (hanging + 3)
2402 hangindent = ' ' * (hanging + 3)
2403 ui.write('%s\n' % (util.wrap(desc, textwidth,
2403 ui.write('%s\n' % (util.wrap(desc, textwidth,
2404 initindent=initindent,
2404 initindent=initindent,
2405 hangindent=hangindent)))
2405 hangindent=hangindent)))
2406 else:
2406 else:
2407 ui.write("%s\n" % opt)
2407 ui.write("%s\n" % opt)
2408
2408
2409 def identify(ui, repo, source=None, rev=None,
2409 def identify(ui, repo, source=None, rev=None,
2410 num=None, id=None, branch=None, tags=None, bookmarks=None):
2410 num=None, id=None, branch=None, tags=None, bookmarks=None):
2411 """identify the working copy or specified revision
2411 """identify the working copy or specified revision
2412
2412
2413 Print a summary identifying the repository state at REV using one or
2413 Print a summary identifying the repository state at REV using one or
2414 two parent hash identifiers, followed by a "+" if the working
2414 two parent hash identifiers, followed by a "+" if the working
2415 directory has uncommitted changes, the branch name (if not default),
2415 directory has uncommitted changes, the branch name (if not default),
2416 a list of tags, and a list of bookmarks.
2416 a list of tags, and a list of bookmarks.
2417
2417
2418 When REV is not given, print a summary of the current state of the
2418 When REV is not given, print a summary of the current state of the
2419 repository.
2419 repository.
2420
2420
2421 Specifying a path to a repository root or Mercurial bundle will
2421 Specifying a path to a repository root or Mercurial bundle will
2422 cause lookup to operate on that repository/bundle.
2422 cause lookup to operate on that repository/bundle.
2423
2423
2424 Returns 0 if successful.
2424 Returns 0 if successful.
2425 """
2425 """
2426
2426
2427 if not repo and not source:
2427 if not repo and not source:
2428 raise util.Abort(_("there is no Mercurial repository here "
2428 raise util.Abort(_("there is no Mercurial repository here "
2429 "(.hg not found)"))
2429 "(.hg not found)"))
2430
2430
2431 hexfunc = ui.debugflag and hex or short
2431 hexfunc = ui.debugflag and hex or short
2432 default = not (num or id or branch or tags or bookmarks)
2432 default = not (num or id or branch or tags or bookmarks)
2433 output = []
2433 output = []
2434 revs = []
2434 revs = []
2435
2435
2436 if source:
2436 if source:
2437 source, branches = hg.parseurl(ui.expandpath(source))
2437 source, branches = hg.parseurl(ui.expandpath(source))
2438 repo = hg.repository(ui, source)
2438 repo = hg.repository(ui, source)
2439 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2439 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2440
2440
2441 if not repo.local():
2441 if not repo.local():
2442 if num or branch or tags:
2442 if num or branch or tags:
2443 raise util.Abort(
2443 raise util.Abort(
2444 _("can't query remote revision number, branch, or tags"))
2444 _("can't query remote revision number, branch, or tags"))
2445 if not rev and revs:
2445 if not rev and revs:
2446 rev = revs[0]
2446 rev = revs[0]
2447 if not rev:
2447 if not rev:
2448 rev = "tip"
2448 rev = "tip"
2449
2449
2450 remoterev = repo.lookup(rev)
2450 remoterev = repo.lookup(rev)
2451 if default or id:
2451 if default or id:
2452 output = [hexfunc(remoterev)]
2452 output = [hexfunc(remoterev)]
2453
2453
2454 def getbms():
2454 def getbms():
2455 bms = []
2455 bms = []
2456
2456
2457 if 'bookmarks' in repo.listkeys('namespaces'):
2457 if 'bookmarks' in repo.listkeys('namespaces'):
2458 hexremoterev = hex(remoterev)
2458 hexremoterev = hex(remoterev)
2459 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2459 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2460 if bmr == hexremoterev]
2460 if bmr == hexremoterev]
2461
2461
2462 return bms
2462 return bms
2463
2463
2464 if bookmarks:
2464 if bookmarks:
2465 output.extend(getbms())
2465 output.extend(getbms())
2466 elif default and not ui.quiet:
2466 elif default and not ui.quiet:
2467 # multiple bookmarks for a single parent separated by '/'
2467 # multiple bookmarks for a single parent separated by '/'
2468 bm = '/'.join(getbms())
2468 bm = '/'.join(getbms())
2469 if bm:
2469 if bm:
2470 output.append(bm)
2470 output.append(bm)
2471 else:
2471 else:
2472 if not rev:
2472 if not rev:
2473 ctx = repo[None]
2473 ctx = repo[None]
2474 parents = ctx.parents()
2474 parents = ctx.parents()
2475 changed = ""
2475 changed = ""
2476 if default or id or num:
2476 if default or id or num:
2477 changed = util.any(repo.status()) and "+" or ""
2477 changed = util.any(repo.status()) and "+" or ""
2478 if default or id:
2478 if default or id:
2479 output = ["%s%s" %
2479 output = ["%s%s" %
2480 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2480 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2481 if num:
2481 if num:
2482 output.append("%s%s" %
2482 output.append("%s%s" %
2483 ('+'.join([str(p.rev()) for p in parents]), changed))
2483 ('+'.join([str(p.rev()) for p in parents]), changed))
2484 else:
2484 else:
2485 ctx = cmdutil.revsingle(repo, rev)
2485 ctx = cmdutil.revsingle(repo, rev)
2486 if default or id:
2486 if default or id:
2487 output = [hexfunc(ctx.node())]
2487 output = [hexfunc(ctx.node())]
2488 if num:
2488 if num:
2489 output.append(str(ctx.rev()))
2489 output.append(str(ctx.rev()))
2490
2490
2491 if default and not ui.quiet:
2491 if default and not ui.quiet:
2492 b = ctx.branch()
2492 b = ctx.branch()
2493 if b != 'default':
2493 if b != 'default':
2494 output.append("(%s)" % b)
2494 output.append("(%s)" % b)
2495
2495
2496 # multiple tags for a single parent separated by '/'
2496 # multiple tags for a single parent separated by '/'
2497 t = '/'.join(ctx.tags())
2497 t = '/'.join(ctx.tags())
2498 if t:
2498 if t:
2499 output.append(t)
2499 output.append(t)
2500
2500
2501 # multiple bookmarks for a single parent separated by '/'
2501 # multiple bookmarks for a single parent separated by '/'
2502 bm = '/'.join(ctx.bookmarks())
2502 bm = '/'.join(ctx.bookmarks())
2503 if bm:
2503 if bm:
2504 output.append(bm)
2504 output.append(bm)
2505 else:
2505 else:
2506 if branch:
2506 if branch:
2507 output.append(ctx.branch())
2507 output.append(ctx.branch())
2508
2508
2509 if tags:
2509 if tags:
2510 output.extend(ctx.tags())
2510 output.extend(ctx.tags())
2511
2511
2512 if bookmarks:
2512 if bookmarks:
2513 output.extend(ctx.bookmarks())
2513 output.extend(ctx.bookmarks())
2514
2514
2515 ui.write("%s\n" % ' '.join(output))
2515 ui.write("%s\n" % ' '.join(output))
2516
2516
2517 def import_(ui, repo, patch1, *patches, **opts):
2517 def import_(ui, repo, patch1, *patches, **opts):
2518 """import an ordered set of patches
2518 """import an ordered set of patches
2519
2519
2520 Import a list of patches and commit them individually (unless
2520 Import a list of patches and commit them individually (unless
2521 --no-commit is specified).
2521 --no-commit is specified).
2522
2522
2523 If there are outstanding changes in the working directory, import
2523 If there are outstanding changes in the working directory, import
2524 will abort unless given the -f/--force flag.
2524 will abort unless given the -f/--force flag.
2525
2525
2526 You can import a patch straight from a mail message. Even patches
2526 You can import a patch straight from a mail message. Even patches
2527 as attachments work (to use the body part, it must have type
2527 as attachments work (to use the body part, it must have type
2528 text/plain or text/x-patch). From and Subject headers of email
2528 text/plain or text/x-patch). From and Subject headers of email
2529 message are used as default committer and commit message. All
2529 message are used as default committer and commit message. All
2530 text/plain body parts before first diff are added to commit
2530 text/plain body parts before first diff are added to commit
2531 message.
2531 message.
2532
2532
2533 If the imported patch was generated by :hg:`export`, user and
2533 If the imported patch was generated by :hg:`export`, user and
2534 description from patch override values from message headers and
2534 description from patch override values from message headers and
2535 body. Values given on command line with -m/--message and -u/--user
2535 body. Values given on command line with -m/--message and -u/--user
2536 override these.
2536 override these.
2537
2537
2538 If --exact is specified, import will set the working directory to
2538 If --exact is specified, import will set the working directory to
2539 the parent of each patch before applying it, and will abort if the
2539 the parent of each patch before applying it, and will abort if the
2540 resulting changeset has a different ID than the one recorded in
2540 resulting changeset has a different ID than the one recorded in
2541 the patch. This may happen due to character set problems or other
2541 the patch. This may happen due to character set problems or other
2542 deficiencies in the text patch format.
2542 deficiencies in the text patch format.
2543
2543
2544 With -s/--similarity, hg will attempt to discover renames and
2544 With -s/--similarity, hg will attempt to discover renames and
2545 copies in the patch in the same way as 'addremove'.
2545 copies in the patch in the same way as 'addremove'.
2546
2546
2547 To read a patch from standard input, use "-" as the patch name. If
2547 To read a patch from standard input, use "-" as the patch name. If
2548 a URL is specified, the patch will be downloaded from it.
2548 a URL is specified, the patch will be downloaded from it.
2549 See :hg:`help dates` for a list of formats valid for -d/--date.
2549 See :hg:`help dates` for a list of formats valid for -d/--date.
2550
2550
2551 Returns 0 on success.
2551 Returns 0 on success.
2552 """
2552 """
2553 patches = (patch1,) + patches
2553 patches = (patch1,) + patches
2554
2554
2555 date = opts.get('date')
2555 date = opts.get('date')
2556 if date:
2556 if date:
2557 opts['date'] = util.parsedate(date)
2557 opts['date'] = util.parsedate(date)
2558
2558
2559 try:
2559 try:
2560 sim = float(opts.get('similarity') or 0)
2560 sim = float(opts.get('similarity') or 0)
2561 except ValueError:
2561 except ValueError:
2562 raise util.Abort(_('similarity must be a number'))
2562 raise util.Abort(_('similarity must be a number'))
2563 if sim < 0 or sim > 100:
2563 if sim < 0 or sim > 100:
2564 raise util.Abort(_('similarity must be between 0 and 100'))
2564 raise util.Abort(_('similarity must be between 0 and 100'))
2565
2565
2566 if opts.get('exact') or not opts.get('force'):
2566 if opts.get('exact') or not opts.get('force'):
2567 cmdutil.bail_if_changed(repo)
2567 cmdutil.bail_if_changed(repo)
2568
2568
2569 d = opts["base"]
2569 d = opts["base"]
2570 strip = opts["strip"]
2570 strip = opts["strip"]
2571 wlock = lock = None
2571 wlock = lock = None
2572 msgs = []
2572 msgs = []
2573
2573
2574 def tryone(ui, hunk):
2574 def tryone(ui, hunk):
2575 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2575 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2576 patch.extract(ui, hunk)
2576 patch.extract(ui, hunk)
2577
2577
2578 if not tmpname:
2578 if not tmpname:
2579 return None
2579 return None
2580 commitid = _('to working directory')
2580 commitid = _('to working directory')
2581
2581
2582 try:
2582 try:
2583 cmdline_message = cmdutil.logmessage(opts)
2583 cmdline_message = cmdutil.logmessage(opts)
2584 if cmdline_message:
2584 if cmdline_message:
2585 # pickup the cmdline msg
2585 # pickup the cmdline msg
2586 message = cmdline_message
2586 message = cmdline_message
2587 elif message:
2587 elif message:
2588 # pickup the patch msg
2588 # pickup the patch msg
2589 message = message.strip()
2589 message = message.strip()
2590 else:
2590 else:
2591 # launch the editor
2591 # launch the editor
2592 message = None
2592 message = None
2593 ui.debug('message:\n%s\n' % message)
2593 ui.debug('message:\n%s\n' % message)
2594
2594
2595 wp = repo.parents()
2595 wp = repo.parents()
2596 if opts.get('exact'):
2596 if opts.get('exact'):
2597 if not nodeid or not p1:
2597 if not nodeid or not p1:
2598 raise util.Abort(_('not a Mercurial patch'))
2598 raise util.Abort(_('not a Mercurial patch'))
2599 p1 = repo.lookup(p1)
2599 p1 = repo.lookup(p1)
2600 p2 = repo.lookup(p2 or hex(nullid))
2600 p2 = repo.lookup(p2 or hex(nullid))
2601
2601
2602 if p1 != wp[0].node():
2602 if p1 != wp[0].node():
2603 hg.clean(repo, p1)
2603 hg.clean(repo, p1)
2604 repo.dirstate.setparents(p1, p2)
2604 repo.dirstate.setparents(p1, p2)
2605 elif p2:
2605 elif p2:
2606 try:
2606 try:
2607 p1 = repo.lookup(p1)
2607 p1 = repo.lookup(p1)
2608 p2 = repo.lookup(p2)
2608 p2 = repo.lookup(p2)
2609 if p1 == wp[0].node():
2609 if p1 == wp[0].node():
2610 repo.dirstate.setparents(p1, p2)
2610 repo.dirstate.setparents(p1, p2)
2611 except error.RepoError:
2611 except error.RepoError:
2612 pass
2612 pass
2613 if opts.get('exact') or opts.get('import_branch'):
2613 if opts.get('exact') or opts.get('import_branch'):
2614 repo.dirstate.setbranch(branch or 'default')
2614 repo.dirstate.setbranch(branch or 'default')
2615
2615
2616 files = {}
2616 files = {}
2617 try:
2617 try:
2618 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2618 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2619 files=files, eolmode=None)
2619 files=files, eolmode=None)
2620 finally:
2620 finally:
2621 files = cmdutil.updatedir(ui, repo, files,
2621 files = cmdutil.updatedir(ui, repo, files,
2622 similarity=sim / 100.0)
2622 similarity=sim / 100.0)
2623 if opts.get('no_commit'):
2623 if opts.get('no_commit'):
2624 if message:
2624 if message:
2625 msgs.append(message)
2625 msgs.append(message)
2626 else:
2626 else:
2627 if opts.get('exact'):
2627 if opts.get('exact'):
2628 m = None
2628 m = None
2629 else:
2629 else:
2630 m = cmdutil.matchfiles(repo, files or [])
2630 m = cmdutil.matchfiles(repo, files or [])
2631 n = repo.commit(message, opts.get('user') or user,
2631 n = repo.commit(message, opts.get('user') or user,
2632 opts.get('date') or date, match=m,
2632 opts.get('date') or date, match=m,
2633 editor=cmdutil.commiteditor)
2633 editor=cmdutil.commiteditor)
2634 if opts.get('exact'):
2634 if opts.get('exact'):
2635 if hex(n) != nodeid:
2635 if hex(n) != nodeid:
2636 repo.rollback()
2636 repo.rollback()
2637 raise util.Abort(_('patch is damaged'
2637 raise util.Abort(_('patch is damaged'
2638 ' or loses information'))
2638 ' or loses information'))
2639 # Force a dirstate write so that the next transaction
2639 # Force a dirstate write so that the next transaction
2640 # backups an up-do-date file.
2640 # backups an up-do-date file.
2641 repo.dirstate.write()
2641 repo.dirstate.write()
2642 if n:
2642 if n:
2643 commitid = short(n)
2643 commitid = short(n)
2644
2644
2645 return commitid
2645 return commitid
2646 finally:
2646 finally:
2647 os.unlink(tmpname)
2647 os.unlink(tmpname)
2648
2648
2649 try:
2649 try:
2650 wlock = repo.wlock()
2650 wlock = repo.wlock()
2651 lock = repo.lock()
2651 lock = repo.lock()
2652 lastcommit = None
2652 lastcommit = None
2653 for p in patches:
2653 for p in patches:
2654 pf = os.path.join(d, p)
2654 pf = os.path.join(d, p)
2655
2655
2656 if pf == '-':
2656 if pf == '-':
2657 ui.status(_("applying patch from stdin\n"))
2657 ui.status(_("applying patch from stdin\n"))
2658 pf = sys.stdin
2658 pf = sys.stdin
2659 else:
2659 else:
2660 ui.status(_("applying %s\n") % p)
2660 ui.status(_("applying %s\n") % p)
2661 pf = url.open(ui, pf)
2661 pf = url.open(ui, pf)
2662
2662
2663 haspatch = False
2663 haspatch = False
2664 for hunk in patch.split(pf):
2664 for hunk in patch.split(pf):
2665 commitid = tryone(ui, hunk)
2665 commitid = tryone(ui, hunk)
2666 if commitid:
2666 if commitid:
2667 haspatch = True
2667 haspatch = True
2668 if lastcommit:
2668 if lastcommit:
2669 ui.status(_('applied %s\n') % lastcommit)
2669 ui.status(_('applied %s\n') % lastcommit)
2670 lastcommit = commitid
2670 lastcommit = commitid
2671
2671
2672 if not haspatch:
2672 if not haspatch:
2673 raise util.Abort(_('no diffs found'))
2673 raise util.Abort(_('no diffs found'))
2674
2674
2675 if msgs:
2675 if msgs:
2676 repo.opener.write('last-message.txt', '\n* * *\n'.join(msgs))
2676 repo.opener.write('last-message.txt', '\n* * *\n'.join(msgs))
2677 finally:
2677 finally:
2678 release(lock, wlock)
2678 release(lock, wlock)
2679
2679
2680 def incoming(ui, repo, source="default", **opts):
2680 def incoming(ui, repo, source="default", **opts):
2681 """show new changesets found in source
2681 """show new changesets found in source
2682
2682
2683 Show new changesets found in the specified path/URL or the default
2683 Show new changesets found in the specified path/URL or the default
2684 pull location. These are the changesets that would have been pulled
2684 pull location. These are the changesets that would have been pulled
2685 if a pull at the time you issued this command.
2685 if a pull at the time you issued this command.
2686
2686
2687 For remote repository, using --bundle avoids downloading the
2687 For remote repository, using --bundle avoids downloading the
2688 changesets twice if the incoming is followed by a pull.
2688 changesets twice if the incoming is followed by a pull.
2689
2689
2690 See pull for valid source format details.
2690 See pull for valid source format details.
2691
2691
2692 Returns 0 if there are incoming changes, 1 otherwise.
2692 Returns 0 if there are incoming changes, 1 otherwise.
2693 """
2693 """
2694 if opts.get('bundle') and opts.get('subrepos'):
2694 if opts.get('bundle') and opts.get('subrepos'):
2695 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2695 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2696
2696
2697 if opts.get('bookmarks'):
2697 if opts.get('bookmarks'):
2698 source, branches = hg.parseurl(ui.expandpath(source),
2698 source, branches = hg.parseurl(ui.expandpath(source),
2699 opts.get('branch'))
2699 opts.get('branch'))
2700 other = hg.repository(hg.remoteui(repo, opts), source)
2700 other = hg.repository(hg.remoteui(repo, opts), source)
2701 if 'bookmarks' not in other.listkeys('namespaces'):
2701 if 'bookmarks' not in other.listkeys('namespaces'):
2702 ui.warn(_("remote doesn't support bookmarks\n"))
2702 ui.warn(_("remote doesn't support bookmarks\n"))
2703 return 0
2703 return 0
2704 ui.status(_('comparing with %s\n') % util.hidepassword(source))
2704 ui.status(_('comparing with %s\n') % util.hidepassword(source))
2705 return bookmarks.diff(ui, repo, other)
2705 return bookmarks.diff(ui, repo, other)
2706
2706
2707 ret = hg.incoming(ui, repo, source, opts)
2707 ret = hg.incoming(ui, repo, source, opts)
2708 return ret
2708 return ret
2709
2709
2710 def init(ui, dest=".", **opts):
2710 def init(ui, dest=".", **opts):
2711 """create a new repository in the given directory
2711 """create a new repository in the given directory
2712
2712
2713 Initialize a new repository in the given directory. If the given
2713 Initialize a new repository in the given directory. If the given
2714 directory does not exist, it will be created.
2714 directory does not exist, it will be created.
2715
2715
2716 If no directory is given, the current directory is used.
2716 If no directory is given, the current directory is used.
2717
2717
2718 It is possible to specify an ``ssh://`` URL as the destination.
2718 It is possible to specify an ``ssh://`` URL as the destination.
2719 See :hg:`help urls` for more information.
2719 See :hg:`help urls` for more information.
2720
2720
2721 Returns 0 on success.
2721 Returns 0 on success.
2722 """
2722 """
2723 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2723 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2724
2724
2725 def locate(ui, repo, *pats, **opts):
2725 def locate(ui, repo, *pats, **opts):
2726 """locate files matching specific patterns
2726 """locate files matching specific patterns
2727
2727
2728 Print files under Mercurial control in the working directory whose
2728 Print files under Mercurial control in the working directory whose
2729 names match the given patterns.
2729 names match the given patterns.
2730
2730
2731 By default, this command searches all directories in the working
2731 By default, this command searches all directories in the working
2732 directory. To search just the current directory and its
2732 directory. To search just the current directory and its
2733 subdirectories, use "--include .".
2733 subdirectories, use "--include .".
2734
2734
2735 If no patterns are given to match, this command prints the names
2735 If no patterns are given to match, this command prints the names
2736 of all files under Mercurial control in the working directory.
2736 of all files under Mercurial control in the working directory.
2737
2737
2738 If you want to feed the output of this command into the "xargs"
2738 If you want to feed the output of this command into the "xargs"
2739 command, use the -0 option to both this command and "xargs". This
2739 command, use the -0 option to both this command and "xargs". This
2740 will avoid the problem of "xargs" treating single filenames that
2740 will avoid the problem of "xargs" treating single filenames that
2741 contain whitespace as multiple filenames.
2741 contain whitespace as multiple filenames.
2742
2742
2743 Returns 0 if a match is found, 1 otherwise.
2743 Returns 0 if a match is found, 1 otherwise.
2744 """
2744 """
2745 end = opts.get('print0') and '\0' or '\n'
2745 end = opts.get('print0') and '\0' or '\n'
2746 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2746 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2747
2747
2748 ret = 1
2748 ret = 1
2749 m = cmdutil.match(repo, pats, opts, default='relglob')
2749 m = cmdutil.match(repo, pats, opts, default='relglob')
2750 m.bad = lambda x, y: False
2750 m.bad = lambda x, y: False
2751 for abs in repo[rev].walk(m):
2751 for abs in repo[rev].walk(m):
2752 if not rev and abs not in repo.dirstate:
2752 if not rev and abs not in repo.dirstate:
2753 continue
2753 continue
2754 if opts.get('fullpath'):
2754 if opts.get('fullpath'):
2755 ui.write(repo.wjoin(abs), end)
2755 ui.write(repo.wjoin(abs), end)
2756 else:
2756 else:
2757 ui.write(((pats and m.rel(abs)) or abs), end)
2757 ui.write(((pats and m.rel(abs)) or abs), end)
2758 ret = 0
2758 ret = 0
2759
2759
2760 return ret
2760 return ret
2761
2761
2762 def log(ui, repo, *pats, **opts):
2762 def log(ui, repo, *pats, **opts):
2763 """show revision history of entire repository or files
2763 """show revision history of entire repository or files
2764
2764
2765 Print the revision history of the specified files or the entire
2765 Print the revision history of the specified files or the entire
2766 project.
2766 project.
2767
2767
2768 File history is shown without following rename or copy history of
2768 File history is shown without following rename or copy history of
2769 files. Use -f/--follow with a filename to follow history across
2769 files. Use -f/--follow with a filename to follow history across
2770 renames and copies. --follow without a filename will only show
2770 renames and copies. --follow without a filename will only show
2771 ancestors or descendants of the starting revision. --follow-first
2771 ancestors or descendants of the starting revision. --follow-first
2772 only follows the first parent of merge revisions.
2772 only follows the first parent of merge revisions.
2773
2773
2774 If no revision range is specified, the default is ``tip:0`` unless
2774 If no revision range is specified, the default is ``tip:0`` unless
2775 --follow is set, in which case the working directory parent is
2775 --follow is set, in which case the working directory parent is
2776 used as the starting revision. You can specify a revision set for
2776 used as the starting revision. You can specify a revision set for
2777 log, see :hg:`help revsets` for more information.
2777 log, see :hg:`help revsets` for more information.
2778
2778
2779 See :hg:`help dates` for a list of formats valid for -d/--date.
2779 See :hg:`help dates` for a list of formats valid for -d/--date.
2780
2780
2781 By default this command prints revision number and changeset id,
2781 By default this command prints revision number and changeset id,
2782 tags, non-trivial parents, user, date and time, and a summary for
2782 tags, non-trivial parents, user, date and time, and a summary for
2783 each commit. When the -v/--verbose switch is used, the list of
2783 each commit. When the -v/--verbose switch is used, the list of
2784 changed files and full commit message are shown.
2784 changed files and full commit message are shown.
2785
2785
2786 .. note::
2786 .. note::
2787 log -p/--patch may generate unexpected diff output for merge
2787 log -p/--patch may generate unexpected diff output for merge
2788 changesets, as it will only compare the merge changeset against
2788 changesets, as it will only compare the merge changeset against
2789 its first parent. Also, only files different from BOTH parents
2789 its first parent. Also, only files different from BOTH parents
2790 will appear in files:.
2790 will appear in files:.
2791
2791
2792 Returns 0 on success.
2792 Returns 0 on success.
2793 """
2793 """
2794
2794
2795 matchfn = cmdutil.match(repo, pats, opts)
2795 matchfn = cmdutil.match(repo, pats, opts)
2796 limit = cmdutil.loglimit(opts)
2796 limit = cmdutil.loglimit(opts)
2797 count = 0
2797 count = 0
2798
2798
2799 endrev = None
2799 endrev = None
2800 if opts.get('copies') and opts.get('rev'):
2800 if opts.get('copies') and opts.get('rev'):
2801 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2801 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2802
2802
2803 df = False
2803 df = False
2804 if opts["date"]:
2804 if opts["date"]:
2805 df = util.matchdate(opts["date"])
2805 df = util.matchdate(opts["date"])
2806
2806
2807 branches = opts.get('branch', []) + opts.get('only_branch', [])
2807 branches = opts.get('branch', []) + opts.get('only_branch', [])
2808 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2808 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2809
2809
2810 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2810 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2811 def prep(ctx, fns):
2811 def prep(ctx, fns):
2812 rev = ctx.rev()
2812 rev = ctx.rev()
2813 parents = [p for p in repo.changelog.parentrevs(rev)
2813 parents = [p for p in repo.changelog.parentrevs(rev)
2814 if p != nullrev]
2814 if p != nullrev]
2815 if opts.get('no_merges') and len(parents) == 2:
2815 if opts.get('no_merges') and len(parents) == 2:
2816 return
2816 return
2817 if opts.get('only_merges') and len(parents) != 2:
2817 if opts.get('only_merges') and len(parents) != 2:
2818 return
2818 return
2819 if opts.get('branch') and ctx.branch() not in opts['branch']:
2819 if opts.get('branch') and ctx.branch() not in opts['branch']:
2820 return
2820 return
2821 if df and not df(ctx.date()[0]):
2821 if df and not df(ctx.date()[0]):
2822 return
2822 return
2823 if opts['user'] and not [k for k in opts['user']
2823 if opts['user'] and not [k for k in opts['user']
2824 if k.lower() in ctx.user().lower()]:
2824 if k.lower() in ctx.user().lower()]:
2825 return
2825 return
2826 if opts.get('keyword'):
2826 if opts.get('keyword'):
2827 for k in [kw.lower() for kw in opts['keyword']]:
2827 for k in [kw.lower() for kw in opts['keyword']]:
2828 if (k in ctx.user().lower() or
2828 if (k in ctx.user().lower() or
2829 k in ctx.description().lower() or
2829 k in ctx.description().lower() or
2830 k in " ".join(ctx.files()).lower()):
2830 k in " ".join(ctx.files()).lower()):
2831 break
2831 break
2832 else:
2832 else:
2833 return
2833 return
2834
2834
2835 copies = None
2835 copies = None
2836 if opts.get('copies') and rev:
2836 if opts.get('copies') and rev:
2837 copies = []
2837 copies = []
2838 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2838 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2839 for fn in ctx.files():
2839 for fn in ctx.files():
2840 rename = getrenamed(fn, rev)
2840 rename = getrenamed(fn, rev)
2841 if rename:
2841 if rename:
2842 copies.append((fn, rename[0]))
2842 copies.append((fn, rename[0]))
2843
2843
2844 revmatchfn = None
2844 revmatchfn = None
2845 if opts.get('patch') or opts.get('stat'):
2845 if opts.get('patch') or opts.get('stat'):
2846 if opts.get('follow') or opts.get('follow_first'):
2846 if opts.get('follow') or opts.get('follow_first'):
2847 # note: this might be wrong when following through merges
2847 # note: this might be wrong when following through merges
2848 revmatchfn = cmdutil.match(repo, fns, default='path')
2848 revmatchfn = cmdutil.match(repo, fns, default='path')
2849 else:
2849 else:
2850 revmatchfn = matchfn
2850 revmatchfn = matchfn
2851
2851
2852 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2852 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2853
2853
2854 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2854 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2855 if count == limit:
2855 if count == limit:
2856 break
2856 break
2857 if displayer.flush(ctx.rev()):
2857 if displayer.flush(ctx.rev()):
2858 count += 1
2858 count += 1
2859 displayer.close()
2859 displayer.close()
2860
2860
2861 def manifest(ui, repo, node=None, rev=None):
2861 def manifest(ui, repo, node=None, rev=None):
2862 """output the current or given revision of the project manifest
2862 """output the current or given revision of the project manifest
2863
2863
2864 Print a list of version controlled files for the given revision.
2864 Print a list of version controlled files for the given revision.
2865 If no revision is given, the first parent of the working directory
2865 If no revision is given, the first parent of the working directory
2866 is used, or the null revision if no revision is checked out.
2866 is used, or the null revision if no revision is checked out.
2867
2867
2868 With -v, print file permissions, symlink and executable bits.
2868 With -v, print file permissions, symlink and executable bits.
2869 With --debug, print file revision hashes.
2869 With --debug, print file revision hashes.
2870
2870
2871 Returns 0 on success.
2871 Returns 0 on success.
2872 """
2872 """
2873
2873
2874 if rev and node:
2874 if rev and node:
2875 raise util.Abort(_("please specify just one revision"))
2875 raise util.Abort(_("please specify just one revision"))
2876
2876
2877 if not node:
2877 if not node:
2878 node = rev
2878 node = rev
2879
2879
2880 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2880 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2881 ctx = cmdutil.revsingle(repo, node)
2881 ctx = cmdutil.revsingle(repo, node)
2882 for f in ctx:
2882 for f in ctx:
2883 if ui.debugflag:
2883 if ui.debugflag:
2884 ui.write("%40s " % hex(ctx.manifest()[f]))
2884 ui.write("%40s " % hex(ctx.manifest()[f]))
2885 if ui.verbose:
2885 if ui.verbose:
2886 ui.write(decor[ctx.flags(f)])
2886 ui.write(decor[ctx.flags(f)])
2887 ui.write("%s\n" % f)
2887 ui.write("%s\n" % f)
2888
2888
2889 def merge(ui, repo, node=None, **opts):
2889 def merge(ui, repo, node=None, **opts):
2890 """merge working directory with another revision
2890 """merge working directory with another revision
2891
2891
2892 The current working directory is updated with all changes made in
2892 The current working directory is updated with all changes made in
2893 the requested revision since the last common predecessor revision.
2893 the requested revision since the last common predecessor revision.
2894
2894
2895 Files that changed between either parent are marked as changed for
2895 Files that changed between either parent are marked as changed for
2896 the next commit and a commit must be performed before any further
2896 the next commit and a commit must be performed before any further
2897 updates to the repository are allowed. The next commit will have
2897 updates to the repository are allowed. The next commit will have
2898 two parents.
2898 two parents.
2899
2899
2900 ``--tool`` can be used to specify the merge tool used for file
2900 ``--tool`` can be used to specify the merge tool used for file
2901 merges. It overrides the HGMERGE environment variable and your
2901 merges. It overrides the HGMERGE environment variable and your
2902 configuration files. See :hg:`help merge-tools` for options.
2902 configuration files. See :hg:`help merge-tools` for options.
2903
2903
2904 If no revision is specified, the working directory's parent is a
2904 If no revision is specified, the working directory's parent is a
2905 head revision, and the current branch contains exactly one other
2905 head revision, and the current branch contains exactly one other
2906 head, the other head is merged with by default. Otherwise, an
2906 head, the other head is merged with by default. Otherwise, an
2907 explicit revision with which to merge with must be provided.
2907 explicit revision with which to merge with must be provided.
2908
2908
2909 :hg:`resolve` must be used to resolve unresolved files.
2909 :hg:`resolve` must be used to resolve unresolved files.
2910
2910
2911 To undo an uncommitted merge, use :hg:`update --clean .` which
2911 To undo an uncommitted merge, use :hg:`update --clean .` which
2912 will check out a clean copy of the original merge parent, losing
2912 will check out a clean copy of the original merge parent, losing
2913 all changes.
2913 all changes.
2914
2914
2915 Returns 0 on success, 1 if there are unresolved files.
2915 Returns 0 on success, 1 if there are unresolved files.
2916 """
2916 """
2917
2917
2918 if opts.get('rev') and node:
2918 if opts.get('rev') and node:
2919 raise util.Abort(_("please specify just one revision"))
2919 raise util.Abort(_("please specify just one revision"))
2920 if not node:
2920 if not node:
2921 node = opts.get('rev')
2921 node = opts.get('rev')
2922
2922
2923 if not node:
2923 if not node:
2924 branch = repo[None].branch()
2924 branch = repo[None].branch()
2925 bheads = repo.branchheads(branch)
2925 bheads = repo.branchheads(branch)
2926 if len(bheads) > 2:
2926 if len(bheads) > 2:
2927 raise util.Abort(_("branch '%s' has %d heads - "
2927 raise util.Abort(_("branch '%s' has %d heads - "
2928 "please merge with an explicit rev")
2928 "please merge with an explicit rev")
2929 % (branch, len(bheads)),
2929 % (branch, len(bheads)),
2930 hint=_("run 'hg heads .' to see heads"))
2930 hint=_("run 'hg heads .' to see heads"))
2931
2931
2932 parent = repo.dirstate.p1()
2932 parent = repo.dirstate.p1()
2933 if len(bheads) == 1:
2933 if len(bheads) == 1:
2934 if len(repo.heads()) > 1:
2934 if len(repo.heads()) > 1:
2935 raise util.Abort(_("branch '%s' has one head - "
2935 raise util.Abort(_("branch '%s' has one head - "
2936 "please merge with an explicit rev")
2936 "please merge with an explicit rev")
2937 % branch,
2937 % branch,
2938 hint=_("run 'hg heads' to see all heads"))
2938 hint=_("run 'hg heads' to see all heads"))
2939 msg = _('there is nothing to merge')
2939 msg = _('there is nothing to merge')
2940 if parent != repo.lookup(repo[None].branch()):
2940 if parent != repo.lookup(repo[None].branch()):
2941 msg = _('%s - use "hg update" instead') % msg
2941 msg = _('%s - use "hg update" instead') % msg
2942 raise util.Abort(msg)
2942 raise util.Abort(msg)
2943
2943
2944 if parent not in bheads:
2944 if parent not in bheads:
2945 raise util.Abort(_('working directory not at a head revision'),
2945 raise util.Abort(_('working directory not at a head revision'),
2946 hint=_("use 'hg update' or merge with an "
2946 hint=_("use 'hg update' or merge with an "
2947 "explicit revision"))
2947 "explicit revision"))
2948 node = parent == bheads[0] and bheads[-1] or bheads[0]
2948 node = parent == bheads[0] and bheads[-1] or bheads[0]
2949 else:
2949 else:
2950 node = cmdutil.revsingle(repo, node).node()
2950 node = cmdutil.revsingle(repo, node).node()
2951
2951
2952 if opts.get('preview'):
2952 if opts.get('preview'):
2953 # find nodes that are ancestors of p2 but not of p1
2953 # find nodes that are ancestors of p2 but not of p1
2954 p1 = repo.lookup('.')
2954 p1 = repo.lookup('.')
2955 p2 = repo.lookup(node)
2955 p2 = repo.lookup(node)
2956 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2956 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2957
2957
2958 displayer = cmdutil.show_changeset(ui, repo, opts)
2958 displayer = cmdutil.show_changeset(ui, repo, opts)
2959 for node in nodes:
2959 for node in nodes:
2960 displayer.show(repo[node])
2960 displayer.show(repo[node])
2961 displayer.close()
2961 displayer.close()
2962 return 0
2962 return 0
2963
2963
2964 try:
2964 try:
2965 # ui.forcemerge is an internal variable, do not document
2965 # ui.forcemerge is an internal variable, do not document
2966 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2966 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2967 return hg.merge(repo, node, force=opts.get('force'))
2967 return hg.merge(repo, node, force=opts.get('force'))
2968 finally:
2968 finally:
2969 ui.setconfig('ui', 'forcemerge', '')
2969 ui.setconfig('ui', 'forcemerge', '')
2970
2970
2971 def outgoing(ui, repo, dest=None, **opts):
2971 def outgoing(ui, repo, dest=None, **opts):
2972 """show changesets not found in the destination
2972 """show changesets not found in the destination
2973
2973
2974 Show changesets not found in the specified destination repository
2974 Show changesets not found in the specified destination repository
2975 or the default push location. These are the changesets that would
2975 or the default push location. These are the changesets that would
2976 be pushed if a push was requested.
2976 be pushed if a push was requested.
2977
2977
2978 See pull for details of valid destination formats.
2978 See pull for details of valid destination formats.
2979
2979
2980 Returns 0 if there are outgoing changes, 1 otherwise.
2980 Returns 0 if there are outgoing changes, 1 otherwise.
2981 """
2981 """
2982
2982
2983 if opts.get('bookmarks'):
2983 if opts.get('bookmarks'):
2984 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2984 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2985 dest, branches = hg.parseurl(dest, opts.get('branch'))
2985 dest, branches = hg.parseurl(dest, opts.get('branch'))
2986 other = hg.repository(hg.remoteui(repo, opts), dest)
2986 other = hg.repository(hg.remoteui(repo, opts), dest)
2987 if 'bookmarks' not in other.listkeys('namespaces'):
2987 if 'bookmarks' not in other.listkeys('namespaces'):
2988 ui.warn(_("remote doesn't support bookmarks\n"))
2988 ui.warn(_("remote doesn't support bookmarks\n"))
2989 return 0
2989 return 0
2990 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
2990 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
2991 return bookmarks.diff(ui, other, repo)
2991 return bookmarks.diff(ui, other, repo)
2992
2992
2993 ret = hg.outgoing(ui, repo, dest, opts)
2993 ret = hg.outgoing(ui, repo, dest, opts)
2994 return ret
2994 return ret
2995
2995
2996 def parents(ui, repo, file_=None, **opts):
2996 def parents(ui, repo, file_=None, **opts):
2997 """show the parents of the working directory or revision
2997 """show the parents of the working directory or revision
2998
2998
2999 Print the working directory's parent revisions. If a revision is
2999 Print the working directory's parent revisions. If a revision is
3000 given via -r/--rev, the parent of that revision will be printed.
3000 given via -r/--rev, the parent of that revision will be printed.
3001 If a file argument is given, the revision in which the file was
3001 If a file argument is given, the revision in which the file was
3002 last changed (before the working directory revision or the
3002 last changed (before the working directory revision or the
3003 argument to --rev if given) is printed.
3003 argument to --rev if given) is printed.
3004
3004
3005 Returns 0 on success.
3005 Returns 0 on success.
3006 """
3006 """
3007
3007
3008 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
3008 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
3009
3009
3010 if file_:
3010 if file_:
3011 m = cmdutil.match(repo, (file_,), opts)
3011 m = cmdutil.match(repo, (file_,), opts)
3012 if m.anypats() or len(m.files()) != 1:
3012 if m.anypats() or len(m.files()) != 1:
3013 raise util.Abort(_('can only specify an explicit filename'))
3013 raise util.Abort(_('can only specify an explicit filename'))
3014 file_ = m.files()[0]
3014 file_ = m.files()[0]
3015 filenodes = []
3015 filenodes = []
3016 for cp in ctx.parents():
3016 for cp in ctx.parents():
3017 if not cp:
3017 if not cp:
3018 continue
3018 continue
3019 try:
3019 try:
3020 filenodes.append(cp.filenode(file_))
3020 filenodes.append(cp.filenode(file_))
3021 except error.LookupError:
3021 except error.LookupError:
3022 pass
3022 pass
3023 if not filenodes:
3023 if not filenodes:
3024 raise util.Abort(_("'%s' not found in manifest!") % file_)
3024 raise util.Abort(_("'%s' not found in manifest!") % file_)
3025 fl = repo.file(file_)
3025 fl = repo.file(file_)
3026 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3026 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3027 else:
3027 else:
3028 p = [cp.node() for cp in ctx.parents()]
3028 p = [cp.node() for cp in ctx.parents()]
3029
3029
3030 displayer = cmdutil.show_changeset(ui, repo, opts)
3030 displayer = cmdutil.show_changeset(ui, repo, opts)
3031 for n in p:
3031 for n in p:
3032 if n != nullid:
3032 if n != nullid:
3033 displayer.show(repo[n])
3033 displayer.show(repo[n])
3034 displayer.close()
3034 displayer.close()
3035
3035
3036 def paths(ui, repo, search=None):
3036 def paths(ui, repo, search=None):
3037 """show aliases for remote repositories
3037 """show aliases for remote repositories
3038
3038
3039 Show definition of symbolic path name NAME. If no name is given,
3039 Show definition of symbolic path name NAME. If no name is given,
3040 show definition of all available names.
3040 show definition of all available names.
3041
3041
3042 Path names are defined in the [paths] section of your
3042 Path names are defined in the [paths] section of your
3043 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3043 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3044 repository, ``.hg/hgrc`` is used, too.
3044 repository, ``.hg/hgrc`` is used, too.
3045
3045
3046 The path names ``default`` and ``default-push`` have a special
3046 The path names ``default`` and ``default-push`` have a special
3047 meaning. When performing a push or pull operation, they are used
3047 meaning. When performing a push or pull operation, they are used
3048 as fallbacks if no location is specified on the command-line.
3048 as fallbacks if no location is specified on the command-line.
3049 When ``default-push`` is set, it will be used for push and
3049 When ``default-push`` is set, it will be used for push and
3050 ``default`` will be used for pull; otherwise ``default`` is used
3050 ``default`` will be used for pull; otherwise ``default`` is used
3051 as the fallback for both. When cloning a repository, the clone
3051 as the fallback for both. When cloning a repository, the clone
3052 source is written as ``default`` in ``.hg/hgrc``. Note that
3052 source is written as ``default`` in ``.hg/hgrc``. Note that
3053 ``default`` and ``default-push`` apply to all inbound (e.g.
3053 ``default`` and ``default-push`` apply to all inbound (e.g.
3054 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3054 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3055 :hg:`bundle`) operations.
3055 :hg:`bundle`) operations.
3056
3056
3057 See :hg:`help urls` for more information.
3057 See :hg:`help urls` for more information.
3058
3058
3059 Returns 0 on success.
3059 Returns 0 on success.
3060 """
3060 """
3061 if search:
3061 if search:
3062 for name, path in ui.configitems("paths"):
3062 for name, path in ui.configitems("paths"):
3063 if name == search:
3063 if name == search:
3064 ui.write("%s\n" % util.hidepassword(path))
3064 ui.write("%s\n" % util.hidepassword(path))
3065 return
3065 return
3066 ui.warn(_("not found!\n"))
3066 ui.warn(_("not found!\n"))
3067 return 1
3067 return 1
3068 else:
3068 else:
3069 for name, path in ui.configitems("paths"):
3069 for name, path in ui.configitems("paths"):
3070 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3070 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3071
3071
3072 def postincoming(ui, repo, modheads, optupdate, checkout):
3072 def postincoming(ui, repo, modheads, optupdate, checkout):
3073 if modheads == 0:
3073 if modheads == 0:
3074 return
3074 return
3075 if optupdate:
3075 if optupdate:
3076 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
3076 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
3077 return hg.update(repo, checkout)
3077 return hg.update(repo, checkout)
3078 else:
3078 else:
3079 ui.status(_("not updating, since new heads added\n"))
3079 ui.status(_("not updating, since new heads added\n"))
3080 if modheads > 1:
3080 if modheads > 1:
3081 currentbranchheads = len(repo.branchheads())
3081 currentbranchheads = len(repo.branchheads())
3082 if currentbranchheads == modheads:
3082 if currentbranchheads == modheads:
3083 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3083 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3084 elif currentbranchheads > 1:
3084 elif currentbranchheads > 1:
3085 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3085 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3086 else:
3086 else:
3087 ui.status(_("(run 'hg heads' to see heads)\n"))
3087 ui.status(_("(run 'hg heads' to see heads)\n"))
3088 else:
3088 else:
3089 ui.status(_("(run 'hg update' to get a working copy)\n"))
3089 ui.status(_("(run 'hg update' to get a working copy)\n"))
3090
3090
3091 def pull(ui, repo, source="default", **opts):
3091 def pull(ui, repo, source="default", **opts):
3092 """pull changes from the specified source
3092 """pull changes from the specified source
3093
3093
3094 Pull changes from a remote repository to a local one.
3094 Pull changes from a remote repository to a local one.
3095
3095
3096 This finds all changes from the repository at the specified path
3096 This finds all changes from the repository at the specified path
3097 or URL and adds them to a local repository (the current one unless
3097 or URL and adds them to a local repository (the current one unless
3098 -R is specified). By default, this does not update the copy of the
3098 -R is specified). By default, this does not update the copy of the
3099 project in the working directory.
3099 project in the working directory.
3100
3100
3101 Use :hg:`incoming` if you want to see what would have been added
3101 Use :hg:`incoming` if you want to see what would have been added
3102 by a pull at the time you issued this command. If you then decide
3102 by a pull at the time you issued this command. If you then decide
3103 to add those changes to the repository, you should use :hg:`pull
3103 to add those changes to the repository, you should use :hg:`pull
3104 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3104 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3105
3105
3106 If SOURCE is omitted, the 'default' path will be used.
3106 If SOURCE is omitted, the 'default' path will be used.
3107 See :hg:`help urls` for more information.
3107 See :hg:`help urls` for more information.
3108
3108
3109 Returns 0 on success, 1 if an update had unresolved files.
3109 Returns 0 on success, 1 if an update had unresolved files.
3110 """
3110 """
3111 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3111 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3112 other = hg.repository(hg.remoteui(repo, opts), source)
3112 other = hg.repository(hg.remoteui(repo, opts), source)
3113 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3113 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3114 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3114 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3115
3115
3116 if opts.get('bookmark'):
3116 if opts.get('bookmark'):
3117 if not revs:
3117 if not revs:
3118 revs = []
3118 revs = []
3119 rb = other.listkeys('bookmarks')
3119 rb = other.listkeys('bookmarks')
3120 for b in opts['bookmark']:
3120 for b in opts['bookmark']:
3121 if b not in rb:
3121 if b not in rb:
3122 raise util.Abort(_('remote bookmark %s not found!') % b)
3122 raise util.Abort(_('remote bookmark %s not found!') % b)
3123 revs.append(rb[b])
3123 revs.append(rb[b])
3124
3124
3125 if revs:
3125 if revs:
3126 try:
3126 try:
3127 revs = [other.lookup(rev) for rev in revs]
3127 revs = [other.lookup(rev) for rev in revs]
3128 except error.CapabilityError:
3128 except error.CapabilityError:
3129 err = _("other repository doesn't support revision lookup, "
3129 err = _("other repository doesn't support revision lookup, "
3130 "so a rev cannot be specified.")
3130 "so a rev cannot be specified.")
3131 raise util.Abort(err)
3131 raise util.Abort(err)
3132
3132
3133 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3133 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3134 bookmarks.updatefromremote(ui, repo, other)
3134 bookmarks.updatefromremote(ui, repo, other)
3135 if checkout:
3135 if checkout:
3136 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3136 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3137 repo._subtoppath = source
3137 repo._subtoppath = source
3138 try:
3138 try:
3139 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3139 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3140
3140
3141 finally:
3141 finally:
3142 del repo._subtoppath
3142 del repo._subtoppath
3143
3143
3144 # update specified bookmarks
3144 # update specified bookmarks
3145 if opts.get('bookmark'):
3145 if opts.get('bookmark'):
3146 for b in opts['bookmark']:
3146 for b in opts['bookmark']:
3147 # explicit pull overrides local bookmark if any
3147 # explicit pull overrides local bookmark if any
3148 ui.status(_("importing bookmark %s\n") % b)
3148 ui.status(_("importing bookmark %s\n") % b)
3149 repo._bookmarks[b] = repo[rb[b]].node()
3149 repo._bookmarks[b] = repo[rb[b]].node()
3150 bookmarks.write(repo)
3150 bookmarks.write(repo)
3151
3151
3152 return ret
3152 return ret
3153
3153
3154 def push(ui, repo, dest=None, **opts):
3154 def push(ui, repo, dest=None, **opts):
3155 """push changes to the specified destination
3155 """push changes to the specified destination
3156
3156
3157 Push changesets from the local repository to the specified
3157 Push changesets from the local repository to the specified
3158 destination.
3158 destination.
3159
3159
3160 This operation is symmetrical to pull: it is identical to a pull
3160 This operation is symmetrical to pull: it is identical to a pull
3161 in the destination repository from the current one.
3161 in the destination repository from the current one.
3162
3162
3163 By default, push will not allow creation of new heads at the
3163 By default, push will not allow creation of new heads at the
3164 destination, since multiple heads would make it unclear which head
3164 destination, since multiple heads would make it unclear which head
3165 to use. In this situation, it is recommended to pull and merge
3165 to use. In this situation, it is recommended to pull and merge
3166 before pushing.
3166 before pushing.
3167
3167
3168 Use --new-branch if you want to allow push to create a new named
3168 Use --new-branch if you want to allow push to create a new named
3169 branch that is not present at the destination. This allows you to
3169 branch that is not present at the destination. This allows you to
3170 only create a new branch without forcing other changes.
3170 only create a new branch without forcing other changes.
3171
3171
3172 Use -f/--force to override the default behavior and push all
3172 Use -f/--force to override the default behavior and push all
3173 changesets on all branches.
3173 changesets on all branches.
3174
3174
3175 If -r/--rev is used, the specified revision and all its ancestors
3175 If -r/--rev is used, the specified revision and all its ancestors
3176 will be pushed to the remote repository.
3176 will be pushed to the remote repository.
3177
3177
3178 Please see :hg:`help urls` for important details about ``ssh://``
3178 Please see :hg:`help urls` for important details about ``ssh://``
3179 URLs. If DESTINATION is omitted, a default path will be used.
3179 URLs. If DESTINATION is omitted, a default path will be used.
3180
3180
3181 Returns 0 if push was successful, 1 if nothing to push.
3181 Returns 0 if push was successful, 1 if nothing to push.
3182 """
3182 """
3183
3183
3184 if opts.get('bookmark'):
3184 if opts.get('bookmark'):
3185 for b in opts['bookmark']:
3185 for b in opts['bookmark']:
3186 # translate -B options to -r so changesets get pushed
3186 # translate -B options to -r so changesets get pushed
3187 if b in repo._bookmarks:
3187 if b in repo._bookmarks:
3188 opts.setdefault('rev', []).append(b)
3188 opts.setdefault('rev', []).append(b)
3189 else:
3189 else:
3190 # if we try to push a deleted bookmark, translate it to null
3190 # if we try to push a deleted bookmark, translate it to null
3191 # this lets simultaneous -r, -b options continue working
3191 # this lets simultaneous -r, -b options continue working
3192 opts.setdefault('rev', []).append("null")
3192 opts.setdefault('rev', []).append("null")
3193
3193
3194 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3194 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3195 dest, branches = hg.parseurl(dest, opts.get('branch'))
3195 dest, branches = hg.parseurl(dest, opts.get('branch'))
3196 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3196 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3197 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3197 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3198 other = hg.repository(hg.remoteui(repo, opts), dest)
3198 other = hg.repository(hg.remoteui(repo, opts), dest)
3199 if revs:
3199 if revs:
3200 revs = [repo.lookup(rev) for rev in revs]
3200 revs = [repo.lookup(rev) for rev in revs]
3201
3201
3202 repo._subtoppath = dest
3202 repo._subtoppath = dest
3203 try:
3203 try:
3204 # push subrepos depth-first for coherent ordering
3204 # push subrepos depth-first for coherent ordering
3205 c = repo['']
3205 c = repo['']
3206 subs = c.substate # only repos that are committed
3206 subs = c.substate # only repos that are committed
3207 for s in sorted(subs):
3207 for s in sorted(subs):
3208 if not c.sub(s).push(opts.get('force')):
3208 if not c.sub(s).push(opts.get('force')):
3209 return False
3209 return False
3210 finally:
3210 finally:
3211 del repo._subtoppath
3211 del repo._subtoppath
3212 result = repo.push(other, opts.get('force'), revs=revs,
3212 result = repo.push(other, opts.get('force'), revs=revs,
3213 newbranch=opts.get('new_branch'))
3213 newbranch=opts.get('new_branch'))
3214
3214
3215 result = (result == 0)
3215 result = (result == 0)
3216
3216
3217 if opts.get('bookmark'):
3217 if opts.get('bookmark'):
3218 rb = other.listkeys('bookmarks')
3218 rb = other.listkeys('bookmarks')
3219 for b in opts['bookmark']:
3219 for b in opts['bookmark']:
3220 # explicit push overrides remote bookmark if any
3220 # explicit push overrides remote bookmark if any
3221 if b in repo._bookmarks:
3221 if b in repo._bookmarks:
3222 ui.status(_("exporting bookmark %s\n") % b)
3222 ui.status(_("exporting bookmark %s\n") % b)
3223 new = repo[b].hex()
3223 new = repo[b].hex()
3224 elif b in rb:
3224 elif b in rb:
3225 ui.status(_("deleting remote bookmark %s\n") % b)
3225 ui.status(_("deleting remote bookmark %s\n") % b)
3226 new = '' # delete
3226 new = '' # delete
3227 else:
3227 else:
3228 ui.warn(_('bookmark %s does not exist on the local '
3228 ui.warn(_('bookmark %s does not exist on the local '
3229 'or remote repository!\n') % b)
3229 'or remote repository!\n') % b)
3230 return 2
3230 return 2
3231 old = rb.get(b, '')
3231 old = rb.get(b, '')
3232 r = other.pushkey('bookmarks', b, old, new)
3232 r = other.pushkey('bookmarks', b, old, new)
3233 if not r:
3233 if not r:
3234 ui.warn(_('updating bookmark %s failed!\n') % b)
3234 ui.warn(_('updating bookmark %s failed!\n') % b)
3235 if not result:
3235 if not result:
3236 result = 2
3236 result = 2
3237
3237
3238 return result
3238 return result
3239
3239
3240 def recover(ui, repo):
3240 def recover(ui, repo):
3241 """roll back an interrupted transaction
3241 """roll back an interrupted transaction
3242
3242
3243 Recover from an interrupted commit or pull.
3243 Recover from an interrupted commit or pull.
3244
3244
3245 This command tries to fix the repository status after an
3245 This command tries to fix the repository status after an
3246 interrupted operation. It should only be necessary when Mercurial
3246 interrupted operation. It should only be necessary when Mercurial
3247 suggests it.
3247 suggests it.
3248
3248
3249 Returns 0 if successful, 1 if nothing to recover or verify fails.
3249 Returns 0 if successful, 1 if nothing to recover or verify fails.
3250 """
3250 """
3251 if repo.recover():
3251 if repo.recover():
3252 return hg.verify(repo)
3252 return hg.verify(repo)
3253 return 1
3253 return 1
3254
3254
3255 def remove(ui, repo, *pats, **opts):
3255 def remove(ui, repo, *pats, **opts):
3256 """remove the specified files on the next commit
3256 """remove the specified files on the next commit
3257
3257
3258 Schedule the indicated files for removal from the repository.
3258 Schedule the indicated files for removal from the repository.
3259
3259
3260 This only removes files from the current branch, not from the
3260 This only removes files from the current branch, not from the
3261 entire project history. -A/--after can be used to remove only
3261 entire project history. -A/--after can be used to remove only
3262 files that have already been deleted, -f/--force can be used to
3262 files that have already been deleted, -f/--force can be used to
3263 force deletion, and -Af can be used to remove files from the next
3263 force deletion, and -Af can be used to remove files from the next
3264 revision without deleting them from the working directory.
3264 revision without deleting them from the working directory.
3265
3265
3266 The following table details the behavior of remove for different
3266 The following table details the behavior of remove for different
3267 file states (columns) and option combinations (rows). The file
3267 file states (columns) and option combinations (rows). The file
3268 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3268 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3269 reported by :hg:`status`). The actions are Warn, Remove (from
3269 reported by :hg:`status`). The actions are Warn, Remove (from
3270 branch) and Delete (from disk)::
3270 branch) and Delete (from disk)::
3271
3271
3272 A C M !
3272 A C M !
3273 none W RD W R
3273 none W RD W R
3274 -f R RD RD R
3274 -f R RD RD R
3275 -A W W W R
3275 -A W W W R
3276 -Af R R R R
3276 -Af R R R R
3277
3277
3278 This command schedules the files to be removed at the next commit.
3278 This command schedules the files to be removed at the next commit.
3279 To undo a remove before that, see :hg:`revert`.
3279 To undo a remove before that, see :hg:`revert`.
3280
3280
3281 Returns 0 on success, 1 if any warnings encountered.
3281 Returns 0 on success, 1 if any warnings encountered.
3282 """
3282 """
3283
3283
3284 ret = 0
3284 ret = 0
3285 after, force = opts.get('after'), opts.get('force')
3285 after, force = opts.get('after'), opts.get('force')
3286 if not pats and not after:
3286 if not pats and not after:
3287 raise util.Abort(_('no files specified'))
3287 raise util.Abort(_('no files specified'))
3288
3288
3289 m = cmdutil.match(repo, pats, opts)
3289 m = cmdutil.match(repo, pats, opts)
3290 s = repo.status(match=m, clean=True)
3290 s = repo.status(match=m, clean=True)
3291 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3291 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3292
3292
3293 for f in m.files():
3293 for f in m.files():
3294 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3294 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3295 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3295 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3296 ret = 1
3296 ret = 1
3297
3297
3298 if force:
3298 if force:
3299 remove, forget = modified + deleted + clean, added
3299 remove, forget = modified + deleted + clean, added
3300 elif after:
3300 elif after:
3301 remove, forget = deleted, []
3301 remove, forget = deleted, []
3302 for f in modified + added + clean:
3302 for f in modified + added + clean:
3303 ui.warn(_('not removing %s: file still exists (use -f'
3303 ui.warn(_('not removing %s: file still exists (use -f'
3304 ' to force removal)\n') % m.rel(f))
3304 ' to force removal)\n') % m.rel(f))
3305 ret = 1
3305 ret = 1
3306 else:
3306 else:
3307 remove, forget = deleted + clean, []
3307 remove, forget = deleted + clean, []
3308 for f in modified:
3308 for f in modified:
3309 ui.warn(_('not removing %s: file is modified (use -f'
3309 ui.warn(_('not removing %s: file is modified (use -f'
3310 ' to force removal)\n') % m.rel(f))
3310 ' to force removal)\n') % m.rel(f))
3311 ret = 1
3311 ret = 1
3312 for f in added:
3312 for f in added:
3313 ui.warn(_('not removing %s: file has been marked for add (use -f'
3313 ui.warn(_('not removing %s: file has been marked for add (use -f'
3314 ' to force removal)\n') % m.rel(f))
3314 ' to force removal)\n') % m.rel(f))
3315 ret = 1
3315 ret = 1
3316
3316
3317 for f in sorted(remove + forget):
3317 for f in sorted(remove + forget):
3318 if ui.verbose or not m.exact(f):
3318 if ui.verbose or not m.exact(f):
3319 ui.status(_('removing %s\n') % m.rel(f))
3319 ui.status(_('removing %s\n') % m.rel(f))
3320
3320
3321 repo[None].forget(forget)
3321 repo[None].forget(forget)
3322 repo[None].remove(remove, unlink=not after)
3322 repo[None].remove(remove, unlink=not after)
3323 return ret
3323 return ret
3324
3324
3325 def rename(ui, repo, *pats, **opts):
3325 def rename(ui, repo, *pats, **opts):
3326 """rename files; equivalent of copy + remove
3326 """rename files; equivalent of copy + remove
3327
3327
3328 Mark dest as copies of sources; mark sources for deletion. If dest
3328 Mark dest as copies of sources; mark sources for deletion. If dest
3329 is a directory, copies are put in that directory. If dest is a
3329 is a directory, copies are put in that directory. If dest is a
3330 file, there can only be one source.
3330 file, there can only be one source.
3331
3331
3332 By default, this command copies the contents of files as they
3332 By default, this command copies the contents of files as they
3333 exist in the working directory. If invoked with -A/--after, the
3333 exist in the working directory. If invoked with -A/--after, the
3334 operation is recorded, but no copying is performed.
3334 operation is recorded, but no copying is performed.
3335
3335
3336 This command takes effect at the next commit. To undo a rename
3336 This command takes effect at the next commit. To undo a rename
3337 before that, see :hg:`revert`.
3337 before that, see :hg:`revert`.
3338
3338
3339 Returns 0 on success, 1 if errors are encountered.
3339 Returns 0 on success, 1 if errors are encountered.
3340 """
3340 """
3341 wlock = repo.wlock(False)
3341 wlock = repo.wlock(False)
3342 try:
3342 try:
3343 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3343 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3344 finally:
3344 finally:
3345 wlock.release()
3345 wlock.release()
3346
3346
3347 def resolve(ui, repo, *pats, **opts):
3347 def resolve(ui, repo, *pats, **opts):
3348 """redo merges or set/view the merge status of files
3348 """redo merges or set/view the merge status of files
3349
3349
3350 Merges with unresolved conflicts are often the result of
3350 Merges with unresolved conflicts are often the result of
3351 non-interactive merging using the ``internal:merge`` configuration
3351 non-interactive merging using the ``internal:merge`` configuration
3352 setting, or a command-line merge tool like ``diff3``. The resolve
3352 setting, or a command-line merge tool like ``diff3``. The resolve
3353 command is used to manage the files involved in a merge, after
3353 command is used to manage the files involved in a merge, after
3354 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3354 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3355 working directory must have two parents).
3355 working directory must have two parents).
3356
3356
3357 The resolve command can be used in the following ways:
3357 The resolve command can be used in the following ways:
3358
3358
3359 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3359 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3360 files, discarding any previous merge attempts. Re-merging is not
3360 files, discarding any previous merge attempts. Re-merging is not
3361 performed for files already marked as resolved. Use ``--all/-a``
3361 performed for files already marked as resolved. Use ``--all/-a``
3362 to selects all unresolved files. ``--tool`` can be used to specify
3362 to selects all unresolved files. ``--tool`` can be used to specify
3363 the merge tool used for the given files. It overrides the HGMERGE
3363 the merge tool used for the given files. It overrides the HGMERGE
3364 environment variable and your configuration files.
3364 environment variable and your configuration files.
3365
3365
3366 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3366 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3367 (e.g. after having manually fixed-up the files). The default is
3367 (e.g. after having manually fixed-up the files). The default is
3368 to mark all unresolved files.
3368 to mark all unresolved files.
3369
3369
3370 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3370 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3371 default is to mark all resolved files.
3371 default is to mark all resolved files.
3372
3372
3373 - :hg:`resolve -l`: list files which had or still have conflicts.
3373 - :hg:`resolve -l`: list files which had or still have conflicts.
3374 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3374 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3375
3375
3376 Note that Mercurial will not let you commit files with unresolved
3376 Note that Mercurial will not let you commit files with unresolved
3377 merge conflicts. You must use :hg:`resolve -m ...` before you can
3377 merge conflicts. You must use :hg:`resolve -m ...` before you can
3378 commit after a conflicting merge.
3378 commit after a conflicting merge.
3379
3379
3380 Returns 0 on success, 1 if any files fail a resolve attempt.
3380 Returns 0 on success, 1 if any files fail a resolve attempt.
3381 """
3381 """
3382
3382
3383 all, mark, unmark, show, nostatus = \
3383 all, mark, unmark, show, nostatus = \
3384 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3384 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3385
3385
3386 if (show and (mark or unmark)) or (mark and unmark):
3386 if (show and (mark or unmark)) or (mark and unmark):
3387 raise util.Abort(_("too many options specified"))
3387 raise util.Abort(_("too many options specified"))
3388 if pats and all:
3388 if pats and all:
3389 raise util.Abort(_("can't specify --all and patterns"))
3389 raise util.Abort(_("can't specify --all and patterns"))
3390 if not (all or pats or show or mark or unmark):
3390 if not (all or pats or show or mark or unmark):
3391 raise util.Abort(_('no files or directories specified; '
3391 raise util.Abort(_('no files or directories specified; '
3392 'use --all to remerge all files'))
3392 'use --all to remerge all files'))
3393
3393
3394 ms = mergemod.mergestate(repo)
3394 ms = mergemod.mergestate(repo)
3395 m = cmdutil.match(repo, pats, opts)
3395 m = cmdutil.match(repo, pats, opts)
3396 ret = 0
3396 ret = 0
3397
3397
3398 for f in ms:
3398 for f in ms:
3399 if m(f):
3399 if m(f):
3400 if show:
3400 if show:
3401 if nostatus:
3401 if nostatus:
3402 ui.write("%s\n" % f)
3402 ui.write("%s\n" % f)
3403 else:
3403 else:
3404 ui.write("%s %s\n" % (ms[f].upper(), f),
3404 ui.write("%s %s\n" % (ms[f].upper(), f),
3405 label='resolve.' +
3405 label='resolve.' +
3406 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3406 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3407 elif mark:
3407 elif mark:
3408 ms.mark(f, "r")
3408 ms.mark(f, "r")
3409 elif unmark:
3409 elif unmark:
3410 ms.mark(f, "u")
3410 ms.mark(f, "u")
3411 else:
3411 else:
3412 wctx = repo[None]
3412 wctx = repo[None]
3413 mctx = wctx.parents()[-1]
3413 mctx = wctx.parents()[-1]
3414
3414
3415 # backup pre-resolve (merge uses .orig for its own purposes)
3415 # backup pre-resolve (merge uses .orig for its own purposes)
3416 a = repo.wjoin(f)
3416 a = repo.wjoin(f)
3417 util.copyfile(a, a + ".resolve")
3417 util.copyfile(a, a + ".resolve")
3418
3418
3419 try:
3419 try:
3420 # resolve file
3420 # resolve file
3421 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3421 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3422 if ms.resolve(f, wctx, mctx):
3422 if ms.resolve(f, wctx, mctx):
3423 ret = 1
3423 ret = 1
3424 finally:
3424 finally:
3425 ui.setconfig('ui', 'forcemerge', '')
3425 ui.setconfig('ui', 'forcemerge', '')
3426
3426
3427 # replace filemerge's .orig file with our resolve file
3427 # replace filemerge's .orig file with our resolve file
3428 util.rename(a + ".resolve", a + ".orig")
3428 util.rename(a + ".resolve", a + ".orig")
3429
3429
3430 ms.commit()
3430 ms.commit()
3431 return ret
3431 return ret
3432
3432
3433 def revert(ui, repo, *pats, **opts):
3433 def revert(ui, repo, *pats, **opts):
3434 """restore individual files or directories to an earlier state
3434 """restore individual files or directories to an earlier state
3435
3435
3436 .. note::
3436 .. note::
3437 This command is most likely not what you are looking for.
3437 This command is most likely not what you are looking for.
3438 Revert will partially overwrite content in the working
3438 Revert will partially overwrite content in the working
3439 directory without changing the working directory parents. Use
3439 directory without changing the working directory parents. Use
3440 :hg:`update -r rev` to check out earlier revisions, or
3440 :hg:`update -r rev` to check out earlier revisions, or
3441 :hg:`update --clean .` to undo a merge which has added another
3441 :hg:`update --clean .` to undo a merge which has added another
3442 parent.
3442 parent.
3443
3443
3444 With no revision specified, revert the named files or directories
3444 With no revision specified, revert the named files or directories
3445 to the contents they had in the parent of the working directory.
3445 to the contents they had in the parent of the working directory.
3446 This restores the contents of the affected files to an unmodified
3446 This restores the contents of the affected files to an unmodified
3447 state and unschedules adds, removes, copies, and renames. If the
3447 state and unschedules adds, removes, copies, and renames. If the
3448 working directory has two parents, you must explicitly specify a
3448 working directory has two parents, you must explicitly specify a
3449 revision.
3449 revision.
3450
3450
3451 Using the -r/--rev option, revert the given files or directories
3451 Using the -r/--rev option, revert the given files or directories
3452 to their contents as of a specific revision. This can be helpful
3452 to their contents as of a specific revision. This can be helpful
3453 to "roll back" some or all of an earlier change. See :hg:`help
3453 to "roll back" some or all of an earlier change. See :hg:`help
3454 dates` for a list of formats valid for -d/--date.
3454 dates` for a list of formats valid for -d/--date.
3455
3455
3456 Revert modifies the working directory. It does not commit any
3456 Revert modifies the working directory. It does not commit any
3457 changes, or change the parent of the working directory. If you
3457 changes, or change the parent of the working directory. If you
3458 revert to a revision other than the parent of the working
3458 revert to a revision other than the parent of the working
3459 directory, the reverted files will thus appear modified
3459 directory, the reverted files will thus appear modified
3460 afterwards.
3460 afterwards.
3461
3461
3462 If a file has been deleted, it is restored. Files scheduled for
3462 If a file has been deleted, it is restored. Files scheduled for
3463 addition are just unscheduled and left as they are. If the
3463 addition are just unscheduled and left as they are. If the
3464 executable mode of a file was changed, it is reset.
3464 executable mode of a file was changed, it is reset.
3465
3465
3466 If names are given, all files matching the names are reverted.
3466 If names are given, all files matching the names are reverted.
3467 If no arguments are given, no files are reverted.
3467 If no arguments are given, no files are reverted.
3468
3468
3469 Modified files are saved with a .orig suffix before reverting.
3469 Modified files are saved with a .orig suffix before reverting.
3470 To disable these backups, use --no-backup.
3470 To disable these backups, use --no-backup.
3471
3471
3472 Returns 0 on success.
3472 Returns 0 on success.
3473 """
3473 """
3474
3474
3475 if opts.get("date"):
3475 if opts.get("date"):
3476 if opts.get("rev"):
3476 if opts.get("rev"):
3477 raise util.Abort(_("you can't specify a revision and a date"))
3477 raise util.Abort(_("you can't specify a revision and a date"))
3478 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3478 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3479
3479
3480 parent, p2 = repo.dirstate.parents()
3480 parent, p2 = repo.dirstate.parents()
3481 if not opts.get('rev') and p2 != nullid:
3481 if not opts.get('rev') and p2 != nullid:
3482 raise util.Abort(_('uncommitted merge - '
3482 raise util.Abort(_('uncommitted merge - '
3483 'use "hg update", see "hg help revert"'))
3483 'use "hg update", see "hg help revert"'))
3484
3484
3485 if not pats and not opts.get('all'):
3485 if not pats and not opts.get('all'):
3486 raise util.Abort(_('no files or directories specified; '
3486 raise util.Abort(_('no files or directories specified; '
3487 'use --all to revert the whole repo'))
3487 'use --all to revert the whole repo'))
3488
3488
3489 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3489 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3490 node = ctx.node()
3490 node = ctx.node()
3491 mf = ctx.manifest()
3491 mf = ctx.manifest()
3492 if node == parent:
3492 if node == parent:
3493 pmf = mf
3493 pmf = mf
3494 else:
3494 else:
3495 pmf = None
3495 pmf = None
3496
3496
3497 # need all matching names in dirstate and manifest of target rev,
3497 # need all matching names in dirstate and manifest of target rev,
3498 # so have to walk both. do not print errors if files exist in one
3498 # so have to walk both. do not print errors if files exist in one
3499 # but not other.
3499 # but not other.
3500
3500
3501 names = {}
3501 names = {}
3502
3502
3503 wlock = repo.wlock()
3503 wlock = repo.wlock()
3504 try:
3504 try:
3505 # walk dirstate.
3505 # walk dirstate.
3506
3506
3507 m = cmdutil.match(repo, pats, opts)
3507 m = cmdutil.match(repo, pats, opts)
3508 m.bad = lambda x, y: False
3508 m.bad = lambda x, y: False
3509 for abs in repo.walk(m):
3509 for abs in repo.walk(m):
3510 names[abs] = m.rel(abs), m.exact(abs)
3510 names[abs] = m.rel(abs), m.exact(abs)
3511
3511
3512 # walk target manifest.
3512 # walk target manifest.
3513
3513
3514 def badfn(path, msg):
3514 def badfn(path, msg):
3515 if path in names:
3515 if path in names:
3516 return
3516 return
3517 path_ = path + '/'
3517 path_ = path + '/'
3518 for f in names:
3518 for f in names:
3519 if f.startswith(path_):
3519 if f.startswith(path_):
3520 return
3520 return
3521 ui.warn("%s: %s\n" % (m.rel(path), msg))
3521 ui.warn("%s: %s\n" % (m.rel(path), msg))
3522
3522
3523 m = cmdutil.match(repo, pats, opts)
3523 m = cmdutil.match(repo, pats, opts)
3524 m.bad = badfn
3524 m.bad = badfn
3525 for abs in repo[node].walk(m):
3525 for abs in repo[node].walk(m):
3526 if abs not in names:
3526 if abs not in names:
3527 names[abs] = m.rel(abs), m.exact(abs)
3527 names[abs] = m.rel(abs), m.exact(abs)
3528
3528
3529 m = cmdutil.matchfiles(repo, names)
3529 m = cmdutil.matchfiles(repo, names)
3530 changes = repo.status(match=m)[:4]
3530 changes = repo.status(match=m)[:4]
3531 modified, added, removed, deleted = map(set, changes)
3531 modified, added, removed, deleted = map(set, changes)
3532
3532
3533 # if f is a rename, also revert the source
3533 # if f is a rename, also revert the source
3534 cwd = repo.getcwd()
3534 cwd = repo.getcwd()
3535 for f in added:
3535 for f in added:
3536 src = repo.dirstate.copied(f)
3536 src = repo.dirstate.copied(f)
3537 if src and src not in names and repo.dirstate[src] == 'r':
3537 if src and src not in names and repo.dirstate[src] == 'r':
3538 removed.add(src)
3538 removed.add(src)
3539 names[src] = (repo.pathto(src, cwd), True)
3539 names[src] = (repo.pathto(src, cwd), True)
3540
3540
3541 def removeforget(abs):
3541 def removeforget(abs):
3542 if repo.dirstate[abs] == 'a':
3542 if repo.dirstate[abs] == 'a':
3543 return _('forgetting %s\n')
3543 return _('forgetting %s\n')
3544 return _('removing %s\n')
3544 return _('removing %s\n')
3545
3545
3546 revert = ([], _('reverting %s\n'))
3546 revert = ([], _('reverting %s\n'))
3547 add = ([], _('adding %s\n'))
3547 add = ([], _('adding %s\n'))
3548 remove = ([], removeforget)
3548 remove = ([], removeforget)
3549 undelete = ([], _('undeleting %s\n'))
3549 undelete = ([], _('undeleting %s\n'))
3550
3550
3551 disptable = (
3551 disptable = (
3552 # dispatch table:
3552 # dispatch table:
3553 # file state
3553 # file state
3554 # action if in target manifest
3554 # action if in target manifest
3555 # action if not in target manifest
3555 # action if not in target manifest
3556 # make backup if in target manifest
3556 # make backup if in target manifest
3557 # make backup if not in target manifest
3557 # make backup if not in target manifest
3558 (modified, revert, remove, True, True),
3558 (modified, revert, remove, True, True),
3559 (added, revert, remove, True, False),
3559 (added, revert, remove, True, False),
3560 (removed, undelete, None, False, False),
3560 (removed, undelete, None, False, False),
3561 (deleted, revert, remove, False, False),
3561 (deleted, revert, remove, False, False),
3562 )
3562 )
3563
3563
3564 for abs, (rel, exact) in sorted(names.items()):
3564 for abs, (rel, exact) in sorted(names.items()):
3565 mfentry = mf.get(abs)
3565 mfentry = mf.get(abs)
3566 target = repo.wjoin(abs)
3566 target = repo.wjoin(abs)
3567 def handle(xlist, dobackup):
3567 def handle(xlist, dobackup):
3568 xlist[0].append(abs)
3568 xlist[0].append(abs)
3569 if (dobackup and not opts.get('no_backup') and
3569 if (dobackup and not opts.get('no_backup') and
3570 os.path.lexists(target)):
3570 os.path.lexists(target)):
3571 bakname = "%s.orig" % rel
3571 bakname = "%s.orig" % rel
3572 ui.note(_('saving current version of %s as %s\n') %
3572 ui.note(_('saving current version of %s as %s\n') %
3573 (rel, bakname))
3573 (rel, bakname))
3574 if not opts.get('dry_run'):
3574 if not opts.get('dry_run'):
3575 util.rename(target, bakname)
3575 util.rename(target, bakname)
3576 if ui.verbose or not exact:
3576 if ui.verbose or not exact:
3577 msg = xlist[1]
3577 msg = xlist[1]
3578 if not isinstance(msg, basestring):
3578 if not isinstance(msg, basestring):
3579 msg = msg(abs)
3579 msg = msg(abs)
3580 ui.status(msg % rel)
3580 ui.status(msg % rel)
3581 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3581 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3582 if abs not in table:
3582 if abs not in table:
3583 continue
3583 continue
3584 # file has changed in dirstate
3584 # file has changed in dirstate
3585 if mfentry:
3585 if mfentry:
3586 handle(hitlist, backuphit)
3586 handle(hitlist, backuphit)
3587 elif misslist is not None:
3587 elif misslist is not None:
3588 handle(misslist, backupmiss)
3588 handle(misslist, backupmiss)
3589 break
3589 break
3590 else:
3590 else:
3591 if abs not in repo.dirstate:
3591 if abs not in repo.dirstate:
3592 if mfentry:
3592 if mfentry:
3593 handle(add, True)
3593 handle(add, True)
3594 elif exact:
3594 elif exact:
3595 ui.warn(_('file not managed: %s\n') % rel)
3595 ui.warn(_('file not managed: %s\n') % rel)
3596 continue
3596 continue
3597 # file has not changed in dirstate
3597 # file has not changed in dirstate
3598 if node == parent:
3598 if node == parent:
3599 if exact:
3599 if exact:
3600 ui.warn(_('no changes needed to %s\n') % rel)
3600 ui.warn(_('no changes needed to %s\n') % rel)
3601 continue
3601 continue
3602 if pmf is None:
3602 if pmf is None:
3603 # only need parent manifest in this unlikely case,
3603 # only need parent manifest in this unlikely case,
3604 # so do not read by default
3604 # so do not read by default
3605 pmf = repo[parent].manifest()
3605 pmf = repo[parent].manifest()
3606 if abs in pmf:
3606 if abs in pmf:
3607 if mfentry:
3607 if mfentry:
3608 # if version of file is same in parent and target
3608 # if version of file is same in parent and target
3609 # manifests, do nothing
3609 # manifests, do nothing
3610 if (pmf[abs] != mfentry or
3610 if (pmf[abs] != mfentry or
3611 pmf.flags(abs) != mf.flags(abs)):
3611 pmf.flags(abs) != mf.flags(abs)):
3612 handle(revert, False)
3612 handle(revert, False)
3613 else:
3613 else:
3614 handle(remove, False)
3614 handle(remove, False)
3615
3615
3616 if not opts.get('dry_run'):
3616 if not opts.get('dry_run'):
3617 def checkout(f):
3617 def checkout(f):
3618 fc = ctx[f]
3618 fc = ctx[f]
3619 repo.wwrite(f, fc.data(), fc.flags())
3619 repo.wwrite(f, fc.data(), fc.flags())
3620
3620
3621 audit_path = scmutil.pathauditor(repo.root)
3621 audit_path = scmutil.pathauditor(repo.root)
3622 for f in remove[0]:
3622 for f in remove[0]:
3623 if repo.dirstate[f] == 'a':
3623 if repo.dirstate[f] == 'a':
3624 repo.dirstate.forget(f)
3624 repo.dirstate.forget(f)
3625 continue
3625 continue
3626 audit_path(f)
3626 audit_path(f)
3627 try:
3627 try:
3628 util.unlinkpath(repo.wjoin(f))
3628 util.unlinkpath(repo.wjoin(f))
3629 except OSError:
3629 except OSError:
3630 pass
3630 pass
3631 repo.dirstate.remove(f)
3631 repo.dirstate.remove(f)
3632
3632
3633 normal = None
3633 normal = None
3634 if node == parent:
3634 if node == parent:
3635 # We're reverting to our parent. If possible, we'd like status
3635 # We're reverting to our parent. If possible, we'd like status
3636 # to report the file as clean. We have to use normallookup for
3636 # to report the file as clean. We have to use normallookup for
3637 # merges to avoid losing information about merged/dirty files.
3637 # merges to avoid losing information about merged/dirty files.
3638 if p2 != nullid:
3638 if p2 != nullid:
3639 normal = repo.dirstate.normallookup
3639 normal = repo.dirstate.normallookup
3640 else:
3640 else:
3641 normal = repo.dirstate.normal
3641 normal = repo.dirstate.normal
3642 for f in revert[0]:
3642 for f in revert[0]:
3643 checkout(f)
3643 checkout(f)
3644 if normal:
3644 if normal:
3645 normal(f)
3645 normal(f)
3646
3646
3647 for f in add[0]:
3647 for f in add[0]:
3648 checkout(f)
3648 checkout(f)
3649 repo.dirstate.add(f)
3649 repo.dirstate.add(f)
3650
3650
3651 normal = repo.dirstate.normallookup
3651 normal = repo.dirstate.normallookup
3652 if node == parent and p2 == nullid:
3652 if node == parent and p2 == nullid:
3653 normal = repo.dirstate.normal
3653 normal = repo.dirstate.normal
3654 for f in undelete[0]:
3654 for f in undelete[0]:
3655 checkout(f)
3655 checkout(f)
3656 normal(f)
3656 normal(f)
3657
3657
3658 finally:
3658 finally:
3659 wlock.release()
3659 wlock.release()
3660
3660
3661 def rollback(ui, repo, **opts):
3661 def rollback(ui, repo, **opts):
3662 """roll back the last transaction (dangerous)
3662 """roll back the last transaction (dangerous)
3663
3663
3664 This command should be used with care. There is only one level of
3664 This command should be used with care. There is only one level of
3665 rollback, and there is no way to undo a rollback. It will also
3665 rollback, and there is no way to undo a rollback. It will also
3666 restore the dirstate at the time of the last transaction, losing
3666 restore the dirstate at the time of the last transaction, losing
3667 any dirstate changes since that time. This command does not alter
3667 any dirstate changes since that time. This command does not alter
3668 the working directory.
3668 the working directory.
3669
3669
3670 Transactions are used to encapsulate the effects of all commands
3670 Transactions are used to encapsulate the effects of all commands
3671 that create new changesets or propagate existing changesets into a
3671 that create new changesets or propagate existing changesets into a
3672 repository. For example, the following commands are transactional,
3672 repository. For example, the following commands are transactional,
3673 and their effects can be rolled back:
3673 and their effects can be rolled back:
3674
3674
3675 - commit
3675 - commit
3676 - import
3676 - import
3677 - pull
3677 - pull
3678 - push (with this repository as the destination)
3678 - push (with this repository as the destination)
3679 - unbundle
3679 - unbundle
3680
3680
3681 This command is not intended for use on public repositories. Once
3681 This command is not intended for use on public repositories. Once
3682 changes are visible for pull by other users, rolling a transaction
3682 changes are visible for pull by other users, rolling a transaction
3683 back locally is ineffective (someone else may already have pulled
3683 back locally is ineffective (someone else may already have pulled
3684 the changes). Furthermore, a race is possible with readers of the
3684 the changes). Furthermore, a race is possible with readers of the
3685 repository; for example an in-progress pull from the repository
3685 repository; for example an in-progress pull from the repository
3686 may fail if a rollback is performed.
3686 may fail if a rollback is performed.
3687
3687
3688 Returns 0 on success, 1 if no rollback data is available.
3688 Returns 0 on success, 1 if no rollback data is available.
3689 """
3689 """
3690 return repo.rollback(opts.get('dry_run'))
3690 return repo.rollback(opts.get('dry_run'))
3691
3691
3692 def root(ui, repo):
3692 def root(ui, repo):
3693 """print the root (top) of the current working directory
3693 """print the root (top) of the current working directory
3694
3694
3695 Print the root directory of the current repository.
3695 Print the root directory of the current repository.
3696
3696
3697 Returns 0 on success.
3697 Returns 0 on success.
3698 """
3698 """
3699 ui.write(repo.root + "\n")
3699 ui.write(repo.root + "\n")
3700
3700
3701 def serve(ui, repo, **opts):
3701 def serve(ui, repo, **opts):
3702 """start stand-alone webserver
3702 """start stand-alone webserver
3703
3703
3704 Start a local HTTP repository browser and pull server. You can use
3704 Start a local HTTP repository browser and pull server. You can use
3705 this for ad-hoc sharing and browsing of repositories. It is
3705 this for ad-hoc sharing and browsing of repositories. It is
3706 recommended to use a real web server to serve a repository for
3706 recommended to use a real web server to serve a repository for
3707 longer periods of time.
3707 longer periods of time.
3708
3708
3709 Please note that the server does not implement access control.
3709 Please note that the server does not implement access control.
3710 This means that, by default, anybody can read from the server and
3710 This means that, by default, anybody can read from the server and
3711 nobody can write to it by default. Set the ``web.allow_push``
3711 nobody can write to it by default. Set the ``web.allow_push``
3712 option to ``*`` to allow everybody to push to the server. You
3712 option to ``*`` to allow everybody to push to the server. You
3713 should use a real web server if you need to authenticate users.
3713 should use a real web server if you need to authenticate users.
3714
3714
3715 By default, the server logs accesses to stdout and errors to
3715 By default, the server logs accesses to stdout and errors to
3716 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3716 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3717 files.
3717 files.
3718
3718
3719 To have the server choose a free port number to listen on, specify
3719 To have the server choose a free port number to listen on, specify
3720 a port number of 0; in this case, the server will print the port
3720 a port number of 0; in this case, the server will print the port
3721 number it uses.
3721 number it uses.
3722
3722
3723 Returns 0 on success.
3723 Returns 0 on success.
3724 """
3724 """
3725
3725
3726 if opts["stdio"]:
3726 if opts["stdio"]:
3727 if repo is None:
3727 if repo is None:
3728 raise error.RepoError(_("There is no Mercurial repository here"
3728 raise error.RepoError(_("There is no Mercurial repository here"
3729 " (.hg not found)"))
3729 " (.hg not found)"))
3730 s = sshserver.sshserver(ui, repo)
3730 s = sshserver.sshserver(ui, repo)
3731 s.serve_forever()
3731 s.serve_forever()
3732
3732
3733 # this way we can check if something was given in the command-line
3733 # this way we can check if something was given in the command-line
3734 if opts.get('port'):
3734 if opts.get('port'):
3735 opts['port'] = util.getport(opts.get('port'))
3735 opts['port'] = util.getport(opts.get('port'))
3736
3736
3737 baseui = repo and repo.baseui or ui
3737 baseui = repo and repo.baseui or ui
3738 optlist = ("name templates style address port prefix ipv6"
3738 optlist = ("name templates style address port prefix ipv6"
3739 " accesslog errorlog certificate encoding")
3739 " accesslog errorlog certificate encoding")
3740 for o in optlist.split():
3740 for o in optlist.split():
3741 val = opts.get(o, '')
3741 val = opts.get(o, '')
3742 if val in (None, ''): # should check against default options instead
3742 if val in (None, ''): # should check against default options instead
3743 continue
3743 continue
3744 baseui.setconfig("web", o, val)
3744 baseui.setconfig("web", o, val)
3745 if repo and repo.ui != baseui:
3745 if repo and repo.ui != baseui:
3746 repo.ui.setconfig("web", o, val)
3746 repo.ui.setconfig("web", o, val)
3747
3747
3748 o = opts.get('web_conf') or opts.get('webdir_conf')
3748 o = opts.get('web_conf') or opts.get('webdir_conf')
3749 if not o:
3749 if not o:
3750 if not repo:
3750 if not repo:
3751 raise error.RepoError(_("There is no Mercurial repository"
3751 raise error.RepoError(_("There is no Mercurial repository"
3752 " here (.hg not found)"))
3752 " here (.hg not found)"))
3753 o = repo.root
3753 o = repo.root
3754
3754
3755 app = hgweb.hgweb(o, baseui=ui)
3755 app = hgweb.hgweb(o, baseui=ui)
3756
3756
3757 class service(object):
3757 class service(object):
3758 def init(self):
3758 def init(self):
3759 util.set_signal_handler()
3759 util.setsignalhandler()
3760 self.httpd = hgweb.server.create_server(ui, app)
3760 self.httpd = hgweb.server.create_server(ui, app)
3761
3761
3762 if opts['port'] and not ui.verbose:
3762 if opts['port'] and not ui.verbose:
3763 return
3763 return
3764
3764
3765 if self.httpd.prefix:
3765 if self.httpd.prefix:
3766 prefix = self.httpd.prefix.strip('/') + '/'
3766 prefix = self.httpd.prefix.strip('/') + '/'
3767 else:
3767 else:
3768 prefix = ''
3768 prefix = ''
3769
3769
3770 port = ':%d' % self.httpd.port
3770 port = ':%d' % self.httpd.port
3771 if port == ':80':
3771 if port == ':80':
3772 port = ''
3772 port = ''
3773
3773
3774 bindaddr = self.httpd.addr
3774 bindaddr = self.httpd.addr
3775 if bindaddr == '0.0.0.0':
3775 if bindaddr == '0.0.0.0':
3776 bindaddr = '*'
3776 bindaddr = '*'
3777 elif ':' in bindaddr: # IPv6
3777 elif ':' in bindaddr: # IPv6
3778 bindaddr = '[%s]' % bindaddr
3778 bindaddr = '[%s]' % bindaddr
3779
3779
3780 fqaddr = self.httpd.fqaddr
3780 fqaddr = self.httpd.fqaddr
3781 if ':' in fqaddr:
3781 if ':' in fqaddr:
3782 fqaddr = '[%s]' % fqaddr
3782 fqaddr = '[%s]' % fqaddr
3783 if opts['port']:
3783 if opts['port']:
3784 write = ui.status
3784 write = ui.status
3785 else:
3785 else:
3786 write = ui.write
3786 write = ui.write
3787 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3787 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3788 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3788 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3789
3789
3790 def run(self):
3790 def run(self):
3791 self.httpd.serve_forever()
3791 self.httpd.serve_forever()
3792
3792
3793 service = service()
3793 service = service()
3794
3794
3795 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3795 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3796
3796
3797 def status(ui, repo, *pats, **opts):
3797 def status(ui, repo, *pats, **opts):
3798 """show changed files in the working directory
3798 """show changed files in the working directory
3799
3799
3800 Show status of files in the repository. If names are given, only
3800 Show status of files in the repository. If names are given, only
3801 files that match are shown. Files that are clean or ignored or
3801 files that match are shown. Files that are clean or ignored or
3802 the source of a copy/move operation, are not listed unless
3802 the source of a copy/move operation, are not listed unless
3803 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3803 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3804 Unless options described with "show only ..." are given, the
3804 Unless options described with "show only ..." are given, the
3805 options -mardu are used.
3805 options -mardu are used.
3806
3806
3807 Option -q/--quiet hides untracked (unknown and ignored) files
3807 Option -q/--quiet hides untracked (unknown and ignored) files
3808 unless explicitly requested with -u/--unknown or -i/--ignored.
3808 unless explicitly requested with -u/--unknown or -i/--ignored.
3809
3809
3810 .. note::
3810 .. note::
3811 status may appear to disagree with diff if permissions have
3811 status may appear to disagree with diff if permissions have
3812 changed or a merge has occurred. The standard diff format does
3812 changed or a merge has occurred. The standard diff format does
3813 not report permission changes and diff only reports changes
3813 not report permission changes and diff only reports changes
3814 relative to one merge parent.
3814 relative to one merge parent.
3815
3815
3816 If one revision is given, it is used as the base revision.
3816 If one revision is given, it is used as the base revision.
3817 If two revisions are given, the differences between them are
3817 If two revisions are given, the differences between them are
3818 shown. The --change option can also be used as a shortcut to list
3818 shown. The --change option can also be used as a shortcut to list
3819 the changed files of a revision from its first parent.
3819 the changed files of a revision from its first parent.
3820
3820
3821 The codes used to show the status of files are::
3821 The codes used to show the status of files are::
3822
3822
3823 M = modified
3823 M = modified
3824 A = added
3824 A = added
3825 R = removed
3825 R = removed
3826 C = clean
3826 C = clean
3827 ! = missing (deleted by non-hg command, but still tracked)
3827 ! = missing (deleted by non-hg command, but still tracked)
3828 ? = not tracked
3828 ? = not tracked
3829 I = ignored
3829 I = ignored
3830 = origin of the previous file listed as A (added)
3830 = origin of the previous file listed as A (added)
3831
3831
3832 Returns 0 on success.
3832 Returns 0 on success.
3833 """
3833 """
3834
3834
3835 revs = opts.get('rev')
3835 revs = opts.get('rev')
3836 change = opts.get('change')
3836 change = opts.get('change')
3837
3837
3838 if revs and change:
3838 if revs and change:
3839 msg = _('cannot specify --rev and --change at the same time')
3839 msg = _('cannot specify --rev and --change at the same time')
3840 raise util.Abort(msg)
3840 raise util.Abort(msg)
3841 elif change:
3841 elif change:
3842 node2 = repo.lookup(change)
3842 node2 = repo.lookup(change)
3843 node1 = repo[node2].p1().node()
3843 node1 = repo[node2].p1().node()
3844 else:
3844 else:
3845 node1, node2 = cmdutil.revpair(repo, revs)
3845 node1, node2 = cmdutil.revpair(repo, revs)
3846
3846
3847 cwd = (pats and repo.getcwd()) or ''
3847 cwd = (pats and repo.getcwd()) or ''
3848 end = opts.get('print0') and '\0' or '\n'
3848 end = opts.get('print0') and '\0' or '\n'
3849 copy = {}
3849 copy = {}
3850 states = 'modified added removed deleted unknown ignored clean'.split()
3850 states = 'modified added removed deleted unknown ignored clean'.split()
3851 show = [k for k in states if opts.get(k)]
3851 show = [k for k in states if opts.get(k)]
3852 if opts.get('all'):
3852 if opts.get('all'):
3853 show += ui.quiet and (states[:4] + ['clean']) or states
3853 show += ui.quiet and (states[:4] + ['clean']) or states
3854 if not show:
3854 if not show:
3855 show = ui.quiet and states[:4] or states[:5]
3855 show = ui.quiet and states[:4] or states[:5]
3856
3856
3857 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3857 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3858 'ignored' in show, 'clean' in show, 'unknown' in show,
3858 'ignored' in show, 'clean' in show, 'unknown' in show,
3859 opts.get('subrepos'))
3859 opts.get('subrepos'))
3860 changestates = zip(states, 'MAR!?IC', stat)
3860 changestates = zip(states, 'MAR!?IC', stat)
3861
3861
3862 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3862 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3863 ctxn = repo[nullid]
3863 ctxn = repo[nullid]
3864 ctx1 = repo[node1]
3864 ctx1 = repo[node1]
3865 ctx2 = repo[node2]
3865 ctx2 = repo[node2]
3866 added = stat[1]
3866 added = stat[1]
3867 if node2 is None:
3867 if node2 is None:
3868 added = stat[0] + stat[1] # merged?
3868 added = stat[0] + stat[1] # merged?
3869
3869
3870 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3870 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3871 if k in added:
3871 if k in added:
3872 copy[k] = v
3872 copy[k] = v
3873 elif v in added:
3873 elif v in added:
3874 copy[v] = k
3874 copy[v] = k
3875
3875
3876 for state, char, files in changestates:
3876 for state, char, files in changestates:
3877 if state in show:
3877 if state in show:
3878 format = "%s %%s%s" % (char, end)
3878 format = "%s %%s%s" % (char, end)
3879 if opts.get('no_status'):
3879 if opts.get('no_status'):
3880 format = "%%s%s" % end
3880 format = "%%s%s" % end
3881
3881
3882 for f in files:
3882 for f in files:
3883 ui.write(format % repo.pathto(f, cwd),
3883 ui.write(format % repo.pathto(f, cwd),
3884 label='status.' + state)
3884 label='status.' + state)
3885 if f in copy:
3885 if f in copy:
3886 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3886 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3887 label='status.copied')
3887 label='status.copied')
3888
3888
3889 def summary(ui, repo, **opts):
3889 def summary(ui, repo, **opts):
3890 """summarize working directory state
3890 """summarize working directory state
3891
3891
3892 This generates a brief summary of the working directory state,
3892 This generates a brief summary of the working directory state,
3893 including parents, branch, commit status, and available updates.
3893 including parents, branch, commit status, and available updates.
3894
3894
3895 With the --remote option, this will check the default paths for
3895 With the --remote option, this will check the default paths for
3896 incoming and outgoing changes. This can be time-consuming.
3896 incoming and outgoing changes. This can be time-consuming.
3897
3897
3898 Returns 0 on success.
3898 Returns 0 on success.
3899 """
3899 """
3900
3900
3901 ctx = repo[None]
3901 ctx = repo[None]
3902 parents = ctx.parents()
3902 parents = ctx.parents()
3903 pnode = parents[0].node()
3903 pnode = parents[0].node()
3904
3904
3905 for p in parents:
3905 for p in parents:
3906 # label with log.changeset (instead of log.parent) since this
3906 # label with log.changeset (instead of log.parent) since this
3907 # shows a working directory parent *changeset*:
3907 # shows a working directory parent *changeset*:
3908 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3908 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3909 label='log.changeset')
3909 label='log.changeset')
3910 ui.write(' '.join(p.tags()), label='log.tag')
3910 ui.write(' '.join(p.tags()), label='log.tag')
3911 if p.bookmarks():
3911 if p.bookmarks():
3912 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3912 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3913 if p.rev() == -1:
3913 if p.rev() == -1:
3914 if not len(repo):
3914 if not len(repo):
3915 ui.write(_(' (empty repository)'))
3915 ui.write(_(' (empty repository)'))
3916 else:
3916 else:
3917 ui.write(_(' (no revision checked out)'))
3917 ui.write(_(' (no revision checked out)'))
3918 ui.write('\n')
3918 ui.write('\n')
3919 if p.description():
3919 if p.description():
3920 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3920 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3921 label='log.summary')
3921 label='log.summary')
3922
3922
3923 branch = ctx.branch()
3923 branch = ctx.branch()
3924 bheads = repo.branchheads(branch)
3924 bheads = repo.branchheads(branch)
3925 m = _('branch: %s\n') % branch
3925 m = _('branch: %s\n') % branch
3926 if branch != 'default':
3926 if branch != 'default':
3927 ui.write(m, label='log.branch')
3927 ui.write(m, label='log.branch')
3928 else:
3928 else:
3929 ui.status(m, label='log.branch')
3929 ui.status(m, label='log.branch')
3930
3930
3931 st = list(repo.status(unknown=True))[:6]
3931 st = list(repo.status(unknown=True))[:6]
3932
3932
3933 c = repo.dirstate.copies()
3933 c = repo.dirstate.copies()
3934 copied, renamed = [], []
3934 copied, renamed = [], []
3935 for d, s in c.iteritems():
3935 for d, s in c.iteritems():
3936 if s in st[2]:
3936 if s in st[2]:
3937 st[2].remove(s)
3937 st[2].remove(s)
3938 renamed.append(d)
3938 renamed.append(d)
3939 else:
3939 else:
3940 copied.append(d)
3940 copied.append(d)
3941 if d in st[1]:
3941 if d in st[1]:
3942 st[1].remove(d)
3942 st[1].remove(d)
3943 st.insert(3, renamed)
3943 st.insert(3, renamed)
3944 st.insert(4, copied)
3944 st.insert(4, copied)
3945
3945
3946 ms = mergemod.mergestate(repo)
3946 ms = mergemod.mergestate(repo)
3947 st.append([f for f in ms if ms[f] == 'u'])
3947 st.append([f for f in ms if ms[f] == 'u'])
3948
3948
3949 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3949 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3950 st.append(subs)
3950 st.append(subs)
3951
3951
3952 labels = [ui.label(_('%d modified'), 'status.modified'),
3952 labels = [ui.label(_('%d modified'), 'status.modified'),
3953 ui.label(_('%d added'), 'status.added'),
3953 ui.label(_('%d added'), 'status.added'),
3954 ui.label(_('%d removed'), 'status.removed'),
3954 ui.label(_('%d removed'), 'status.removed'),
3955 ui.label(_('%d renamed'), 'status.copied'),
3955 ui.label(_('%d renamed'), 'status.copied'),
3956 ui.label(_('%d copied'), 'status.copied'),
3956 ui.label(_('%d copied'), 'status.copied'),
3957 ui.label(_('%d deleted'), 'status.deleted'),
3957 ui.label(_('%d deleted'), 'status.deleted'),
3958 ui.label(_('%d unknown'), 'status.unknown'),
3958 ui.label(_('%d unknown'), 'status.unknown'),
3959 ui.label(_('%d ignored'), 'status.ignored'),
3959 ui.label(_('%d ignored'), 'status.ignored'),
3960 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3960 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3961 ui.label(_('%d subrepos'), 'status.modified')]
3961 ui.label(_('%d subrepos'), 'status.modified')]
3962 t = []
3962 t = []
3963 for s, l in zip(st, labels):
3963 for s, l in zip(st, labels):
3964 if s:
3964 if s:
3965 t.append(l % len(s))
3965 t.append(l % len(s))
3966
3966
3967 t = ', '.join(t)
3967 t = ', '.join(t)
3968 cleanworkdir = False
3968 cleanworkdir = False
3969
3969
3970 if len(parents) > 1:
3970 if len(parents) > 1:
3971 t += _(' (merge)')
3971 t += _(' (merge)')
3972 elif branch != parents[0].branch():
3972 elif branch != parents[0].branch():
3973 t += _(' (new branch)')
3973 t += _(' (new branch)')
3974 elif (parents[0].extra().get('close') and
3974 elif (parents[0].extra().get('close') and
3975 pnode in repo.branchheads(branch, closed=True)):
3975 pnode in repo.branchheads(branch, closed=True)):
3976 t += _(' (head closed)')
3976 t += _(' (head closed)')
3977 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3977 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3978 t += _(' (clean)')
3978 t += _(' (clean)')
3979 cleanworkdir = True
3979 cleanworkdir = True
3980 elif pnode not in bheads:
3980 elif pnode not in bheads:
3981 t += _(' (new branch head)')
3981 t += _(' (new branch head)')
3982
3982
3983 if cleanworkdir:
3983 if cleanworkdir:
3984 ui.status(_('commit: %s\n') % t.strip())
3984 ui.status(_('commit: %s\n') % t.strip())
3985 else:
3985 else:
3986 ui.write(_('commit: %s\n') % t.strip())
3986 ui.write(_('commit: %s\n') % t.strip())
3987
3987
3988 # all ancestors of branch heads - all ancestors of parent = new csets
3988 # all ancestors of branch heads - all ancestors of parent = new csets
3989 new = [0] * len(repo)
3989 new = [0] * len(repo)
3990 cl = repo.changelog
3990 cl = repo.changelog
3991 for a in [cl.rev(n) for n in bheads]:
3991 for a in [cl.rev(n) for n in bheads]:
3992 new[a] = 1
3992 new[a] = 1
3993 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3993 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3994 new[a] = 1
3994 new[a] = 1
3995 for a in [p.rev() for p in parents]:
3995 for a in [p.rev() for p in parents]:
3996 if a >= 0:
3996 if a >= 0:
3997 new[a] = 0
3997 new[a] = 0
3998 for a in cl.ancestors(*[p.rev() for p in parents]):
3998 for a in cl.ancestors(*[p.rev() for p in parents]):
3999 new[a] = 0
3999 new[a] = 0
4000 new = sum(new)
4000 new = sum(new)
4001
4001
4002 if new == 0:
4002 if new == 0:
4003 ui.status(_('update: (current)\n'))
4003 ui.status(_('update: (current)\n'))
4004 elif pnode not in bheads:
4004 elif pnode not in bheads:
4005 ui.write(_('update: %d new changesets (update)\n') % new)
4005 ui.write(_('update: %d new changesets (update)\n') % new)
4006 else:
4006 else:
4007 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4007 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4008 (new, len(bheads)))
4008 (new, len(bheads)))
4009
4009
4010 if opts.get('remote'):
4010 if opts.get('remote'):
4011 t = []
4011 t = []
4012 source, branches = hg.parseurl(ui.expandpath('default'))
4012 source, branches = hg.parseurl(ui.expandpath('default'))
4013 other = hg.repository(hg.remoteui(repo, {}), source)
4013 other = hg.repository(hg.remoteui(repo, {}), source)
4014 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4014 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4015 ui.debug('comparing with %s\n' % util.hidepassword(source))
4015 ui.debug('comparing with %s\n' % util.hidepassword(source))
4016 repo.ui.pushbuffer()
4016 repo.ui.pushbuffer()
4017 common, incoming, rheads = discovery.findcommonincoming(repo, other)
4017 common, incoming, rheads = discovery.findcommonincoming(repo, other)
4018 repo.ui.popbuffer()
4018 repo.ui.popbuffer()
4019 if incoming:
4019 if incoming:
4020 t.append(_('1 or more incoming'))
4020 t.append(_('1 or more incoming'))
4021
4021
4022 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4022 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4023 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4023 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4024 other = hg.repository(hg.remoteui(repo, {}), dest)
4024 other = hg.repository(hg.remoteui(repo, {}), dest)
4025 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4025 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4026 repo.ui.pushbuffer()
4026 repo.ui.pushbuffer()
4027 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
4027 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
4028 repo.ui.popbuffer()
4028 repo.ui.popbuffer()
4029 o = repo.changelog.findmissing(common=common)
4029 o = repo.changelog.findmissing(common=common)
4030 if o:
4030 if o:
4031 t.append(_('%d outgoing') % len(o))
4031 t.append(_('%d outgoing') % len(o))
4032 if 'bookmarks' in other.listkeys('namespaces'):
4032 if 'bookmarks' in other.listkeys('namespaces'):
4033 lmarks = repo.listkeys('bookmarks')
4033 lmarks = repo.listkeys('bookmarks')
4034 rmarks = other.listkeys('bookmarks')
4034 rmarks = other.listkeys('bookmarks')
4035 diff = set(rmarks) - set(lmarks)
4035 diff = set(rmarks) - set(lmarks)
4036 if len(diff) > 0:
4036 if len(diff) > 0:
4037 t.append(_('%d incoming bookmarks') % len(diff))
4037 t.append(_('%d incoming bookmarks') % len(diff))
4038 diff = set(lmarks) - set(rmarks)
4038 diff = set(lmarks) - set(rmarks)
4039 if len(diff) > 0:
4039 if len(diff) > 0:
4040 t.append(_('%d outgoing bookmarks') % len(diff))
4040 t.append(_('%d outgoing bookmarks') % len(diff))
4041
4041
4042 if t:
4042 if t:
4043 ui.write(_('remote: %s\n') % (', '.join(t)))
4043 ui.write(_('remote: %s\n') % (', '.join(t)))
4044 else:
4044 else:
4045 ui.status(_('remote: (synced)\n'))
4045 ui.status(_('remote: (synced)\n'))
4046
4046
4047 def tag(ui, repo, name1, *names, **opts):
4047 def tag(ui, repo, name1, *names, **opts):
4048 """add one or more tags for the current or given revision
4048 """add one or more tags for the current or given revision
4049
4049
4050 Name a particular revision using <name>.
4050 Name a particular revision using <name>.
4051
4051
4052 Tags are used to name particular revisions of the repository and are
4052 Tags are used to name particular revisions of the repository and are
4053 very useful to compare different revisions, to go back to significant
4053 very useful to compare different revisions, to go back to significant
4054 earlier versions or to mark branch points as releases, etc. Changing
4054 earlier versions or to mark branch points as releases, etc. Changing
4055 an existing tag is normally disallowed; use -f/--force to override.
4055 an existing tag is normally disallowed; use -f/--force to override.
4056
4056
4057 If no revision is given, the parent of the working directory is
4057 If no revision is given, the parent of the working directory is
4058 used, or tip if no revision is checked out.
4058 used, or tip if no revision is checked out.
4059
4059
4060 To facilitate version control, distribution, and merging of tags,
4060 To facilitate version control, distribution, and merging of tags,
4061 they are stored as a file named ".hgtags" which is managed similarly
4061 they are stored as a file named ".hgtags" which is managed similarly
4062 to other project files and can be hand-edited if necessary. This
4062 to other project files and can be hand-edited if necessary. This
4063 also means that tagging creates a new commit. The file
4063 also means that tagging creates a new commit. The file
4064 ".hg/localtags" is used for local tags (not shared among
4064 ".hg/localtags" is used for local tags (not shared among
4065 repositories).
4065 repositories).
4066
4066
4067 Tag commits are usually made at the head of a branch. If the parent
4067 Tag commits are usually made at the head of a branch. If the parent
4068 of the working directory is not a branch head, :hg:`tag` aborts; use
4068 of the working directory is not a branch head, :hg:`tag` aborts; use
4069 -f/--force to force the tag commit to be based on a non-head
4069 -f/--force to force the tag commit to be based on a non-head
4070 changeset.
4070 changeset.
4071
4071
4072 See :hg:`help dates` for a list of formats valid for -d/--date.
4072 See :hg:`help dates` for a list of formats valid for -d/--date.
4073
4073
4074 Since tag names have priority over branch names during revision
4074 Since tag names have priority over branch names during revision
4075 lookup, using an existing branch name as a tag name is discouraged.
4075 lookup, using an existing branch name as a tag name is discouraged.
4076
4076
4077 Returns 0 on success.
4077 Returns 0 on success.
4078 """
4078 """
4079
4079
4080 rev_ = "."
4080 rev_ = "."
4081 names = [t.strip() for t in (name1,) + names]
4081 names = [t.strip() for t in (name1,) + names]
4082 if len(names) != len(set(names)):
4082 if len(names) != len(set(names)):
4083 raise util.Abort(_('tag names must be unique'))
4083 raise util.Abort(_('tag names must be unique'))
4084 for n in names:
4084 for n in names:
4085 if n in ['tip', '.', 'null']:
4085 if n in ['tip', '.', 'null']:
4086 raise util.Abort(_("the name '%s' is reserved") % n)
4086 raise util.Abort(_("the name '%s' is reserved") % n)
4087 if not n:
4087 if not n:
4088 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4088 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4089 if opts.get('rev') and opts.get('remove'):
4089 if opts.get('rev') and opts.get('remove'):
4090 raise util.Abort(_("--rev and --remove are incompatible"))
4090 raise util.Abort(_("--rev and --remove are incompatible"))
4091 if opts.get('rev'):
4091 if opts.get('rev'):
4092 rev_ = opts['rev']
4092 rev_ = opts['rev']
4093 message = opts.get('message')
4093 message = opts.get('message')
4094 if opts.get('remove'):
4094 if opts.get('remove'):
4095 expectedtype = opts.get('local') and 'local' or 'global'
4095 expectedtype = opts.get('local') and 'local' or 'global'
4096 for n in names:
4096 for n in names:
4097 if not repo.tagtype(n):
4097 if not repo.tagtype(n):
4098 raise util.Abort(_("tag '%s' does not exist") % n)
4098 raise util.Abort(_("tag '%s' does not exist") % n)
4099 if repo.tagtype(n) != expectedtype:
4099 if repo.tagtype(n) != expectedtype:
4100 if expectedtype == 'global':
4100 if expectedtype == 'global':
4101 raise util.Abort(_("tag '%s' is not a global tag") % n)
4101 raise util.Abort(_("tag '%s' is not a global tag") % n)
4102 else:
4102 else:
4103 raise util.Abort(_("tag '%s' is not a local tag") % n)
4103 raise util.Abort(_("tag '%s' is not a local tag") % n)
4104 rev_ = nullid
4104 rev_ = nullid
4105 if not message:
4105 if not message:
4106 # we don't translate commit messages
4106 # we don't translate commit messages
4107 message = 'Removed tag %s' % ', '.join(names)
4107 message = 'Removed tag %s' % ', '.join(names)
4108 elif not opts.get('force'):
4108 elif not opts.get('force'):
4109 for n in names:
4109 for n in names:
4110 if n in repo.tags():
4110 if n in repo.tags():
4111 raise util.Abort(_("tag '%s' already exists "
4111 raise util.Abort(_("tag '%s' already exists "
4112 "(use -f to force)") % n)
4112 "(use -f to force)") % n)
4113 if not opts.get('local'):
4113 if not opts.get('local'):
4114 p1, p2 = repo.dirstate.parents()
4114 p1, p2 = repo.dirstate.parents()
4115 if p2 != nullid:
4115 if p2 != nullid:
4116 raise util.Abort(_('uncommitted merge'))
4116 raise util.Abort(_('uncommitted merge'))
4117 bheads = repo.branchheads()
4117 bheads = repo.branchheads()
4118 if not opts.get('force') and bheads and p1 not in bheads:
4118 if not opts.get('force') and bheads and p1 not in bheads:
4119 raise util.Abort(_('not at a branch head (use -f to force)'))
4119 raise util.Abort(_('not at a branch head (use -f to force)'))
4120 r = cmdutil.revsingle(repo, rev_).node()
4120 r = cmdutil.revsingle(repo, rev_).node()
4121
4121
4122 if not message:
4122 if not message:
4123 # we don't translate commit messages
4123 # we don't translate commit messages
4124 message = ('Added tag %s for changeset %s' %
4124 message = ('Added tag %s for changeset %s' %
4125 (', '.join(names), short(r)))
4125 (', '.join(names), short(r)))
4126
4126
4127 date = opts.get('date')
4127 date = opts.get('date')
4128 if date:
4128 if date:
4129 date = util.parsedate(date)
4129 date = util.parsedate(date)
4130
4130
4131 if opts.get('edit'):
4131 if opts.get('edit'):
4132 message = ui.edit(message, ui.username())
4132 message = ui.edit(message, ui.username())
4133
4133
4134 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4134 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4135
4135
4136 def tags(ui, repo):
4136 def tags(ui, repo):
4137 """list repository tags
4137 """list repository tags
4138
4138
4139 This lists both regular and local tags. When the -v/--verbose
4139 This lists both regular and local tags. When the -v/--verbose
4140 switch is used, a third column "local" is printed for local tags.
4140 switch is used, a third column "local" is printed for local tags.
4141
4141
4142 Returns 0 on success.
4142 Returns 0 on success.
4143 """
4143 """
4144
4144
4145 hexfunc = ui.debugflag and hex or short
4145 hexfunc = ui.debugflag and hex or short
4146 tagtype = ""
4146 tagtype = ""
4147
4147
4148 for t, n in reversed(repo.tagslist()):
4148 for t, n in reversed(repo.tagslist()):
4149 if ui.quiet:
4149 if ui.quiet:
4150 ui.write("%s\n" % t)
4150 ui.write("%s\n" % t)
4151 continue
4151 continue
4152
4152
4153 hn = hexfunc(n)
4153 hn = hexfunc(n)
4154 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4154 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4155 spaces = " " * (30 - encoding.colwidth(t))
4155 spaces = " " * (30 - encoding.colwidth(t))
4156
4156
4157 if ui.verbose:
4157 if ui.verbose:
4158 if repo.tagtype(t) == 'local':
4158 if repo.tagtype(t) == 'local':
4159 tagtype = " local"
4159 tagtype = " local"
4160 else:
4160 else:
4161 tagtype = ""
4161 tagtype = ""
4162 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4162 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4163
4163
4164 def tip(ui, repo, **opts):
4164 def tip(ui, repo, **opts):
4165 """show the tip revision
4165 """show the tip revision
4166
4166
4167 The tip revision (usually just called the tip) is the changeset
4167 The tip revision (usually just called the tip) is the changeset
4168 most recently added to the repository (and therefore the most
4168 most recently added to the repository (and therefore the most
4169 recently changed head).
4169 recently changed head).
4170
4170
4171 If you have just made a commit, that commit will be the tip. If
4171 If you have just made a commit, that commit will be the tip. If
4172 you have just pulled changes from another repository, the tip of
4172 you have just pulled changes from another repository, the tip of
4173 that repository becomes the current tip. The "tip" tag is special
4173 that repository becomes the current tip. The "tip" tag is special
4174 and cannot be renamed or assigned to a different changeset.
4174 and cannot be renamed or assigned to a different changeset.
4175
4175
4176 Returns 0 on success.
4176 Returns 0 on success.
4177 """
4177 """
4178 displayer = cmdutil.show_changeset(ui, repo, opts)
4178 displayer = cmdutil.show_changeset(ui, repo, opts)
4179 displayer.show(repo[len(repo) - 1])
4179 displayer.show(repo[len(repo) - 1])
4180 displayer.close()
4180 displayer.close()
4181
4181
4182 def unbundle(ui, repo, fname1, *fnames, **opts):
4182 def unbundle(ui, repo, fname1, *fnames, **opts):
4183 """apply one or more changegroup files
4183 """apply one or more changegroup files
4184
4184
4185 Apply one or more compressed changegroup files generated by the
4185 Apply one or more compressed changegroup files generated by the
4186 bundle command.
4186 bundle command.
4187
4187
4188 Returns 0 on success, 1 if an update has unresolved files.
4188 Returns 0 on success, 1 if an update has unresolved files.
4189 """
4189 """
4190 fnames = (fname1,) + fnames
4190 fnames = (fname1,) + fnames
4191
4191
4192 lock = repo.lock()
4192 lock = repo.lock()
4193 wc = repo['.']
4193 wc = repo['.']
4194 try:
4194 try:
4195 for fname in fnames:
4195 for fname in fnames:
4196 f = url.open(ui, fname)
4196 f = url.open(ui, fname)
4197 gen = changegroup.readbundle(f, fname)
4197 gen = changegroup.readbundle(f, fname)
4198 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4198 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4199 lock=lock)
4199 lock=lock)
4200 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4200 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4201 finally:
4201 finally:
4202 lock.release()
4202 lock.release()
4203 return postincoming(ui, repo, modheads, opts.get('update'), None)
4203 return postincoming(ui, repo, modheads, opts.get('update'), None)
4204
4204
4205 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4205 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4206 """update working directory (or switch revisions)
4206 """update working directory (or switch revisions)
4207
4207
4208 Update the repository's working directory to the specified
4208 Update the repository's working directory to the specified
4209 changeset. If no changeset is specified, update to the tip of the
4209 changeset. If no changeset is specified, update to the tip of the
4210 current named branch.
4210 current named branch.
4211
4211
4212 If the changeset is not a descendant of the working directory's
4212 If the changeset is not a descendant of the working directory's
4213 parent, the update is aborted. With the -c/--check option, the
4213 parent, the update is aborted. With the -c/--check option, the
4214 working directory is checked for uncommitted changes; if none are
4214 working directory is checked for uncommitted changes; if none are
4215 found, the working directory is updated to the specified
4215 found, the working directory is updated to the specified
4216 changeset.
4216 changeset.
4217
4217
4218 The following rules apply when the working directory contains
4218 The following rules apply when the working directory contains
4219 uncommitted changes:
4219 uncommitted changes:
4220
4220
4221 1. If neither -c/--check nor -C/--clean is specified, and if
4221 1. If neither -c/--check nor -C/--clean is specified, and if
4222 the requested changeset is an ancestor or descendant of
4222 the requested changeset is an ancestor or descendant of
4223 the working directory's parent, the uncommitted changes
4223 the working directory's parent, the uncommitted changes
4224 are merged into the requested changeset and the merged
4224 are merged into the requested changeset and the merged
4225 result is left uncommitted. If the requested changeset is
4225 result is left uncommitted. If the requested changeset is
4226 not an ancestor or descendant (that is, it is on another
4226 not an ancestor or descendant (that is, it is on another
4227 branch), the update is aborted and the uncommitted changes
4227 branch), the update is aborted and the uncommitted changes
4228 are preserved.
4228 are preserved.
4229
4229
4230 2. With the -c/--check option, the update is aborted and the
4230 2. With the -c/--check option, the update is aborted and the
4231 uncommitted changes are preserved.
4231 uncommitted changes are preserved.
4232
4232
4233 3. With the -C/--clean option, uncommitted changes are discarded and
4233 3. With the -C/--clean option, uncommitted changes are discarded and
4234 the working directory is updated to the requested changeset.
4234 the working directory is updated to the requested changeset.
4235
4235
4236 Use null as the changeset to remove the working directory (like
4236 Use null as the changeset to remove the working directory (like
4237 :hg:`clone -U`).
4237 :hg:`clone -U`).
4238
4238
4239 If you want to update just one file to an older changeset, use
4239 If you want to update just one file to an older changeset, use
4240 :hg:`revert`.
4240 :hg:`revert`.
4241
4241
4242 See :hg:`help dates` for a list of formats valid for -d/--date.
4242 See :hg:`help dates` for a list of formats valid for -d/--date.
4243
4243
4244 Returns 0 on success, 1 if there are unresolved files.
4244 Returns 0 on success, 1 if there are unresolved files.
4245 """
4245 """
4246 if rev and node:
4246 if rev and node:
4247 raise util.Abort(_("please specify just one revision"))
4247 raise util.Abort(_("please specify just one revision"))
4248
4248
4249 if rev is None or rev == '':
4249 if rev is None or rev == '':
4250 rev = node
4250 rev = node
4251
4251
4252 # if we defined a bookmark, we have to remember the original bookmark name
4252 # if we defined a bookmark, we have to remember the original bookmark name
4253 brev = rev
4253 brev = rev
4254 rev = cmdutil.revsingle(repo, rev, rev).rev()
4254 rev = cmdutil.revsingle(repo, rev, rev).rev()
4255
4255
4256 if check and clean:
4256 if check and clean:
4257 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4257 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4258
4258
4259 if check:
4259 if check:
4260 # we could use dirty() but we can ignore merge and branch trivia
4260 # we could use dirty() but we can ignore merge and branch trivia
4261 c = repo[None]
4261 c = repo[None]
4262 if c.modified() or c.added() or c.removed():
4262 if c.modified() or c.added() or c.removed():
4263 raise util.Abort(_("uncommitted local changes"))
4263 raise util.Abort(_("uncommitted local changes"))
4264
4264
4265 if date:
4265 if date:
4266 if rev is not None:
4266 if rev is not None:
4267 raise util.Abort(_("you can't specify a revision and a date"))
4267 raise util.Abort(_("you can't specify a revision and a date"))
4268 rev = cmdutil.finddate(ui, repo, date)
4268 rev = cmdutil.finddate(ui, repo, date)
4269
4269
4270 if clean or check:
4270 if clean or check:
4271 ret = hg.clean(repo, rev)
4271 ret = hg.clean(repo, rev)
4272 else:
4272 else:
4273 ret = hg.update(repo, rev)
4273 ret = hg.update(repo, rev)
4274
4274
4275 if brev in repo._bookmarks:
4275 if brev in repo._bookmarks:
4276 bookmarks.setcurrent(repo, brev)
4276 bookmarks.setcurrent(repo, brev)
4277
4277
4278 return ret
4278 return ret
4279
4279
4280 def verify(ui, repo):
4280 def verify(ui, repo):
4281 """verify the integrity of the repository
4281 """verify the integrity of the repository
4282
4282
4283 Verify the integrity of the current repository.
4283 Verify the integrity of the current repository.
4284
4284
4285 This will perform an extensive check of the repository's
4285 This will perform an extensive check of the repository's
4286 integrity, validating the hashes and checksums of each entry in
4286 integrity, validating the hashes and checksums of each entry in
4287 the changelog, manifest, and tracked files, as well as the
4287 the changelog, manifest, and tracked files, as well as the
4288 integrity of their crosslinks and indices.
4288 integrity of their crosslinks and indices.
4289
4289
4290 Returns 0 on success, 1 if errors are encountered.
4290 Returns 0 on success, 1 if errors are encountered.
4291 """
4291 """
4292 return hg.verify(repo)
4292 return hg.verify(repo)
4293
4293
4294 def version_(ui):
4294 def version_(ui):
4295 """output version and copyright information"""
4295 """output version and copyright information"""
4296 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4296 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4297 % util.version())
4297 % util.version())
4298 ui.status(_(
4298 ui.status(_(
4299 "(see http://mercurial.selenic.com for more information)\n"
4299 "(see http://mercurial.selenic.com for more information)\n"
4300 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4300 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4301 "This is free software; see the source for copying conditions. "
4301 "This is free software; see the source for copying conditions. "
4302 "There is NO\nwarranty; "
4302 "There is NO\nwarranty; "
4303 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4303 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4304 ))
4304 ))
4305
4305
4306 # Command options and aliases are listed here, alphabetically
4306 # Command options and aliases are listed here, alphabetically
4307
4307
4308 globalopts = [
4308 globalopts = [
4309 ('R', 'repository', '',
4309 ('R', 'repository', '',
4310 _('repository root directory or name of overlay bundle file'),
4310 _('repository root directory or name of overlay bundle file'),
4311 _('REPO')),
4311 _('REPO')),
4312 ('', 'cwd', '',
4312 ('', 'cwd', '',
4313 _('change working directory'), _('DIR')),
4313 _('change working directory'), _('DIR')),
4314 ('y', 'noninteractive', None,
4314 ('y', 'noninteractive', None,
4315 _('do not prompt, assume \'yes\' for any required answers')),
4315 _('do not prompt, assume \'yes\' for any required answers')),
4316 ('q', 'quiet', None, _('suppress output')),
4316 ('q', 'quiet', None, _('suppress output')),
4317 ('v', 'verbose', None, _('enable additional output')),
4317 ('v', 'verbose', None, _('enable additional output')),
4318 ('', 'config', [],
4318 ('', 'config', [],
4319 _('set/override config option (use \'section.name=value\')'),
4319 _('set/override config option (use \'section.name=value\')'),
4320 _('CONFIG')),
4320 _('CONFIG')),
4321 ('', 'debug', None, _('enable debugging output')),
4321 ('', 'debug', None, _('enable debugging output')),
4322 ('', 'debugger', None, _('start debugger')),
4322 ('', 'debugger', None, _('start debugger')),
4323 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4323 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4324 _('ENCODE')),
4324 _('ENCODE')),
4325 ('', 'encodingmode', encoding.encodingmode,
4325 ('', 'encodingmode', encoding.encodingmode,
4326 _('set the charset encoding mode'), _('MODE')),
4326 _('set the charset encoding mode'), _('MODE')),
4327 ('', 'traceback', None, _('always print a traceback on exception')),
4327 ('', 'traceback', None, _('always print a traceback on exception')),
4328 ('', 'time', None, _('time how long the command takes')),
4328 ('', 'time', None, _('time how long the command takes')),
4329 ('', 'profile', None, _('print command execution profile')),
4329 ('', 'profile', None, _('print command execution profile')),
4330 ('', 'version', None, _('output version information and exit')),
4330 ('', 'version', None, _('output version information and exit')),
4331 ('h', 'help', None, _('display help and exit')),
4331 ('h', 'help', None, _('display help and exit')),
4332 ]
4332 ]
4333
4333
4334 dryrunopts = [('n', 'dry-run', None,
4334 dryrunopts = [('n', 'dry-run', None,
4335 _('do not perform actions, just print output'))]
4335 _('do not perform actions, just print output'))]
4336
4336
4337 remoteopts = [
4337 remoteopts = [
4338 ('e', 'ssh', '',
4338 ('e', 'ssh', '',
4339 _('specify ssh command to use'), _('CMD')),
4339 _('specify ssh command to use'), _('CMD')),
4340 ('', 'remotecmd', '',
4340 ('', 'remotecmd', '',
4341 _('specify hg command to run on the remote side'), _('CMD')),
4341 _('specify hg command to run on the remote side'), _('CMD')),
4342 ('', 'insecure', None,
4342 ('', 'insecure', None,
4343 _('do not verify server certificate (ignoring web.cacerts config)')),
4343 _('do not verify server certificate (ignoring web.cacerts config)')),
4344 ]
4344 ]
4345
4345
4346 walkopts = [
4346 walkopts = [
4347 ('I', 'include', [],
4347 ('I', 'include', [],
4348 _('include names matching the given patterns'), _('PATTERN')),
4348 _('include names matching the given patterns'), _('PATTERN')),
4349 ('X', 'exclude', [],
4349 ('X', 'exclude', [],
4350 _('exclude names matching the given patterns'), _('PATTERN')),
4350 _('exclude names matching the given patterns'), _('PATTERN')),
4351 ]
4351 ]
4352
4352
4353 commitopts = [
4353 commitopts = [
4354 ('m', 'message', '',
4354 ('m', 'message', '',
4355 _('use text as commit message'), _('TEXT')),
4355 _('use text as commit message'), _('TEXT')),
4356 ('l', 'logfile', '',
4356 ('l', 'logfile', '',
4357 _('read commit message from file'), _('FILE')),
4357 _('read commit message from file'), _('FILE')),
4358 ]
4358 ]
4359
4359
4360 commitopts2 = [
4360 commitopts2 = [
4361 ('d', 'date', '',
4361 ('d', 'date', '',
4362 _('record the specified date as commit date'), _('DATE')),
4362 _('record the specified date as commit date'), _('DATE')),
4363 ('u', 'user', '',
4363 ('u', 'user', '',
4364 _('record the specified user as committer'), _('USER')),
4364 _('record the specified user as committer'), _('USER')),
4365 ]
4365 ]
4366
4366
4367 templateopts = [
4367 templateopts = [
4368 ('', 'style', '',
4368 ('', 'style', '',
4369 _('display using template map file'), _('STYLE')),
4369 _('display using template map file'), _('STYLE')),
4370 ('', 'template', '',
4370 ('', 'template', '',
4371 _('display with template'), _('TEMPLATE')),
4371 _('display with template'), _('TEMPLATE')),
4372 ]
4372 ]
4373
4373
4374 logopts = [
4374 logopts = [
4375 ('p', 'patch', None, _('show patch')),
4375 ('p', 'patch', None, _('show patch')),
4376 ('g', 'git', None, _('use git extended diff format')),
4376 ('g', 'git', None, _('use git extended diff format')),
4377 ('l', 'limit', '',
4377 ('l', 'limit', '',
4378 _('limit number of changes displayed'), _('NUM')),
4378 _('limit number of changes displayed'), _('NUM')),
4379 ('M', 'no-merges', None, _('do not show merges')),
4379 ('M', 'no-merges', None, _('do not show merges')),
4380 ('', 'stat', None, _('output diffstat-style summary of changes')),
4380 ('', 'stat', None, _('output diffstat-style summary of changes')),
4381 ] + templateopts
4381 ] + templateopts
4382
4382
4383 diffopts = [
4383 diffopts = [
4384 ('a', 'text', None, _('treat all files as text')),
4384 ('a', 'text', None, _('treat all files as text')),
4385 ('g', 'git', None, _('use git extended diff format')),
4385 ('g', 'git', None, _('use git extended diff format')),
4386 ('', 'nodates', None, _('omit dates from diff headers'))
4386 ('', 'nodates', None, _('omit dates from diff headers'))
4387 ]
4387 ]
4388
4388
4389 diffopts2 = [
4389 diffopts2 = [
4390 ('p', 'show-function', None, _('show which function each change is in')),
4390 ('p', 'show-function', None, _('show which function each change is in')),
4391 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4391 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4392 ('w', 'ignore-all-space', None,
4392 ('w', 'ignore-all-space', None,
4393 _('ignore white space when comparing lines')),
4393 _('ignore white space when comparing lines')),
4394 ('b', 'ignore-space-change', None,
4394 ('b', 'ignore-space-change', None,
4395 _('ignore changes in the amount of white space')),
4395 _('ignore changes in the amount of white space')),
4396 ('B', 'ignore-blank-lines', None,
4396 ('B', 'ignore-blank-lines', None,
4397 _('ignore changes whose lines are all blank')),
4397 _('ignore changes whose lines are all blank')),
4398 ('U', 'unified', '',
4398 ('U', 'unified', '',
4399 _('number of lines of context to show'), _('NUM')),
4399 _('number of lines of context to show'), _('NUM')),
4400 ('', 'stat', None, _('output diffstat-style summary of changes')),
4400 ('', 'stat', None, _('output diffstat-style summary of changes')),
4401 ]
4401 ]
4402
4402
4403 similarityopts = [
4403 similarityopts = [
4404 ('s', 'similarity', '',
4404 ('s', 'similarity', '',
4405 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4405 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4406 ]
4406 ]
4407
4407
4408 subrepoopts = [
4408 subrepoopts = [
4409 ('S', 'subrepos', None,
4409 ('S', 'subrepos', None,
4410 _('recurse into subrepositories'))
4410 _('recurse into subrepositories'))
4411 ]
4411 ]
4412
4412
4413 table = {
4413 table = {
4414 "^add": (add, walkopts + subrepoopts + dryrunopts,
4414 "^add": (add, walkopts + subrepoopts + dryrunopts,
4415 _('[OPTION]... [FILE]...')),
4415 _('[OPTION]... [FILE]...')),
4416 "addremove":
4416 "addremove":
4417 (addremove, similarityopts + walkopts + dryrunopts,
4417 (addremove, similarityopts + walkopts + dryrunopts,
4418 _('[OPTION]... [FILE]...')),
4418 _('[OPTION]... [FILE]...')),
4419 "^annotate|blame":
4419 "^annotate|blame":
4420 (annotate,
4420 (annotate,
4421 [('r', 'rev', '',
4421 [('r', 'rev', '',
4422 _('annotate the specified revision'), _('REV')),
4422 _('annotate the specified revision'), _('REV')),
4423 ('', 'follow', None,
4423 ('', 'follow', None,
4424 _('follow copies/renames and list the filename (DEPRECATED)')),
4424 _('follow copies/renames and list the filename (DEPRECATED)')),
4425 ('', 'no-follow', None, _("don't follow copies and renames")),
4425 ('', 'no-follow', None, _("don't follow copies and renames")),
4426 ('a', 'text', None, _('treat all files as text')),
4426 ('a', 'text', None, _('treat all files as text')),
4427 ('u', 'user', None, _('list the author (long with -v)')),
4427 ('u', 'user', None, _('list the author (long with -v)')),
4428 ('f', 'file', None, _('list the filename')),
4428 ('f', 'file', None, _('list the filename')),
4429 ('d', 'date', None, _('list the date (short with -q)')),
4429 ('d', 'date', None, _('list the date (short with -q)')),
4430 ('n', 'number', None, _('list the revision number (default)')),
4430 ('n', 'number', None, _('list the revision number (default)')),
4431 ('c', 'changeset', None, _('list the changeset')),
4431 ('c', 'changeset', None, _('list the changeset')),
4432 ('l', 'line-number', None,
4432 ('l', 'line-number', None,
4433 _('show line number at the first appearance'))
4433 _('show line number at the first appearance'))
4434 ] + walkopts,
4434 ] + walkopts,
4435 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4435 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4436 "archive":
4436 "archive":
4437 (archive,
4437 (archive,
4438 [('', 'no-decode', None, _('do not pass files through decoders')),
4438 [('', 'no-decode', None, _('do not pass files through decoders')),
4439 ('p', 'prefix', '',
4439 ('p', 'prefix', '',
4440 _('directory prefix for files in archive'), _('PREFIX')),
4440 _('directory prefix for files in archive'), _('PREFIX')),
4441 ('r', 'rev', '',
4441 ('r', 'rev', '',
4442 _('revision to distribute'), _('REV')),
4442 _('revision to distribute'), _('REV')),
4443 ('t', 'type', '',
4443 ('t', 'type', '',
4444 _('type of distribution to create'), _('TYPE')),
4444 _('type of distribution to create'), _('TYPE')),
4445 ] + subrepoopts + walkopts,
4445 ] + subrepoopts + walkopts,
4446 _('[OPTION]... DEST')),
4446 _('[OPTION]... DEST')),
4447 "backout":
4447 "backout":
4448 (backout,
4448 (backout,
4449 [('', 'merge', None,
4449 [('', 'merge', None,
4450 _('merge with old dirstate parent after backout')),
4450 _('merge with old dirstate parent after backout')),
4451 ('', 'parent', '',
4451 ('', 'parent', '',
4452 _('parent to choose when backing out merge'), _('REV')),
4452 _('parent to choose when backing out merge'), _('REV')),
4453 ('t', 'tool', '',
4453 ('t', 'tool', '',
4454 _('specify merge tool')),
4454 _('specify merge tool')),
4455 ('r', 'rev', '',
4455 ('r', 'rev', '',
4456 _('revision to backout'), _('REV')),
4456 _('revision to backout'), _('REV')),
4457 ] + walkopts + commitopts + commitopts2,
4457 ] + walkopts + commitopts + commitopts2,
4458 _('[OPTION]... [-r] REV')),
4458 _('[OPTION]... [-r] REV')),
4459 "bisect":
4459 "bisect":
4460 (bisect,
4460 (bisect,
4461 [('r', 'reset', False, _('reset bisect state')),
4461 [('r', 'reset', False, _('reset bisect state')),
4462 ('g', 'good', False, _('mark changeset good')),
4462 ('g', 'good', False, _('mark changeset good')),
4463 ('b', 'bad', False, _('mark changeset bad')),
4463 ('b', 'bad', False, _('mark changeset bad')),
4464 ('s', 'skip', False, _('skip testing changeset')),
4464 ('s', 'skip', False, _('skip testing changeset')),
4465 ('e', 'extend', False, _('extend the bisect range')),
4465 ('e', 'extend', False, _('extend the bisect range')),
4466 ('c', 'command', '',
4466 ('c', 'command', '',
4467 _('use command to check changeset state'), _('CMD')),
4467 _('use command to check changeset state'), _('CMD')),
4468 ('U', 'noupdate', False, _('do not update to target'))],
4468 ('U', 'noupdate', False, _('do not update to target'))],
4469 _("[-gbsr] [-U] [-c CMD] [REV]")),
4469 _("[-gbsr] [-U] [-c CMD] [REV]")),
4470 "bookmarks":
4470 "bookmarks":
4471 (bookmark,
4471 (bookmark,
4472 [('f', 'force', False, _('force')),
4472 [('f', 'force', False, _('force')),
4473 ('r', 'rev', '', _('revision'), _('REV')),
4473 ('r', 'rev', '', _('revision'), _('REV')),
4474 ('d', 'delete', False, _('delete a given bookmark')),
4474 ('d', 'delete', False, _('delete a given bookmark')),
4475 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
4475 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
4476 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
4476 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
4477 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]')),
4477 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]')),
4478 "branch":
4478 "branch":
4479 (branch,
4479 (branch,
4480 [('f', 'force', None,
4480 [('f', 'force', None,
4481 _('set branch name even if it shadows an existing branch')),
4481 _('set branch name even if it shadows an existing branch')),
4482 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4482 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4483 _('[-fC] [NAME]')),
4483 _('[-fC] [NAME]')),
4484 "branches":
4484 "branches":
4485 (branches,
4485 (branches,
4486 [('a', 'active', False,
4486 [('a', 'active', False,
4487 _('show only branches that have unmerged heads')),
4487 _('show only branches that have unmerged heads')),
4488 ('c', 'closed', False,
4488 ('c', 'closed', False,
4489 _('show normal and closed branches'))],
4489 _('show normal and closed branches'))],
4490 _('[-ac]')),
4490 _('[-ac]')),
4491 "bundle":
4491 "bundle":
4492 (bundle,
4492 (bundle,
4493 [('f', 'force', None,
4493 [('f', 'force', None,
4494 _('run even when the destination is unrelated')),
4494 _('run even when the destination is unrelated')),
4495 ('r', 'rev', [],
4495 ('r', 'rev', [],
4496 _('a changeset intended to be added to the destination'),
4496 _('a changeset intended to be added to the destination'),
4497 _('REV')),
4497 _('REV')),
4498 ('b', 'branch', [],
4498 ('b', 'branch', [],
4499 _('a specific branch you would like to bundle'),
4499 _('a specific branch you would like to bundle'),
4500 _('BRANCH')),
4500 _('BRANCH')),
4501 ('', 'base', [],
4501 ('', 'base', [],
4502 _('a base changeset assumed to be available at the destination'),
4502 _('a base changeset assumed to be available at the destination'),
4503 _('REV')),
4503 _('REV')),
4504 ('a', 'all', None, _('bundle all changesets in the repository')),
4504 ('a', 'all', None, _('bundle all changesets in the repository')),
4505 ('t', 'type', 'bzip2',
4505 ('t', 'type', 'bzip2',
4506 _('bundle compression type to use'), _('TYPE')),
4506 _('bundle compression type to use'), _('TYPE')),
4507 ] + remoteopts,
4507 ] + remoteopts,
4508 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4508 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4509 "cat":
4509 "cat":
4510 (cat,
4510 (cat,
4511 [('o', 'output', '',
4511 [('o', 'output', '',
4512 _('print output to file with formatted name'), _('FORMAT')),
4512 _('print output to file with formatted name'), _('FORMAT')),
4513 ('r', 'rev', '',
4513 ('r', 'rev', '',
4514 _('print the given revision'), _('REV')),
4514 _('print the given revision'), _('REV')),
4515 ('', 'decode', None, _('apply any matching decode filter')),
4515 ('', 'decode', None, _('apply any matching decode filter')),
4516 ] + walkopts,
4516 ] + walkopts,
4517 _('[OPTION]... FILE...')),
4517 _('[OPTION]... FILE...')),
4518 "^clone":
4518 "^clone":
4519 (clone,
4519 (clone,
4520 [('U', 'noupdate', None,
4520 [('U', 'noupdate', None,
4521 _('the clone will include an empty working copy (only a repository)')),
4521 _('the clone will include an empty working copy (only a repository)')),
4522 ('u', 'updaterev', '',
4522 ('u', 'updaterev', '',
4523 _('revision, tag or branch to check out'), _('REV')),
4523 _('revision, tag or branch to check out'), _('REV')),
4524 ('r', 'rev', [],
4524 ('r', 'rev', [],
4525 _('include the specified changeset'), _('REV')),
4525 _('include the specified changeset'), _('REV')),
4526 ('b', 'branch', [],
4526 ('b', 'branch', [],
4527 _('clone only the specified branch'), _('BRANCH')),
4527 _('clone only the specified branch'), _('BRANCH')),
4528 ('', 'pull', None, _('use pull protocol to copy metadata')),
4528 ('', 'pull', None, _('use pull protocol to copy metadata')),
4529 ('', 'uncompressed', None,
4529 ('', 'uncompressed', None,
4530 _('use uncompressed transfer (fast over LAN)')),
4530 _('use uncompressed transfer (fast over LAN)')),
4531 ] + remoteopts,
4531 ] + remoteopts,
4532 _('[OPTION]... SOURCE [DEST]')),
4532 _('[OPTION]... SOURCE [DEST]')),
4533 "^commit|ci":
4533 "^commit|ci":
4534 (commit,
4534 (commit,
4535 [('A', 'addremove', None,
4535 [('A', 'addremove', None,
4536 _('mark new/missing files as added/removed before committing')),
4536 _('mark new/missing files as added/removed before committing')),
4537 ('', 'close-branch', None,
4537 ('', 'close-branch', None,
4538 _('mark a branch as closed, hiding it from the branch list')),
4538 _('mark a branch as closed, hiding it from the branch list')),
4539 ] + walkopts + commitopts + commitopts2,
4539 ] + walkopts + commitopts + commitopts2,
4540 _('[OPTION]... [FILE]...')),
4540 _('[OPTION]... [FILE]...')),
4541 "copy|cp":
4541 "copy|cp":
4542 (copy,
4542 (copy,
4543 [('A', 'after', None, _('record a copy that has already occurred')),
4543 [('A', 'after', None, _('record a copy that has already occurred')),
4544 ('f', 'force', None,
4544 ('f', 'force', None,
4545 _('forcibly copy over an existing managed file')),
4545 _('forcibly copy over an existing managed file')),
4546 ] + walkopts + dryrunopts,
4546 ] + walkopts + dryrunopts,
4547 _('[OPTION]... [SOURCE]... DEST')),
4547 _('[OPTION]... [SOURCE]... DEST')),
4548 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4548 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4549 "debugbuilddag":
4549 "debugbuilddag":
4550 (debugbuilddag,
4550 (debugbuilddag,
4551 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4551 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4552 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4552 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4553 ('n', 'new-file', None, _('add new file at each rev')),
4553 ('n', 'new-file', None, _('add new file at each rev')),
4554 ],
4554 ],
4555 _('[OPTION]... TEXT')),
4555 _('[OPTION]... TEXT')),
4556 "debugbundle":
4556 "debugbundle":
4557 (debugbundle,
4557 (debugbundle,
4558 [('a', 'all', None, _('show all details')),
4558 [('a', 'all', None, _('show all details')),
4559 ],
4559 ],
4560 _('FILE')),
4560 _('FILE')),
4561 "debugcheckstate": (debugcheckstate, [], ''),
4561 "debugcheckstate": (debugcheckstate, [], ''),
4562 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4562 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4563 "debugcomplete":
4563 "debugcomplete":
4564 (debugcomplete,
4564 (debugcomplete,
4565 [('o', 'options', None, _('show the command options'))],
4565 [('o', 'options', None, _('show the command options'))],
4566 _('[-o] CMD')),
4566 _('[-o] CMD')),
4567 "debugdag":
4567 "debugdag":
4568 (debugdag,
4568 (debugdag,
4569 [('t', 'tags', None, _('use tags as labels')),
4569 [('t', 'tags', None, _('use tags as labels')),
4570 ('b', 'branches', None, _('annotate with branch names')),
4570 ('b', 'branches', None, _('annotate with branch names')),
4571 ('', 'dots', None, _('use dots for runs')),
4571 ('', 'dots', None, _('use dots for runs')),
4572 ('s', 'spaces', None, _('separate elements by spaces')),
4572 ('s', 'spaces', None, _('separate elements by spaces')),
4573 ],
4573 ],
4574 _('[OPTION]... [FILE [REV]...]')),
4574 _('[OPTION]... [FILE [REV]...]')),
4575 "debugdate":
4575 "debugdate":
4576 (debugdate,
4576 (debugdate,
4577 [('e', 'extended', None, _('try extended date formats'))],
4577 [('e', 'extended', None, _('try extended date formats'))],
4578 _('[-e] DATE [RANGE]')),
4578 _('[-e] DATE [RANGE]')),
4579 "debugdata": (debugdata, [], _('FILE REV')),
4579 "debugdata": (debugdata, [], _('FILE REV')),
4580 "debugdiscovery": (debugdiscovery,
4580 "debugdiscovery": (debugdiscovery,
4581 [('', 'old', None,
4581 [('', 'old', None,
4582 _('use old-style discovery')),
4582 _('use old-style discovery')),
4583 ('', 'nonheads', None,
4583 ('', 'nonheads', None,
4584 _('use old-style discovery with non-heads included')),
4584 _('use old-style discovery with non-heads included')),
4585 ] + remoteopts,
4585 ] + remoteopts,
4586 _('[-l REV] [-r REV] [-b BRANCH]...'
4586 _('[-l REV] [-r REV] [-b BRANCH]...'
4587 ' [OTHER]')),
4587 ' [OTHER]')),
4588 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4588 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4589 "debuggetbundle":
4589 "debuggetbundle":
4590 (debuggetbundle,
4590 (debuggetbundle,
4591 [('H', 'head', [], _('id of head node'), _('ID')),
4591 [('H', 'head', [], _('id of head node'), _('ID')),
4592 ('C', 'common', [], _('id of common node'), _('ID')),
4592 ('C', 'common', [], _('id of common node'), _('ID')),
4593 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4593 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4594 ],
4594 ],
4595 _('REPO FILE [-H|-C ID]...')),
4595 _('REPO FILE [-H|-C ID]...')),
4596 "debugignore": (debugignore, [], ''),
4596 "debugignore": (debugignore, [], ''),
4597 "debugindex": (debugindex,
4597 "debugindex": (debugindex,
4598 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4598 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4599 _('FILE')),
4599 _('FILE')),
4600 "debugindexdot": (debugindexdot, [], _('FILE')),
4600 "debugindexdot": (debugindexdot, [], _('FILE')),
4601 "debuginstall": (debuginstall, [], ''),
4601 "debuginstall": (debuginstall, [], ''),
4602 "debugknown": (debugknown, [], _('REPO ID...')),
4602 "debugknown": (debugknown, [], _('REPO ID...')),
4603 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4603 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4604 "debugrebuildstate":
4604 "debugrebuildstate":
4605 (debugrebuildstate,
4605 (debugrebuildstate,
4606 [('r', 'rev', '',
4606 [('r', 'rev', '',
4607 _('revision to rebuild to'), _('REV'))],
4607 _('revision to rebuild to'), _('REV'))],
4608 _('[-r REV] [REV]')),
4608 _('[-r REV] [REV]')),
4609 "debugrename":
4609 "debugrename":
4610 (debugrename,
4610 (debugrename,
4611 [('r', 'rev', '',
4611 [('r', 'rev', '',
4612 _('revision to debug'), _('REV'))],
4612 _('revision to debug'), _('REV'))],
4613 _('[-r REV] FILE')),
4613 _('[-r REV] FILE')),
4614 "debugrevspec":
4614 "debugrevspec":
4615 (debugrevspec, [], ('REVSPEC')),
4615 (debugrevspec, [], ('REVSPEC')),
4616 "debugsetparents":
4616 "debugsetparents":
4617 (debugsetparents, [], _('REV1 [REV2]')),
4617 (debugsetparents, [], _('REV1 [REV2]')),
4618 "debugstate":
4618 "debugstate":
4619 (debugstate,
4619 (debugstate,
4620 [('', 'nodates', None, _('do not display the saved mtime')),
4620 [('', 'nodates', None, _('do not display the saved mtime')),
4621 ('', 'datesort', None, _('sort by saved mtime'))],
4621 ('', 'datesort', None, _('sort by saved mtime'))],
4622 _('[OPTION]...')),
4622 _('[OPTION]...')),
4623 "debugsub":
4623 "debugsub":
4624 (debugsub,
4624 (debugsub,
4625 [('r', 'rev', '',
4625 [('r', 'rev', '',
4626 _('revision to check'), _('REV'))],
4626 _('revision to check'), _('REV'))],
4627 _('[-r REV] [REV]')),
4627 _('[-r REV] [REV]')),
4628 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4628 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4629 "debugwireargs":
4629 "debugwireargs":
4630 (debugwireargs,
4630 (debugwireargs,
4631 [('', 'three', '', 'three'),
4631 [('', 'three', '', 'three'),
4632 ('', 'four', '', 'four'),
4632 ('', 'four', '', 'four'),
4633 ('', 'five', '', 'five'),
4633 ('', 'five', '', 'five'),
4634 ] + remoteopts,
4634 ] + remoteopts,
4635 _('REPO [OPTIONS]... [ONE [TWO]]')),
4635 _('REPO [OPTIONS]... [ONE [TWO]]')),
4636 "^diff":
4636 "^diff":
4637 (diff,
4637 (diff,
4638 [('r', 'rev', [],
4638 [('r', 'rev', [],
4639 _('revision'), _('REV')),
4639 _('revision'), _('REV')),
4640 ('c', 'change', '',
4640 ('c', 'change', '',
4641 _('change made by revision'), _('REV'))
4641 _('change made by revision'), _('REV'))
4642 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4642 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4643 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4643 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4644 "^export":
4644 "^export":
4645 (export,
4645 (export,
4646 [('o', 'output', '',
4646 [('o', 'output', '',
4647 _('print output to file with formatted name'), _('FORMAT')),
4647 _('print output to file with formatted name'), _('FORMAT')),
4648 ('', 'switch-parent', None, _('diff against the second parent')),
4648 ('', 'switch-parent', None, _('diff against the second parent')),
4649 ('r', 'rev', [],
4649 ('r', 'rev', [],
4650 _('revisions to export'), _('REV')),
4650 _('revisions to export'), _('REV')),
4651 ] + diffopts,
4651 ] + diffopts,
4652 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4652 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4653 "^forget":
4653 "^forget":
4654 (forget,
4654 (forget,
4655 [] + walkopts,
4655 [] + walkopts,
4656 _('[OPTION]... FILE...')),
4656 _('[OPTION]... FILE...')),
4657 "grep":
4657 "grep":
4658 (grep,
4658 (grep,
4659 [('0', 'print0', None, _('end fields with NUL')),
4659 [('0', 'print0', None, _('end fields with NUL')),
4660 ('', 'all', None, _('print all revisions that match')),
4660 ('', 'all', None, _('print all revisions that match')),
4661 ('a', 'text', None, _('treat all files as text')),
4661 ('a', 'text', None, _('treat all files as text')),
4662 ('f', 'follow', None,
4662 ('f', 'follow', None,
4663 _('follow changeset history,'
4663 _('follow changeset history,'
4664 ' or file history across copies and renames')),
4664 ' or file history across copies and renames')),
4665 ('i', 'ignore-case', None, _('ignore case when matching')),
4665 ('i', 'ignore-case', None, _('ignore case when matching')),
4666 ('l', 'files-with-matches', None,
4666 ('l', 'files-with-matches', None,
4667 _('print only filenames and revisions that match')),
4667 _('print only filenames and revisions that match')),
4668 ('n', 'line-number', None, _('print matching line numbers')),
4668 ('n', 'line-number', None, _('print matching line numbers')),
4669 ('r', 'rev', [],
4669 ('r', 'rev', [],
4670 _('only search files changed within revision range'), _('REV')),
4670 _('only search files changed within revision range'), _('REV')),
4671 ('u', 'user', None, _('list the author (long with -v)')),
4671 ('u', 'user', None, _('list the author (long with -v)')),
4672 ('d', 'date', None, _('list the date (short with -q)')),
4672 ('d', 'date', None, _('list the date (short with -q)')),
4673 ] + walkopts,
4673 ] + walkopts,
4674 _('[OPTION]... PATTERN [FILE]...')),
4674 _('[OPTION]... PATTERN [FILE]...')),
4675 "heads":
4675 "heads":
4676 (heads,
4676 (heads,
4677 [('r', 'rev', '',
4677 [('r', 'rev', '',
4678 _('show only heads which are descendants of STARTREV'),
4678 _('show only heads which are descendants of STARTREV'),
4679 _('STARTREV')),
4679 _('STARTREV')),
4680 ('t', 'topo', False, _('show topological heads only')),
4680 ('t', 'topo', False, _('show topological heads only')),
4681 ('a', 'active', False,
4681 ('a', 'active', False,
4682 _('show active branchheads only (DEPRECATED)')),
4682 _('show active branchheads only (DEPRECATED)')),
4683 ('c', 'closed', False,
4683 ('c', 'closed', False,
4684 _('show normal and closed branch heads')),
4684 _('show normal and closed branch heads')),
4685 ] + templateopts,
4685 ] + templateopts,
4686 _('[-ac] [-r STARTREV] [REV]...')),
4686 _('[-ac] [-r STARTREV] [REV]...')),
4687 "help": (help_, [], _('[TOPIC]')),
4687 "help": (help_, [], _('[TOPIC]')),
4688 "identify|id":
4688 "identify|id":
4689 (identify,
4689 (identify,
4690 [('r', 'rev', '',
4690 [('r', 'rev', '',
4691 _('identify the specified revision'), _('REV')),
4691 _('identify the specified revision'), _('REV')),
4692 ('n', 'num', None, _('show local revision number')),
4692 ('n', 'num', None, _('show local revision number')),
4693 ('i', 'id', None, _('show global revision id')),
4693 ('i', 'id', None, _('show global revision id')),
4694 ('b', 'branch', None, _('show branch')),
4694 ('b', 'branch', None, _('show branch')),
4695 ('t', 'tags', None, _('show tags')),
4695 ('t', 'tags', None, _('show tags')),
4696 ('B', 'bookmarks', None, _('show bookmarks'))],
4696 ('B', 'bookmarks', None, _('show bookmarks'))],
4697 _('[-nibtB] [-r REV] [SOURCE]')),
4697 _('[-nibtB] [-r REV] [SOURCE]')),
4698 "import|patch":
4698 "import|patch":
4699 (import_,
4699 (import_,
4700 [('p', 'strip', 1,
4700 [('p', 'strip', 1,
4701 _('directory strip option for patch. This has the same '
4701 _('directory strip option for patch. This has the same '
4702 'meaning as the corresponding patch option'),
4702 'meaning as the corresponding patch option'),
4703 _('NUM')),
4703 _('NUM')),
4704 ('b', 'base', '',
4704 ('b', 'base', '',
4705 _('base path'), _('PATH')),
4705 _('base path'), _('PATH')),
4706 ('f', 'force', None,
4706 ('f', 'force', None,
4707 _('skip check for outstanding uncommitted changes')),
4707 _('skip check for outstanding uncommitted changes')),
4708 ('', 'no-commit', None,
4708 ('', 'no-commit', None,
4709 _("don't commit, just update the working directory")),
4709 _("don't commit, just update the working directory")),
4710 ('', 'exact', None,
4710 ('', 'exact', None,
4711 _('apply patch to the nodes from which it was generated')),
4711 _('apply patch to the nodes from which it was generated')),
4712 ('', 'import-branch', None,
4712 ('', 'import-branch', None,
4713 _('use any branch information in patch (implied by --exact)'))] +
4713 _('use any branch information in patch (implied by --exact)'))] +
4714 commitopts + commitopts2 + similarityopts,
4714 commitopts + commitopts2 + similarityopts,
4715 _('[OPTION]... PATCH...')),
4715 _('[OPTION]... PATCH...')),
4716 "incoming|in":
4716 "incoming|in":
4717 (incoming,
4717 (incoming,
4718 [('f', 'force', None,
4718 [('f', 'force', None,
4719 _('run even if remote repository is unrelated')),
4719 _('run even if remote repository is unrelated')),
4720 ('n', 'newest-first', None, _('show newest record first')),
4720 ('n', 'newest-first', None, _('show newest record first')),
4721 ('', 'bundle', '',
4721 ('', 'bundle', '',
4722 _('file to store the bundles into'), _('FILE')),
4722 _('file to store the bundles into'), _('FILE')),
4723 ('r', 'rev', [],
4723 ('r', 'rev', [],
4724 _('a remote changeset intended to be added'), _('REV')),
4724 _('a remote changeset intended to be added'), _('REV')),
4725 ('B', 'bookmarks', False, _("compare bookmarks")),
4725 ('B', 'bookmarks', False, _("compare bookmarks")),
4726 ('b', 'branch', [],
4726 ('b', 'branch', [],
4727 _('a specific branch you would like to pull'), _('BRANCH')),
4727 _('a specific branch you would like to pull'), _('BRANCH')),
4728 ] + logopts + remoteopts + subrepoopts,
4728 ] + logopts + remoteopts + subrepoopts,
4729 _('[-p] [-n] [-M] [-f] [-r REV]...'
4729 _('[-p] [-n] [-M] [-f] [-r REV]...'
4730 ' [--bundle FILENAME] [SOURCE]')),
4730 ' [--bundle FILENAME] [SOURCE]')),
4731 "^init":
4731 "^init":
4732 (init,
4732 (init,
4733 remoteopts,
4733 remoteopts,
4734 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4734 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4735 "locate":
4735 "locate":
4736 (locate,
4736 (locate,
4737 [('r', 'rev', '',
4737 [('r', 'rev', '',
4738 _('search the repository as it is in REV'), _('REV')),
4738 _('search the repository as it is in REV'), _('REV')),
4739 ('0', 'print0', None,
4739 ('0', 'print0', None,
4740 _('end filenames with NUL, for use with xargs')),
4740 _('end filenames with NUL, for use with xargs')),
4741 ('f', 'fullpath', None,
4741 ('f', 'fullpath', None,
4742 _('print complete paths from the filesystem root')),
4742 _('print complete paths from the filesystem root')),
4743 ] + walkopts,
4743 ] + walkopts,
4744 _('[OPTION]... [PATTERN]...')),
4744 _('[OPTION]... [PATTERN]...')),
4745 "^log|history":
4745 "^log|history":
4746 (log,
4746 (log,
4747 [('f', 'follow', None,
4747 [('f', 'follow', None,
4748 _('follow changeset history,'
4748 _('follow changeset history,'
4749 ' or file history across copies and renames')),
4749 ' or file history across copies and renames')),
4750 ('', 'follow-first', None,
4750 ('', 'follow-first', None,
4751 _('only follow the first parent of merge changesets')),
4751 _('only follow the first parent of merge changesets')),
4752 ('d', 'date', '',
4752 ('d', 'date', '',
4753 _('show revisions matching date spec'), _('DATE')),
4753 _('show revisions matching date spec'), _('DATE')),
4754 ('C', 'copies', None, _('show copied files')),
4754 ('C', 'copies', None, _('show copied files')),
4755 ('k', 'keyword', [],
4755 ('k', 'keyword', [],
4756 _('do case-insensitive search for a given text'), _('TEXT')),
4756 _('do case-insensitive search for a given text'), _('TEXT')),
4757 ('r', 'rev', [],
4757 ('r', 'rev', [],
4758 _('show the specified revision or range'), _('REV')),
4758 _('show the specified revision or range'), _('REV')),
4759 ('', 'removed', None, _('include revisions where files were removed')),
4759 ('', 'removed', None, _('include revisions where files were removed')),
4760 ('m', 'only-merges', None, _('show only merges')),
4760 ('m', 'only-merges', None, _('show only merges')),
4761 ('u', 'user', [],
4761 ('u', 'user', [],
4762 _('revisions committed by user'), _('USER')),
4762 _('revisions committed by user'), _('USER')),
4763 ('', 'only-branch', [],
4763 ('', 'only-branch', [],
4764 _('show only changesets within the given named branch (DEPRECATED)'),
4764 _('show only changesets within the given named branch (DEPRECATED)'),
4765 _('BRANCH')),
4765 _('BRANCH')),
4766 ('b', 'branch', [],
4766 ('b', 'branch', [],
4767 _('show changesets within the given named branch'), _('BRANCH')),
4767 _('show changesets within the given named branch'), _('BRANCH')),
4768 ('P', 'prune', [],
4768 ('P', 'prune', [],
4769 _('do not display revision or any of its ancestors'), _('REV')),
4769 _('do not display revision or any of its ancestors'), _('REV')),
4770 ] + logopts + walkopts,
4770 ] + logopts + walkopts,
4771 _('[OPTION]... [FILE]')),
4771 _('[OPTION]... [FILE]')),
4772 "manifest":
4772 "manifest":
4773 (manifest,
4773 (manifest,
4774 [('r', 'rev', '',
4774 [('r', 'rev', '',
4775 _('revision to display'), _('REV'))],
4775 _('revision to display'), _('REV'))],
4776 _('[-r REV]')),
4776 _('[-r REV]')),
4777 "^merge":
4777 "^merge":
4778 (merge,
4778 (merge,
4779 [('f', 'force', None, _('force a merge with outstanding changes')),
4779 [('f', 'force', None, _('force a merge with outstanding changes')),
4780 ('t', 'tool', '', _('specify merge tool')),
4780 ('t', 'tool', '', _('specify merge tool')),
4781 ('r', 'rev', '',
4781 ('r', 'rev', '',
4782 _('revision to merge'), _('REV')),
4782 _('revision to merge'), _('REV')),
4783 ('P', 'preview', None,
4783 ('P', 'preview', None,
4784 _('review revisions to merge (no merge is performed)'))],
4784 _('review revisions to merge (no merge is performed)'))],
4785 _('[-P] [-f] [[-r] REV]')),
4785 _('[-P] [-f] [[-r] REV]')),
4786 "outgoing|out":
4786 "outgoing|out":
4787 (outgoing,
4787 (outgoing,
4788 [('f', 'force', None,
4788 [('f', 'force', None,
4789 _('run even when the destination is unrelated')),
4789 _('run even when the destination is unrelated')),
4790 ('r', 'rev', [],
4790 ('r', 'rev', [],
4791 _('a changeset intended to be included in the destination'),
4791 _('a changeset intended to be included in the destination'),
4792 _('REV')),
4792 _('REV')),
4793 ('n', 'newest-first', None, _('show newest record first')),
4793 ('n', 'newest-first', None, _('show newest record first')),
4794 ('B', 'bookmarks', False, _("compare bookmarks")),
4794 ('B', 'bookmarks', False, _("compare bookmarks")),
4795 ('b', 'branch', [],
4795 ('b', 'branch', [],
4796 _('a specific branch you would like to push'), _('BRANCH')),
4796 _('a specific branch you would like to push'), _('BRANCH')),
4797 ] + logopts + remoteopts + subrepoopts,
4797 ] + logopts + remoteopts + subrepoopts,
4798 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4798 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4799 "parents":
4799 "parents":
4800 (parents,
4800 (parents,
4801 [('r', 'rev', '',
4801 [('r', 'rev', '',
4802 _('show parents of the specified revision'), _('REV')),
4802 _('show parents of the specified revision'), _('REV')),
4803 ] + templateopts,
4803 ] + templateopts,
4804 _('[-r REV] [FILE]')),
4804 _('[-r REV] [FILE]')),
4805 "paths": (paths, [], _('[NAME]')),
4805 "paths": (paths, [], _('[NAME]')),
4806 "^pull":
4806 "^pull":
4807 (pull,
4807 (pull,
4808 [('u', 'update', None,
4808 [('u', 'update', None,
4809 _('update to new branch head if changesets were pulled')),
4809 _('update to new branch head if changesets were pulled')),
4810 ('f', 'force', None,
4810 ('f', 'force', None,
4811 _('run even when remote repository is unrelated')),
4811 _('run even when remote repository is unrelated')),
4812 ('r', 'rev', [],
4812 ('r', 'rev', [],
4813 _('a remote changeset intended to be added'), _('REV')),
4813 _('a remote changeset intended to be added'), _('REV')),
4814 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4814 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4815 ('b', 'branch', [],
4815 ('b', 'branch', [],
4816 _('a specific branch you would like to pull'), _('BRANCH')),
4816 _('a specific branch you would like to pull'), _('BRANCH')),
4817 ] + remoteopts,
4817 ] + remoteopts,
4818 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4818 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4819 "^push":
4819 "^push":
4820 (push,
4820 (push,
4821 [('f', 'force', None, _('force push')),
4821 [('f', 'force', None, _('force push')),
4822 ('r', 'rev', [],
4822 ('r', 'rev', [],
4823 _('a changeset intended to be included in the destination'),
4823 _('a changeset intended to be included in the destination'),
4824 _('REV')),
4824 _('REV')),
4825 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4825 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4826 ('b', 'branch', [],
4826 ('b', 'branch', [],
4827 _('a specific branch you would like to push'), _('BRANCH')),
4827 _('a specific branch you would like to push'), _('BRANCH')),
4828 ('', 'new-branch', False, _('allow pushing a new branch')),
4828 ('', 'new-branch', False, _('allow pushing a new branch')),
4829 ] + remoteopts,
4829 ] + remoteopts,
4830 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4830 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4831 "recover": (recover, []),
4831 "recover": (recover, []),
4832 "^remove|rm":
4832 "^remove|rm":
4833 (remove,
4833 (remove,
4834 [('A', 'after', None, _('record delete for missing files')),
4834 [('A', 'after', None, _('record delete for missing files')),
4835 ('f', 'force', None,
4835 ('f', 'force', None,
4836 _('remove (and delete) file even if added or modified')),
4836 _('remove (and delete) file even if added or modified')),
4837 ] + walkopts,
4837 ] + walkopts,
4838 _('[OPTION]... FILE...')),
4838 _('[OPTION]... FILE...')),
4839 "rename|move|mv":
4839 "rename|move|mv":
4840 (rename,
4840 (rename,
4841 [('A', 'after', None, _('record a rename that has already occurred')),
4841 [('A', 'after', None, _('record a rename that has already occurred')),
4842 ('f', 'force', None,
4842 ('f', 'force', None,
4843 _('forcibly copy over an existing managed file')),
4843 _('forcibly copy over an existing managed file')),
4844 ] + walkopts + dryrunopts,
4844 ] + walkopts + dryrunopts,
4845 _('[OPTION]... SOURCE... DEST')),
4845 _('[OPTION]... SOURCE... DEST')),
4846 "resolve":
4846 "resolve":
4847 (resolve,
4847 (resolve,
4848 [('a', 'all', None, _('select all unresolved files')),
4848 [('a', 'all', None, _('select all unresolved files')),
4849 ('l', 'list', None, _('list state of files needing merge')),
4849 ('l', 'list', None, _('list state of files needing merge')),
4850 ('m', 'mark', None, _('mark files as resolved')),
4850 ('m', 'mark', None, _('mark files as resolved')),
4851 ('u', 'unmark', None, _('mark files as unresolved')),
4851 ('u', 'unmark', None, _('mark files as unresolved')),
4852 ('t', 'tool', '', _('specify merge tool')),
4852 ('t', 'tool', '', _('specify merge tool')),
4853 ('n', 'no-status', None, _('hide status prefix'))]
4853 ('n', 'no-status', None, _('hide status prefix'))]
4854 + walkopts,
4854 + walkopts,
4855 _('[OPTION]... [FILE]...')),
4855 _('[OPTION]... [FILE]...')),
4856 "revert":
4856 "revert":
4857 (revert,
4857 (revert,
4858 [('a', 'all', None, _('revert all changes when no arguments given')),
4858 [('a', 'all', None, _('revert all changes when no arguments given')),
4859 ('d', 'date', '',
4859 ('d', 'date', '',
4860 _('tipmost revision matching date'), _('DATE')),
4860 _('tipmost revision matching date'), _('DATE')),
4861 ('r', 'rev', '',
4861 ('r', 'rev', '',
4862 _('revert to the specified revision'), _('REV')),
4862 _('revert to the specified revision'), _('REV')),
4863 ('', 'no-backup', None, _('do not save backup copies of files')),
4863 ('', 'no-backup', None, _('do not save backup copies of files')),
4864 ] + walkopts + dryrunopts,
4864 ] + walkopts + dryrunopts,
4865 _('[OPTION]... [-r REV] [NAME]...')),
4865 _('[OPTION]... [-r REV] [NAME]...')),
4866 "rollback": (rollback, dryrunopts),
4866 "rollback": (rollback, dryrunopts),
4867 "root": (root, []),
4867 "root": (root, []),
4868 "^serve":
4868 "^serve":
4869 (serve,
4869 (serve,
4870 [('A', 'accesslog', '',
4870 [('A', 'accesslog', '',
4871 _('name of access log file to write to'), _('FILE')),
4871 _('name of access log file to write to'), _('FILE')),
4872 ('d', 'daemon', None, _('run server in background')),
4872 ('d', 'daemon', None, _('run server in background')),
4873 ('', 'daemon-pipefds', '',
4873 ('', 'daemon-pipefds', '',
4874 _('used internally by daemon mode'), _('NUM')),
4874 _('used internally by daemon mode'), _('NUM')),
4875 ('E', 'errorlog', '',
4875 ('E', 'errorlog', '',
4876 _('name of error log file to write to'), _('FILE')),
4876 _('name of error log file to write to'), _('FILE')),
4877 # use string type, then we can check if something was passed
4877 # use string type, then we can check if something was passed
4878 ('p', 'port', '',
4878 ('p', 'port', '',
4879 _('port to listen on (default: 8000)'), _('PORT')),
4879 _('port to listen on (default: 8000)'), _('PORT')),
4880 ('a', 'address', '',
4880 ('a', 'address', '',
4881 _('address to listen on (default: all interfaces)'), _('ADDR')),
4881 _('address to listen on (default: all interfaces)'), _('ADDR')),
4882 ('', 'prefix', '',
4882 ('', 'prefix', '',
4883 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4883 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4884 ('n', 'name', '',
4884 ('n', 'name', '',
4885 _('name to show in web pages (default: working directory)'),
4885 _('name to show in web pages (default: working directory)'),
4886 _('NAME')),
4886 _('NAME')),
4887 ('', 'web-conf', '',
4887 ('', 'web-conf', '',
4888 _('name of the hgweb config file (see "hg help hgweb")'),
4888 _('name of the hgweb config file (see "hg help hgweb")'),
4889 _('FILE')),
4889 _('FILE')),
4890 ('', 'webdir-conf', '',
4890 ('', 'webdir-conf', '',
4891 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4891 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4892 ('', 'pid-file', '',
4892 ('', 'pid-file', '',
4893 _('name of file to write process ID to'), _('FILE')),
4893 _('name of file to write process ID to'), _('FILE')),
4894 ('', 'stdio', None, _('for remote clients')),
4894 ('', 'stdio', None, _('for remote clients')),
4895 ('t', 'templates', '',
4895 ('t', 'templates', '',
4896 _('web templates to use'), _('TEMPLATE')),
4896 _('web templates to use'), _('TEMPLATE')),
4897 ('', 'style', '',
4897 ('', 'style', '',
4898 _('template style to use'), _('STYLE')),
4898 _('template style to use'), _('STYLE')),
4899 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4899 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4900 ('', 'certificate', '',
4900 ('', 'certificate', '',
4901 _('SSL certificate file'), _('FILE'))],
4901 _('SSL certificate file'), _('FILE'))],
4902 _('[OPTION]...')),
4902 _('[OPTION]...')),
4903 "showconfig|debugconfig":
4903 "showconfig|debugconfig":
4904 (showconfig,
4904 (showconfig,
4905 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4905 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4906 _('[-u] [NAME]...')),
4906 _('[-u] [NAME]...')),
4907 "^summary|sum":
4907 "^summary|sum":
4908 (summary,
4908 (summary,
4909 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4909 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4910 "^status|st":
4910 "^status|st":
4911 (status,
4911 (status,
4912 [('A', 'all', None, _('show status of all files')),
4912 [('A', 'all', None, _('show status of all files')),
4913 ('m', 'modified', None, _('show only modified files')),
4913 ('m', 'modified', None, _('show only modified files')),
4914 ('a', 'added', None, _('show only added files')),
4914 ('a', 'added', None, _('show only added files')),
4915 ('r', 'removed', None, _('show only removed files')),
4915 ('r', 'removed', None, _('show only removed files')),
4916 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4916 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4917 ('c', 'clean', None, _('show only files without changes')),
4917 ('c', 'clean', None, _('show only files without changes')),
4918 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4918 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4919 ('i', 'ignored', None, _('show only ignored files')),
4919 ('i', 'ignored', None, _('show only ignored files')),
4920 ('n', 'no-status', None, _('hide status prefix')),
4920 ('n', 'no-status', None, _('hide status prefix')),
4921 ('C', 'copies', None, _('show source of copied files')),
4921 ('C', 'copies', None, _('show source of copied files')),
4922 ('0', 'print0', None,
4922 ('0', 'print0', None,
4923 _('end filenames with NUL, for use with xargs')),
4923 _('end filenames with NUL, for use with xargs')),
4924 ('', 'rev', [],
4924 ('', 'rev', [],
4925 _('show difference from revision'), _('REV')),
4925 _('show difference from revision'), _('REV')),
4926 ('', 'change', '',
4926 ('', 'change', '',
4927 _('list the changed files of a revision'), _('REV')),
4927 _('list the changed files of a revision'), _('REV')),
4928 ] + walkopts + subrepoopts,
4928 ] + walkopts + subrepoopts,
4929 _('[OPTION]... [FILE]...')),
4929 _('[OPTION]... [FILE]...')),
4930 "tag":
4930 "tag":
4931 (tag,
4931 (tag,
4932 [('f', 'force', None, _('force tag')),
4932 [('f', 'force', None, _('force tag')),
4933 ('l', 'local', None, _('make the tag local')),
4933 ('l', 'local', None, _('make the tag local')),
4934 ('r', 'rev', '',
4934 ('r', 'rev', '',
4935 _('revision to tag'), _('REV')),
4935 _('revision to tag'), _('REV')),
4936 ('', 'remove', None, _('remove a tag')),
4936 ('', 'remove', None, _('remove a tag')),
4937 # -l/--local is already there, commitopts cannot be used
4937 # -l/--local is already there, commitopts cannot be used
4938 ('e', 'edit', None, _('edit commit message')),
4938 ('e', 'edit', None, _('edit commit message')),
4939 ('m', 'message', '',
4939 ('m', 'message', '',
4940 _('use <text> as commit message'), _('TEXT')),
4940 _('use <text> as commit message'), _('TEXT')),
4941 ] + commitopts2,
4941 ] + commitopts2,
4942 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4942 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4943 "tags": (tags, [], ''),
4943 "tags": (tags, [], ''),
4944 "tip":
4944 "tip":
4945 (tip,
4945 (tip,
4946 [('p', 'patch', None, _('show patch')),
4946 [('p', 'patch', None, _('show patch')),
4947 ('g', 'git', None, _('use git extended diff format')),
4947 ('g', 'git', None, _('use git extended diff format')),
4948 ] + templateopts,
4948 ] + templateopts,
4949 _('[-p] [-g]')),
4949 _('[-p] [-g]')),
4950 "unbundle":
4950 "unbundle":
4951 (unbundle,
4951 (unbundle,
4952 [('u', 'update', None,
4952 [('u', 'update', None,
4953 _('update to new branch head if changesets were unbundled'))],
4953 _('update to new branch head if changesets were unbundled'))],
4954 _('[-u] FILE...')),
4954 _('[-u] FILE...')),
4955 "^update|up|checkout|co":
4955 "^update|up|checkout|co":
4956 (update,
4956 (update,
4957 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4957 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4958 ('c', 'check', None,
4958 ('c', 'check', None,
4959 _('update across branches if no uncommitted changes')),
4959 _('update across branches if no uncommitted changes')),
4960 ('d', 'date', '',
4960 ('d', 'date', '',
4961 _('tipmost revision matching date'), _('DATE')),
4961 _('tipmost revision matching date'), _('DATE')),
4962 ('r', 'rev', '',
4962 ('r', 'rev', '',
4963 _('revision'), _('REV'))],
4963 _('revision'), _('REV'))],
4964 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4964 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4965 "verify": (verify, []),
4965 "verify": (verify, []),
4966 "version": (version_, []),
4966 "version": (version_, []),
4967 }
4967 }
4968
4968
4969 norepo = ("clone init version help debugcommands debugcomplete"
4969 norepo = ("clone init version help debugcommands debugcomplete"
4970 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
4970 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
4971 " debugknown debuggetbundle debugbundle")
4971 " debugknown debuggetbundle debugbundle")
4972 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4972 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4973 " debugdata debugindex debugindexdot")
4973 " debugdata debugindex debugindexdot")
@@ -1,331 +1,331
1 # posix.py - Posix utility function implementations for Mercurial
1 # posix.py - Posix utility function implementations for Mercurial
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
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 os, sys, errno, stat, getpass, pwd, grp, tempfile
9 import os, sys, errno, stat, getpass, pwd, grp, tempfile
10
10
11 posixfile = open
11 posixfile = open
12 nulldev = '/dev/null'
12 nulldev = '/dev/null'
13 normpath = os.path.normpath
13 normpath = os.path.normpath
14 samestat = os.path.samestat
14 samestat = os.path.samestat
15 oslink = os.link
15 oslink = os.link
16 unlink = os.unlink
16 unlink = os.unlink
17 rename = os.rename
17 rename = os.rename
18 expandglobs = False
18 expandglobs = False
19
19
20 umask = os.umask(0)
20 umask = os.umask(0)
21 os.umask(umask)
21 os.umask(umask)
22
22
23 def openhardlinks():
23 def openhardlinks():
24 '''return true if it is safe to hold open file handles to hardlinks'''
24 '''return true if it is safe to hold open file handles to hardlinks'''
25 return True
25 return True
26
26
27 def nlinks(name):
27 def nlinks(name):
28 '''return number of hardlinks for the given file'''
28 '''return number of hardlinks for the given file'''
29 return os.lstat(name).st_nlink
29 return os.lstat(name).st_nlink
30
30
31 def parsepatchoutput(output_line):
31 def parsepatchoutput(output_line):
32 """parses the output produced by patch and returns the filename"""
32 """parses the output produced by patch and returns the filename"""
33 pf = output_line[14:]
33 pf = output_line[14:]
34 if os.sys.platform == 'OpenVMS':
34 if os.sys.platform == 'OpenVMS':
35 if pf[0] == '`':
35 if pf[0] == '`':
36 pf = pf[1:-1] # Remove the quotes
36 pf = pf[1:-1] # Remove the quotes
37 else:
37 else:
38 if pf.startswith("'") and pf.endswith("'") and " " in pf:
38 if pf.startswith("'") and pf.endswith("'") and " " in pf:
39 pf = pf[1:-1] # Remove the quotes
39 pf = pf[1:-1] # Remove the quotes
40 return pf
40 return pf
41
41
42 def sshargs(sshcmd, host, user, port):
42 def sshargs(sshcmd, host, user, port):
43 '''Build argument list for ssh'''
43 '''Build argument list for ssh'''
44 args = user and ("%s@%s" % (user, host)) or host
44 args = user and ("%s@%s" % (user, host)) or host
45 return port and ("%s -p %s" % (args, port)) or args
45 return port and ("%s -p %s" % (args, port)) or args
46
46
47 def is_exec(f):
47 def is_exec(f):
48 """check whether a file is executable"""
48 """check whether a file is executable"""
49 return (os.lstat(f).st_mode & 0100 != 0)
49 return (os.lstat(f).st_mode & 0100 != 0)
50
50
51 def setflags(f, l, x):
51 def setflags(f, l, x):
52 s = os.lstat(f).st_mode
52 s = os.lstat(f).st_mode
53 if l:
53 if l:
54 if not stat.S_ISLNK(s):
54 if not stat.S_ISLNK(s):
55 # switch file to link
55 # switch file to link
56 fp = open(f)
56 fp = open(f)
57 data = fp.read()
57 data = fp.read()
58 fp.close()
58 fp.close()
59 os.unlink(f)
59 os.unlink(f)
60 try:
60 try:
61 os.symlink(data, f)
61 os.symlink(data, f)
62 except OSError:
62 except OSError:
63 # failed to make a link, rewrite file
63 # failed to make a link, rewrite file
64 fp = open(f, "w")
64 fp = open(f, "w")
65 fp.write(data)
65 fp.write(data)
66 fp.close()
66 fp.close()
67 # no chmod needed at this point
67 # no chmod needed at this point
68 return
68 return
69 if stat.S_ISLNK(s):
69 if stat.S_ISLNK(s):
70 # switch link to file
70 # switch link to file
71 data = os.readlink(f)
71 data = os.readlink(f)
72 os.unlink(f)
72 os.unlink(f)
73 fp = open(f, "w")
73 fp = open(f, "w")
74 fp.write(data)
74 fp.write(data)
75 fp.close()
75 fp.close()
76 s = 0666 & ~umask # avoid restatting for chmod
76 s = 0666 & ~umask # avoid restatting for chmod
77
77
78 sx = s & 0100
78 sx = s & 0100
79 if x and not sx:
79 if x and not sx:
80 # Turn on +x for every +r bit when making a file executable
80 # Turn on +x for every +r bit when making a file executable
81 # and obey umask.
81 # and obey umask.
82 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
82 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
83 elif not x and sx:
83 elif not x and sx:
84 # Turn off all +x bits
84 # Turn off all +x bits
85 os.chmod(f, s & 0666)
85 os.chmod(f, s & 0666)
86
86
87 def checkexec(path):
87 def checkexec(path):
88 """
88 """
89 Check whether the given path is on a filesystem with UNIX-like exec flags
89 Check whether the given path is on a filesystem with UNIX-like exec flags
90
90
91 Requires a directory (like /foo/.hg)
91 Requires a directory (like /foo/.hg)
92 """
92 """
93
93
94 # VFAT on some Linux versions can flip mode but it doesn't persist
94 # VFAT on some Linux versions can flip mode but it doesn't persist
95 # a FS remount. Frequently we can detect it if files are created
95 # a FS remount. Frequently we can detect it if files are created
96 # with exec bit on.
96 # with exec bit on.
97
97
98 try:
98 try:
99 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
99 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
100 fh, fn = tempfile.mkstemp(dir=path, prefix='hg-checkexec-')
100 fh, fn = tempfile.mkstemp(dir=path, prefix='hg-checkexec-')
101 try:
101 try:
102 os.close(fh)
102 os.close(fh)
103 m = os.stat(fn).st_mode & 0777
103 m = os.stat(fn).st_mode & 0777
104 new_file_has_exec = m & EXECFLAGS
104 new_file_has_exec = m & EXECFLAGS
105 os.chmod(fn, m ^ EXECFLAGS)
105 os.chmod(fn, m ^ EXECFLAGS)
106 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
106 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
107 finally:
107 finally:
108 os.unlink(fn)
108 os.unlink(fn)
109 except (IOError, OSError):
109 except (IOError, OSError):
110 # we don't care, the user probably won't be able to commit anyway
110 # we don't care, the user probably won't be able to commit anyway
111 return False
111 return False
112 return not (new_file_has_exec or exec_flags_cannot_flip)
112 return not (new_file_has_exec or exec_flags_cannot_flip)
113
113
114 def checklink(path):
114 def checklink(path):
115 """check whether the given path is on a symlink-capable filesystem"""
115 """check whether the given path is on a symlink-capable filesystem"""
116 # mktemp is not racy because symlink creation will fail if the
116 # mktemp is not racy because symlink creation will fail if the
117 # file already exists
117 # file already exists
118 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
118 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
119 try:
119 try:
120 os.symlink(".", name)
120 os.symlink(".", name)
121 os.unlink(name)
121 os.unlink(name)
122 return True
122 return True
123 except (OSError, AttributeError):
123 except (OSError, AttributeError):
124 return False
124 return False
125
125
126 def checkosfilename(path):
126 def checkosfilename(path):
127 '''Check that the base-relative path is a valid filename on this platform.
127 '''Check that the base-relative path is a valid filename on this platform.
128 Returns None if the path is ok, or a UI string describing the problem.'''
128 Returns None if the path is ok, or a UI string describing the problem.'''
129 pass # on posix platforms, every path is ok
129 pass # on posix platforms, every path is ok
130
130
131 def setbinary(fd):
131 def setbinary(fd):
132 pass
132 pass
133
133
134 def pconvert(path):
134 def pconvert(path):
135 return path
135 return path
136
136
137 def localpath(path):
137 def localpath(path):
138 return path
138 return path
139
139
140 def samefile(fpath1, fpath2):
140 def samefile(fpath1, fpath2):
141 """Returns whether path1 and path2 refer to the same file. This is only
141 """Returns whether path1 and path2 refer to the same file. This is only
142 guaranteed to work for files, not directories."""
142 guaranteed to work for files, not directories."""
143 return os.path.samefile(fpath1, fpath2)
143 return os.path.samefile(fpath1, fpath2)
144
144
145 def samedevice(fpath1, fpath2):
145 def samedevice(fpath1, fpath2):
146 """Returns whether fpath1 and fpath2 are on the same device. This is only
146 """Returns whether fpath1 and fpath2 are on the same device. This is only
147 guaranteed to work for files, not directories."""
147 guaranteed to work for files, not directories."""
148 st1 = os.lstat(fpath1)
148 st1 = os.lstat(fpath1)
149 st2 = os.lstat(fpath2)
149 st2 = os.lstat(fpath2)
150 return st1.st_dev == st2.st_dev
150 return st1.st_dev == st2.st_dev
151
151
152 if sys.platform == 'darwin':
152 if sys.platform == 'darwin':
153 import fcntl # only needed on darwin, missing on jython
153 import fcntl # only needed on darwin, missing on jython
154 def realpath(path):
154 def realpath(path):
155 '''
155 '''
156 Returns the true, canonical file system path equivalent to the given
156 Returns the true, canonical file system path equivalent to the given
157 path.
157 path.
158
158
159 Equivalent means, in this case, resulting in the same, unique
159 Equivalent means, in this case, resulting in the same, unique
160 file system link to the path. Every file system entry, whether a file,
160 file system link to the path. Every file system entry, whether a file,
161 directory, hard link or symbolic link or special, will have a single
161 directory, hard link or symbolic link or special, will have a single
162 path preferred by the system, but may allow multiple, differing path
162 path preferred by the system, but may allow multiple, differing path
163 lookups to point to it.
163 lookups to point to it.
164
164
165 Most regular UNIX file systems only allow a file system entry to be
165 Most regular UNIX file systems only allow a file system entry to be
166 looked up by its distinct path. Obviously, this does not apply to case
166 looked up by its distinct path. Obviously, this does not apply to case
167 insensitive file systems, whether case preserving or not. The most
167 insensitive file systems, whether case preserving or not. The most
168 complex issue to deal with is file systems transparently reencoding the
168 complex issue to deal with is file systems transparently reencoding the
169 path, such as the non-standard Unicode normalisation required for HFS+
169 path, such as the non-standard Unicode normalisation required for HFS+
170 and HFSX.
170 and HFSX.
171 '''
171 '''
172 # Constants copied from /usr/include/sys/fcntl.h
172 # Constants copied from /usr/include/sys/fcntl.h
173 F_GETPATH = 50
173 F_GETPATH = 50
174 O_SYMLINK = 0x200000
174 O_SYMLINK = 0x200000
175
175
176 try:
176 try:
177 fd = os.open(path, O_SYMLINK)
177 fd = os.open(path, O_SYMLINK)
178 except OSError, err:
178 except OSError, err:
179 if err.errno == errno.ENOENT:
179 if err.errno == errno.ENOENT:
180 return path
180 return path
181 raise
181 raise
182
182
183 try:
183 try:
184 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
184 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
185 finally:
185 finally:
186 os.close(fd)
186 os.close(fd)
187 else:
187 else:
188 # Fallback to the likely inadequate Python builtin function.
188 # Fallback to the likely inadequate Python builtin function.
189 realpath = os.path.realpath
189 realpath = os.path.realpath
190
190
191 def shellquote(s):
191 def shellquote(s):
192 if os.sys.platform == 'OpenVMS':
192 if os.sys.platform == 'OpenVMS':
193 return '"%s"' % s
193 return '"%s"' % s
194 else:
194 else:
195 return "'%s'" % s.replace("'", "'\\''")
195 return "'%s'" % s.replace("'", "'\\''")
196
196
197 def quotecommand(cmd):
197 def quotecommand(cmd):
198 return cmd
198 return cmd
199
199
200 def popen(command, mode='r'):
200 def popen(command, mode='r'):
201 return os.popen(command, mode)
201 return os.popen(command, mode)
202
202
203 def testpid(pid):
203 def testpid(pid):
204 '''return False if pid dead, True if running or not sure'''
204 '''return False if pid dead, True if running or not sure'''
205 if os.sys.platform == 'OpenVMS':
205 if os.sys.platform == 'OpenVMS':
206 return True
206 return True
207 try:
207 try:
208 os.kill(pid, 0)
208 os.kill(pid, 0)
209 return True
209 return True
210 except OSError, inst:
210 except OSError, inst:
211 return inst.errno != errno.ESRCH
211 return inst.errno != errno.ESRCH
212
212
213 def explainexit(code):
213 def explainexit(code):
214 """return a 2-tuple (desc, code) describing a subprocess status
214 """return a 2-tuple (desc, code) describing a subprocess status
215 (codes from kill are negative - not os.system/wait encoding)"""
215 (codes from kill are negative - not os.system/wait encoding)"""
216 if code >= 0:
216 if code >= 0:
217 return _("exited with status %d") % code, code
217 return _("exited with status %d") % code, code
218 return _("killed by signal %d") % -code, -code
218 return _("killed by signal %d") % -code, -code
219
219
220 def isowner(st):
220 def isowner(st):
221 """Return True if the stat object st is from the current user."""
221 """Return True if the stat object st is from the current user."""
222 return st.st_uid == os.getuid()
222 return st.st_uid == os.getuid()
223
223
224 def find_exe(command):
224 def find_exe(command):
225 '''Find executable for command searching like which does.
225 '''Find executable for command searching like which does.
226 If command is a basename then PATH is searched for command.
226 If command is a basename then PATH is searched for command.
227 PATH isn't searched if command is an absolute or relative path.
227 PATH isn't searched if command is an absolute or relative path.
228 If command isn't found None is returned.'''
228 If command isn't found None is returned.'''
229 if sys.platform == 'OpenVMS':
229 if sys.platform == 'OpenVMS':
230 return command
230 return command
231
231
232 def findexisting(executable):
232 def findexisting(executable):
233 'Will return executable if existing file'
233 'Will return executable if existing file'
234 if os.path.exists(executable):
234 if os.path.exists(executable):
235 return executable
235 return executable
236 return None
236 return None
237
237
238 if os.sep in command:
238 if os.sep in command:
239 return findexisting(command)
239 return findexisting(command)
240
240
241 for path in os.environ.get('PATH', '').split(os.pathsep):
241 for path in os.environ.get('PATH', '').split(os.pathsep):
242 executable = findexisting(os.path.join(path, command))
242 executable = findexisting(os.path.join(path, command))
243 if executable is not None:
243 if executable is not None:
244 return executable
244 return executable
245 return None
245 return None
246
246
247 def set_signal_handler():
247 def setsignalhandler():
248 pass
248 pass
249
249
250 def statfiles(files):
250 def statfiles(files):
251 'Stat each file in files and yield stat or None if file does not exist.'
251 'Stat each file in files and yield stat or None if file does not exist.'
252 lstat = os.lstat
252 lstat = os.lstat
253 for nf in files:
253 for nf in files:
254 try:
254 try:
255 st = lstat(nf)
255 st = lstat(nf)
256 except OSError, err:
256 except OSError, err:
257 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
257 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
258 raise
258 raise
259 st = None
259 st = None
260 yield st
260 yield st
261
261
262 def getuser():
262 def getuser():
263 '''return name of current user'''
263 '''return name of current user'''
264 return getpass.getuser()
264 return getpass.getuser()
265
265
266 def expand_glob(pats):
266 def expand_glob(pats):
267 '''On Windows, expand the implicit globs in a list of patterns'''
267 '''On Windows, expand the implicit globs in a list of patterns'''
268 return list(pats)
268 return list(pats)
269
269
270 def username(uid=None):
270 def username(uid=None):
271 """Return the name of the user with the given uid.
271 """Return the name of the user with the given uid.
272
272
273 If uid is None, return the name of the current user."""
273 If uid is None, return the name of the current user."""
274
274
275 if uid is None:
275 if uid is None:
276 uid = os.getuid()
276 uid = os.getuid()
277 try:
277 try:
278 return pwd.getpwuid(uid)[0]
278 return pwd.getpwuid(uid)[0]
279 except KeyError:
279 except KeyError:
280 return str(uid)
280 return str(uid)
281
281
282 def groupname(gid=None):
282 def groupname(gid=None):
283 """Return the name of the group with the given gid.
283 """Return the name of the group with the given gid.
284
284
285 If gid is None, return the name of the current group."""
285 If gid is None, return the name of the current group."""
286
286
287 if gid is None:
287 if gid is None:
288 gid = os.getgid()
288 gid = os.getgid()
289 try:
289 try:
290 return grp.getgrgid(gid)[0]
290 return grp.getgrgid(gid)[0]
291 except KeyError:
291 except KeyError:
292 return str(gid)
292 return str(gid)
293
293
294 def groupmembers(name):
294 def groupmembers(name):
295 """Return the list of members of the group with the given
295 """Return the list of members of the group with the given
296 name, KeyError if the group does not exist.
296 name, KeyError if the group does not exist.
297 """
297 """
298 return list(grp.getgrnam(name).gr_mem)
298 return list(grp.getgrnam(name).gr_mem)
299
299
300 def spawndetached(args):
300 def spawndetached(args):
301 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
301 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
302 args[0], args)
302 args[0], args)
303
303
304 def gethgcmd():
304 def gethgcmd():
305 return sys.argv[:1]
305 return sys.argv[:1]
306
306
307 def termwidth():
307 def termwidth():
308 try:
308 try:
309 import termios, array, fcntl
309 import termios, array, fcntl
310 for dev in (sys.stderr, sys.stdout, sys.stdin):
310 for dev in (sys.stderr, sys.stdout, sys.stdin):
311 try:
311 try:
312 try:
312 try:
313 fd = dev.fileno()
313 fd = dev.fileno()
314 except AttributeError:
314 except AttributeError:
315 continue
315 continue
316 if not os.isatty(fd):
316 if not os.isatty(fd):
317 continue
317 continue
318 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
318 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
319 width = array.array('h', arri)[1]
319 width = array.array('h', arri)[1]
320 if width > 0:
320 if width > 0:
321 return width
321 return width
322 except ValueError:
322 except ValueError:
323 pass
323 pass
324 except IOError, e:
324 except IOError, e:
325 if e[0] == errno.EINVAL:
325 if e[0] == errno.EINVAL:
326 pass
326 pass
327 else:
327 else:
328 raise
328 raise
329 except ImportError:
329 except ImportError:
330 pass
330 pass
331 return 80
331 return 80
@@ -1,376 +1,376
1 # win32.py - utility functions that use win32 API
1 # win32.py - utility functions that use win32 API
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
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 encoding
8 import encoding
9 import ctypes, errno, os, struct, subprocess, random
9 import ctypes, errno, os, struct, subprocess, random
10
10
11 _kernel32 = ctypes.windll.kernel32
11 _kernel32 = ctypes.windll.kernel32
12
12
13 _BOOL = ctypes.c_long
13 _BOOL = ctypes.c_long
14 _WORD = ctypes.c_ushort
14 _WORD = ctypes.c_ushort
15 _DWORD = ctypes.c_ulong
15 _DWORD = ctypes.c_ulong
16 _LPCSTR = _LPSTR = ctypes.c_char_p
16 _LPCSTR = _LPSTR = ctypes.c_char_p
17 _HANDLE = ctypes.c_void_p
17 _HANDLE = ctypes.c_void_p
18 _HWND = _HANDLE
18 _HWND = _HANDLE
19
19
20 _INVALID_HANDLE_VALUE = -1
20 _INVALID_HANDLE_VALUE = -1
21
21
22 # GetLastError
22 # GetLastError
23 _ERROR_SUCCESS = 0
23 _ERROR_SUCCESS = 0
24 _ERROR_INVALID_PARAMETER = 87
24 _ERROR_INVALID_PARAMETER = 87
25 _ERROR_INSUFFICIENT_BUFFER = 122
25 _ERROR_INSUFFICIENT_BUFFER = 122
26
26
27 # WPARAM is defined as UINT_PTR (unsigned type)
27 # WPARAM is defined as UINT_PTR (unsigned type)
28 # LPARAM is defined as LONG_PTR (signed type)
28 # LPARAM is defined as LONG_PTR (signed type)
29 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
29 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
30 _WPARAM = ctypes.c_ulong
30 _WPARAM = ctypes.c_ulong
31 _LPARAM = ctypes.c_long
31 _LPARAM = ctypes.c_long
32 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
32 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
33 _WPARAM = ctypes.c_ulonglong
33 _WPARAM = ctypes.c_ulonglong
34 _LPARAM = ctypes.c_longlong
34 _LPARAM = ctypes.c_longlong
35
35
36 class _FILETIME(ctypes.Structure):
36 class _FILETIME(ctypes.Structure):
37 _fields_ = [('dwLowDateTime', _DWORD),
37 _fields_ = [('dwLowDateTime', _DWORD),
38 ('dwHighDateTime', _DWORD)]
38 ('dwHighDateTime', _DWORD)]
39
39
40 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
40 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
41 _fields_ = [('dwFileAttributes', _DWORD),
41 _fields_ = [('dwFileAttributes', _DWORD),
42 ('ftCreationTime', _FILETIME),
42 ('ftCreationTime', _FILETIME),
43 ('ftLastAccessTime', _FILETIME),
43 ('ftLastAccessTime', _FILETIME),
44 ('ftLastWriteTime', _FILETIME),
44 ('ftLastWriteTime', _FILETIME),
45 ('dwVolumeSerialNumber', _DWORD),
45 ('dwVolumeSerialNumber', _DWORD),
46 ('nFileSizeHigh', _DWORD),
46 ('nFileSizeHigh', _DWORD),
47 ('nFileSizeLow', _DWORD),
47 ('nFileSizeLow', _DWORD),
48 ('nNumberOfLinks', _DWORD),
48 ('nNumberOfLinks', _DWORD),
49 ('nFileIndexHigh', _DWORD),
49 ('nFileIndexHigh', _DWORD),
50 ('nFileIndexLow', _DWORD)]
50 ('nFileIndexLow', _DWORD)]
51
51
52 # CreateFile
52 # CreateFile
53 _FILE_SHARE_READ = 0x00000001
53 _FILE_SHARE_READ = 0x00000001
54 _FILE_SHARE_WRITE = 0x00000002
54 _FILE_SHARE_WRITE = 0x00000002
55 _FILE_SHARE_DELETE = 0x00000004
55 _FILE_SHARE_DELETE = 0x00000004
56
56
57 _OPEN_EXISTING = 3
57 _OPEN_EXISTING = 3
58
58
59 # SetFileAttributes
59 # SetFileAttributes
60 _FILE_ATTRIBUTE_NORMAL = 0x80
60 _FILE_ATTRIBUTE_NORMAL = 0x80
61 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
61 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
62
62
63 # Process Security and Access Rights
63 # Process Security and Access Rights
64 _PROCESS_QUERY_INFORMATION = 0x0400
64 _PROCESS_QUERY_INFORMATION = 0x0400
65
65
66 # GetExitCodeProcess
66 # GetExitCodeProcess
67 _STILL_ACTIVE = 259
67 _STILL_ACTIVE = 259
68
68
69 # registry
69 # registry
70 _HKEY_CURRENT_USER = 0x80000001L
70 _HKEY_CURRENT_USER = 0x80000001L
71 _HKEY_LOCAL_MACHINE = 0x80000002L
71 _HKEY_LOCAL_MACHINE = 0x80000002L
72 _KEY_READ = 0x20019
72 _KEY_READ = 0x20019
73 _REG_SZ = 1
73 _REG_SZ = 1
74 _REG_DWORD = 4
74 _REG_DWORD = 4
75
75
76 class _STARTUPINFO(ctypes.Structure):
76 class _STARTUPINFO(ctypes.Structure):
77 _fields_ = [('cb', _DWORD),
77 _fields_ = [('cb', _DWORD),
78 ('lpReserved', _LPSTR),
78 ('lpReserved', _LPSTR),
79 ('lpDesktop', _LPSTR),
79 ('lpDesktop', _LPSTR),
80 ('lpTitle', _LPSTR),
80 ('lpTitle', _LPSTR),
81 ('dwX', _DWORD),
81 ('dwX', _DWORD),
82 ('dwY', _DWORD),
82 ('dwY', _DWORD),
83 ('dwXSize', _DWORD),
83 ('dwXSize', _DWORD),
84 ('dwYSize', _DWORD),
84 ('dwYSize', _DWORD),
85 ('dwXCountChars', _DWORD),
85 ('dwXCountChars', _DWORD),
86 ('dwYCountChars', _DWORD),
86 ('dwYCountChars', _DWORD),
87 ('dwFillAttribute', _DWORD),
87 ('dwFillAttribute', _DWORD),
88 ('dwFlags', _DWORD),
88 ('dwFlags', _DWORD),
89 ('wShowWindow', _WORD),
89 ('wShowWindow', _WORD),
90 ('cbReserved2', _WORD),
90 ('cbReserved2', _WORD),
91 ('lpReserved2', ctypes.c_char_p),
91 ('lpReserved2', ctypes.c_char_p),
92 ('hStdInput', _HANDLE),
92 ('hStdInput', _HANDLE),
93 ('hStdOutput', _HANDLE),
93 ('hStdOutput', _HANDLE),
94 ('hStdError', _HANDLE)]
94 ('hStdError', _HANDLE)]
95
95
96 class _PROCESS_INFORMATION(ctypes.Structure):
96 class _PROCESS_INFORMATION(ctypes.Structure):
97 _fields_ = [('hProcess', _HANDLE),
97 _fields_ = [('hProcess', _HANDLE),
98 ('hThread', _HANDLE),
98 ('hThread', _HANDLE),
99 ('dwProcessId', _DWORD),
99 ('dwProcessId', _DWORD),
100 ('dwThreadId', _DWORD)]
100 ('dwThreadId', _DWORD)]
101
101
102 _DETACHED_PROCESS = 0x00000008
102 _DETACHED_PROCESS = 0x00000008
103 _STARTF_USESHOWWINDOW = 0x00000001
103 _STARTF_USESHOWWINDOW = 0x00000001
104 _SW_HIDE = 0
104 _SW_HIDE = 0
105
105
106 class _COORD(ctypes.Structure):
106 class _COORD(ctypes.Structure):
107 _fields_ = [('X', ctypes.c_short),
107 _fields_ = [('X', ctypes.c_short),
108 ('Y', ctypes.c_short)]
108 ('Y', ctypes.c_short)]
109
109
110 class _SMALL_RECT(ctypes.Structure):
110 class _SMALL_RECT(ctypes.Structure):
111 _fields_ = [('Left', ctypes.c_short),
111 _fields_ = [('Left', ctypes.c_short),
112 ('Top', ctypes.c_short),
112 ('Top', ctypes.c_short),
113 ('Right', ctypes.c_short),
113 ('Right', ctypes.c_short),
114 ('Bottom', ctypes.c_short)]
114 ('Bottom', ctypes.c_short)]
115
115
116 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
116 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
117 _fields_ = [('dwSize', _COORD),
117 _fields_ = [('dwSize', _COORD),
118 ('dwCursorPosition', _COORD),
118 ('dwCursorPosition', _COORD),
119 ('wAttributes', _WORD),
119 ('wAttributes', _WORD),
120 ('srWindow', _SMALL_RECT),
120 ('srWindow', _SMALL_RECT),
121 ('dwMaximumWindowSize', _COORD)]
121 ('dwMaximumWindowSize', _COORD)]
122
122
123 _STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
123 _STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
124
124
125 def _raiseoserror(name):
125 def _raiseoserror(name):
126 err = ctypes.WinError()
126 err = ctypes.WinError()
127 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
127 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
128
128
129 def _getfileinfo(name):
129 def _getfileinfo(name):
130 fh = _kernel32.CreateFileA(name, 0,
130 fh = _kernel32.CreateFileA(name, 0,
131 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
131 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
132 None, _OPEN_EXISTING, 0, None)
132 None, _OPEN_EXISTING, 0, None)
133 if fh == _INVALID_HANDLE_VALUE:
133 if fh == _INVALID_HANDLE_VALUE:
134 _raiseoserror(name)
134 _raiseoserror(name)
135 try:
135 try:
136 fi = _BY_HANDLE_FILE_INFORMATION()
136 fi = _BY_HANDLE_FILE_INFORMATION()
137 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
137 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
138 _raiseoserror(name)
138 _raiseoserror(name)
139 return fi
139 return fi
140 finally:
140 finally:
141 _kernel32.CloseHandle(fh)
141 _kernel32.CloseHandle(fh)
142
142
143 def oslink(src, dst):
143 def oslink(src, dst):
144 try:
144 try:
145 if not _kernel32.CreateHardLinkA(dst, src, None):
145 if not _kernel32.CreateHardLinkA(dst, src, None):
146 _raiseoserror(src)
146 _raiseoserror(src)
147 except AttributeError: # Wine doesn't support this function
147 except AttributeError: # Wine doesn't support this function
148 _raiseoserror(src)
148 _raiseoserror(src)
149
149
150 def nlinks(name):
150 def nlinks(name):
151 '''return number of hardlinks for the given file'''
151 '''return number of hardlinks for the given file'''
152 return _getfileinfo(name).nNumberOfLinks
152 return _getfileinfo(name).nNumberOfLinks
153
153
154 def samefile(fpath1, fpath2):
154 def samefile(fpath1, fpath2):
155 '''Returns whether fpath1 and fpath2 refer to the same file. This is only
155 '''Returns whether fpath1 and fpath2 refer to the same file. This is only
156 guaranteed to work for files, not directories.'''
156 guaranteed to work for files, not directories.'''
157 res1 = _getfileinfo(fpath1)
157 res1 = _getfileinfo(fpath1)
158 res2 = _getfileinfo(fpath2)
158 res2 = _getfileinfo(fpath2)
159 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
159 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
160 and res1.nFileIndexHigh == res2.nFileIndexHigh
160 and res1.nFileIndexHigh == res2.nFileIndexHigh
161 and res1.nFileIndexLow == res2.nFileIndexLow)
161 and res1.nFileIndexLow == res2.nFileIndexLow)
162
162
163 def samedevice(fpath1, fpath2):
163 def samedevice(fpath1, fpath2):
164 '''Returns whether fpath1 and fpath2 are on the same device. This is only
164 '''Returns whether fpath1 and fpath2 are on the same device. This is only
165 guaranteed to work for files, not directories.'''
165 guaranteed to work for files, not directories.'''
166 res1 = _getfileinfo(fpath1)
166 res1 = _getfileinfo(fpath1)
167 res2 = _getfileinfo(fpath2)
167 res2 = _getfileinfo(fpath2)
168 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
168 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
169
169
170 def testpid(pid):
170 def testpid(pid):
171 '''return True if pid is still running or unable to
171 '''return True if pid is still running or unable to
172 determine, False otherwise'''
172 determine, False otherwise'''
173 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
173 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
174 if h:
174 if h:
175 try:
175 try:
176 status = _DWORD()
176 status = _DWORD()
177 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
177 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
178 return status.value == _STILL_ACTIVE
178 return status.value == _STILL_ACTIVE
179 finally:
179 finally:
180 _kernel32.CloseHandle(h)
180 _kernel32.CloseHandle(h)
181 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
181 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
182
182
183 def lookupreg(key, valname=None, scope=None):
183 def lookupreg(key, valname=None, scope=None):
184 ''' Look up a key/value name in the Windows registry.
184 ''' Look up a key/value name in the Windows registry.
185
185
186 valname: value name. If unspecified, the default value for the key
186 valname: value name. If unspecified, the default value for the key
187 is used.
187 is used.
188 scope: optionally specify scope for registry lookup, this can be
188 scope: optionally specify scope for registry lookup, this can be
189 a sequence of scopes to look up in order. Default (CURRENT_USER,
189 a sequence of scopes to look up in order. Default (CURRENT_USER,
190 LOCAL_MACHINE).
190 LOCAL_MACHINE).
191 '''
191 '''
192 adv = ctypes.windll.advapi32
192 adv = ctypes.windll.advapi32
193 byref = ctypes.byref
193 byref = ctypes.byref
194 if scope is None:
194 if scope is None:
195 scope = (_HKEY_CURRENT_USER, _HKEY_LOCAL_MACHINE)
195 scope = (_HKEY_CURRENT_USER, _HKEY_LOCAL_MACHINE)
196 elif not isinstance(scope, (list, tuple)):
196 elif not isinstance(scope, (list, tuple)):
197 scope = (scope,)
197 scope = (scope,)
198 for s in scope:
198 for s in scope:
199 kh = _HANDLE()
199 kh = _HANDLE()
200 res = adv.RegOpenKeyExA(s, key, 0, _KEY_READ, ctypes.byref(kh))
200 res = adv.RegOpenKeyExA(s, key, 0, _KEY_READ, ctypes.byref(kh))
201 if res != _ERROR_SUCCESS:
201 if res != _ERROR_SUCCESS:
202 continue
202 continue
203 try:
203 try:
204 size = _DWORD(600)
204 size = _DWORD(600)
205 type = _DWORD()
205 type = _DWORD()
206 buf = ctypes.create_string_buffer(size.value + 1)
206 buf = ctypes.create_string_buffer(size.value + 1)
207 res = adv.RegQueryValueExA(kh.value, valname, None,
207 res = adv.RegQueryValueExA(kh.value, valname, None,
208 byref(type), buf, byref(size))
208 byref(type), buf, byref(size))
209 if res != _ERROR_SUCCESS:
209 if res != _ERROR_SUCCESS:
210 continue
210 continue
211 if type.value == _REG_SZ:
211 if type.value == _REG_SZ:
212 # never let a Unicode string escape into the wild
212 # never let a Unicode string escape into the wild
213 return encoding.tolocal(buf.value.encode('UTF-8'))
213 return encoding.tolocal(buf.value.encode('UTF-8'))
214 elif type.value == _REG_DWORD:
214 elif type.value == _REG_DWORD:
215 fmt = '<L'
215 fmt = '<L'
216 s = ctypes.string_at(byref(buf), struct.calcsize(fmt))
216 s = ctypes.string_at(byref(buf), struct.calcsize(fmt))
217 return struct.unpack(fmt, s)[0]
217 return struct.unpack(fmt, s)[0]
218 finally:
218 finally:
219 adv.RegCloseKey(kh.value)
219 adv.RegCloseKey(kh.value)
220
220
221 def executablepath():
221 def executablepath():
222 '''return full path of hg.exe'''
222 '''return full path of hg.exe'''
223 size = 600
223 size = 600
224 buf = ctypes.create_string_buffer(size + 1)
224 buf = ctypes.create_string_buffer(size + 1)
225 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
225 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
226 if len == 0:
226 if len == 0:
227 raise ctypes.WinError()
227 raise ctypes.WinError()
228 elif len == size:
228 elif len == size:
229 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
229 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
230 return buf.value
230 return buf.value
231
231
232 def getuser():
232 def getuser():
233 '''return name of current user'''
233 '''return name of current user'''
234 adv = ctypes.windll.advapi32
234 adv = ctypes.windll.advapi32
235 size = _DWORD(300)
235 size = _DWORD(300)
236 buf = ctypes.create_string_buffer(size.value + 1)
236 buf = ctypes.create_string_buffer(size.value + 1)
237 if not adv.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
237 if not adv.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
238 raise ctypes.WinError()
238 raise ctypes.WinError()
239 return buf.value
239 return buf.value
240
240
241 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
241 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
242 _signal_handler = []
242 _signalhandler = []
243
243
244 def set_signal_handler():
244 def setsignalhandler():
245 '''Register a termination handler for console events including
245 '''Register a termination handler for console events including
246 CTRL+C. python signal handlers do not work well with socket
246 CTRL+C. python signal handlers do not work well with socket
247 operations.
247 operations.
248 '''
248 '''
249 def handler(event):
249 def handler(event):
250 _kernel32.ExitProcess(1)
250 _kernel32.ExitProcess(1)
251
251
252 if _signal_handler:
252 if _signalhandler:
253 return # already registered
253 return # already registered
254 h = _SIGNAL_HANDLER(handler)
254 h = _SIGNAL_HANDLER(handler)
255 _signal_handler.append(h) # needed to prevent garbage collection
255 _signalhandler.append(h) # needed to prevent garbage collection
256 if not _kernel32.SetConsoleCtrlHandler(h, True):
256 if not _kernel32.SetConsoleCtrlHandler(h, True):
257 raise ctypes.WinError()
257 raise ctypes.WinError()
258
258
259 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
259 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
260
260
261 def hidewindow():
261 def hidewindow():
262 user32 = ctypes.windll.user32
262 user32 = ctypes.windll.user32
263
263
264 def callback(hwnd, pid):
264 def callback(hwnd, pid):
265 wpid = _DWORD()
265 wpid = _DWORD()
266 user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
266 user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
267 if pid == wpid.value:
267 if pid == wpid.value:
268 user32.ShowWindow(hwnd, _SW_HIDE)
268 user32.ShowWindow(hwnd, _SW_HIDE)
269 return False # stop enumerating windows
269 return False # stop enumerating windows
270 return True
270 return True
271
271
272 pid = _kernel32.GetCurrentProcessId()
272 pid = _kernel32.GetCurrentProcessId()
273 user32.EnumWindows(_WNDENUMPROC(callback), pid)
273 user32.EnumWindows(_WNDENUMPROC(callback), pid)
274
274
275 def termwidth():
275 def termwidth():
276 # cmd.exe does not handle CR like a unix console, the CR is
276 # cmd.exe does not handle CR like a unix console, the CR is
277 # counted in the line length. On 80 columns consoles, if 80
277 # counted in the line length. On 80 columns consoles, if 80
278 # characters are written, the following CR won't apply on the
278 # characters are written, the following CR won't apply on the
279 # current line but on the new one. Keep room for it.
279 # current line but on the new one. Keep room for it.
280 width = 79
280 width = 79
281 # Query stderr to avoid problems with redirections
281 # Query stderr to avoid problems with redirections
282 screenbuf = _kernel32.GetStdHandle(
282 screenbuf = _kernel32.GetStdHandle(
283 _STD_ERROR_HANDLE) # don't close the handle returned
283 _STD_ERROR_HANDLE) # don't close the handle returned
284 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
284 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
285 return width
285 return width
286 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
286 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
287 if not _kernel32.GetConsoleScreenBufferInfo(
287 if not _kernel32.GetConsoleScreenBufferInfo(
288 screenbuf, ctypes.byref(csbi)):
288 screenbuf, ctypes.byref(csbi)):
289 return width
289 return width
290 width = csbi.srWindow.Right - csbi.srWindow.Left
290 width = csbi.srWindow.Right - csbi.srWindow.Left
291 return width
291 return width
292
292
293 def spawndetached(args):
293 def spawndetached(args):
294 # No standard library function really spawns a fully detached
294 # No standard library function really spawns a fully detached
295 # process under win32 because they allocate pipes or other objects
295 # process under win32 because they allocate pipes or other objects
296 # to handle standard streams communications. Passing these objects
296 # to handle standard streams communications. Passing these objects
297 # to the child process requires handle inheritance to be enabled
297 # to the child process requires handle inheritance to be enabled
298 # which makes really detached processes impossible.
298 # which makes really detached processes impossible.
299 si = _STARTUPINFO()
299 si = _STARTUPINFO()
300 si.cb = ctypes.sizeof(_STARTUPINFO)
300 si.cb = ctypes.sizeof(_STARTUPINFO)
301 si.dwFlags = _STARTF_USESHOWWINDOW
301 si.dwFlags = _STARTF_USESHOWWINDOW
302 si.wShowWindow = _SW_HIDE
302 si.wShowWindow = _SW_HIDE
303
303
304 pi = _PROCESS_INFORMATION()
304 pi = _PROCESS_INFORMATION()
305
305
306 env = ''
306 env = ''
307 for k in os.environ:
307 for k in os.environ:
308 env += "%s=%s\0" % (k, os.environ[k])
308 env += "%s=%s\0" % (k, os.environ[k])
309 if not env:
309 if not env:
310 env = '\0'
310 env = '\0'
311 env += '\0'
311 env += '\0'
312
312
313 args = subprocess.list2cmdline(args)
313 args = subprocess.list2cmdline(args)
314 # Not running the command in shell mode makes python26 hang when
314 # Not running the command in shell mode makes python26 hang when
315 # writing to hgweb output socket.
315 # writing to hgweb output socket.
316 comspec = os.environ.get("COMSPEC", "cmd.exe")
316 comspec = os.environ.get("COMSPEC", "cmd.exe")
317 args = comspec + " /c " + args
317 args = comspec + " /c " + args
318
318
319 res = _kernel32.CreateProcessA(
319 res = _kernel32.CreateProcessA(
320 None, args, None, None, False, _DETACHED_PROCESS,
320 None, args, None, None, False, _DETACHED_PROCESS,
321 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
321 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
322 if not res:
322 if not res:
323 raise ctypes.WinError()
323 raise ctypes.WinError()
324
324
325 return pi.dwProcessId
325 return pi.dwProcessId
326
326
327 def unlink(f):
327 def unlink(f):
328 '''try to implement POSIX' unlink semantics on Windows'''
328 '''try to implement POSIX' unlink semantics on Windows'''
329
329
330 # POSIX allows to unlink and rename open files. Windows has serious
330 # POSIX allows to unlink and rename open files. Windows has serious
331 # problems with doing that:
331 # problems with doing that:
332 # - Calling os.unlink (or os.rename) on a file f fails if f or any
332 # - Calling os.unlink (or os.rename) on a file f fails if f or any
333 # hardlinked copy of f has been opened with Python's open(). There is no
333 # hardlinked copy of f has been opened with Python's open(). There is no
334 # way such a file can be deleted or renamed on Windows (other than
334 # way such a file can be deleted or renamed on Windows (other than
335 # scheduling the delete or rename for the next reboot).
335 # scheduling the delete or rename for the next reboot).
336 # - Calling os.unlink on a file that has been opened with Mercurial's
336 # - Calling os.unlink on a file that has been opened with Mercurial's
337 # posixfile (or comparable methods) will delay the actual deletion of
337 # posixfile (or comparable methods) will delay the actual deletion of
338 # the file for as long as the file is held open. The filename is blocked
338 # the file for as long as the file is held open. The filename is blocked
339 # during that time and cannot be used for recreating a new file under
339 # during that time and cannot be used for recreating a new file under
340 # that same name ("zombie file"). Directories containing such zombie files
340 # that same name ("zombie file"). Directories containing such zombie files
341 # cannot be removed or moved.
341 # cannot be removed or moved.
342 # A file that has been opened with posixfile can be renamed, so we rename
342 # A file that has been opened with posixfile can be renamed, so we rename
343 # f to a random temporary name before calling os.unlink on it. This allows
343 # f to a random temporary name before calling os.unlink on it. This allows
344 # callers to recreate f immediately while having other readers do their
344 # callers to recreate f immediately while having other readers do their
345 # implicit zombie filename blocking on a temporary name.
345 # implicit zombie filename blocking on a temporary name.
346
346
347 for tries in xrange(10):
347 for tries in xrange(10):
348 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
348 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
349 try:
349 try:
350 os.rename(f, temp) # raises OSError EEXIST if temp exists
350 os.rename(f, temp) # raises OSError EEXIST if temp exists
351 break
351 break
352 except OSError, e:
352 except OSError, e:
353 if e.errno != errno.EEXIST:
353 if e.errno != errno.EEXIST:
354 raise
354 raise
355 else:
355 else:
356 raise IOError, (errno.EEXIST, "No usable temporary filename found")
356 raise IOError, (errno.EEXIST, "No usable temporary filename found")
357
357
358 try:
358 try:
359 os.unlink(temp)
359 os.unlink(temp)
360 except OSError:
360 except OSError:
361 # The unlink might have failed because the READONLY attribute may heave
361 # The unlink might have failed because the READONLY attribute may heave
362 # been set on the original file. Rename works fine with READONLY set,
362 # been set on the original file. Rename works fine with READONLY set,
363 # but not os.unlink. Reset all attributes and try again.
363 # but not os.unlink. Reset all attributes and try again.
364 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
364 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
365 try:
365 try:
366 os.unlink(temp)
366 os.unlink(temp)
367 except OSError:
367 except OSError:
368 # The unlink might have failed due to some very rude AV-Scanners.
368 # The unlink might have failed due to some very rude AV-Scanners.
369 # Leaking a tempfile is the lesser evil than aborting here and
369 # Leaking a tempfile is the lesser evil than aborting here and
370 # leaving some potentially serious inconsistencies.
370 # leaving some potentially serious inconsistencies.
371 pass
371 pass
372
372
373 def makedir(path, notindexed):
373 def makedir(path, notindexed):
374 os.mkdir(path)
374 os.mkdir(path)
375 if notindexed:
375 if notindexed:
376 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
376 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
General Comments 0
You need to be logged in to leave comments. Login now