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