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