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