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