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