##// END OF EJS Templates
util: make wrap() require a width argument...
Matt Mackall -
r12698:7aef77e7 default
parent child Browse files
Show More
@@ -1,4451 +1,4451 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, difflib, time, tempfile
11 import os, re, sys, difflib, time, tempfile
12 import hg, util, revlog, extensions, copies, error
12 import hg, util, revlog, extensions, copies, error
13 import patch, help, mdiff, url, encoding, templatekw, discovery
13 import patch, help, mdiff, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
15 import merge as mergemod
15 import merge as mergemod
16 import minirst, revset
16 import minirst, revset
17 import dagparser
17 import dagparser
18
18
19 # Commands start here, listed alphabetically
19 # Commands start here, listed alphabetically
20
20
21 def add(ui, repo, *pats, **opts):
21 def add(ui, repo, *pats, **opts):
22 """add the specified files on the next commit
22 """add the specified files on the next commit
23
23
24 Schedule files to be version controlled and added to the
24 Schedule files to be version controlled and added to the
25 repository.
25 repository.
26
26
27 The files will be added to the repository at the next commit. To
27 The files will be added to the repository at the next commit. To
28 undo an add before that, see :hg:`forget`.
28 undo an add before that, see :hg:`forget`.
29
29
30 If no names are given, add all files to the repository.
30 If no names are given, add all files to the repository.
31
31
32 .. container:: verbose
32 .. container:: verbose
33
33
34 An example showing how new (unknown) files are added
34 An example showing how new (unknown) files are added
35 automatically by :hg:`add`::
35 automatically by :hg:`add`::
36
36
37 $ ls
37 $ ls
38 foo.c
38 foo.c
39 $ hg status
39 $ hg status
40 ? foo.c
40 ? foo.c
41 $ hg add
41 $ hg add
42 adding foo.c
42 adding foo.c
43 $ hg status
43 $ hg status
44 A foo.c
44 A foo.c
45
45
46 Returns 0 if all files are successfully added.
46 Returns 0 if all files are successfully added.
47 """
47 """
48
48
49 m = cmdutil.match(repo, pats, opts)
49 m = cmdutil.match(repo, pats, opts)
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
51 opts.get('subrepos'), prefix="")
51 opts.get('subrepos'), prefix="")
52 return rejected and 1 or 0
52 return rejected and 1 or 0
53
53
54 def addremove(ui, repo, *pats, **opts):
54 def addremove(ui, repo, *pats, **opts):
55 """add all new files, delete all missing files
55 """add all new files, delete all missing files
56
56
57 Add all new files and remove all missing files from the
57 Add all new files and remove all missing files from the
58 repository.
58 repository.
59
59
60 New files are ignored if they match any of the patterns in
60 New files are ignored if they match any of the patterns in
61 .hgignore. As with add, these changes take effect at the next
61 .hgignore. As with add, these changes take effect at the next
62 commit.
62 commit.
63
63
64 Use the -s/--similarity option to detect renamed files. With a
64 Use the -s/--similarity option to detect renamed files. With a
65 parameter greater than 0, this compares every removed file with
65 parameter greater than 0, this compares every removed file with
66 every added file and records those similar enough as renames. This
66 every added file and records those similar enough as renames. This
67 option takes a percentage between 0 (disabled) and 100 (files must
67 option takes a percentage between 0 (disabled) and 100 (files must
68 be identical) as its parameter. Detecting renamed files this way
68 be identical) as its parameter. Detecting renamed files this way
69 can be expensive. After using this option, :hg:`status -C` can be
69 can be expensive. After using this option, :hg:`status -C` can be
70 used to check which files were identified as moved or renamed.
70 used to check which files were identified as moved or renamed.
71
71
72 Returns 0 if all files are successfully added.
72 Returns 0 if all files are successfully added.
73 """
73 """
74 try:
74 try:
75 sim = float(opts.get('similarity') or 100)
75 sim = float(opts.get('similarity') or 100)
76 except ValueError:
76 except ValueError:
77 raise util.Abort(_('similarity must be a number'))
77 raise util.Abort(_('similarity must be a number'))
78 if sim < 0 or sim > 100:
78 if sim < 0 or sim > 100:
79 raise util.Abort(_('similarity must be between 0 and 100'))
79 raise util.Abort(_('similarity must be between 0 and 100'))
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
81
81
82 def annotate(ui, repo, *pats, **opts):
82 def annotate(ui, repo, *pats, **opts):
83 """show changeset information by line for each file
83 """show changeset information by line for each file
84
84
85 List changes in files, showing the revision id responsible for
85 List changes in files, showing the revision id responsible for
86 each line
86 each line
87
87
88 This command is useful for discovering when a change was made and
88 This command is useful for discovering when a change was made and
89 by whom.
89 by whom.
90
90
91 Without the -a/--text option, annotate will avoid processing files
91 Without the -a/--text option, annotate will avoid processing files
92 it detects as binary. With -a, annotate will annotate the file
92 it detects as binary. With -a, annotate will annotate the file
93 anyway, although the results will probably be neither useful
93 anyway, although the results will probably be neither useful
94 nor desirable.
94 nor desirable.
95
95
96 Returns 0 on success.
96 Returns 0 on success.
97 """
97 """
98 if opts.get('follow'):
98 if opts.get('follow'):
99 # --follow is deprecated and now just an alias for -f/--file
99 # --follow is deprecated and now just an alias for -f/--file
100 # to mimic the behavior of Mercurial before version 1.5
100 # to mimic the behavior of Mercurial before version 1.5
101 opts['file'] = 1
101 opts['file'] = 1
102
102
103 datefunc = ui.quiet and util.shortdate or util.datestr
103 datefunc = ui.quiet and util.shortdate or util.datestr
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
105
105
106 if not pats:
106 if not pats:
107 raise util.Abort(_('at least one filename or pattern is required'))
107 raise util.Abort(_('at least one filename or pattern is required'))
108
108
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
110 ('number', lambda x: str(x[0].rev())),
110 ('number', lambda x: str(x[0].rev())),
111 ('changeset', lambda x: short(x[0].node())),
111 ('changeset', lambda x: short(x[0].node())),
112 ('date', getdate),
112 ('date', getdate),
113 ('file', lambda x: x[0].path()),
113 ('file', lambda x: x[0].path()),
114 ]
114 ]
115
115
116 if (not opts.get('user') and not opts.get('changeset')
116 if (not opts.get('user') and not opts.get('changeset')
117 and not opts.get('date') and not opts.get('file')):
117 and not opts.get('date') and not opts.get('file')):
118 opts['number'] = 1
118 opts['number'] = 1
119
119
120 linenumber = opts.get('line_number') is not None
120 linenumber = opts.get('line_number') is not None
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
123
123
124 funcmap = [func for op, func in opmap if opts.get(op)]
124 funcmap = [func for op, func in opmap if opts.get(op)]
125 if linenumber:
125 if linenumber:
126 lastfunc = funcmap[-1]
126 lastfunc = funcmap[-1]
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
128
128
129 ctx = repo[opts.get('rev')]
129 ctx = repo[opts.get('rev')]
130 m = cmdutil.match(repo, pats, opts)
130 m = cmdutil.match(repo, pats, opts)
131 follow = not opts.get('no_follow')
131 follow = not opts.get('no_follow')
132 for abs in ctx.walk(m):
132 for abs in ctx.walk(m):
133 fctx = ctx[abs]
133 fctx = ctx[abs]
134 if not opts.get('text') and util.binary(fctx.data()):
134 if not opts.get('text') and util.binary(fctx.data()):
135 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
135 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
136 continue
136 continue
137
137
138 lines = fctx.annotate(follow=follow, linenumber=linenumber)
138 lines = fctx.annotate(follow=follow, linenumber=linenumber)
139 pieces = []
139 pieces = []
140
140
141 for f in funcmap:
141 for f in funcmap:
142 l = [f(n) for n, dummy in lines]
142 l = [f(n) for n, dummy in lines]
143 if l:
143 if l:
144 sized = [(x, encoding.colwidth(x)) for x in l]
144 sized = [(x, encoding.colwidth(x)) for x in l]
145 ml = max([w for x, w in sized])
145 ml = max([w for x, w in sized])
146 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
146 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
147
147
148 if pieces:
148 if pieces:
149 for p, l in zip(zip(*pieces), lines):
149 for p, l in zip(zip(*pieces), lines):
150 ui.write("%s: %s" % (" ".join(p), l[1]))
150 ui.write("%s: %s" % (" ".join(p), l[1]))
151
151
152 def archive(ui, repo, dest, **opts):
152 def archive(ui, repo, dest, **opts):
153 '''create an unversioned archive of a repository revision
153 '''create an unversioned archive of a repository revision
154
154
155 By default, the revision used is the parent of the working
155 By default, the revision used is the parent of the working
156 directory; use -r/--rev to specify a different revision.
156 directory; use -r/--rev to specify a different revision.
157
157
158 The archive type is automatically detected based on file
158 The archive type is automatically detected based on file
159 extension (or override using -t/--type).
159 extension (or override using -t/--type).
160
160
161 Valid types are:
161 Valid types are:
162
162
163 :``files``: a directory full of files (default)
163 :``files``: a directory full of files (default)
164 :``tar``: tar archive, uncompressed
164 :``tar``: tar archive, uncompressed
165 :``tbz2``: tar archive, compressed using bzip2
165 :``tbz2``: tar archive, compressed using bzip2
166 :``tgz``: tar archive, compressed using gzip
166 :``tgz``: tar archive, compressed using gzip
167 :``uzip``: zip archive, uncompressed
167 :``uzip``: zip archive, uncompressed
168 :``zip``: zip archive, compressed using deflate
168 :``zip``: zip archive, compressed using deflate
169
169
170 The exact name of the destination archive or directory is given
170 The exact name of the destination archive or directory is given
171 using a format string; see :hg:`help export` for details.
171 using a format string; see :hg:`help export` for details.
172
172
173 Each member added to an archive file has a directory prefix
173 Each member added to an archive file has a directory prefix
174 prepended. Use -p/--prefix to specify a format string for the
174 prepended. Use -p/--prefix to specify a format string for the
175 prefix. The default is the basename of the archive, with suffixes
175 prefix. The default is the basename of the archive, with suffixes
176 removed.
176 removed.
177
177
178 Returns 0 on success.
178 Returns 0 on success.
179 '''
179 '''
180
180
181 ctx = repo[opts.get('rev')]
181 ctx = repo[opts.get('rev')]
182 if not ctx:
182 if not ctx:
183 raise util.Abort(_('no working directory: please specify a revision'))
183 raise util.Abort(_('no working directory: please specify a revision'))
184 node = ctx.node()
184 node = ctx.node()
185 dest = cmdutil.make_filename(repo, dest, node)
185 dest = cmdutil.make_filename(repo, dest, node)
186 if os.path.realpath(dest) == repo.root:
186 if os.path.realpath(dest) == repo.root:
187 raise util.Abort(_('repository root cannot be destination'))
187 raise util.Abort(_('repository root cannot be destination'))
188
188
189 kind = opts.get('type') or archival.guesskind(dest) or 'files'
189 kind = opts.get('type') or archival.guesskind(dest) or 'files'
190 prefix = opts.get('prefix')
190 prefix = opts.get('prefix')
191
191
192 if dest == '-':
192 if dest == '-':
193 if kind == 'files':
193 if kind == 'files':
194 raise util.Abort(_('cannot archive plain files to stdout'))
194 raise util.Abort(_('cannot archive plain files to stdout'))
195 dest = sys.stdout
195 dest = sys.stdout
196 if not prefix:
196 if not prefix:
197 prefix = os.path.basename(repo.root) + '-%h'
197 prefix = os.path.basename(repo.root) + '-%h'
198
198
199 prefix = cmdutil.make_filename(repo, prefix, node)
199 prefix = cmdutil.make_filename(repo, prefix, node)
200 matchfn = cmdutil.match(repo, [], opts)
200 matchfn = cmdutil.match(repo, [], opts)
201 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
201 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
202 matchfn, prefix, subrepos=opts.get('subrepos'))
202 matchfn, prefix, subrepos=opts.get('subrepos'))
203
203
204 def backout(ui, repo, node=None, rev=None, **opts):
204 def backout(ui, repo, node=None, rev=None, **opts):
205 '''reverse effect of earlier changeset
205 '''reverse effect of earlier changeset
206
206
207 Commit the backed out changes as a new changeset. The new
207 Commit the backed out changes as a new changeset. The new
208 changeset is a child of the backed out changeset.
208 changeset is a child of the backed out changeset.
209
209
210 If you backout a changeset other than the tip, a new head is
210 If you backout a changeset other than the tip, a new head is
211 created. This head will be the new tip and you should merge this
211 created. This head will be the new tip and you should merge this
212 backout changeset with another head.
212 backout changeset with another head.
213
213
214 The --merge option remembers the parent of the working directory
214 The --merge option remembers the parent of the working directory
215 before starting the backout, then merges the new head with that
215 before starting the backout, then merges the new head with that
216 changeset afterwards. This saves you from doing the merge by hand.
216 changeset afterwards. This saves you from doing the merge by hand.
217 The result of this merge is not committed, as with a normal merge.
217 The result of this merge is not committed, as with a normal merge.
218
218
219 See :hg:`help dates` for a list of formats valid for -d/--date.
219 See :hg:`help dates` for a list of formats valid for -d/--date.
220
220
221 Returns 0 on success.
221 Returns 0 on success.
222 '''
222 '''
223 if rev and node:
223 if rev and node:
224 raise util.Abort(_("please specify just one revision"))
224 raise util.Abort(_("please specify just one revision"))
225
225
226 if not rev:
226 if not rev:
227 rev = node
227 rev = node
228
228
229 if not rev:
229 if not rev:
230 raise util.Abort(_("please specify a revision to backout"))
230 raise util.Abort(_("please specify a revision to backout"))
231
231
232 date = opts.get('date')
232 date = opts.get('date')
233 if date:
233 if date:
234 opts['date'] = util.parsedate(date)
234 opts['date'] = util.parsedate(date)
235
235
236 cmdutil.bail_if_changed(repo)
236 cmdutil.bail_if_changed(repo)
237 node = repo.lookup(rev)
237 node = repo.lookup(rev)
238
238
239 op1, op2 = repo.dirstate.parents()
239 op1, op2 = repo.dirstate.parents()
240 a = repo.changelog.ancestor(op1, node)
240 a = repo.changelog.ancestor(op1, node)
241 if a != node:
241 if a != node:
242 raise util.Abort(_('cannot backout change on a different branch'))
242 raise util.Abort(_('cannot backout change on a different branch'))
243
243
244 p1, p2 = repo.changelog.parents(node)
244 p1, p2 = repo.changelog.parents(node)
245 if p1 == nullid:
245 if p1 == nullid:
246 raise util.Abort(_('cannot backout a change with no parents'))
246 raise util.Abort(_('cannot backout a change with no parents'))
247 if p2 != nullid:
247 if p2 != nullid:
248 if not opts.get('parent'):
248 if not opts.get('parent'):
249 raise util.Abort(_('cannot backout a merge changeset without '
249 raise util.Abort(_('cannot backout a merge changeset without '
250 '--parent'))
250 '--parent'))
251 p = repo.lookup(opts['parent'])
251 p = repo.lookup(opts['parent'])
252 if p not in (p1, p2):
252 if p not in (p1, p2):
253 raise util.Abort(_('%s is not a parent of %s') %
253 raise util.Abort(_('%s is not a parent of %s') %
254 (short(p), short(node)))
254 (short(p), short(node)))
255 parent = p
255 parent = p
256 else:
256 else:
257 if opts.get('parent'):
257 if opts.get('parent'):
258 raise util.Abort(_('cannot use --parent on non-merge changeset'))
258 raise util.Abort(_('cannot use --parent on non-merge changeset'))
259 parent = p1
259 parent = p1
260
260
261 # the backout should appear on the same branch
261 # the backout should appear on the same branch
262 branch = repo.dirstate.branch()
262 branch = repo.dirstate.branch()
263 hg.clean(repo, node, show_stats=False)
263 hg.clean(repo, node, show_stats=False)
264 repo.dirstate.setbranch(branch)
264 repo.dirstate.setbranch(branch)
265 revert_opts = opts.copy()
265 revert_opts = opts.copy()
266 revert_opts['date'] = None
266 revert_opts['date'] = None
267 revert_opts['all'] = True
267 revert_opts['all'] = True
268 revert_opts['rev'] = hex(parent)
268 revert_opts['rev'] = hex(parent)
269 revert_opts['no_backup'] = None
269 revert_opts['no_backup'] = None
270 revert(ui, repo, **revert_opts)
270 revert(ui, repo, **revert_opts)
271 commit_opts = opts.copy()
271 commit_opts = opts.copy()
272 commit_opts['addremove'] = False
272 commit_opts['addremove'] = False
273 if not commit_opts['message'] and not commit_opts['logfile']:
273 if not commit_opts['message'] and not commit_opts['logfile']:
274 # we don't translate commit messages
274 # we don't translate commit messages
275 commit_opts['message'] = "Backed out changeset %s" % short(node)
275 commit_opts['message'] = "Backed out changeset %s" % short(node)
276 commit_opts['force_editor'] = True
276 commit_opts['force_editor'] = True
277 commit(ui, repo, **commit_opts)
277 commit(ui, repo, **commit_opts)
278 def nice(node):
278 def nice(node):
279 return '%d:%s' % (repo.changelog.rev(node), short(node))
279 return '%d:%s' % (repo.changelog.rev(node), short(node))
280 ui.status(_('changeset %s backs out changeset %s\n') %
280 ui.status(_('changeset %s backs out changeset %s\n') %
281 (nice(repo.changelog.tip()), nice(node)))
281 (nice(repo.changelog.tip()), nice(node)))
282 if op1 != node:
282 if op1 != node:
283 hg.clean(repo, op1, show_stats=False)
283 hg.clean(repo, op1, show_stats=False)
284 if opts.get('merge'):
284 if opts.get('merge'):
285 ui.status(_('merging with changeset %s\n')
285 ui.status(_('merging with changeset %s\n')
286 % nice(repo.changelog.tip()))
286 % nice(repo.changelog.tip()))
287 hg.merge(repo, hex(repo.changelog.tip()))
287 hg.merge(repo, hex(repo.changelog.tip()))
288 else:
288 else:
289 ui.status(_('the backout changeset is a new head - '
289 ui.status(_('the backout changeset is a new head - '
290 'do not forget to merge\n'))
290 'do not forget to merge\n'))
291 ui.status(_('(use "backout --merge" '
291 ui.status(_('(use "backout --merge" '
292 'if you want to auto-merge)\n'))
292 'if you want to auto-merge)\n'))
293
293
294 def bisect(ui, repo, rev=None, extra=None, command=None,
294 def bisect(ui, repo, rev=None, extra=None, command=None,
295 reset=None, good=None, bad=None, skip=None, noupdate=None):
295 reset=None, good=None, bad=None, skip=None, noupdate=None):
296 """subdivision search of changesets
296 """subdivision search of changesets
297
297
298 This command helps to find changesets which introduce problems. To
298 This command helps to find changesets which introduce problems. To
299 use, mark the earliest changeset you know exhibits the problem as
299 use, mark the earliest changeset you know exhibits the problem as
300 bad, then mark the latest changeset which is free from the problem
300 bad, then mark the latest changeset which is free from the problem
301 as good. Bisect will update your working directory to a revision
301 as good. Bisect will update your working directory to a revision
302 for testing (unless the -U/--noupdate option is specified). Once
302 for testing (unless the -U/--noupdate option is specified). Once
303 you have performed tests, mark the working directory as good or
303 you have performed tests, mark the working directory as good or
304 bad, and bisect will either update to another candidate changeset
304 bad, and bisect will either update to another candidate changeset
305 or announce that it has found the bad revision.
305 or announce that it has found the bad revision.
306
306
307 As a shortcut, you can also use the revision argument to mark a
307 As a shortcut, you can also use the revision argument to mark a
308 revision as good or bad without checking it out first.
308 revision as good or bad without checking it out first.
309
309
310 If you supply a command, it will be used for automatic bisection.
310 If you supply a command, it will be used for automatic bisection.
311 Its exit status will be used to mark revisions as good or bad:
311 Its exit status will be used to mark revisions as good or bad:
312 status 0 means good, 125 means to skip the revision, 127
312 status 0 means good, 125 means to skip the revision, 127
313 (command not found) will abort the bisection, and any other
313 (command not found) will abort the bisection, and any other
314 non-zero exit status means the revision is bad.
314 non-zero exit status means the revision is bad.
315
315
316 Returns 0 on success.
316 Returns 0 on success.
317 """
317 """
318 def print_result(nodes, good):
318 def print_result(nodes, good):
319 displayer = cmdutil.show_changeset(ui, repo, {})
319 displayer = cmdutil.show_changeset(ui, repo, {})
320 if len(nodes) == 1:
320 if len(nodes) == 1:
321 # narrowed it down to a single revision
321 # narrowed it down to a single revision
322 if good:
322 if good:
323 ui.write(_("The first good revision is:\n"))
323 ui.write(_("The first good revision is:\n"))
324 else:
324 else:
325 ui.write(_("The first bad revision is:\n"))
325 ui.write(_("The first bad revision is:\n"))
326 displayer.show(repo[nodes[0]])
326 displayer.show(repo[nodes[0]])
327 parents = repo[nodes[0]].parents()
327 parents = repo[nodes[0]].parents()
328 if len(parents) > 1:
328 if len(parents) > 1:
329 side = good and state['bad'] or state['good']
329 side = good and state['bad'] or state['good']
330 num = len(set(i.node() for i in parents) & set(side))
330 num = len(set(i.node() for i in parents) & set(side))
331 if num == 1:
331 if num == 1:
332 common = parents[0].ancestor(parents[1])
332 common = parents[0].ancestor(parents[1])
333 ui.write(_('Not all ancestors of this changeset have been'
333 ui.write(_('Not all ancestors of this changeset have been'
334 ' checked.\nTo check the other ancestors, start'
334 ' checked.\nTo check the other ancestors, start'
335 ' from the common ancestor, %s.\n' % common))
335 ' from the common ancestor, %s.\n' % common))
336 else:
336 else:
337 # multiple possible revisions
337 # multiple possible revisions
338 if good:
338 if good:
339 ui.write(_("Due to skipped revisions, the first "
339 ui.write(_("Due to skipped revisions, the first "
340 "good revision could be any of:\n"))
340 "good revision could be any of:\n"))
341 else:
341 else:
342 ui.write(_("Due to skipped revisions, the first "
342 ui.write(_("Due to skipped revisions, the first "
343 "bad revision could be any of:\n"))
343 "bad revision could be any of:\n"))
344 for n in nodes:
344 for n in nodes:
345 displayer.show(repo[n])
345 displayer.show(repo[n])
346 displayer.close()
346 displayer.close()
347
347
348 def check_state(state, interactive=True):
348 def check_state(state, interactive=True):
349 if not state['good'] or not state['bad']:
349 if not state['good'] or not state['bad']:
350 if (good or bad or skip or reset) and interactive:
350 if (good or bad or skip or reset) and interactive:
351 return
351 return
352 if not state['good']:
352 if not state['good']:
353 raise util.Abort(_('cannot bisect (no known good revisions)'))
353 raise util.Abort(_('cannot bisect (no known good revisions)'))
354 else:
354 else:
355 raise util.Abort(_('cannot bisect (no known bad revisions)'))
355 raise util.Abort(_('cannot bisect (no known bad revisions)'))
356 return True
356 return True
357
357
358 # backward compatibility
358 # backward compatibility
359 if rev in "good bad reset init".split():
359 if rev in "good bad reset init".split():
360 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
360 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
361 cmd, rev, extra = rev, extra, None
361 cmd, rev, extra = rev, extra, None
362 if cmd == "good":
362 if cmd == "good":
363 good = True
363 good = True
364 elif cmd == "bad":
364 elif cmd == "bad":
365 bad = True
365 bad = True
366 else:
366 else:
367 reset = True
367 reset = True
368 elif extra or good + bad + skip + reset + bool(command) > 1:
368 elif extra or good + bad + skip + reset + bool(command) > 1:
369 raise util.Abort(_('incompatible arguments'))
369 raise util.Abort(_('incompatible arguments'))
370
370
371 if reset:
371 if reset:
372 p = repo.join("bisect.state")
372 p = repo.join("bisect.state")
373 if os.path.exists(p):
373 if os.path.exists(p):
374 os.unlink(p)
374 os.unlink(p)
375 return
375 return
376
376
377 state = hbisect.load_state(repo)
377 state = hbisect.load_state(repo)
378
378
379 if command:
379 if command:
380 changesets = 1
380 changesets = 1
381 try:
381 try:
382 while changesets:
382 while changesets:
383 # update state
383 # update state
384 status = util.system(command)
384 status = util.system(command)
385 if status == 125:
385 if status == 125:
386 transition = "skip"
386 transition = "skip"
387 elif status == 0:
387 elif status == 0:
388 transition = "good"
388 transition = "good"
389 # status < 0 means process was killed
389 # status < 0 means process was killed
390 elif status == 127:
390 elif status == 127:
391 raise util.Abort(_("failed to execute %s") % command)
391 raise util.Abort(_("failed to execute %s") % command)
392 elif status < 0:
392 elif status < 0:
393 raise util.Abort(_("%s killed") % command)
393 raise util.Abort(_("%s killed") % command)
394 else:
394 else:
395 transition = "bad"
395 transition = "bad"
396 ctx = repo[rev or '.']
396 ctx = repo[rev or '.']
397 state[transition].append(ctx.node())
397 state[transition].append(ctx.node())
398 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
398 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
399 check_state(state, interactive=False)
399 check_state(state, interactive=False)
400 # bisect
400 # bisect
401 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
401 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
402 # update to next check
402 # update to next check
403 cmdutil.bail_if_changed(repo)
403 cmdutil.bail_if_changed(repo)
404 hg.clean(repo, nodes[0], show_stats=False)
404 hg.clean(repo, nodes[0], show_stats=False)
405 finally:
405 finally:
406 hbisect.save_state(repo, state)
406 hbisect.save_state(repo, state)
407 print_result(nodes, good)
407 print_result(nodes, good)
408 return
408 return
409
409
410 # update state
410 # update state
411
411
412 if rev:
412 if rev:
413 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
413 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
414 else:
414 else:
415 nodes = [repo.lookup('.')]
415 nodes = [repo.lookup('.')]
416
416
417 if good or bad or skip:
417 if good or bad or skip:
418 if good:
418 if good:
419 state['good'] += nodes
419 state['good'] += nodes
420 elif bad:
420 elif bad:
421 state['bad'] += nodes
421 state['bad'] += nodes
422 elif skip:
422 elif skip:
423 state['skip'] += nodes
423 state['skip'] += nodes
424 hbisect.save_state(repo, state)
424 hbisect.save_state(repo, state)
425
425
426 if not check_state(state):
426 if not check_state(state):
427 return
427 return
428
428
429 # actually bisect
429 # actually bisect
430 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
430 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
431 if changesets == 0:
431 if changesets == 0:
432 print_result(nodes, good)
432 print_result(nodes, good)
433 else:
433 else:
434 assert len(nodes) == 1 # only a single node can be tested next
434 assert len(nodes) == 1 # only a single node can be tested next
435 node = nodes[0]
435 node = nodes[0]
436 # compute the approximate number of remaining tests
436 # compute the approximate number of remaining tests
437 tests, size = 0, 2
437 tests, size = 0, 2
438 while size <= changesets:
438 while size <= changesets:
439 tests, size = tests + 1, size * 2
439 tests, size = tests + 1, size * 2
440 rev = repo.changelog.rev(node)
440 rev = repo.changelog.rev(node)
441 ui.write(_("Testing changeset %d:%s "
441 ui.write(_("Testing changeset %d:%s "
442 "(%d changesets remaining, ~%d tests)\n")
442 "(%d changesets remaining, ~%d tests)\n")
443 % (rev, short(node), changesets, tests))
443 % (rev, short(node), changesets, tests))
444 if not noupdate:
444 if not noupdate:
445 cmdutil.bail_if_changed(repo)
445 cmdutil.bail_if_changed(repo)
446 return hg.clean(repo, node)
446 return hg.clean(repo, node)
447
447
448 def branch(ui, repo, label=None, **opts):
448 def branch(ui, repo, label=None, **opts):
449 """set or show the current branch name
449 """set or show the current branch name
450
450
451 With no argument, show the current branch name. With one argument,
451 With no argument, show the current branch name. With one argument,
452 set the working directory branch name (the branch will not exist
452 set the working directory branch name (the branch will not exist
453 in the repository until the next commit). Standard practice
453 in the repository until the next commit). Standard practice
454 recommends that primary development take place on the 'default'
454 recommends that primary development take place on the 'default'
455 branch.
455 branch.
456
456
457 Unless -f/--force is specified, branch will not let you set a
457 Unless -f/--force is specified, branch will not let you set a
458 branch name that already exists, even if it's inactive.
458 branch name that already exists, even if it's inactive.
459
459
460 Use -C/--clean to reset the working directory branch to that of
460 Use -C/--clean to reset the working directory branch to that of
461 the parent of the working directory, negating a previous branch
461 the parent of the working directory, negating a previous branch
462 change.
462 change.
463
463
464 Use the command :hg:`update` to switch to an existing branch. Use
464 Use the command :hg:`update` to switch to an existing branch. Use
465 :hg:`commit --close-branch` to mark this branch as closed.
465 :hg:`commit --close-branch` to mark this branch as closed.
466
466
467 Returns 0 on success.
467 Returns 0 on success.
468 """
468 """
469
469
470 if opts.get('clean'):
470 if opts.get('clean'):
471 label = repo[None].parents()[0].branch()
471 label = repo[None].parents()[0].branch()
472 repo.dirstate.setbranch(label)
472 repo.dirstate.setbranch(label)
473 ui.status(_('reset working directory to branch %s\n') % label)
473 ui.status(_('reset working directory to branch %s\n') % label)
474 elif label:
474 elif label:
475 utflabel = encoding.fromlocal(label)
475 utflabel = encoding.fromlocal(label)
476 if not opts.get('force') and utflabel in repo.branchtags():
476 if not opts.get('force') and utflabel in repo.branchtags():
477 if label not in [p.branch() for p in repo.parents()]:
477 if label not in [p.branch() for p in repo.parents()]:
478 raise util.Abort(_('a branch of the same name already exists'
478 raise util.Abort(_('a branch of the same name already exists'
479 " (use 'hg update' to switch to it)"))
479 " (use 'hg update' to switch to it)"))
480 repo.dirstate.setbranch(utflabel)
480 repo.dirstate.setbranch(utflabel)
481 ui.status(_('marked working directory as branch %s\n') % label)
481 ui.status(_('marked working directory as branch %s\n') % label)
482 else:
482 else:
483 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
483 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
484
484
485 def branches(ui, repo, active=False, closed=False):
485 def branches(ui, repo, active=False, closed=False):
486 """list repository named branches
486 """list repository named branches
487
487
488 List the repository's named branches, indicating which ones are
488 List the repository's named branches, indicating which ones are
489 inactive. If -c/--closed is specified, also list branches which have
489 inactive. If -c/--closed is specified, also list branches which have
490 been marked closed (see :hg:`commit --close-branch`).
490 been marked closed (see :hg:`commit --close-branch`).
491
491
492 If -a/--active is specified, only show active branches. A branch
492 If -a/--active is specified, only show active branches. A branch
493 is considered active if it contains repository heads.
493 is considered active if it contains repository heads.
494
494
495 Use the command :hg:`update` to switch to an existing branch.
495 Use the command :hg:`update` to switch to an existing branch.
496
496
497 Returns 0.
497 Returns 0.
498 """
498 """
499
499
500 hexfunc = ui.debugflag and hex or short
500 hexfunc = ui.debugflag and hex or short
501 activebranches = [repo[n].branch() for n in repo.heads()]
501 activebranches = [repo[n].branch() for n in repo.heads()]
502 def testactive(tag, node):
502 def testactive(tag, node):
503 realhead = tag in activebranches
503 realhead = tag in activebranches
504 open = node in repo.branchheads(tag, closed=False)
504 open = node in repo.branchheads(tag, closed=False)
505 return realhead and open
505 return realhead and open
506 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
506 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
507 for tag, node in repo.branchtags().items()],
507 for tag, node in repo.branchtags().items()],
508 reverse=True)
508 reverse=True)
509
509
510 for isactive, node, tag in branches:
510 for isactive, node, tag in branches:
511 if (not active) or isactive:
511 if (not active) or isactive:
512 encodedtag = encoding.tolocal(tag)
512 encodedtag = encoding.tolocal(tag)
513 if ui.quiet:
513 if ui.quiet:
514 ui.write("%s\n" % encodedtag)
514 ui.write("%s\n" % encodedtag)
515 else:
515 else:
516 hn = repo.lookup(node)
516 hn = repo.lookup(node)
517 if isactive:
517 if isactive:
518 label = 'branches.active'
518 label = 'branches.active'
519 notice = ''
519 notice = ''
520 elif hn not in repo.branchheads(tag, closed=False):
520 elif hn not in repo.branchheads(tag, closed=False):
521 if not closed:
521 if not closed:
522 continue
522 continue
523 label = 'branches.closed'
523 label = 'branches.closed'
524 notice = _(' (closed)')
524 notice = _(' (closed)')
525 else:
525 else:
526 label = 'branches.inactive'
526 label = 'branches.inactive'
527 notice = _(' (inactive)')
527 notice = _(' (inactive)')
528 if tag == repo.dirstate.branch():
528 if tag == repo.dirstate.branch():
529 label = 'branches.current'
529 label = 'branches.current'
530 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
530 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
531 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
531 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
532 encodedtag = ui.label(encodedtag, label)
532 encodedtag = ui.label(encodedtag, label)
533 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
533 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
534
534
535 def bundle(ui, repo, fname, dest=None, **opts):
535 def bundle(ui, repo, fname, dest=None, **opts):
536 """create a changegroup file
536 """create a changegroup file
537
537
538 Generate a compressed changegroup file collecting changesets not
538 Generate a compressed changegroup file collecting changesets not
539 known to be in another repository.
539 known to be in another repository.
540
540
541 If you omit the destination repository, then hg assumes the
541 If you omit the destination repository, then hg assumes the
542 destination will have all the nodes you specify with --base
542 destination will have all the nodes you specify with --base
543 parameters. To create a bundle containing all changesets, use
543 parameters. To create a bundle containing all changesets, use
544 -a/--all (or --base null).
544 -a/--all (or --base null).
545
545
546 You can change compression method with the -t/--type option.
546 You can change compression method with the -t/--type option.
547 The available compression methods are: none, bzip2, and
547 The available compression methods are: none, bzip2, and
548 gzip (by default, bundles are compressed using bzip2).
548 gzip (by default, bundles are compressed using bzip2).
549
549
550 The bundle file can then be transferred using conventional means
550 The bundle file can then be transferred using conventional means
551 and applied to another repository with the unbundle or pull
551 and applied to another repository with the unbundle or pull
552 command. This is useful when direct push and pull are not
552 command. This is useful when direct push and pull are not
553 available or when exporting an entire repository is undesirable.
553 available or when exporting an entire repository is undesirable.
554
554
555 Applying bundles preserves all changeset contents including
555 Applying bundles preserves all changeset contents including
556 permissions, copy/rename information, and revision history.
556 permissions, copy/rename information, and revision history.
557
557
558 Returns 0 on success, 1 if no changes found.
558 Returns 0 on success, 1 if no changes found.
559 """
559 """
560 revs = opts.get('rev') or None
560 revs = opts.get('rev') or None
561 if opts.get('all'):
561 if opts.get('all'):
562 base = ['null']
562 base = ['null']
563 else:
563 else:
564 base = opts.get('base')
564 base = opts.get('base')
565 if base:
565 if base:
566 if dest:
566 if dest:
567 raise util.Abort(_("--base is incompatible with specifying "
567 raise util.Abort(_("--base is incompatible with specifying "
568 "a destination"))
568 "a destination"))
569 base = [repo.lookup(rev) for rev in base]
569 base = [repo.lookup(rev) for rev in base]
570 # create the right base
570 # create the right base
571 # XXX: nodesbetween / changegroup* should be "fixed" instead
571 # XXX: nodesbetween / changegroup* should be "fixed" instead
572 o = []
572 o = []
573 has = set((nullid,))
573 has = set((nullid,))
574 for n in base:
574 for n in base:
575 has.update(repo.changelog.reachable(n))
575 has.update(repo.changelog.reachable(n))
576 if revs:
576 if revs:
577 revs = [repo.lookup(rev) for rev in revs]
577 revs = [repo.lookup(rev) for rev in revs]
578 visit = revs[:]
578 visit = revs[:]
579 has.difference_update(visit)
579 has.difference_update(visit)
580 else:
580 else:
581 visit = repo.changelog.heads()
581 visit = repo.changelog.heads()
582 seen = {}
582 seen = {}
583 while visit:
583 while visit:
584 n = visit.pop(0)
584 n = visit.pop(0)
585 parents = [p for p in repo.changelog.parents(n) if p not in has]
585 parents = [p for p in repo.changelog.parents(n) if p not in has]
586 if len(parents) == 0:
586 if len(parents) == 0:
587 if n not in has:
587 if n not in has:
588 o.append(n)
588 o.append(n)
589 else:
589 else:
590 for p in parents:
590 for p in parents:
591 if p not in seen:
591 if p not in seen:
592 seen[p] = 1
592 seen[p] = 1
593 visit.append(p)
593 visit.append(p)
594 else:
594 else:
595 dest = ui.expandpath(dest or 'default-push', dest or 'default')
595 dest = ui.expandpath(dest or 'default-push', dest or 'default')
596 dest, branches = hg.parseurl(dest, opts.get('branch'))
596 dest, branches = hg.parseurl(dest, opts.get('branch'))
597 other = hg.repository(hg.remoteui(repo, opts), dest)
597 other = hg.repository(hg.remoteui(repo, opts), dest)
598 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
598 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
599 if revs:
599 if revs:
600 revs = [repo.lookup(rev) for rev in revs]
600 revs = [repo.lookup(rev) for rev in revs]
601 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
601 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
602
602
603 if not o:
603 if not o:
604 ui.status(_("no changes found\n"))
604 ui.status(_("no changes found\n"))
605 return 1
605 return 1
606
606
607 if revs:
607 if revs:
608 cg = repo.changegroupsubset(o, revs, 'bundle')
608 cg = repo.changegroupsubset(o, revs, 'bundle')
609 else:
609 else:
610 cg = repo.changegroup(o, 'bundle')
610 cg = repo.changegroup(o, 'bundle')
611
611
612 bundletype = opts.get('type', 'bzip2').lower()
612 bundletype = opts.get('type', 'bzip2').lower()
613 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
613 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
614 bundletype = btypes.get(bundletype)
614 bundletype = btypes.get(bundletype)
615 if bundletype not in changegroup.bundletypes:
615 if bundletype not in changegroup.bundletypes:
616 raise util.Abort(_('unknown bundle type specified with --type'))
616 raise util.Abort(_('unknown bundle type specified with --type'))
617
617
618 changegroup.writebundle(cg, fname, bundletype)
618 changegroup.writebundle(cg, fname, bundletype)
619
619
620 def cat(ui, repo, file1, *pats, **opts):
620 def cat(ui, repo, file1, *pats, **opts):
621 """output the current or given revision of files
621 """output the current or given revision of files
622
622
623 Print the specified files as they were at the given revision. If
623 Print the specified files as they were at the given revision. If
624 no revision is given, the parent of the working directory is used,
624 no revision is given, the parent of the working directory is used,
625 or tip if no revision is checked out.
625 or tip if no revision is checked out.
626
626
627 Output may be to a file, in which case the name of the file is
627 Output may be to a file, in which case the name of the file is
628 given using a format string. The formatting rules are the same as
628 given using a format string. The formatting rules are the same as
629 for the export command, with the following additions:
629 for the export command, with the following additions:
630
630
631 :``%s``: basename of file being printed
631 :``%s``: basename of file being printed
632 :``%d``: dirname of file being printed, or '.' if in repository root
632 :``%d``: dirname of file being printed, or '.' if in repository root
633 :``%p``: root-relative path name of file being printed
633 :``%p``: root-relative path name of file being printed
634
634
635 Returns 0 on success.
635 Returns 0 on success.
636 """
636 """
637 ctx = cmdutil.revsingle(repo, opts.get('rev'))
637 ctx = cmdutil.revsingle(repo, opts.get('rev'))
638 err = 1
638 err = 1
639 m = cmdutil.match(repo, (file1,) + pats, opts)
639 m = cmdutil.match(repo, (file1,) + pats, opts)
640 for abs in ctx.walk(m):
640 for abs in ctx.walk(m):
641 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
641 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
642 data = ctx[abs].data()
642 data = ctx[abs].data()
643 if opts.get('decode'):
643 if opts.get('decode'):
644 data = repo.wwritedata(abs, data)
644 data = repo.wwritedata(abs, data)
645 fp.write(data)
645 fp.write(data)
646 err = 0
646 err = 0
647 return err
647 return err
648
648
649 def clone(ui, source, dest=None, **opts):
649 def clone(ui, source, dest=None, **opts):
650 """make a copy of an existing repository
650 """make a copy of an existing repository
651
651
652 Create a copy of an existing repository in a new directory.
652 Create a copy of an existing repository in a new directory.
653
653
654 If no destination directory name is specified, it defaults to the
654 If no destination directory name is specified, it defaults to the
655 basename of the source.
655 basename of the source.
656
656
657 The location of the source is added to the new repository's
657 The location of the source is added to the new repository's
658 .hg/hgrc file, as the default to be used for future pulls.
658 .hg/hgrc file, as the default to be used for future pulls.
659
659
660 See :hg:`help urls` for valid source format details.
660 See :hg:`help urls` for valid source format details.
661
661
662 It is possible to specify an ``ssh://`` URL as the destination, but no
662 It is possible to specify an ``ssh://`` URL as the destination, but no
663 .hg/hgrc and working directory will be created on the remote side.
663 .hg/hgrc and working directory will be created on the remote side.
664 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
664 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
665
665
666 A set of changesets (tags, or branch names) to pull may be specified
666 A set of changesets (tags, or branch names) to pull may be specified
667 by listing each changeset (tag, or branch name) with -r/--rev.
667 by listing each changeset (tag, or branch name) with -r/--rev.
668 If -r/--rev is used, the cloned repository will contain only a subset
668 If -r/--rev is used, the cloned repository will contain only a subset
669 of the changesets of the source repository. Only the set of changesets
669 of the changesets of the source repository. Only the set of changesets
670 defined by all -r/--rev options (including all their ancestors)
670 defined by all -r/--rev options (including all their ancestors)
671 will be pulled into the destination repository.
671 will be pulled into the destination repository.
672 No subsequent changesets (including subsequent tags) will be present
672 No subsequent changesets (including subsequent tags) will be present
673 in the destination.
673 in the destination.
674
674
675 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
675 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
676 local source repositories.
676 local source repositories.
677
677
678 For efficiency, hardlinks are used for cloning whenever the source
678 For efficiency, hardlinks are used for cloning whenever the source
679 and destination are on the same filesystem (note this applies only
679 and destination are on the same filesystem (note this applies only
680 to the repository data, not to the working directory). Some
680 to the repository data, not to the working directory). Some
681 filesystems, such as AFS, implement hardlinking incorrectly, but
681 filesystems, such as AFS, implement hardlinking incorrectly, but
682 do not report errors. In these cases, use the --pull option to
682 do not report errors. In these cases, use the --pull option to
683 avoid hardlinking.
683 avoid hardlinking.
684
684
685 In some cases, you can clone repositories and the working directory
685 In some cases, you can clone repositories and the working directory
686 using full hardlinks with ::
686 using full hardlinks with ::
687
687
688 $ cp -al REPO REPOCLONE
688 $ cp -al REPO REPOCLONE
689
689
690 This is the fastest way to clone, but it is not always safe. The
690 This is the fastest way to clone, but it is not always safe. The
691 operation is not atomic (making sure REPO is not modified during
691 operation is not atomic (making sure REPO is not modified during
692 the operation is up to you) and you have to make sure your editor
692 the operation is up to you) and you have to make sure your editor
693 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
693 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
694 this is not compatible with certain extensions that place their
694 this is not compatible with certain extensions that place their
695 metadata under the .hg directory, such as mq.
695 metadata under the .hg directory, such as mq.
696
696
697 Mercurial will update the working directory to the first applicable
697 Mercurial will update the working directory to the first applicable
698 revision from this list:
698 revision from this list:
699
699
700 a) null if -U or the source repository has no changesets
700 a) null if -U or the source repository has no changesets
701 b) if -u . and the source repository is local, the first parent of
701 b) if -u . and the source repository is local, the first parent of
702 the source repository's working directory
702 the source repository's working directory
703 c) the changeset specified with -u (if a branch name, this means the
703 c) the changeset specified with -u (if a branch name, this means the
704 latest head of that branch)
704 latest head of that branch)
705 d) the changeset specified with -r
705 d) the changeset specified with -r
706 e) the tipmost head specified with -b
706 e) the tipmost head specified with -b
707 f) the tipmost head specified with the url#branch source syntax
707 f) the tipmost head specified with the url#branch source syntax
708 g) the tipmost head of the default branch
708 g) the tipmost head of the default branch
709 h) tip
709 h) tip
710
710
711 Returns 0 on success.
711 Returns 0 on success.
712 """
712 """
713 if opts.get('noupdate') and opts.get('updaterev'):
713 if opts.get('noupdate') and opts.get('updaterev'):
714 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
714 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
715
715
716 r = hg.clone(hg.remoteui(ui, opts), source, dest,
716 r = hg.clone(hg.remoteui(ui, opts), source, dest,
717 pull=opts.get('pull'),
717 pull=opts.get('pull'),
718 stream=opts.get('uncompressed'),
718 stream=opts.get('uncompressed'),
719 rev=opts.get('rev'),
719 rev=opts.get('rev'),
720 update=opts.get('updaterev') or not opts.get('noupdate'),
720 update=opts.get('updaterev') or not opts.get('noupdate'),
721 branch=opts.get('branch'))
721 branch=opts.get('branch'))
722
722
723 return r is None
723 return r is None
724
724
725 def commit(ui, repo, *pats, **opts):
725 def commit(ui, repo, *pats, **opts):
726 """commit the specified files or all outstanding changes
726 """commit the specified files or all outstanding changes
727
727
728 Commit changes to the given files into the repository. Unlike a
728 Commit changes to the given files into the repository. Unlike a
729 centralized RCS, this operation is a local operation. See
729 centralized RCS, this operation is a local operation. See
730 :hg:`push` for a way to actively distribute your changes.
730 :hg:`push` for a way to actively distribute your changes.
731
731
732 If a list of files is omitted, all changes reported by :hg:`status`
732 If a list of files is omitted, all changes reported by :hg:`status`
733 will be committed.
733 will be committed.
734
734
735 If you are committing the result of a merge, do not provide any
735 If you are committing the result of a merge, do not provide any
736 filenames or -I/-X filters.
736 filenames or -I/-X filters.
737
737
738 If no commit message is specified, Mercurial starts your
738 If no commit message is specified, Mercurial starts your
739 configured editor where you can enter a message. In case your
739 configured editor where you can enter a message. In case your
740 commit fails, you will find a backup of your message in
740 commit fails, you will find a backup of your message in
741 ``.hg/last-message.txt``.
741 ``.hg/last-message.txt``.
742
742
743 See :hg:`help dates` for a list of formats valid for -d/--date.
743 See :hg:`help dates` for a list of formats valid for -d/--date.
744
744
745 Returns 0 on success, 1 if nothing changed.
745 Returns 0 on success, 1 if nothing changed.
746 """
746 """
747 extra = {}
747 extra = {}
748 if opts.get('close_branch'):
748 if opts.get('close_branch'):
749 if repo['.'].node() not in repo.branchheads():
749 if repo['.'].node() not in repo.branchheads():
750 # The topo heads set is included in the branch heads set of the
750 # The topo heads set is included in the branch heads set of the
751 # current branch, so it's sufficient to test branchheads
751 # current branch, so it's sufficient to test branchheads
752 raise util.Abort(_('can only close branch heads'))
752 raise util.Abort(_('can only close branch heads'))
753 extra['close'] = 1
753 extra['close'] = 1
754 e = cmdutil.commiteditor
754 e = cmdutil.commiteditor
755 if opts.get('force_editor'):
755 if opts.get('force_editor'):
756 e = cmdutil.commitforceeditor
756 e = cmdutil.commitforceeditor
757
757
758 def commitfunc(ui, repo, message, match, opts):
758 def commitfunc(ui, repo, message, match, opts):
759 return repo.commit(message, opts.get('user'), opts.get('date'), match,
759 return repo.commit(message, opts.get('user'), opts.get('date'), match,
760 editor=e, extra=extra)
760 editor=e, extra=extra)
761
761
762 branch = repo[None].branch()
762 branch = repo[None].branch()
763 bheads = repo.branchheads(branch)
763 bheads = repo.branchheads(branch)
764
764
765 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
765 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
766 if not node:
766 if not node:
767 ui.status(_("nothing changed\n"))
767 ui.status(_("nothing changed\n"))
768 return 1
768 return 1
769
769
770 ctx = repo[node]
770 ctx = repo[node]
771 parents = ctx.parents()
771 parents = ctx.parents()
772
772
773 if bheads and not [x for x in parents
773 if bheads and not [x for x in parents
774 if x.node() in bheads and x.branch() == branch]:
774 if x.node() in bheads and x.branch() == branch]:
775 ui.status(_('created new head\n'))
775 ui.status(_('created new head\n'))
776 # The message is not printed for initial roots. For the other
776 # The message is not printed for initial roots. For the other
777 # changesets, it is printed in the following situations:
777 # changesets, it is printed in the following situations:
778 #
778 #
779 # Par column: for the 2 parents with ...
779 # Par column: for the 2 parents with ...
780 # N: null or no parent
780 # N: null or no parent
781 # B: parent is on another named branch
781 # B: parent is on another named branch
782 # C: parent is a regular non head changeset
782 # C: parent is a regular non head changeset
783 # H: parent was a branch head of the current branch
783 # H: parent was a branch head of the current branch
784 # Msg column: whether we print "created new head" message
784 # Msg column: whether we print "created new head" message
785 # In the following, it is assumed that there already exists some
785 # In the following, it is assumed that there already exists some
786 # initial branch heads of the current branch, otherwise nothing is
786 # initial branch heads of the current branch, otherwise nothing is
787 # printed anyway.
787 # printed anyway.
788 #
788 #
789 # Par Msg Comment
789 # Par Msg Comment
790 # NN y additional topo root
790 # NN y additional topo root
791 #
791 #
792 # BN y additional branch root
792 # BN y additional branch root
793 # CN y additional topo head
793 # CN y additional topo head
794 # HN n usual case
794 # HN n usual case
795 #
795 #
796 # BB y weird additional branch root
796 # BB y weird additional branch root
797 # CB y branch merge
797 # CB y branch merge
798 # HB n merge with named branch
798 # HB n merge with named branch
799 #
799 #
800 # CC y additional head from merge
800 # CC y additional head from merge
801 # CH n merge with a head
801 # CH n merge with a head
802 #
802 #
803 # HH n head merge: head count decreases
803 # HH n head merge: head count decreases
804
804
805 if not opts.get('close_branch'):
805 if not opts.get('close_branch'):
806 for r in parents:
806 for r in parents:
807 if r.extra().get('close') and r.branch() == branch:
807 if r.extra().get('close') and r.branch() == branch:
808 ui.status(_('reopening closed branch head %d\n') % r)
808 ui.status(_('reopening closed branch head %d\n') % r)
809
809
810 if ui.debugflag:
810 if ui.debugflag:
811 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
811 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
812 elif ui.verbose:
812 elif ui.verbose:
813 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
813 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
814
814
815 def copy(ui, repo, *pats, **opts):
815 def copy(ui, repo, *pats, **opts):
816 """mark files as copied for the next commit
816 """mark files as copied for the next commit
817
817
818 Mark dest as having copies of source files. If dest is a
818 Mark dest as having copies of source files. If dest is a
819 directory, copies are put in that directory. If dest is a file,
819 directory, copies are put in that directory. If dest is a file,
820 the source must be a single file.
820 the source must be a single file.
821
821
822 By default, this command copies the contents of files as they
822 By default, this command copies the contents of files as they
823 exist in the working directory. If invoked with -A/--after, the
823 exist in the working directory. If invoked with -A/--after, the
824 operation is recorded, but no copying is performed.
824 operation is recorded, but no copying is performed.
825
825
826 This command takes effect with the next commit. To undo a copy
826 This command takes effect with the next commit. To undo a copy
827 before that, see :hg:`revert`.
827 before that, see :hg:`revert`.
828
828
829 Returns 0 on success, 1 if errors are encountered.
829 Returns 0 on success, 1 if errors are encountered.
830 """
830 """
831 wlock = repo.wlock(False)
831 wlock = repo.wlock(False)
832 try:
832 try:
833 return cmdutil.copy(ui, repo, pats, opts)
833 return cmdutil.copy(ui, repo, pats, opts)
834 finally:
834 finally:
835 wlock.release()
835 wlock.release()
836
836
837 def debugancestor(ui, repo, *args):
837 def debugancestor(ui, repo, *args):
838 """find the ancestor revision of two revisions in a given index"""
838 """find the ancestor revision of two revisions in a given index"""
839 if len(args) == 3:
839 if len(args) == 3:
840 index, rev1, rev2 = args
840 index, rev1, rev2 = args
841 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
841 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
842 lookup = r.lookup
842 lookup = r.lookup
843 elif len(args) == 2:
843 elif len(args) == 2:
844 if not repo:
844 if not repo:
845 raise util.Abort(_("there is no Mercurial repository here "
845 raise util.Abort(_("there is no Mercurial repository here "
846 "(.hg not found)"))
846 "(.hg not found)"))
847 rev1, rev2 = args
847 rev1, rev2 = args
848 r = repo.changelog
848 r = repo.changelog
849 lookup = repo.lookup
849 lookup = repo.lookup
850 else:
850 else:
851 raise util.Abort(_('either two or three arguments required'))
851 raise util.Abort(_('either two or three arguments required'))
852 a = r.ancestor(lookup(rev1), lookup(rev2))
852 a = r.ancestor(lookup(rev1), lookup(rev2))
853 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
853 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
854
854
855 def debugbuilddag(ui, repo, text,
855 def debugbuilddag(ui, repo, text,
856 mergeable_file=False,
856 mergeable_file=False,
857 appended_file=False,
857 appended_file=False,
858 overwritten_file=False,
858 overwritten_file=False,
859 new_file=False):
859 new_file=False):
860 """builds a repo with a given dag from scratch in the current empty repo
860 """builds a repo with a given dag from scratch in the current empty repo
861
861
862 Elements:
862 Elements:
863
863
864 - "+n" is a linear run of n nodes based on the current default parent
864 - "+n" is a linear run of n nodes based on the current default parent
865 - "." is a single node based on the current default parent
865 - "." is a single node based on the current default parent
866 - "$" resets the default parent to null (implied at the start);
866 - "$" resets the default parent to null (implied at the start);
867 otherwise the default parent is always the last node created
867 otherwise the default parent is always the last node created
868 - "<p" sets the default parent to the backref p
868 - "<p" sets the default parent to the backref p
869 - "*p" is a fork at parent p, which is a backref
869 - "*p" is a fork at parent p, which is a backref
870 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
870 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
871 - "/p2" is a merge of the preceding node and p2
871 - "/p2" is a merge of the preceding node and p2
872 - ":tag" defines a local tag for the preceding node
872 - ":tag" defines a local tag for the preceding node
873 - "@branch" sets the named branch for subsequent nodes
873 - "@branch" sets the named branch for subsequent nodes
874 - "!command" runs the command using your shell
874 - "!command" runs the command using your shell
875 - "!!my command\\n" is like "!", but to the end of the line
875 - "!!my command\\n" is like "!", but to the end of the line
876 - "#...\\n" is a comment up to the end of the line
876 - "#...\\n" is a comment up to the end of the line
877
877
878 Whitespace between the above elements is ignored.
878 Whitespace between the above elements is ignored.
879
879
880 A backref is either
880 A backref is either
881
881
882 - a number n, which references the node curr-n, where curr is the current
882 - a number n, which references the node curr-n, where curr is the current
883 node, or
883 node, or
884 - the name of a local tag you placed earlier using ":tag", or
884 - the name of a local tag you placed earlier using ":tag", or
885 - empty to denote the default parent.
885 - empty to denote the default parent.
886
886
887 All string valued-elements are either strictly alphanumeric, or must
887 All string valued-elements are either strictly alphanumeric, or must
888 be enclosed in double quotes ("..."), with "\\" as escape character.
888 be enclosed in double quotes ("..."), with "\\" as escape character.
889
889
890 Note that the --overwritten-file and --appended-file options imply the
890 Note that the --overwritten-file and --appended-file options imply the
891 use of "HGMERGE=internal:local" during DAG buildup.
891 use of "HGMERGE=internal:local" during DAG buildup.
892 """
892 """
893
893
894 if not (mergeable_file or appended_file or overwritten_file or new_file):
894 if not (mergeable_file or appended_file or overwritten_file or new_file):
895 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
895 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
896
896
897 if len(repo.changelog) > 0:
897 if len(repo.changelog) > 0:
898 raise util.Abort(_('repository is not empty'))
898 raise util.Abort(_('repository is not empty'))
899
899
900 if overwritten_file or appended_file:
900 if overwritten_file or appended_file:
901 # we don't want to fail in merges during buildup
901 # we don't want to fail in merges during buildup
902 os.environ['HGMERGE'] = 'internal:local'
902 os.environ['HGMERGE'] = 'internal:local'
903
903
904 def writefile(fname, text, fmode="wb"):
904 def writefile(fname, text, fmode="wb"):
905 f = open(fname, fmode)
905 f = open(fname, fmode)
906 try:
906 try:
907 f.write(text)
907 f.write(text)
908 finally:
908 finally:
909 f.close()
909 f.close()
910
910
911 if mergeable_file:
911 if mergeable_file:
912 linesperrev = 2
912 linesperrev = 2
913 # determine number of revs in DAG
913 # determine number of revs in DAG
914 n = 0
914 n = 0
915 for type, data in dagparser.parsedag(text):
915 for type, data in dagparser.parsedag(text):
916 if type == 'n':
916 if type == 'n':
917 n += 1
917 n += 1
918 # make a file with k lines per rev
918 # make a file with k lines per rev
919 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
919 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
920 + "\n")
920 + "\n")
921
921
922 at = -1
922 at = -1
923 atbranch = 'default'
923 atbranch = 'default'
924 for type, data in dagparser.parsedag(text):
924 for type, data in dagparser.parsedag(text):
925 if type == 'n':
925 if type == 'n':
926 ui.status('node %s\n' % str(data))
926 ui.status('node %s\n' % str(data))
927 id, ps = data
927 id, ps = data
928 p1 = ps[0]
928 p1 = ps[0]
929 if p1 != at:
929 if p1 != at:
930 update(ui, repo, node=p1, clean=True)
930 update(ui, repo, node=p1, clean=True)
931 at = p1
931 at = p1
932 if repo.dirstate.branch() != atbranch:
932 if repo.dirstate.branch() != atbranch:
933 branch(ui, repo, atbranch, force=True)
933 branch(ui, repo, atbranch, force=True)
934 if len(ps) > 1:
934 if len(ps) > 1:
935 p2 = ps[1]
935 p2 = ps[1]
936 merge(ui, repo, node=p2)
936 merge(ui, repo, node=p2)
937
937
938 if mergeable_file:
938 if mergeable_file:
939 f = open("mf", "rb+")
939 f = open("mf", "rb+")
940 try:
940 try:
941 lines = f.read().split("\n")
941 lines = f.read().split("\n")
942 lines[id * linesperrev] += " r%i" % id
942 lines[id * linesperrev] += " r%i" % id
943 f.seek(0)
943 f.seek(0)
944 f.write("\n".join(lines))
944 f.write("\n".join(lines))
945 finally:
945 finally:
946 f.close()
946 f.close()
947
947
948 if appended_file:
948 if appended_file:
949 writefile("af", "r%i\n" % id, "ab")
949 writefile("af", "r%i\n" % id, "ab")
950
950
951 if overwritten_file:
951 if overwritten_file:
952 writefile("of", "r%i\n" % id)
952 writefile("of", "r%i\n" % id)
953
953
954 if new_file:
954 if new_file:
955 writefile("nf%i" % id, "r%i\n" % id)
955 writefile("nf%i" % id, "r%i\n" % id)
956
956
957 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
957 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
958 at = id
958 at = id
959 elif type == 'l':
959 elif type == 'l':
960 id, name = data
960 id, name = data
961 ui.status('tag %s\n' % name)
961 ui.status('tag %s\n' % name)
962 tag(ui, repo, name, local=True)
962 tag(ui, repo, name, local=True)
963 elif type == 'a':
963 elif type == 'a':
964 ui.status('branch %s\n' % data)
964 ui.status('branch %s\n' % data)
965 atbranch = data
965 atbranch = data
966 elif type in 'cC':
966 elif type in 'cC':
967 r = util.system(data, cwd=repo.root)
967 r = util.system(data, cwd=repo.root)
968 if r:
968 if r:
969 desc, r = util.explain_exit(r)
969 desc, r = util.explain_exit(r)
970 raise util.Abort(_('%s command %s') % (data, desc))
970 raise util.Abort(_('%s command %s') % (data, desc))
971
971
972 def debugcommands(ui, cmd='', *args):
972 def debugcommands(ui, cmd='', *args):
973 """list all available commands and options"""
973 """list all available commands and options"""
974 for cmd, vals in sorted(table.iteritems()):
974 for cmd, vals in sorted(table.iteritems()):
975 cmd = cmd.split('|')[0].strip('^')
975 cmd = cmd.split('|')[0].strip('^')
976 opts = ', '.join([i[1] for i in vals[1]])
976 opts = ', '.join([i[1] for i in vals[1]])
977 ui.write('%s: %s\n' % (cmd, opts))
977 ui.write('%s: %s\n' % (cmd, opts))
978
978
979 def debugcomplete(ui, cmd='', **opts):
979 def debugcomplete(ui, cmd='', **opts):
980 """returns the completion list associated with the given command"""
980 """returns the completion list associated with the given command"""
981
981
982 if opts.get('options'):
982 if opts.get('options'):
983 options = []
983 options = []
984 otables = [globalopts]
984 otables = [globalopts]
985 if cmd:
985 if cmd:
986 aliases, entry = cmdutil.findcmd(cmd, table, False)
986 aliases, entry = cmdutil.findcmd(cmd, table, False)
987 otables.append(entry[1])
987 otables.append(entry[1])
988 for t in otables:
988 for t in otables:
989 for o in t:
989 for o in t:
990 if "(DEPRECATED)" in o[3]:
990 if "(DEPRECATED)" in o[3]:
991 continue
991 continue
992 if o[0]:
992 if o[0]:
993 options.append('-%s' % o[0])
993 options.append('-%s' % o[0])
994 options.append('--%s' % o[1])
994 options.append('--%s' % o[1])
995 ui.write("%s\n" % "\n".join(options))
995 ui.write("%s\n" % "\n".join(options))
996 return
996 return
997
997
998 cmdlist = cmdutil.findpossible(cmd, table)
998 cmdlist = cmdutil.findpossible(cmd, table)
999 if ui.verbose:
999 if ui.verbose:
1000 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1000 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1001 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1001 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1002
1002
1003 def debugfsinfo(ui, path = "."):
1003 def debugfsinfo(ui, path = "."):
1004 """show information detected about current filesystem"""
1004 """show information detected about current filesystem"""
1005 open('.debugfsinfo', 'w').write('')
1005 open('.debugfsinfo', 'w').write('')
1006 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1006 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1007 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1007 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1008 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1008 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1009 and 'yes' or 'no'))
1009 and 'yes' or 'no'))
1010 os.unlink('.debugfsinfo')
1010 os.unlink('.debugfsinfo')
1011
1011
1012 def debugrebuildstate(ui, repo, rev="tip"):
1012 def debugrebuildstate(ui, repo, rev="tip"):
1013 """rebuild the dirstate as it would look like for the given revision"""
1013 """rebuild the dirstate as it would look like for the given revision"""
1014 ctx = repo[rev]
1014 ctx = repo[rev]
1015 wlock = repo.wlock()
1015 wlock = repo.wlock()
1016 try:
1016 try:
1017 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1017 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1018 finally:
1018 finally:
1019 wlock.release()
1019 wlock.release()
1020
1020
1021 def debugcheckstate(ui, repo):
1021 def debugcheckstate(ui, repo):
1022 """validate the correctness of the current dirstate"""
1022 """validate the correctness of the current dirstate"""
1023 parent1, parent2 = repo.dirstate.parents()
1023 parent1, parent2 = repo.dirstate.parents()
1024 m1 = repo[parent1].manifest()
1024 m1 = repo[parent1].manifest()
1025 m2 = repo[parent2].manifest()
1025 m2 = repo[parent2].manifest()
1026 errors = 0
1026 errors = 0
1027 for f in repo.dirstate:
1027 for f in repo.dirstate:
1028 state = repo.dirstate[f]
1028 state = repo.dirstate[f]
1029 if state in "nr" and f not in m1:
1029 if state in "nr" and f not in m1:
1030 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1030 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1031 errors += 1
1031 errors += 1
1032 if state in "a" and f in m1:
1032 if state in "a" and f in m1:
1033 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1033 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1034 errors += 1
1034 errors += 1
1035 if state in "m" and f not in m1 and f not in m2:
1035 if state in "m" and f not in m1 and f not in m2:
1036 ui.warn(_("%s in state %s, but not in either manifest\n") %
1036 ui.warn(_("%s in state %s, but not in either manifest\n") %
1037 (f, state))
1037 (f, state))
1038 errors += 1
1038 errors += 1
1039 for f in m1:
1039 for f in m1:
1040 state = repo.dirstate[f]
1040 state = repo.dirstate[f]
1041 if state not in "nrm":
1041 if state not in "nrm":
1042 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1042 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1043 errors += 1
1043 errors += 1
1044 if errors:
1044 if errors:
1045 error = _(".hg/dirstate inconsistent with current parent's manifest")
1045 error = _(".hg/dirstate inconsistent with current parent's manifest")
1046 raise util.Abort(error)
1046 raise util.Abort(error)
1047
1047
1048 def showconfig(ui, repo, *values, **opts):
1048 def showconfig(ui, repo, *values, **opts):
1049 """show combined config settings from all hgrc files
1049 """show combined config settings from all hgrc files
1050
1050
1051 With no arguments, print names and values of all config items.
1051 With no arguments, print names and values of all config items.
1052
1052
1053 With one argument of the form section.name, print just the value
1053 With one argument of the form section.name, print just the value
1054 of that config item.
1054 of that config item.
1055
1055
1056 With multiple arguments, print names and values of all config
1056 With multiple arguments, print names and values of all config
1057 items with matching section names.
1057 items with matching section names.
1058
1058
1059 With --debug, the source (filename and line number) is printed
1059 With --debug, the source (filename and line number) is printed
1060 for each config item.
1060 for each config item.
1061
1061
1062 Returns 0 on success.
1062 Returns 0 on success.
1063 """
1063 """
1064
1064
1065 for f in util.rcpath():
1065 for f in util.rcpath():
1066 ui.debug(_('read config from: %s\n') % f)
1066 ui.debug(_('read config from: %s\n') % f)
1067 untrusted = bool(opts.get('untrusted'))
1067 untrusted = bool(opts.get('untrusted'))
1068 if values:
1068 if values:
1069 sections = [v for v in values if '.' not in v]
1069 sections = [v for v in values if '.' not in v]
1070 items = [v for v in values if '.' in v]
1070 items = [v for v in values if '.' in v]
1071 if len(items) > 1 or items and sections:
1071 if len(items) > 1 or items and sections:
1072 raise util.Abort(_('only one config item permitted'))
1072 raise util.Abort(_('only one config item permitted'))
1073 for section, name, value in ui.walkconfig(untrusted=untrusted):
1073 for section, name, value in ui.walkconfig(untrusted=untrusted):
1074 sectname = section + '.' + name
1074 sectname = section + '.' + name
1075 if values:
1075 if values:
1076 for v in values:
1076 for v in values:
1077 if v == section:
1077 if v == section:
1078 ui.debug('%s: ' %
1078 ui.debug('%s: ' %
1079 ui.configsource(section, name, untrusted))
1079 ui.configsource(section, name, untrusted))
1080 ui.write('%s=%s\n' % (sectname, value))
1080 ui.write('%s=%s\n' % (sectname, value))
1081 elif v == sectname:
1081 elif v == sectname:
1082 ui.debug('%s: ' %
1082 ui.debug('%s: ' %
1083 ui.configsource(section, name, untrusted))
1083 ui.configsource(section, name, untrusted))
1084 ui.write(value, '\n')
1084 ui.write(value, '\n')
1085 else:
1085 else:
1086 ui.debug('%s: ' %
1086 ui.debug('%s: ' %
1087 ui.configsource(section, name, untrusted))
1087 ui.configsource(section, name, untrusted))
1088 ui.write('%s=%s\n' % (sectname, value))
1088 ui.write('%s=%s\n' % (sectname, value))
1089
1089
1090 def debugpushkey(ui, repopath, namespace, *keyinfo):
1090 def debugpushkey(ui, repopath, namespace, *keyinfo):
1091 '''access the pushkey key/value protocol
1091 '''access the pushkey key/value protocol
1092
1092
1093 With two args, list the keys in the given namespace.
1093 With two args, list the keys in the given namespace.
1094
1094
1095 With five args, set a key to new if it currently is set to old.
1095 With five args, set a key to new if it currently is set to old.
1096 Reports success or failure.
1096 Reports success or failure.
1097 '''
1097 '''
1098
1098
1099 target = hg.repository(ui, repopath)
1099 target = hg.repository(ui, repopath)
1100 if keyinfo:
1100 if keyinfo:
1101 key, old, new = keyinfo
1101 key, old, new = keyinfo
1102 r = target.pushkey(namespace, key, old, new)
1102 r = target.pushkey(namespace, key, old, new)
1103 ui.status(str(r) + '\n')
1103 ui.status(str(r) + '\n')
1104 return not(r)
1104 return not(r)
1105 else:
1105 else:
1106 for k, v in target.listkeys(namespace).iteritems():
1106 for k, v in target.listkeys(namespace).iteritems():
1107 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1107 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1108 v.encode('string-escape')))
1108 v.encode('string-escape')))
1109
1109
1110 def debugrevspec(ui, repo, expr):
1110 def debugrevspec(ui, repo, expr):
1111 '''parse and apply a revision specification'''
1111 '''parse and apply a revision specification'''
1112 if ui.verbose:
1112 if ui.verbose:
1113 tree = revset.parse(expr)
1113 tree = revset.parse(expr)
1114 ui.note(tree, "\n")
1114 ui.note(tree, "\n")
1115 func = revset.match(expr)
1115 func = revset.match(expr)
1116 for c in func(repo, range(len(repo))):
1116 for c in func(repo, range(len(repo))):
1117 ui.write("%s\n" % c)
1117 ui.write("%s\n" % c)
1118
1118
1119 def debugsetparents(ui, repo, rev1, rev2=None):
1119 def debugsetparents(ui, repo, rev1, rev2=None):
1120 """manually set the parents of the current working directory
1120 """manually set the parents of the current working directory
1121
1121
1122 This is useful for writing repository conversion tools, but should
1122 This is useful for writing repository conversion tools, but should
1123 be used with care.
1123 be used with care.
1124
1124
1125 Returns 0 on success.
1125 Returns 0 on success.
1126 """
1126 """
1127
1127
1128 if not rev2:
1128 if not rev2:
1129 rev2 = hex(nullid)
1129 rev2 = hex(nullid)
1130
1130
1131 wlock = repo.wlock()
1131 wlock = repo.wlock()
1132 try:
1132 try:
1133 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1133 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1134 finally:
1134 finally:
1135 wlock.release()
1135 wlock.release()
1136
1136
1137 def debugstate(ui, repo, nodates=None):
1137 def debugstate(ui, repo, nodates=None):
1138 """show the contents of the current dirstate"""
1138 """show the contents of the current dirstate"""
1139 timestr = ""
1139 timestr = ""
1140 showdate = not nodates
1140 showdate = not nodates
1141 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1141 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1142 if showdate:
1142 if showdate:
1143 if ent[3] == -1:
1143 if ent[3] == -1:
1144 # Pad or slice to locale representation
1144 # Pad or slice to locale representation
1145 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1145 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1146 time.localtime(0)))
1146 time.localtime(0)))
1147 timestr = 'unset'
1147 timestr = 'unset'
1148 timestr = (timestr[:locale_len] +
1148 timestr = (timestr[:locale_len] +
1149 ' ' * (locale_len - len(timestr)))
1149 ' ' * (locale_len - len(timestr)))
1150 else:
1150 else:
1151 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1151 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1152 time.localtime(ent[3]))
1152 time.localtime(ent[3]))
1153 if ent[1] & 020000:
1153 if ent[1] & 020000:
1154 mode = 'lnk'
1154 mode = 'lnk'
1155 else:
1155 else:
1156 mode = '%3o' % (ent[1] & 0777)
1156 mode = '%3o' % (ent[1] & 0777)
1157 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1157 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1158 for f in repo.dirstate.copies():
1158 for f in repo.dirstate.copies():
1159 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1159 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1160
1160
1161 def debugsub(ui, repo, rev=None):
1161 def debugsub(ui, repo, rev=None):
1162 if rev == '':
1162 if rev == '':
1163 rev = None
1163 rev = None
1164 for k, v in sorted(repo[rev].substate.items()):
1164 for k, v in sorted(repo[rev].substate.items()):
1165 ui.write('path %s\n' % k)
1165 ui.write('path %s\n' % k)
1166 ui.write(' source %s\n' % v[0])
1166 ui.write(' source %s\n' % v[0])
1167 ui.write(' revision %s\n' % v[1])
1167 ui.write(' revision %s\n' % v[1])
1168
1168
1169 def debugdag(ui, repo, file_=None, *revs, **opts):
1169 def debugdag(ui, repo, file_=None, *revs, **opts):
1170 """format the changelog or an index DAG as a concise textual description
1170 """format the changelog or an index DAG as a concise textual description
1171
1171
1172 If you pass a revlog index, the revlog's DAG is emitted. If you list
1172 If you pass a revlog index, the revlog's DAG is emitted. If you list
1173 revision numbers, they get labelled in the output as rN.
1173 revision numbers, they get labelled in the output as rN.
1174
1174
1175 Otherwise, the changelog DAG of the current repo is emitted.
1175 Otherwise, the changelog DAG of the current repo is emitted.
1176 """
1176 """
1177 spaces = opts.get('spaces')
1177 spaces = opts.get('spaces')
1178 dots = opts.get('dots')
1178 dots = opts.get('dots')
1179 if file_:
1179 if file_:
1180 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1180 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1181 revs = set((int(r) for r in revs))
1181 revs = set((int(r) for r in revs))
1182 def events():
1182 def events():
1183 for r in rlog:
1183 for r in rlog:
1184 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1184 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1185 if r in revs:
1185 if r in revs:
1186 yield 'l', (r, "r%i" % r)
1186 yield 'l', (r, "r%i" % r)
1187 elif repo:
1187 elif repo:
1188 cl = repo.changelog
1188 cl = repo.changelog
1189 tags = opts.get('tags')
1189 tags = opts.get('tags')
1190 branches = opts.get('branches')
1190 branches = opts.get('branches')
1191 if tags:
1191 if tags:
1192 labels = {}
1192 labels = {}
1193 for l, n in repo.tags().items():
1193 for l, n in repo.tags().items():
1194 labels.setdefault(cl.rev(n), []).append(l)
1194 labels.setdefault(cl.rev(n), []).append(l)
1195 def events():
1195 def events():
1196 b = "default"
1196 b = "default"
1197 for r in cl:
1197 for r in cl:
1198 if branches:
1198 if branches:
1199 newb = cl.read(cl.node(r))[5]['branch']
1199 newb = cl.read(cl.node(r))[5]['branch']
1200 if newb != b:
1200 if newb != b:
1201 yield 'a', newb
1201 yield 'a', newb
1202 b = newb
1202 b = newb
1203 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1203 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1204 if tags:
1204 if tags:
1205 ls = labels.get(r)
1205 ls = labels.get(r)
1206 if ls:
1206 if ls:
1207 for l in ls:
1207 for l in ls:
1208 yield 'l', (r, l)
1208 yield 'l', (r, l)
1209 else:
1209 else:
1210 raise util.Abort(_('need repo for changelog dag'))
1210 raise util.Abort(_('need repo for changelog dag'))
1211
1211
1212 for line in dagparser.dagtextlines(events(),
1212 for line in dagparser.dagtextlines(events(),
1213 addspaces=spaces,
1213 addspaces=spaces,
1214 wraplabels=True,
1214 wraplabels=True,
1215 wrapannotations=True,
1215 wrapannotations=True,
1216 wrapnonlinear=dots,
1216 wrapnonlinear=dots,
1217 usedots=dots,
1217 usedots=dots,
1218 maxlinewidth=70):
1218 maxlinewidth=70):
1219 ui.write(line)
1219 ui.write(line)
1220 ui.write("\n")
1220 ui.write("\n")
1221
1221
1222 def debugdata(ui, repo, file_, rev):
1222 def debugdata(ui, repo, file_, rev):
1223 """dump the contents of a data file revision"""
1223 """dump the contents of a data file revision"""
1224 r = None
1224 r = None
1225 if repo:
1225 if repo:
1226 filelog = repo.file(file_)
1226 filelog = repo.file(file_)
1227 if len(filelog):
1227 if len(filelog):
1228 r = filelog
1228 r = filelog
1229 if not r:
1229 if not r:
1230 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1230 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1231 try:
1231 try:
1232 ui.write(r.revision(r.lookup(rev)))
1232 ui.write(r.revision(r.lookup(rev)))
1233 except KeyError:
1233 except KeyError:
1234 raise util.Abort(_('invalid revision identifier %s') % rev)
1234 raise util.Abort(_('invalid revision identifier %s') % rev)
1235
1235
1236 def debugdate(ui, date, range=None, **opts):
1236 def debugdate(ui, date, range=None, **opts):
1237 """parse and display a date"""
1237 """parse and display a date"""
1238 if opts["extended"]:
1238 if opts["extended"]:
1239 d = util.parsedate(date, util.extendeddateformats)
1239 d = util.parsedate(date, util.extendeddateformats)
1240 else:
1240 else:
1241 d = util.parsedate(date)
1241 d = util.parsedate(date)
1242 ui.write("internal: %s %s\n" % d)
1242 ui.write("internal: %s %s\n" % d)
1243 ui.write("standard: %s\n" % util.datestr(d))
1243 ui.write("standard: %s\n" % util.datestr(d))
1244 if range:
1244 if range:
1245 m = util.matchdate(range)
1245 m = util.matchdate(range)
1246 ui.write("match: %s\n" % m(d[0]))
1246 ui.write("match: %s\n" % m(d[0]))
1247
1247
1248 def debugindex(ui, repo, file_):
1248 def debugindex(ui, repo, file_):
1249 """dump the contents of an index file"""
1249 """dump the contents of an index file"""
1250 r = None
1250 r = None
1251 if repo:
1251 if repo:
1252 filelog = repo.file(file_)
1252 filelog = repo.file(file_)
1253 if len(filelog):
1253 if len(filelog):
1254 r = filelog
1254 r = filelog
1255 if not r:
1255 if not r:
1256 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1256 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1257 ui.write(" rev offset length base linkrev"
1257 ui.write(" rev offset length base linkrev"
1258 " nodeid p1 p2\n")
1258 " nodeid p1 p2\n")
1259 for i in r:
1259 for i in r:
1260 node = r.node(i)
1260 node = r.node(i)
1261 try:
1261 try:
1262 pp = r.parents(node)
1262 pp = r.parents(node)
1263 except:
1263 except:
1264 pp = [nullid, nullid]
1264 pp = [nullid, nullid]
1265 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1265 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1266 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1266 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1267 short(node), short(pp[0]), short(pp[1])))
1267 short(node), short(pp[0]), short(pp[1])))
1268
1268
1269 def debugindexdot(ui, repo, file_):
1269 def debugindexdot(ui, repo, file_):
1270 """dump an index DAG as a graphviz dot file"""
1270 """dump an index DAG as a graphviz dot file"""
1271 r = None
1271 r = None
1272 if repo:
1272 if repo:
1273 filelog = repo.file(file_)
1273 filelog = repo.file(file_)
1274 if len(filelog):
1274 if len(filelog):
1275 r = filelog
1275 r = filelog
1276 if not r:
1276 if not r:
1277 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1277 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1278 ui.write("digraph G {\n")
1278 ui.write("digraph G {\n")
1279 for i in r:
1279 for i in r:
1280 node = r.node(i)
1280 node = r.node(i)
1281 pp = r.parents(node)
1281 pp = r.parents(node)
1282 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1282 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1283 if pp[1] != nullid:
1283 if pp[1] != nullid:
1284 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1284 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1285 ui.write("}\n")
1285 ui.write("}\n")
1286
1286
1287 def debuginstall(ui):
1287 def debuginstall(ui):
1288 '''test Mercurial installation
1288 '''test Mercurial installation
1289
1289
1290 Returns 0 on success.
1290 Returns 0 on success.
1291 '''
1291 '''
1292
1292
1293 def writetemp(contents):
1293 def writetemp(contents):
1294 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1294 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1295 f = os.fdopen(fd, "wb")
1295 f = os.fdopen(fd, "wb")
1296 f.write(contents)
1296 f.write(contents)
1297 f.close()
1297 f.close()
1298 return name
1298 return name
1299
1299
1300 problems = 0
1300 problems = 0
1301
1301
1302 # encoding
1302 # encoding
1303 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1303 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1304 try:
1304 try:
1305 encoding.fromlocal("test")
1305 encoding.fromlocal("test")
1306 except util.Abort, inst:
1306 except util.Abort, inst:
1307 ui.write(" %s\n" % inst)
1307 ui.write(" %s\n" % inst)
1308 ui.write(_(" (check that your locale is properly set)\n"))
1308 ui.write(_(" (check that your locale is properly set)\n"))
1309 problems += 1
1309 problems += 1
1310
1310
1311 # compiled modules
1311 # compiled modules
1312 ui.status(_("Checking installed modules (%s)...\n")
1312 ui.status(_("Checking installed modules (%s)...\n")
1313 % os.path.dirname(__file__))
1313 % os.path.dirname(__file__))
1314 try:
1314 try:
1315 import bdiff, mpatch, base85, osutil
1315 import bdiff, mpatch, base85, osutil
1316 except Exception, inst:
1316 except Exception, inst:
1317 ui.write(" %s\n" % inst)
1317 ui.write(" %s\n" % inst)
1318 ui.write(_(" One or more extensions could not be found"))
1318 ui.write(_(" One or more extensions could not be found"))
1319 ui.write(_(" (check that you compiled the extensions)\n"))
1319 ui.write(_(" (check that you compiled the extensions)\n"))
1320 problems += 1
1320 problems += 1
1321
1321
1322 # templates
1322 # templates
1323 ui.status(_("Checking templates...\n"))
1323 ui.status(_("Checking templates...\n"))
1324 try:
1324 try:
1325 import templater
1325 import templater
1326 templater.templater(templater.templatepath("map-cmdline.default"))
1326 templater.templater(templater.templatepath("map-cmdline.default"))
1327 except Exception, inst:
1327 except Exception, inst:
1328 ui.write(" %s\n" % inst)
1328 ui.write(" %s\n" % inst)
1329 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1329 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1330 problems += 1
1330 problems += 1
1331
1331
1332 # patch
1332 # patch
1333 ui.status(_("Checking patch...\n"))
1333 ui.status(_("Checking patch...\n"))
1334 patchproblems = 0
1334 patchproblems = 0
1335 a = "1\n2\n3\n4\n"
1335 a = "1\n2\n3\n4\n"
1336 b = "1\n2\n3\ninsert\n4\n"
1336 b = "1\n2\n3\ninsert\n4\n"
1337 fa = writetemp(a)
1337 fa = writetemp(a)
1338 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1338 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1339 os.path.basename(fa))
1339 os.path.basename(fa))
1340 fd = writetemp(d)
1340 fd = writetemp(d)
1341
1341
1342 files = {}
1342 files = {}
1343 try:
1343 try:
1344 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1344 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1345 except util.Abort, e:
1345 except util.Abort, e:
1346 ui.write(_(" patch call failed:\n"))
1346 ui.write(_(" patch call failed:\n"))
1347 ui.write(" " + str(e) + "\n")
1347 ui.write(" " + str(e) + "\n")
1348 patchproblems += 1
1348 patchproblems += 1
1349 else:
1349 else:
1350 if list(files) != [os.path.basename(fa)]:
1350 if list(files) != [os.path.basename(fa)]:
1351 ui.write(_(" unexpected patch output!\n"))
1351 ui.write(_(" unexpected patch output!\n"))
1352 patchproblems += 1
1352 patchproblems += 1
1353 a = open(fa).read()
1353 a = open(fa).read()
1354 if a != b:
1354 if a != b:
1355 ui.write(_(" patch test failed!\n"))
1355 ui.write(_(" patch test failed!\n"))
1356 patchproblems += 1
1356 patchproblems += 1
1357
1357
1358 if patchproblems:
1358 if patchproblems:
1359 if ui.config('ui', 'patch'):
1359 if ui.config('ui', 'patch'):
1360 ui.write(_(" (Current patch tool may be incompatible with patch,"
1360 ui.write(_(" (Current patch tool may be incompatible with patch,"
1361 " or misconfigured. Please check your configuration"
1361 " or misconfigured. Please check your configuration"
1362 " file)\n"))
1362 " file)\n"))
1363 else:
1363 else:
1364 ui.write(_(" Internal patcher failure, please report this error"
1364 ui.write(_(" Internal patcher failure, please report this error"
1365 " to http://mercurial.selenic.com/bts/\n"))
1365 " to http://mercurial.selenic.com/bts/\n"))
1366 problems += patchproblems
1366 problems += patchproblems
1367
1367
1368 os.unlink(fa)
1368 os.unlink(fa)
1369 os.unlink(fd)
1369 os.unlink(fd)
1370
1370
1371 # editor
1371 # editor
1372 ui.status(_("Checking commit editor...\n"))
1372 ui.status(_("Checking commit editor...\n"))
1373 editor = ui.geteditor()
1373 editor = ui.geteditor()
1374 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1374 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1375 if not cmdpath:
1375 if not cmdpath:
1376 if editor == 'vi':
1376 if editor == 'vi':
1377 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1377 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1378 ui.write(_(" (specify a commit editor in your configuration"
1378 ui.write(_(" (specify a commit editor in your configuration"
1379 " file)\n"))
1379 " file)\n"))
1380 else:
1380 else:
1381 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1381 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1382 ui.write(_(" (specify a commit editor in your configuration"
1382 ui.write(_(" (specify a commit editor in your configuration"
1383 " file)\n"))
1383 " file)\n"))
1384 problems += 1
1384 problems += 1
1385
1385
1386 # check username
1386 # check username
1387 ui.status(_("Checking username...\n"))
1387 ui.status(_("Checking username...\n"))
1388 try:
1388 try:
1389 ui.username()
1389 ui.username()
1390 except util.Abort, e:
1390 except util.Abort, e:
1391 ui.write(" %s\n" % e)
1391 ui.write(" %s\n" % e)
1392 ui.write(_(" (specify a username in your configuration file)\n"))
1392 ui.write(_(" (specify a username in your configuration file)\n"))
1393 problems += 1
1393 problems += 1
1394
1394
1395 if not problems:
1395 if not problems:
1396 ui.status(_("No problems detected\n"))
1396 ui.status(_("No problems detected\n"))
1397 else:
1397 else:
1398 ui.write(_("%s problems detected,"
1398 ui.write(_("%s problems detected,"
1399 " please check your install!\n") % problems)
1399 " please check your install!\n") % problems)
1400
1400
1401 return problems
1401 return problems
1402
1402
1403 def debugrename(ui, repo, file1, *pats, **opts):
1403 def debugrename(ui, repo, file1, *pats, **opts):
1404 """dump rename information"""
1404 """dump rename information"""
1405
1405
1406 ctx = repo[opts.get('rev')]
1406 ctx = repo[opts.get('rev')]
1407 m = cmdutil.match(repo, (file1,) + pats, opts)
1407 m = cmdutil.match(repo, (file1,) + pats, opts)
1408 for abs in ctx.walk(m):
1408 for abs in ctx.walk(m):
1409 fctx = ctx[abs]
1409 fctx = ctx[abs]
1410 o = fctx.filelog().renamed(fctx.filenode())
1410 o = fctx.filelog().renamed(fctx.filenode())
1411 rel = m.rel(abs)
1411 rel = m.rel(abs)
1412 if o:
1412 if o:
1413 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1413 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1414 else:
1414 else:
1415 ui.write(_("%s not renamed\n") % rel)
1415 ui.write(_("%s not renamed\n") % rel)
1416
1416
1417 def debugwalk(ui, repo, *pats, **opts):
1417 def debugwalk(ui, repo, *pats, **opts):
1418 """show how files match on given patterns"""
1418 """show how files match on given patterns"""
1419 m = cmdutil.match(repo, pats, opts)
1419 m = cmdutil.match(repo, pats, opts)
1420 items = list(repo.walk(m))
1420 items = list(repo.walk(m))
1421 if not items:
1421 if not items:
1422 return
1422 return
1423 fmt = 'f %%-%ds %%-%ds %%s' % (
1423 fmt = 'f %%-%ds %%-%ds %%s' % (
1424 max([len(abs) for abs in items]),
1424 max([len(abs) for abs in items]),
1425 max([len(m.rel(abs)) for abs in items]))
1425 max([len(m.rel(abs)) for abs in items]))
1426 for abs in items:
1426 for abs in items:
1427 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1427 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1428 ui.write("%s\n" % line.rstrip())
1428 ui.write("%s\n" % line.rstrip())
1429
1429
1430 def diff(ui, repo, *pats, **opts):
1430 def diff(ui, repo, *pats, **opts):
1431 """diff repository (or selected files)
1431 """diff repository (or selected files)
1432
1432
1433 Show differences between revisions for the specified files.
1433 Show differences between revisions for the specified files.
1434
1434
1435 Differences between files are shown using the unified diff format.
1435 Differences between files are shown using the unified diff format.
1436
1436
1437 .. note::
1437 .. note::
1438 diff may generate unexpected results for merges, as it will
1438 diff may generate unexpected results for merges, as it will
1439 default to comparing against the working directory's first
1439 default to comparing against the working directory's first
1440 parent changeset if no revisions are specified.
1440 parent changeset if no revisions are specified.
1441
1441
1442 When two revision arguments are given, then changes are shown
1442 When two revision arguments are given, then changes are shown
1443 between those revisions. If only one revision is specified then
1443 between those revisions. If only one revision is specified then
1444 that revision is compared to the working directory, and, when no
1444 that revision is compared to the working directory, and, when no
1445 revisions are specified, the working directory files are compared
1445 revisions are specified, the working directory files are compared
1446 to its parent.
1446 to its parent.
1447
1447
1448 Alternatively you can specify -c/--change with a revision to see
1448 Alternatively you can specify -c/--change with a revision to see
1449 the changes in that changeset relative to its first parent.
1449 the changes in that changeset relative to its first parent.
1450
1450
1451 Without the -a/--text option, diff will avoid generating diffs of
1451 Without the -a/--text option, diff will avoid generating diffs of
1452 files it detects as binary. With -a, diff will generate a diff
1452 files it detects as binary. With -a, diff will generate a diff
1453 anyway, probably with undesirable results.
1453 anyway, probably with undesirable results.
1454
1454
1455 Use the -g/--git option to generate diffs in the git extended diff
1455 Use the -g/--git option to generate diffs in the git extended diff
1456 format. For more information, read :hg:`help diffs`.
1456 format. For more information, read :hg:`help diffs`.
1457
1457
1458 Returns 0 on success.
1458 Returns 0 on success.
1459 """
1459 """
1460
1460
1461 revs = opts.get('rev')
1461 revs = opts.get('rev')
1462 change = opts.get('change')
1462 change = opts.get('change')
1463 stat = opts.get('stat')
1463 stat = opts.get('stat')
1464 reverse = opts.get('reverse')
1464 reverse = opts.get('reverse')
1465
1465
1466 if revs and change:
1466 if revs and change:
1467 msg = _('cannot specify --rev and --change at the same time')
1467 msg = _('cannot specify --rev and --change at the same time')
1468 raise util.Abort(msg)
1468 raise util.Abort(msg)
1469 elif change:
1469 elif change:
1470 node2 = repo.lookup(change)
1470 node2 = repo.lookup(change)
1471 node1 = repo[node2].parents()[0].node()
1471 node1 = repo[node2].parents()[0].node()
1472 else:
1472 else:
1473 node1, node2 = cmdutil.revpair(repo, revs)
1473 node1, node2 = cmdutil.revpair(repo, revs)
1474
1474
1475 if reverse:
1475 if reverse:
1476 node1, node2 = node2, node1
1476 node1, node2 = node2, node1
1477
1477
1478 diffopts = patch.diffopts(ui, opts)
1478 diffopts = patch.diffopts(ui, opts)
1479 m = cmdutil.match(repo, pats, opts)
1479 m = cmdutil.match(repo, pats, opts)
1480 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1480 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1481 listsubrepos=opts.get('subrepos'))
1481 listsubrepos=opts.get('subrepos'))
1482
1482
1483 def export(ui, repo, *changesets, **opts):
1483 def export(ui, repo, *changesets, **opts):
1484 """dump the header and diffs for one or more changesets
1484 """dump the header and diffs for one or more changesets
1485
1485
1486 Print the changeset header and diffs for one or more revisions.
1486 Print the changeset header and diffs for one or more revisions.
1487
1487
1488 The information shown in the changeset header is: author, date,
1488 The information shown in the changeset header is: author, date,
1489 branch name (if non-default), changeset hash, parent(s) and commit
1489 branch name (if non-default), changeset hash, parent(s) and commit
1490 comment.
1490 comment.
1491
1491
1492 .. note::
1492 .. note::
1493 export may generate unexpected diff output for merge
1493 export may generate unexpected diff output for merge
1494 changesets, as it will compare the merge changeset against its
1494 changesets, as it will compare the merge changeset against its
1495 first parent only.
1495 first parent only.
1496
1496
1497 Output may be to a file, in which case the name of the file is
1497 Output may be to a file, in which case the name of the file is
1498 given using a format string. The formatting rules are as follows:
1498 given using a format string. The formatting rules are as follows:
1499
1499
1500 :``%%``: literal "%" character
1500 :``%%``: literal "%" character
1501 :``%H``: changeset hash (40 hexadecimal digits)
1501 :``%H``: changeset hash (40 hexadecimal digits)
1502 :``%N``: number of patches being generated
1502 :``%N``: number of patches being generated
1503 :``%R``: changeset revision number
1503 :``%R``: changeset revision number
1504 :``%b``: basename of the exporting repository
1504 :``%b``: basename of the exporting repository
1505 :``%h``: short-form changeset hash (12 hexadecimal digits)
1505 :``%h``: short-form changeset hash (12 hexadecimal digits)
1506 :``%n``: zero-padded sequence number, starting at 1
1506 :``%n``: zero-padded sequence number, starting at 1
1507 :``%r``: zero-padded changeset revision number
1507 :``%r``: zero-padded changeset revision number
1508
1508
1509 Without the -a/--text option, export will avoid generating diffs
1509 Without the -a/--text option, export will avoid generating diffs
1510 of files it detects as binary. With -a, export will generate a
1510 of files it detects as binary. With -a, export will generate a
1511 diff anyway, probably with undesirable results.
1511 diff anyway, probably with undesirable results.
1512
1512
1513 Use the -g/--git option to generate diffs in the git extended diff
1513 Use the -g/--git option to generate diffs in the git extended diff
1514 format. See :hg:`help diffs` for more information.
1514 format. See :hg:`help diffs` for more information.
1515
1515
1516 With the --switch-parent option, the diff will be against the
1516 With the --switch-parent option, the diff will be against the
1517 second parent. It can be useful to review a merge.
1517 second parent. It can be useful to review a merge.
1518
1518
1519 Returns 0 on success.
1519 Returns 0 on success.
1520 """
1520 """
1521 changesets += tuple(opts.get('rev', []))
1521 changesets += tuple(opts.get('rev', []))
1522 if not changesets:
1522 if not changesets:
1523 raise util.Abort(_("export requires at least one changeset"))
1523 raise util.Abort(_("export requires at least one changeset"))
1524 revs = cmdutil.revrange(repo, changesets)
1524 revs = cmdutil.revrange(repo, changesets)
1525 if len(revs) > 1:
1525 if len(revs) > 1:
1526 ui.note(_('exporting patches:\n'))
1526 ui.note(_('exporting patches:\n'))
1527 else:
1527 else:
1528 ui.note(_('exporting patch:\n'))
1528 ui.note(_('exporting patch:\n'))
1529 cmdutil.export(repo, revs, template=opts.get('output'),
1529 cmdutil.export(repo, revs, template=opts.get('output'),
1530 switch_parent=opts.get('switch_parent'),
1530 switch_parent=opts.get('switch_parent'),
1531 opts=patch.diffopts(ui, opts))
1531 opts=patch.diffopts(ui, opts))
1532
1532
1533 def forget(ui, repo, *pats, **opts):
1533 def forget(ui, repo, *pats, **opts):
1534 """forget the specified files on the next commit
1534 """forget the specified files on the next commit
1535
1535
1536 Mark the specified files so they will no longer be tracked
1536 Mark the specified files so they will no longer be tracked
1537 after the next commit.
1537 after the next commit.
1538
1538
1539 This only removes files from the current branch, not from the
1539 This only removes files from the current branch, not from the
1540 entire project history, and it does not delete them from the
1540 entire project history, and it does not delete them from the
1541 working directory.
1541 working directory.
1542
1542
1543 To undo a forget before the next commit, see :hg:`add`.
1543 To undo a forget before the next commit, see :hg:`add`.
1544
1544
1545 Returns 0 on success.
1545 Returns 0 on success.
1546 """
1546 """
1547
1547
1548 if not pats:
1548 if not pats:
1549 raise util.Abort(_('no files specified'))
1549 raise util.Abort(_('no files specified'))
1550
1550
1551 m = cmdutil.match(repo, pats, opts)
1551 m = cmdutil.match(repo, pats, opts)
1552 s = repo.status(match=m, clean=True)
1552 s = repo.status(match=m, clean=True)
1553 forget = sorted(s[0] + s[1] + s[3] + s[6])
1553 forget = sorted(s[0] + s[1] + s[3] + s[6])
1554 errs = 0
1554 errs = 0
1555
1555
1556 for f in m.files():
1556 for f in m.files():
1557 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1557 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1558 ui.warn(_('not removing %s: file is already untracked\n')
1558 ui.warn(_('not removing %s: file is already untracked\n')
1559 % m.rel(f))
1559 % m.rel(f))
1560 errs = 1
1560 errs = 1
1561
1561
1562 for f in forget:
1562 for f in forget:
1563 if ui.verbose or not m.exact(f):
1563 if ui.verbose or not m.exact(f):
1564 ui.status(_('removing %s\n') % m.rel(f))
1564 ui.status(_('removing %s\n') % m.rel(f))
1565
1565
1566 repo[None].remove(forget, unlink=False)
1566 repo[None].remove(forget, unlink=False)
1567 return errs
1567 return errs
1568
1568
1569 def grep(ui, repo, pattern, *pats, **opts):
1569 def grep(ui, repo, pattern, *pats, **opts):
1570 """search for a pattern in specified files and revisions
1570 """search for a pattern in specified files and revisions
1571
1571
1572 Search revisions of files for a regular expression.
1572 Search revisions of files for a regular expression.
1573
1573
1574 This command behaves differently than Unix grep. It only accepts
1574 This command behaves differently than Unix grep. It only accepts
1575 Python/Perl regexps. It searches repository history, not the
1575 Python/Perl regexps. It searches repository history, not the
1576 working directory. It always prints the revision number in which a
1576 working directory. It always prints the revision number in which a
1577 match appears.
1577 match appears.
1578
1578
1579 By default, grep only prints output for the first revision of a
1579 By default, grep only prints output for the first revision of a
1580 file in which it finds a match. To get it to print every revision
1580 file in which it finds a match. To get it to print every revision
1581 that contains a change in match status ("-" for a match that
1581 that contains a change in match status ("-" for a match that
1582 becomes a non-match, or "+" for a non-match that becomes a match),
1582 becomes a non-match, or "+" for a non-match that becomes a match),
1583 use the --all flag.
1583 use the --all flag.
1584
1584
1585 Returns 0 if a match is found, 1 otherwise.
1585 Returns 0 if a match is found, 1 otherwise.
1586 """
1586 """
1587 reflags = 0
1587 reflags = 0
1588 if opts.get('ignore_case'):
1588 if opts.get('ignore_case'):
1589 reflags |= re.I
1589 reflags |= re.I
1590 try:
1590 try:
1591 regexp = re.compile(pattern, reflags)
1591 regexp = re.compile(pattern, reflags)
1592 except re.error, inst:
1592 except re.error, inst:
1593 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1593 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1594 return 1
1594 return 1
1595 sep, eol = ':', '\n'
1595 sep, eol = ':', '\n'
1596 if opts.get('print0'):
1596 if opts.get('print0'):
1597 sep = eol = '\0'
1597 sep = eol = '\0'
1598
1598
1599 getfile = util.lrucachefunc(repo.file)
1599 getfile = util.lrucachefunc(repo.file)
1600
1600
1601 def matchlines(body):
1601 def matchlines(body):
1602 begin = 0
1602 begin = 0
1603 linenum = 0
1603 linenum = 0
1604 while True:
1604 while True:
1605 match = regexp.search(body, begin)
1605 match = regexp.search(body, begin)
1606 if not match:
1606 if not match:
1607 break
1607 break
1608 mstart, mend = match.span()
1608 mstart, mend = match.span()
1609 linenum += body.count('\n', begin, mstart) + 1
1609 linenum += body.count('\n', begin, mstart) + 1
1610 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1610 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1611 begin = body.find('\n', mend) + 1 or len(body)
1611 begin = body.find('\n', mend) + 1 or len(body)
1612 lend = begin - 1
1612 lend = begin - 1
1613 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1613 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1614
1614
1615 class linestate(object):
1615 class linestate(object):
1616 def __init__(self, line, linenum, colstart, colend):
1616 def __init__(self, line, linenum, colstart, colend):
1617 self.line = line
1617 self.line = line
1618 self.linenum = linenum
1618 self.linenum = linenum
1619 self.colstart = colstart
1619 self.colstart = colstart
1620 self.colend = colend
1620 self.colend = colend
1621
1621
1622 def __hash__(self):
1622 def __hash__(self):
1623 return hash((self.linenum, self.line))
1623 return hash((self.linenum, self.line))
1624
1624
1625 def __eq__(self, other):
1625 def __eq__(self, other):
1626 return self.line == other.line
1626 return self.line == other.line
1627
1627
1628 matches = {}
1628 matches = {}
1629 copies = {}
1629 copies = {}
1630 def grepbody(fn, rev, body):
1630 def grepbody(fn, rev, body):
1631 matches[rev].setdefault(fn, [])
1631 matches[rev].setdefault(fn, [])
1632 m = matches[rev][fn]
1632 m = matches[rev][fn]
1633 for lnum, cstart, cend, line in matchlines(body):
1633 for lnum, cstart, cend, line in matchlines(body):
1634 s = linestate(line, lnum, cstart, cend)
1634 s = linestate(line, lnum, cstart, cend)
1635 m.append(s)
1635 m.append(s)
1636
1636
1637 def difflinestates(a, b):
1637 def difflinestates(a, b):
1638 sm = difflib.SequenceMatcher(None, a, b)
1638 sm = difflib.SequenceMatcher(None, a, b)
1639 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1639 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1640 if tag == 'insert':
1640 if tag == 'insert':
1641 for i in xrange(blo, bhi):
1641 for i in xrange(blo, bhi):
1642 yield ('+', b[i])
1642 yield ('+', b[i])
1643 elif tag == 'delete':
1643 elif tag == 'delete':
1644 for i in xrange(alo, ahi):
1644 for i in xrange(alo, ahi):
1645 yield ('-', a[i])
1645 yield ('-', a[i])
1646 elif tag == 'replace':
1646 elif tag == 'replace':
1647 for i in xrange(alo, ahi):
1647 for i in xrange(alo, ahi):
1648 yield ('-', a[i])
1648 yield ('-', a[i])
1649 for i in xrange(blo, bhi):
1649 for i in xrange(blo, bhi):
1650 yield ('+', b[i])
1650 yield ('+', b[i])
1651
1651
1652 def display(fn, ctx, pstates, states):
1652 def display(fn, ctx, pstates, states):
1653 rev = ctx.rev()
1653 rev = ctx.rev()
1654 datefunc = ui.quiet and util.shortdate or util.datestr
1654 datefunc = ui.quiet and util.shortdate or util.datestr
1655 found = False
1655 found = False
1656 filerevmatches = {}
1656 filerevmatches = {}
1657 if opts.get('all'):
1657 if opts.get('all'):
1658 iter = difflinestates(pstates, states)
1658 iter = difflinestates(pstates, states)
1659 else:
1659 else:
1660 iter = [('', l) for l in states]
1660 iter = [('', l) for l in states]
1661 for change, l in iter:
1661 for change, l in iter:
1662 cols = [fn, str(rev)]
1662 cols = [fn, str(rev)]
1663 before, match, after = None, None, None
1663 before, match, after = None, None, None
1664 if opts.get('line_number'):
1664 if opts.get('line_number'):
1665 cols.append(str(l.linenum))
1665 cols.append(str(l.linenum))
1666 if opts.get('all'):
1666 if opts.get('all'):
1667 cols.append(change)
1667 cols.append(change)
1668 if opts.get('user'):
1668 if opts.get('user'):
1669 cols.append(ui.shortuser(ctx.user()))
1669 cols.append(ui.shortuser(ctx.user()))
1670 if opts.get('date'):
1670 if opts.get('date'):
1671 cols.append(datefunc(ctx.date()))
1671 cols.append(datefunc(ctx.date()))
1672 if opts.get('files_with_matches'):
1672 if opts.get('files_with_matches'):
1673 c = (fn, rev)
1673 c = (fn, rev)
1674 if c in filerevmatches:
1674 if c in filerevmatches:
1675 continue
1675 continue
1676 filerevmatches[c] = 1
1676 filerevmatches[c] = 1
1677 else:
1677 else:
1678 before = l.line[:l.colstart]
1678 before = l.line[:l.colstart]
1679 match = l.line[l.colstart:l.colend]
1679 match = l.line[l.colstart:l.colend]
1680 after = l.line[l.colend:]
1680 after = l.line[l.colend:]
1681 ui.write(sep.join(cols))
1681 ui.write(sep.join(cols))
1682 if before is not None:
1682 if before is not None:
1683 ui.write(sep + before)
1683 ui.write(sep + before)
1684 ui.write(match, label='grep.match')
1684 ui.write(match, label='grep.match')
1685 ui.write(after)
1685 ui.write(after)
1686 ui.write(eol)
1686 ui.write(eol)
1687 found = True
1687 found = True
1688 return found
1688 return found
1689
1689
1690 skip = {}
1690 skip = {}
1691 revfiles = {}
1691 revfiles = {}
1692 matchfn = cmdutil.match(repo, pats, opts)
1692 matchfn = cmdutil.match(repo, pats, opts)
1693 found = False
1693 found = False
1694 follow = opts.get('follow')
1694 follow = opts.get('follow')
1695
1695
1696 def prep(ctx, fns):
1696 def prep(ctx, fns):
1697 rev = ctx.rev()
1697 rev = ctx.rev()
1698 pctx = ctx.parents()[0]
1698 pctx = ctx.parents()[0]
1699 parent = pctx.rev()
1699 parent = pctx.rev()
1700 matches.setdefault(rev, {})
1700 matches.setdefault(rev, {})
1701 matches.setdefault(parent, {})
1701 matches.setdefault(parent, {})
1702 files = revfiles.setdefault(rev, [])
1702 files = revfiles.setdefault(rev, [])
1703 for fn in fns:
1703 for fn in fns:
1704 flog = getfile(fn)
1704 flog = getfile(fn)
1705 try:
1705 try:
1706 fnode = ctx.filenode(fn)
1706 fnode = ctx.filenode(fn)
1707 except error.LookupError:
1707 except error.LookupError:
1708 continue
1708 continue
1709
1709
1710 copied = flog.renamed(fnode)
1710 copied = flog.renamed(fnode)
1711 copy = follow and copied and copied[0]
1711 copy = follow and copied and copied[0]
1712 if copy:
1712 if copy:
1713 copies.setdefault(rev, {})[fn] = copy
1713 copies.setdefault(rev, {})[fn] = copy
1714 if fn in skip:
1714 if fn in skip:
1715 if copy:
1715 if copy:
1716 skip[copy] = True
1716 skip[copy] = True
1717 continue
1717 continue
1718 files.append(fn)
1718 files.append(fn)
1719
1719
1720 if fn not in matches[rev]:
1720 if fn not in matches[rev]:
1721 grepbody(fn, rev, flog.read(fnode))
1721 grepbody(fn, rev, flog.read(fnode))
1722
1722
1723 pfn = copy or fn
1723 pfn = copy or fn
1724 if pfn not in matches[parent]:
1724 if pfn not in matches[parent]:
1725 try:
1725 try:
1726 fnode = pctx.filenode(pfn)
1726 fnode = pctx.filenode(pfn)
1727 grepbody(pfn, parent, flog.read(fnode))
1727 grepbody(pfn, parent, flog.read(fnode))
1728 except error.LookupError:
1728 except error.LookupError:
1729 pass
1729 pass
1730
1730
1731 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1731 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1732 rev = ctx.rev()
1732 rev = ctx.rev()
1733 parent = ctx.parents()[0].rev()
1733 parent = ctx.parents()[0].rev()
1734 for fn in sorted(revfiles.get(rev, [])):
1734 for fn in sorted(revfiles.get(rev, [])):
1735 states = matches[rev][fn]
1735 states = matches[rev][fn]
1736 copy = copies.get(rev, {}).get(fn)
1736 copy = copies.get(rev, {}).get(fn)
1737 if fn in skip:
1737 if fn in skip:
1738 if copy:
1738 if copy:
1739 skip[copy] = True
1739 skip[copy] = True
1740 continue
1740 continue
1741 pstates = matches.get(parent, {}).get(copy or fn, [])
1741 pstates = matches.get(parent, {}).get(copy or fn, [])
1742 if pstates or states:
1742 if pstates or states:
1743 r = display(fn, ctx, pstates, states)
1743 r = display(fn, ctx, pstates, states)
1744 found = found or r
1744 found = found or r
1745 if r and not opts.get('all'):
1745 if r and not opts.get('all'):
1746 skip[fn] = True
1746 skip[fn] = True
1747 if copy:
1747 if copy:
1748 skip[copy] = True
1748 skip[copy] = True
1749 del matches[rev]
1749 del matches[rev]
1750 del revfiles[rev]
1750 del revfiles[rev]
1751
1751
1752 return not found
1752 return not found
1753
1753
1754 def heads(ui, repo, *branchrevs, **opts):
1754 def heads(ui, repo, *branchrevs, **opts):
1755 """show current repository heads or show branch heads
1755 """show current repository heads or show branch heads
1756
1756
1757 With no arguments, show all repository branch heads.
1757 With no arguments, show all repository branch heads.
1758
1758
1759 Repository "heads" are changesets with no child changesets. They are
1759 Repository "heads" are changesets with no child changesets. They are
1760 where development generally takes place and are the usual targets
1760 where development generally takes place and are the usual targets
1761 for update and merge operations. Branch heads are changesets that have
1761 for update and merge operations. Branch heads are changesets that have
1762 no child changeset on the same branch.
1762 no child changeset on the same branch.
1763
1763
1764 If one or more REVs are given, only branch heads on the branches
1764 If one or more REVs are given, only branch heads on the branches
1765 associated with the specified changesets are shown.
1765 associated with the specified changesets are shown.
1766
1766
1767 If -c/--closed is specified, also show branch heads marked closed
1767 If -c/--closed is specified, also show branch heads marked closed
1768 (see :hg:`commit --close-branch`).
1768 (see :hg:`commit --close-branch`).
1769
1769
1770 If STARTREV is specified, only those heads that are descendants of
1770 If STARTREV is specified, only those heads that are descendants of
1771 STARTREV will be displayed.
1771 STARTREV will be displayed.
1772
1772
1773 If -t/--topo is specified, named branch mechanics will be ignored and only
1773 If -t/--topo is specified, named branch mechanics will be ignored and only
1774 changesets without children will be shown.
1774 changesets without children will be shown.
1775
1775
1776 Returns 0 if matching heads are found, 1 if not.
1776 Returns 0 if matching heads are found, 1 if not.
1777 """
1777 """
1778
1778
1779 if opts.get('rev'):
1779 if opts.get('rev'):
1780 start = repo.lookup(opts['rev'])
1780 start = repo.lookup(opts['rev'])
1781 else:
1781 else:
1782 start = None
1782 start = None
1783
1783
1784 if opts.get('topo'):
1784 if opts.get('topo'):
1785 heads = [repo[h] for h in repo.heads(start)]
1785 heads = [repo[h] for h in repo.heads(start)]
1786 else:
1786 else:
1787 heads = []
1787 heads = []
1788 for b, ls in repo.branchmap().iteritems():
1788 for b, ls in repo.branchmap().iteritems():
1789 if start is None:
1789 if start is None:
1790 heads += [repo[h] for h in ls]
1790 heads += [repo[h] for h in ls]
1791 continue
1791 continue
1792 startrev = repo.changelog.rev(start)
1792 startrev = repo.changelog.rev(start)
1793 descendants = set(repo.changelog.descendants(startrev))
1793 descendants = set(repo.changelog.descendants(startrev))
1794 descendants.add(startrev)
1794 descendants.add(startrev)
1795 rev = repo.changelog.rev
1795 rev = repo.changelog.rev
1796 heads += [repo[h] for h in ls if rev(h) in descendants]
1796 heads += [repo[h] for h in ls if rev(h) in descendants]
1797
1797
1798 if branchrevs:
1798 if branchrevs:
1799 decode, encode = encoding.fromlocal, encoding.tolocal
1799 decode, encode = encoding.fromlocal, encoding.tolocal
1800 branches = set(repo[decode(br)].branch() for br in branchrevs)
1800 branches = set(repo[decode(br)].branch() for br in branchrevs)
1801 heads = [h for h in heads if h.branch() in branches]
1801 heads = [h for h in heads if h.branch() in branches]
1802
1802
1803 if not opts.get('closed'):
1803 if not opts.get('closed'):
1804 heads = [h for h in heads if not h.extra().get('close')]
1804 heads = [h for h in heads if not h.extra().get('close')]
1805
1805
1806 if opts.get('active') and branchrevs:
1806 if opts.get('active') and branchrevs:
1807 dagheads = repo.heads(start)
1807 dagheads = repo.heads(start)
1808 heads = [h for h in heads if h.node() in dagheads]
1808 heads = [h for h in heads if h.node() in dagheads]
1809
1809
1810 if branchrevs:
1810 if branchrevs:
1811 haveheads = set(h.branch() for h in heads)
1811 haveheads = set(h.branch() for h in heads)
1812 if branches - haveheads:
1812 if branches - haveheads:
1813 headless = ', '.join(encode(b) for b in branches - haveheads)
1813 headless = ', '.join(encode(b) for b in branches - haveheads)
1814 msg = _('no open branch heads found on branches %s')
1814 msg = _('no open branch heads found on branches %s')
1815 if opts.get('rev'):
1815 if opts.get('rev'):
1816 msg += _(' (started at %s)' % opts['rev'])
1816 msg += _(' (started at %s)' % opts['rev'])
1817 ui.warn((msg + '\n') % headless)
1817 ui.warn((msg + '\n') % headless)
1818
1818
1819 if not heads:
1819 if not heads:
1820 return 1
1820 return 1
1821
1821
1822 heads = sorted(heads, key=lambda x: -x.rev())
1822 heads = sorted(heads, key=lambda x: -x.rev())
1823 displayer = cmdutil.show_changeset(ui, repo, opts)
1823 displayer = cmdutil.show_changeset(ui, repo, opts)
1824 for ctx in heads:
1824 for ctx in heads:
1825 displayer.show(ctx)
1825 displayer.show(ctx)
1826 displayer.close()
1826 displayer.close()
1827
1827
1828 def help_(ui, name=None, with_version=False, unknowncmd=False):
1828 def help_(ui, name=None, with_version=False, unknowncmd=False):
1829 """show help for a given topic or a help overview
1829 """show help for a given topic or a help overview
1830
1830
1831 With no arguments, print a list of commands with short help messages.
1831 With no arguments, print a list of commands with short help messages.
1832
1832
1833 Given a topic, extension, or command name, print help for that
1833 Given a topic, extension, or command name, print help for that
1834 topic.
1834 topic.
1835
1835
1836 Returns 0 if successful.
1836 Returns 0 if successful.
1837 """
1837 """
1838 option_lists = []
1838 option_lists = []
1839 textwidth = ui.termwidth() - 2
1839 textwidth = ui.termwidth() - 2
1840
1840
1841 def addglobalopts(aliases):
1841 def addglobalopts(aliases):
1842 if ui.verbose:
1842 if ui.verbose:
1843 option_lists.append((_("global options:"), globalopts))
1843 option_lists.append((_("global options:"), globalopts))
1844 if name == 'shortlist':
1844 if name == 'shortlist':
1845 option_lists.append((_('use "hg help" for the full list '
1845 option_lists.append((_('use "hg help" for the full list '
1846 'of commands'), ()))
1846 'of commands'), ()))
1847 else:
1847 else:
1848 if name == 'shortlist':
1848 if name == 'shortlist':
1849 msg = _('use "hg help" for the full list of commands '
1849 msg = _('use "hg help" for the full list of commands '
1850 'or "hg -v" for details')
1850 'or "hg -v" for details')
1851 elif aliases:
1851 elif aliases:
1852 msg = _('use "hg -v help%s" to show aliases and '
1852 msg = _('use "hg -v help%s" to show aliases and '
1853 'global options') % (name and " " + name or "")
1853 'global options') % (name and " " + name or "")
1854 else:
1854 else:
1855 msg = _('use "hg -v help %s" to show global options') % name
1855 msg = _('use "hg -v help %s" to show global options') % name
1856 option_lists.append((msg, ()))
1856 option_lists.append((msg, ()))
1857
1857
1858 def helpcmd(name):
1858 def helpcmd(name):
1859 if with_version:
1859 if with_version:
1860 version_(ui)
1860 version_(ui)
1861 ui.write('\n')
1861 ui.write('\n')
1862
1862
1863 try:
1863 try:
1864 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1864 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1865 except error.AmbiguousCommand, inst:
1865 except error.AmbiguousCommand, inst:
1866 # py3k fix: except vars can't be used outside the scope of the
1866 # py3k fix: except vars can't be used outside the scope of the
1867 # except block, nor can be used inside a lambda. python issue4617
1867 # except block, nor can be used inside a lambda. python issue4617
1868 prefix = inst.args[0]
1868 prefix = inst.args[0]
1869 select = lambda c: c.lstrip('^').startswith(prefix)
1869 select = lambda c: c.lstrip('^').startswith(prefix)
1870 helplist(_('list of commands:\n\n'), select)
1870 helplist(_('list of commands:\n\n'), select)
1871 return
1871 return
1872
1872
1873 # check if it's an invalid alias and display its error if it is
1873 # check if it's an invalid alias and display its error if it is
1874 if getattr(entry[0], 'badalias', False):
1874 if getattr(entry[0], 'badalias', False):
1875 if not unknowncmd:
1875 if not unknowncmd:
1876 entry[0](ui)
1876 entry[0](ui)
1877 return
1877 return
1878
1878
1879 # synopsis
1879 # synopsis
1880 if len(entry) > 2:
1880 if len(entry) > 2:
1881 if entry[2].startswith('hg'):
1881 if entry[2].startswith('hg'):
1882 ui.write("%s\n" % entry[2])
1882 ui.write("%s\n" % entry[2])
1883 else:
1883 else:
1884 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1884 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1885 else:
1885 else:
1886 ui.write('hg %s\n' % aliases[0])
1886 ui.write('hg %s\n' % aliases[0])
1887
1887
1888 # aliases
1888 # aliases
1889 if not ui.quiet and len(aliases) > 1:
1889 if not ui.quiet and len(aliases) > 1:
1890 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1890 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1891
1891
1892 # description
1892 # description
1893 doc = gettext(entry[0].__doc__)
1893 doc = gettext(entry[0].__doc__)
1894 if not doc:
1894 if not doc:
1895 doc = _("(no help text available)")
1895 doc = _("(no help text available)")
1896 if hasattr(entry[0], 'definition'): # aliased command
1896 if hasattr(entry[0], 'definition'): # aliased command
1897 if entry[0].definition.startswith('!'): # shell alias
1897 if entry[0].definition.startswith('!'): # shell alias
1898 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1898 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1899 else:
1899 else:
1900 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1900 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1901 if ui.quiet:
1901 if ui.quiet:
1902 doc = doc.splitlines()[0]
1902 doc = doc.splitlines()[0]
1903 keep = ui.verbose and ['verbose'] or []
1903 keep = ui.verbose and ['verbose'] or []
1904 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1904 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1905 ui.write("\n%s\n" % formatted)
1905 ui.write("\n%s\n" % formatted)
1906 if pruned:
1906 if pruned:
1907 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1907 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1908
1908
1909 if not ui.quiet:
1909 if not ui.quiet:
1910 # options
1910 # options
1911 if entry[1]:
1911 if entry[1]:
1912 option_lists.append((_("options:\n"), entry[1]))
1912 option_lists.append((_("options:\n"), entry[1]))
1913
1913
1914 addglobalopts(False)
1914 addglobalopts(False)
1915
1915
1916 def helplist(header, select=None):
1916 def helplist(header, select=None):
1917 h = {}
1917 h = {}
1918 cmds = {}
1918 cmds = {}
1919 for c, e in table.iteritems():
1919 for c, e in table.iteritems():
1920 f = c.split("|", 1)[0]
1920 f = c.split("|", 1)[0]
1921 if select and not select(f):
1921 if select and not select(f):
1922 continue
1922 continue
1923 if (not select and name != 'shortlist' and
1923 if (not select and name != 'shortlist' and
1924 e[0].__module__ != __name__):
1924 e[0].__module__ != __name__):
1925 continue
1925 continue
1926 if name == "shortlist" and not f.startswith("^"):
1926 if name == "shortlist" and not f.startswith("^"):
1927 continue
1927 continue
1928 f = f.lstrip("^")
1928 f = f.lstrip("^")
1929 if not ui.debugflag and f.startswith("debug"):
1929 if not ui.debugflag and f.startswith("debug"):
1930 continue
1930 continue
1931 doc = e[0].__doc__
1931 doc = e[0].__doc__
1932 if doc and 'DEPRECATED' in doc and not ui.verbose:
1932 if doc and 'DEPRECATED' in doc and not ui.verbose:
1933 continue
1933 continue
1934 doc = gettext(doc)
1934 doc = gettext(doc)
1935 if not doc:
1935 if not doc:
1936 doc = _("(no help text available)")
1936 doc = _("(no help text available)")
1937 h[f] = doc.splitlines()[0].rstrip()
1937 h[f] = doc.splitlines()[0].rstrip()
1938 cmds[f] = c.lstrip("^")
1938 cmds[f] = c.lstrip("^")
1939
1939
1940 if not h:
1940 if not h:
1941 ui.status(_('no commands defined\n'))
1941 ui.status(_('no commands defined\n'))
1942 return
1942 return
1943
1943
1944 ui.status(header)
1944 ui.status(header)
1945 fns = sorted(h)
1945 fns = sorted(h)
1946 m = max(map(len, fns))
1946 m = max(map(len, fns))
1947 for f in fns:
1947 for f in fns:
1948 if ui.verbose:
1948 if ui.verbose:
1949 commands = cmds[f].replace("|",", ")
1949 commands = cmds[f].replace("|",", ")
1950 ui.write(" %s:\n %s\n"%(commands, h[f]))
1950 ui.write(" %s:\n %s\n"%(commands, h[f]))
1951 else:
1951 else:
1952 ui.write('%s\n' % (util.wrap(h[f],
1952 ui.write('%s\n' % (util.wrap(h[f], textwidth,
1953 initindent=' %-*s ' % (m, f),
1953 initindent=' %-*s ' % (m, f),
1954 hangindent=' ' * (m + 4))))
1954 hangindent=' ' * (m + 4))))
1955
1955
1956 if not ui.quiet:
1956 if not ui.quiet:
1957 addglobalopts(True)
1957 addglobalopts(True)
1958
1958
1959 def helptopic(name):
1959 def helptopic(name):
1960 for names, header, doc in help.helptable:
1960 for names, header, doc in help.helptable:
1961 if name in names:
1961 if name in names:
1962 break
1962 break
1963 else:
1963 else:
1964 raise error.UnknownCommand(name)
1964 raise error.UnknownCommand(name)
1965
1965
1966 # description
1966 # description
1967 if not doc:
1967 if not doc:
1968 doc = _("(no help text available)")
1968 doc = _("(no help text available)")
1969 if hasattr(doc, '__call__'):
1969 if hasattr(doc, '__call__'):
1970 doc = doc()
1970 doc = doc()
1971
1971
1972 ui.write("%s\n\n" % header)
1972 ui.write("%s\n\n" % header)
1973 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1973 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1974
1974
1975 def helpext(name):
1975 def helpext(name):
1976 try:
1976 try:
1977 mod = extensions.find(name)
1977 mod = extensions.find(name)
1978 doc = gettext(mod.__doc__) or _('no help text available')
1978 doc = gettext(mod.__doc__) or _('no help text available')
1979 except KeyError:
1979 except KeyError:
1980 mod = None
1980 mod = None
1981 doc = extensions.disabledext(name)
1981 doc = extensions.disabledext(name)
1982 if not doc:
1982 if not doc:
1983 raise error.UnknownCommand(name)
1983 raise error.UnknownCommand(name)
1984
1984
1985 if '\n' not in doc:
1985 if '\n' not in doc:
1986 head, tail = doc, ""
1986 head, tail = doc, ""
1987 else:
1987 else:
1988 head, tail = doc.split('\n', 1)
1988 head, tail = doc.split('\n', 1)
1989 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
1989 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
1990 if tail:
1990 if tail:
1991 ui.write(minirst.format(tail, textwidth))
1991 ui.write(minirst.format(tail, textwidth))
1992 ui.status('\n\n')
1992 ui.status('\n\n')
1993
1993
1994 if mod:
1994 if mod:
1995 try:
1995 try:
1996 ct = mod.cmdtable
1996 ct = mod.cmdtable
1997 except AttributeError:
1997 except AttributeError:
1998 ct = {}
1998 ct = {}
1999 modcmds = set([c.split('|', 1)[0] for c in ct])
1999 modcmds = set([c.split('|', 1)[0] for c in ct])
2000 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2000 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2001 else:
2001 else:
2002 ui.write(_('use "hg help extensions" for information on enabling '
2002 ui.write(_('use "hg help extensions" for information on enabling '
2003 'extensions\n'))
2003 'extensions\n'))
2004
2004
2005 def helpextcmd(name):
2005 def helpextcmd(name):
2006 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
2006 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
2007 doc = gettext(mod.__doc__).splitlines()[0]
2007 doc = gettext(mod.__doc__).splitlines()[0]
2008
2008
2009 msg = help.listexts(_("'%s' is provided by the following "
2009 msg = help.listexts(_("'%s' is provided by the following "
2010 "extension:") % cmd, {ext: doc}, len(ext),
2010 "extension:") % cmd, {ext: doc}, len(ext),
2011 indent=4)
2011 indent=4)
2012 ui.write(minirst.format(msg, textwidth))
2012 ui.write(minirst.format(msg, textwidth))
2013 ui.write('\n\n')
2013 ui.write('\n\n')
2014 ui.write(_('use "hg help extensions" for information on enabling '
2014 ui.write(_('use "hg help extensions" for information on enabling '
2015 'extensions\n'))
2015 'extensions\n'))
2016
2016
2017 if name and name != 'shortlist':
2017 if name and name != 'shortlist':
2018 i = None
2018 i = None
2019 if unknowncmd:
2019 if unknowncmd:
2020 queries = (helpextcmd,)
2020 queries = (helpextcmd,)
2021 else:
2021 else:
2022 queries = (helptopic, helpcmd, helpext, helpextcmd)
2022 queries = (helptopic, helpcmd, helpext, helpextcmd)
2023 for f in queries:
2023 for f in queries:
2024 try:
2024 try:
2025 f(name)
2025 f(name)
2026 i = None
2026 i = None
2027 break
2027 break
2028 except error.UnknownCommand, inst:
2028 except error.UnknownCommand, inst:
2029 i = inst
2029 i = inst
2030 if i:
2030 if i:
2031 raise i
2031 raise i
2032
2032
2033 else:
2033 else:
2034 # program name
2034 # program name
2035 if ui.verbose or with_version:
2035 if ui.verbose or with_version:
2036 version_(ui)
2036 version_(ui)
2037 else:
2037 else:
2038 ui.status(_("Mercurial Distributed SCM\n"))
2038 ui.status(_("Mercurial Distributed SCM\n"))
2039 ui.status('\n')
2039 ui.status('\n')
2040
2040
2041 # list of commands
2041 # list of commands
2042 if name == "shortlist":
2042 if name == "shortlist":
2043 header = _('basic commands:\n\n')
2043 header = _('basic commands:\n\n')
2044 else:
2044 else:
2045 header = _('list of commands:\n\n')
2045 header = _('list of commands:\n\n')
2046
2046
2047 helplist(header)
2047 helplist(header)
2048 if name != 'shortlist':
2048 if name != 'shortlist':
2049 exts, maxlength = extensions.enabled()
2049 exts, maxlength = extensions.enabled()
2050 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2050 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2051 if text:
2051 if text:
2052 ui.write("\n%s\n" % minirst.format(text, textwidth))
2052 ui.write("\n%s\n" % minirst.format(text, textwidth))
2053
2053
2054 # list all option lists
2054 # list all option lists
2055 opt_output = []
2055 opt_output = []
2056 multioccur = False
2056 multioccur = False
2057 for title, options in option_lists:
2057 for title, options in option_lists:
2058 opt_output.append(("\n%s" % title, None))
2058 opt_output.append(("\n%s" % title, None))
2059 for option in options:
2059 for option in options:
2060 if len(option) == 5:
2060 if len(option) == 5:
2061 shortopt, longopt, default, desc, optlabel = option
2061 shortopt, longopt, default, desc, optlabel = option
2062 else:
2062 else:
2063 shortopt, longopt, default, desc = option
2063 shortopt, longopt, default, desc = option
2064 optlabel = _("VALUE") # default label
2064 optlabel = _("VALUE") # default label
2065
2065
2066 if _("DEPRECATED") in desc and not ui.verbose:
2066 if _("DEPRECATED") in desc and not ui.verbose:
2067 continue
2067 continue
2068 if isinstance(default, list):
2068 if isinstance(default, list):
2069 numqualifier = " %s [+]" % optlabel
2069 numqualifier = " %s [+]" % optlabel
2070 multioccur = True
2070 multioccur = True
2071 elif (default is not None) and not isinstance(default, bool):
2071 elif (default is not None) and not isinstance(default, bool):
2072 numqualifier = " %s" % optlabel
2072 numqualifier = " %s" % optlabel
2073 else:
2073 else:
2074 numqualifier = ""
2074 numqualifier = ""
2075 opt_output.append(("%2s%s" %
2075 opt_output.append(("%2s%s" %
2076 (shortopt and "-%s" % shortopt,
2076 (shortopt and "-%s" % shortopt,
2077 longopt and " --%s%s" %
2077 longopt and " --%s%s" %
2078 (longopt, numqualifier)),
2078 (longopt, numqualifier)),
2079 "%s%s" % (desc,
2079 "%s%s" % (desc,
2080 default
2080 default
2081 and _(" (default: %s)") % default
2081 and _(" (default: %s)") % default
2082 or "")))
2082 or "")))
2083 if multioccur:
2083 if multioccur:
2084 msg = _("\n[+] marked option can be specified multiple times")
2084 msg = _("\n[+] marked option can be specified multiple times")
2085 if ui.verbose and name != 'shortlist':
2085 if ui.verbose and name != 'shortlist':
2086 opt_output.append((msg, None))
2086 opt_output.append((msg, None))
2087 else:
2087 else:
2088 opt_output.insert(-1, (msg, None))
2088 opt_output.insert(-1, (msg, None))
2089
2089
2090 if not name:
2090 if not name:
2091 ui.write(_("\nadditional help topics:\n\n"))
2091 ui.write(_("\nadditional help topics:\n\n"))
2092 topics = []
2092 topics = []
2093 for names, header, doc in help.helptable:
2093 for names, header, doc in help.helptable:
2094 topics.append((sorted(names, key=len, reverse=True)[0], header))
2094 topics.append((sorted(names, key=len, reverse=True)[0], header))
2095 topics_len = max([len(s[0]) for s in topics])
2095 topics_len = max([len(s[0]) for s in topics])
2096 for t, desc in topics:
2096 for t, desc in topics:
2097 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2097 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2098
2098
2099 if opt_output:
2099 if opt_output:
2100 colwidth = encoding.colwidth
2100 colwidth = encoding.colwidth
2101 # normalize: (opt or message, desc or None, width of opt)
2101 # normalize: (opt or message, desc or None, width of opt)
2102 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2102 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2103 for opt, desc in opt_output]
2103 for opt, desc in opt_output]
2104 hanging = max([e[2] for e in entries])
2104 hanging = max([e[2] for e in entries])
2105 for opt, desc, width in entries:
2105 for opt, desc, width in entries:
2106 if desc:
2106 if desc:
2107 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2107 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2108 hangindent = ' ' * (hanging + 3)
2108 hangindent = ' ' * (hanging + 3)
2109 ui.write('%s\n' % (util.wrap(desc,
2109 ui.write('%s\n' % (util.wrap(desc, textwidth,
2110 initindent=initindent,
2110 initindent=initindent,
2111 hangindent=hangindent)))
2111 hangindent=hangindent)))
2112 else:
2112 else:
2113 ui.write("%s\n" % opt)
2113 ui.write("%s\n" % opt)
2114
2114
2115 def identify(ui, repo, source=None,
2115 def identify(ui, repo, source=None,
2116 rev=None, num=None, id=None, branch=None, tags=None):
2116 rev=None, num=None, id=None, branch=None, tags=None):
2117 """identify the working copy or specified revision
2117 """identify the working copy or specified revision
2118
2118
2119 With no revision, print a summary of the current state of the
2119 With no revision, print a summary of the current state of the
2120 repository.
2120 repository.
2121
2121
2122 Specifying a path to a repository root or Mercurial bundle will
2122 Specifying a path to a repository root or Mercurial bundle will
2123 cause lookup to operate on that repository/bundle.
2123 cause lookup to operate on that repository/bundle.
2124
2124
2125 This summary identifies the repository state using one or two
2125 This summary identifies the repository state using one or two
2126 parent hash identifiers, followed by a "+" if there are
2126 parent hash identifiers, followed by a "+" if there are
2127 uncommitted changes in the working directory, a list of tags for
2127 uncommitted changes in the working directory, a list of tags for
2128 this revision and a branch name for non-default branches.
2128 this revision and a branch name for non-default branches.
2129
2129
2130 Returns 0 if successful.
2130 Returns 0 if successful.
2131 """
2131 """
2132
2132
2133 if not repo and not source:
2133 if not repo and not source:
2134 raise util.Abort(_("there is no Mercurial repository here "
2134 raise util.Abort(_("there is no Mercurial repository here "
2135 "(.hg not found)"))
2135 "(.hg not found)"))
2136
2136
2137 hexfunc = ui.debugflag and hex or short
2137 hexfunc = ui.debugflag and hex or short
2138 default = not (num or id or branch or tags)
2138 default = not (num or id or branch or tags)
2139 output = []
2139 output = []
2140
2140
2141 revs = []
2141 revs = []
2142 if source:
2142 if source:
2143 source, branches = hg.parseurl(ui.expandpath(source))
2143 source, branches = hg.parseurl(ui.expandpath(source))
2144 repo = hg.repository(ui, source)
2144 repo = hg.repository(ui, source)
2145 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2145 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2146
2146
2147 if not repo.local():
2147 if not repo.local():
2148 if not rev and revs:
2148 if not rev and revs:
2149 rev = revs[0]
2149 rev = revs[0]
2150 if not rev:
2150 if not rev:
2151 rev = "tip"
2151 rev = "tip"
2152 if num or branch or tags:
2152 if num or branch or tags:
2153 raise util.Abort(
2153 raise util.Abort(
2154 "can't query remote revision number, branch, or tags")
2154 "can't query remote revision number, branch, or tags")
2155 output = [hexfunc(repo.lookup(rev))]
2155 output = [hexfunc(repo.lookup(rev))]
2156 elif not rev:
2156 elif not rev:
2157 ctx = repo[None]
2157 ctx = repo[None]
2158 parents = ctx.parents()
2158 parents = ctx.parents()
2159 changed = False
2159 changed = False
2160 if default or id or num:
2160 if default or id or num:
2161 changed = util.any(repo.status())
2161 changed = util.any(repo.status())
2162 if default or id:
2162 if default or id:
2163 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2163 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2164 (changed) and "+" or "")]
2164 (changed) and "+" or "")]
2165 if num:
2165 if num:
2166 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2166 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2167 (changed) and "+" or ""))
2167 (changed) and "+" or ""))
2168 else:
2168 else:
2169 ctx = repo[rev]
2169 ctx = repo[rev]
2170 if default or id:
2170 if default or id:
2171 output = [hexfunc(ctx.node())]
2171 output = [hexfunc(ctx.node())]
2172 if num:
2172 if num:
2173 output.append(str(ctx.rev()))
2173 output.append(str(ctx.rev()))
2174
2174
2175 if repo.local() and default and not ui.quiet:
2175 if repo.local() and default and not ui.quiet:
2176 b = encoding.tolocal(ctx.branch())
2176 b = encoding.tolocal(ctx.branch())
2177 if b != 'default':
2177 if b != 'default':
2178 output.append("(%s)" % b)
2178 output.append("(%s)" % b)
2179
2179
2180 # multiple tags for a single parent separated by '/'
2180 # multiple tags for a single parent separated by '/'
2181 t = "/".join(ctx.tags())
2181 t = "/".join(ctx.tags())
2182 if t:
2182 if t:
2183 output.append(t)
2183 output.append(t)
2184
2184
2185 if branch:
2185 if branch:
2186 output.append(encoding.tolocal(ctx.branch()))
2186 output.append(encoding.tolocal(ctx.branch()))
2187
2187
2188 if tags:
2188 if tags:
2189 output.extend(ctx.tags())
2189 output.extend(ctx.tags())
2190
2190
2191 ui.write("%s\n" % ' '.join(output))
2191 ui.write("%s\n" % ' '.join(output))
2192
2192
2193 def import_(ui, repo, patch1, *patches, **opts):
2193 def import_(ui, repo, patch1, *patches, **opts):
2194 """import an ordered set of patches
2194 """import an ordered set of patches
2195
2195
2196 Import a list of patches and commit them individually (unless
2196 Import a list of patches and commit them individually (unless
2197 --no-commit is specified).
2197 --no-commit is specified).
2198
2198
2199 If there are outstanding changes in the working directory, import
2199 If there are outstanding changes in the working directory, import
2200 will abort unless given the -f/--force flag.
2200 will abort unless given the -f/--force flag.
2201
2201
2202 You can import a patch straight from a mail message. Even patches
2202 You can import a patch straight from a mail message. Even patches
2203 as attachments work (to use the body part, it must have type
2203 as attachments work (to use the body part, it must have type
2204 text/plain or text/x-patch). From and Subject headers of email
2204 text/plain or text/x-patch). From and Subject headers of email
2205 message are used as default committer and commit message. All
2205 message are used as default committer and commit message. All
2206 text/plain body parts before first diff are added to commit
2206 text/plain body parts before first diff are added to commit
2207 message.
2207 message.
2208
2208
2209 If the imported patch was generated by :hg:`export`, user and
2209 If the imported patch was generated by :hg:`export`, user and
2210 description from patch override values from message headers and
2210 description from patch override values from message headers and
2211 body. Values given on command line with -m/--message and -u/--user
2211 body. Values given on command line with -m/--message and -u/--user
2212 override these.
2212 override these.
2213
2213
2214 If --exact is specified, import will set the working directory to
2214 If --exact is specified, import will set the working directory to
2215 the parent of each patch before applying it, and will abort if the
2215 the parent of each patch before applying it, and will abort if the
2216 resulting changeset has a different ID than the one recorded in
2216 resulting changeset has a different ID than the one recorded in
2217 the patch. This may happen due to character set problems or other
2217 the patch. This may happen due to character set problems or other
2218 deficiencies in the text patch format.
2218 deficiencies in the text patch format.
2219
2219
2220 With -s/--similarity, hg will attempt to discover renames and
2220 With -s/--similarity, hg will attempt to discover renames and
2221 copies in the patch in the same way as 'addremove'.
2221 copies in the patch in the same way as 'addremove'.
2222
2222
2223 To read a patch from standard input, use "-" as the patch name. If
2223 To read a patch from standard input, use "-" as the patch name. If
2224 a URL is specified, the patch will be downloaded from it.
2224 a URL is specified, the patch will be downloaded from it.
2225 See :hg:`help dates` for a list of formats valid for -d/--date.
2225 See :hg:`help dates` for a list of formats valid for -d/--date.
2226
2226
2227 Returns 0 on success.
2227 Returns 0 on success.
2228 """
2228 """
2229 patches = (patch1,) + patches
2229 patches = (patch1,) + patches
2230
2230
2231 date = opts.get('date')
2231 date = opts.get('date')
2232 if date:
2232 if date:
2233 opts['date'] = util.parsedate(date)
2233 opts['date'] = util.parsedate(date)
2234
2234
2235 try:
2235 try:
2236 sim = float(opts.get('similarity') or 0)
2236 sim = float(opts.get('similarity') or 0)
2237 except ValueError:
2237 except ValueError:
2238 raise util.Abort(_('similarity must be a number'))
2238 raise util.Abort(_('similarity must be a number'))
2239 if sim < 0 or sim > 100:
2239 if sim < 0 or sim > 100:
2240 raise util.Abort(_('similarity must be between 0 and 100'))
2240 raise util.Abort(_('similarity must be between 0 and 100'))
2241
2241
2242 if opts.get('exact') or not opts.get('force'):
2242 if opts.get('exact') or not opts.get('force'):
2243 cmdutil.bail_if_changed(repo)
2243 cmdutil.bail_if_changed(repo)
2244
2244
2245 d = opts["base"]
2245 d = opts["base"]
2246 strip = opts["strip"]
2246 strip = opts["strip"]
2247 wlock = lock = None
2247 wlock = lock = None
2248
2248
2249 def tryone(ui, hunk):
2249 def tryone(ui, hunk):
2250 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2250 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2251 patch.extract(ui, hunk)
2251 patch.extract(ui, hunk)
2252
2252
2253 if not tmpname:
2253 if not tmpname:
2254 return None
2254 return None
2255 commitid = _('to working directory')
2255 commitid = _('to working directory')
2256
2256
2257 try:
2257 try:
2258 cmdline_message = cmdutil.logmessage(opts)
2258 cmdline_message = cmdutil.logmessage(opts)
2259 if cmdline_message:
2259 if cmdline_message:
2260 # pickup the cmdline msg
2260 # pickup the cmdline msg
2261 message = cmdline_message
2261 message = cmdline_message
2262 elif message:
2262 elif message:
2263 # pickup the patch msg
2263 # pickup the patch msg
2264 message = message.strip()
2264 message = message.strip()
2265 else:
2265 else:
2266 # launch the editor
2266 # launch the editor
2267 message = None
2267 message = None
2268 ui.debug('message:\n%s\n' % message)
2268 ui.debug('message:\n%s\n' % message)
2269
2269
2270 wp = repo.parents()
2270 wp = repo.parents()
2271 if opts.get('exact'):
2271 if opts.get('exact'):
2272 if not nodeid or not p1:
2272 if not nodeid or not p1:
2273 raise util.Abort(_('not a Mercurial patch'))
2273 raise util.Abort(_('not a Mercurial patch'))
2274 p1 = repo.lookup(p1)
2274 p1 = repo.lookup(p1)
2275 p2 = repo.lookup(p2 or hex(nullid))
2275 p2 = repo.lookup(p2 or hex(nullid))
2276
2276
2277 if p1 != wp[0].node():
2277 if p1 != wp[0].node():
2278 hg.clean(repo, p1)
2278 hg.clean(repo, p1)
2279 repo.dirstate.setparents(p1, p2)
2279 repo.dirstate.setparents(p1, p2)
2280 elif p2:
2280 elif p2:
2281 try:
2281 try:
2282 p1 = repo.lookup(p1)
2282 p1 = repo.lookup(p1)
2283 p2 = repo.lookup(p2)
2283 p2 = repo.lookup(p2)
2284 if p1 == wp[0].node():
2284 if p1 == wp[0].node():
2285 repo.dirstate.setparents(p1, p2)
2285 repo.dirstate.setparents(p1, p2)
2286 except error.RepoError:
2286 except error.RepoError:
2287 pass
2287 pass
2288 if opts.get('exact') or opts.get('import_branch'):
2288 if opts.get('exact') or opts.get('import_branch'):
2289 repo.dirstate.setbranch(branch or 'default')
2289 repo.dirstate.setbranch(branch or 'default')
2290
2290
2291 files = {}
2291 files = {}
2292 try:
2292 try:
2293 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2293 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2294 files=files, eolmode=None)
2294 files=files, eolmode=None)
2295 finally:
2295 finally:
2296 files = cmdutil.updatedir(ui, repo, files,
2296 files = cmdutil.updatedir(ui, repo, files,
2297 similarity=sim / 100.0)
2297 similarity=sim / 100.0)
2298 if not opts.get('no_commit'):
2298 if not opts.get('no_commit'):
2299 if opts.get('exact'):
2299 if opts.get('exact'):
2300 m = None
2300 m = None
2301 else:
2301 else:
2302 m = cmdutil.matchfiles(repo, files or [])
2302 m = cmdutil.matchfiles(repo, files or [])
2303 n = repo.commit(message, opts.get('user') or user,
2303 n = repo.commit(message, opts.get('user') or user,
2304 opts.get('date') or date, match=m,
2304 opts.get('date') or date, match=m,
2305 editor=cmdutil.commiteditor)
2305 editor=cmdutil.commiteditor)
2306 if opts.get('exact'):
2306 if opts.get('exact'):
2307 if hex(n) != nodeid:
2307 if hex(n) != nodeid:
2308 repo.rollback()
2308 repo.rollback()
2309 raise util.Abort(_('patch is damaged'
2309 raise util.Abort(_('patch is damaged'
2310 ' or loses information'))
2310 ' or loses information'))
2311 # Force a dirstate write so that the next transaction
2311 # Force a dirstate write so that the next transaction
2312 # backups an up-do-date file.
2312 # backups an up-do-date file.
2313 repo.dirstate.write()
2313 repo.dirstate.write()
2314 if n:
2314 if n:
2315 commitid = short(n)
2315 commitid = short(n)
2316
2316
2317 return commitid
2317 return commitid
2318 finally:
2318 finally:
2319 os.unlink(tmpname)
2319 os.unlink(tmpname)
2320
2320
2321 try:
2321 try:
2322 wlock = repo.wlock()
2322 wlock = repo.wlock()
2323 lock = repo.lock()
2323 lock = repo.lock()
2324 lastcommit = None
2324 lastcommit = None
2325 for p in patches:
2325 for p in patches:
2326 pf = os.path.join(d, p)
2326 pf = os.path.join(d, p)
2327
2327
2328 if pf == '-':
2328 if pf == '-':
2329 ui.status(_("applying patch from stdin\n"))
2329 ui.status(_("applying patch from stdin\n"))
2330 pf = sys.stdin
2330 pf = sys.stdin
2331 else:
2331 else:
2332 ui.status(_("applying %s\n") % p)
2332 ui.status(_("applying %s\n") % p)
2333 pf = url.open(ui, pf)
2333 pf = url.open(ui, pf)
2334
2334
2335 haspatch = False
2335 haspatch = False
2336 for hunk in patch.split(pf):
2336 for hunk in patch.split(pf):
2337 commitid = tryone(ui, hunk)
2337 commitid = tryone(ui, hunk)
2338 if commitid:
2338 if commitid:
2339 haspatch = True
2339 haspatch = True
2340 if lastcommit:
2340 if lastcommit:
2341 ui.status(_('applied %s\n') % lastcommit)
2341 ui.status(_('applied %s\n') % lastcommit)
2342 lastcommit = commitid
2342 lastcommit = commitid
2343
2343
2344 if not haspatch:
2344 if not haspatch:
2345 raise util.Abort(_('no diffs found'))
2345 raise util.Abort(_('no diffs found'))
2346
2346
2347 finally:
2347 finally:
2348 release(lock, wlock)
2348 release(lock, wlock)
2349
2349
2350 def incoming(ui, repo, source="default", **opts):
2350 def incoming(ui, repo, source="default", **opts):
2351 """show new changesets found in source
2351 """show new changesets found in source
2352
2352
2353 Show new changesets found in the specified path/URL or the default
2353 Show new changesets found in the specified path/URL or the default
2354 pull location. These are the changesets that would have been pulled
2354 pull location. These are the changesets that would have been pulled
2355 if a pull at the time you issued this command.
2355 if a pull at the time you issued this command.
2356
2356
2357 For remote repository, using --bundle avoids downloading the
2357 For remote repository, using --bundle avoids downloading the
2358 changesets twice if the incoming is followed by a pull.
2358 changesets twice if the incoming is followed by a pull.
2359
2359
2360 See pull for valid source format details.
2360 See pull for valid source format details.
2361
2361
2362 Returns 0 if there are incoming changes, 1 otherwise.
2362 Returns 0 if there are incoming changes, 1 otherwise.
2363 """
2363 """
2364 if opts.get('bundle') and opts.get('subrepos'):
2364 if opts.get('bundle') and opts.get('subrepos'):
2365 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2365 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2366
2366
2367 ret = hg.incoming(ui, repo, source, opts)
2367 ret = hg.incoming(ui, repo, source, opts)
2368 return ret
2368 return ret
2369
2369
2370 def init(ui, dest=".", **opts):
2370 def init(ui, dest=".", **opts):
2371 """create a new repository in the given directory
2371 """create a new repository in the given directory
2372
2372
2373 Initialize a new repository in the given directory. If the given
2373 Initialize a new repository in the given directory. If the given
2374 directory does not exist, it will be created.
2374 directory does not exist, it will be created.
2375
2375
2376 If no directory is given, the current directory is used.
2376 If no directory is given, the current directory is used.
2377
2377
2378 It is possible to specify an ``ssh://`` URL as the destination.
2378 It is possible to specify an ``ssh://`` URL as the destination.
2379 See :hg:`help urls` for more information.
2379 See :hg:`help urls` for more information.
2380
2380
2381 Returns 0 on success.
2381 Returns 0 on success.
2382 """
2382 """
2383 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2383 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2384
2384
2385 def locate(ui, repo, *pats, **opts):
2385 def locate(ui, repo, *pats, **opts):
2386 """locate files matching specific patterns
2386 """locate files matching specific patterns
2387
2387
2388 Print files under Mercurial control in the working directory whose
2388 Print files under Mercurial control in the working directory whose
2389 names match the given patterns.
2389 names match the given patterns.
2390
2390
2391 By default, this command searches all directories in the working
2391 By default, this command searches all directories in the working
2392 directory. To search just the current directory and its
2392 directory. To search just the current directory and its
2393 subdirectories, use "--include .".
2393 subdirectories, use "--include .".
2394
2394
2395 If no patterns are given to match, this command prints the names
2395 If no patterns are given to match, this command prints the names
2396 of all files under Mercurial control in the working directory.
2396 of all files under Mercurial control in the working directory.
2397
2397
2398 If you want to feed the output of this command into the "xargs"
2398 If you want to feed the output of this command into the "xargs"
2399 command, use the -0 option to both this command and "xargs". This
2399 command, use the -0 option to both this command and "xargs". This
2400 will avoid the problem of "xargs" treating single filenames that
2400 will avoid the problem of "xargs" treating single filenames that
2401 contain whitespace as multiple filenames.
2401 contain whitespace as multiple filenames.
2402
2402
2403 Returns 0 if a match is found, 1 otherwise.
2403 Returns 0 if a match is found, 1 otherwise.
2404 """
2404 """
2405 end = opts.get('print0') and '\0' or '\n'
2405 end = opts.get('print0') and '\0' or '\n'
2406 rev = opts.get('rev') or None
2406 rev = opts.get('rev') or None
2407
2407
2408 ret = 1
2408 ret = 1
2409 m = cmdutil.match(repo, pats, opts, default='relglob')
2409 m = cmdutil.match(repo, pats, opts, default='relglob')
2410 m.bad = lambda x, y: False
2410 m.bad = lambda x, y: False
2411 for abs in repo[rev].walk(m):
2411 for abs in repo[rev].walk(m):
2412 if not rev and abs not in repo.dirstate:
2412 if not rev and abs not in repo.dirstate:
2413 continue
2413 continue
2414 if opts.get('fullpath'):
2414 if opts.get('fullpath'):
2415 ui.write(repo.wjoin(abs), end)
2415 ui.write(repo.wjoin(abs), end)
2416 else:
2416 else:
2417 ui.write(((pats and m.rel(abs)) or abs), end)
2417 ui.write(((pats and m.rel(abs)) or abs), end)
2418 ret = 0
2418 ret = 0
2419
2419
2420 return ret
2420 return ret
2421
2421
2422 def log(ui, repo, *pats, **opts):
2422 def log(ui, repo, *pats, **opts):
2423 """show revision history of entire repository or files
2423 """show revision history of entire repository or files
2424
2424
2425 Print the revision history of the specified files or the entire
2425 Print the revision history of the specified files or the entire
2426 project.
2426 project.
2427
2427
2428 File history is shown without following rename or copy history of
2428 File history is shown without following rename or copy history of
2429 files. Use -f/--follow with a filename to follow history across
2429 files. Use -f/--follow with a filename to follow history across
2430 renames and copies. --follow without a filename will only show
2430 renames and copies. --follow without a filename will only show
2431 ancestors or descendants of the starting revision. --follow-first
2431 ancestors or descendants of the starting revision. --follow-first
2432 only follows the first parent of merge revisions.
2432 only follows the first parent of merge revisions.
2433
2433
2434 If no revision range is specified, the default is tip:0 unless
2434 If no revision range is specified, the default is tip:0 unless
2435 --follow is set, in which case the working directory parent is
2435 --follow is set, in which case the working directory parent is
2436 used as the starting revision. You can specify a revision set for
2436 used as the starting revision. You can specify a revision set for
2437 log, see :hg:`help revsets` for more information.
2437 log, see :hg:`help revsets` for more information.
2438
2438
2439 See :hg:`help dates` for a list of formats valid for -d/--date.
2439 See :hg:`help dates` for a list of formats valid for -d/--date.
2440
2440
2441 By default this command prints revision number and changeset id,
2441 By default this command prints revision number and changeset id,
2442 tags, non-trivial parents, user, date and time, and a summary for
2442 tags, non-trivial parents, user, date and time, and a summary for
2443 each commit. When the -v/--verbose switch is used, the list of
2443 each commit. When the -v/--verbose switch is used, the list of
2444 changed files and full commit message are shown.
2444 changed files and full commit message are shown.
2445
2445
2446 .. note::
2446 .. note::
2447 log -p/--patch may generate unexpected diff output for merge
2447 log -p/--patch may generate unexpected diff output for merge
2448 changesets, as it will only compare the merge changeset against
2448 changesets, as it will only compare the merge changeset against
2449 its first parent. Also, only files different from BOTH parents
2449 its first parent. Also, only files different from BOTH parents
2450 will appear in files:.
2450 will appear in files:.
2451
2451
2452 Returns 0 on success.
2452 Returns 0 on success.
2453 """
2453 """
2454
2454
2455 matchfn = cmdutil.match(repo, pats, opts)
2455 matchfn = cmdutil.match(repo, pats, opts)
2456 limit = cmdutil.loglimit(opts)
2456 limit = cmdutil.loglimit(opts)
2457 count = 0
2457 count = 0
2458
2458
2459 endrev = None
2459 endrev = None
2460 if opts.get('copies') and opts.get('rev'):
2460 if opts.get('copies') and opts.get('rev'):
2461 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2461 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2462
2462
2463 df = False
2463 df = False
2464 if opts["date"]:
2464 if opts["date"]:
2465 df = util.matchdate(opts["date"])
2465 df = util.matchdate(opts["date"])
2466
2466
2467 branches = opts.get('branch', []) + opts.get('only_branch', [])
2467 branches = opts.get('branch', []) + opts.get('only_branch', [])
2468 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2468 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2469
2469
2470 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2470 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2471 def prep(ctx, fns):
2471 def prep(ctx, fns):
2472 rev = ctx.rev()
2472 rev = ctx.rev()
2473 parents = [p for p in repo.changelog.parentrevs(rev)
2473 parents = [p for p in repo.changelog.parentrevs(rev)
2474 if p != nullrev]
2474 if p != nullrev]
2475 if opts.get('no_merges') and len(parents) == 2:
2475 if opts.get('no_merges') and len(parents) == 2:
2476 return
2476 return
2477 if opts.get('only_merges') and len(parents) != 2:
2477 if opts.get('only_merges') and len(parents) != 2:
2478 return
2478 return
2479 if opts.get('branch') and ctx.branch() not in opts['branch']:
2479 if opts.get('branch') and ctx.branch() not in opts['branch']:
2480 return
2480 return
2481 if df and not df(ctx.date()[0]):
2481 if df and not df(ctx.date()[0]):
2482 return
2482 return
2483 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2483 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2484 return
2484 return
2485 if opts.get('keyword'):
2485 if opts.get('keyword'):
2486 for k in [kw.lower() for kw in opts['keyword']]:
2486 for k in [kw.lower() for kw in opts['keyword']]:
2487 if (k in ctx.user().lower() or
2487 if (k in ctx.user().lower() or
2488 k in ctx.description().lower() or
2488 k in ctx.description().lower() or
2489 k in " ".join(ctx.files()).lower()):
2489 k in " ".join(ctx.files()).lower()):
2490 break
2490 break
2491 else:
2491 else:
2492 return
2492 return
2493
2493
2494 copies = None
2494 copies = None
2495 if opts.get('copies') and rev:
2495 if opts.get('copies') and rev:
2496 copies = []
2496 copies = []
2497 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2497 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2498 for fn in ctx.files():
2498 for fn in ctx.files():
2499 rename = getrenamed(fn, rev)
2499 rename = getrenamed(fn, rev)
2500 if rename:
2500 if rename:
2501 copies.append((fn, rename[0]))
2501 copies.append((fn, rename[0]))
2502
2502
2503 revmatchfn = None
2503 revmatchfn = None
2504 if opts.get('patch') or opts.get('stat'):
2504 if opts.get('patch') or opts.get('stat'):
2505 if opts.get('follow') or opts.get('follow_first'):
2505 if opts.get('follow') or opts.get('follow_first'):
2506 # note: this might be wrong when following through merges
2506 # note: this might be wrong when following through merges
2507 revmatchfn = cmdutil.match(repo, fns, default='path')
2507 revmatchfn = cmdutil.match(repo, fns, default='path')
2508 else:
2508 else:
2509 revmatchfn = matchfn
2509 revmatchfn = matchfn
2510
2510
2511 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2511 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2512
2512
2513 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2513 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2514 if count == limit:
2514 if count == limit:
2515 break
2515 break
2516 if displayer.flush(ctx.rev()):
2516 if displayer.flush(ctx.rev()):
2517 count += 1
2517 count += 1
2518 displayer.close()
2518 displayer.close()
2519
2519
2520 def manifest(ui, repo, node=None, rev=None):
2520 def manifest(ui, repo, node=None, rev=None):
2521 """output the current or given revision of the project manifest
2521 """output the current or given revision of the project manifest
2522
2522
2523 Print a list of version controlled files for the given revision.
2523 Print a list of version controlled files for the given revision.
2524 If no revision is given, the first parent of the working directory
2524 If no revision is given, the first parent of the working directory
2525 is used, or the null revision if no revision is checked out.
2525 is used, or the null revision if no revision is checked out.
2526
2526
2527 With -v, print file permissions, symlink and executable bits.
2527 With -v, print file permissions, symlink and executable bits.
2528 With --debug, print file revision hashes.
2528 With --debug, print file revision hashes.
2529
2529
2530 Returns 0 on success.
2530 Returns 0 on success.
2531 """
2531 """
2532
2532
2533 if rev and node:
2533 if rev and node:
2534 raise util.Abort(_("please specify just one revision"))
2534 raise util.Abort(_("please specify just one revision"))
2535
2535
2536 if not node:
2536 if not node:
2537 node = rev
2537 node = rev
2538
2538
2539 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2539 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2540 ctx = repo[node]
2540 ctx = repo[node]
2541 for f in ctx:
2541 for f in ctx:
2542 if ui.debugflag:
2542 if ui.debugflag:
2543 ui.write("%40s " % hex(ctx.manifest()[f]))
2543 ui.write("%40s " % hex(ctx.manifest()[f]))
2544 if ui.verbose:
2544 if ui.verbose:
2545 ui.write(decor[ctx.flags(f)])
2545 ui.write(decor[ctx.flags(f)])
2546 ui.write("%s\n" % f)
2546 ui.write("%s\n" % f)
2547
2547
2548 def merge(ui, repo, node=None, **opts):
2548 def merge(ui, repo, node=None, **opts):
2549 """merge working directory with another revision
2549 """merge working directory with another revision
2550
2550
2551 The current working directory is updated with all changes made in
2551 The current working directory is updated with all changes made in
2552 the requested revision since the last common predecessor revision.
2552 the requested revision since the last common predecessor revision.
2553
2553
2554 Files that changed between either parent are marked as changed for
2554 Files that changed between either parent are marked as changed for
2555 the next commit and a commit must be performed before any further
2555 the next commit and a commit must be performed before any further
2556 updates to the repository are allowed. The next commit will have
2556 updates to the repository are allowed. The next commit will have
2557 two parents.
2557 two parents.
2558
2558
2559 If no revision is specified, the working directory's parent is a
2559 If no revision is specified, the working directory's parent is a
2560 head revision, and the current branch contains exactly one other
2560 head revision, and the current branch contains exactly one other
2561 head, the other head is merged with by default. Otherwise, an
2561 head, the other head is merged with by default. Otherwise, an
2562 explicit revision with which to merge with must be provided.
2562 explicit revision with which to merge with must be provided.
2563
2563
2564 To undo an uncommitted merge, use :hg:`update --clean .` which
2564 To undo an uncommitted merge, use :hg:`update --clean .` which
2565 will check out a clean copy of the original merge parent, losing
2565 will check out a clean copy of the original merge parent, losing
2566 all changes.
2566 all changes.
2567
2567
2568 Returns 0 on success, 1 if there are unresolved files.
2568 Returns 0 on success, 1 if there are unresolved files.
2569 """
2569 """
2570
2570
2571 if opts.get('rev') and node:
2571 if opts.get('rev') and node:
2572 raise util.Abort(_("please specify just one revision"))
2572 raise util.Abort(_("please specify just one revision"))
2573 if not node:
2573 if not node:
2574 node = opts.get('rev')
2574 node = opts.get('rev')
2575
2575
2576 if not node:
2576 if not node:
2577 branch = repo.changectx(None).branch()
2577 branch = repo.changectx(None).branch()
2578 bheads = repo.branchheads(branch)
2578 bheads = repo.branchheads(branch)
2579 if len(bheads) > 2:
2579 if len(bheads) > 2:
2580 raise util.Abort(_(
2580 raise util.Abort(_(
2581 'branch \'%s\' has %d heads - '
2581 'branch \'%s\' has %d heads - '
2582 'please merge with an explicit rev\n'
2582 'please merge with an explicit rev\n'
2583 '(run \'hg heads .\' to see heads)')
2583 '(run \'hg heads .\' to see heads)')
2584 % (branch, len(bheads)))
2584 % (branch, len(bheads)))
2585
2585
2586 parent = repo.dirstate.parents()[0]
2586 parent = repo.dirstate.parents()[0]
2587 if len(bheads) == 1:
2587 if len(bheads) == 1:
2588 if len(repo.heads()) > 1:
2588 if len(repo.heads()) > 1:
2589 raise util.Abort(_(
2589 raise util.Abort(_(
2590 'branch \'%s\' has one head - '
2590 'branch \'%s\' has one head - '
2591 'please merge with an explicit rev\n'
2591 'please merge with an explicit rev\n'
2592 '(run \'hg heads\' to see all heads)')
2592 '(run \'hg heads\' to see all heads)')
2593 % branch)
2593 % branch)
2594 msg = _('there is nothing to merge')
2594 msg = _('there is nothing to merge')
2595 if parent != repo.lookup(repo[None].branch()):
2595 if parent != repo.lookup(repo[None].branch()):
2596 msg = _('%s - use "hg update" instead') % msg
2596 msg = _('%s - use "hg update" instead') % msg
2597 raise util.Abort(msg)
2597 raise util.Abort(msg)
2598
2598
2599 if parent not in bheads:
2599 if parent not in bheads:
2600 raise util.Abort(_('working dir not at a head rev - '
2600 raise util.Abort(_('working dir not at a head rev - '
2601 'use "hg update" or merge with an explicit rev'))
2601 'use "hg update" or merge with an explicit rev'))
2602 node = parent == bheads[0] and bheads[-1] or bheads[0]
2602 node = parent == bheads[0] and bheads[-1] or bheads[0]
2603
2603
2604 if opts.get('preview'):
2604 if opts.get('preview'):
2605 # find nodes that are ancestors of p2 but not of p1
2605 # find nodes that are ancestors of p2 but not of p1
2606 p1 = repo.lookup('.')
2606 p1 = repo.lookup('.')
2607 p2 = repo.lookup(node)
2607 p2 = repo.lookup(node)
2608 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2608 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2609
2609
2610 displayer = cmdutil.show_changeset(ui, repo, opts)
2610 displayer = cmdutil.show_changeset(ui, repo, opts)
2611 for node in nodes:
2611 for node in nodes:
2612 displayer.show(repo[node])
2612 displayer.show(repo[node])
2613 displayer.close()
2613 displayer.close()
2614 return 0
2614 return 0
2615
2615
2616 return hg.merge(repo, node, force=opts.get('force'))
2616 return hg.merge(repo, node, force=opts.get('force'))
2617
2617
2618 def outgoing(ui, repo, dest=None, **opts):
2618 def outgoing(ui, repo, dest=None, **opts):
2619 """show changesets not found in the destination
2619 """show changesets not found in the destination
2620
2620
2621 Show changesets not found in the specified destination repository
2621 Show changesets not found in the specified destination repository
2622 or the default push location. These are the changesets that would
2622 or the default push location. These are the changesets that would
2623 be pushed if a push was requested.
2623 be pushed if a push was requested.
2624
2624
2625 See pull for details of valid destination formats.
2625 See pull for details of valid destination formats.
2626
2626
2627 Returns 0 if there are outgoing changes, 1 otherwise.
2627 Returns 0 if there are outgoing changes, 1 otherwise.
2628 """
2628 """
2629 ret = hg.outgoing(ui, repo, dest, opts)
2629 ret = hg.outgoing(ui, repo, dest, opts)
2630 return ret
2630 return ret
2631
2631
2632 def parents(ui, repo, file_=None, **opts):
2632 def parents(ui, repo, file_=None, **opts):
2633 """show the parents of the working directory or revision
2633 """show the parents of the working directory or revision
2634
2634
2635 Print the working directory's parent revisions. If a revision is
2635 Print the working directory's parent revisions. If a revision is
2636 given via -r/--rev, the parent of that revision will be printed.
2636 given via -r/--rev, the parent of that revision will be printed.
2637 If a file argument is given, the revision in which the file was
2637 If a file argument is given, the revision in which the file was
2638 last changed (before the working directory revision or the
2638 last changed (before the working directory revision or the
2639 argument to --rev if given) is printed.
2639 argument to --rev if given) is printed.
2640
2640
2641 Returns 0 on success.
2641 Returns 0 on success.
2642 """
2642 """
2643 rev = opts.get('rev')
2643 rev = opts.get('rev')
2644 if rev:
2644 if rev:
2645 ctx = repo[rev]
2645 ctx = repo[rev]
2646 else:
2646 else:
2647 ctx = repo[None]
2647 ctx = repo[None]
2648
2648
2649 if file_:
2649 if file_:
2650 m = cmdutil.match(repo, (file_,), opts)
2650 m = cmdutil.match(repo, (file_,), opts)
2651 if m.anypats() or len(m.files()) != 1:
2651 if m.anypats() or len(m.files()) != 1:
2652 raise util.Abort(_('can only specify an explicit filename'))
2652 raise util.Abort(_('can only specify an explicit filename'))
2653 file_ = m.files()[0]
2653 file_ = m.files()[0]
2654 filenodes = []
2654 filenodes = []
2655 for cp in ctx.parents():
2655 for cp in ctx.parents():
2656 if not cp:
2656 if not cp:
2657 continue
2657 continue
2658 try:
2658 try:
2659 filenodes.append(cp.filenode(file_))
2659 filenodes.append(cp.filenode(file_))
2660 except error.LookupError:
2660 except error.LookupError:
2661 pass
2661 pass
2662 if not filenodes:
2662 if not filenodes:
2663 raise util.Abort(_("'%s' not found in manifest!") % file_)
2663 raise util.Abort(_("'%s' not found in manifest!") % file_)
2664 fl = repo.file(file_)
2664 fl = repo.file(file_)
2665 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2665 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2666 else:
2666 else:
2667 p = [cp.node() for cp in ctx.parents()]
2667 p = [cp.node() for cp in ctx.parents()]
2668
2668
2669 displayer = cmdutil.show_changeset(ui, repo, opts)
2669 displayer = cmdutil.show_changeset(ui, repo, opts)
2670 for n in p:
2670 for n in p:
2671 if n != nullid:
2671 if n != nullid:
2672 displayer.show(repo[n])
2672 displayer.show(repo[n])
2673 displayer.close()
2673 displayer.close()
2674
2674
2675 def paths(ui, repo, search=None):
2675 def paths(ui, repo, search=None):
2676 """show aliases for remote repositories
2676 """show aliases for remote repositories
2677
2677
2678 Show definition of symbolic path name NAME. If no name is given,
2678 Show definition of symbolic path name NAME. If no name is given,
2679 show definition of all available names.
2679 show definition of all available names.
2680
2680
2681 Path names are defined in the [paths] section of your
2681 Path names are defined in the [paths] section of your
2682 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2682 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2683 repository, ``.hg/hgrc`` is used, too.
2683 repository, ``.hg/hgrc`` is used, too.
2684
2684
2685 The path names ``default`` and ``default-push`` have a special
2685 The path names ``default`` and ``default-push`` have a special
2686 meaning. When performing a push or pull operation, they are used
2686 meaning. When performing a push or pull operation, they are used
2687 as fallbacks if no location is specified on the command-line.
2687 as fallbacks if no location is specified on the command-line.
2688 When ``default-push`` is set, it will be used for push and
2688 When ``default-push`` is set, it will be used for push and
2689 ``default`` will be used for pull; otherwise ``default`` is used
2689 ``default`` will be used for pull; otherwise ``default`` is used
2690 as the fallback for both. When cloning a repository, the clone
2690 as the fallback for both. When cloning a repository, the clone
2691 source is written as ``default`` in ``.hg/hgrc``. Note that
2691 source is written as ``default`` in ``.hg/hgrc``. Note that
2692 ``default`` and ``default-push`` apply to all inbound (e.g.
2692 ``default`` and ``default-push`` apply to all inbound (e.g.
2693 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2693 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2694 :hg:`bundle`) operations.
2694 :hg:`bundle`) operations.
2695
2695
2696 See :hg:`help urls` for more information.
2696 See :hg:`help urls` for more information.
2697
2697
2698 Returns 0 on success.
2698 Returns 0 on success.
2699 """
2699 """
2700 if search:
2700 if search:
2701 for name, path in ui.configitems("paths"):
2701 for name, path in ui.configitems("paths"):
2702 if name == search:
2702 if name == search:
2703 ui.write("%s\n" % url.hidepassword(path))
2703 ui.write("%s\n" % url.hidepassword(path))
2704 return
2704 return
2705 ui.warn(_("not found!\n"))
2705 ui.warn(_("not found!\n"))
2706 return 1
2706 return 1
2707 else:
2707 else:
2708 for name, path in ui.configitems("paths"):
2708 for name, path in ui.configitems("paths"):
2709 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2709 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2710
2710
2711 def postincoming(ui, repo, modheads, optupdate, checkout):
2711 def postincoming(ui, repo, modheads, optupdate, checkout):
2712 if modheads == 0:
2712 if modheads == 0:
2713 return
2713 return
2714 if optupdate:
2714 if optupdate:
2715 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2715 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2716 return hg.update(repo, checkout)
2716 return hg.update(repo, checkout)
2717 else:
2717 else:
2718 ui.status(_("not updating, since new heads added\n"))
2718 ui.status(_("not updating, since new heads added\n"))
2719 if modheads > 1:
2719 if modheads > 1:
2720 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2720 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2721 else:
2721 else:
2722 ui.status(_("(run 'hg update' to get a working copy)\n"))
2722 ui.status(_("(run 'hg update' to get a working copy)\n"))
2723
2723
2724 def pull(ui, repo, source="default", **opts):
2724 def pull(ui, repo, source="default", **opts):
2725 """pull changes from the specified source
2725 """pull changes from the specified source
2726
2726
2727 Pull changes from a remote repository to a local one.
2727 Pull changes from a remote repository to a local one.
2728
2728
2729 This finds all changes from the repository at the specified path
2729 This finds all changes from the repository at the specified path
2730 or URL and adds them to a local repository (the current one unless
2730 or URL and adds them to a local repository (the current one unless
2731 -R is specified). By default, this does not update the copy of the
2731 -R is specified). By default, this does not update the copy of the
2732 project in the working directory.
2732 project in the working directory.
2733
2733
2734 Use :hg:`incoming` if you want to see what would have been added
2734 Use :hg:`incoming` if you want to see what would have been added
2735 by a pull at the time you issued this command. If you then decide
2735 by a pull at the time you issued this command. If you then decide
2736 to add those changes to the repository, you should use :hg:`pull
2736 to add those changes to the repository, you should use :hg:`pull
2737 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2737 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2738
2738
2739 If SOURCE is omitted, the 'default' path will be used.
2739 If SOURCE is omitted, the 'default' path will be used.
2740 See :hg:`help urls` for more information.
2740 See :hg:`help urls` for more information.
2741
2741
2742 Returns 0 on success, 1 if an update had unresolved files.
2742 Returns 0 on success, 1 if an update had unresolved files.
2743 """
2743 """
2744 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2744 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2745 other = hg.repository(hg.remoteui(repo, opts), source)
2745 other = hg.repository(hg.remoteui(repo, opts), source)
2746 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2746 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2747 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2747 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2748 if revs:
2748 if revs:
2749 try:
2749 try:
2750 revs = [other.lookup(rev) for rev in revs]
2750 revs = [other.lookup(rev) for rev in revs]
2751 except error.CapabilityError:
2751 except error.CapabilityError:
2752 err = _("other repository doesn't support revision lookup, "
2752 err = _("other repository doesn't support revision lookup, "
2753 "so a rev cannot be specified.")
2753 "so a rev cannot be specified.")
2754 raise util.Abort(err)
2754 raise util.Abort(err)
2755
2755
2756 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2756 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2757 if checkout:
2757 if checkout:
2758 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2758 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2759 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2759 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2760
2760
2761 def push(ui, repo, dest=None, **opts):
2761 def push(ui, repo, dest=None, **opts):
2762 """push changes to the specified destination
2762 """push changes to the specified destination
2763
2763
2764 Push changesets from the local repository to the specified
2764 Push changesets from the local repository to the specified
2765 destination.
2765 destination.
2766
2766
2767 This operation is symmetrical to pull: it is identical to a pull
2767 This operation is symmetrical to pull: it is identical to a pull
2768 in the destination repository from the current one.
2768 in the destination repository from the current one.
2769
2769
2770 By default, push will not allow creation of new heads at the
2770 By default, push will not allow creation of new heads at the
2771 destination, since multiple heads would make it unclear which head
2771 destination, since multiple heads would make it unclear which head
2772 to use. In this situation, it is recommended to pull and merge
2772 to use. In this situation, it is recommended to pull and merge
2773 before pushing.
2773 before pushing.
2774
2774
2775 Use --new-branch if you want to allow push to create a new named
2775 Use --new-branch if you want to allow push to create a new named
2776 branch that is not present at the destination. This allows you to
2776 branch that is not present at the destination. This allows you to
2777 only create a new branch without forcing other changes.
2777 only create a new branch without forcing other changes.
2778
2778
2779 Use -f/--force to override the default behavior and push all
2779 Use -f/--force to override the default behavior and push all
2780 changesets on all branches.
2780 changesets on all branches.
2781
2781
2782 If -r/--rev is used, the specified revision and all its ancestors
2782 If -r/--rev is used, the specified revision and all its ancestors
2783 will be pushed to the remote repository.
2783 will be pushed to the remote repository.
2784
2784
2785 Please see :hg:`help urls` for important details about ``ssh://``
2785 Please see :hg:`help urls` for important details about ``ssh://``
2786 URLs. If DESTINATION is omitted, a default path will be used.
2786 URLs. If DESTINATION is omitted, a default path will be used.
2787
2787
2788 Returns 0 if push was successful, 1 if nothing to push.
2788 Returns 0 if push was successful, 1 if nothing to push.
2789 """
2789 """
2790 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2790 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2791 dest, branches = hg.parseurl(dest, opts.get('branch'))
2791 dest, branches = hg.parseurl(dest, opts.get('branch'))
2792 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2792 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2793 other = hg.repository(hg.remoteui(repo, opts), dest)
2793 other = hg.repository(hg.remoteui(repo, opts), dest)
2794 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2794 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2795 if revs:
2795 if revs:
2796 revs = [repo.lookup(rev) for rev in revs]
2796 revs = [repo.lookup(rev) for rev in revs]
2797
2797
2798 # push subrepos depth-first for coherent ordering
2798 # push subrepos depth-first for coherent ordering
2799 c = repo['']
2799 c = repo['']
2800 subs = c.substate # only repos that are committed
2800 subs = c.substate # only repos that are committed
2801 for s in sorted(subs):
2801 for s in sorted(subs):
2802 if not c.sub(s).push(opts.get('force')):
2802 if not c.sub(s).push(opts.get('force')):
2803 return False
2803 return False
2804
2804
2805 r = repo.push(other, opts.get('force'), revs=revs,
2805 r = repo.push(other, opts.get('force'), revs=revs,
2806 newbranch=opts.get('new_branch'))
2806 newbranch=opts.get('new_branch'))
2807 return r == 0
2807 return r == 0
2808
2808
2809 def recover(ui, repo):
2809 def recover(ui, repo):
2810 """roll back an interrupted transaction
2810 """roll back an interrupted transaction
2811
2811
2812 Recover from an interrupted commit or pull.
2812 Recover from an interrupted commit or pull.
2813
2813
2814 This command tries to fix the repository status after an
2814 This command tries to fix the repository status after an
2815 interrupted operation. It should only be necessary when Mercurial
2815 interrupted operation. It should only be necessary when Mercurial
2816 suggests it.
2816 suggests it.
2817
2817
2818 Returns 0 if successful, 1 if nothing to recover or verify fails.
2818 Returns 0 if successful, 1 if nothing to recover or verify fails.
2819 """
2819 """
2820 if repo.recover():
2820 if repo.recover():
2821 return hg.verify(repo)
2821 return hg.verify(repo)
2822 return 1
2822 return 1
2823
2823
2824 def remove(ui, repo, *pats, **opts):
2824 def remove(ui, repo, *pats, **opts):
2825 """remove the specified files on the next commit
2825 """remove the specified files on the next commit
2826
2826
2827 Schedule the indicated files for removal from the repository.
2827 Schedule the indicated files for removal from the repository.
2828
2828
2829 This only removes files from the current branch, not from the
2829 This only removes files from the current branch, not from the
2830 entire project history. -A/--after can be used to remove only
2830 entire project history. -A/--after can be used to remove only
2831 files that have already been deleted, -f/--force can be used to
2831 files that have already been deleted, -f/--force can be used to
2832 force deletion, and -Af can be used to remove files from the next
2832 force deletion, and -Af can be used to remove files from the next
2833 revision without deleting them from the working directory.
2833 revision without deleting them from the working directory.
2834
2834
2835 The following table details the behavior of remove for different
2835 The following table details the behavior of remove for different
2836 file states (columns) and option combinations (rows). The file
2836 file states (columns) and option combinations (rows). The file
2837 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2837 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2838 reported by :hg:`status`). The actions are Warn, Remove (from
2838 reported by :hg:`status`). The actions are Warn, Remove (from
2839 branch) and Delete (from disk)::
2839 branch) and Delete (from disk)::
2840
2840
2841 A C M !
2841 A C M !
2842 none W RD W R
2842 none W RD W R
2843 -f R RD RD R
2843 -f R RD RD R
2844 -A W W W R
2844 -A W W W R
2845 -Af R R R R
2845 -Af R R R R
2846
2846
2847 This command schedules the files to be removed at the next commit.
2847 This command schedules the files to be removed at the next commit.
2848 To undo a remove before that, see :hg:`revert`.
2848 To undo a remove before that, see :hg:`revert`.
2849
2849
2850 Returns 0 on success, 1 if any warnings encountered.
2850 Returns 0 on success, 1 if any warnings encountered.
2851 """
2851 """
2852
2852
2853 ret = 0
2853 ret = 0
2854 after, force = opts.get('after'), opts.get('force')
2854 after, force = opts.get('after'), opts.get('force')
2855 if not pats and not after:
2855 if not pats and not after:
2856 raise util.Abort(_('no files specified'))
2856 raise util.Abort(_('no files specified'))
2857
2857
2858 m = cmdutil.match(repo, pats, opts)
2858 m = cmdutil.match(repo, pats, opts)
2859 s = repo.status(match=m, clean=True)
2859 s = repo.status(match=m, clean=True)
2860 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2860 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2861
2861
2862 for f in m.files():
2862 for f in m.files():
2863 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2863 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2864 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2864 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2865 ret = 1
2865 ret = 1
2866
2866
2867 if force:
2867 if force:
2868 remove, forget = modified + deleted + clean, added
2868 remove, forget = modified + deleted + clean, added
2869 elif after:
2869 elif after:
2870 remove, forget = deleted, []
2870 remove, forget = deleted, []
2871 for f in modified + added + clean:
2871 for f in modified + added + clean:
2872 ui.warn(_('not removing %s: file still exists (use -f'
2872 ui.warn(_('not removing %s: file still exists (use -f'
2873 ' to force removal)\n') % m.rel(f))
2873 ' to force removal)\n') % m.rel(f))
2874 ret = 1
2874 ret = 1
2875 else:
2875 else:
2876 remove, forget = deleted + clean, []
2876 remove, forget = deleted + clean, []
2877 for f in modified:
2877 for f in modified:
2878 ui.warn(_('not removing %s: file is modified (use -f'
2878 ui.warn(_('not removing %s: file is modified (use -f'
2879 ' to force removal)\n') % m.rel(f))
2879 ' to force removal)\n') % m.rel(f))
2880 ret = 1
2880 ret = 1
2881 for f in added:
2881 for f in added:
2882 ui.warn(_('not removing %s: file has been marked for add (use -f'
2882 ui.warn(_('not removing %s: file has been marked for add (use -f'
2883 ' to force removal)\n') % m.rel(f))
2883 ' to force removal)\n') % m.rel(f))
2884 ret = 1
2884 ret = 1
2885
2885
2886 for f in sorted(remove + forget):
2886 for f in sorted(remove + forget):
2887 if ui.verbose or not m.exact(f):
2887 if ui.verbose or not m.exact(f):
2888 ui.status(_('removing %s\n') % m.rel(f))
2888 ui.status(_('removing %s\n') % m.rel(f))
2889
2889
2890 repo[None].forget(forget)
2890 repo[None].forget(forget)
2891 repo[None].remove(remove, unlink=not after)
2891 repo[None].remove(remove, unlink=not after)
2892 return ret
2892 return ret
2893
2893
2894 def rename(ui, repo, *pats, **opts):
2894 def rename(ui, repo, *pats, **opts):
2895 """rename files; equivalent of copy + remove
2895 """rename files; equivalent of copy + remove
2896
2896
2897 Mark dest as copies of sources; mark sources for deletion. If dest
2897 Mark dest as copies of sources; mark sources for deletion. If dest
2898 is a directory, copies are put in that directory. If dest is a
2898 is a directory, copies are put in that directory. If dest is a
2899 file, there can only be one source.
2899 file, there can only be one source.
2900
2900
2901 By default, this command copies the contents of files as they
2901 By default, this command copies the contents of files as they
2902 exist in the working directory. If invoked with -A/--after, the
2902 exist in the working directory. If invoked with -A/--after, the
2903 operation is recorded, but no copying is performed.
2903 operation is recorded, but no copying is performed.
2904
2904
2905 This command takes effect at the next commit. To undo a rename
2905 This command takes effect at the next commit. To undo a rename
2906 before that, see :hg:`revert`.
2906 before that, see :hg:`revert`.
2907
2907
2908 Returns 0 on success, 1 if errors are encountered.
2908 Returns 0 on success, 1 if errors are encountered.
2909 """
2909 """
2910 wlock = repo.wlock(False)
2910 wlock = repo.wlock(False)
2911 try:
2911 try:
2912 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2912 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2913 finally:
2913 finally:
2914 wlock.release()
2914 wlock.release()
2915
2915
2916 def resolve(ui, repo, *pats, **opts):
2916 def resolve(ui, repo, *pats, **opts):
2917 """redo merges or set/view the merge status of files
2917 """redo merges or set/view the merge status of files
2918
2918
2919 Merges with unresolved conflicts are often the result of
2919 Merges with unresolved conflicts are often the result of
2920 non-interactive merging using the ``internal:merge`` configuration
2920 non-interactive merging using the ``internal:merge`` configuration
2921 setting, or a command-line merge tool like ``diff3``. The resolve
2921 setting, or a command-line merge tool like ``diff3``. The resolve
2922 command is used to manage the files involved in a merge, after
2922 command is used to manage the files involved in a merge, after
2923 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
2923 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
2924 working directory must have two parents).
2924 working directory must have two parents).
2925
2925
2926 The resolve command can be used in the following ways:
2926 The resolve command can be used in the following ways:
2927
2927
2928 - :hg:`resolve FILE...`: attempt to re-merge the specified files,
2928 - :hg:`resolve FILE...`: attempt to re-merge the specified files,
2929 discarding any previous merge attempts. Re-merging is not
2929 discarding any previous merge attempts. Re-merging is not
2930 performed for files already marked as resolved. Use ``--all/-a``
2930 performed for files already marked as resolved. Use ``--all/-a``
2931 to selects all unresolved files.
2931 to selects all unresolved files.
2932
2932
2933 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
2933 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
2934 (e.g. after having manually fixed-up the files). The default is
2934 (e.g. after having manually fixed-up the files). The default is
2935 to mark all unresolved files.
2935 to mark all unresolved files.
2936
2936
2937 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
2937 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
2938 default is to mark all resolved files.
2938 default is to mark all resolved files.
2939
2939
2940 - :hg:`resolve -l`: list files which had or still have conflicts.
2940 - :hg:`resolve -l`: list files which had or still have conflicts.
2941 In the printed list, ``U`` = unresolved and ``R`` = resolved.
2941 In the printed list, ``U`` = unresolved and ``R`` = resolved.
2942
2942
2943 Note that Mercurial will not let you commit files with unresolved
2943 Note that Mercurial will not let you commit files with unresolved
2944 merge conflicts. You must use :hg:`resolve -m ...` before you can
2944 merge conflicts. You must use :hg:`resolve -m ...` before you can
2945 commit after a conflicting merge.
2945 commit after a conflicting merge.
2946
2946
2947 Returns 0 on success, 1 if any files fail a resolve attempt.
2947 Returns 0 on success, 1 if any files fail a resolve attempt.
2948 """
2948 """
2949
2949
2950 all, mark, unmark, show, nostatus = \
2950 all, mark, unmark, show, nostatus = \
2951 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
2951 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
2952
2952
2953 if (show and (mark or unmark)) or (mark and unmark):
2953 if (show and (mark or unmark)) or (mark and unmark):
2954 raise util.Abort(_("too many options specified"))
2954 raise util.Abort(_("too many options specified"))
2955 if pats and all:
2955 if pats and all:
2956 raise util.Abort(_("can't specify --all and patterns"))
2956 raise util.Abort(_("can't specify --all and patterns"))
2957 if not (all or pats or show or mark or unmark):
2957 if not (all or pats or show or mark or unmark):
2958 raise util.Abort(_('no files or directories specified; '
2958 raise util.Abort(_('no files or directories specified; '
2959 'use --all to remerge all files'))
2959 'use --all to remerge all files'))
2960
2960
2961 ms = mergemod.mergestate(repo)
2961 ms = mergemod.mergestate(repo)
2962 m = cmdutil.match(repo, pats, opts)
2962 m = cmdutil.match(repo, pats, opts)
2963 ret = 0
2963 ret = 0
2964
2964
2965 for f in ms:
2965 for f in ms:
2966 if m(f):
2966 if m(f):
2967 if show:
2967 if show:
2968 if nostatus:
2968 if nostatus:
2969 ui.write("%s\n" % f)
2969 ui.write("%s\n" % f)
2970 else:
2970 else:
2971 ui.write("%s %s\n" % (ms[f].upper(), f),
2971 ui.write("%s %s\n" % (ms[f].upper(), f),
2972 label='resolve.' +
2972 label='resolve.' +
2973 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
2973 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
2974 elif mark:
2974 elif mark:
2975 ms.mark(f, "r")
2975 ms.mark(f, "r")
2976 elif unmark:
2976 elif unmark:
2977 ms.mark(f, "u")
2977 ms.mark(f, "u")
2978 else:
2978 else:
2979 wctx = repo[None]
2979 wctx = repo[None]
2980 mctx = wctx.parents()[-1]
2980 mctx = wctx.parents()[-1]
2981
2981
2982 # backup pre-resolve (merge uses .orig for its own purposes)
2982 # backup pre-resolve (merge uses .orig for its own purposes)
2983 a = repo.wjoin(f)
2983 a = repo.wjoin(f)
2984 util.copyfile(a, a + ".resolve")
2984 util.copyfile(a, a + ".resolve")
2985
2985
2986 # resolve file
2986 # resolve file
2987 if ms.resolve(f, wctx, mctx):
2987 if ms.resolve(f, wctx, mctx):
2988 ret = 1
2988 ret = 1
2989
2989
2990 # replace filemerge's .orig file with our resolve file
2990 # replace filemerge's .orig file with our resolve file
2991 util.rename(a + ".resolve", a + ".orig")
2991 util.rename(a + ".resolve", a + ".orig")
2992
2992
2993 ms.commit()
2993 ms.commit()
2994 return ret
2994 return ret
2995
2995
2996 def revert(ui, repo, *pats, **opts):
2996 def revert(ui, repo, *pats, **opts):
2997 """restore individual files or directories to an earlier state
2997 """restore individual files or directories to an earlier state
2998
2998
2999 .. note::
2999 .. note::
3000 This command is most likely not what you are looking for.
3000 This command is most likely not what you are looking for.
3001 revert will partially overwrite content in the working
3001 revert will partially overwrite content in the working
3002 directory without changing the working directory parents. Use
3002 directory without changing the working directory parents. Use
3003 :hg:`update -r rev` to check out earlier revisions, or
3003 :hg:`update -r rev` to check out earlier revisions, or
3004 :hg:`update --clean .` to undo a merge which has added another
3004 :hg:`update --clean .` to undo a merge which has added another
3005 parent.
3005 parent.
3006
3006
3007 With no revision specified, revert the named files or directories
3007 With no revision specified, revert the named files or directories
3008 to the contents they had in the parent of the working directory.
3008 to the contents they had in the parent of the working directory.
3009 This restores the contents of the affected files to an unmodified
3009 This restores the contents of the affected files to an unmodified
3010 state and unschedules adds, removes, copies, and renames. If the
3010 state and unschedules adds, removes, copies, and renames. If the
3011 working directory has two parents, you must explicitly specify a
3011 working directory has two parents, you must explicitly specify a
3012 revision.
3012 revision.
3013
3013
3014 Using the -r/--rev option, revert the given files or directories
3014 Using the -r/--rev option, revert the given files or directories
3015 to their contents as of a specific revision. This can be helpful
3015 to their contents as of a specific revision. This can be helpful
3016 to "roll back" some or all of an earlier change. See :hg:`help
3016 to "roll back" some or all of an earlier change. See :hg:`help
3017 dates` for a list of formats valid for -d/--date.
3017 dates` for a list of formats valid for -d/--date.
3018
3018
3019 Revert modifies the working directory. It does not commit any
3019 Revert modifies the working directory. It does not commit any
3020 changes, or change the parent of the working directory. If you
3020 changes, or change the parent of the working directory. If you
3021 revert to a revision other than the parent of the working
3021 revert to a revision other than the parent of the working
3022 directory, the reverted files will thus appear modified
3022 directory, the reverted files will thus appear modified
3023 afterwards.
3023 afterwards.
3024
3024
3025 If a file has been deleted, it is restored. If the executable mode
3025 If a file has been deleted, it is restored. If the executable mode
3026 of a file was changed, it is reset.
3026 of a file was changed, it is reset.
3027
3027
3028 If names are given, all files matching the names are reverted.
3028 If names are given, all files matching the names are reverted.
3029 If no arguments are given, no files are reverted.
3029 If no arguments are given, no files are reverted.
3030
3030
3031 Modified files are saved with a .orig suffix before reverting.
3031 Modified files are saved with a .orig suffix before reverting.
3032 To disable these backups, use --no-backup.
3032 To disable these backups, use --no-backup.
3033
3033
3034 Returns 0 on success.
3034 Returns 0 on success.
3035 """
3035 """
3036
3036
3037 if opts.get("date"):
3037 if opts.get("date"):
3038 if opts.get("rev"):
3038 if opts.get("rev"):
3039 raise util.Abort(_("you can't specify a revision and a date"))
3039 raise util.Abort(_("you can't specify a revision and a date"))
3040 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3040 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3041
3041
3042 if not pats and not opts.get('all'):
3042 if not pats and not opts.get('all'):
3043 raise util.Abort(_('no files or directories specified; '
3043 raise util.Abort(_('no files or directories specified; '
3044 'use --all to revert the whole repo'))
3044 'use --all to revert the whole repo'))
3045
3045
3046 parent, p2 = repo.dirstate.parents()
3046 parent, p2 = repo.dirstate.parents()
3047 if not opts.get('rev') and p2 != nullid:
3047 if not opts.get('rev') and p2 != nullid:
3048 raise util.Abort(_('uncommitted merge - please provide a '
3048 raise util.Abort(_('uncommitted merge - please provide a '
3049 'specific revision'))
3049 'specific revision'))
3050 ctx = repo[opts.get('rev')]
3050 ctx = repo[opts.get('rev')]
3051 node = ctx.node()
3051 node = ctx.node()
3052 mf = ctx.manifest()
3052 mf = ctx.manifest()
3053 if node == parent:
3053 if node == parent:
3054 pmf = mf
3054 pmf = mf
3055 else:
3055 else:
3056 pmf = None
3056 pmf = None
3057
3057
3058 # need all matching names in dirstate and manifest of target rev,
3058 # need all matching names in dirstate and manifest of target rev,
3059 # so have to walk both. do not print errors if files exist in one
3059 # so have to walk both. do not print errors if files exist in one
3060 # but not other.
3060 # but not other.
3061
3061
3062 names = {}
3062 names = {}
3063
3063
3064 wlock = repo.wlock()
3064 wlock = repo.wlock()
3065 try:
3065 try:
3066 # walk dirstate.
3066 # walk dirstate.
3067
3067
3068 m = cmdutil.match(repo, pats, opts)
3068 m = cmdutil.match(repo, pats, opts)
3069 m.bad = lambda x, y: False
3069 m.bad = lambda x, y: False
3070 for abs in repo.walk(m):
3070 for abs in repo.walk(m):
3071 names[abs] = m.rel(abs), m.exact(abs)
3071 names[abs] = m.rel(abs), m.exact(abs)
3072
3072
3073 # walk target manifest.
3073 # walk target manifest.
3074
3074
3075 def badfn(path, msg):
3075 def badfn(path, msg):
3076 if path in names:
3076 if path in names:
3077 return
3077 return
3078 path_ = path + '/'
3078 path_ = path + '/'
3079 for f in names:
3079 for f in names:
3080 if f.startswith(path_):
3080 if f.startswith(path_):
3081 return
3081 return
3082 ui.warn("%s: %s\n" % (m.rel(path), msg))
3082 ui.warn("%s: %s\n" % (m.rel(path), msg))
3083
3083
3084 m = cmdutil.match(repo, pats, opts)
3084 m = cmdutil.match(repo, pats, opts)
3085 m.bad = badfn
3085 m.bad = badfn
3086 for abs in repo[node].walk(m):
3086 for abs in repo[node].walk(m):
3087 if abs not in names:
3087 if abs not in names:
3088 names[abs] = m.rel(abs), m.exact(abs)
3088 names[abs] = m.rel(abs), m.exact(abs)
3089
3089
3090 m = cmdutil.matchfiles(repo, names)
3090 m = cmdutil.matchfiles(repo, names)
3091 changes = repo.status(match=m)[:4]
3091 changes = repo.status(match=m)[:4]
3092 modified, added, removed, deleted = map(set, changes)
3092 modified, added, removed, deleted = map(set, changes)
3093
3093
3094 # if f is a rename, also revert the source
3094 # if f is a rename, also revert the source
3095 cwd = repo.getcwd()
3095 cwd = repo.getcwd()
3096 for f in added:
3096 for f in added:
3097 src = repo.dirstate.copied(f)
3097 src = repo.dirstate.copied(f)
3098 if src and src not in names and repo.dirstate[src] == 'r':
3098 if src and src not in names and repo.dirstate[src] == 'r':
3099 removed.add(src)
3099 removed.add(src)
3100 names[src] = (repo.pathto(src, cwd), True)
3100 names[src] = (repo.pathto(src, cwd), True)
3101
3101
3102 def removeforget(abs):
3102 def removeforget(abs):
3103 if repo.dirstate[abs] == 'a':
3103 if repo.dirstate[abs] == 'a':
3104 return _('forgetting %s\n')
3104 return _('forgetting %s\n')
3105 return _('removing %s\n')
3105 return _('removing %s\n')
3106
3106
3107 revert = ([], _('reverting %s\n'))
3107 revert = ([], _('reverting %s\n'))
3108 add = ([], _('adding %s\n'))
3108 add = ([], _('adding %s\n'))
3109 remove = ([], removeforget)
3109 remove = ([], removeforget)
3110 undelete = ([], _('undeleting %s\n'))
3110 undelete = ([], _('undeleting %s\n'))
3111
3111
3112 disptable = (
3112 disptable = (
3113 # dispatch table:
3113 # dispatch table:
3114 # file state
3114 # file state
3115 # action if in target manifest
3115 # action if in target manifest
3116 # action if not in target manifest
3116 # action if not in target manifest
3117 # make backup if in target manifest
3117 # make backup if in target manifest
3118 # make backup if not in target manifest
3118 # make backup if not in target manifest
3119 (modified, revert, remove, True, True),
3119 (modified, revert, remove, True, True),
3120 (added, revert, remove, True, False),
3120 (added, revert, remove, True, False),
3121 (removed, undelete, None, False, False),
3121 (removed, undelete, None, False, False),
3122 (deleted, revert, remove, False, False),
3122 (deleted, revert, remove, False, False),
3123 )
3123 )
3124
3124
3125 for abs, (rel, exact) in sorted(names.items()):
3125 for abs, (rel, exact) in sorted(names.items()):
3126 mfentry = mf.get(abs)
3126 mfentry = mf.get(abs)
3127 target = repo.wjoin(abs)
3127 target = repo.wjoin(abs)
3128 def handle(xlist, dobackup):
3128 def handle(xlist, dobackup):
3129 xlist[0].append(abs)
3129 xlist[0].append(abs)
3130 if (dobackup and not opts.get('no_backup') and
3130 if (dobackup and not opts.get('no_backup') and
3131 os.path.lexists(target)):
3131 os.path.lexists(target)):
3132 bakname = "%s.orig" % rel
3132 bakname = "%s.orig" % rel
3133 ui.note(_('saving current version of %s as %s\n') %
3133 ui.note(_('saving current version of %s as %s\n') %
3134 (rel, bakname))
3134 (rel, bakname))
3135 if not opts.get('dry_run'):
3135 if not opts.get('dry_run'):
3136 util.rename(target, bakname)
3136 util.rename(target, bakname)
3137 if ui.verbose or not exact:
3137 if ui.verbose or not exact:
3138 msg = xlist[1]
3138 msg = xlist[1]
3139 if not isinstance(msg, basestring):
3139 if not isinstance(msg, basestring):
3140 msg = msg(abs)
3140 msg = msg(abs)
3141 ui.status(msg % rel)
3141 ui.status(msg % rel)
3142 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3142 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3143 if abs not in table:
3143 if abs not in table:
3144 continue
3144 continue
3145 # file has changed in dirstate
3145 # file has changed in dirstate
3146 if mfentry:
3146 if mfentry:
3147 handle(hitlist, backuphit)
3147 handle(hitlist, backuphit)
3148 elif misslist is not None:
3148 elif misslist is not None:
3149 handle(misslist, backupmiss)
3149 handle(misslist, backupmiss)
3150 break
3150 break
3151 else:
3151 else:
3152 if abs not in repo.dirstate:
3152 if abs not in repo.dirstate:
3153 if mfentry:
3153 if mfentry:
3154 handle(add, True)
3154 handle(add, True)
3155 elif exact:
3155 elif exact:
3156 ui.warn(_('file not managed: %s\n') % rel)
3156 ui.warn(_('file not managed: %s\n') % rel)
3157 continue
3157 continue
3158 # file has not changed in dirstate
3158 # file has not changed in dirstate
3159 if node == parent:
3159 if node == parent:
3160 if exact:
3160 if exact:
3161 ui.warn(_('no changes needed to %s\n') % rel)
3161 ui.warn(_('no changes needed to %s\n') % rel)
3162 continue
3162 continue
3163 if pmf is None:
3163 if pmf is None:
3164 # only need parent manifest in this unlikely case,
3164 # only need parent manifest in this unlikely case,
3165 # so do not read by default
3165 # so do not read by default
3166 pmf = repo[parent].manifest()
3166 pmf = repo[parent].manifest()
3167 if abs in pmf:
3167 if abs in pmf:
3168 if mfentry:
3168 if mfentry:
3169 # if version of file is same in parent and target
3169 # if version of file is same in parent and target
3170 # manifests, do nothing
3170 # manifests, do nothing
3171 if (pmf[abs] != mfentry or
3171 if (pmf[abs] != mfentry or
3172 pmf.flags(abs) != mf.flags(abs)):
3172 pmf.flags(abs) != mf.flags(abs)):
3173 handle(revert, False)
3173 handle(revert, False)
3174 else:
3174 else:
3175 handle(remove, False)
3175 handle(remove, False)
3176
3176
3177 if not opts.get('dry_run'):
3177 if not opts.get('dry_run'):
3178 def checkout(f):
3178 def checkout(f):
3179 fc = ctx[f]
3179 fc = ctx[f]
3180 repo.wwrite(f, fc.data(), fc.flags())
3180 repo.wwrite(f, fc.data(), fc.flags())
3181
3181
3182 audit_path = util.path_auditor(repo.root)
3182 audit_path = util.path_auditor(repo.root)
3183 for f in remove[0]:
3183 for f in remove[0]:
3184 if repo.dirstate[f] == 'a':
3184 if repo.dirstate[f] == 'a':
3185 repo.dirstate.forget(f)
3185 repo.dirstate.forget(f)
3186 continue
3186 continue
3187 audit_path(f)
3187 audit_path(f)
3188 try:
3188 try:
3189 util.unlink(repo.wjoin(f))
3189 util.unlink(repo.wjoin(f))
3190 except OSError:
3190 except OSError:
3191 pass
3191 pass
3192 repo.dirstate.remove(f)
3192 repo.dirstate.remove(f)
3193
3193
3194 normal = None
3194 normal = None
3195 if node == parent:
3195 if node == parent:
3196 # We're reverting to our parent. If possible, we'd like status
3196 # We're reverting to our parent. If possible, we'd like status
3197 # to report the file as clean. We have to use normallookup for
3197 # to report the file as clean. We have to use normallookup for
3198 # merges to avoid losing information about merged/dirty files.
3198 # merges to avoid losing information about merged/dirty files.
3199 if p2 != nullid:
3199 if p2 != nullid:
3200 normal = repo.dirstate.normallookup
3200 normal = repo.dirstate.normallookup
3201 else:
3201 else:
3202 normal = repo.dirstate.normal
3202 normal = repo.dirstate.normal
3203 for f in revert[0]:
3203 for f in revert[0]:
3204 checkout(f)
3204 checkout(f)
3205 if normal:
3205 if normal:
3206 normal(f)
3206 normal(f)
3207
3207
3208 for f in add[0]:
3208 for f in add[0]:
3209 checkout(f)
3209 checkout(f)
3210 repo.dirstate.add(f)
3210 repo.dirstate.add(f)
3211
3211
3212 normal = repo.dirstate.normallookup
3212 normal = repo.dirstate.normallookup
3213 if node == parent and p2 == nullid:
3213 if node == parent and p2 == nullid:
3214 normal = repo.dirstate.normal
3214 normal = repo.dirstate.normal
3215 for f in undelete[0]:
3215 for f in undelete[0]:
3216 checkout(f)
3216 checkout(f)
3217 normal(f)
3217 normal(f)
3218
3218
3219 finally:
3219 finally:
3220 wlock.release()
3220 wlock.release()
3221
3221
3222 def rollback(ui, repo, **opts):
3222 def rollback(ui, repo, **opts):
3223 """roll back the last transaction (dangerous)
3223 """roll back the last transaction (dangerous)
3224
3224
3225 This command should be used with care. There is only one level of
3225 This command should be used with care. There is only one level of
3226 rollback, and there is no way to undo a rollback. It will also
3226 rollback, and there is no way to undo a rollback. It will also
3227 restore the dirstate at the time of the last transaction, losing
3227 restore the dirstate at the time of the last transaction, losing
3228 any dirstate changes since that time. This command does not alter
3228 any dirstate changes since that time. This command does not alter
3229 the working directory.
3229 the working directory.
3230
3230
3231 Transactions are used to encapsulate the effects of all commands
3231 Transactions are used to encapsulate the effects of all commands
3232 that create new changesets or propagate existing changesets into a
3232 that create new changesets or propagate existing changesets into a
3233 repository. For example, the following commands are transactional,
3233 repository. For example, the following commands are transactional,
3234 and their effects can be rolled back:
3234 and their effects can be rolled back:
3235
3235
3236 - commit
3236 - commit
3237 - import
3237 - import
3238 - pull
3238 - pull
3239 - push (with this repository as the destination)
3239 - push (with this repository as the destination)
3240 - unbundle
3240 - unbundle
3241
3241
3242 This command is not intended for use on public repositories. Once
3242 This command is not intended for use on public repositories. Once
3243 changes are visible for pull by other users, rolling a transaction
3243 changes are visible for pull by other users, rolling a transaction
3244 back locally is ineffective (someone else may already have pulled
3244 back locally is ineffective (someone else may already have pulled
3245 the changes). Furthermore, a race is possible with readers of the
3245 the changes). Furthermore, a race is possible with readers of the
3246 repository; for example an in-progress pull from the repository
3246 repository; for example an in-progress pull from the repository
3247 may fail if a rollback is performed.
3247 may fail if a rollback is performed.
3248
3248
3249 Returns 0 on success, 1 if no rollback data is available.
3249 Returns 0 on success, 1 if no rollback data is available.
3250 """
3250 """
3251 return repo.rollback(opts.get('dry_run'))
3251 return repo.rollback(opts.get('dry_run'))
3252
3252
3253 def root(ui, repo):
3253 def root(ui, repo):
3254 """print the root (top) of the current working directory
3254 """print the root (top) of the current working directory
3255
3255
3256 Print the root directory of the current repository.
3256 Print the root directory of the current repository.
3257
3257
3258 Returns 0 on success.
3258 Returns 0 on success.
3259 """
3259 """
3260 ui.write(repo.root + "\n")
3260 ui.write(repo.root + "\n")
3261
3261
3262 def serve(ui, repo, **opts):
3262 def serve(ui, repo, **opts):
3263 """start stand-alone webserver
3263 """start stand-alone webserver
3264
3264
3265 Start a local HTTP repository browser and pull server. You can use
3265 Start a local HTTP repository browser and pull server. You can use
3266 this for ad-hoc sharing and browing of repositories. It is
3266 this for ad-hoc sharing and browing of repositories. It is
3267 recommended to use a real web server to serve a repository for
3267 recommended to use a real web server to serve a repository for
3268 longer periods of time.
3268 longer periods of time.
3269
3269
3270 Please note that the server does not implement access control.
3270 Please note that the server does not implement access control.
3271 This means that, by default, anybody can read from the server and
3271 This means that, by default, anybody can read from the server and
3272 nobody can write to it by default. Set the ``web.allow_push``
3272 nobody can write to it by default. Set the ``web.allow_push``
3273 option to ``*`` to allow everybody to push to the server. You
3273 option to ``*`` to allow everybody to push to the server. You
3274 should use a real web server if you need to authenticate users.
3274 should use a real web server if you need to authenticate users.
3275
3275
3276 By default, the server logs accesses to stdout and errors to
3276 By default, the server logs accesses to stdout and errors to
3277 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3277 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3278 files.
3278 files.
3279
3279
3280 To have the server choose a free port number to listen on, specify
3280 To have the server choose a free port number to listen on, specify
3281 a port number of 0; in this case, the server will print the port
3281 a port number of 0; in this case, the server will print the port
3282 number it uses.
3282 number it uses.
3283
3283
3284 Returns 0 on success.
3284 Returns 0 on success.
3285 """
3285 """
3286
3286
3287 if opts["stdio"]:
3287 if opts["stdio"]:
3288 if repo is None:
3288 if repo is None:
3289 raise error.RepoError(_("There is no Mercurial repository here"
3289 raise error.RepoError(_("There is no Mercurial repository here"
3290 " (.hg not found)"))
3290 " (.hg not found)"))
3291 s = sshserver.sshserver(ui, repo)
3291 s = sshserver.sshserver(ui, repo)
3292 s.serve_forever()
3292 s.serve_forever()
3293
3293
3294 # this way we can check if something was given in the command-line
3294 # this way we can check if something was given in the command-line
3295 if opts.get('port'):
3295 if opts.get('port'):
3296 opts['port'] = util.getport(opts.get('port'))
3296 opts['port'] = util.getport(opts.get('port'))
3297
3297
3298 baseui = repo and repo.baseui or ui
3298 baseui = repo and repo.baseui or ui
3299 optlist = ("name templates style address port prefix ipv6"
3299 optlist = ("name templates style address port prefix ipv6"
3300 " accesslog errorlog certificate encoding")
3300 " accesslog errorlog certificate encoding")
3301 for o in optlist.split():
3301 for o in optlist.split():
3302 val = opts.get(o, '')
3302 val = opts.get(o, '')
3303 if val in (None, ''): # should check against default options instead
3303 if val in (None, ''): # should check against default options instead
3304 continue
3304 continue
3305 baseui.setconfig("web", o, val)
3305 baseui.setconfig("web", o, val)
3306 if repo and repo.ui != baseui:
3306 if repo and repo.ui != baseui:
3307 repo.ui.setconfig("web", o, val)
3307 repo.ui.setconfig("web", o, val)
3308
3308
3309 o = opts.get('web_conf') or opts.get('webdir_conf')
3309 o = opts.get('web_conf') or opts.get('webdir_conf')
3310 if not o:
3310 if not o:
3311 if not repo:
3311 if not repo:
3312 raise error.RepoError(_("There is no Mercurial repository"
3312 raise error.RepoError(_("There is no Mercurial repository"
3313 " here (.hg not found)"))
3313 " here (.hg not found)"))
3314 o = repo.root
3314 o = repo.root
3315
3315
3316 app = hgweb.hgweb(o, baseui=ui)
3316 app = hgweb.hgweb(o, baseui=ui)
3317
3317
3318 class service(object):
3318 class service(object):
3319 def init(self):
3319 def init(self):
3320 util.set_signal_handler()
3320 util.set_signal_handler()
3321 self.httpd = hgweb.server.create_server(ui, app)
3321 self.httpd = hgweb.server.create_server(ui, app)
3322
3322
3323 if opts['port'] and not ui.verbose:
3323 if opts['port'] and not ui.verbose:
3324 return
3324 return
3325
3325
3326 if self.httpd.prefix:
3326 if self.httpd.prefix:
3327 prefix = self.httpd.prefix.strip('/') + '/'
3327 prefix = self.httpd.prefix.strip('/') + '/'
3328 else:
3328 else:
3329 prefix = ''
3329 prefix = ''
3330
3330
3331 port = ':%d' % self.httpd.port
3331 port = ':%d' % self.httpd.port
3332 if port == ':80':
3332 if port == ':80':
3333 port = ''
3333 port = ''
3334
3334
3335 bindaddr = self.httpd.addr
3335 bindaddr = self.httpd.addr
3336 if bindaddr == '0.0.0.0':
3336 if bindaddr == '0.0.0.0':
3337 bindaddr = '*'
3337 bindaddr = '*'
3338 elif ':' in bindaddr: # IPv6
3338 elif ':' in bindaddr: # IPv6
3339 bindaddr = '[%s]' % bindaddr
3339 bindaddr = '[%s]' % bindaddr
3340
3340
3341 fqaddr = self.httpd.fqaddr
3341 fqaddr = self.httpd.fqaddr
3342 if ':' in fqaddr:
3342 if ':' in fqaddr:
3343 fqaddr = '[%s]' % fqaddr
3343 fqaddr = '[%s]' % fqaddr
3344 if opts['port']:
3344 if opts['port']:
3345 write = ui.status
3345 write = ui.status
3346 else:
3346 else:
3347 write = ui.write
3347 write = ui.write
3348 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3348 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3349 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3349 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3350
3350
3351 def run(self):
3351 def run(self):
3352 self.httpd.serve_forever()
3352 self.httpd.serve_forever()
3353
3353
3354 service = service()
3354 service = service()
3355
3355
3356 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3356 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3357
3357
3358 def status(ui, repo, *pats, **opts):
3358 def status(ui, repo, *pats, **opts):
3359 """show changed files in the working directory
3359 """show changed files in the working directory
3360
3360
3361 Show status of files in the repository. If names are given, only
3361 Show status of files in the repository. If names are given, only
3362 files that match are shown. Files that are clean or ignored or
3362 files that match are shown. Files that are clean or ignored or
3363 the source of a copy/move operation, are not listed unless
3363 the source of a copy/move operation, are not listed unless
3364 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3364 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3365 Unless options described with "show only ..." are given, the
3365 Unless options described with "show only ..." are given, the
3366 options -mardu are used.
3366 options -mardu are used.
3367
3367
3368 Option -q/--quiet hides untracked (unknown and ignored) files
3368 Option -q/--quiet hides untracked (unknown and ignored) files
3369 unless explicitly requested with -u/--unknown or -i/--ignored.
3369 unless explicitly requested with -u/--unknown or -i/--ignored.
3370
3370
3371 .. note::
3371 .. note::
3372 status may appear to disagree with diff if permissions have
3372 status may appear to disagree with diff if permissions have
3373 changed or a merge has occurred. The standard diff format does
3373 changed or a merge has occurred. The standard diff format does
3374 not report permission changes and diff only reports changes
3374 not report permission changes and diff only reports changes
3375 relative to one merge parent.
3375 relative to one merge parent.
3376
3376
3377 If one revision is given, it is used as the base revision.
3377 If one revision is given, it is used as the base revision.
3378 If two revisions are given, the differences between them are
3378 If two revisions are given, the differences between them are
3379 shown. The --change option can also be used as a shortcut to list
3379 shown. The --change option can also be used as a shortcut to list
3380 the changed files of a revision from its first parent.
3380 the changed files of a revision from its first parent.
3381
3381
3382 The codes used to show the status of files are::
3382 The codes used to show the status of files are::
3383
3383
3384 M = modified
3384 M = modified
3385 A = added
3385 A = added
3386 R = removed
3386 R = removed
3387 C = clean
3387 C = clean
3388 ! = missing (deleted by non-hg command, but still tracked)
3388 ! = missing (deleted by non-hg command, but still tracked)
3389 ? = not tracked
3389 ? = not tracked
3390 I = ignored
3390 I = ignored
3391 = origin of the previous file listed as A (added)
3391 = origin of the previous file listed as A (added)
3392
3392
3393 Returns 0 on success.
3393 Returns 0 on success.
3394 """
3394 """
3395
3395
3396 revs = opts.get('rev')
3396 revs = opts.get('rev')
3397 change = opts.get('change')
3397 change = opts.get('change')
3398
3398
3399 if revs and change:
3399 if revs and change:
3400 msg = _('cannot specify --rev and --change at the same time')
3400 msg = _('cannot specify --rev and --change at the same time')
3401 raise util.Abort(msg)
3401 raise util.Abort(msg)
3402 elif change:
3402 elif change:
3403 node2 = repo.lookup(change)
3403 node2 = repo.lookup(change)
3404 node1 = repo[node2].parents()[0].node()
3404 node1 = repo[node2].parents()[0].node()
3405 else:
3405 else:
3406 node1, node2 = cmdutil.revpair(repo, revs)
3406 node1, node2 = cmdutil.revpair(repo, revs)
3407
3407
3408 cwd = (pats and repo.getcwd()) or ''
3408 cwd = (pats and repo.getcwd()) or ''
3409 end = opts.get('print0') and '\0' or '\n'
3409 end = opts.get('print0') and '\0' or '\n'
3410 copy = {}
3410 copy = {}
3411 states = 'modified added removed deleted unknown ignored clean'.split()
3411 states = 'modified added removed deleted unknown ignored clean'.split()
3412 show = [k for k in states if opts.get(k)]
3412 show = [k for k in states if opts.get(k)]
3413 if opts.get('all'):
3413 if opts.get('all'):
3414 show += ui.quiet and (states[:4] + ['clean']) or states
3414 show += ui.quiet and (states[:4] + ['clean']) or states
3415 if not show:
3415 if not show:
3416 show = ui.quiet and states[:4] or states[:5]
3416 show = ui.quiet and states[:4] or states[:5]
3417
3417
3418 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3418 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3419 'ignored' in show, 'clean' in show, 'unknown' in show,
3419 'ignored' in show, 'clean' in show, 'unknown' in show,
3420 opts.get('subrepos'))
3420 opts.get('subrepos'))
3421 changestates = zip(states, 'MAR!?IC', stat)
3421 changestates = zip(states, 'MAR!?IC', stat)
3422
3422
3423 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3423 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3424 ctxn = repo[nullid]
3424 ctxn = repo[nullid]
3425 ctx1 = repo[node1]
3425 ctx1 = repo[node1]
3426 ctx2 = repo[node2]
3426 ctx2 = repo[node2]
3427 added = stat[1]
3427 added = stat[1]
3428 if node2 is None:
3428 if node2 is None:
3429 added = stat[0] + stat[1] # merged?
3429 added = stat[0] + stat[1] # merged?
3430
3430
3431 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3431 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3432 if k in added:
3432 if k in added:
3433 copy[k] = v
3433 copy[k] = v
3434 elif v in added:
3434 elif v in added:
3435 copy[v] = k
3435 copy[v] = k
3436
3436
3437 for state, char, files in changestates:
3437 for state, char, files in changestates:
3438 if state in show:
3438 if state in show:
3439 format = "%s %%s%s" % (char, end)
3439 format = "%s %%s%s" % (char, end)
3440 if opts.get('no_status'):
3440 if opts.get('no_status'):
3441 format = "%%s%s" % end
3441 format = "%%s%s" % end
3442
3442
3443 for f in files:
3443 for f in files:
3444 ui.write(format % repo.pathto(f, cwd),
3444 ui.write(format % repo.pathto(f, cwd),
3445 label='status.' + state)
3445 label='status.' + state)
3446 if f in copy:
3446 if f in copy:
3447 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3447 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3448 label='status.copied')
3448 label='status.copied')
3449
3449
3450 def summary(ui, repo, **opts):
3450 def summary(ui, repo, **opts):
3451 """summarize working directory state
3451 """summarize working directory state
3452
3452
3453 This generates a brief summary of the working directory state,
3453 This generates a brief summary of the working directory state,
3454 including parents, branch, commit status, and available updates.
3454 including parents, branch, commit status, and available updates.
3455
3455
3456 With the --remote option, this will check the default paths for
3456 With the --remote option, this will check the default paths for
3457 incoming and outgoing changes. This can be time-consuming.
3457 incoming and outgoing changes. This can be time-consuming.
3458
3458
3459 Returns 0 on success.
3459 Returns 0 on success.
3460 """
3460 """
3461
3461
3462 ctx = repo[None]
3462 ctx = repo[None]
3463 parents = ctx.parents()
3463 parents = ctx.parents()
3464 pnode = parents[0].node()
3464 pnode = parents[0].node()
3465
3465
3466 for p in parents:
3466 for p in parents:
3467 # label with log.changeset (instead of log.parent) since this
3467 # label with log.changeset (instead of log.parent) since this
3468 # shows a working directory parent *changeset*:
3468 # shows a working directory parent *changeset*:
3469 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3469 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3470 label='log.changeset')
3470 label='log.changeset')
3471 ui.write(' '.join(p.tags()), label='log.tag')
3471 ui.write(' '.join(p.tags()), label='log.tag')
3472 if p.rev() == -1:
3472 if p.rev() == -1:
3473 if not len(repo):
3473 if not len(repo):
3474 ui.write(_(' (empty repository)'))
3474 ui.write(_(' (empty repository)'))
3475 else:
3475 else:
3476 ui.write(_(' (no revision checked out)'))
3476 ui.write(_(' (no revision checked out)'))
3477 ui.write('\n')
3477 ui.write('\n')
3478 if p.description():
3478 if p.description():
3479 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3479 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3480 label='log.summary')
3480 label='log.summary')
3481
3481
3482 branch = ctx.branch()
3482 branch = ctx.branch()
3483 bheads = repo.branchheads(branch)
3483 bheads = repo.branchheads(branch)
3484 m = _('branch: %s\n') % branch
3484 m = _('branch: %s\n') % branch
3485 if branch != 'default':
3485 if branch != 'default':
3486 ui.write(m, label='log.branch')
3486 ui.write(m, label='log.branch')
3487 else:
3487 else:
3488 ui.status(m, label='log.branch')
3488 ui.status(m, label='log.branch')
3489
3489
3490 st = list(repo.status(unknown=True))[:6]
3490 st = list(repo.status(unknown=True))[:6]
3491
3491
3492 c = repo.dirstate.copies()
3492 c = repo.dirstate.copies()
3493 copied, renamed = [], []
3493 copied, renamed = [], []
3494 for d, s in c.iteritems():
3494 for d, s in c.iteritems():
3495 if s in st[2]:
3495 if s in st[2]:
3496 st[2].remove(s)
3496 st[2].remove(s)
3497 renamed.append(d)
3497 renamed.append(d)
3498 else:
3498 else:
3499 copied.append(d)
3499 copied.append(d)
3500 if d in st[1]:
3500 if d in st[1]:
3501 st[1].remove(d)
3501 st[1].remove(d)
3502 st.insert(3, renamed)
3502 st.insert(3, renamed)
3503 st.insert(4, copied)
3503 st.insert(4, copied)
3504
3504
3505 ms = mergemod.mergestate(repo)
3505 ms = mergemod.mergestate(repo)
3506 st.append([f for f in ms if ms[f] == 'u'])
3506 st.append([f for f in ms if ms[f] == 'u'])
3507
3507
3508 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3508 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3509 st.append(subs)
3509 st.append(subs)
3510
3510
3511 labels = [ui.label(_('%d modified'), 'status.modified'),
3511 labels = [ui.label(_('%d modified'), 'status.modified'),
3512 ui.label(_('%d added'), 'status.added'),
3512 ui.label(_('%d added'), 'status.added'),
3513 ui.label(_('%d removed'), 'status.removed'),
3513 ui.label(_('%d removed'), 'status.removed'),
3514 ui.label(_('%d renamed'), 'status.copied'),
3514 ui.label(_('%d renamed'), 'status.copied'),
3515 ui.label(_('%d copied'), 'status.copied'),
3515 ui.label(_('%d copied'), 'status.copied'),
3516 ui.label(_('%d deleted'), 'status.deleted'),
3516 ui.label(_('%d deleted'), 'status.deleted'),
3517 ui.label(_('%d unknown'), 'status.unknown'),
3517 ui.label(_('%d unknown'), 'status.unknown'),
3518 ui.label(_('%d ignored'), 'status.ignored'),
3518 ui.label(_('%d ignored'), 'status.ignored'),
3519 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3519 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3520 ui.label(_('%d subrepos'), 'status.modified')]
3520 ui.label(_('%d subrepos'), 'status.modified')]
3521 t = []
3521 t = []
3522 for s, l in zip(st, labels):
3522 for s, l in zip(st, labels):
3523 if s:
3523 if s:
3524 t.append(l % len(s))
3524 t.append(l % len(s))
3525
3525
3526 t = ', '.join(t)
3526 t = ', '.join(t)
3527 cleanworkdir = False
3527 cleanworkdir = False
3528
3528
3529 if len(parents) > 1:
3529 if len(parents) > 1:
3530 t += _(' (merge)')
3530 t += _(' (merge)')
3531 elif branch != parents[0].branch():
3531 elif branch != parents[0].branch():
3532 t += _(' (new branch)')
3532 t += _(' (new branch)')
3533 elif (parents[0].extra().get('close') and
3533 elif (parents[0].extra().get('close') and
3534 pnode in repo.branchheads(branch, closed=True)):
3534 pnode in repo.branchheads(branch, closed=True)):
3535 t += _(' (head closed)')
3535 t += _(' (head closed)')
3536 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3536 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3537 t += _(' (clean)')
3537 t += _(' (clean)')
3538 cleanworkdir = True
3538 cleanworkdir = True
3539 elif pnode not in bheads:
3539 elif pnode not in bheads:
3540 t += _(' (new branch head)')
3540 t += _(' (new branch head)')
3541
3541
3542 if cleanworkdir:
3542 if cleanworkdir:
3543 ui.status(_('commit: %s\n') % t.strip())
3543 ui.status(_('commit: %s\n') % t.strip())
3544 else:
3544 else:
3545 ui.write(_('commit: %s\n') % t.strip())
3545 ui.write(_('commit: %s\n') % t.strip())
3546
3546
3547 # all ancestors of branch heads - all ancestors of parent = new csets
3547 # all ancestors of branch heads - all ancestors of parent = new csets
3548 new = [0] * len(repo)
3548 new = [0] * len(repo)
3549 cl = repo.changelog
3549 cl = repo.changelog
3550 for a in [cl.rev(n) for n in bheads]:
3550 for a in [cl.rev(n) for n in bheads]:
3551 new[a] = 1
3551 new[a] = 1
3552 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3552 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3553 new[a] = 1
3553 new[a] = 1
3554 for a in [p.rev() for p in parents]:
3554 for a in [p.rev() for p in parents]:
3555 if a >= 0:
3555 if a >= 0:
3556 new[a] = 0
3556 new[a] = 0
3557 for a in cl.ancestors(*[p.rev() for p in parents]):
3557 for a in cl.ancestors(*[p.rev() for p in parents]):
3558 new[a] = 0
3558 new[a] = 0
3559 new = sum(new)
3559 new = sum(new)
3560
3560
3561 if new == 0:
3561 if new == 0:
3562 ui.status(_('update: (current)\n'))
3562 ui.status(_('update: (current)\n'))
3563 elif pnode not in bheads:
3563 elif pnode not in bheads:
3564 ui.write(_('update: %d new changesets (update)\n') % new)
3564 ui.write(_('update: %d new changesets (update)\n') % new)
3565 else:
3565 else:
3566 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3566 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3567 (new, len(bheads)))
3567 (new, len(bheads)))
3568
3568
3569 if opts.get('remote'):
3569 if opts.get('remote'):
3570 t = []
3570 t = []
3571 source, branches = hg.parseurl(ui.expandpath('default'))
3571 source, branches = hg.parseurl(ui.expandpath('default'))
3572 other = hg.repository(hg.remoteui(repo, {}), source)
3572 other = hg.repository(hg.remoteui(repo, {}), source)
3573 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3573 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3574 ui.debug('comparing with %s\n' % url.hidepassword(source))
3574 ui.debug('comparing with %s\n' % url.hidepassword(source))
3575 repo.ui.pushbuffer()
3575 repo.ui.pushbuffer()
3576 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3576 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3577 repo.ui.popbuffer()
3577 repo.ui.popbuffer()
3578 if incoming:
3578 if incoming:
3579 t.append(_('1 or more incoming'))
3579 t.append(_('1 or more incoming'))
3580
3580
3581 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3581 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3582 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3582 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3583 other = hg.repository(hg.remoteui(repo, {}), dest)
3583 other = hg.repository(hg.remoteui(repo, {}), dest)
3584 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3584 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3585 repo.ui.pushbuffer()
3585 repo.ui.pushbuffer()
3586 o = discovery.findoutgoing(repo, other)
3586 o = discovery.findoutgoing(repo, other)
3587 repo.ui.popbuffer()
3587 repo.ui.popbuffer()
3588 o = repo.changelog.nodesbetween(o, None)[0]
3588 o = repo.changelog.nodesbetween(o, None)[0]
3589 if o:
3589 if o:
3590 t.append(_('%d outgoing') % len(o))
3590 t.append(_('%d outgoing') % len(o))
3591
3591
3592 if t:
3592 if t:
3593 ui.write(_('remote: %s\n') % (', '.join(t)))
3593 ui.write(_('remote: %s\n') % (', '.join(t)))
3594 else:
3594 else:
3595 ui.status(_('remote: (synced)\n'))
3595 ui.status(_('remote: (synced)\n'))
3596
3596
3597 def tag(ui, repo, name1, *names, **opts):
3597 def tag(ui, repo, name1, *names, **opts):
3598 """add one or more tags for the current or given revision
3598 """add one or more tags for the current or given revision
3599
3599
3600 Name a particular revision using <name>.
3600 Name a particular revision using <name>.
3601
3601
3602 Tags are used to name particular revisions of the repository and are
3602 Tags are used to name particular revisions of the repository and are
3603 very useful to compare different revisions, to go back to significant
3603 very useful to compare different revisions, to go back to significant
3604 earlier versions or to mark branch points as releases, etc.
3604 earlier versions or to mark branch points as releases, etc.
3605
3605
3606 If no revision is given, the parent of the working directory is
3606 If no revision is given, the parent of the working directory is
3607 used, or tip if no revision is checked out.
3607 used, or tip if no revision is checked out.
3608
3608
3609 To facilitate version control, distribution, and merging of tags,
3609 To facilitate version control, distribution, and merging of tags,
3610 they are stored as a file named ".hgtags" which is managed
3610 they are stored as a file named ".hgtags" which is managed
3611 similarly to other project files and can be hand-edited if
3611 similarly to other project files and can be hand-edited if
3612 necessary. The file '.hg/localtags' is used for local tags (not
3612 necessary. The file '.hg/localtags' is used for local tags (not
3613 shared among repositories).
3613 shared among repositories).
3614
3614
3615 See :hg:`help dates` for a list of formats valid for -d/--date.
3615 See :hg:`help dates` for a list of formats valid for -d/--date.
3616
3616
3617 Since tag names have priority over branch names during revision
3617 Since tag names have priority over branch names during revision
3618 lookup, using an existing branch name as a tag name is discouraged.
3618 lookup, using an existing branch name as a tag name is discouraged.
3619
3619
3620 Returns 0 on success.
3620 Returns 0 on success.
3621 """
3621 """
3622
3622
3623 rev_ = "."
3623 rev_ = "."
3624 names = [t.strip() for t in (name1,) + names]
3624 names = [t.strip() for t in (name1,) + names]
3625 if len(names) != len(set(names)):
3625 if len(names) != len(set(names)):
3626 raise util.Abort(_('tag names must be unique'))
3626 raise util.Abort(_('tag names must be unique'))
3627 for n in names:
3627 for n in names:
3628 if n in ['tip', '.', 'null']:
3628 if n in ['tip', '.', 'null']:
3629 raise util.Abort(_('the name \'%s\' is reserved') % n)
3629 raise util.Abort(_('the name \'%s\' is reserved') % n)
3630 if not n:
3630 if not n:
3631 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3631 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3632 if opts.get('rev') and opts.get('remove'):
3632 if opts.get('rev') and opts.get('remove'):
3633 raise util.Abort(_("--rev and --remove are incompatible"))
3633 raise util.Abort(_("--rev and --remove are incompatible"))
3634 if opts.get('rev'):
3634 if opts.get('rev'):
3635 rev_ = opts['rev']
3635 rev_ = opts['rev']
3636 message = opts.get('message')
3636 message = opts.get('message')
3637 if opts.get('remove'):
3637 if opts.get('remove'):
3638 expectedtype = opts.get('local') and 'local' or 'global'
3638 expectedtype = opts.get('local') and 'local' or 'global'
3639 for n in names:
3639 for n in names:
3640 if not repo.tagtype(n):
3640 if not repo.tagtype(n):
3641 raise util.Abort(_('tag \'%s\' does not exist') % n)
3641 raise util.Abort(_('tag \'%s\' does not exist') % n)
3642 if repo.tagtype(n) != expectedtype:
3642 if repo.tagtype(n) != expectedtype:
3643 if expectedtype == 'global':
3643 if expectedtype == 'global':
3644 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3644 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3645 else:
3645 else:
3646 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3646 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3647 rev_ = nullid
3647 rev_ = nullid
3648 if not message:
3648 if not message:
3649 # we don't translate commit messages
3649 # we don't translate commit messages
3650 message = 'Removed tag %s' % ', '.join(names)
3650 message = 'Removed tag %s' % ', '.join(names)
3651 elif not opts.get('force'):
3651 elif not opts.get('force'):
3652 for n in names:
3652 for n in names:
3653 if n in repo.tags():
3653 if n in repo.tags():
3654 raise util.Abort(_('tag \'%s\' already exists '
3654 raise util.Abort(_('tag \'%s\' already exists '
3655 '(use -f to force)') % n)
3655 '(use -f to force)') % n)
3656 if not rev_ and repo.dirstate.parents()[1] != nullid:
3656 if not rev_ and repo.dirstate.parents()[1] != nullid:
3657 raise util.Abort(_('uncommitted merge - please provide a '
3657 raise util.Abort(_('uncommitted merge - please provide a '
3658 'specific revision'))
3658 'specific revision'))
3659 r = repo[rev_].node()
3659 r = repo[rev_].node()
3660
3660
3661 if not message:
3661 if not message:
3662 # we don't translate commit messages
3662 # we don't translate commit messages
3663 message = ('Added tag %s for changeset %s' %
3663 message = ('Added tag %s for changeset %s' %
3664 (', '.join(names), short(r)))
3664 (', '.join(names), short(r)))
3665
3665
3666 date = opts.get('date')
3666 date = opts.get('date')
3667 if date:
3667 if date:
3668 date = util.parsedate(date)
3668 date = util.parsedate(date)
3669
3669
3670 if opts.get('edit'):
3670 if opts.get('edit'):
3671 message = ui.edit(message, ui.username())
3671 message = ui.edit(message, ui.username())
3672
3672
3673 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3673 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3674
3674
3675 def tags(ui, repo):
3675 def tags(ui, repo):
3676 """list repository tags
3676 """list repository tags
3677
3677
3678 This lists both regular and local tags. When the -v/--verbose
3678 This lists both regular and local tags. When the -v/--verbose
3679 switch is used, a third column "local" is printed for local tags.
3679 switch is used, a third column "local" is printed for local tags.
3680
3680
3681 Returns 0 on success.
3681 Returns 0 on success.
3682 """
3682 """
3683
3683
3684 hexfunc = ui.debugflag and hex or short
3684 hexfunc = ui.debugflag and hex or short
3685 tagtype = ""
3685 tagtype = ""
3686
3686
3687 for t, n in reversed(repo.tagslist()):
3687 for t, n in reversed(repo.tagslist()):
3688 if ui.quiet:
3688 if ui.quiet:
3689 ui.write("%s\n" % t)
3689 ui.write("%s\n" % t)
3690 continue
3690 continue
3691
3691
3692 try:
3692 try:
3693 hn = hexfunc(n)
3693 hn = hexfunc(n)
3694 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3694 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3695 except error.LookupError:
3695 except error.LookupError:
3696 r = " ?:%s" % hn
3696 r = " ?:%s" % hn
3697 else:
3697 else:
3698 spaces = " " * (30 - encoding.colwidth(t))
3698 spaces = " " * (30 - encoding.colwidth(t))
3699 if ui.verbose:
3699 if ui.verbose:
3700 if repo.tagtype(t) == 'local':
3700 if repo.tagtype(t) == 'local':
3701 tagtype = " local"
3701 tagtype = " local"
3702 else:
3702 else:
3703 tagtype = ""
3703 tagtype = ""
3704 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3704 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3705
3705
3706 def tip(ui, repo, **opts):
3706 def tip(ui, repo, **opts):
3707 """show the tip revision
3707 """show the tip revision
3708
3708
3709 The tip revision (usually just called the tip) is the changeset
3709 The tip revision (usually just called the tip) is the changeset
3710 most recently added to the repository (and therefore the most
3710 most recently added to the repository (and therefore the most
3711 recently changed head).
3711 recently changed head).
3712
3712
3713 If you have just made a commit, that commit will be the tip. If
3713 If you have just made a commit, that commit will be the tip. If
3714 you have just pulled changes from another repository, the tip of
3714 you have just pulled changes from another repository, the tip of
3715 that repository becomes the current tip. The "tip" tag is special
3715 that repository becomes the current tip. The "tip" tag is special
3716 and cannot be renamed or assigned to a different changeset.
3716 and cannot be renamed or assigned to a different changeset.
3717
3717
3718 Returns 0 on success.
3718 Returns 0 on success.
3719 """
3719 """
3720 displayer = cmdutil.show_changeset(ui, repo, opts)
3720 displayer = cmdutil.show_changeset(ui, repo, opts)
3721 displayer.show(repo[len(repo) - 1])
3721 displayer.show(repo[len(repo) - 1])
3722 displayer.close()
3722 displayer.close()
3723
3723
3724 def unbundle(ui, repo, fname1, *fnames, **opts):
3724 def unbundle(ui, repo, fname1, *fnames, **opts):
3725 """apply one or more changegroup files
3725 """apply one or more changegroup files
3726
3726
3727 Apply one or more compressed changegroup files generated by the
3727 Apply one or more compressed changegroup files generated by the
3728 bundle command.
3728 bundle command.
3729
3729
3730 Returns 0 on success, 1 if an update has unresolved files.
3730 Returns 0 on success, 1 if an update has unresolved files.
3731 """
3731 """
3732 fnames = (fname1,) + fnames
3732 fnames = (fname1,) + fnames
3733
3733
3734 lock = repo.lock()
3734 lock = repo.lock()
3735 try:
3735 try:
3736 for fname in fnames:
3736 for fname in fnames:
3737 f = url.open(ui, fname)
3737 f = url.open(ui, fname)
3738 gen = changegroup.readbundle(f, fname)
3738 gen = changegroup.readbundle(f, fname)
3739 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3739 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3740 lock=lock)
3740 lock=lock)
3741 finally:
3741 finally:
3742 lock.release()
3742 lock.release()
3743
3743
3744 return postincoming(ui, repo, modheads, opts.get('update'), None)
3744 return postincoming(ui, repo, modheads, opts.get('update'), None)
3745
3745
3746 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3746 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3747 """update working directory (or switch revisions)
3747 """update working directory (or switch revisions)
3748
3748
3749 Update the repository's working directory to the specified
3749 Update the repository's working directory to the specified
3750 changeset. If no changeset is specified, update to the tip of the
3750 changeset. If no changeset is specified, update to the tip of the
3751 current named branch.
3751 current named branch.
3752
3752
3753 If the changeset is not a descendant of the working directory's
3753 If the changeset is not a descendant of the working directory's
3754 parent, the update is aborted. With the -c/--check option, the
3754 parent, the update is aborted. With the -c/--check option, the
3755 working directory is checked for uncommitted changes; if none are
3755 working directory is checked for uncommitted changes; if none are
3756 found, the working directory is updated to the specified
3756 found, the working directory is updated to the specified
3757 changeset.
3757 changeset.
3758
3758
3759 The following rules apply when the working directory contains
3759 The following rules apply when the working directory contains
3760 uncommitted changes:
3760 uncommitted changes:
3761
3761
3762 1. If neither -c/--check nor -C/--clean is specified, and if
3762 1. If neither -c/--check nor -C/--clean is specified, and if
3763 the requested changeset is an ancestor or descendant of
3763 the requested changeset is an ancestor or descendant of
3764 the working directory's parent, the uncommitted changes
3764 the working directory's parent, the uncommitted changes
3765 are merged into the requested changeset and the merged
3765 are merged into the requested changeset and the merged
3766 result is left uncommitted. If the requested changeset is
3766 result is left uncommitted. If the requested changeset is
3767 not an ancestor or descendant (that is, it is on another
3767 not an ancestor or descendant (that is, it is on another
3768 branch), the update is aborted and the uncommitted changes
3768 branch), the update is aborted and the uncommitted changes
3769 are preserved.
3769 are preserved.
3770
3770
3771 2. With the -c/--check option, the update is aborted and the
3771 2. With the -c/--check option, the update is aborted and the
3772 uncommitted changes are preserved.
3772 uncommitted changes are preserved.
3773
3773
3774 3. With the -C/--clean option, uncommitted changes are discarded and
3774 3. With the -C/--clean option, uncommitted changes are discarded and
3775 the working directory is updated to the requested changeset.
3775 the working directory is updated to the requested changeset.
3776
3776
3777 Use null as the changeset to remove the working directory (like
3777 Use null as the changeset to remove the working directory (like
3778 :hg:`clone -U`).
3778 :hg:`clone -U`).
3779
3779
3780 If you want to update just one file to an older changeset, use
3780 If you want to update just one file to an older changeset, use
3781 :hg:`revert`.
3781 :hg:`revert`.
3782
3782
3783 See :hg:`help dates` for a list of formats valid for -d/--date.
3783 See :hg:`help dates` for a list of formats valid for -d/--date.
3784
3784
3785 Returns 0 on success, 1 if there are unresolved files.
3785 Returns 0 on success, 1 if there are unresolved files.
3786 """
3786 """
3787 if rev and node:
3787 if rev and node:
3788 raise util.Abort(_("please specify just one revision"))
3788 raise util.Abort(_("please specify just one revision"))
3789
3789
3790 if not rev:
3790 if not rev:
3791 rev = node
3791 rev = node
3792
3792
3793 if check and clean:
3793 if check and clean:
3794 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3794 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3795
3795
3796 if check:
3796 if check:
3797 # we could use dirty() but we can ignore merge and branch trivia
3797 # we could use dirty() but we can ignore merge and branch trivia
3798 c = repo[None]
3798 c = repo[None]
3799 if c.modified() or c.added() or c.removed():
3799 if c.modified() or c.added() or c.removed():
3800 raise util.Abort(_("uncommitted local changes"))
3800 raise util.Abort(_("uncommitted local changes"))
3801
3801
3802 if date:
3802 if date:
3803 if rev:
3803 if rev:
3804 raise util.Abort(_("you can't specify a revision and a date"))
3804 raise util.Abort(_("you can't specify a revision and a date"))
3805 rev = cmdutil.finddate(ui, repo, date)
3805 rev = cmdutil.finddate(ui, repo, date)
3806
3806
3807 if clean or check:
3807 if clean or check:
3808 return hg.clean(repo, rev)
3808 return hg.clean(repo, rev)
3809 else:
3809 else:
3810 return hg.update(repo, rev)
3810 return hg.update(repo, rev)
3811
3811
3812 def verify(ui, repo):
3812 def verify(ui, repo):
3813 """verify the integrity of the repository
3813 """verify the integrity of the repository
3814
3814
3815 Verify the integrity of the current repository.
3815 Verify the integrity of the current repository.
3816
3816
3817 This will perform an extensive check of the repository's
3817 This will perform an extensive check of the repository's
3818 integrity, validating the hashes and checksums of each entry in
3818 integrity, validating the hashes and checksums of each entry in
3819 the changelog, manifest, and tracked files, as well as the
3819 the changelog, manifest, and tracked files, as well as the
3820 integrity of their crosslinks and indices.
3820 integrity of their crosslinks and indices.
3821
3821
3822 Returns 0 on success, 1 if errors are encountered.
3822 Returns 0 on success, 1 if errors are encountered.
3823 """
3823 """
3824 return hg.verify(repo)
3824 return hg.verify(repo)
3825
3825
3826 def version_(ui):
3826 def version_(ui):
3827 """output version and copyright information"""
3827 """output version and copyright information"""
3828 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3828 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3829 % util.version())
3829 % util.version())
3830 ui.status(_(
3830 ui.status(_(
3831 "\nCopyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others\n"
3831 "\nCopyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others\n"
3832 "This is free software; see the source for copying conditions. "
3832 "This is free software; see the source for copying conditions. "
3833 "There is NO\nwarranty; "
3833 "There is NO\nwarranty; "
3834 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3834 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3835 ))
3835 ))
3836
3836
3837 # Command options and aliases are listed here, alphabetically
3837 # Command options and aliases are listed here, alphabetically
3838
3838
3839 globalopts = [
3839 globalopts = [
3840 ('R', 'repository', '',
3840 ('R', 'repository', '',
3841 _('repository root directory or name of overlay bundle file'),
3841 _('repository root directory or name of overlay bundle file'),
3842 _('REPO')),
3842 _('REPO')),
3843 ('', 'cwd', '',
3843 ('', 'cwd', '',
3844 _('change working directory'), _('DIR')),
3844 _('change working directory'), _('DIR')),
3845 ('y', 'noninteractive', None,
3845 ('y', 'noninteractive', None,
3846 _('do not prompt, assume \'yes\' for any required answers')),
3846 _('do not prompt, assume \'yes\' for any required answers')),
3847 ('q', 'quiet', None, _('suppress output')),
3847 ('q', 'quiet', None, _('suppress output')),
3848 ('v', 'verbose', None, _('enable additional output')),
3848 ('v', 'verbose', None, _('enable additional output')),
3849 ('', 'config', [],
3849 ('', 'config', [],
3850 _('set/override config option (use \'section.name=value\')'),
3850 _('set/override config option (use \'section.name=value\')'),
3851 _('CONFIG')),
3851 _('CONFIG')),
3852 ('', 'debug', None, _('enable debugging output')),
3852 ('', 'debug', None, _('enable debugging output')),
3853 ('', 'debugger', None, _('start debugger')),
3853 ('', 'debugger', None, _('start debugger')),
3854 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3854 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3855 _('ENCODE')),
3855 _('ENCODE')),
3856 ('', 'encodingmode', encoding.encodingmode,
3856 ('', 'encodingmode', encoding.encodingmode,
3857 _('set the charset encoding mode'), _('MODE')),
3857 _('set the charset encoding mode'), _('MODE')),
3858 ('', 'traceback', None, _('always print a traceback on exception')),
3858 ('', 'traceback', None, _('always print a traceback on exception')),
3859 ('', 'time', None, _('time how long the command takes')),
3859 ('', 'time', None, _('time how long the command takes')),
3860 ('', 'profile', None, _('print command execution profile')),
3860 ('', 'profile', None, _('print command execution profile')),
3861 ('', 'version', None, _('output version information and exit')),
3861 ('', 'version', None, _('output version information and exit')),
3862 ('h', 'help', None, _('display help and exit')),
3862 ('h', 'help', None, _('display help and exit')),
3863 ]
3863 ]
3864
3864
3865 dryrunopts = [('n', 'dry-run', None,
3865 dryrunopts = [('n', 'dry-run', None,
3866 _('do not perform actions, just print output'))]
3866 _('do not perform actions, just print output'))]
3867
3867
3868 remoteopts = [
3868 remoteopts = [
3869 ('e', 'ssh', '',
3869 ('e', 'ssh', '',
3870 _('specify ssh command to use'), _('CMD')),
3870 _('specify ssh command to use'), _('CMD')),
3871 ('', 'remotecmd', '',
3871 ('', 'remotecmd', '',
3872 _('specify hg command to run on the remote side'), _('CMD')),
3872 _('specify hg command to run on the remote side'), _('CMD')),
3873 ]
3873 ]
3874
3874
3875 walkopts = [
3875 walkopts = [
3876 ('I', 'include', [],
3876 ('I', 'include', [],
3877 _('include names matching the given patterns'), _('PATTERN')),
3877 _('include names matching the given patterns'), _('PATTERN')),
3878 ('X', 'exclude', [],
3878 ('X', 'exclude', [],
3879 _('exclude names matching the given patterns'), _('PATTERN')),
3879 _('exclude names matching the given patterns'), _('PATTERN')),
3880 ]
3880 ]
3881
3881
3882 commitopts = [
3882 commitopts = [
3883 ('m', 'message', '',
3883 ('m', 'message', '',
3884 _('use text as commit message'), _('TEXT')),
3884 _('use text as commit message'), _('TEXT')),
3885 ('l', 'logfile', '',
3885 ('l', 'logfile', '',
3886 _('read commit message from file'), _('FILE')),
3886 _('read commit message from file'), _('FILE')),
3887 ]
3887 ]
3888
3888
3889 commitopts2 = [
3889 commitopts2 = [
3890 ('d', 'date', '',
3890 ('d', 'date', '',
3891 _('record datecode as commit date'), _('DATE')),
3891 _('record datecode as commit date'), _('DATE')),
3892 ('u', 'user', '',
3892 ('u', 'user', '',
3893 _('record the specified user as committer'), _('USER')),
3893 _('record the specified user as committer'), _('USER')),
3894 ]
3894 ]
3895
3895
3896 templateopts = [
3896 templateopts = [
3897 ('', 'style', '',
3897 ('', 'style', '',
3898 _('display using template map file'), _('STYLE')),
3898 _('display using template map file'), _('STYLE')),
3899 ('', 'template', '',
3899 ('', 'template', '',
3900 _('display with template'), _('TEMPLATE')),
3900 _('display with template'), _('TEMPLATE')),
3901 ]
3901 ]
3902
3902
3903 logopts = [
3903 logopts = [
3904 ('p', 'patch', None, _('show patch')),
3904 ('p', 'patch', None, _('show patch')),
3905 ('g', 'git', None, _('use git extended diff format')),
3905 ('g', 'git', None, _('use git extended diff format')),
3906 ('l', 'limit', '',
3906 ('l', 'limit', '',
3907 _('limit number of changes displayed'), _('NUM')),
3907 _('limit number of changes displayed'), _('NUM')),
3908 ('M', 'no-merges', None, _('do not show merges')),
3908 ('M', 'no-merges', None, _('do not show merges')),
3909 ('', 'stat', None, _('output diffstat-style summary of changes')),
3909 ('', 'stat', None, _('output diffstat-style summary of changes')),
3910 ] + templateopts
3910 ] + templateopts
3911
3911
3912 diffopts = [
3912 diffopts = [
3913 ('a', 'text', None, _('treat all files as text')),
3913 ('a', 'text', None, _('treat all files as text')),
3914 ('g', 'git', None, _('use git extended diff format')),
3914 ('g', 'git', None, _('use git extended diff format')),
3915 ('', 'nodates', None, _('omit dates from diff headers'))
3915 ('', 'nodates', None, _('omit dates from diff headers'))
3916 ]
3916 ]
3917
3917
3918 diffopts2 = [
3918 diffopts2 = [
3919 ('p', 'show-function', None, _('show which function each change is in')),
3919 ('p', 'show-function', None, _('show which function each change is in')),
3920 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3920 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3921 ('w', 'ignore-all-space', None,
3921 ('w', 'ignore-all-space', None,
3922 _('ignore white space when comparing lines')),
3922 _('ignore white space when comparing lines')),
3923 ('b', 'ignore-space-change', None,
3923 ('b', 'ignore-space-change', None,
3924 _('ignore changes in the amount of white space')),
3924 _('ignore changes in the amount of white space')),
3925 ('B', 'ignore-blank-lines', None,
3925 ('B', 'ignore-blank-lines', None,
3926 _('ignore changes whose lines are all blank')),
3926 _('ignore changes whose lines are all blank')),
3927 ('U', 'unified', '',
3927 ('U', 'unified', '',
3928 _('number of lines of context to show'), _('NUM')),
3928 _('number of lines of context to show'), _('NUM')),
3929 ('', 'stat', None, _('output diffstat-style summary of changes')),
3929 ('', 'stat', None, _('output diffstat-style summary of changes')),
3930 ]
3930 ]
3931
3931
3932 similarityopts = [
3932 similarityopts = [
3933 ('s', 'similarity', '',
3933 ('s', 'similarity', '',
3934 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
3934 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
3935 ]
3935 ]
3936
3936
3937 subrepoopts = [
3937 subrepoopts = [
3938 ('S', 'subrepos', None,
3938 ('S', 'subrepos', None,
3939 _('recurse into subrepositories'))
3939 _('recurse into subrepositories'))
3940 ]
3940 ]
3941
3941
3942 table = {
3942 table = {
3943 "^add": (add, walkopts + subrepoopts + dryrunopts,
3943 "^add": (add, walkopts + subrepoopts + dryrunopts,
3944 _('[OPTION]... [FILE]...')),
3944 _('[OPTION]... [FILE]...')),
3945 "addremove":
3945 "addremove":
3946 (addremove, similarityopts + walkopts + dryrunopts,
3946 (addremove, similarityopts + walkopts + dryrunopts,
3947 _('[OPTION]... [FILE]...')),
3947 _('[OPTION]... [FILE]...')),
3948 "^annotate|blame":
3948 "^annotate|blame":
3949 (annotate,
3949 (annotate,
3950 [('r', 'rev', '',
3950 [('r', 'rev', '',
3951 _('annotate the specified revision'), _('REV')),
3951 _('annotate the specified revision'), _('REV')),
3952 ('', 'follow', None,
3952 ('', 'follow', None,
3953 _('follow copies/renames and list the filename (DEPRECATED)')),
3953 _('follow copies/renames and list the filename (DEPRECATED)')),
3954 ('', 'no-follow', None, _("don't follow copies and renames")),
3954 ('', 'no-follow', None, _("don't follow copies and renames")),
3955 ('a', 'text', None, _('treat all files as text')),
3955 ('a', 'text', None, _('treat all files as text')),
3956 ('u', 'user', None, _('list the author (long with -v)')),
3956 ('u', 'user', None, _('list the author (long with -v)')),
3957 ('f', 'file', None, _('list the filename')),
3957 ('f', 'file', None, _('list the filename')),
3958 ('d', 'date', None, _('list the date (short with -q)')),
3958 ('d', 'date', None, _('list the date (short with -q)')),
3959 ('n', 'number', None, _('list the revision number (default)')),
3959 ('n', 'number', None, _('list the revision number (default)')),
3960 ('c', 'changeset', None, _('list the changeset')),
3960 ('c', 'changeset', None, _('list the changeset')),
3961 ('l', 'line-number', None,
3961 ('l', 'line-number', None,
3962 _('show line number at the first appearance'))
3962 _('show line number at the first appearance'))
3963 ] + walkopts,
3963 ] + walkopts,
3964 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3964 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3965 "archive":
3965 "archive":
3966 (archive,
3966 (archive,
3967 [('', 'no-decode', None, _('do not pass files through decoders')),
3967 [('', 'no-decode', None, _('do not pass files through decoders')),
3968 ('p', 'prefix', '',
3968 ('p', 'prefix', '',
3969 _('directory prefix for files in archive'), _('PREFIX')),
3969 _('directory prefix for files in archive'), _('PREFIX')),
3970 ('r', 'rev', '',
3970 ('r', 'rev', '',
3971 _('revision to distribute'), _('REV')),
3971 _('revision to distribute'), _('REV')),
3972 ('t', 'type', '',
3972 ('t', 'type', '',
3973 _('type of distribution to create'), _('TYPE')),
3973 _('type of distribution to create'), _('TYPE')),
3974 ] + subrepoopts + walkopts,
3974 ] + subrepoopts + walkopts,
3975 _('[OPTION]... DEST')),
3975 _('[OPTION]... DEST')),
3976 "backout":
3976 "backout":
3977 (backout,
3977 (backout,
3978 [('', 'merge', None,
3978 [('', 'merge', None,
3979 _('merge with old dirstate parent after backout')),
3979 _('merge with old dirstate parent after backout')),
3980 ('', 'parent', '',
3980 ('', 'parent', '',
3981 _('parent to choose when backing out merge'), _('REV')),
3981 _('parent to choose when backing out merge'), _('REV')),
3982 ('r', 'rev', '',
3982 ('r', 'rev', '',
3983 _('revision to backout'), _('REV')),
3983 _('revision to backout'), _('REV')),
3984 ] + walkopts + commitopts + commitopts2,
3984 ] + walkopts + commitopts + commitopts2,
3985 _('[OPTION]... [-r] REV')),
3985 _('[OPTION]... [-r] REV')),
3986 "bisect":
3986 "bisect":
3987 (bisect,
3987 (bisect,
3988 [('r', 'reset', False, _('reset bisect state')),
3988 [('r', 'reset', False, _('reset bisect state')),
3989 ('g', 'good', False, _('mark changeset good')),
3989 ('g', 'good', False, _('mark changeset good')),
3990 ('b', 'bad', False, _('mark changeset bad')),
3990 ('b', 'bad', False, _('mark changeset bad')),
3991 ('s', 'skip', False, _('skip testing changeset')),
3991 ('s', 'skip', False, _('skip testing changeset')),
3992 ('c', 'command', '',
3992 ('c', 'command', '',
3993 _('use command to check changeset state'), _('CMD')),
3993 _('use command to check changeset state'), _('CMD')),
3994 ('U', 'noupdate', False, _('do not update to target'))],
3994 ('U', 'noupdate', False, _('do not update to target'))],
3995 _("[-gbsr] [-U] [-c CMD] [REV]")),
3995 _("[-gbsr] [-U] [-c CMD] [REV]")),
3996 "branch":
3996 "branch":
3997 (branch,
3997 (branch,
3998 [('f', 'force', None,
3998 [('f', 'force', None,
3999 _('set branch name even if it shadows an existing branch')),
3999 _('set branch name even if it shadows an existing branch')),
4000 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4000 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4001 _('[-fC] [NAME]')),
4001 _('[-fC] [NAME]')),
4002 "branches":
4002 "branches":
4003 (branches,
4003 (branches,
4004 [('a', 'active', False,
4004 [('a', 'active', False,
4005 _('show only branches that have unmerged heads')),
4005 _('show only branches that have unmerged heads')),
4006 ('c', 'closed', False,
4006 ('c', 'closed', False,
4007 _('show normal and closed branches'))],
4007 _('show normal and closed branches'))],
4008 _('[-ac]')),
4008 _('[-ac]')),
4009 "bundle":
4009 "bundle":
4010 (bundle,
4010 (bundle,
4011 [('f', 'force', None,
4011 [('f', 'force', None,
4012 _('run even when the destination is unrelated')),
4012 _('run even when the destination is unrelated')),
4013 ('r', 'rev', [],
4013 ('r', 'rev', [],
4014 _('a changeset intended to be added to the destination'),
4014 _('a changeset intended to be added to the destination'),
4015 _('REV')),
4015 _('REV')),
4016 ('b', 'branch', [],
4016 ('b', 'branch', [],
4017 _('a specific branch you would like to bundle'),
4017 _('a specific branch you would like to bundle'),
4018 _('BRANCH')),
4018 _('BRANCH')),
4019 ('', 'base', [],
4019 ('', 'base', [],
4020 _('a base changeset assumed to be available at the destination'),
4020 _('a base changeset assumed to be available at the destination'),
4021 _('REV')),
4021 _('REV')),
4022 ('a', 'all', None, _('bundle all changesets in the repository')),
4022 ('a', 'all', None, _('bundle all changesets in the repository')),
4023 ('t', 'type', 'bzip2',
4023 ('t', 'type', 'bzip2',
4024 _('bundle compression type to use'), _('TYPE')),
4024 _('bundle compression type to use'), _('TYPE')),
4025 ] + remoteopts,
4025 ] + remoteopts,
4026 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4026 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4027 "cat":
4027 "cat":
4028 (cat,
4028 (cat,
4029 [('o', 'output', '',
4029 [('o', 'output', '',
4030 _('print output to file with formatted name'), _('FORMAT')),
4030 _('print output to file with formatted name'), _('FORMAT')),
4031 ('r', 'rev', '',
4031 ('r', 'rev', '',
4032 _('print the given revision'), _('REV')),
4032 _('print the given revision'), _('REV')),
4033 ('', 'decode', None, _('apply any matching decode filter')),
4033 ('', 'decode', None, _('apply any matching decode filter')),
4034 ] + walkopts,
4034 ] + walkopts,
4035 _('[OPTION]... FILE...')),
4035 _('[OPTION]... FILE...')),
4036 "^clone":
4036 "^clone":
4037 (clone,
4037 (clone,
4038 [('U', 'noupdate', None,
4038 [('U', 'noupdate', None,
4039 _('the clone will include an empty working copy (only a repository)')),
4039 _('the clone will include an empty working copy (only a repository)')),
4040 ('u', 'updaterev', '',
4040 ('u', 'updaterev', '',
4041 _('revision, tag or branch to check out'), _('REV')),
4041 _('revision, tag or branch to check out'), _('REV')),
4042 ('r', 'rev', [],
4042 ('r', 'rev', [],
4043 _('include the specified changeset'), _('REV')),
4043 _('include the specified changeset'), _('REV')),
4044 ('b', 'branch', [],
4044 ('b', 'branch', [],
4045 _('clone only the specified branch'), _('BRANCH')),
4045 _('clone only the specified branch'), _('BRANCH')),
4046 ('', 'pull', None, _('use pull protocol to copy metadata')),
4046 ('', 'pull', None, _('use pull protocol to copy metadata')),
4047 ('', 'uncompressed', None,
4047 ('', 'uncompressed', None,
4048 _('use uncompressed transfer (fast over LAN)')),
4048 _('use uncompressed transfer (fast over LAN)')),
4049 ] + remoteopts,
4049 ] + remoteopts,
4050 _('[OPTION]... SOURCE [DEST]')),
4050 _('[OPTION]... SOURCE [DEST]')),
4051 "^commit|ci":
4051 "^commit|ci":
4052 (commit,
4052 (commit,
4053 [('A', 'addremove', None,
4053 [('A', 'addremove', None,
4054 _('mark new/missing files as added/removed before committing')),
4054 _('mark new/missing files as added/removed before committing')),
4055 ('', 'close-branch', None,
4055 ('', 'close-branch', None,
4056 _('mark a branch as closed, hiding it from the branch list')),
4056 _('mark a branch as closed, hiding it from the branch list')),
4057 ] + walkopts + commitopts + commitopts2,
4057 ] + walkopts + commitopts + commitopts2,
4058 _('[OPTION]... [FILE]...')),
4058 _('[OPTION]... [FILE]...')),
4059 "copy|cp":
4059 "copy|cp":
4060 (copy,
4060 (copy,
4061 [('A', 'after', None, _('record a copy that has already occurred')),
4061 [('A', 'after', None, _('record a copy that has already occurred')),
4062 ('f', 'force', None,
4062 ('f', 'force', None,
4063 _('forcibly copy over an existing managed file')),
4063 _('forcibly copy over an existing managed file')),
4064 ] + walkopts + dryrunopts,
4064 ] + walkopts + dryrunopts,
4065 _('[OPTION]... [SOURCE]... DEST')),
4065 _('[OPTION]... [SOURCE]... DEST')),
4066 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4066 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4067 "debugbuilddag":
4067 "debugbuilddag":
4068 (debugbuilddag,
4068 (debugbuilddag,
4069 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4069 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4070 ('a', 'appended-file', None, _('add single file all revs append to')),
4070 ('a', 'appended-file', None, _('add single file all revs append to')),
4071 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4071 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4072 ('n', 'new-file', None, _('add new file at each rev')),
4072 ('n', 'new-file', None, _('add new file at each rev')),
4073 ],
4073 ],
4074 _('[OPTION]... TEXT')),
4074 _('[OPTION]... TEXT')),
4075 "debugcheckstate": (debugcheckstate, [], ''),
4075 "debugcheckstate": (debugcheckstate, [], ''),
4076 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4076 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4077 "debugcomplete":
4077 "debugcomplete":
4078 (debugcomplete,
4078 (debugcomplete,
4079 [('o', 'options', None, _('show the command options'))],
4079 [('o', 'options', None, _('show the command options'))],
4080 _('[-o] CMD')),
4080 _('[-o] CMD')),
4081 "debugdag":
4081 "debugdag":
4082 (debugdag,
4082 (debugdag,
4083 [('t', 'tags', None, _('use tags as labels')),
4083 [('t', 'tags', None, _('use tags as labels')),
4084 ('b', 'branches', None, _('annotate with branch names')),
4084 ('b', 'branches', None, _('annotate with branch names')),
4085 ('', 'dots', None, _('use dots for runs')),
4085 ('', 'dots', None, _('use dots for runs')),
4086 ('s', 'spaces', None, _('separate elements by spaces')),
4086 ('s', 'spaces', None, _('separate elements by spaces')),
4087 ],
4087 ],
4088 _('[OPTION]... [FILE [REV]...]')),
4088 _('[OPTION]... [FILE [REV]...]')),
4089 "debugdate":
4089 "debugdate":
4090 (debugdate,
4090 (debugdate,
4091 [('e', 'extended', None, _('try extended date formats'))],
4091 [('e', 'extended', None, _('try extended date formats'))],
4092 _('[-e] DATE [RANGE]')),
4092 _('[-e] DATE [RANGE]')),
4093 "debugdata": (debugdata, [], _('FILE REV')),
4093 "debugdata": (debugdata, [], _('FILE REV')),
4094 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4094 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4095 "debugindex": (debugindex, [], _('FILE')),
4095 "debugindex": (debugindex, [], _('FILE')),
4096 "debugindexdot": (debugindexdot, [], _('FILE')),
4096 "debugindexdot": (debugindexdot, [], _('FILE')),
4097 "debuginstall": (debuginstall, [], ''),
4097 "debuginstall": (debuginstall, [], ''),
4098 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4098 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4099 "debugrebuildstate":
4099 "debugrebuildstate":
4100 (debugrebuildstate,
4100 (debugrebuildstate,
4101 [('r', 'rev', '',
4101 [('r', 'rev', '',
4102 _('revision to rebuild to'), _('REV'))],
4102 _('revision to rebuild to'), _('REV'))],
4103 _('[-r REV] [REV]')),
4103 _('[-r REV] [REV]')),
4104 "debugrename":
4104 "debugrename":
4105 (debugrename,
4105 (debugrename,
4106 [('r', 'rev', '',
4106 [('r', 'rev', '',
4107 _('revision to debug'), _('REV'))],
4107 _('revision to debug'), _('REV'))],
4108 _('[-r REV] FILE')),
4108 _('[-r REV] FILE')),
4109 "debugrevspec":
4109 "debugrevspec":
4110 (debugrevspec, [], ('REVSPEC')),
4110 (debugrevspec, [], ('REVSPEC')),
4111 "debugsetparents":
4111 "debugsetparents":
4112 (debugsetparents, [], _('REV1 [REV2]')),
4112 (debugsetparents, [], _('REV1 [REV2]')),
4113 "debugstate":
4113 "debugstate":
4114 (debugstate,
4114 (debugstate,
4115 [('', 'nodates', None, _('do not display the saved mtime'))],
4115 [('', 'nodates', None, _('do not display the saved mtime'))],
4116 _('[OPTION]...')),
4116 _('[OPTION]...')),
4117 "debugsub":
4117 "debugsub":
4118 (debugsub,
4118 (debugsub,
4119 [('r', 'rev', '',
4119 [('r', 'rev', '',
4120 _('revision to check'), _('REV'))],
4120 _('revision to check'), _('REV'))],
4121 _('[-r REV] [REV]')),
4121 _('[-r REV] [REV]')),
4122 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4122 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4123 "^diff":
4123 "^diff":
4124 (diff,
4124 (diff,
4125 [('r', 'rev', [],
4125 [('r', 'rev', [],
4126 _('revision'), _('REV')),
4126 _('revision'), _('REV')),
4127 ('c', 'change', '',
4127 ('c', 'change', '',
4128 _('change made by revision'), _('REV'))
4128 _('change made by revision'), _('REV'))
4129 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4129 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4130 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4130 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4131 "^export":
4131 "^export":
4132 (export,
4132 (export,
4133 [('o', 'output', '',
4133 [('o', 'output', '',
4134 _('print output to file with formatted name'), _('FORMAT')),
4134 _('print output to file with formatted name'), _('FORMAT')),
4135 ('', 'switch-parent', None, _('diff against the second parent')),
4135 ('', 'switch-parent', None, _('diff against the second parent')),
4136 ('r', 'rev', [],
4136 ('r', 'rev', [],
4137 _('revisions to export'), _('REV')),
4137 _('revisions to export'), _('REV')),
4138 ] + diffopts,
4138 ] + diffopts,
4139 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4139 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4140 "^forget":
4140 "^forget":
4141 (forget,
4141 (forget,
4142 [] + walkopts,
4142 [] + walkopts,
4143 _('[OPTION]... FILE...')),
4143 _('[OPTION]... FILE...')),
4144 "grep":
4144 "grep":
4145 (grep,
4145 (grep,
4146 [('0', 'print0', None, _('end fields with NUL')),
4146 [('0', 'print0', None, _('end fields with NUL')),
4147 ('', 'all', None, _('print all revisions that match')),
4147 ('', 'all', None, _('print all revisions that match')),
4148 ('f', 'follow', None,
4148 ('f', 'follow', None,
4149 _('follow changeset history,'
4149 _('follow changeset history,'
4150 ' or file history across copies and renames')),
4150 ' or file history across copies and renames')),
4151 ('i', 'ignore-case', None, _('ignore case when matching')),
4151 ('i', 'ignore-case', None, _('ignore case when matching')),
4152 ('l', 'files-with-matches', None,
4152 ('l', 'files-with-matches', None,
4153 _('print only filenames and revisions that match')),
4153 _('print only filenames and revisions that match')),
4154 ('n', 'line-number', None, _('print matching line numbers')),
4154 ('n', 'line-number', None, _('print matching line numbers')),
4155 ('r', 'rev', [],
4155 ('r', 'rev', [],
4156 _('only search files changed within revision range'), _('REV')),
4156 _('only search files changed within revision range'), _('REV')),
4157 ('u', 'user', None, _('list the author (long with -v)')),
4157 ('u', 'user', None, _('list the author (long with -v)')),
4158 ('d', 'date', None, _('list the date (short with -q)')),
4158 ('d', 'date', None, _('list the date (short with -q)')),
4159 ] + walkopts,
4159 ] + walkopts,
4160 _('[OPTION]... PATTERN [FILE]...')),
4160 _('[OPTION]... PATTERN [FILE]...')),
4161 "heads":
4161 "heads":
4162 (heads,
4162 (heads,
4163 [('r', 'rev', '',
4163 [('r', 'rev', '',
4164 _('show only heads which are descendants of STARTREV'),
4164 _('show only heads which are descendants of STARTREV'),
4165 _('STARTREV')),
4165 _('STARTREV')),
4166 ('t', 'topo', False, _('show topological heads only')),
4166 ('t', 'topo', False, _('show topological heads only')),
4167 ('a', 'active', False,
4167 ('a', 'active', False,
4168 _('show active branchheads only (DEPRECATED)')),
4168 _('show active branchheads only (DEPRECATED)')),
4169 ('c', 'closed', False,
4169 ('c', 'closed', False,
4170 _('show normal and closed branch heads')),
4170 _('show normal and closed branch heads')),
4171 ] + templateopts,
4171 ] + templateopts,
4172 _('[-ac] [-r STARTREV] [REV]...')),
4172 _('[-ac] [-r STARTREV] [REV]...')),
4173 "help": (help_, [], _('[TOPIC]')),
4173 "help": (help_, [], _('[TOPIC]')),
4174 "identify|id":
4174 "identify|id":
4175 (identify,
4175 (identify,
4176 [('r', 'rev', '',
4176 [('r', 'rev', '',
4177 _('identify the specified revision'), _('REV')),
4177 _('identify the specified revision'), _('REV')),
4178 ('n', 'num', None, _('show local revision number')),
4178 ('n', 'num', None, _('show local revision number')),
4179 ('i', 'id', None, _('show global revision id')),
4179 ('i', 'id', None, _('show global revision id')),
4180 ('b', 'branch', None, _('show branch')),
4180 ('b', 'branch', None, _('show branch')),
4181 ('t', 'tags', None, _('show tags'))],
4181 ('t', 'tags', None, _('show tags'))],
4182 _('[-nibt] [-r REV] [SOURCE]')),
4182 _('[-nibt] [-r REV] [SOURCE]')),
4183 "import|patch":
4183 "import|patch":
4184 (import_,
4184 (import_,
4185 [('p', 'strip', 1,
4185 [('p', 'strip', 1,
4186 _('directory strip option for patch. This has the same '
4186 _('directory strip option for patch. This has the same '
4187 'meaning as the corresponding patch option'),
4187 'meaning as the corresponding patch option'),
4188 _('NUM')),
4188 _('NUM')),
4189 ('b', 'base', '',
4189 ('b', 'base', '',
4190 _('base path'), _('PATH')),
4190 _('base path'), _('PATH')),
4191 ('f', 'force', None,
4191 ('f', 'force', None,
4192 _('skip check for outstanding uncommitted changes')),
4192 _('skip check for outstanding uncommitted changes')),
4193 ('', 'no-commit', None,
4193 ('', 'no-commit', None,
4194 _("don't commit, just update the working directory")),
4194 _("don't commit, just update the working directory")),
4195 ('', 'exact', None,
4195 ('', 'exact', None,
4196 _('apply patch to the nodes from which it was generated')),
4196 _('apply patch to the nodes from which it was generated')),
4197 ('', 'import-branch', None,
4197 ('', 'import-branch', None,
4198 _('use any branch information in patch (implied by --exact)'))] +
4198 _('use any branch information in patch (implied by --exact)'))] +
4199 commitopts + commitopts2 + similarityopts,
4199 commitopts + commitopts2 + similarityopts,
4200 _('[OPTION]... PATCH...')),
4200 _('[OPTION]... PATCH...')),
4201 "incoming|in":
4201 "incoming|in":
4202 (incoming,
4202 (incoming,
4203 [('f', 'force', None,
4203 [('f', 'force', None,
4204 _('run even if remote repository is unrelated')),
4204 _('run even if remote repository is unrelated')),
4205 ('n', 'newest-first', None, _('show newest record first')),
4205 ('n', 'newest-first', None, _('show newest record first')),
4206 ('', 'bundle', '',
4206 ('', 'bundle', '',
4207 _('file to store the bundles into'), _('FILE')),
4207 _('file to store the bundles into'), _('FILE')),
4208 ('r', 'rev', [],
4208 ('r', 'rev', [],
4209 _('a remote changeset intended to be added'), _('REV')),
4209 _('a remote changeset intended to be added'), _('REV')),
4210 ('b', 'branch', [],
4210 ('b', 'branch', [],
4211 _('a specific branch you would like to pull'), _('BRANCH')),
4211 _('a specific branch you would like to pull'), _('BRANCH')),
4212 ] + logopts + remoteopts + subrepoopts,
4212 ] + logopts + remoteopts + subrepoopts,
4213 _('[-p] [-n] [-M] [-f] [-r REV]...'
4213 _('[-p] [-n] [-M] [-f] [-r REV]...'
4214 ' [--bundle FILENAME] [SOURCE]')),
4214 ' [--bundle FILENAME] [SOURCE]')),
4215 "^init":
4215 "^init":
4216 (init,
4216 (init,
4217 remoteopts,
4217 remoteopts,
4218 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4218 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4219 "locate":
4219 "locate":
4220 (locate,
4220 (locate,
4221 [('r', 'rev', '',
4221 [('r', 'rev', '',
4222 _('search the repository as it is in REV'), _('REV')),
4222 _('search the repository as it is in REV'), _('REV')),
4223 ('0', 'print0', None,
4223 ('0', 'print0', None,
4224 _('end filenames with NUL, for use with xargs')),
4224 _('end filenames with NUL, for use with xargs')),
4225 ('f', 'fullpath', None,
4225 ('f', 'fullpath', None,
4226 _('print complete paths from the filesystem root')),
4226 _('print complete paths from the filesystem root')),
4227 ] + walkopts,
4227 ] + walkopts,
4228 _('[OPTION]... [PATTERN]...')),
4228 _('[OPTION]... [PATTERN]...')),
4229 "^log|history":
4229 "^log|history":
4230 (log,
4230 (log,
4231 [('f', 'follow', None,
4231 [('f', 'follow', None,
4232 _('follow changeset history,'
4232 _('follow changeset history,'
4233 ' or file history across copies and renames')),
4233 ' or file history across copies and renames')),
4234 ('', 'follow-first', None,
4234 ('', 'follow-first', None,
4235 _('only follow the first parent of merge changesets')),
4235 _('only follow the first parent of merge changesets')),
4236 ('d', 'date', '',
4236 ('d', 'date', '',
4237 _('show revisions matching date spec'), _('DATE')),
4237 _('show revisions matching date spec'), _('DATE')),
4238 ('C', 'copies', None, _('show copied files')),
4238 ('C', 'copies', None, _('show copied files')),
4239 ('k', 'keyword', [],
4239 ('k', 'keyword', [],
4240 _('do case-insensitive search for a given text'), _('TEXT')),
4240 _('do case-insensitive search for a given text'), _('TEXT')),
4241 ('r', 'rev', [],
4241 ('r', 'rev', [],
4242 _('show the specified revision or range'), _('REV')),
4242 _('show the specified revision or range'), _('REV')),
4243 ('', 'removed', None, _('include revisions where files were removed')),
4243 ('', 'removed', None, _('include revisions where files were removed')),
4244 ('m', 'only-merges', None, _('show only merges')),
4244 ('m', 'only-merges', None, _('show only merges')),
4245 ('u', 'user', [],
4245 ('u', 'user', [],
4246 _('revisions committed by user'), _('USER')),
4246 _('revisions committed by user'), _('USER')),
4247 ('', 'only-branch', [],
4247 ('', 'only-branch', [],
4248 _('show only changesets within the given named branch (DEPRECATED)'),
4248 _('show only changesets within the given named branch (DEPRECATED)'),
4249 _('BRANCH')),
4249 _('BRANCH')),
4250 ('b', 'branch', [],
4250 ('b', 'branch', [],
4251 _('show changesets within the given named branch'), _('BRANCH')),
4251 _('show changesets within the given named branch'), _('BRANCH')),
4252 ('P', 'prune', [],
4252 ('P', 'prune', [],
4253 _('do not display revision or any of its ancestors'), _('REV')),
4253 _('do not display revision or any of its ancestors'), _('REV')),
4254 ] + logopts + walkopts,
4254 ] + logopts + walkopts,
4255 _('[OPTION]... [FILE]')),
4255 _('[OPTION]... [FILE]')),
4256 "manifest":
4256 "manifest":
4257 (manifest,
4257 (manifest,
4258 [('r', 'rev', '',
4258 [('r', 'rev', '',
4259 _('revision to display'), _('REV'))],
4259 _('revision to display'), _('REV'))],
4260 _('[-r REV]')),
4260 _('[-r REV]')),
4261 "^merge":
4261 "^merge":
4262 (merge,
4262 (merge,
4263 [('f', 'force', None, _('force a merge with outstanding changes')),
4263 [('f', 'force', None, _('force a merge with outstanding changes')),
4264 ('r', 'rev', '',
4264 ('r', 'rev', '',
4265 _('revision to merge'), _('REV')),
4265 _('revision to merge'), _('REV')),
4266 ('P', 'preview', None,
4266 ('P', 'preview', None,
4267 _('review revisions to merge (no merge is performed)'))],
4267 _('review revisions to merge (no merge is performed)'))],
4268 _('[-P] [-f] [[-r] REV]')),
4268 _('[-P] [-f] [[-r] REV]')),
4269 "outgoing|out":
4269 "outgoing|out":
4270 (outgoing,
4270 (outgoing,
4271 [('f', 'force', None,
4271 [('f', 'force', None,
4272 _('run even when the destination is unrelated')),
4272 _('run even when the destination is unrelated')),
4273 ('r', 'rev', [],
4273 ('r', 'rev', [],
4274 _('a changeset intended to be included in the destination'),
4274 _('a changeset intended to be included in the destination'),
4275 _('REV')),
4275 _('REV')),
4276 ('n', 'newest-first', None, _('show newest record first')),
4276 ('n', 'newest-first', None, _('show newest record first')),
4277 ('b', 'branch', [],
4277 ('b', 'branch', [],
4278 _('a specific branch you would like to push'), _('BRANCH')),
4278 _('a specific branch you would like to push'), _('BRANCH')),
4279 ] + logopts + remoteopts + subrepoopts,
4279 ] + logopts + remoteopts + subrepoopts,
4280 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4280 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4281 "parents":
4281 "parents":
4282 (parents,
4282 (parents,
4283 [('r', 'rev', '',
4283 [('r', 'rev', '',
4284 _('show parents of the specified revision'), _('REV')),
4284 _('show parents of the specified revision'), _('REV')),
4285 ] + templateopts,
4285 ] + templateopts,
4286 _('[-r REV] [FILE]')),
4286 _('[-r REV] [FILE]')),
4287 "paths": (paths, [], _('[NAME]')),
4287 "paths": (paths, [], _('[NAME]')),
4288 "^pull":
4288 "^pull":
4289 (pull,
4289 (pull,
4290 [('u', 'update', None,
4290 [('u', 'update', None,
4291 _('update to new branch head if changesets were pulled')),
4291 _('update to new branch head if changesets were pulled')),
4292 ('f', 'force', None,
4292 ('f', 'force', None,
4293 _('run even when remote repository is unrelated')),
4293 _('run even when remote repository is unrelated')),
4294 ('r', 'rev', [],
4294 ('r', 'rev', [],
4295 _('a remote changeset intended to be added'), _('REV')),
4295 _('a remote changeset intended to be added'), _('REV')),
4296 ('b', 'branch', [],
4296 ('b', 'branch', [],
4297 _('a specific branch you would like to pull'), _('BRANCH')),
4297 _('a specific branch you would like to pull'), _('BRANCH')),
4298 ] + remoteopts,
4298 ] + remoteopts,
4299 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4299 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4300 "^push":
4300 "^push":
4301 (push,
4301 (push,
4302 [('f', 'force', None, _('force push')),
4302 [('f', 'force', None, _('force push')),
4303 ('r', 'rev', [],
4303 ('r', 'rev', [],
4304 _('a changeset intended to be included in the destination'),
4304 _('a changeset intended to be included in the destination'),
4305 _('REV')),
4305 _('REV')),
4306 ('b', 'branch', [],
4306 ('b', 'branch', [],
4307 _('a specific branch you would like to push'), _('BRANCH')),
4307 _('a specific branch you would like to push'), _('BRANCH')),
4308 ('', 'new-branch', False, _('allow pushing a new branch')),
4308 ('', 'new-branch', False, _('allow pushing a new branch')),
4309 ] + remoteopts,
4309 ] + remoteopts,
4310 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4310 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4311 "recover": (recover, []),
4311 "recover": (recover, []),
4312 "^remove|rm":
4312 "^remove|rm":
4313 (remove,
4313 (remove,
4314 [('A', 'after', None, _('record delete for missing files')),
4314 [('A', 'after', None, _('record delete for missing files')),
4315 ('f', 'force', None,
4315 ('f', 'force', None,
4316 _('remove (and delete) file even if added or modified')),
4316 _('remove (and delete) file even if added or modified')),
4317 ] + walkopts,
4317 ] + walkopts,
4318 _('[OPTION]... FILE...')),
4318 _('[OPTION]... FILE...')),
4319 "rename|mv":
4319 "rename|mv":
4320 (rename,
4320 (rename,
4321 [('A', 'after', None, _('record a rename that has already occurred')),
4321 [('A', 'after', None, _('record a rename that has already occurred')),
4322 ('f', 'force', None,
4322 ('f', 'force', None,
4323 _('forcibly copy over an existing managed file')),
4323 _('forcibly copy over an existing managed file')),
4324 ] + walkopts + dryrunopts,
4324 ] + walkopts + dryrunopts,
4325 _('[OPTION]... SOURCE... DEST')),
4325 _('[OPTION]... SOURCE... DEST')),
4326 "resolve":
4326 "resolve":
4327 (resolve,
4327 (resolve,
4328 [('a', 'all', None, _('select all unresolved files')),
4328 [('a', 'all', None, _('select all unresolved files')),
4329 ('l', 'list', None, _('list state of files needing merge')),
4329 ('l', 'list', None, _('list state of files needing merge')),
4330 ('m', 'mark', None, _('mark files as resolved')),
4330 ('m', 'mark', None, _('mark files as resolved')),
4331 ('u', 'unmark', None, _('mark files as unresolved')),
4331 ('u', 'unmark', None, _('mark files as unresolved')),
4332 ('n', 'no-status', None, _('hide status prefix'))]
4332 ('n', 'no-status', None, _('hide status prefix'))]
4333 + walkopts,
4333 + walkopts,
4334 _('[OPTION]... [FILE]...')),
4334 _('[OPTION]... [FILE]...')),
4335 "revert":
4335 "revert":
4336 (revert,
4336 (revert,
4337 [('a', 'all', None, _('revert all changes when no arguments given')),
4337 [('a', 'all', None, _('revert all changes when no arguments given')),
4338 ('d', 'date', '',
4338 ('d', 'date', '',
4339 _('tipmost revision matching date'), _('DATE')),
4339 _('tipmost revision matching date'), _('DATE')),
4340 ('r', 'rev', '',
4340 ('r', 'rev', '',
4341 _('revert to the specified revision'), _('REV')),
4341 _('revert to the specified revision'), _('REV')),
4342 ('', 'no-backup', None, _('do not save backup copies of files')),
4342 ('', 'no-backup', None, _('do not save backup copies of files')),
4343 ] + walkopts + dryrunopts,
4343 ] + walkopts + dryrunopts,
4344 _('[OPTION]... [-r REV] [NAME]...')),
4344 _('[OPTION]... [-r REV] [NAME]...')),
4345 "rollback": (rollback, dryrunopts),
4345 "rollback": (rollback, dryrunopts),
4346 "root": (root, []),
4346 "root": (root, []),
4347 "^serve":
4347 "^serve":
4348 (serve,
4348 (serve,
4349 [('A', 'accesslog', '',
4349 [('A', 'accesslog', '',
4350 _('name of access log file to write to'), _('FILE')),
4350 _('name of access log file to write to'), _('FILE')),
4351 ('d', 'daemon', None, _('run server in background')),
4351 ('d', 'daemon', None, _('run server in background')),
4352 ('', 'daemon-pipefds', '',
4352 ('', 'daemon-pipefds', '',
4353 _('used internally by daemon mode'), _('NUM')),
4353 _('used internally by daemon mode'), _('NUM')),
4354 ('E', 'errorlog', '',
4354 ('E', 'errorlog', '',
4355 _('name of error log file to write to'), _('FILE')),
4355 _('name of error log file to write to'), _('FILE')),
4356 # use string type, then we can check if something was passed
4356 # use string type, then we can check if something was passed
4357 ('p', 'port', '',
4357 ('p', 'port', '',
4358 _('port to listen on (default: 8000)'), _('PORT')),
4358 _('port to listen on (default: 8000)'), _('PORT')),
4359 ('a', 'address', '',
4359 ('a', 'address', '',
4360 _('address to listen on (default: all interfaces)'), _('ADDR')),
4360 _('address to listen on (default: all interfaces)'), _('ADDR')),
4361 ('', 'prefix', '',
4361 ('', 'prefix', '',
4362 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4362 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4363 ('n', 'name', '',
4363 ('n', 'name', '',
4364 _('name to show in web pages (default: working directory)'),
4364 _('name to show in web pages (default: working directory)'),
4365 _('NAME')),
4365 _('NAME')),
4366 ('', 'web-conf', '',
4366 ('', 'web-conf', '',
4367 _('name of the hgweb config file (see "hg help hgweb")'),
4367 _('name of the hgweb config file (see "hg help hgweb")'),
4368 _('FILE')),
4368 _('FILE')),
4369 ('', 'webdir-conf', '',
4369 ('', 'webdir-conf', '',
4370 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4370 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4371 ('', 'pid-file', '',
4371 ('', 'pid-file', '',
4372 _('name of file to write process ID to'), _('FILE')),
4372 _('name of file to write process ID to'), _('FILE')),
4373 ('', 'stdio', None, _('for remote clients')),
4373 ('', 'stdio', None, _('for remote clients')),
4374 ('t', 'templates', '',
4374 ('t', 'templates', '',
4375 _('web templates to use'), _('TEMPLATE')),
4375 _('web templates to use'), _('TEMPLATE')),
4376 ('', 'style', '',
4376 ('', 'style', '',
4377 _('template style to use'), _('STYLE')),
4377 _('template style to use'), _('STYLE')),
4378 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4378 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4379 ('', 'certificate', '',
4379 ('', 'certificate', '',
4380 _('SSL certificate file'), _('FILE'))],
4380 _('SSL certificate file'), _('FILE'))],
4381 _('[OPTION]...')),
4381 _('[OPTION]...')),
4382 "showconfig|debugconfig":
4382 "showconfig|debugconfig":
4383 (showconfig,
4383 (showconfig,
4384 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4384 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4385 _('[-u] [NAME]...')),
4385 _('[-u] [NAME]...')),
4386 "^summary|sum":
4386 "^summary|sum":
4387 (summary,
4387 (summary,
4388 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4388 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4389 "^status|st":
4389 "^status|st":
4390 (status,
4390 (status,
4391 [('A', 'all', None, _('show status of all files')),
4391 [('A', 'all', None, _('show status of all files')),
4392 ('m', 'modified', None, _('show only modified files')),
4392 ('m', 'modified', None, _('show only modified files')),
4393 ('a', 'added', None, _('show only added files')),
4393 ('a', 'added', None, _('show only added files')),
4394 ('r', 'removed', None, _('show only removed files')),
4394 ('r', 'removed', None, _('show only removed files')),
4395 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4395 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4396 ('c', 'clean', None, _('show only files without changes')),
4396 ('c', 'clean', None, _('show only files without changes')),
4397 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4397 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4398 ('i', 'ignored', None, _('show only ignored files')),
4398 ('i', 'ignored', None, _('show only ignored files')),
4399 ('n', 'no-status', None, _('hide status prefix')),
4399 ('n', 'no-status', None, _('hide status prefix')),
4400 ('C', 'copies', None, _('show source of copied files')),
4400 ('C', 'copies', None, _('show source of copied files')),
4401 ('0', 'print0', None,
4401 ('0', 'print0', None,
4402 _('end filenames with NUL, for use with xargs')),
4402 _('end filenames with NUL, for use with xargs')),
4403 ('', 'rev', [],
4403 ('', 'rev', [],
4404 _('show difference from revision'), _('REV')),
4404 _('show difference from revision'), _('REV')),
4405 ('', 'change', '',
4405 ('', 'change', '',
4406 _('list the changed files of a revision'), _('REV')),
4406 _('list the changed files of a revision'), _('REV')),
4407 ] + walkopts + subrepoopts,
4407 ] + walkopts + subrepoopts,
4408 _('[OPTION]... [FILE]...')),
4408 _('[OPTION]... [FILE]...')),
4409 "tag":
4409 "tag":
4410 (tag,
4410 (tag,
4411 [('f', 'force', None, _('replace existing tag')),
4411 [('f', 'force', None, _('replace existing tag')),
4412 ('l', 'local', None, _('make the tag local')),
4412 ('l', 'local', None, _('make the tag local')),
4413 ('r', 'rev', '',
4413 ('r', 'rev', '',
4414 _('revision to tag'), _('REV')),
4414 _('revision to tag'), _('REV')),
4415 ('', 'remove', None, _('remove a tag')),
4415 ('', 'remove', None, _('remove a tag')),
4416 # -l/--local is already there, commitopts cannot be used
4416 # -l/--local is already there, commitopts cannot be used
4417 ('e', 'edit', None, _('edit commit message')),
4417 ('e', 'edit', None, _('edit commit message')),
4418 ('m', 'message', '',
4418 ('m', 'message', '',
4419 _('use <text> as commit message'), _('TEXT')),
4419 _('use <text> as commit message'), _('TEXT')),
4420 ] + commitopts2,
4420 ] + commitopts2,
4421 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4421 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4422 "tags": (tags, [], ''),
4422 "tags": (tags, [], ''),
4423 "tip":
4423 "tip":
4424 (tip,
4424 (tip,
4425 [('p', 'patch', None, _('show patch')),
4425 [('p', 'patch', None, _('show patch')),
4426 ('g', 'git', None, _('use git extended diff format')),
4426 ('g', 'git', None, _('use git extended diff format')),
4427 ] + templateopts,
4427 ] + templateopts,
4428 _('[-p] [-g]')),
4428 _('[-p] [-g]')),
4429 "unbundle":
4429 "unbundle":
4430 (unbundle,
4430 (unbundle,
4431 [('u', 'update', None,
4431 [('u', 'update', None,
4432 _('update to new branch head if changesets were unbundled'))],
4432 _('update to new branch head if changesets were unbundled'))],
4433 _('[-u] FILE...')),
4433 _('[-u] FILE...')),
4434 "^update|up|checkout|co":
4434 "^update|up|checkout|co":
4435 (update,
4435 (update,
4436 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4436 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4437 ('c', 'check', None,
4437 ('c', 'check', None,
4438 _('update across branches if no uncommitted changes')),
4438 _('update across branches if no uncommitted changes')),
4439 ('d', 'date', '',
4439 ('d', 'date', '',
4440 _('tipmost revision matching date'), _('DATE')),
4440 _('tipmost revision matching date'), _('DATE')),
4441 ('r', 'rev', '',
4441 ('r', 'rev', '',
4442 _('revision'), _('REV'))],
4442 _('revision'), _('REV'))],
4443 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4443 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4444 "verify": (verify, []),
4444 "verify": (verify, []),
4445 "version": (version_, []),
4445 "version": (version_, []),
4446 }
4446 }
4447
4447
4448 norepo = ("clone init version help debugcommands debugcomplete"
4448 norepo = ("clone init version help debugcommands debugcomplete"
4449 " debugdate debuginstall debugfsinfo debugpushkey")
4449 " debugdate debuginstall debugfsinfo debugpushkey")
4450 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4450 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4451 " debugdata debugindex debugindexdot")
4451 " debugdata debugindex debugindexdot")
@@ -1,1436 +1,1434 b''
1 # util.py - Mercurial utility functions and platform specfic implementations
1 # util.py - Mercurial utility functions and platform specfic implementations
2 #
2 #
3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 """Mercurial utility functions and platform specfic implementations.
10 """Mercurial utility functions and platform specfic implementations.
11
11
12 This contains helper routines that are independent of the SCM core and
12 This contains helper routines that are independent of the SCM core and
13 hide platform-specific details from the core.
13 hide platform-specific details from the core.
14 """
14 """
15
15
16 from i18n import _
16 from i18n import _
17 import error, osutil, encoding
17 import error, osutil, encoding
18 import errno, re, shutil, sys, tempfile, traceback
18 import errno, re, shutil, sys, tempfile, traceback
19 import os, stat, time, calendar, textwrap, unicodedata, signal
19 import os, stat, time, calendar, textwrap, unicodedata, signal
20 import imp, socket
20 import imp, socket
21
21
22 # Python compatibility
22 # Python compatibility
23
23
24 def sha1(s):
24 def sha1(s):
25 return _fastsha1(s)
25 return _fastsha1(s)
26
26
27 def _fastsha1(s):
27 def _fastsha1(s):
28 # This function will import sha1 from hashlib or sha (whichever is
28 # This function will import sha1 from hashlib or sha (whichever is
29 # available) and overwrite itself with it on the first call.
29 # available) and overwrite itself with it on the first call.
30 # Subsequent calls will go directly to the imported function.
30 # Subsequent calls will go directly to the imported function.
31 if sys.version_info >= (2, 5):
31 if sys.version_info >= (2, 5):
32 from hashlib import sha1 as _sha1
32 from hashlib import sha1 as _sha1
33 else:
33 else:
34 from sha import sha as _sha1
34 from sha import sha as _sha1
35 global _fastsha1, sha1
35 global _fastsha1, sha1
36 _fastsha1 = sha1 = _sha1
36 _fastsha1 = sha1 = _sha1
37 return _sha1(s)
37 return _sha1(s)
38
38
39 import __builtin__
39 import __builtin__
40
40
41 if sys.version_info[0] < 3:
41 if sys.version_info[0] < 3:
42 def fakebuffer(sliceable, offset=0):
42 def fakebuffer(sliceable, offset=0):
43 return sliceable[offset:]
43 return sliceable[offset:]
44 else:
44 else:
45 def fakebuffer(sliceable, offset=0):
45 def fakebuffer(sliceable, offset=0):
46 return memoryview(sliceable)[offset:]
46 return memoryview(sliceable)[offset:]
47 try:
47 try:
48 buffer
48 buffer
49 except NameError:
49 except NameError:
50 __builtin__.buffer = fakebuffer
50 __builtin__.buffer = fakebuffer
51
51
52 import subprocess
52 import subprocess
53 closefds = os.name == 'posix'
53 closefds = os.name == 'posix'
54
54
55 def popen2(cmd, env=None, newlines=False):
55 def popen2(cmd, env=None, newlines=False):
56 # Setting bufsize to -1 lets the system decide the buffer size.
56 # Setting bufsize to -1 lets the system decide the buffer size.
57 # The default for bufsize is 0, meaning unbuffered. This leads to
57 # The default for bufsize is 0, meaning unbuffered. This leads to
58 # poor performance on Mac OS X: http://bugs.python.org/issue4194
58 # poor performance on Mac OS X: http://bugs.python.org/issue4194
59 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
59 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
60 close_fds=closefds,
60 close_fds=closefds,
61 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
61 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
62 universal_newlines=newlines,
62 universal_newlines=newlines,
63 env=env)
63 env=env)
64 return p.stdin, p.stdout
64 return p.stdin, p.stdout
65
65
66 def popen3(cmd, env=None, newlines=False):
66 def popen3(cmd, env=None, newlines=False):
67 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
67 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
68 close_fds=closefds,
68 close_fds=closefds,
69 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
69 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
70 stderr=subprocess.PIPE,
70 stderr=subprocess.PIPE,
71 universal_newlines=newlines,
71 universal_newlines=newlines,
72 env=env)
72 env=env)
73 return p.stdin, p.stdout, p.stderr
73 return p.stdin, p.stdout, p.stderr
74
74
75 def version():
75 def version():
76 """Return version information if available."""
76 """Return version information if available."""
77 try:
77 try:
78 import __version__
78 import __version__
79 return __version__.version
79 return __version__.version
80 except ImportError:
80 except ImportError:
81 return 'unknown'
81 return 'unknown'
82
82
83 # used by parsedate
83 # used by parsedate
84 defaultdateformats = (
84 defaultdateformats = (
85 '%Y-%m-%d %H:%M:%S',
85 '%Y-%m-%d %H:%M:%S',
86 '%Y-%m-%d %I:%M:%S%p',
86 '%Y-%m-%d %I:%M:%S%p',
87 '%Y-%m-%d %H:%M',
87 '%Y-%m-%d %H:%M',
88 '%Y-%m-%d %I:%M%p',
88 '%Y-%m-%d %I:%M%p',
89 '%Y-%m-%d',
89 '%Y-%m-%d',
90 '%m-%d',
90 '%m-%d',
91 '%m/%d',
91 '%m/%d',
92 '%m/%d/%y',
92 '%m/%d/%y',
93 '%m/%d/%Y',
93 '%m/%d/%Y',
94 '%a %b %d %H:%M:%S %Y',
94 '%a %b %d %H:%M:%S %Y',
95 '%a %b %d %I:%M:%S%p %Y',
95 '%a %b %d %I:%M:%S%p %Y',
96 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
96 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
97 '%b %d %H:%M:%S %Y',
97 '%b %d %H:%M:%S %Y',
98 '%b %d %I:%M:%S%p %Y',
98 '%b %d %I:%M:%S%p %Y',
99 '%b %d %H:%M:%S',
99 '%b %d %H:%M:%S',
100 '%b %d %I:%M:%S%p',
100 '%b %d %I:%M:%S%p',
101 '%b %d %H:%M',
101 '%b %d %H:%M',
102 '%b %d %I:%M%p',
102 '%b %d %I:%M%p',
103 '%b %d %Y',
103 '%b %d %Y',
104 '%b %d',
104 '%b %d',
105 '%H:%M:%S',
105 '%H:%M:%S',
106 '%I:%M:%S%p',
106 '%I:%M:%S%p',
107 '%H:%M',
107 '%H:%M',
108 '%I:%M%p',
108 '%I:%M%p',
109 )
109 )
110
110
111 extendeddateformats = defaultdateformats + (
111 extendeddateformats = defaultdateformats + (
112 "%Y",
112 "%Y",
113 "%Y-%m",
113 "%Y-%m",
114 "%b",
114 "%b",
115 "%b %Y",
115 "%b %Y",
116 )
116 )
117
117
118 def cachefunc(func):
118 def cachefunc(func):
119 '''cache the result of function calls'''
119 '''cache the result of function calls'''
120 # XXX doesn't handle keywords args
120 # XXX doesn't handle keywords args
121 cache = {}
121 cache = {}
122 if func.func_code.co_argcount == 1:
122 if func.func_code.co_argcount == 1:
123 # we gain a small amount of time because
123 # we gain a small amount of time because
124 # we don't need to pack/unpack the list
124 # we don't need to pack/unpack the list
125 def f(arg):
125 def f(arg):
126 if arg not in cache:
126 if arg not in cache:
127 cache[arg] = func(arg)
127 cache[arg] = func(arg)
128 return cache[arg]
128 return cache[arg]
129 else:
129 else:
130 def f(*args):
130 def f(*args):
131 if args not in cache:
131 if args not in cache:
132 cache[args] = func(*args)
132 cache[args] = func(*args)
133 return cache[args]
133 return cache[args]
134
134
135 return f
135 return f
136
136
137 def lrucachefunc(func):
137 def lrucachefunc(func):
138 '''cache most recent results of function calls'''
138 '''cache most recent results of function calls'''
139 cache = {}
139 cache = {}
140 order = []
140 order = []
141 if func.func_code.co_argcount == 1:
141 if func.func_code.co_argcount == 1:
142 def f(arg):
142 def f(arg):
143 if arg not in cache:
143 if arg not in cache:
144 if len(cache) > 20:
144 if len(cache) > 20:
145 del cache[order.pop(0)]
145 del cache[order.pop(0)]
146 cache[arg] = func(arg)
146 cache[arg] = func(arg)
147 else:
147 else:
148 order.remove(arg)
148 order.remove(arg)
149 order.append(arg)
149 order.append(arg)
150 return cache[arg]
150 return cache[arg]
151 else:
151 else:
152 def f(*args):
152 def f(*args):
153 if args not in cache:
153 if args not in cache:
154 if len(cache) > 20:
154 if len(cache) > 20:
155 del cache[order.pop(0)]
155 del cache[order.pop(0)]
156 cache[args] = func(*args)
156 cache[args] = func(*args)
157 else:
157 else:
158 order.remove(args)
158 order.remove(args)
159 order.append(args)
159 order.append(args)
160 return cache[args]
160 return cache[args]
161
161
162 return f
162 return f
163
163
164 class propertycache(object):
164 class propertycache(object):
165 def __init__(self, func):
165 def __init__(self, func):
166 self.func = func
166 self.func = func
167 self.name = func.__name__
167 self.name = func.__name__
168 def __get__(self, obj, type=None):
168 def __get__(self, obj, type=None):
169 result = self.func(obj)
169 result = self.func(obj)
170 setattr(obj, self.name, result)
170 setattr(obj, self.name, result)
171 return result
171 return result
172
172
173 def pipefilter(s, cmd):
173 def pipefilter(s, cmd):
174 '''filter string S through command CMD, returning its output'''
174 '''filter string S through command CMD, returning its output'''
175 p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
175 p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
176 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
176 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
177 pout, perr = p.communicate(s)
177 pout, perr = p.communicate(s)
178 return pout
178 return pout
179
179
180 def tempfilter(s, cmd):
180 def tempfilter(s, cmd):
181 '''filter string S through a pair of temporary files with CMD.
181 '''filter string S through a pair of temporary files with CMD.
182 CMD is used as a template to create the real command to be run,
182 CMD is used as a template to create the real command to be run,
183 with the strings INFILE and OUTFILE replaced by the real names of
183 with the strings INFILE and OUTFILE replaced by the real names of
184 the temporary files generated.'''
184 the temporary files generated.'''
185 inname, outname = None, None
185 inname, outname = None, None
186 try:
186 try:
187 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
187 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
188 fp = os.fdopen(infd, 'wb')
188 fp = os.fdopen(infd, 'wb')
189 fp.write(s)
189 fp.write(s)
190 fp.close()
190 fp.close()
191 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
191 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
192 os.close(outfd)
192 os.close(outfd)
193 cmd = cmd.replace('INFILE', inname)
193 cmd = cmd.replace('INFILE', inname)
194 cmd = cmd.replace('OUTFILE', outname)
194 cmd = cmd.replace('OUTFILE', outname)
195 code = os.system(cmd)
195 code = os.system(cmd)
196 if sys.platform == 'OpenVMS' and code & 1:
196 if sys.platform == 'OpenVMS' and code & 1:
197 code = 0
197 code = 0
198 if code:
198 if code:
199 raise Abort(_("command '%s' failed: %s") %
199 raise Abort(_("command '%s' failed: %s") %
200 (cmd, explain_exit(code)))
200 (cmd, explain_exit(code)))
201 return open(outname, 'rb').read()
201 return open(outname, 'rb').read()
202 finally:
202 finally:
203 try:
203 try:
204 if inname:
204 if inname:
205 os.unlink(inname)
205 os.unlink(inname)
206 except:
206 except:
207 pass
207 pass
208 try:
208 try:
209 if outname:
209 if outname:
210 os.unlink(outname)
210 os.unlink(outname)
211 except:
211 except:
212 pass
212 pass
213
213
214 filtertable = {
214 filtertable = {
215 'tempfile:': tempfilter,
215 'tempfile:': tempfilter,
216 'pipe:': pipefilter,
216 'pipe:': pipefilter,
217 }
217 }
218
218
219 def filter(s, cmd):
219 def filter(s, cmd):
220 "filter a string through a command that transforms its input to its output"
220 "filter a string through a command that transforms its input to its output"
221 for name, fn in filtertable.iteritems():
221 for name, fn in filtertable.iteritems():
222 if cmd.startswith(name):
222 if cmd.startswith(name):
223 return fn(s, cmd[len(name):].lstrip())
223 return fn(s, cmd[len(name):].lstrip())
224 return pipefilter(s, cmd)
224 return pipefilter(s, cmd)
225
225
226 def binary(s):
226 def binary(s):
227 """return true if a string is binary data"""
227 """return true if a string is binary data"""
228 return bool(s and '\0' in s)
228 return bool(s and '\0' in s)
229
229
230 def increasingchunks(source, min=1024, max=65536):
230 def increasingchunks(source, min=1024, max=65536):
231 '''return no less than min bytes per chunk while data remains,
231 '''return no less than min bytes per chunk while data remains,
232 doubling min after each chunk until it reaches max'''
232 doubling min after each chunk until it reaches max'''
233 def log2(x):
233 def log2(x):
234 if not x:
234 if not x:
235 return 0
235 return 0
236 i = 0
236 i = 0
237 while x:
237 while x:
238 x >>= 1
238 x >>= 1
239 i += 1
239 i += 1
240 return i - 1
240 return i - 1
241
241
242 buf = []
242 buf = []
243 blen = 0
243 blen = 0
244 for chunk in source:
244 for chunk in source:
245 buf.append(chunk)
245 buf.append(chunk)
246 blen += len(chunk)
246 blen += len(chunk)
247 if blen >= min:
247 if blen >= min:
248 if min < max:
248 if min < max:
249 min = min << 1
249 min = min << 1
250 nmin = 1 << log2(blen)
250 nmin = 1 << log2(blen)
251 if nmin > min:
251 if nmin > min:
252 min = nmin
252 min = nmin
253 if min > max:
253 if min > max:
254 min = max
254 min = max
255 yield ''.join(buf)
255 yield ''.join(buf)
256 blen = 0
256 blen = 0
257 buf = []
257 buf = []
258 if buf:
258 if buf:
259 yield ''.join(buf)
259 yield ''.join(buf)
260
260
261 Abort = error.Abort
261 Abort = error.Abort
262
262
263 def always(fn):
263 def always(fn):
264 return True
264 return True
265
265
266 def never(fn):
266 def never(fn):
267 return False
267 return False
268
268
269 def pathto(root, n1, n2):
269 def pathto(root, n1, n2):
270 '''return the relative path from one place to another.
270 '''return the relative path from one place to another.
271 root should use os.sep to separate directories
271 root should use os.sep to separate directories
272 n1 should use os.sep to separate directories
272 n1 should use os.sep to separate directories
273 n2 should use "/" to separate directories
273 n2 should use "/" to separate directories
274 returns an os.sep-separated path.
274 returns an os.sep-separated path.
275
275
276 If n1 is a relative path, it's assumed it's
276 If n1 is a relative path, it's assumed it's
277 relative to root.
277 relative to root.
278 n2 should always be relative to root.
278 n2 should always be relative to root.
279 '''
279 '''
280 if not n1:
280 if not n1:
281 return localpath(n2)
281 return localpath(n2)
282 if os.path.isabs(n1):
282 if os.path.isabs(n1):
283 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
283 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
284 return os.path.join(root, localpath(n2))
284 return os.path.join(root, localpath(n2))
285 n2 = '/'.join((pconvert(root), n2))
285 n2 = '/'.join((pconvert(root), n2))
286 a, b = splitpath(n1), n2.split('/')
286 a, b = splitpath(n1), n2.split('/')
287 a.reverse()
287 a.reverse()
288 b.reverse()
288 b.reverse()
289 while a and b and a[-1] == b[-1]:
289 while a and b and a[-1] == b[-1]:
290 a.pop()
290 a.pop()
291 b.pop()
291 b.pop()
292 b.reverse()
292 b.reverse()
293 return os.sep.join((['..'] * len(a)) + b) or '.'
293 return os.sep.join((['..'] * len(a)) + b) or '.'
294
294
295 def canonpath(root, cwd, myname, auditor=None):
295 def canonpath(root, cwd, myname, auditor=None):
296 """return the canonical path of myname, given cwd and root"""
296 """return the canonical path of myname, given cwd and root"""
297 if endswithsep(root):
297 if endswithsep(root):
298 rootsep = root
298 rootsep = root
299 else:
299 else:
300 rootsep = root + os.sep
300 rootsep = root + os.sep
301 name = myname
301 name = myname
302 if not os.path.isabs(name):
302 if not os.path.isabs(name):
303 name = os.path.join(root, cwd, name)
303 name = os.path.join(root, cwd, name)
304 name = os.path.normpath(name)
304 name = os.path.normpath(name)
305 if auditor is None:
305 if auditor is None:
306 auditor = path_auditor(root)
306 auditor = path_auditor(root)
307 if name != rootsep and name.startswith(rootsep):
307 if name != rootsep and name.startswith(rootsep):
308 name = name[len(rootsep):]
308 name = name[len(rootsep):]
309 auditor(name)
309 auditor(name)
310 return pconvert(name)
310 return pconvert(name)
311 elif name == root:
311 elif name == root:
312 return ''
312 return ''
313 else:
313 else:
314 # Determine whether `name' is in the hierarchy at or beneath `root',
314 # Determine whether `name' is in the hierarchy at or beneath `root',
315 # by iterating name=dirname(name) until that causes no change (can't
315 # by iterating name=dirname(name) until that causes no change (can't
316 # check name == '/', because that doesn't work on windows). For each
316 # check name == '/', because that doesn't work on windows). For each
317 # `name', compare dev/inode numbers. If they match, the list `rel'
317 # `name', compare dev/inode numbers. If they match, the list `rel'
318 # holds the reversed list of components making up the relative file
318 # holds the reversed list of components making up the relative file
319 # name we want.
319 # name we want.
320 root_st = os.stat(root)
320 root_st = os.stat(root)
321 rel = []
321 rel = []
322 while True:
322 while True:
323 try:
323 try:
324 name_st = os.stat(name)
324 name_st = os.stat(name)
325 except OSError:
325 except OSError:
326 break
326 break
327 if samestat(name_st, root_st):
327 if samestat(name_st, root_st):
328 if not rel:
328 if not rel:
329 # name was actually the same as root (maybe a symlink)
329 # name was actually the same as root (maybe a symlink)
330 return ''
330 return ''
331 rel.reverse()
331 rel.reverse()
332 name = os.path.join(*rel)
332 name = os.path.join(*rel)
333 auditor(name)
333 auditor(name)
334 return pconvert(name)
334 return pconvert(name)
335 dirname, basename = os.path.split(name)
335 dirname, basename = os.path.split(name)
336 rel.append(basename)
336 rel.append(basename)
337 if dirname == name:
337 if dirname == name:
338 break
338 break
339 name = dirname
339 name = dirname
340
340
341 raise Abort('%s not under root' % myname)
341 raise Abort('%s not under root' % myname)
342
342
343 _hgexecutable = None
343 _hgexecutable = None
344
344
345 def main_is_frozen():
345 def main_is_frozen():
346 """return True if we are a frozen executable.
346 """return True if we are a frozen executable.
347
347
348 The code supports py2exe (most common, Windows only) and tools/freeze
348 The code supports py2exe (most common, Windows only) and tools/freeze
349 (portable, not much used).
349 (portable, not much used).
350 """
350 """
351 return (hasattr(sys, "frozen") or # new py2exe
351 return (hasattr(sys, "frozen") or # new py2exe
352 hasattr(sys, "importers") or # old py2exe
352 hasattr(sys, "importers") or # old py2exe
353 imp.is_frozen("__main__")) # tools/freeze
353 imp.is_frozen("__main__")) # tools/freeze
354
354
355 def hgexecutable():
355 def hgexecutable():
356 """return location of the 'hg' executable.
356 """return location of the 'hg' executable.
357
357
358 Defaults to $HG or 'hg' in the search path.
358 Defaults to $HG or 'hg' in the search path.
359 """
359 """
360 if _hgexecutable is None:
360 if _hgexecutable is None:
361 hg = os.environ.get('HG')
361 hg = os.environ.get('HG')
362 if hg:
362 if hg:
363 set_hgexecutable(hg)
363 set_hgexecutable(hg)
364 elif main_is_frozen():
364 elif main_is_frozen():
365 set_hgexecutable(sys.executable)
365 set_hgexecutable(sys.executable)
366 else:
366 else:
367 exe = find_exe('hg') or os.path.basename(sys.argv[0])
367 exe = find_exe('hg') or os.path.basename(sys.argv[0])
368 set_hgexecutable(exe)
368 set_hgexecutable(exe)
369 return _hgexecutable
369 return _hgexecutable
370
370
371 def set_hgexecutable(path):
371 def set_hgexecutable(path):
372 """set location of the 'hg' executable"""
372 """set location of the 'hg' executable"""
373 global _hgexecutable
373 global _hgexecutable
374 _hgexecutable = path
374 _hgexecutable = path
375
375
376 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
376 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
377 '''enhanced shell command execution.
377 '''enhanced shell command execution.
378 run with environment maybe modified, maybe in different dir.
378 run with environment maybe modified, maybe in different dir.
379
379
380 if command fails and onerr is None, return status. if ui object,
380 if command fails and onerr is None, return status. if ui object,
381 print error message and return status, else raise onerr object as
381 print error message and return status, else raise onerr object as
382 exception.
382 exception.
383
383
384 if out is specified, it is assumed to be a file-like object that has a
384 if out is specified, it is assumed to be a file-like object that has a
385 write() method. stdout and stderr will be redirected to out.'''
385 write() method. stdout and stderr will be redirected to out.'''
386 def py2shell(val):
386 def py2shell(val):
387 'convert python object into string that is useful to shell'
387 'convert python object into string that is useful to shell'
388 if val is None or val is False:
388 if val is None or val is False:
389 return '0'
389 return '0'
390 if val is True:
390 if val is True:
391 return '1'
391 return '1'
392 return str(val)
392 return str(val)
393 origcmd = cmd
393 origcmd = cmd
394 if os.name == 'nt':
394 if os.name == 'nt':
395 cmd = '"%s"' % cmd
395 cmd = '"%s"' % cmd
396 env = dict(os.environ)
396 env = dict(os.environ)
397 env.update((k, py2shell(v)) for k, v in environ.iteritems())
397 env.update((k, py2shell(v)) for k, v in environ.iteritems())
398 env['HG'] = hgexecutable()
398 env['HG'] = hgexecutable()
399 if out is None:
399 if out is None:
400 rc = subprocess.call(cmd, shell=True, close_fds=closefds,
400 rc = subprocess.call(cmd, shell=True, close_fds=closefds,
401 env=env, cwd=cwd)
401 env=env, cwd=cwd)
402 else:
402 else:
403 proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
403 proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
404 env=env, cwd=cwd, stdout=subprocess.PIPE,
404 env=env, cwd=cwd, stdout=subprocess.PIPE,
405 stderr=subprocess.STDOUT)
405 stderr=subprocess.STDOUT)
406 for line in proc.stdout:
406 for line in proc.stdout:
407 out.write(line)
407 out.write(line)
408 proc.wait()
408 proc.wait()
409 rc = proc.returncode
409 rc = proc.returncode
410 if sys.platform == 'OpenVMS' and rc & 1:
410 if sys.platform == 'OpenVMS' and rc & 1:
411 rc = 0
411 rc = 0
412 if rc and onerr:
412 if rc and onerr:
413 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
413 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
414 explain_exit(rc)[0])
414 explain_exit(rc)[0])
415 if errprefix:
415 if errprefix:
416 errmsg = '%s: %s' % (errprefix, errmsg)
416 errmsg = '%s: %s' % (errprefix, errmsg)
417 try:
417 try:
418 onerr.warn(errmsg + '\n')
418 onerr.warn(errmsg + '\n')
419 except AttributeError:
419 except AttributeError:
420 raise onerr(errmsg)
420 raise onerr(errmsg)
421 return rc
421 return rc
422
422
423 def checksignature(func):
423 def checksignature(func):
424 '''wrap a function with code to check for calling errors'''
424 '''wrap a function with code to check for calling errors'''
425 def check(*args, **kwargs):
425 def check(*args, **kwargs):
426 try:
426 try:
427 return func(*args, **kwargs)
427 return func(*args, **kwargs)
428 except TypeError:
428 except TypeError:
429 if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
429 if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
430 raise error.SignatureError
430 raise error.SignatureError
431 raise
431 raise
432
432
433 return check
433 return check
434
434
435 def unlink(f):
435 def unlink(f):
436 """unlink and remove the directory if it is empty"""
436 """unlink and remove the directory if it is empty"""
437 os.unlink(f)
437 os.unlink(f)
438 # try removing directories that might now be empty
438 # try removing directories that might now be empty
439 try:
439 try:
440 os.removedirs(os.path.dirname(f))
440 os.removedirs(os.path.dirname(f))
441 except OSError:
441 except OSError:
442 pass
442 pass
443
443
444 def copyfile(src, dest):
444 def copyfile(src, dest):
445 "copy a file, preserving mode and atime/mtime"
445 "copy a file, preserving mode and atime/mtime"
446 if os.path.islink(src):
446 if os.path.islink(src):
447 try:
447 try:
448 os.unlink(dest)
448 os.unlink(dest)
449 except:
449 except:
450 pass
450 pass
451 os.symlink(os.readlink(src), dest)
451 os.symlink(os.readlink(src), dest)
452 else:
452 else:
453 try:
453 try:
454 shutil.copyfile(src, dest)
454 shutil.copyfile(src, dest)
455 shutil.copystat(src, dest)
455 shutil.copystat(src, dest)
456 except shutil.Error, inst:
456 except shutil.Error, inst:
457 raise Abort(str(inst))
457 raise Abort(str(inst))
458
458
459 def copyfiles(src, dst, hardlink=None):
459 def copyfiles(src, dst, hardlink=None):
460 """Copy a directory tree using hardlinks if possible"""
460 """Copy a directory tree using hardlinks if possible"""
461
461
462 if hardlink is None:
462 if hardlink is None:
463 hardlink = (os.stat(src).st_dev ==
463 hardlink = (os.stat(src).st_dev ==
464 os.stat(os.path.dirname(dst)).st_dev)
464 os.stat(os.path.dirname(dst)).st_dev)
465
465
466 num = 0
466 num = 0
467 if os.path.isdir(src):
467 if os.path.isdir(src):
468 os.mkdir(dst)
468 os.mkdir(dst)
469 for name, kind in osutil.listdir(src):
469 for name, kind in osutil.listdir(src):
470 srcname = os.path.join(src, name)
470 srcname = os.path.join(src, name)
471 dstname = os.path.join(dst, name)
471 dstname = os.path.join(dst, name)
472 hardlink, n = copyfiles(srcname, dstname, hardlink)
472 hardlink, n = copyfiles(srcname, dstname, hardlink)
473 num += n
473 num += n
474 else:
474 else:
475 if hardlink:
475 if hardlink:
476 try:
476 try:
477 os_link(src, dst)
477 os_link(src, dst)
478 except (IOError, OSError):
478 except (IOError, OSError):
479 hardlink = False
479 hardlink = False
480 shutil.copy(src, dst)
480 shutil.copy(src, dst)
481 else:
481 else:
482 shutil.copy(src, dst)
482 shutil.copy(src, dst)
483 num += 1
483 num += 1
484
484
485 return hardlink, num
485 return hardlink, num
486
486
487 class path_auditor(object):
487 class path_auditor(object):
488 '''ensure that a filesystem path contains no banned components.
488 '''ensure that a filesystem path contains no banned components.
489 the following properties of a path are checked:
489 the following properties of a path are checked:
490
490
491 - under top-level .hg
491 - under top-level .hg
492 - starts at the root of a windows drive
492 - starts at the root of a windows drive
493 - contains ".."
493 - contains ".."
494 - traverses a symlink (e.g. a/symlink_here/b)
494 - traverses a symlink (e.g. a/symlink_here/b)
495 - inside a nested repository (a callback can be used to approve
495 - inside a nested repository (a callback can be used to approve
496 some nested repositories, e.g., subrepositories)
496 some nested repositories, e.g., subrepositories)
497 '''
497 '''
498
498
499 def __init__(self, root, callback=None):
499 def __init__(self, root, callback=None):
500 self.audited = set()
500 self.audited = set()
501 self.auditeddir = set()
501 self.auditeddir = set()
502 self.root = root
502 self.root = root
503 self.callback = callback
503 self.callback = callback
504
504
505 def __call__(self, path):
505 def __call__(self, path):
506 if path in self.audited:
506 if path in self.audited:
507 return
507 return
508 normpath = os.path.normcase(path)
508 normpath = os.path.normcase(path)
509 parts = splitpath(normpath)
509 parts = splitpath(normpath)
510 if (os.path.splitdrive(path)[0]
510 if (os.path.splitdrive(path)[0]
511 or parts[0].lower() in ('.hg', '.hg.', '')
511 or parts[0].lower() in ('.hg', '.hg.', '')
512 or os.pardir in parts):
512 or os.pardir in parts):
513 raise Abort(_("path contains illegal component: %s") % path)
513 raise Abort(_("path contains illegal component: %s") % path)
514 if '.hg' in path.lower():
514 if '.hg' in path.lower():
515 lparts = [p.lower() for p in parts]
515 lparts = [p.lower() for p in parts]
516 for p in '.hg', '.hg.':
516 for p in '.hg', '.hg.':
517 if p in lparts[1:]:
517 if p in lparts[1:]:
518 pos = lparts.index(p)
518 pos = lparts.index(p)
519 base = os.path.join(*parts[:pos])
519 base = os.path.join(*parts[:pos])
520 raise Abort(_('path %r is inside repo %r') % (path, base))
520 raise Abort(_('path %r is inside repo %r') % (path, base))
521 def check(prefix):
521 def check(prefix):
522 curpath = os.path.join(self.root, prefix)
522 curpath = os.path.join(self.root, prefix)
523 try:
523 try:
524 st = os.lstat(curpath)
524 st = os.lstat(curpath)
525 except OSError, err:
525 except OSError, err:
526 # EINVAL can be raised as invalid path syntax under win32.
526 # EINVAL can be raised as invalid path syntax under win32.
527 # They must be ignored for patterns can be checked too.
527 # They must be ignored for patterns can be checked too.
528 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
528 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
529 raise
529 raise
530 else:
530 else:
531 if stat.S_ISLNK(st.st_mode):
531 if stat.S_ISLNK(st.st_mode):
532 raise Abort(_('path %r traverses symbolic link %r') %
532 raise Abort(_('path %r traverses symbolic link %r') %
533 (path, prefix))
533 (path, prefix))
534 elif (stat.S_ISDIR(st.st_mode) and
534 elif (stat.S_ISDIR(st.st_mode) and
535 os.path.isdir(os.path.join(curpath, '.hg'))):
535 os.path.isdir(os.path.join(curpath, '.hg'))):
536 if not self.callback or not self.callback(curpath):
536 if not self.callback or not self.callback(curpath):
537 raise Abort(_('path %r is inside repo %r') %
537 raise Abort(_('path %r is inside repo %r') %
538 (path, prefix))
538 (path, prefix))
539 parts.pop()
539 parts.pop()
540 prefixes = []
540 prefixes = []
541 while parts:
541 while parts:
542 prefix = os.sep.join(parts)
542 prefix = os.sep.join(parts)
543 if prefix in self.auditeddir:
543 if prefix in self.auditeddir:
544 break
544 break
545 check(prefix)
545 check(prefix)
546 prefixes.append(prefix)
546 prefixes.append(prefix)
547 parts.pop()
547 parts.pop()
548
548
549 self.audited.add(path)
549 self.audited.add(path)
550 # only add prefixes to the cache after checking everything: we don't
550 # only add prefixes to the cache after checking everything: we don't
551 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
551 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
552 self.auditeddir.update(prefixes)
552 self.auditeddir.update(prefixes)
553
553
554 def nlinks(pathname):
554 def nlinks(pathname):
555 """Return number of hardlinks for the given file."""
555 """Return number of hardlinks for the given file."""
556 return os.lstat(pathname).st_nlink
556 return os.lstat(pathname).st_nlink
557
557
558 if hasattr(os, 'link'):
558 if hasattr(os, 'link'):
559 os_link = os.link
559 os_link = os.link
560 else:
560 else:
561 def os_link(src, dst):
561 def os_link(src, dst):
562 raise OSError(0, _("Hardlinks not supported"))
562 raise OSError(0, _("Hardlinks not supported"))
563
563
564 def lookup_reg(key, name=None, scope=None):
564 def lookup_reg(key, name=None, scope=None):
565 return None
565 return None
566
566
567 def hidewindow():
567 def hidewindow():
568 """Hide current shell window.
568 """Hide current shell window.
569
569
570 Used to hide the window opened when starting asynchronous
570 Used to hide the window opened when starting asynchronous
571 child process under Windows, unneeded on other systems.
571 child process under Windows, unneeded on other systems.
572 """
572 """
573 pass
573 pass
574
574
575 if os.name == 'nt':
575 if os.name == 'nt':
576 from windows import *
576 from windows import *
577 else:
577 else:
578 from posix import *
578 from posix import *
579
579
580 def makelock(info, pathname):
580 def makelock(info, pathname):
581 try:
581 try:
582 return os.symlink(info, pathname)
582 return os.symlink(info, pathname)
583 except OSError, why:
583 except OSError, why:
584 if why.errno == errno.EEXIST:
584 if why.errno == errno.EEXIST:
585 raise
585 raise
586 except AttributeError: # no symlink in os
586 except AttributeError: # no symlink in os
587 pass
587 pass
588
588
589 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
589 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
590 os.write(ld, info)
590 os.write(ld, info)
591 os.close(ld)
591 os.close(ld)
592
592
593 def readlock(pathname):
593 def readlock(pathname):
594 try:
594 try:
595 return os.readlink(pathname)
595 return os.readlink(pathname)
596 except OSError, why:
596 except OSError, why:
597 if why.errno not in (errno.EINVAL, errno.ENOSYS):
597 if why.errno not in (errno.EINVAL, errno.ENOSYS):
598 raise
598 raise
599 except AttributeError: # no symlink in os
599 except AttributeError: # no symlink in os
600 pass
600 pass
601 return posixfile(pathname).read()
601 return posixfile(pathname).read()
602
602
603 def fstat(fp):
603 def fstat(fp):
604 '''stat file object that may not have fileno method.'''
604 '''stat file object that may not have fileno method.'''
605 try:
605 try:
606 return os.fstat(fp.fileno())
606 return os.fstat(fp.fileno())
607 except AttributeError:
607 except AttributeError:
608 return os.stat(fp.name)
608 return os.stat(fp.name)
609
609
610 # File system features
610 # File system features
611
611
612 def checkcase(path):
612 def checkcase(path):
613 """
613 """
614 Check whether the given path is on a case-sensitive filesystem
614 Check whether the given path is on a case-sensitive filesystem
615
615
616 Requires a path (like /foo/.hg) ending with a foldable final
616 Requires a path (like /foo/.hg) ending with a foldable final
617 directory component.
617 directory component.
618 """
618 """
619 s1 = os.stat(path)
619 s1 = os.stat(path)
620 d, b = os.path.split(path)
620 d, b = os.path.split(path)
621 p2 = os.path.join(d, b.upper())
621 p2 = os.path.join(d, b.upper())
622 if path == p2:
622 if path == p2:
623 p2 = os.path.join(d, b.lower())
623 p2 = os.path.join(d, b.lower())
624 try:
624 try:
625 s2 = os.stat(p2)
625 s2 = os.stat(p2)
626 if s2 == s1:
626 if s2 == s1:
627 return False
627 return False
628 return True
628 return True
629 except:
629 except:
630 return True
630 return True
631
631
632 _fspathcache = {}
632 _fspathcache = {}
633 def fspath(name, root):
633 def fspath(name, root):
634 '''Get name in the case stored in the filesystem
634 '''Get name in the case stored in the filesystem
635
635
636 The name is either relative to root, or it is an absolute path starting
636 The name is either relative to root, or it is an absolute path starting
637 with root. Note that this function is unnecessary, and should not be
637 with root. Note that this function is unnecessary, and should not be
638 called, for case-sensitive filesystems (simply because it's expensive).
638 called, for case-sensitive filesystems (simply because it's expensive).
639 '''
639 '''
640 # If name is absolute, make it relative
640 # If name is absolute, make it relative
641 if name.lower().startswith(root.lower()):
641 if name.lower().startswith(root.lower()):
642 l = len(root)
642 l = len(root)
643 if name[l] == os.sep or name[l] == os.altsep:
643 if name[l] == os.sep or name[l] == os.altsep:
644 l = l + 1
644 l = l + 1
645 name = name[l:]
645 name = name[l:]
646
646
647 if not os.path.lexists(os.path.join(root, name)):
647 if not os.path.lexists(os.path.join(root, name)):
648 return None
648 return None
649
649
650 seps = os.sep
650 seps = os.sep
651 if os.altsep:
651 if os.altsep:
652 seps = seps + os.altsep
652 seps = seps + os.altsep
653 # Protect backslashes. This gets silly very quickly.
653 # Protect backslashes. This gets silly very quickly.
654 seps.replace('\\','\\\\')
654 seps.replace('\\','\\\\')
655 pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
655 pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
656 dir = os.path.normcase(os.path.normpath(root))
656 dir = os.path.normcase(os.path.normpath(root))
657 result = []
657 result = []
658 for part, sep in pattern.findall(name):
658 for part, sep in pattern.findall(name):
659 if sep:
659 if sep:
660 result.append(sep)
660 result.append(sep)
661 continue
661 continue
662
662
663 if dir not in _fspathcache:
663 if dir not in _fspathcache:
664 _fspathcache[dir] = os.listdir(dir)
664 _fspathcache[dir] = os.listdir(dir)
665 contents = _fspathcache[dir]
665 contents = _fspathcache[dir]
666
666
667 lpart = part.lower()
667 lpart = part.lower()
668 lenp = len(part)
668 lenp = len(part)
669 for n in contents:
669 for n in contents:
670 if lenp == len(n) and n.lower() == lpart:
670 if lenp == len(n) and n.lower() == lpart:
671 result.append(n)
671 result.append(n)
672 break
672 break
673 else:
673 else:
674 # Cannot happen, as the file exists!
674 # Cannot happen, as the file exists!
675 result.append(part)
675 result.append(part)
676 dir = os.path.join(dir, lpart)
676 dir = os.path.join(dir, lpart)
677
677
678 return ''.join(result)
678 return ''.join(result)
679
679
680 def checkexec(path):
680 def checkexec(path):
681 """
681 """
682 Check whether the given path is on a filesystem with UNIX-like exec flags
682 Check whether the given path is on a filesystem with UNIX-like exec flags
683
683
684 Requires a directory (like /foo/.hg)
684 Requires a directory (like /foo/.hg)
685 """
685 """
686
686
687 # VFAT on some Linux versions can flip mode but it doesn't persist
687 # VFAT on some Linux versions can flip mode but it doesn't persist
688 # a FS remount. Frequently we can detect it if files are created
688 # a FS remount. Frequently we can detect it if files are created
689 # with exec bit on.
689 # with exec bit on.
690
690
691 try:
691 try:
692 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
692 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
693 fh, fn = tempfile.mkstemp(dir=path, prefix='hg-checkexec-')
693 fh, fn = tempfile.mkstemp(dir=path, prefix='hg-checkexec-')
694 try:
694 try:
695 os.close(fh)
695 os.close(fh)
696 m = os.stat(fn).st_mode & 0777
696 m = os.stat(fn).st_mode & 0777
697 new_file_has_exec = m & EXECFLAGS
697 new_file_has_exec = m & EXECFLAGS
698 os.chmod(fn, m ^ EXECFLAGS)
698 os.chmod(fn, m ^ EXECFLAGS)
699 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
699 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
700 finally:
700 finally:
701 os.unlink(fn)
701 os.unlink(fn)
702 except (IOError, OSError):
702 except (IOError, OSError):
703 # we don't care, the user probably won't be able to commit anyway
703 # we don't care, the user probably won't be able to commit anyway
704 return False
704 return False
705 return not (new_file_has_exec or exec_flags_cannot_flip)
705 return not (new_file_has_exec or exec_flags_cannot_flip)
706
706
707 def checklink(path):
707 def checklink(path):
708 """check whether the given path is on a symlink-capable filesystem"""
708 """check whether the given path is on a symlink-capable filesystem"""
709 # mktemp is not racy because symlink creation will fail if the
709 # mktemp is not racy because symlink creation will fail if the
710 # file already exists
710 # file already exists
711 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
711 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
712 try:
712 try:
713 os.symlink(".", name)
713 os.symlink(".", name)
714 os.unlink(name)
714 os.unlink(name)
715 return True
715 return True
716 except (OSError, AttributeError):
716 except (OSError, AttributeError):
717 return False
717 return False
718
718
719 def endswithsep(path):
719 def endswithsep(path):
720 '''Check path ends with os.sep or os.altsep.'''
720 '''Check path ends with os.sep or os.altsep.'''
721 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
721 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
722
722
723 def splitpath(path):
723 def splitpath(path):
724 '''Split path by os.sep.
724 '''Split path by os.sep.
725 Note that this function does not use os.altsep because this is
725 Note that this function does not use os.altsep because this is
726 an alternative of simple "xxx.split(os.sep)".
726 an alternative of simple "xxx.split(os.sep)".
727 It is recommended to use os.path.normpath() before using this
727 It is recommended to use os.path.normpath() before using this
728 function if need.'''
728 function if need.'''
729 return path.split(os.sep)
729 return path.split(os.sep)
730
730
731 def gui():
731 def gui():
732 '''Are we running in a GUI?'''
732 '''Are we running in a GUI?'''
733 return os.name == "nt" or os.name == "mac" or os.environ.get("DISPLAY")
733 return os.name == "nt" or os.name == "mac" or os.environ.get("DISPLAY")
734
734
735 def mktempcopy(name, emptyok=False, createmode=None):
735 def mktempcopy(name, emptyok=False, createmode=None):
736 """Create a temporary file with the same contents from name
736 """Create a temporary file with the same contents from name
737
737
738 The permission bits are copied from the original file.
738 The permission bits are copied from the original file.
739
739
740 If the temporary file is going to be truncated immediately, you
740 If the temporary file is going to be truncated immediately, you
741 can use emptyok=True as an optimization.
741 can use emptyok=True as an optimization.
742
742
743 Returns the name of the temporary file.
743 Returns the name of the temporary file.
744 """
744 """
745 d, fn = os.path.split(name)
745 d, fn = os.path.split(name)
746 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
746 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
747 os.close(fd)
747 os.close(fd)
748 # Temporary files are created with mode 0600, which is usually not
748 # Temporary files are created with mode 0600, which is usually not
749 # what we want. If the original file already exists, just copy
749 # what we want. If the original file already exists, just copy
750 # its mode. Otherwise, manually obey umask.
750 # its mode. Otherwise, manually obey umask.
751 try:
751 try:
752 st_mode = os.lstat(name).st_mode & 0777
752 st_mode = os.lstat(name).st_mode & 0777
753 except OSError, inst:
753 except OSError, inst:
754 if inst.errno != errno.ENOENT:
754 if inst.errno != errno.ENOENT:
755 raise
755 raise
756 st_mode = createmode
756 st_mode = createmode
757 if st_mode is None:
757 if st_mode is None:
758 st_mode = ~umask
758 st_mode = ~umask
759 st_mode &= 0666
759 st_mode &= 0666
760 os.chmod(temp, st_mode)
760 os.chmod(temp, st_mode)
761 if emptyok:
761 if emptyok:
762 return temp
762 return temp
763 try:
763 try:
764 try:
764 try:
765 ifp = posixfile(name, "rb")
765 ifp = posixfile(name, "rb")
766 except IOError, inst:
766 except IOError, inst:
767 if inst.errno == errno.ENOENT:
767 if inst.errno == errno.ENOENT:
768 return temp
768 return temp
769 if not getattr(inst, 'filename', None):
769 if not getattr(inst, 'filename', None):
770 inst.filename = name
770 inst.filename = name
771 raise
771 raise
772 ofp = posixfile(temp, "wb")
772 ofp = posixfile(temp, "wb")
773 for chunk in filechunkiter(ifp):
773 for chunk in filechunkiter(ifp):
774 ofp.write(chunk)
774 ofp.write(chunk)
775 ifp.close()
775 ifp.close()
776 ofp.close()
776 ofp.close()
777 except:
777 except:
778 try: os.unlink(temp)
778 try: os.unlink(temp)
779 except: pass
779 except: pass
780 raise
780 raise
781 return temp
781 return temp
782
782
783 class atomictempfile(object):
783 class atomictempfile(object):
784 """file-like object that atomically updates a file
784 """file-like object that atomically updates a file
785
785
786 All writes will be redirected to a temporary copy of the original
786 All writes will be redirected to a temporary copy of the original
787 file. When rename is called, the copy is renamed to the original
787 file. When rename is called, the copy is renamed to the original
788 name, making the changes visible.
788 name, making the changes visible.
789 """
789 """
790 def __init__(self, name, mode='w+b', createmode=None):
790 def __init__(self, name, mode='w+b', createmode=None):
791 self.__name = name
791 self.__name = name
792 self._fp = None
792 self._fp = None
793 self.temp = mktempcopy(name, emptyok=('w' in mode),
793 self.temp = mktempcopy(name, emptyok=('w' in mode),
794 createmode=createmode)
794 createmode=createmode)
795 self._fp = posixfile(self.temp, mode)
795 self._fp = posixfile(self.temp, mode)
796
796
797 def __getattr__(self, name):
797 def __getattr__(self, name):
798 return getattr(self._fp, name)
798 return getattr(self._fp, name)
799
799
800 def rename(self):
800 def rename(self):
801 if not self._fp.closed:
801 if not self._fp.closed:
802 self._fp.close()
802 self._fp.close()
803 rename(self.temp, localpath(self.__name))
803 rename(self.temp, localpath(self.__name))
804
804
805 def __del__(self):
805 def __del__(self):
806 if not self._fp:
806 if not self._fp:
807 return
807 return
808 if not self._fp.closed:
808 if not self._fp.closed:
809 try:
809 try:
810 os.unlink(self.temp)
810 os.unlink(self.temp)
811 except: pass
811 except: pass
812 self._fp.close()
812 self._fp.close()
813
813
814 def makedirs(name, mode=None):
814 def makedirs(name, mode=None):
815 """recursive directory creation with parent mode inheritance"""
815 """recursive directory creation with parent mode inheritance"""
816 try:
816 try:
817 os.mkdir(name)
817 os.mkdir(name)
818 if mode is not None:
818 if mode is not None:
819 os.chmod(name, mode)
819 os.chmod(name, mode)
820 return
820 return
821 except OSError, err:
821 except OSError, err:
822 if err.errno == errno.EEXIST:
822 if err.errno == errno.EEXIST:
823 return
823 return
824 if err.errno != errno.ENOENT:
824 if err.errno != errno.ENOENT:
825 raise
825 raise
826 parent = os.path.abspath(os.path.dirname(name))
826 parent = os.path.abspath(os.path.dirname(name))
827 makedirs(parent, mode)
827 makedirs(parent, mode)
828 makedirs(name, mode)
828 makedirs(name, mode)
829
829
830 class opener(object):
830 class opener(object):
831 """Open files relative to a base directory
831 """Open files relative to a base directory
832
832
833 This class is used to hide the details of COW semantics and
833 This class is used to hide the details of COW semantics and
834 remote file access from higher level code.
834 remote file access from higher level code.
835 """
835 """
836 def __init__(self, base, audit=True):
836 def __init__(self, base, audit=True):
837 self.base = base
837 self.base = base
838 if audit:
838 if audit:
839 self.auditor = path_auditor(base)
839 self.auditor = path_auditor(base)
840 else:
840 else:
841 self.auditor = always
841 self.auditor = always
842 self.createmode = None
842 self.createmode = None
843
843
844 @propertycache
844 @propertycache
845 def _can_symlink(self):
845 def _can_symlink(self):
846 return checklink(self.base)
846 return checklink(self.base)
847
847
848 def _fixfilemode(self, name):
848 def _fixfilemode(self, name):
849 if self.createmode is None:
849 if self.createmode is None:
850 return
850 return
851 os.chmod(name, self.createmode & 0666)
851 os.chmod(name, self.createmode & 0666)
852
852
853 def __call__(self, path, mode="r", text=False, atomictemp=False):
853 def __call__(self, path, mode="r", text=False, atomictemp=False):
854 self.auditor(path)
854 self.auditor(path)
855 f = os.path.join(self.base, path)
855 f = os.path.join(self.base, path)
856
856
857 if not text and "b" not in mode:
857 if not text and "b" not in mode:
858 mode += "b" # for that other OS
858 mode += "b" # for that other OS
859
859
860 nlink = -1
860 nlink = -1
861 if mode not in ("r", "rb"):
861 if mode not in ("r", "rb"):
862 try:
862 try:
863 nlink = nlinks(f)
863 nlink = nlinks(f)
864 except OSError:
864 except OSError:
865 nlink = 0
865 nlink = 0
866 d = os.path.dirname(f)
866 d = os.path.dirname(f)
867 if not os.path.isdir(d):
867 if not os.path.isdir(d):
868 makedirs(d, self.createmode)
868 makedirs(d, self.createmode)
869 if atomictemp:
869 if atomictemp:
870 return atomictempfile(f, mode, self.createmode)
870 return atomictempfile(f, mode, self.createmode)
871 if nlink > 1:
871 if nlink > 1:
872 rename(mktempcopy(f), f)
872 rename(mktempcopy(f), f)
873 fp = posixfile(f, mode)
873 fp = posixfile(f, mode)
874 if nlink == 0:
874 if nlink == 0:
875 self._fixfilemode(f)
875 self._fixfilemode(f)
876 return fp
876 return fp
877
877
878 def symlink(self, src, dst):
878 def symlink(self, src, dst):
879 self.auditor(dst)
879 self.auditor(dst)
880 linkname = os.path.join(self.base, dst)
880 linkname = os.path.join(self.base, dst)
881 try:
881 try:
882 os.unlink(linkname)
882 os.unlink(linkname)
883 except OSError:
883 except OSError:
884 pass
884 pass
885
885
886 dirname = os.path.dirname(linkname)
886 dirname = os.path.dirname(linkname)
887 if not os.path.exists(dirname):
887 if not os.path.exists(dirname):
888 makedirs(dirname, self.createmode)
888 makedirs(dirname, self.createmode)
889
889
890 if self._can_symlink:
890 if self._can_symlink:
891 try:
891 try:
892 os.symlink(src, linkname)
892 os.symlink(src, linkname)
893 except OSError, err:
893 except OSError, err:
894 raise OSError(err.errno, _('could not symlink to %r: %s') %
894 raise OSError(err.errno, _('could not symlink to %r: %s') %
895 (src, err.strerror), linkname)
895 (src, err.strerror), linkname)
896 else:
896 else:
897 f = self(dst, "w")
897 f = self(dst, "w")
898 f.write(src)
898 f.write(src)
899 f.close()
899 f.close()
900 self._fixfilemode(dst)
900 self._fixfilemode(dst)
901
901
902 class chunkbuffer(object):
902 class chunkbuffer(object):
903 """Allow arbitrary sized chunks of data to be efficiently read from an
903 """Allow arbitrary sized chunks of data to be efficiently read from an
904 iterator over chunks of arbitrary size."""
904 iterator over chunks of arbitrary size."""
905
905
906 def __init__(self, in_iter):
906 def __init__(self, in_iter):
907 """in_iter is the iterator that's iterating over the input chunks.
907 """in_iter is the iterator that's iterating over the input chunks.
908 targetsize is how big a buffer to try to maintain."""
908 targetsize is how big a buffer to try to maintain."""
909 def splitbig(chunks):
909 def splitbig(chunks):
910 for chunk in chunks:
910 for chunk in chunks:
911 if len(chunk) > 2**20:
911 if len(chunk) > 2**20:
912 pos = 0
912 pos = 0
913 while pos < len(chunk):
913 while pos < len(chunk):
914 end = pos + 2 ** 18
914 end = pos + 2 ** 18
915 yield chunk[pos:end]
915 yield chunk[pos:end]
916 pos = end
916 pos = end
917 else:
917 else:
918 yield chunk
918 yield chunk
919 self.iter = splitbig(in_iter)
919 self.iter = splitbig(in_iter)
920 self._queue = []
920 self._queue = []
921
921
922 def read(self, l):
922 def read(self, l):
923 """Read L bytes of data from the iterator of chunks of data.
923 """Read L bytes of data from the iterator of chunks of data.
924 Returns less than L bytes if the iterator runs dry."""
924 Returns less than L bytes if the iterator runs dry."""
925 left = l
925 left = l
926 buf = ''
926 buf = ''
927 queue = self._queue
927 queue = self._queue
928 while left > 0:
928 while left > 0:
929 # refill the queue
929 # refill the queue
930 if not queue:
930 if not queue:
931 target = 2**18
931 target = 2**18
932 for chunk in self.iter:
932 for chunk in self.iter:
933 queue.append(chunk)
933 queue.append(chunk)
934 target -= len(chunk)
934 target -= len(chunk)
935 if target <= 0:
935 if target <= 0:
936 break
936 break
937 if not queue:
937 if not queue:
938 break
938 break
939
939
940 chunk = queue.pop(0)
940 chunk = queue.pop(0)
941 left -= len(chunk)
941 left -= len(chunk)
942 if left < 0:
942 if left < 0:
943 queue.insert(0, chunk[left:])
943 queue.insert(0, chunk[left:])
944 buf += chunk[:left]
944 buf += chunk[:left]
945 else:
945 else:
946 buf += chunk
946 buf += chunk
947
947
948 return buf
948 return buf
949
949
950 def filechunkiter(f, size=65536, limit=None):
950 def filechunkiter(f, size=65536, limit=None):
951 """Create a generator that produces the data in the file size
951 """Create a generator that produces the data in the file size
952 (default 65536) bytes at a time, up to optional limit (default is
952 (default 65536) bytes at a time, up to optional limit (default is
953 to read all data). Chunks may be less than size bytes if the
953 to read all data). Chunks may be less than size bytes if the
954 chunk is the last chunk in the file, or the file is a socket or
954 chunk is the last chunk in the file, or the file is a socket or
955 some other type of file that sometimes reads less data than is
955 some other type of file that sometimes reads less data than is
956 requested."""
956 requested."""
957 assert size >= 0
957 assert size >= 0
958 assert limit is None or limit >= 0
958 assert limit is None or limit >= 0
959 while True:
959 while True:
960 if limit is None:
960 if limit is None:
961 nbytes = size
961 nbytes = size
962 else:
962 else:
963 nbytes = min(limit, size)
963 nbytes = min(limit, size)
964 s = nbytes and f.read(nbytes)
964 s = nbytes and f.read(nbytes)
965 if not s:
965 if not s:
966 break
966 break
967 if limit:
967 if limit:
968 limit -= len(s)
968 limit -= len(s)
969 yield s
969 yield s
970
970
971 def makedate():
971 def makedate():
972 lt = time.localtime()
972 lt = time.localtime()
973 if lt[8] == 1 and time.daylight:
973 if lt[8] == 1 and time.daylight:
974 tz = time.altzone
974 tz = time.altzone
975 else:
975 else:
976 tz = time.timezone
976 tz = time.timezone
977 return time.mktime(lt), tz
977 return time.mktime(lt), tz
978
978
979 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
979 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
980 """represent a (unixtime, offset) tuple as a localized time.
980 """represent a (unixtime, offset) tuple as a localized time.
981 unixtime is seconds since the epoch, and offset is the time zone's
981 unixtime is seconds since the epoch, and offset is the time zone's
982 number of seconds away from UTC. if timezone is false, do not
982 number of seconds away from UTC. if timezone is false, do not
983 append time zone to string."""
983 append time zone to string."""
984 t, tz = date or makedate()
984 t, tz = date or makedate()
985 if "%1" in format or "%2" in format:
985 if "%1" in format or "%2" in format:
986 sign = (tz > 0) and "-" or "+"
986 sign = (tz > 0) and "-" or "+"
987 minutes = abs(tz) // 60
987 minutes = abs(tz) // 60
988 format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
988 format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
989 format = format.replace("%2", "%02d" % (minutes % 60))
989 format = format.replace("%2", "%02d" % (minutes % 60))
990 s = time.strftime(format, time.gmtime(float(t) - tz))
990 s = time.strftime(format, time.gmtime(float(t) - tz))
991 return s
991 return s
992
992
993 def shortdate(date=None):
993 def shortdate(date=None):
994 """turn (timestamp, tzoff) tuple into iso 8631 date."""
994 """turn (timestamp, tzoff) tuple into iso 8631 date."""
995 return datestr(date, format='%Y-%m-%d')
995 return datestr(date, format='%Y-%m-%d')
996
996
997 def strdate(string, format, defaults=[]):
997 def strdate(string, format, defaults=[]):
998 """parse a localized time string and return a (unixtime, offset) tuple.
998 """parse a localized time string and return a (unixtime, offset) tuple.
999 if the string cannot be parsed, ValueError is raised."""
999 if the string cannot be parsed, ValueError is raised."""
1000 def timezone(string):
1000 def timezone(string):
1001 tz = string.split()[-1]
1001 tz = string.split()[-1]
1002 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1002 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1003 sign = (tz[0] == "+") and 1 or -1
1003 sign = (tz[0] == "+") and 1 or -1
1004 hours = int(tz[1:3])
1004 hours = int(tz[1:3])
1005 minutes = int(tz[3:5])
1005 minutes = int(tz[3:5])
1006 return -sign * (hours * 60 + minutes) * 60
1006 return -sign * (hours * 60 + minutes) * 60
1007 if tz == "GMT" or tz == "UTC":
1007 if tz == "GMT" or tz == "UTC":
1008 return 0
1008 return 0
1009 return None
1009 return None
1010
1010
1011 # NOTE: unixtime = localunixtime + offset
1011 # NOTE: unixtime = localunixtime + offset
1012 offset, date = timezone(string), string
1012 offset, date = timezone(string), string
1013 if offset != None:
1013 if offset != None:
1014 date = " ".join(string.split()[:-1])
1014 date = " ".join(string.split()[:-1])
1015
1015
1016 # add missing elements from defaults
1016 # add missing elements from defaults
1017 for part in defaults:
1017 for part in defaults:
1018 found = [True for p in part if ("%"+p) in format]
1018 found = [True for p in part if ("%"+p) in format]
1019 if not found:
1019 if not found:
1020 date += "@" + defaults[part]
1020 date += "@" + defaults[part]
1021 format += "@%" + part[0]
1021 format += "@%" + part[0]
1022
1022
1023 timetuple = time.strptime(date, format)
1023 timetuple = time.strptime(date, format)
1024 localunixtime = int(calendar.timegm(timetuple))
1024 localunixtime = int(calendar.timegm(timetuple))
1025 if offset is None:
1025 if offset is None:
1026 # local timezone
1026 # local timezone
1027 unixtime = int(time.mktime(timetuple))
1027 unixtime = int(time.mktime(timetuple))
1028 offset = unixtime - localunixtime
1028 offset = unixtime - localunixtime
1029 else:
1029 else:
1030 unixtime = localunixtime + offset
1030 unixtime = localunixtime + offset
1031 return unixtime, offset
1031 return unixtime, offset
1032
1032
1033 def parsedate(date, formats=None, defaults=None):
1033 def parsedate(date, formats=None, defaults=None):
1034 """parse a localized date/time string and return a (unixtime, offset) tuple.
1034 """parse a localized date/time string and return a (unixtime, offset) tuple.
1035
1035
1036 The date may be a "unixtime offset" string or in one of the specified
1036 The date may be a "unixtime offset" string or in one of the specified
1037 formats. If the date already is a (unixtime, offset) tuple, it is returned.
1037 formats. If the date already is a (unixtime, offset) tuple, it is returned.
1038 """
1038 """
1039 if not date:
1039 if not date:
1040 return 0, 0
1040 return 0, 0
1041 if isinstance(date, tuple) and len(date) == 2:
1041 if isinstance(date, tuple) and len(date) == 2:
1042 return date
1042 return date
1043 if not formats:
1043 if not formats:
1044 formats = defaultdateformats
1044 formats = defaultdateformats
1045 date = date.strip()
1045 date = date.strip()
1046 try:
1046 try:
1047 when, offset = map(int, date.split(' '))
1047 when, offset = map(int, date.split(' '))
1048 except ValueError:
1048 except ValueError:
1049 # fill out defaults
1049 # fill out defaults
1050 if not defaults:
1050 if not defaults:
1051 defaults = {}
1051 defaults = {}
1052 now = makedate()
1052 now = makedate()
1053 for part in "d mb yY HI M S".split():
1053 for part in "d mb yY HI M S".split():
1054 if part not in defaults:
1054 if part not in defaults:
1055 if part[0] in "HMS":
1055 if part[0] in "HMS":
1056 defaults[part] = "00"
1056 defaults[part] = "00"
1057 else:
1057 else:
1058 defaults[part] = datestr(now, "%" + part[0])
1058 defaults[part] = datestr(now, "%" + part[0])
1059
1059
1060 for format in formats:
1060 for format in formats:
1061 try:
1061 try:
1062 when, offset = strdate(date, format, defaults)
1062 when, offset = strdate(date, format, defaults)
1063 except (ValueError, OverflowError):
1063 except (ValueError, OverflowError):
1064 pass
1064 pass
1065 else:
1065 else:
1066 break
1066 break
1067 else:
1067 else:
1068 raise Abort(_('invalid date: %r') % date)
1068 raise Abort(_('invalid date: %r') % date)
1069 # validate explicit (probably user-specified) date and
1069 # validate explicit (probably user-specified) date and
1070 # time zone offset. values must fit in signed 32 bits for
1070 # time zone offset. values must fit in signed 32 bits for
1071 # current 32-bit linux runtimes. timezones go from UTC-12
1071 # current 32-bit linux runtimes. timezones go from UTC-12
1072 # to UTC+14
1072 # to UTC+14
1073 if abs(when) > 0x7fffffff:
1073 if abs(when) > 0x7fffffff:
1074 raise Abort(_('date exceeds 32 bits: %d') % when)
1074 raise Abort(_('date exceeds 32 bits: %d') % when)
1075 if offset < -50400 or offset > 43200:
1075 if offset < -50400 or offset > 43200:
1076 raise Abort(_('impossible time zone offset: %d') % offset)
1076 raise Abort(_('impossible time zone offset: %d') % offset)
1077 return when, offset
1077 return when, offset
1078
1078
1079 def matchdate(date):
1079 def matchdate(date):
1080 """Return a function that matches a given date match specifier
1080 """Return a function that matches a given date match specifier
1081
1081
1082 Formats include:
1082 Formats include:
1083
1083
1084 '{date}' match a given date to the accuracy provided
1084 '{date}' match a given date to the accuracy provided
1085
1085
1086 '<{date}' on or before a given date
1086 '<{date}' on or before a given date
1087
1087
1088 '>{date}' on or after a given date
1088 '>{date}' on or after a given date
1089
1089
1090 """
1090 """
1091
1091
1092 def lower(date):
1092 def lower(date):
1093 d = dict(mb="1", d="1")
1093 d = dict(mb="1", d="1")
1094 return parsedate(date, extendeddateformats, d)[0]
1094 return parsedate(date, extendeddateformats, d)[0]
1095
1095
1096 def upper(date):
1096 def upper(date):
1097 d = dict(mb="12", HI="23", M="59", S="59")
1097 d = dict(mb="12", HI="23", M="59", S="59")
1098 for days in "31 30 29".split():
1098 for days in "31 30 29".split():
1099 try:
1099 try:
1100 d["d"] = days
1100 d["d"] = days
1101 return parsedate(date, extendeddateformats, d)[0]
1101 return parsedate(date, extendeddateformats, d)[0]
1102 except:
1102 except:
1103 pass
1103 pass
1104 d["d"] = "28"
1104 d["d"] = "28"
1105 return parsedate(date, extendeddateformats, d)[0]
1105 return parsedate(date, extendeddateformats, d)[0]
1106
1106
1107 date = date.strip()
1107 date = date.strip()
1108 if date[0] == "<":
1108 if date[0] == "<":
1109 when = upper(date[1:])
1109 when = upper(date[1:])
1110 return lambda x: x <= when
1110 return lambda x: x <= when
1111 elif date[0] == ">":
1111 elif date[0] == ">":
1112 when = lower(date[1:])
1112 when = lower(date[1:])
1113 return lambda x: x >= when
1113 return lambda x: x >= when
1114 elif date[0] == "-":
1114 elif date[0] == "-":
1115 try:
1115 try:
1116 days = int(date[1:])
1116 days = int(date[1:])
1117 except ValueError:
1117 except ValueError:
1118 raise Abort(_("invalid day spec: %s") % date[1:])
1118 raise Abort(_("invalid day spec: %s") % date[1:])
1119 when = makedate()[0] - days * 3600 * 24
1119 when = makedate()[0] - days * 3600 * 24
1120 return lambda x: x >= when
1120 return lambda x: x >= when
1121 elif " to " in date:
1121 elif " to " in date:
1122 a, b = date.split(" to ")
1122 a, b = date.split(" to ")
1123 start, stop = lower(a), upper(b)
1123 start, stop = lower(a), upper(b)
1124 return lambda x: x >= start and x <= stop
1124 return lambda x: x >= start and x <= stop
1125 else:
1125 else:
1126 start, stop = lower(date), upper(date)
1126 start, stop = lower(date), upper(date)
1127 return lambda x: x >= start and x <= stop
1127 return lambda x: x >= start and x <= stop
1128
1128
1129 def shortuser(user):
1129 def shortuser(user):
1130 """Return a short representation of a user name or email address."""
1130 """Return a short representation of a user name or email address."""
1131 f = user.find('@')
1131 f = user.find('@')
1132 if f >= 0:
1132 if f >= 0:
1133 user = user[:f]
1133 user = user[:f]
1134 f = user.find('<')
1134 f = user.find('<')
1135 if f >= 0:
1135 if f >= 0:
1136 user = user[f + 1:]
1136 user = user[f + 1:]
1137 f = user.find(' ')
1137 f = user.find(' ')
1138 if f >= 0:
1138 if f >= 0:
1139 user = user[:f]
1139 user = user[:f]
1140 f = user.find('.')
1140 f = user.find('.')
1141 if f >= 0:
1141 if f >= 0:
1142 user = user[:f]
1142 user = user[:f]
1143 return user
1143 return user
1144
1144
1145 def email(author):
1145 def email(author):
1146 '''get email of author.'''
1146 '''get email of author.'''
1147 r = author.find('>')
1147 r = author.find('>')
1148 if r == -1:
1148 if r == -1:
1149 r = None
1149 r = None
1150 return author[author.find('<') + 1:r]
1150 return author[author.find('<') + 1:r]
1151
1151
1152 def ellipsis(text, maxlength=400):
1152 def ellipsis(text, maxlength=400):
1153 """Trim string to at most maxlength (default: 400) characters."""
1153 """Trim string to at most maxlength (default: 400) characters."""
1154 if len(text) <= maxlength:
1154 if len(text) <= maxlength:
1155 return text
1155 return text
1156 else:
1156 else:
1157 return "%s..." % (text[:maxlength - 3])
1157 return "%s..." % (text[:maxlength - 3])
1158
1158
1159 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
1159 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
1160 '''yield every hg repository under path, recursively.'''
1160 '''yield every hg repository under path, recursively.'''
1161 def errhandler(err):
1161 def errhandler(err):
1162 if err.filename == path:
1162 if err.filename == path:
1163 raise err
1163 raise err
1164 if followsym and hasattr(os.path, 'samestat'):
1164 if followsym and hasattr(os.path, 'samestat'):
1165 def _add_dir_if_not_there(dirlst, dirname):
1165 def _add_dir_if_not_there(dirlst, dirname):
1166 match = False
1166 match = False
1167 samestat = os.path.samestat
1167 samestat = os.path.samestat
1168 dirstat = os.stat(dirname)
1168 dirstat = os.stat(dirname)
1169 for lstdirstat in dirlst:
1169 for lstdirstat in dirlst:
1170 if samestat(dirstat, lstdirstat):
1170 if samestat(dirstat, lstdirstat):
1171 match = True
1171 match = True
1172 break
1172 break
1173 if not match:
1173 if not match:
1174 dirlst.append(dirstat)
1174 dirlst.append(dirstat)
1175 return not match
1175 return not match
1176 else:
1176 else:
1177 followsym = False
1177 followsym = False
1178
1178
1179 if (seen_dirs is None) and followsym:
1179 if (seen_dirs is None) and followsym:
1180 seen_dirs = []
1180 seen_dirs = []
1181 _add_dir_if_not_there(seen_dirs, path)
1181 _add_dir_if_not_there(seen_dirs, path)
1182 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
1182 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
1183 dirs.sort()
1183 dirs.sort()
1184 if '.hg' in dirs:
1184 if '.hg' in dirs:
1185 yield root # found a repository
1185 yield root # found a repository
1186 qroot = os.path.join(root, '.hg', 'patches')
1186 qroot = os.path.join(root, '.hg', 'patches')
1187 if os.path.isdir(os.path.join(qroot, '.hg')):
1187 if os.path.isdir(os.path.join(qroot, '.hg')):
1188 yield qroot # we have a patch queue repo here
1188 yield qroot # we have a patch queue repo here
1189 if recurse:
1189 if recurse:
1190 # avoid recursing inside the .hg directory
1190 # avoid recursing inside the .hg directory
1191 dirs.remove('.hg')
1191 dirs.remove('.hg')
1192 else:
1192 else:
1193 dirs[:] = [] # don't descend further
1193 dirs[:] = [] # don't descend further
1194 elif followsym:
1194 elif followsym:
1195 newdirs = []
1195 newdirs = []
1196 for d in dirs:
1196 for d in dirs:
1197 fname = os.path.join(root, d)
1197 fname = os.path.join(root, d)
1198 if _add_dir_if_not_there(seen_dirs, fname):
1198 if _add_dir_if_not_there(seen_dirs, fname):
1199 if os.path.islink(fname):
1199 if os.path.islink(fname):
1200 for hgname in walkrepos(fname, True, seen_dirs):
1200 for hgname in walkrepos(fname, True, seen_dirs):
1201 yield hgname
1201 yield hgname
1202 else:
1202 else:
1203 newdirs.append(d)
1203 newdirs.append(d)
1204 dirs[:] = newdirs
1204 dirs[:] = newdirs
1205
1205
1206 _rcpath = None
1206 _rcpath = None
1207
1207
1208 def os_rcpath():
1208 def os_rcpath():
1209 '''return default os-specific hgrc search path'''
1209 '''return default os-specific hgrc search path'''
1210 path = system_rcpath()
1210 path = system_rcpath()
1211 path.extend(user_rcpath())
1211 path.extend(user_rcpath())
1212 path = [os.path.normpath(f) for f in path]
1212 path = [os.path.normpath(f) for f in path]
1213 return path
1213 return path
1214
1214
1215 def rcpath():
1215 def rcpath():
1216 '''return hgrc search path. if env var HGRCPATH is set, use it.
1216 '''return hgrc search path. if env var HGRCPATH is set, use it.
1217 for each item in path, if directory, use files ending in .rc,
1217 for each item in path, if directory, use files ending in .rc,
1218 else use item.
1218 else use item.
1219 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1219 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1220 if no HGRCPATH, use default os-specific path.'''
1220 if no HGRCPATH, use default os-specific path.'''
1221 global _rcpath
1221 global _rcpath
1222 if _rcpath is None:
1222 if _rcpath is None:
1223 if 'HGRCPATH' in os.environ:
1223 if 'HGRCPATH' in os.environ:
1224 _rcpath = []
1224 _rcpath = []
1225 for p in os.environ['HGRCPATH'].split(os.pathsep):
1225 for p in os.environ['HGRCPATH'].split(os.pathsep):
1226 if not p:
1226 if not p:
1227 continue
1227 continue
1228 p = expandpath(p)
1228 p = expandpath(p)
1229 if os.path.isdir(p):
1229 if os.path.isdir(p):
1230 for f, kind in osutil.listdir(p):
1230 for f, kind in osutil.listdir(p):
1231 if f.endswith('.rc'):
1231 if f.endswith('.rc'):
1232 _rcpath.append(os.path.join(p, f))
1232 _rcpath.append(os.path.join(p, f))
1233 else:
1233 else:
1234 _rcpath.append(p)
1234 _rcpath.append(p)
1235 else:
1235 else:
1236 _rcpath = os_rcpath()
1236 _rcpath = os_rcpath()
1237 return _rcpath
1237 return _rcpath
1238
1238
1239 def bytecount(nbytes):
1239 def bytecount(nbytes):
1240 '''return byte count formatted as readable string, with units'''
1240 '''return byte count formatted as readable string, with units'''
1241
1241
1242 units = (
1242 units = (
1243 (100, 1 << 30, _('%.0f GB')),
1243 (100, 1 << 30, _('%.0f GB')),
1244 (10, 1 << 30, _('%.1f GB')),
1244 (10, 1 << 30, _('%.1f GB')),
1245 (1, 1 << 30, _('%.2f GB')),
1245 (1, 1 << 30, _('%.2f GB')),
1246 (100, 1 << 20, _('%.0f MB')),
1246 (100, 1 << 20, _('%.0f MB')),
1247 (10, 1 << 20, _('%.1f MB')),
1247 (10, 1 << 20, _('%.1f MB')),
1248 (1, 1 << 20, _('%.2f MB')),
1248 (1, 1 << 20, _('%.2f MB')),
1249 (100, 1 << 10, _('%.0f KB')),
1249 (100, 1 << 10, _('%.0f KB')),
1250 (10, 1 << 10, _('%.1f KB')),
1250 (10, 1 << 10, _('%.1f KB')),
1251 (1, 1 << 10, _('%.2f KB')),
1251 (1, 1 << 10, _('%.2f KB')),
1252 (1, 1, _('%.0f bytes')),
1252 (1, 1, _('%.0f bytes')),
1253 )
1253 )
1254
1254
1255 for multiplier, divisor, format in units:
1255 for multiplier, divisor, format in units:
1256 if nbytes >= divisor * multiplier:
1256 if nbytes >= divisor * multiplier:
1257 return format % (nbytes / float(divisor))
1257 return format % (nbytes / float(divisor))
1258 return units[-1][2] % nbytes
1258 return units[-1][2] % nbytes
1259
1259
1260 def drop_scheme(scheme, path):
1260 def drop_scheme(scheme, path):
1261 sc = scheme + ':'
1261 sc = scheme + ':'
1262 if path.startswith(sc):
1262 if path.startswith(sc):
1263 path = path[len(sc):]
1263 path = path[len(sc):]
1264 if path.startswith('//'):
1264 if path.startswith('//'):
1265 if scheme == 'file':
1265 if scheme == 'file':
1266 i = path.find('/', 2)
1266 i = path.find('/', 2)
1267 if i == -1:
1267 if i == -1:
1268 return ''
1268 return ''
1269 # On Windows, absolute paths are rooted at the current drive
1269 # On Windows, absolute paths are rooted at the current drive
1270 # root. On POSIX they are rooted at the file system root.
1270 # root. On POSIX they are rooted at the file system root.
1271 if os.name == 'nt':
1271 if os.name == 'nt':
1272 droot = os.path.splitdrive(os.getcwd())[0] + '/'
1272 droot = os.path.splitdrive(os.getcwd())[0] + '/'
1273 path = os.path.join(droot, path[i + 1:])
1273 path = os.path.join(droot, path[i + 1:])
1274 else:
1274 else:
1275 path = path[i:]
1275 path = path[i:]
1276 else:
1276 else:
1277 path = path[2:]
1277 path = path[2:]
1278 return path
1278 return path
1279
1279
1280 def uirepr(s):
1280 def uirepr(s):
1281 # Avoid double backslash in Windows path repr()
1281 # Avoid double backslash in Windows path repr()
1282 return repr(s).replace('\\\\', '\\')
1282 return repr(s).replace('\\\\', '\\')
1283
1283
1284 #### naming convention of below implementation follows 'textwrap' module
1284 #### naming convention of below implementation follows 'textwrap' module
1285
1285
1286 class MBTextWrapper(textwrap.TextWrapper):
1286 class MBTextWrapper(textwrap.TextWrapper):
1287 def __init__(self, **kwargs):
1287 def __init__(self, **kwargs):
1288 textwrap.TextWrapper.__init__(self, **kwargs)
1288 textwrap.TextWrapper.__init__(self, **kwargs)
1289
1289
1290 def _cutdown(self, str, space_left):
1290 def _cutdown(self, str, space_left):
1291 l = 0
1291 l = 0
1292 ucstr = unicode(str, encoding.encoding)
1292 ucstr = unicode(str, encoding.encoding)
1293 w = unicodedata.east_asian_width
1293 w = unicodedata.east_asian_width
1294 for i in xrange(len(ucstr)):
1294 for i in xrange(len(ucstr)):
1295 l += w(ucstr[i]) in 'WFA' and 2 or 1
1295 l += w(ucstr[i]) in 'WFA' and 2 or 1
1296 if space_left < l:
1296 if space_left < l:
1297 return (ucstr[:i].encode(encoding.encoding),
1297 return (ucstr[:i].encode(encoding.encoding),
1298 ucstr[i:].encode(encoding.encoding))
1298 ucstr[i:].encode(encoding.encoding))
1299 return str, ''
1299 return str, ''
1300
1300
1301 # ----------------------------------------
1301 # ----------------------------------------
1302 # overriding of base class
1302 # overriding of base class
1303
1303
1304 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
1304 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
1305 space_left = max(width - cur_len, 1)
1305 space_left = max(width - cur_len, 1)
1306
1306
1307 if self.break_long_words:
1307 if self.break_long_words:
1308 cut, res = self._cutdown(reversed_chunks[-1], space_left)
1308 cut, res = self._cutdown(reversed_chunks[-1], space_left)
1309 cur_line.append(cut)
1309 cur_line.append(cut)
1310 reversed_chunks[-1] = res
1310 reversed_chunks[-1] = res
1311 elif not cur_line:
1311 elif not cur_line:
1312 cur_line.append(reversed_chunks.pop())
1312 cur_line.append(reversed_chunks.pop())
1313
1313
1314 #### naming convention of above implementation follows 'textwrap' module
1314 #### naming convention of above implementation follows 'textwrap' module
1315
1315
1316 def wrap(line, width=None, initindent='', hangindent=''):
1316 def wrap(line, width, initindent='', hangindent=''):
1317 if width is None:
1318 width = termwidth() - 2
1319 maxindent = max(len(hangindent), len(initindent))
1317 maxindent = max(len(hangindent), len(initindent))
1320 if width <= maxindent:
1318 if width <= maxindent:
1321 # adjust for weird terminal size
1319 # adjust for weird terminal size
1322 width = max(78, maxindent + 1)
1320 width = max(78, maxindent + 1)
1323 wrapper = MBTextWrapper(width=width,
1321 wrapper = MBTextWrapper(width=width,
1324 initial_indent=initindent,
1322 initial_indent=initindent,
1325 subsequent_indent=hangindent)
1323 subsequent_indent=hangindent)
1326 return wrapper.fill(line)
1324 return wrapper.fill(line)
1327
1325
1328 def iterlines(iterator):
1326 def iterlines(iterator):
1329 for chunk in iterator:
1327 for chunk in iterator:
1330 for line in chunk.splitlines():
1328 for line in chunk.splitlines():
1331 yield line
1329 yield line
1332
1330
1333 def expandpath(path):
1331 def expandpath(path):
1334 return os.path.expanduser(os.path.expandvars(path))
1332 return os.path.expanduser(os.path.expandvars(path))
1335
1333
1336 def hgcmd():
1334 def hgcmd():
1337 """Return the command used to execute current hg
1335 """Return the command used to execute current hg
1338
1336
1339 This is different from hgexecutable() because on Windows we want
1337 This is different from hgexecutable() because on Windows we want
1340 to avoid things opening new shell windows like batch files, so we
1338 to avoid things opening new shell windows like batch files, so we
1341 get either the python call or current executable.
1339 get either the python call or current executable.
1342 """
1340 """
1343 if main_is_frozen():
1341 if main_is_frozen():
1344 return [sys.executable]
1342 return [sys.executable]
1345 return gethgcmd()
1343 return gethgcmd()
1346
1344
1347 def rundetached(args, condfn):
1345 def rundetached(args, condfn):
1348 """Execute the argument list in a detached process.
1346 """Execute the argument list in a detached process.
1349
1347
1350 condfn is a callable which is called repeatedly and should return
1348 condfn is a callable which is called repeatedly and should return
1351 True once the child process is known to have started successfully.
1349 True once the child process is known to have started successfully.
1352 At this point, the child process PID is returned. If the child
1350 At this point, the child process PID is returned. If the child
1353 process fails to start or finishes before condfn() evaluates to
1351 process fails to start or finishes before condfn() evaluates to
1354 True, return -1.
1352 True, return -1.
1355 """
1353 """
1356 # Windows case is easier because the child process is either
1354 # Windows case is easier because the child process is either
1357 # successfully starting and validating the condition or exiting
1355 # successfully starting and validating the condition or exiting
1358 # on failure. We just poll on its PID. On Unix, if the child
1356 # on failure. We just poll on its PID. On Unix, if the child
1359 # process fails to start, it will be left in a zombie state until
1357 # process fails to start, it will be left in a zombie state until
1360 # the parent wait on it, which we cannot do since we expect a long
1358 # the parent wait on it, which we cannot do since we expect a long
1361 # running process on success. Instead we listen for SIGCHLD telling
1359 # running process on success. Instead we listen for SIGCHLD telling
1362 # us our child process terminated.
1360 # us our child process terminated.
1363 terminated = set()
1361 terminated = set()
1364 def handler(signum, frame):
1362 def handler(signum, frame):
1365 terminated.add(os.wait())
1363 terminated.add(os.wait())
1366 prevhandler = None
1364 prevhandler = None
1367 if hasattr(signal, 'SIGCHLD'):
1365 if hasattr(signal, 'SIGCHLD'):
1368 prevhandler = signal.signal(signal.SIGCHLD, handler)
1366 prevhandler = signal.signal(signal.SIGCHLD, handler)
1369 try:
1367 try:
1370 pid = spawndetached(args)
1368 pid = spawndetached(args)
1371 while not condfn():
1369 while not condfn():
1372 if ((pid in terminated or not testpid(pid))
1370 if ((pid in terminated or not testpid(pid))
1373 and not condfn()):
1371 and not condfn()):
1374 return -1
1372 return -1
1375 time.sleep(0.1)
1373 time.sleep(0.1)
1376 return pid
1374 return pid
1377 finally:
1375 finally:
1378 if prevhandler is not None:
1376 if prevhandler is not None:
1379 signal.signal(signal.SIGCHLD, prevhandler)
1377 signal.signal(signal.SIGCHLD, prevhandler)
1380
1378
1381 try:
1379 try:
1382 any, all = any, all
1380 any, all = any, all
1383 except NameError:
1381 except NameError:
1384 def any(iterable):
1382 def any(iterable):
1385 for i in iterable:
1383 for i in iterable:
1386 if i:
1384 if i:
1387 return True
1385 return True
1388 return False
1386 return False
1389
1387
1390 def all(iterable):
1388 def all(iterable):
1391 for i in iterable:
1389 for i in iterable:
1392 if not i:
1390 if not i:
1393 return False
1391 return False
1394 return True
1392 return True
1395
1393
1396 def interpolate(prefix, mapping, s, fn=None):
1394 def interpolate(prefix, mapping, s, fn=None):
1397 """Return the result of interpolating items in the mapping into string s.
1395 """Return the result of interpolating items in the mapping into string s.
1398
1396
1399 prefix is a single character string, or a two character string with
1397 prefix is a single character string, or a two character string with
1400 a backslash as the first character if the prefix needs to be escaped in
1398 a backslash as the first character if the prefix needs to be escaped in
1401 a regular expression.
1399 a regular expression.
1402
1400
1403 fn is an optional function that will be applied to the replacement text
1401 fn is an optional function that will be applied to the replacement text
1404 just before replacement.
1402 just before replacement.
1405 """
1403 """
1406 fn = fn or (lambda s: s)
1404 fn = fn or (lambda s: s)
1407 r = re.compile(r'%s(%s)' % (prefix, '|'.join(mapping.keys())))
1405 r = re.compile(r'%s(%s)' % (prefix, '|'.join(mapping.keys())))
1408 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
1406 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
1409
1407
1410 def getport(port):
1408 def getport(port):
1411 """Return the port for a given network service.
1409 """Return the port for a given network service.
1412
1410
1413 If port is an integer, it's returned as is. If it's a string, it's
1411 If port is an integer, it's returned as is. If it's a string, it's
1414 looked up using socket.getservbyname(). If there's no matching
1412 looked up using socket.getservbyname(). If there's no matching
1415 service, util.Abort is raised.
1413 service, util.Abort is raised.
1416 """
1414 """
1417 try:
1415 try:
1418 return int(port)
1416 return int(port)
1419 except ValueError:
1417 except ValueError:
1420 pass
1418 pass
1421
1419
1422 try:
1420 try:
1423 return socket.getservbyname(port)
1421 return socket.getservbyname(port)
1424 except socket.error:
1422 except socket.error:
1425 raise Abort(_("no port number associated with service '%s'") % port)
1423 raise Abort(_("no port number associated with service '%s'") % port)
1426
1424
1427 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1425 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1428 '0': False, 'no': False, 'false': False, 'off': False,
1426 '0': False, 'no': False, 'false': False, 'off': False,
1429 'never': False}
1427 'never': False}
1430
1428
1431 def parsebool(s):
1429 def parsebool(s):
1432 """Parse s into a boolean.
1430 """Parse s into a boolean.
1433
1431
1434 If s is not a valid boolean, returns None.
1432 If s is not a valid boolean, returns None.
1435 """
1433 """
1436 return _booleans.get(s.lower(), None)
1434 return _booleans.get(s.lower(), None)
General Comments 0
You need to be logged in to leave comments. Login now