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