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