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