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