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