##// END OF EJS Templates
fix use of python 2.4 features.
Vadim Gelfer -
r1937:3f6be77e 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 (AttributeError, ValueError):
417 vargs.update([(name, v)])
417 try:
418 for a, b in v:
419 vargs[a] = b
420 except ValueError:
421 vargs[name] = v
418 return self.t(tag, **vargs)
422 return self.t(tag, **vargs)
419 lastname = 'last_' + name
423 lastname = 'last_' + name
420 if lastname in self.t:
424 if lastname in self.t:
421 last = values.pop()
425 last = values.pop()
422 else:
426 else:
423 last = None
427 last = None
424 for v in values:
428 for v in values:
425 yield one(v)
429 yield one(v)
426 if last is not None:
430 if last is not None:
427 yield one(last, tag=lastname)
431 yield one(last, tag=lastname)
428 endname = 'end_' + names
432 endname = 'end_' + names
429 if endname in self.t:
433 if endname in self.t:
430 yield self.t(endname, **args)
434 yield self.t(endname, **args)
431
435
432 if brinfo:
436 if brinfo:
433 def showbranches(**args):
437 def showbranches(**args):
434 if changenode in brinfo:
438 if changenode in brinfo:
435 for x in showlist('branch', brinfo[changenode],
439 for x in showlist('branch', brinfo[changenode],
436 plural='branches', **args):
440 plural='branches', **args):
437 yield x
441 yield x
438 else:
442 else:
439 showbranches = ''
443 showbranches = ''
440
444
441 if self.ui.debugflag:
445 if self.ui.debugflag:
442 def showmanifest(**args):
446 def showmanifest(**args):
443 args = args.copy()
447 args = args.copy()
444 args.update(rev=self.repo.manifest.rev(changes[0]),
448 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
445 node=hex(changes[0]))
449 node=hex(changes[0])))
446 yield self.t('manifest', **args)
450 yield self.t('manifest', **args)
447 else:
451 else:
448 showmanifest = ''
452 showmanifest = ''
449
453
450 def showparents(**args):
454 def showparents(**args):
451 parents = [[('rev', log.rev(p)), ('node', hex(p))]
455 parents = [[('rev', log.rev(p)), ('node', hex(p))]
452 for p in log.parents(changenode)
456 for p in log.parents(changenode)
453 if self.ui.debugflag or p != nullid]
457 if self.ui.debugflag or p != nullid]
454 if (not self.ui.debugflag and len(parents) == 1 and
458 if (not self.ui.debugflag and len(parents) == 1 and
455 parents[0][0][1] == rev - 1):
459 parents[0][0][1] == rev - 1):
456 return
460 return
457 for x in showlist('parent', parents, **args):
461 for x in showlist('parent', parents, **args):
458 yield x
462 yield x
459
463
460 def showtags(**args):
464 def showtags(**args):
461 for x in showlist('tag', self.repo.nodetags(changenode), **args):
465 for x in showlist('tag', self.repo.nodetags(changenode), **args):
462 yield x
466 yield x
463
467
464 if self.ui.debugflag:
468 if self.ui.debugflag:
465 files = self.repo.changes(log.parents(changenode)[0], changenode)
469 files = self.repo.changes(log.parents(changenode)[0], changenode)
466 def showfiles(**args):
470 def showfiles(**args):
467 for x in showlist('file', files[0], **args): yield x
471 for x in showlist('file', files[0], **args): yield x
468 def showadds(**args):
472 def showadds(**args):
469 for x in showlist('file_add', files[1], **args): yield x
473 for x in showlist('file_add', files[1], **args): yield x
470 def showdels(**args):
474 def showdels(**args):
471 for x in showlist('file_del', files[2], **args): yield x
475 for x in showlist('file_del', files[2], **args): yield x
472 else:
476 else:
473 def showfiles(**args):
477 def showfiles(**args):
474 for x in showlist('file', changes[3], **args): yield x
478 for x in showlist('file', changes[3], **args): yield x
475 showadds = ''
479 showadds = ''
476 showdels = ''
480 showdels = ''
477
481
478 props = {
482 props = {
479 'author': changes[1],
483 'author': changes[1],
480 'branches': showbranches,
484 'branches': showbranches,
481 'date': changes[2],
485 'date': changes[2],
482 'desc': changes[4],
486 'desc': changes[4],
483 'file_adds': showadds,
487 'file_adds': showadds,
484 'file_dels': showdels,
488 'file_dels': showdels,
485 'files': showfiles,
489 'files': showfiles,
486 'manifest': showmanifest,
490 'manifest': showmanifest,
487 'node': hex(changenode),
491 'node': hex(changenode),
488 'parents': showparents,
492 'parents': showparents,
489 'rev': rev,
493 'rev': rev,
490 'tags': showtags,
494 'tags': showtags,
491 }
495 }
492
496
493 try:
497 try:
494 if self.ui.debugflag and 'changeset_debug' in self.t:
498 if self.ui.debugflag and 'changeset_debug' in self.t:
495 key = 'changeset_debug'
499 key = 'changeset_debug'
496 elif self.ui.quiet and 'changeset_quiet' in self.t:
500 elif self.ui.quiet and 'changeset_quiet' in self.t:
497 key = 'changeset_quiet'
501 key = 'changeset_quiet'
498 elif self.ui.verbose and 'changeset_verbose' in self.t:
502 elif self.ui.verbose and 'changeset_verbose' in self.t:
499 key = 'changeset_verbose'
503 key = 'changeset_verbose'
500 else:
504 else:
501 key = 'changeset'
505 key = 'changeset'
502 self.write(self.t(key, **props))
506 self.write(self.t(key, **props))
503 except KeyError, inst:
507 except KeyError, inst:
504 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
508 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
505 inst.args[0]))
509 inst.args[0]))
506 except SyntaxError, inst:
510 except SyntaxError, inst:
507 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
511 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
508
512
509 class changeset_printer(object):
513 class changeset_printer(object):
510 '''show changeset information when templating not requested.'''
514 '''show changeset information when templating not requested.'''
511
515
512 def __init__(self, ui, repo):
516 def __init__(self, ui, repo):
513 self.ui = ui
517 self.ui = ui
514 self.repo = repo
518 self.repo = repo
515
519
516 def show(self, rev=0, changenode=None, brinfo=None):
520 def show(self, rev=0, changenode=None, brinfo=None):
517 '''show a single changeset or file revision'''
521 '''show a single changeset or file revision'''
518 log = self.repo.changelog
522 log = self.repo.changelog
519 if changenode is None:
523 if changenode is None:
520 changenode = log.node(rev)
524 changenode = log.node(rev)
521 elif not rev:
525 elif not rev:
522 rev = log.rev(changenode)
526 rev = log.rev(changenode)
523
527
524 if self.ui.quiet:
528 if self.ui.quiet:
525 self.ui.write("%d:%s\n" % (rev, short(changenode)))
529 self.ui.write("%d:%s\n" % (rev, short(changenode)))
526 return
530 return
527
531
528 changes = log.read(changenode)
532 changes = log.read(changenode)
529 date = util.datestr(changes[2])
533 date = util.datestr(changes[2])
530
534
531 parents = [(log.rev(p), self.ui.verbose and hex(p) or short(p))
535 parents = [(log.rev(p), self.ui.verbose and hex(p) or short(p))
532 for p in log.parents(changenode)
536 for p in log.parents(changenode)
533 if self.ui.debugflag or p != nullid]
537 if self.ui.debugflag or p != nullid]
534 if (not self.ui.debugflag and len(parents) == 1 and
538 if (not self.ui.debugflag and len(parents) == 1 and
535 parents[0][0] == rev-1):
539 parents[0][0] == rev-1):
536 parents = []
540 parents = []
537
541
538 if self.ui.verbose:
542 if self.ui.verbose:
539 self.ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
543 self.ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
540 else:
544 else:
541 self.ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
545 self.ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
542
546
543 for tag in self.repo.nodetags(changenode):
547 for tag in self.repo.nodetags(changenode):
544 self.ui.status(_("tag: %s\n") % tag)
548 self.ui.status(_("tag: %s\n") % tag)
545 for parent in parents:
549 for parent in parents:
546 self.ui.write(_("parent: %d:%s\n") % parent)
550 self.ui.write(_("parent: %d:%s\n") % parent)
547
551
548 if brinfo and changenode in brinfo:
552 if brinfo and changenode in brinfo:
549 br = brinfo[changenode]
553 br = brinfo[changenode]
550 self.ui.write(_("branch: %s\n") % " ".join(br))
554 self.ui.write(_("branch: %s\n") % " ".join(br))
551
555
552 self.ui.debug(_("manifest: %d:%s\n") %
556 self.ui.debug(_("manifest: %d:%s\n") %
553 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
557 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
554 self.ui.status(_("user: %s\n") % changes[1])
558 self.ui.status(_("user: %s\n") % changes[1])
555 self.ui.status(_("date: %s\n") % date)
559 self.ui.status(_("date: %s\n") % date)
556
560
557 if self.ui.debugflag:
561 if self.ui.debugflag:
558 files = self.repo.changes(log.parents(changenode)[0], changenode)
562 files = self.repo.changes(log.parents(changenode)[0], changenode)
559 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
563 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
560 files):
564 files):
561 if value:
565 if value:
562 self.ui.note("%-12s %s\n" % (key, " ".join(value)))
566 self.ui.note("%-12s %s\n" % (key, " ".join(value)))
563 else:
567 else:
564 self.ui.note(_("files: %s\n") % " ".join(changes[3]))
568 self.ui.note(_("files: %s\n") % " ".join(changes[3]))
565
569
566 description = changes[4].strip()
570 description = changes[4].strip()
567 if description:
571 if description:
568 if self.ui.verbose:
572 if self.ui.verbose:
569 self.ui.status(_("description:\n"))
573 self.ui.status(_("description:\n"))
570 self.ui.status(description)
574 self.ui.status(description)
571 self.ui.status("\n\n")
575 self.ui.status("\n\n")
572 else:
576 else:
573 self.ui.status(_("summary: %s\n") %
577 self.ui.status(_("summary: %s\n") %
574 description.splitlines()[0])
578 description.splitlines()[0])
575 self.ui.status("\n")
579 self.ui.status("\n")
576
580
577 def show_changeset(ui, repo, opts):
581 def show_changeset(ui, repo, opts):
578 '''show one changeset. uses template or regular display. caller
582 '''show one changeset. uses template or regular display. caller
579 can pass in 'style' and 'template' options in opts.'''
583 can pass in 'style' and 'template' options in opts.'''
580
584
581 tmpl = opts.get('template')
585 tmpl = opts.get('template')
582 if tmpl:
586 if tmpl:
583 tmpl = templater.parsestring(tmpl, quoted=False)
587 tmpl = templater.parsestring(tmpl, quoted=False)
584 else:
588 else:
585 tmpl = ui.config('ui', 'logtemplate')
589 tmpl = ui.config('ui', 'logtemplate')
586 if tmpl: tmpl = templater.parsestring(tmpl)
590 if tmpl: tmpl = templater.parsestring(tmpl)
587 mapfile = opts.get('style') or ui.config('ui', 'style')
591 mapfile = opts.get('style') or ui.config('ui', 'style')
588 if tmpl or mapfile:
592 if tmpl or mapfile:
589 if mapfile:
593 if mapfile:
590 if not os.path.isfile(mapfile):
594 if not os.path.isfile(mapfile):
591 mapname = templater.templatepath('map-cmdline.' + mapfile)
595 mapname = templater.templatepath('map-cmdline.' + mapfile)
592 if not mapname: mapname = templater.templatepath(mapfile)
596 if not mapname: mapname = templater.templatepath(mapfile)
593 if mapname: mapfile = mapname
597 if mapname: mapfile = mapname
594 try:
598 try:
595 t = changeset_templater(ui, repo, mapfile)
599 t = changeset_templater(ui, repo, mapfile)
596 except SyntaxError, inst:
600 except SyntaxError, inst:
597 raise util.Abort(inst.args[0])
601 raise util.Abort(inst.args[0])
598 if tmpl: t.use_template(tmpl)
602 if tmpl: t.use_template(tmpl)
599 return t
603 return t
600 return changeset_printer(ui, repo)
604 return changeset_printer(ui, repo)
601
605
602 def show_version(ui):
606 def show_version(ui):
603 """output version and copyright information"""
607 """output version and copyright information"""
604 ui.write(_("Mercurial Distributed SCM (version %s)\n")
608 ui.write(_("Mercurial Distributed SCM (version %s)\n")
605 % version.get_version())
609 % version.get_version())
606 ui.status(_(
610 ui.status(_(
607 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
611 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
608 "This is free software; see the source for copying conditions. "
612 "This is free software; see the source for copying conditions. "
609 "There is NO\nwarranty; "
613 "There is NO\nwarranty; "
610 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
614 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
611 ))
615 ))
612
616
613 def help_(ui, cmd=None, with_version=False):
617 def help_(ui, cmd=None, with_version=False):
614 """show help for a given command or all commands"""
618 """show help for a given command or all commands"""
615 option_lists = []
619 option_lists = []
616 if cmd and cmd != 'shortlist':
620 if cmd and cmd != 'shortlist':
617 if with_version:
621 if with_version:
618 show_version(ui)
622 show_version(ui)
619 ui.write('\n')
623 ui.write('\n')
620 aliases, i = find(cmd)
624 aliases, i = find(cmd)
621 # synopsis
625 # synopsis
622 ui.write("%s\n\n" % i[2])
626 ui.write("%s\n\n" % i[2])
623
627
624 # description
628 # description
625 doc = i[0].__doc__
629 doc = i[0].__doc__
626 if not doc:
630 if not doc:
627 doc = _("(No help text available)")
631 doc = _("(No help text available)")
628 if ui.quiet:
632 if ui.quiet:
629 doc = doc.splitlines(0)[0]
633 doc = doc.splitlines(0)[0]
630 ui.write("%s\n" % doc.rstrip())
634 ui.write("%s\n" % doc.rstrip())
631
635
632 if not ui.quiet:
636 if not ui.quiet:
633 # aliases
637 # aliases
634 if len(aliases) > 1:
638 if len(aliases) > 1:
635 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
639 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
636
640
637 # options
641 # options
638 if i[1]:
642 if i[1]:
639 option_lists.append(("options", i[1]))
643 option_lists.append(("options", i[1]))
640
644
641 else:
645 else:
642 # program name
646 # program name
643 if ui.verbose or with_version:
647 if ui.verbose or with_version:
644 show_version(ui)
648 show_version(ui)
645 else:
649 else:
646 ui.status(_("Mercurial Distributed SCM\n"))
650 ui.status(_("Mercurial Distributed SCM\n"))
647 ui.status('\n')
651 ui.status('\n')
648
652
649 # list of commands
653 # list of commands
650 if cmd == "shortlist":
654 if cmd == "shortlist":
651 ui.status(_('basic commands (use "hg help" '
655 ui.status(_('basic commands (use "hg help" '
652 'for the full list or option "-v" for details):\n\n'))
656 'for the full list or option "-v" for details):\n\n'))
653 elif ui.verbose:
657 elif ui.verbose:
654 ui.status(_('list of commands:\n\n'))
658 ui.status(_('list of commands:\n\n'))
655 else:
659 else:
656 ui.status(_('list of commands (use "hg help -v" '
660 ui.status(_('list of commands (use "hg help -v" '
657 'to show aliases and global options):\n\n'))
661 'to show aliases and global options):\n\n'))
658
662
659 h = {}
663 h = {}
660 cmds = {}
664 cmds = {}
661 for c, e in table.items():
665 for c, e in table.items():
662 f = c.split("|")[0]
666 f = c.split("|")[0]
663 if cmd == "shortlist" and not f.startswith("^"):
667 if cmd == "shortlist" and not f.startswith("^"):
664 continue
668 continue
665 f = f.lstrip("^")
669 f = f.lstrip("^")
666 if not ui.debugflag and f.startswith("debug"):
670 if not ui.debugflag and f.startswith("debug"):
667 continue
671 continue
668 doc = e[0].__doc__
672 doc = e[0].__doc__
669 if not doc:
673 if not doc:
670 doc = _("(No help text available)")
674 doc = _("(No help text available)")
671 h[f] = doc.splitlines(0)[0].rstrip()
675 h[f] = doc.splitlines(0)[0].rstrip()
672 cmds[f] = c.lstrip("^")
676 cmds[f] = c.lstrip("^")
673
677
674 fns = h.keys()
678 fns = h.keys()
675 fns.sort()
679 fns.sort()
676 m = max(map(len, fns))
680 m = max(map(len, fns))
677 for f in fns:
681 for f in fns:
678 if ui.verbose:
682 if ui.verbose:
679 commands = cmds[f].replace("|",", ")
683 commands = cmds[f].replace("|",", ")
680 ui.write(" %s:\n %s\n"%(commands, h[f]))
684 ui.write(" %s:\n %s\n"%(commands, h[f]))
681 else:
685 else:
682 ui.write(' %-*s %s\n' % (m, f, h[f]))
686 ui.write(' %-*s %s\n' % (m, f, h[f]))
683
687
684 # global options
688 # global options
685 if ui.verbose:
689 if ui.verbose:
686 option_lists.append(("global options", globalopts))
690 option_lists.append(("global options", globalopts))
687
691
688 # list all option lists
692 # list all option lists
689 opt_output = []
693 opt_output = []
690 for title, options in option_lists:
694 for title, options in option_lists:
691 opt_output.append(("\n%s:\n" % title, None))
695 opt_output.append(("\n%s:\n" % title, None))
692 for shortopt, longopt, default, desc in options:
696 for shortopt, longopt, default, desc in options:
693 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
697 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
694 longopt and " --%s" % longopt),
698 longopt and " --%s" % longopt),
695 "%s%s" % (desc,
699 "%s%s" % (desc,
696 default
700 default
697 and _(" (default: %s)") % default
701 and _(" (default: %s)") % default
698 or "")))
702 or "")))
699
703
700 if opt_output:
704 if opt_output:
701 opts_len = max([len(line[0]) for line in opt_output if line[1]])
705 opts_len = max([len(line[0]) for line in opt_output if line[1]])
702 for first, second in opt_output:
706 for first, second in opt_output:
703 if second:
707 if second:
704 ui.write(" %-*s %s\n" % (opts_len, first, second))
708 ui.write(" %-*s %s\n" % (opts_len, first, second))
705 else:
709 else:
706 ui.write("%s\n" % first)
710 ui.write("%s\n" % first)
707
711
708 # Commands start here, listed alphabetically
712 # Commands start here, listed alphabetically
709
713
710 def add(ui, repo, *pats, **opts):
714 def add(ui, repo, *pats, **opts):
711 """add the specified files on the next commit
715 """add the specified files on the next commit
712
716
713 Schedule files to be version controlled and added to the repository.
717 Schedule files to be version controlled and added to the repository.
714
718
715 The files will be added to the repository at the next commit.
719 The files will be added to the repository at the next commit.
716
720
717 If no names are given, add all files in the repository.
721 If no names are given, add all files in the repository.
718 """
722 """
719
723
720 names = []
724 names = []
721 for src, abs, rel, exact in walk(repo, pats, opts):
725 for src, abs, rel, exact in walk(repo, pats, opts):
722 if exact:
726 if exact:
723 if ui.verbose:
727 if ui.verbose:
724 ui.status(_('adding %s\n') % rel)
728 ui.status(_('adding %s\n') % rel)
725 names.append(abs)
729 names.append(abs)
726 elif repo.dirstate.state(abs) == '?':
730 elif repo.dirstate.state(abs) == '?':
727 ui.status(_('adding %s\n') % rel)
731 ui.status(_('adding %s\n') % rel)
728 names.append(abs)
732 names.append(abs)
729 repo.add(names)
733 repo.add(names)
730
734
731 def addremove(ui, repo, *pats, **opts):
735 def addremove(ui, repo, *pats, **opts):
732 """add all new files, delete all missing files
736 """add all new files, delete all missing files
733
737
734 Add all new files and remove all missing files from the repository.
738 Add all new files and remove all missing files from the repository.
735
739
736 New files are ignored if they match any of the patterns in .hgignore. As
740 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.
741 with add, these changes take effect at the next commit.
738 """
742 """
739 return addremove_lock(ui, repo, pats, opts)
743 return addremove_lock(ui, repo, pats, opts)
740
744
741 def addremove_lock(ui, repo, pats, opts, wlock=None):
745 def addremove_lock(ui, repo, pats, opts, wlock=None):
742 add, remove = [], []
746 add, remove = [], []
743 for src, abs, rel, exact in walk(repo, pats, opts):
747 for src, abs, rel, exact in walk(repo, pats, opts):
744 if src == 'f' and repo.dirstate.state(abs) == '?':
748 if src == 'f' and repo.dirstate.state(abs) == '?':
745 add.append(abs)
749 add.append(abs)
746 if ui.verbose or not exact:
750 if ui.verbose or not exact:
747 ui.status(_('adding %s\n') % ((pats and rel) or abs))
751 ui.status(_('adding %s\n') % ((pats and rel) or abs))
748 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
752 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
749 remove.append(abs)
753 remove.append(abs)
750 if ui.verbose or not exact:
754 if ui.verbose or not exact:
751 ui.status(_('removing %s\n') % ((pats and rel) or abs))
755 ui.status(_('removing %s\n') % ((pats and rel) or abs))
752 repo.add(add, wlock=wlock)
756 repo.add(add, wlock=wlock)
753 repo.remove(remove, wlock=wlock)
757 repo.remove(remove, wlock=wlock)
754
758
755 def annotate(ui, repo, *pats, **opts):
759 def annotate(ui, repo, *pats, **opts):
756 """show changeset information per file line
760 """show changeset information per file line
757
761
758 List changes in files, showing the revision id responsible for each line
762 List changes in files, showing the revision id responsible for each line
759
763
760 This command is useful to discover who did a change or when a change took
764 This command is useful to discover who did a change or when a change took
761 place.
765 place.
762
766
763 Without the -a option, annotate will avoid processing files it
767 Without the -a option, annotate will avoid processing files it
764 detects as binary. With -a, annotate will generate an annotation
768 detects as binary. With -a, annotate will generate an annotation
765 anyway, probably with undesirable results.
769 anyway, probably with undesirable results.
766 """
770 """
767 def getnode(rev):
771 def getnode(rev):
768 return short(repo.changelog.node(rev))
772 return short(repo.changelog.node(rev))
769
773
770 ucache = {}
774 ucache = {}
771 def getname(rev):
775 def getname(rev):
772 cl = repo.changelog.read(repo.changelog.node(rev))
776 cl = repo.changelog.read(repo.changelog.node(rev))
773 return trimuser(ui, cl[1], rev, ucache)
777 return trimuser(ui, cl[1], rev, ucache)
774
778
775 dcache = {}
779 dcache = {}
776 def getdate(rev):
780 def getdate(rev):
777 datestr = dcache.get(rev)
781 datestr = dcache.get(rev)
778 if datestr is None:
782 if datestr is None:
779 cl = repo.changelog.read(repo.changelog.node(rev))
783 cl = repo.changelog.read(repo.changelog.node(rev))
780 datestr = dcache[rev] = util.datestr(cl[2])
784 datestr = dcache[rev] = util.datestr(cl[2])
781 return datestr
785 return datestr
782
786
783 if not pats:
787 if not pats:
784 raise util.Abort(_('at least one file name or pattern required'))
788 raise util.Abort(_('at least one file name or pattern required'))
785
789
786 opmap = [['user', getname], ['number', str], ['changeset', getnode],
790 opmap = [['user', getname], ['number', str], ['changeset', getnode],
787 ['date', getdate]]
791 ['date', getdate]]
788 if not opts['user'] and not opts['changeset'] and not opts['date']:
792 if not opts['user'] and not opts['changeset'] and not opts['date']:
789 opts['number'] = 1
793 opts['number'] = 1
790
794
791 if opts['rev']:
795 if opts['rev']:
792 node = repo.changelog.lookup(opts['rev'])
796 node = repo.changelog.lookup(opts['rev'])
793 else:
797 else:
794 node = repo.dirstate.parents()[0]
798 node = repo.dirstate.parents()[0]
795 change = repo.changelog.read(node)
799 change = repo.changelog.read(node)
796 mmap = repo.manifest.read(change[0])
800 mmap = repo.manifest.read(change[0])
797
801
798 for src, abs, rel, exact in walk(repo, pats, opts, node=node):
802 for src, abs, rel, exact in walk(repo, pats, opts, node=node):
799 f = repo.file(abs)
803 f = repo.file(abs)
800 if not opts['text'] and util.binary(f.read(mmap[abs])):
804 if not opts['text'] and util.binary(f.read(mmap[abs])):
801 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
805 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
802 continue
806 continue
803
807
804 lines = f.annotate(mmap[abs])
808 lines = f.annotate(mmap[abs])
805 pieces = []
809 pieces = []
806
810
807 for o, f in opmap:
811 for o, f in opmap:
808 if opts[o]:
812 if opts[o]:
809 l = [f(n) for n, dummy in lines]
813 l = [f(n) for n, dummy in lines]
810 if l:
814 if l:
811 m = max(map(len, l))
815 m = max(map(len, l))
812 pieces.append(["%*s" % (m, x) for x in l])
816 pieces.append(["%*s" % (m, x) for x in l])
813
817
814 if pieces:
818 if pieces:
815 for p, l in zip(zip(*pieces), lines):
819 for p, l in zip(zip(*pieces), lines):
816 ui.write("%s: %s" % (" ".join(p), l[1]))
820 ui.write("%s: %s" % (" ".join(p), l[1]))
817
821
818 def bundle(ui, repo, fname, dest="default-push", **opts):
822 def bundle(ui, repo, fname, dest="default-push", **opts):
819 """create a changegroup file
823 """create a changegroup file
820
824
821 Generate a compressed changegroup file collecting all changesets
825 Generate a compressed changegroup file collecting all changesets
822 not found in the other repository.
826 not found in the other repository.
823
827
824 This file can then be transferred using conventional means and
828 This file can then be transferred using conventional means and
825 applied to another repository with the unbundle command. This is
829 applied to another repository with the unbundle command. This is
826 useful when native push and pull are not available or when
830 useful when native push and pull are not available or when
827 exporting an entire repository is undesirable. The standard file
831 exporting an entire repository is undesirable. The standard file
828 extension is ".hg".
832 extension is ".hg".
829
833
830 Unlike import/export, this exactly preserves all changeset
834 Unlike import/export, this exactly preserves all changeset
831 contents including permissions, rename data, and revision history.
835 contents including permissions, rename data, and revision history.
832 """
836 """
833 f = open(fname, "wb")
837 f = open(fname, "wb")
834 dest = ui.expandpath(dest)
838 dest = ui.expandpath(dest)
835 other = hg.repository(ui, dest)
839 other = hg.repository(ui, dest)
836 o = repo.findoutgoing(other)
840 o = repo.findoutgoing(other)
837 cg = repo.changegroup(o, 'bundle')
841 cg = repo.changegroup(o, 'bundle')
838
842
839 try:
843 try:
840 f.write("HG10")
844 f.write("HG10")
841 z = bz2.BZ2Compressor(9)
845 z = bz2.BZ2Compressor(9)
842 while 1:
846 while 1:
843 chunk = cg.read(4096)
847 chunk = cg.read(4096)
844 if not chunk:
848 if not chunk:
845 break
849 break
846 f.write(z.compress(chunk))
850 f.write(z.compress(chunk))
847 f.write(z.flush())
851 f.write(z.flush())
848 except:
852 except:
849 os.unlink(fname)
853 os.unlink(fname)
850 raise
854 raise
851
855
852 def cat(ui, repo, file1, *pats, **opts):
856 def cat(ui, repo, file1, *pats, **opts):
853 """output the latest or given revisions of files
857 """output the latest or given revisions of files
854
858
855 Print the specified files as they were at the given revision.
859 Print the specified files as they were at the given revision.
856 If no revision is given then the tip is used.
860 If no revision is given then the tip is used.
857
861
858 Output may be to a file, in which case the name of the file is
862 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
863 given using a format string. The formatting rules are the same as
860 for the export command, with the following additions:
864 for the export command, with the following additions:
861
865
862 %s basename of file being printed
866 %s basename of file being printed
863 %d dirname of file being printed, or '.' if in repo root
867 %d dirname of file being printed, or '.' if in repo root
864 %p root-relative path name of file being printed
868 %p root-relative path name of file being printed
865 """
869 """
866 mf = {}
870 mf = {}
867 rev = opts['rev']
871 rev = opts['rev']
868 if rev:
872 if rev:
869 node = repo.lookup(rev)
873 node = repo.lookup(rev)
870 else:
874 else:
871 node = repo.changelog.tip()
875 node = repo.changelog.tip()
872 change = repo.changelog.read(node)
876 change = repo.changelog.read(node)
873 mf = repo.manifest.read(change[0])
877 mf = repo.manifest.read(change[0])
874 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, node):
878 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, node):
875 r = repo.file(abs)
879 r = repo.file(abs)
876 n = mf[abs]
880 n = mf[abs]
877 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
881 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
878 fp.write(r.read(n))
882 fp.write(r.read(n))
879
883
880 def clone(ui, source, dest=None, **opts):
884 def clone(ui, source, dest=None, **opts):
881 """make a copy of an existing repository
885 """make a copy of an existing repository
882
886
883 Create a copy of an existing repository in a new directory.
887 Create a copy of an existing repository in a new directory.
884
888
885 If no destination directory name is specified, it defaults to the
889 If no destination directory name is specified, it defaults to the
886 basename of the source.
890 basename of the source.
887
891
888 The location of the source is added to the new repository's
892 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.
893 .hg/hgrc file, as the default to be used for future pulls.
890
894
891 For efficiency, hardlinks are used for cloning whenever the source
895 For efficiency, hardlinks are used for cloning whenever the source
892 and destination are on the same filesystem. Some filesystems,
896 and destination are on the same filesystem. Some filesystems,
893 such as AFS, implement hardlinking incorrectly, but do not report
897 such as AFS, implement hardlinking incorrectly, but do not report
894 errors. In these cases, use the --pull option to avoid
898 errors. In these cases, use the --pull option to avoid
895 hardlinking.
899 hardlinking.
896
900
897 See pull for valid source format details.
901 See pull for valid source format details.
898 """
902 """
899 if dest is None:
903 if dest is None:
900 dest = os.path.basename(os.path.normpath(source))
904 dest = os.path.basename(os.path.normpath(source))
901
905
902 if os.path.exists(dest):
906 if os.path.exists(dest):
903 raise util.Abort(_("destination '%s' already exists"), dest)
907 raise util.Abort(_("destination '%s' already exists"), dest)
904
908
905 dest = os.path.realpath(dest)
909 dest = os.path.realpath(dest)
906
910
907 class Dircleanup(object):
911 class Dircleanup(object):
908 def __init__(self, dir_):
912 def __init__(self, dir_):
909 self.rmtree = shutil.rmtree
913 self.rmtree = shutil.rmtree
910 self.dir_ = dir_
914 self.dir_ = dir_
911 os.mkdir(dir_)
915 os.mkdir(dir_)
912 def close(self):
916 def close(self):
913 self.dir_ = None
917 self.dir_ = None
914 def __del__(self):
918 def __del__(self):
915 if self.dir_:
919 if self.dir_:
916 self.rmtree(self.dir_, True)
920 self.rmtree(self.dir_, True)
917
921
918 if opts['ssh']:
922 if opts['ssh']:
919 ui.setconfig("ui", "ssh", opts['ssh'])
923 ui.setconfig("ui", "ssh", opts['ssh'])
920 if opts['remotecmd']:
924 if opts['remotecmd']:
921 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
925 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
922
926
923 source = ui.expandpath(source)
927 source = ui.expandpath(source)
924
928
925 d = Dircleanup(dest)
929 d = Dircleanup(dest)
926 abspath = source
930 abspath = source
927 other = hg.repository(ui, source)
931 other = hg.repository(ui, source)
928
932
929 copy = False
933 copy = False
930 if other.dev() != -1:
934 if other.dev() != -1:
931 abspath = os.path.abspath(source)
935 abspath = os.path.abspath(source)
932 if not opts['pull'] and not opts['rev']:
936 if not opts['pull'] and not opts['rev']:
933 copy = True
937 copy = True
934
938
935 if copy:
939 if copy:
936 try:
940 try:
937 # we use a lock here because if we race with commit, we
941 # 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
942 # can end up with extra data in the cloned revlogs that's
939 # not pointed to by changesets, thus causing verify to
943 # not pointed to by changesets, thus causing verify to
940 # fail
944 # fail
941 l1 = other.lock()
945 l1 = other.lock()
942 except lock.LockException:
946 except lock.LockException:
943 copy = False
947 copy = False
944
948
945 if copy:
949 if copy:
946 # we lock here to avoid premature writing to the target
950 # we lock here to avoid premature writing to the target
947 os.mkdir(os.path.join(dest, ".hg"))
951 os.mkdir(os.path.join(dest, ".hg"))
948 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
952 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
949
953
950 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
954 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
951 for f in files.split():
955 for f in files.split():
952 src = os.path.join(source, ".hg", f)
956 src = os.path.join(source, ".hg", f)
953 dst = os.path.join(dest, ".hg", f)
957 dst = os.path.join(dest, ".hg", f)
954 try:
958 try:
955 util.copyfiles(src, dst)
959 util.copyfiles(src, dst)
956 except OSError, inst:
960 except OSError, inst:
957 if inst.errno != errno.ENOENT:
961 if inst.errno != errno.ENOENT:
958 raise
962 raise
959
963
960 repo = hg.repository(ui, dest)
964 repo = hg.repository(ui, dest)
961
965
962 else:
966 else:
963 revs = None
967 revs = None
964 if opts['rev']:
968 if opts['rev']:
965 if not other.local():
969 if not other.local():
966 error = _("clone -r not supported yet for remote repositories.")
970 error = _("clone -r not supported yet for remote repositories.")
967 raise util.Abort(error)
971 raise util.Abort(error)
968 else:
972 else:
969 revs = [other.lookup(rev) for rev in opts['rev']]
973 revs = [other.lookup(rev) for rev in opts['rev']]
970 repo = hg.repository(ui, dest, create=1)
974 repo = hg.repository(ui, dest, create=1)
971 repo.pull(other, heads = revs)
975 repo.pull(other, heads = revs)
972
976
973 f = repo.opener("hgrc", "w", text=True)
977 f = repo.opener("hgrc", "w", text=True)
974 f.write("[paths]\n")
978 f.write("[paths]\n")
975 f.write("default = %s\n" % abspath)
979 f.write("default = %s\n" % abspath)
976 f.close()
980 f.close()
977
981
978 if not opts['noupdate']:
982 if not opts['noupdate']:
979 update(repo.ui, repo)
983 update(repo.ui, repo)
980
984
981 d.close()
985 d.close()
982
986
983 def commit(ui, repo, *pats, **opts):
987 def commit(ui, repo, *pats, **opts):
984 """commit the specified files or all outstanding changes
988 """commit the specified files or all outstanding changes
985
989
986 Commit changes to the given files into the repository.
990 Commit changes to the given files into the repository.
987
991
988 If a list of files is omitted, all changes reported by "hg status"
992 If a list of files is omitted, all changes reported by "hg status"
989 will be commited.
993 will be commited.
990
994
991 The HGEDITOR or EDITOR environment variables are used to start an
995 The HGEDITOR or EDITOR environment variables are used to start an
992 editor to add a commit comment.
996 editor to add a commit comment.
993 """
997 """
994 message = opts['message']
998 message = opts['message']
995 logfile = opts['logfile']
999 logfile = opts['logfile']
996
1000
997 if message and logfile:
1001 if message and logfile:
998 raise util.Abort(_('options --message and --logfile are mutually '
1002 raise util.Abort(_('options --message and --logfile are mutually '
999 'exclusive'))
1003 'exclusive'))
1000 if not message and logfile:
1004 if not message and logfile:
1001 try:
1005 try:
1002 if logfile == '-':
1006 if logfile == '-':
1003 message = sys.stdin.read()
1007 message = sys.stdin.read()
1004 else:
1008 else:
1005 message = open(logfile).read()
1009 message = open(logfile).read()
1006 except IOError, inst:
1010 except IOError, inst:
1007 raise util.Abort(_("can't read commit message '%s': %s") %
1011 raise util.Abort(_("can't read commit message '%s': %s") %
1008 (logfile, inst.strerror))
1012 (logfile, inst.strerror))
1009
1013
1010 if opts['addremove']:
1014 if opts['addremove']:
1011 addremove(ui, repo, *pats, **opts)
1015 addremove(ui, repo, *pats, **opts)
1012 fns, match, anypats = matchpats(repo, pats, opts)
1016 fns, match, anypats = matchpats(repo, pats, opts)
1013 if pats:
1017 if pats:
1014 modified, added, removed, deleted, unknown = (
1018 modified, added, removed, deleted, unknown = (
1015 repo.changes(files=fns, match=match))
1019 repo.changes(files=fns, match=match))
1016 files = modified + added + removed
1020 files = modified + added + removed
1017 else:
1021 else:
1018 files = []
1022 files = []
1019 try:
1023 try:
1020 repo.commit(files, message, opts['user'], opts['date'], match)
1024 repo.commit(files, message, opts['user'], opts['date'], match)
1021 except ValueError, inst:
1025 except ValueError, inst:
1022 raise util.Abort(str(inst))
1026 raise util.Abort(str(inst))
1023
1027
1024 def docopy(ui, repo, pats, opts, wlock):
1028 def docopy(ui, repo, pats, opts, wlock):
1025 # called with the repo lock held
1029 # called with the repo lock held
1026 cwd = repo.getcwd()
1030 cwd = repo.getcwd()
1027 errors = 0
1031 errors = 0
1028 copied = []
1032 copied = []
1029 targets = {}
1033 targets = {}
1030
1034
1031 def okaytocopy(abs, rel, exact):
1035 def okaytocopy(abs, rel, exact):
1032 reasons = {'?': _('is not managed'),
1036 reasons = {'?': _('is not managed'),
1033 'a': _('has been marked for add'),
1037 'a': _('has been marked for add'),
1034 'r': _('has been marked for remove')}
1038 'r': _('has been marked for remove')}
1035 state = repo.dirstate.state(abs)
1039 state = repo.dirstate.state(abs)
1036 reason = reasons.get(state)
1040 reason = reasons.get(state)
1037 if reason:
1041 if reason:
1038 if state == 'a':
1042 if state == 'a':
1039 origsrc = repo.dirstate.copied(abs)
1043 origsrc = repo.dirstate.copied(abs)
1040 if origsrc is not None:
1044 if origsrc is not None:
1041 return origsrc
1045 return origsrc
1042 if exact:
1046 if exact:
1043 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
1047 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
1044 else:
1048 else:
1045 return abs
1049 return abs
1046
1050
1047 def copy(origsrc, abssrc, relsrc, target, exact):
1051 def copy(origsrc, abssrc, relsrc, target, exact):
1048 abstarget = util.canonpath(repo.root, cwd, target)
1052 abstarget = util.canonpath(repo.root, cwd, target)
1049 reltarget = util.pathto(cwd, abstarget)
1053 reltarget = util.pathto(cwd, abstarget)
1050 prevsrc = targets.get(abstarget)
1054 prevsrc = targets.get(abstarget)
1051 if prevsrc is not None:
1055 if prevsrc is not None:
1052 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
1056 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
1053 (reltarget, abssrc, prevsrc))
1057 (reltarget, abssrc, prevsrc))
1054 return
1058 return
1055 if (not opts['after'] and os.path.exists(reltarget) or
1059 if (not opts['after'] and os.path.exists(reltarget) or
1056 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
1060 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
1057 if not opts['force']:
1061 if not opts['force']:
1058 ui.warn(_('%s: not overwriting - file exists\n') %
1062 ui.warn(_('%s: not overwriting - file exists\n') %
1059 reltarget)
1063 reltarget)
1060 return
1064 return
1061 if not opts['after']:
1065 if not opts['after']:
1062 os.unlink(reltarget)
1066 os.unlink(reltarget)
1063 if opts['after']:
1067 if opts['after']:
1064 if not os.path.exists(reltarget):
1068 if not os.path.exists(reltarget):
1065 return
1069 return
1066 else:
1070 else:
1067 targetdir = os.path.dirname(reltarget) or '.'
1071 targetdir = os.path.dirname(reltarget) or '.'
1068 if not os.path.isdir(targetdir):
1072 if not os.path.isdir(targetdir):
1069 os.makedirs(targetdir)
1073 os.makedirs(targetdir)
1070 try:
1074 try:
1071 restore = repo.dirstate.state(abstarget) == 'r'
1075 restore = repo.dirstate.state(abstarget) == 'r'
1072 if restore:
1076 if restore:
1073 repo.undelete([abstarget], wlock)
1077 repo.undelete([abstarget], wlock)
1074 try:
1078 try:
1075 shutil.copyfile(relsrc, reltarget)
1079 shutil.copyfile(relsrc, reltarget)
1076 shutil.copymode(relsrc, reltarget)
1080 shutil.copymode(relsrc, reltarget)
1077 restore = False
1081 restore = False
1078 finally:
1082 finally:
1079 if restore:
1083 if restore:
1080 repo.remove([abstarget], wlock)
1084 repo.remove([abstarget], wlock)
1081 except shutil.Error, inst:
1085 except shutil.Error, inst:
1082 raise util.Abort(str(inst))
1086 raise util.Abort(str(inst))
1083 except IOError, inst:
1087 except IOError, inst:
1084 if inst.errno == errno.ENOENT:
1088 if inst.errno == errno.ENOENT:
1085 ui.warn(_('%s: deleted in working copy\n') % relsrc)
1089 ui.warn(_('%s: deleted in working copy\n') % relsrc)
1086 else:
1090 else:
1087 ui.warn(_('%s: cannot copy - %s\n') %
1091 ui.warn(_('%s: cannot copy - %s\n') %
1088 (relsrc, inst.strerror))
1092 (relsrc, inst.strerror))
1089 errors += 1
1093 errors += 1
1090 return
1094 return
1091 if ui.verbose or not exact:
1095 if ui.verbose or not exact:
1092 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1096 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1093 targets[abstarget] = abssrc
1097 targets[abstarget] = abssrc
1094 if abstarget != origsrc:
1098 if abstarget != origsrc:
1095 repo.copy(origsrc, abstarget, wlock)
1099 repo.copy(origsrc, abstarget, wlock)
1096 copied.append((abssrc, relsrc, exact))
1100 copied.append((abssrc, relsrc, exact))
1097
1101
1098 def targetpathfn(pat, dest, srcs):
1102 def targetpathfn(pat, dest, srcs):
1099 if os.path.isdir(pat):
1103 if os.path.isdir(pat):
1100 abspfx = util.canonpath(repo.root, cwd, pat)
1104 abspfx = util.canonpath(repo.root, cwd, pat)
1101 if destdirexists:
1105 if destdirexists:
1102 striplen = len(os.path.split(abspfx)[0])
1106 striplen = len(os.path.split(abspfx)[0])
1103 else:
1107 else:
1104 striplen = len(abspfx)
1108 striplen = len(abspfx)
1105 if striplen:
1109 if striplen:
1106 striplen += len(os.sep)
1110 striplen += len(os.sep)
1107 res = lambda p: os.path.join(dest, p[striplen:])
1111 res = lambda p: os.path.join(dest, p[striplen:])
1108 elif destdirexists:
1112 elif destdirexists:
1109 res = lambda p: os.path.join(dest, os.path.basename(p))
1113 res = lambda p: os.path.join(dest, os.path.basename(p))
1110 else:
1114 else:
1111 res = lambda p: dest
1115 res = lambda p: dest
1112 return res
1116 return res
1113
1117
1114 def targetpathafterfn(pat, dest, srcs):
1118 def targetpathafterfn(pat, dest, srcs):
1115 if util.patkind(pat, None)[0]:
1119 if util.patkind(pat, None)[0]:
1116 # a mercurial pattern
1120 # a mercurial pattern
1117 res = lambda p: os.path.join(dest, os.path.basename(p))
1121 res = lambda p: os.path.join(dest, os.path.basename(p))
1118 else:
1122 else:
1119 abspfx = util.canonpath(repo.root, cwd, pat)
1123 abspfx = util.canonpath(repo.root, cwd, pat)
1120 if len(abspfx) < len(srcs[0][0]):
1124 if len(abspfx) < len(srcs[0][0]):
1121 # A directory. Either the target path contains the last
1125 # A directory. Either the target path contains the last
1122 # component of the source path or it does not.
1126 # component of the source path or it does not.
1123 def evalpath(striplen):
1127 def evalpath(striplen):
1124 score = 0
1128 score = 0
1125 for s in srcs:
1129 for s in srcs:
1126 t = os.path.join(dest, s[0][striplen:])
1130 t = os.path.join(dest, s[0][striplen:])
1127 if os.path.exists(t):
1131 if os.path.exists(t):
1128 score += 1
1132 score += 1
1129 return score
1133 return score
1130
1134
1131 striplen = len(abspfx)
1135 striplen = len(abspfx)
1132 if striplen:
1136 if striplen:
1133 striplen += len(os.sep)
1137 striplen += len(os.sep)
1134 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1138 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1135 score = evalpath(striplen)
1139 score = evalpath(striplen)
1136 striplen1 = len(os.path.split(abspfx)[0])
1140 striplen1 = len(os.path.split(abspfx)[0])
1137 if striplen1:
1141 if striplen1:
1138 striplen1 += len(os.sep)
1142 striplen1 += len(os.sep)
1139 if evalpath(striplen1) > score:
1143 if evalpath(striplen1) > score:
1140 striplen = striplen1
1144 striplen = striplen1
1141 res = lambda p: os.path.join(dest, p[striplen:])
1145 res = lambda p: os.path.join(dest, p[striplen:])
1142 else:
1146 else:
1143 # a file
1147 # a file
1144 if destdirexists:
1148 if destdirexists:
1145 res = lambda p: os.path.join(dest, os.path.basename(p))
1149 res = lambda p: os.path.join(dest, os.path.basename(p))
1146 else:
1150 else:
1147 res = lambda p: dest
1151 res = lambda p: dest
1148 return res
1152 return res
1149
1153
1150
1154
1151 pats = list(pats)
1155 pats = list(pats)
1152 if not pats:
1156 if not pats:
1153 raise util.Abort(_('no source or destination specified'))
1157 raise util.Abort(_('no source or destination specified'))
1154 if len(pats) == 1:
1158 if len(pats) == 1:
1155 raise util.Abort(_('no destination specified'))
1159 raise util.Abort(_('no destination specified'))
1156 dest = pats.pop()
1160 dest = pats.pop()
1157 destdirexists = os.path.isdir(dest)
1161 destdirexists = os.path.isdir(dest)
1158 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
1162 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 '
1163 raise util.Abort(_('with multiple sources, destination must be an '
1160 'existing directory'))
1164 'existing directory'))
1161 if opts['after']:
1165 if opts['after']:
1162 tfn = targetpathafterfn
1166 tfn = targetpathafterfn
1163 else:
1167 else:
1164 tfn = targetpathfn
1168 tfn = targetpathfn
1165 copylist = []
1169 copylist = []
1166 for pat in pats:
1170 for pat in pats:
1167 srcs = []
1171 srcs = []
1168 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
1172 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
1169 origsrc = okaytocopy(abssrc, relsrc, exact)
1173 origsrc = okaytocopy(abssrc, relsrc, exact)
1170 if origsrc:
1174 if origsrc:
1171 srcs.append((origsrc, abssrc, relsrc, exact))
1175 srcs.append((origsrc, abssrc, relsrc, exact))
1172 if not srcs:
1176 if not srcs:
1173 continue
1177 continue
1174 copylist.append((tfn(pat, dest, srcs), srcs))
1178 copylist.append((tfn(pat, dest, srcs), srcs))
1175 if not copylist:
1179 if not copylist:
1176 raise util.Abort(_('no files to copy'))
1180 raise util.Abort(_('no files to copy'))
1177
1181
1178 for targetpath, srcs in copylist:
1182 for targetpath, srcs in copylist:
1179 for origsrc, abssrc, relsrc, exact in srcs:
1183 for origsrc, abssrc, relsrc, exact in srcs:
1180 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
1184 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
1181
1185
1182 if errors:
1186 if errors:
1183 ui.warn(_('(consider using --after)\n'))
1187 ui.warn(_('(consider using --after)\n'))
1184 return errors, copied
1188 return errors, copied
1185
1189
1186 def copy(ui, repo, *pats, **opts):
1190 def copy(ui, repo, *pats, **opts):
1187 """mark files as copied for the next commit
1191 """mark files as copied for the next commit
1188
1192
1189 Mark dest as having copies of source files. If dest is a
1193 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,
1194 directory, copies are put in that directory. If dest is a file,
1191 there can only be one source.
1195 there can only be one source.
1192
1196
1193 By default, this command copies the contents of files as they
1197 By default, this command copies the contents of files as they
1194 stand in the working directory. If invoked with --after, the
1198 stand in the working directory. If invoked with --after, the
1195 operation is recorded, but no copying is performed.
1199 operation is recorded, but no copying is performed.
1196
1200
1197 This command takes effect in the next commit.
1201 This command takes effect in the next commit.
1198
1202
1199 NOTE: This command should be treated as experimental. While it
1203 NOTE: This command should be treated as experimental. While it
1200 should properly record copied files, this information is not yet
1204 should properly record copied files, this information is not yet
1201 fully used by merge, nor fully reported by log.
1205 fully used by merge, nor fully reported by log.
1202 """
1206 """
1203 try:
1207 try:
1204 wlock = repo.wlock(0)
1208 wlock = repo.wlock(0)
1205 errs, copied = docopy(ui, repo, pats, opts, wlock)
1209 errs, copied = docopy(ui, repo, pats, opts, wlock)
1206 except lock.LockHeld, inst:
1210 except lock.LockHeld, inst:
1207 ui.warn(_("repository lock held by %s\n") % inst.args[0])
1211 ui.warn(_("repository lock held by %s\n") % inst.args[0])
1208 errs = 1
1212 errs = 1
1209 return errs
1213 return errs
1210
1214
1211 def debugancestor(ui, index, rev1, rev2):
1215 def debugancestor(ui, index, rev1, rev2):
1212 """find the ancestor revision of two revisions in a given index"""
1216 """find the ancestor revision of two revisions in a given index"""
1213 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "")
1217 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "")
1214 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1218 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1215 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1219 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1216
1220
1217 def debugcomplete(ui, cmd):
1221 def debugcomplete(ui, cmd):
1218 """returns the completion list associated with the given command"""
1222 """returns the completion list associated with the given command"""
1219 clist = findpossible(cmd).keys()
1223 clist = findpossible(cmd).keys()
1220 clist.sort()
1224 clist.sort()
1221 ui.write("%s\n" % " ".join(clist))
1225 ui.write("%s\n" % " ".join(clist))
1222
1226
1223 def debugrebuildstate(ui, repo, rev=None):
1227 def debugrebuildstate(ui, repo, rev=None):
1224 """rebuild the dirstate as it would look like for the given revision"""
1228 """rebuild the dirstate as it would look like for the given revision"""
1225 if not rev:
1229 if not rev:
1226 rev = repo.changelog.tip()
1230 rev = repo.changelog.tip()
1227 else:
1231 else:
1228 rev = repo.lookup(rev)
1232 rev = repo.lookup(rev)
1229 change = repo.changelog.read(rev)
1233 change = repo.changelog.read(rev)
1230 n = change[0]
1234 n = change[0]
1231 files = repo.manifest.readflags(n)
1235 files = repo.manifest.readflags(n)
1232 wlock = repo.wlock()
1236 wlock = repo.wlock()
1233 repo.dirstate.rebuild(rev, files.iteritems())
1237 repo.dirstate.rebuild(rev, files.iteritems())
1234
1238
1235 def debugcheckstate(ui, repo):
1239 def debugcheckstate(ui, repo):
1236 """validate the correctness of the current dirstate"""
1240 """validate the correctness of the current dirstate"""
1237 parent1, parent2 = repo.dirstate.parents()
1241 parent1, parent2 = repo.dirstate.parents()
1238 repo.dirstate.read()
1242 repo.dirstate.read()
1239 dc = repo.dirstate.map
1243 dc = repo.dirstate.map
1240 keys = dc.keys()
1244 keys = dc.keys()
1241 keys.sort()
1245 keys.sort()
1242 m1n = repo.changelog.read(parent1)[0]
1246 m1n = repo.changelog.read(parent1)[0]
1243 m2n = repo.changelog.read(parent2)[0]
1247 m2n = repo.changelog.read(parent2)[0]
1244 m1 = repo.manifest.read(m1n)
1248 m1 = repo.manifest.read(m1n)
1245 m2 = repo.manifest.read(m2n)
1249 m2 = repo.manifest.read(m2n)
1246 errors = 0
1250 errors = 0
1247 for f in dc:
1251 for f in dc:
1248 state = repo.dirstate.state(f)
1252 state = repo.dirstate.state(f)
1249 if state in "nr" and f not in m1:
1253 if state in "nr" and f not in m1:
1250 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1254 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1251 errors += 1
1255 errors += 1
1252 if state in "a" and f in m1:
1256 if state in "a" and f in m1:
1253 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1257 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1254 errors += 1
1258 errors += 1
1255 if state in "m" and f not in m1 and f not in m2:
1259 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") %
1260 ui.warn(_("%s in state %s, but not in either manifest\n") %
1257 (f, state))
1261 (f, state))
1258 errors += 1
1262 errors += 1
1259 for f in m1:
1263 for f in m1:
1260 state = repo.dirstate.state(f)
1264 state = repo.dirstate.state(f)
1261 if state not in "nrm":
1265 if state not in "nrm":
1262 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1266 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1263 errors += 1
1267 errors += 1
1264 if errors:
1268 if errors:
1265 error = _(".hg/dirstate inconsistent with current parent's manifest")
1269 error = _(".hg/dirstate inconsistent with current parent's manifest")
1266 raise util.Abort(error)
1270 raise util.Abort(error)
1267
1271
1268 def debugconfig(ui, repo):
1272 def debugconfig(ui, repo):
1269 """show combined config settings from all hgrc files"""
1273 """show combined config settings from all hgrc files"""
1270 for section, name, value in ui.walkconfig():
1274 for section, name, value in ui.walkconfig():
1271 ui.write('%s.%s=%s\n' % (section, name, value))
1275 ui.write('%s.%s=%s\n' % (section, name, value))
1272
1276
1273 def debugsetparents(ui, repo, rev1, rev2=None):
1277 def debugsetparents(ui, repo, rev1, rev2=None):
1274 """manually set the parents of the current working directory
1278 """manually set the parents of the current working directory
1275
1279
1276 This is useful for writing repository conversion tools, but should
1280 This is useful for writing repository conversion tools, but should
1277 be used with care.
1281 be used with care.
1278 """
1282 """
1279
1283
1280 if not rev2:
1284 if not rev2:
1281 rev2 = hex(nullid)
1285 rev2 = hex(nullid)
1282
1286
1283 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1287 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1284
1288
1285 def debugstate(ui, repo):
1289 def debugstate(ui, repo):
1286 """show the contents of the current dirstate"""
1290 """show the contents of the current dirstate"""
1287 repo.dirstate.read()
1291 repo.dirstate.read()
1288 dc = repo.dirstate.map
1292 dc = repo.dirstate.map
1289 keys = dc.keys()
1293 keys = dc.keys()
1290 keys.sort()
1294 keys.sort()
1291 for file_ in keys:
1295 for file_ in keys:
1292 ui.write("%c %3o %10d %s %s\n"
1296 ui.write("%c %3o %10d %s %s\n"
1293 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1297 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1294 time.strftime("%x %X",
1298 time.strftime("%x %X",
1295 time.localtime(dc[file_][3])), file_))
1299 time.localtime(dc[file_][3])), file_))
1296 for f in repo.dirstate.copies:
1300 for f in repo.dirstate.copies:
1297 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1301 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1298
1302
1299 def debugdata(ui, file_, rev):
1303 def debugdata(ui, file_, rev):
1300 """dump the contents of an data file revision"""
1304 """dump the contents of an data file revision"""
1301 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1305 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1302 file_[:-2] + ".i", file_)
1306 file_[:-2] + ".i", file_)
1303 try:
1307 try:
1304 ui.write(r.revision(r.lookup(rev)))
1308 ui.write(r.revision(r.lookup(rev)))
1305 except KeyError:
1309 except KeyError:
1306 raise util.Abort(_('invalid revision identifier %s'), rev)
1310 raise util.Abort(_('invalid revision identifier %s'), rev)
1307
1311
1308 def debugindex(ui, file_):
1312 def debugindex(ui, file_):
1309 """dump the contents of an index file"""
1313 """dump the contents of an index file"""
1310 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "")
1314 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "")
1311 ui.write(" rev offset length base linkrev" +
1315 ui.write(" rev offset length base linkrev" +
1312 " nodeid p1 p2\n")
1316 " nodeid p1 p2\n")
1313 for i in range(r.count()):
1317 for i in range(r.count()):
1314 e = r.index[i]
1318 e = r.index[i]
1315 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1319 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1316 i, e[0], e[1], e[2], e[3],
1320 i, e[0], e[1], e[2], e[3],
1317 short(e[6]), short(e[4]), short(e[5])))
1321 short(e[6]), short(e[4]), short(e[5])))
1318
1322
1319 def debugindexdot(ui, file_):
1323 def debugindexdot(ui, file_):
1320 """dump an index DAG as a .dot file"""
1324 """dump an index DAG as a .dot file"""
1321 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "")
1325 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "")
1322 ui.write("digraph G {\n")
1326 ui.write("digraph G {\n")
1323 for i in range(r.count()):
1327 for i in range(r.count()):
1324 e = r.index[i]
1328 e = r.index[i]
1325 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
1329 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
1326 if e[5] != nullid:
1330 if e[5] != nullid:
1327 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
1331 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
1328 ui.write("}\n")
1332 ui.write("}\n")
1329
1333
1330 def debugrename(ui, repo, file, rev=None):
1334 def debugrename(ui, repo, file, rev=None):
1331 """dump rename information"""
1335 """dump rename information"""
1332 r = repo.file(relpath(repo, [file])[0])
1336 r = repo.file(relpath(repo, [file])[0])
1333 if rev:
1337 if rev:
1334 try:
1338 try:
1335 # assume all revision numbers are for changesets
1339 # assume all revision numbers are for changesets
1336 n = repo.lookup(rev)
1340 n = repo.lookup(rev)
1337 change = repo.changelog.read(n)
1341 change = repo.changelog.read(n)
1338 m = repo.manifest.read(change[0])
1342 m = repo.manifest.read(change[0])
1339 n = m[relpath(repo, [file])[0]]
1343 n = m[relpath(repo, [file])[0]]
1340 except (hg.RepoError, KeyError):
1344 except (hg.RepoError, KeyError):
1341 n = r.lookup(rev)
1345 n = r.lookup(rev)
1342 else:
1346 else:
1343 n = r.tip()
1347 n = r.tip()
1344 m = r.renamed(n)
1348 m = r.renamed(n)
1345 if m:
1349 if m:
1346 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1350 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1347 else:
1351 else:
1348 ui.write(_("not renamed\n"))
1352 ui.write(_("not renamed\n"))
1349
1353
1350 def debugwalk(ui, repo, *pats, **opts):
1354 def debugwalk(ui, repo, *pats, **opts):
1351 """show how files match on given patterns"""
1355 """show how files match on given patterns"""
1352 items = list(walk(repo, pats, opts))
1356 items = list(walk(repo, pats, opts))
1353 if not items:
1357 if not items:
1354 return
1358 return
1355 fmt = '%%s %%-%ds %%-%ds %%s' % (
1359 fmt = '%%s %%-%ds %%-%ds %%s' % (
1356 max([len(abs) for (src, abs, rel, exact) in items]),
1360 max([len(abs) for (src, abs, rel, exact) in items]),
1357 max([len(rel) for (src, abs, rel, exact) in items]))
1361 max([len(rel) for (src, abs, rel, exact) in items]))
1358 for src, abs, rel, exact in items:
1362 for src, abs, rel, exact in items:
1359 line = fmt % (src, abs, rel, exact and 'exact' or '')
1363 line = fmt % (src, abs, rel, exact and 'exact' or '')
1360 ui.write("%s\n" % line.rstrip())
1364 ui.write("%s\n" % line.rstrip())
1361
1365
1362 def diff(ui, repo, *pats, **opts):
1366 def diff(ui, repo, *pats, **opts):
1363 """diff repository (or selected files)
1367 """diff repository (or selected files)
1364
1368
1365 Show differences between revisions for the specified files.
1369 Show differences between revisions for the specified files.
1366
1370
1367 Differences between files are shown using the unified diff format.
1371 Differences between files are shown using the unified diff format.
1368
1372
1369 When two revision arguments are given, then changes are shown
1373 When two revision arguments are given, then changes are shown
1370 between those revisions. If only one revision is specified then
1374 between those revisions. If only one revision is specified then
1371 that revision is compared to the working directory, and, when no
1375 that revision is compared to the working directory, and, when no
1372 revisions are specified, the working directory files are compared
1376 revisions are specified, the working directory files are compared
1373 to its parent.
1377 to its parent.
1374
1378
1375 Without the -a option, diff will avoid generating diffs of files
1379 Without the -a option, diff will avoid generating diffs of files
1376 it detects as binary. With -a, diff will generate a diff anyway,
1380 it detects as binary. With -a, diff will generate a diff anyway,
1377 probably with undesirable results.
1381 probably with undesirable results.
1378 """
1382 """
1379 node1, node2 = None, None
1383 node1, node2 = None, None
1380 revs = [repo.lookup(x) for x in opts['rev']]
1384 revs = [repo.lookup(x) for x in opts['rev']]
1381
1385
1382 if len(revs) > 0:
1386 if len(revs) > 0:
1383 node1 = revs[0]
1387 node1 = revs[0]
1384 if len(revs) > 1:
1388 if len(revs) > 1:
1385 node2 = revs[1]
1389 node2 = revs[1]
1386 if len(revs) > 2:
1390 if len(revs) > 2:
1387 raise util.Abort(_("too many revisions to diff"))
1391 raise util.Abort(_("too many revisions to diff"))
1388
1392
1389 fns, matchfn, anypats = matchpats(repo, pats, opts)
1393 fns, matchfn, anypats = matchpats(repo, pats, opts)
1390
1394
1391 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1395 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1392 text=opts['text'], opts=opts)
1396 text=opts['text'], opts=opts)
1393
1397
1394 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1398 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1395 node = repo.lookup(changeset)
1399 node = repo.lookup(changeset)
1396 parents = [p for p in repo.changelog.parents(node) if p != nullid]
1400 parents = [p for p in repo.changelog.parents(node) if p != nullid]
1397 if opts['switch_parent']:
1401 if opts['switch_parent']:
1398 parents.reverse()
1402 parents.reverse()
1399 prev = (parents and parents[0]) or nullid
1403 prev = (parents and parents[0]) or nullid
1400 change = repo.changelog.read(node)
1404 change = repo.changelog.read(node)
1401
1405
1402 fp = make_file(repo, repo.changelog, opts['output'],
1406 fp = make_file(repo, repo.changelog, opts['output'],
1403 node=node, total=total, seqno=seqno,
1407 node=node, total=total, seqno=seqno,
1404 revwidth=revwidth)
1408 revwidth=revwidth)
1405 if fp != sys.stdout:
1409 if fp != sys.stdout:
1406 ui.note("%s\n" % fp.name)
1410 ui.note("%s\n" % fp.name)
1407
1411
1408 fp.write("# HG changeset patch\n")
1412 fp.write("# HG changeset patch\n")
1409 fp.write("# User %s\n" % change[1])
1413 fp.write("# User %s\n" % change[1])
1410 fp.write("# Node ID %s\n" % hex(node))
1414 fp.write("# Node ID %s\n" % hex(node))
1411 fp.write("# Parent %s\n" % hex(prev))
1415 fp.write("# Parent %s\n" % hex(prev))
1412 if len(parents) > 1:
1416 if len(parents) > 1:
1413 fp.write("# Parent %s\n" % hex(parents[1]))
1417 fp.write("# Parent %s\n" % hex(parents[1]))
1414 fp.write(change[4].rstrip())
1418 fp.write(change[4].rstrip())
1415 fp.write("\n\n")
1419 fp.write("\n\n")
1416
1420
1417 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1421 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1418 if fp != sys.stdout:
1422 if fp != sys.stdout:
1419 fp.close()
1423 fp.close()
1420
1424
1421 def export(ui, repo, *changesets, **opts):
1425 def export(ui, repo, *changesets, **opts):
1422 """dump the header and diffs for one or more changesets
1426 """dump the header and diffs for one or more changesets
1423
1427
1424 Print the changeset header and diffs for one or more revisions.
1428 Print the changeset header and diffs for one or more revisions.
1425
1429
1426 The information shown in the changeset header is: author,
1430 The information shown in the changeset header is: author,
1427 changeset hash, parent and commit comment.
1431 changeset hash, parent and commit comment.
1428
1432
1429 Output may be to a file, in which case the name of the file is
1433 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:
1434 given using a format string. The formatting rules are as follows:
1431
1435
1432 %% literal "%" character
1436 %% literal "%" character
1433 %H changeset hash (40 bytes of hexadecimal)
1437 %H changeset hash (40 bytes of hexadecimal)
1434 %N number of patches being generated
1438 %N number of patches being generated
1435 %R changeset revision number
1439 %R changeset revision number
1436 %b basename of the exporting repository
1440 %b basename of the exporting repository
1437 %h short-form changeset hash (12 bytes of hexadecimal)
1441 %h short-form changeset hash (12 bytes of hexadecimal)
1438 %n zero-padded sequence number, starting at 1
1442 %n zero-padded sequence number, starting at 1
1439 %r zero-padded changeset revision number
1443 %r zero-padded changeset revision number
1440
1444
1441 Without the -a option, export will avoid generating diffs of files
1445 Without the -a option, export will avoid generating diffs of files
1442 it detects as binary. With -a, export will generate a diff anyway,
1446 it detects as binary. With -a, export will generate a diff anyway,
1443 probably with undesirable results.
1447 probably with undesirable results.
1444
1448
1445 With the --switch-parent option, the diff will be against the second
1449 With the --switch-parent option, the diff will be against the second
1446 parent. It can be useful to review a merge.
1450 parent. It can be useful to review a merge.
1447 """
1451 """
1448 if not changesets:
1452 if not changesets:
1449 raise util.Abort(_("export requires at least one changeset"))
1453 raise util.Abort(_("export requires at least one changeset"))
1450 seqno = 0
1454 seqno = 0
1451 revs = list(revrange(ui, repo, changesets))
1455 revs = list(revrange(ui, repo, changesets))
1452 total = len(revs)
1456 total = len(revs)
1453 revwidth = max(map(len, revs))
1457 revwidth = max(map(len, revs))
1454 msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
1458 msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
1455 ui.note(msg)
1459 ui.note(msg)
1456 for cset in revs:
1460 for cset in revs:
1457 seqno += 1
1461 seqno += 1
1458 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1462 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1459
1463
1460 def forget(ui, repo, *pats, **opts):
1464 def forget(ui, repo, *pats, **opts):
1461 """don't add the specified files on the next commit
1465 """don't add the specified files on the next commit
1462
1466
1463 Undo an 'hg add' scheduled for the next commit.
1467 Undo an 'hg add' scheduled for the next commit.
1464 """
1468 """
1465 forget = []
1469 forget = []
1466 for src, abs, rel, exact in walk(repo, pats, opts):
1470 for src, abs, rel, exact in walk(repo, pats, opts):
1467 if repo.dirstate.state(abs) == 'a':
1471 if repo.dirstate.state(abs) == 'a':
1468 forget.append(abs)
1472 forget.append(abs)
1469 if ui.verbose or not exact:
1473 if ui.verbose or not exact:
1470 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1474 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1471 repo.forget(forget)
1475 repo.forget(forget)
1472
1476
1473 def grep(ui, repo, pattern, *pats, **opts):
1477 def grep(ui, repo, pattern, *pats, **opts):
1474 """search for a pattern in specified files and revisions
1478 """search for a pattern in specified files and revisions
1475
1479
1476 Search revisions of files for a regular expression.
1480 Search revisions of files for a regular expression.
1477
1481
1478 This command behaves differently than Unix grep. It only accepts
1482 This command behaves differently than Unix grep. It only accepts
1479 Python/Perl regexps. It searches repository history, not the
1483 Python/Perl regexps. It searches repository history, not the
1480 working directory. It always prints the revision number in which
1484 working directory. It always prints the revision number in which
1481 a match appears.
1485 a match appears.
1482
1486
1483 By default, grep only prints output for the first revision of a
1487 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
1488 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
1489 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),
1490 becomes a non-match, or "+" for a non-match that becomes a match),
1487 use the --all flag.
1491 use the --all flag.
1488 """
1492 """
1489 reflags = 0
1493 reflags = 0
1490 if opts['ignore_case']:
1494 if opts['ignore_case']:
1491 reflags |= re.I
1495 reflags |= re.I
1492 regexp = re.compile(pattern, reflags)
1496 regexp = re.compile(pattern, reflags)
1493 sep, eol = ':', '\n'
1497 sep, eol = ':', '\n'
1494 if opts['print0']:
1498 if opts['print0']:
1495 sep = eol = '\0'
1499 sep = eol = '\0'
1496
1500
1497 fcache = {}
1501 fcache = {}
1498 def getfile(fn):
1502 def getfile(fn):
1499 if fn not in fcache:
1503 if fn not in fcache:
1500 fcache[fn] = repo.file(fn)
1504 fcache[fn] = repo.file(fn)
1501 return fcache[fn]
1505 return fcache[fn]
1502
1506
1503 def matchlines(body):
1507 def matchlines(body):
1504 begin = 0
1508 begin = 0
1505 linenum = 0
1509 linenum = 0
1506 while True:
1510 while True:
1507 match = regexp.search(body, begin)
1511 match = regexp.search(body, begin)
1508 if not match:
1512 if not match:
1509 break
1513 break
1510 mstart, mend = match.span()
1514 mstart, mend = match.span()
1511 linenum += body.count('\n', begin, mstart) + 1
1515 linenum += body.count('\n', begin, mstart) + 1
1512 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1516 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1513 lend = body.find('\n', mend)
1517 lend = body.find('\n', mend)
1514 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1518 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1515 begin = lend + 1
1519 begin = lend + 1
1516
1520
1517 class linestate(object):
1521 class linestate(object):
1518 def __init__(self, line, linenum, colstart, colend):
1522 def __init__(self, line, linenum, colstart, colend):
1519 self.line = line
1523 self.line = line
1520 self.linenum = linenum
1524 self.linenum = linenum
1521 self.colstart = colstart
1525 self.colstart = colstart
1522 self.colend = colend
1526 self.colend = colend
1523 def __eq__(self, other):
1527 def __eq__(self, other):
1524 return self.line == other.line
1528 return self.line == other.line
1525 def __hash__(self):
1529 def __hash__(self):
1526 return hash(self.line)
1530 return hash(self.line)
1527
1531
1528 matches = {}
1532 matches = {}
1529 def grepbody(fn, rev, body):
1533 def grepbody(fn, rev, body):
1530 matches[rev].setdefault(fn, {})
1534 matches[rev].setdefault(fn, {})
1531 m = matches[rev][fn]
1535 m = matches[rev][fn]
1532 for lnum, cstart, cend, line in matchlines(body):
1536 for lnum, cstart, cend, line in matchlines(body):
1533 s = linestate(line, lnum, cstart, cend)
1537 s = linestate(line, lnum, cstart, cend)
1534 m[s] = s
1538 m[s] = s
1535
1539
1536 # FIXME: prev isn't used, why ?
1540 # FIXME: prev isn't used, why ?
1537 prev = {}
1541 prev = {}
1538 ucache = {}
1542 ucache = {}
1539 def display(fn, rev, states, prevstates):
1543 def display(fn, rev, states, prevstates):
1540 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1544 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1541 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1545 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1542 counts = {'-': 0, '+': 0}
1546 counts = {'-': 0, '+': 0}
1543 filerevmatches = {}
1547 filerevmatches = {}
1544 for l in diff:
1548 for l in diff:
1545 if incrementing or not opts['all']:
1549 if incrementing or not opts['all']:
1546 change = ((l in prevstates) and '-') or '+'
1550 change = ((l in prevstates) and '-') or '+'
1547 r = rev
1551 r = rev
1548 else:
1552 else:
1549 change = ((l in states) and '-') or '+'
1553 change = ((l in states) and '-') or '+'
1550 r = prev[fn]
1554 r = prev[fn]
1551 cols = [fn, str(rev)]
1555 cols = [fn, str(rev)]
1552 if opts['line_number']:
1556 if opts['line_number']:
1553 cols.append(str(l.linenum))
1557 cols.append(str(l.linenum))
1554 if opts['all']:
1558 if opts['all']:
1555 cols.append(change)
1559 cols.append(change)
1556 if opts['user']:
1560 if opts['user']:
1557 cols.append(trimuser(ui, getchange(rev)[1], rev,
1561 cols.append(trimuser(ui, getchange(rev)[1], rev,
1558 ucache))
1562 ucache))
1559 if opts['files_with_matches']:
1563 if opts['files_with_matches']:
1560 c = (fn, rev)
1564 c = (fn, rev)
1561 if c in filerevmatches:
1565 if c in filerevmatches:
1562 continue
1566 continue
1563 filerevmatches[c] = 1
1567 filerevmatches[c] = 1
1564 else:
1568 else:
1565 cols.append(l.line)
1569 cols.append(l.line)
1566 ui.write(sep.join(cols), eol)
1570 ui.write(sep.join(cols), eol)
1567 counts[change] += 1
1571 counts[change] += 1
1568 return counts['+'], counts['-']
1572 return counts['+'], counts['-']
1569
1573
1570 fstate = {}
1574 fstate = {}
1571 skip = {}
1575 skip = {}
1572 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1576 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1573 count = 0
1577 count = 0
1574 incrementing = False
1578 incrementing = False
1575 for st, rev, fns in changeiter:
1579 for st, rev, fns in changeiter:
1576 if st == 'window':
1580 if st == 'window':
1577 incrementing = rev
1581 incrementing = rev
1578 matches.clear()
1582 matches.clear()
1579 elif st == 'add':
1583 elif st == 'add':
1580 change = repo.changelog.read(repo.lookup(str(rev)))
1584 change = repo.changelog.read(repo.lookup(str(rev)))
1581 mf = repo.manifest.read(change[0])
1585 mf = repo.manifest.read(change[0])
1582 matches[rev] = {}
1586 matches[rev] = {}
1583 for fn in fns:
1587 for fn in fns:
1584 if fn in skip:
1588 if fn in skip:
1585 continue
1589 continue
1586 fstate.setdefault(fn, {})
1590 fstate.setdefault(fn, {})
1587 try:
1591 try:
1588 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1592 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1589 except KeyError:
1593 except KeyError:
1590 pass
1594 pass
1591 elif st == 'iter':
1595 elif st == 'iter':
1592 states = matches[rev].items()
1596 states = matches[rev].items()
1593 states.sort()
1597 states.sort()
1594 for fn, m in states:
1598 for fn, m in states:
1595 if fn in skip:
1599 if fn in skip:
1596 continue
1600 continue
1597 if incrementing or not opts['all'] or fstate[fn]:
1601 if incrementing or not opts['all'] or fstate[fn]:
1598 pos, neg = display(fn, rev, m, fstate[fn])
1602 pos, neg = display(fn, rev, m, fstate[fn])
1599 count += pos + neg
1603 count += pos + neg
1600 if pos and not opts['all']:
1604 if pos and not opts['all']:
1601 skip[fn] = True
1605 skip[fn] = True
1602 fstate[fn] = m
1606 fstate[fn] = m
1603 prev[fn] = rev
1607 prev[fn] = rev
1604
1608
1605 if not incrementing:
1609 if not incrementing:
1606 fstate = fstate.items()
1610 fstate = fstate.items()
1607 fstate.sort()
1611 fstate.sort()
1608 for fn, state in fstate:
1612 for fn, state in fstate:
1609 if fn in skip:
1613 if fn in skip:
1610 continue
1614 continue
1611 display(fn, rev, {}, state)
1615 display(fn, rev, {}, state)
1612 return (count == 0 and 1) or 0
1616 return (count == 0 and 1) or 0
1613
1617
1614 def heads(ui, repo, **opts):
1618 def heads(ui, repo, **opts):
1615 """show current repository heads
1619 """show current repository heads
1616
1620
1617 Show all repository head changesets.
1621 Show all repository head changesets.
1618
1622
1619 Repository "heads" are changesets that don't have children
1623 Repository "heads" are changesets that don't have children
1620 changesets. They are where development generally takes place and
1624 changesets. They are where development generally takes place and
1621 are the usual targets for update and merge operations.
1625 are the usual targets for update and merge operations.
1622 """
1626 """
1623 if opts['rev']:
1627 if opts['rev']:
1624 heads = repo.heads(repo.lookup(opts['rev']))
1628 heads = repo.heads(repo.lookup(opts['rev']))
1625 else:
1629 else:
1626 heads = repo.heads()
1630 heads = repo.heads()
1627 br = None
1631 br = None
1628 if opts['branches']:
1632 if opts['branches']:
1629 br = repo.branchlookup(heads)
1633 br = repo.branchlookup(heads)
1630 displayer = show_changeset(ui, repo, opts)
1634 displayer = show_changeset(ui, repo, opts)
1631 for n in heads:
1635 for n in heads:
1632 displayer.show(changenode=n, brinfo=br)
1636 displayer.show(changenode=n, brinfo=br)
1633
1637
1634 def identify(ui, repo):
1638 def identify(ui, repo):
1635 """print information about the working copy
1639 """print information about the working copy
1636
1640
1637 Print a short summary of the current state of the repo.
1641 Print a short summary of the current state of the repo.
1638
1642
1639 This summary identifies the repository state using one or two parent
1643 This summary identifies the repository state using one or two parent
1640 hash identifiers, followed by a "+" if there are uncommitted changes
1644 hash identifiers, followed by a "+" if there are uncommitted changes
1641 in the working directory, followed by a list of tags for this revision.
1645 in the working directory, followed by a list of tags for this revision.
1642 """
1646 """
1643 parents = [p for p in repo.dirstate.parents() if p != nullid]
1647 parents = [p for p in repo.dirstate.parents() if p != nullid]
1644 if not parents:
1648 if not parents:
1645 ui.write(_("unknown\n"))
1649 ui.write(_("unknown\n"))
1646 return
1650 return
1647
1651
1648 hexfunc = ui.verbose and hex or short
1652 hexfunc = ui.verbose and hex or short
1649 modified, added, removed, deleted, unknown = repo.changes()
1653 modified, added, removed, deleted, unknown = repo.changes()
1650 output = ["%s%s" %
1654 output = ["%s%s" %
1651 ('+'.join([hexfunc(parent) for parent in parents]),
1655 ('+'.join([hexfunc(parent) for parent in parents]),
1652 (modified or added or removed or deleted) and "+" or "")]
1656 (modified or added or removed or deleted) and "+" or "")]
1653
1657
1654 if not ui.quiet:
1658 if not ui.quiet:
1655 # multiple tags for a single parent separated by '/'
1659 # multiple tags for a single parent separated by '/'
1656 parenttags = ['/'.join(tags)
1660 parenttags = ['/'.join(tags)
1657 for tags in map(repo.nodetags, parents) if tags]
1661 for tags in map(repo.nodetags, parents) if tags]
1658 # tags for multiple parents separated by ' + '
1662 # tags for multiple parents separated by ' + '
1659 if parenttags:
1663 if parenttags:
1660 output.append(' + '.join(parenttags))
1664 output.append(' + '.join(parenttags))
1661
1665
1662 ui.write("%s\n" % ' '.join(output))
1666 ui.write("%s\n" % ' '.join(output))
1663
1667
1664 def import_(ui, repo, patch1, *patches, **opts):
1668 def import_(ui, repo, patch1, *patches, **opts):
1665 """import an ordered set of patches
1669 """import an ordered set of patches
1666
1670
1667 Import a list of patches and commit them individually.
1671 Import a list of patches and commit them individually.
1668
1672
1669 If there are outstanding changes in the working directory, import
1673 If there are outstanding changes in the working directory, import
1670 will abort unless given the -f flag.
1674 will abort unless given the -f flag.
1671
1675
1672 If a patch looks like a mail message (its first line starts with
1676 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
1677 "From " or looks like an RFC822 header), it will not be applied
1674 unless the -f option is used. The importer neither parses nor
1678 unless the -f option is used. The importer neither parses nor
1675 discards mail headers, so use -f only to override the "mailness"
1679 discards mail headers, so use -f only to override the "mailness"
1676 safety check, not to import a real mail message.
1680 safety check, not to import a real mail message.
1677 """
1681 """
1678 patches = (patch1,) + patches
1682 patches = (patch1,) + patches
1679
1683
1680 if not opts['force']:
1684 if not opts['force']:
1681 modified, added, removed, deleted, unknown = repo.changes()
1685 modified, added, removed, deleted, unknown = repo.changes()
1682 if modified or added or removed or deleted:
1686 if modified or added or removed or deleted:
1683 raise util.Abort(_("outstanding uncommitted changes"))
1687 raise util.Abort(_("outstanding uncommitted changes"))
1684
1688
1685 d = opts["base"]
1689 d = opts["base"]
1686 strip = opts["strip"]
1690 strip = opts["strip"]
1687
1691
1688 mailre = re.compile(r'(?:From |[\w-]+:)')
1692 mailre = re.compile(r'(?:From |[\w-]+:)')
1689
1693
1690 # attempt to detect the start of a patch
1694 # attempt to detect the start of a patch
1691 # (this heuristic is borrowed from quilt)
1695 # (this heuristic is borrowed from quilt)
1692 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1696 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1693 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1697 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1694 '(---|\*\*\*)[ \t])')
1698 '(---|\*\*\*)[ \t])')
1695
1699
1696 for patch in patches:
1700 for patch in patches:
1697 ui.status(_("applying %s\n") % patch)
1701 ui.status(_("applying %s\n") % patch)
1698 pf = os.path.join(d, patch)
1702 pf = os.path.join(d, patch)
1699
1703
1700 message = []
1704 message = []
1701 user = None
1705 user = None
1702 hgpatch = False
1706 hgpatch = False
1703 for line in file(pf):
1707 for line in file(pf):
1704 line = line.rstrip()
1708 line = line.rstrip()
1705 if (not message and not hgpatch and
1709 if (not message and not hgpatch and
1706 mailre.match(line) and not opts['force']):
1710 mailre.match(line) and not opts['force']):
1707 if len(line) > 35:
1711 if len(line) > 35:
1708 line = line[:32] + '...'
1712 line = line[:32] + '...'
1709 raise util.Abort(_('first line looks like a '
1713 raise util.Abort(_('first line looks like a '
1710 'mail header: ') + line)
1714 'mail header: ') + line)
1711 if diffre.match(line):
1715 if diffre.match(line):
1712 break
1716 break
1713 elif hgpatch:
1717 elif hgpatch:
1714 # parse values when importing the result of an hg export
1718 # parse values when importing the result of an hg export
1715 if line.startswith("# User "):
1719 if line.startswith("# User "):
1716 user = line[7:]
1720 user = line[7:]
1717 ui.debug(_('User: %s\n') % user)
1721 ui.debug(_('User: %s\n') % user)
1718 elif not line.startswith("# ") and line:
1722 elif not line.startswith("# ") and line:
1719 message.append(line)
1723 message.append(line)
1720 hgpatch = False
1724 hgpatch = False
1721 elif line == '# HG changeset patch':
1725 elif line == '# HG changeset patch':
1722 hgpatch = True
1726 hgpatch = True
1723 message = [] # We may have collected garbage
1727 message = [] # We may have collected garbage
1724 else:
1728 else:
1725 message.append(line)
1729 message.append(line)
1726
1730
1727 # make sure message isn't empty
1731 # make sure message isn't empty
1728 if not message:
1732 if not message:
1729 message = _("imported patch %s\n") % patch
1733 message = _("imported patch %s\n") % patch
1730 else:
1734 else:
1731 message = "%s\n" % '\n'.join(message)
1735 message = "%s\n" % '\n'.join(message)
1732 ui.debug(_('message:\n%s\n') % message)
1736 ui.debug(_('message:\n%s\n') % message)
1733
1737
1734 files = util.patch(strip, pf, ui)
1738 files = util.patch(strip, pf, ui)
1735
1739
1736 if len(files) > 0:
1740 if len(files) > 0:
1737 addremove(ui, repo, *files)
1741 addremove(ui, repo, *files)
1738 repo.commit(files, message, user)
1742 repo.commit(files, message, user)
1739
1743
1740 def incoming(ui, repo, source="default", **opts):
1744 def incoming(ui, repo, source="default", **opts):
1741 """show new changesets found in source
1745 """show new changesets found in source
1742
1746
1743 Show new changesets found in the specified repo or the default
1747 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
1748 pull repo. These are the changesets that would be pulled if a pull
1745 was requested.
1749 was requested.
1746
1750
1747 Currently only local repositories are supported.
1751 Currently only local repositories are supported.
1748 """
1752 """
1749 source = ui.expandpath(source)
1753 source = ui.expandpath(source)
1750 other = hg.repository(ui, source)
1754 other = hg.repository(ui, source)
1751 if not other.local():
1755 if not other.local():
1752 raise util.Abort(_("incoming doesn't work for remote repositories yet"))
1756 raise util.Abort(_("incoming doesn't work for remote repositories yet"))
1753 o = repo.findincoming(other)
1757 o = repo.findincoming(other)
1754 if not o:
1758 if not o:
1755 return
1759 return
1756 o = other.changelog.nodesbetween(o)[0]
1760 o = other.changelog.nodesbetween(o)[0]
1757 if opts['newest_first']:
1761 if opts['newest_first']:
1758 o.reverse()
1762 o.reverse()
1759 displayer = show_changeset(ui, other, opts)
1763 displayer = show_changeset(ui, other, opts)
1760 for n in o:
1764 for n in o:
1761 parents = [p for p in other.changelog.parents(n) if p != nullid]
1765 parents = [p for p in other.changelog.parents(n) if p != nullid]
1762 if opts['no_merges'] and len(parents) == 2:
1766 if opts['no_merges'] and len(parents) == 2:
1763 continue
1767 continue
1764 displayer.show(changenode=n)
1768 displayer.show(changenode=n)
1765 if opts['patch']:
1769 if opts['patch']:
1766 prev = (parents and parents[0]) or nullid
1770 prev = (parents and parents[0]) or nullid
1767 dodiff(ui, ui, other, prev, n)
1771 dodiff(ui, ui, other, prev, n)
1768 ui.write("\n")
1772 ui.write("\n")
1769
1773
1770 def init(ui, dest="."):
1774 def init(ui, dest="."):
1771 """create a new repository in the given directory
1775 """create a new repository in the given directory
1772
1776
1773 Initialize a new repository in the given directory. If the given
1777 Initialize a new repository in the given directory. If the given
1774 directory does not exist, it is created.
1778 directory does not exist, it is created.
1775
1779
1776 If no directory is given, the current directory is used.
1780 If no directory is given, the current directory is used.
1777 """
1781 """
1778 if not os.path.exists(dest):
1782 if not os.path.exists(dest):
1779 os.mkdir(dest)
1783 os.mkdir(dest)
1780 hg.repository(ui, dest, create=1)
1784 hg.repository(ui, dest, create=1)
1781
1785
1782 def locate(ui, repo, *pats, **opts):
1786 def locate(ui, repo, *pats, **opts):
1783 """locate files matching specific patterns
1787 """locate files matching specific patterns
1784
1788
1785 Print all files under Mercurial control whose names match the
1789 Print all files under Mercurial control whose names match the
1786 given patterns.
1790 given patterns.
1787
1791
1788 This command searches the current directory and its
1792 This command searches the current directory and its
1789 subdirectories. To search an entire repository, move to the root
1793 subdirectories. To search an entire repository, move to the root
1790 of the repository.
1794 of the repository.
1791
1795
1792 If no patterns are given to match, this command prints all file
1796 If no patterns are given to match, this command prints all file
1793 names.
1797 names.
1794
1798
1795 If you want to feed the output of this command into the "xargs"
1799 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".
1800 command, use the "-0" option to both this command and "xargs".
1797 This will avoid the problem of "xargs" treating single filenames
1801 This will avoid the problem of "xargs" treating single filenames
1798 that contain white space as multiple filenames.
1802 that contain white space as multiple filenames.
1799 """
1803 """
1800 end = opts['print0'] and '\0' or '\n'
1804 end = opts['print0'] and '\0' or '\n'
1801 rev = opts['rev']
1805 rev = opts['rev']
1802 if rev:
1806 if rev:
1803 node = repo.lookup(rev)
1807 node = repo.lookup(rev)
1804 else:
1808 else:
1805 node = None
1809 node = None
1806
1810
1807 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
1811 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
1808 head='(?:.*/|)'):
1812 head='(?:.*/|)'):
1809 if not node and repo.dirstate.state(abs) == '?':
1813 if not node and repo.dirstate.state(abs) == '?':
1810 continue
1814 continue
1811 if opts['fullpath']:
1815 if opts['fullpath']:
1812 ui.write(os.path.join(repo.root, abs), end)
1816 ui.write(os.path.join(repo.root, abs), end)
1813 else:
1817 else:
1814 ui.write(((pats and rel) or abs), end)
1818 ui.write(((pats and rel) or abs), end)
1815
1819
1816 def log(ui, repo, *pats, **opts):
1820 def log(ui, repo, *pats, **opts):
1817 """show revision history of entire repository or files
1821 """show revision history of entire repository or files
1818
1822
1819 Print the revision history of the specified files or the entire project.
1823 Print the revision history of the specified files or the entire project.
1820
1824
1821 By default this command outputs: changeset id and hash, tags,
1825 By default this command outputs: changeset id and hash, tags,
1822 non-trivial parents, user, date and time, and a summary for each
1826 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
1827 commit. When the -v/--verbose switch is used, the list of changed
1824 files and full commit message is shown.
1828 files and full commit message is shown.
1825 """
1829 """
1826 class dui(object):
1830 class dui(object):
1827 # Implement and delegate some ui protocol. Save hunks of
1831 # Implement and delegate some ui protocol. Save hunks of
1828 # output for later display in the desired order.
1832 # output for later display in the desired order.
1829 def __init__(self, ui):
1833 def __init__(self, ui):
1830 self.ui = ui
1834 self.ui = ui
1831 self.hunk = {}
1835 self.hunk = {}
1832 def bump(self, rev):
1836 def bump(self, rev):
1833 self.rev = rev
1837 self.rev = rev
1834 self.hunk[rev] = []
1838 self.hunk[rev] = []
1835 def note(self, *args):
1839 def note(self, *args):
1836 if self.verbose:
1840 if self.verbose:
1837 self.write(*args)
1841 self.write(*args)
1838 def status(self, *args):
1842 def status(self, *args):
1839 if not self.quiet:
1843 if not self.quiet:
1840 self.write(*args)
1844 self.write(*args)
1841 def write(self, *args):
1845 def write(self, *args):
1842 self.hunk[self.rev].append(args)
1846 self.hunk[self.rev].append(args)
1843 def debug(self, *args):
1847 def debug(self, *args):
1844 if self.debugflag:
1848 if self.debugflag:
1845 self.write(*args)
1849 self.write(*args)
1846 def __getattr__(self, key):
1850 def __getattr__(self, key):
1847 return getattr(self.ui, key)
1851 return getattr(self.ui, key)
1848
1852
1849 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1853 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1850
1854
1851 if opts['limit']:
1855 if opts['limit']:
1852 try:
1856 try:
1853 limit = int(opts['limit'])
1857 limit = int(opts['limit'])
1854 except ValueError:
1858 except ValueError:
1855 raise util.Abort(_('limit must be a positive integer'))
1859 raise util.Abort(_('limit must be a positive integer'))
1856 if limit <= 0: raise util.Abort(_('limit must be positive'))
1860 if limit <= 0: raise util.Abort(_('limit must be positive'))
1857 else:
1861 else:
1858 limit = sys.maxint
1862 limit = sys.maxint
1859 count = 0
1863 count = 0
1860
1864
1861 displayer = show_changeset(ui, repo, opts)
1865 displayer = show_changeset(ui, repo, opts)
1862 for st, rev, fns in changeiter:
1866 for st, rev, fns in changeiter:
1863 if st == 'window':
1867 if st == 'window':
1864 du = dui(ui)
1868 du = dui(ui)
1865 displayer.ui = du
1869 displayer.ui = du
1866 elif st == 'add':
1870 elif st == 'add':
1867 du.bump(rev)
1871 du.bump(rev)
1868 changenode = repo.changelog.node(rev)
1872 changenode = repo.changelog.node(rev)
1869 parents = [p for p in repo.changelog.parents(changenode)
1873 parents = [p for p in repo.changelog.parents(changenode)
1870 if p != nullid]
1874 if p != nullid]
1871 if opts['no_merges'] and len(parents) == 2:
1875 if opts['no_merges'] and len(parents) == 2:
1872 continue
1876 continue
1873 if opts['only_merges'] and len(parents) != 2:
1877 if opts['only_merges'] and len(parents) != 2:
1874 continue
1878 continue
1875
1879
1876 if opts['keyword']:
1880 if opts['keyword']:
1877 changes = getchange(rev)
1881 changes = getchange(rev)
1878 miss = 0
1882 miss = 0
1879 for k in [kw.lower() for kw in opts['keyword']]:
1883 for k in [kw.lower() for kw in opts['keyword']]:
1880 if not (k in changes[1].lower() or
1884 if not (k in changes[1].lower() or
1881 k in changes[4].lower() or
1885 k in changes[4].lower() or
1882 k in " ".join(changes[3][:20]).lower()):
1886 k in " ".join(changes[3][:20]).lower()):
1883 miss = 1
1887 miss = 1
1884 break
1888 break
1885 if miss:
1889 if miss:
1886 continue
1890 continue
1887
1891
1888 br = None
1892 br = None
1889 if opts['branches']:
1893 if opts['branches']:
1890 br = repo.branchlookup([repo.changelog.node(rev)])
1894 br = repo.branchlookup([repo.changelog.node(rev)])
1891
1895
1892 displayer.show(rev, brinfo=br)
1896 displayer.show(rev, brinfo=br)
1893 if opts['patch']:
1897 if opts['patch']:
1894 prev = (parents and parents[0]) or nullid
1898 prev = (parents and parents[0]) or nullid
1895 dodiff(du, du, repo, prev, changenode, match=matchfn)
1899 dodiff(du, du, repo, prev, changenode, match=matchfn)
1896 du.write("\n\n")
1900 du.write("\n\n")
1897 elif st == 'iter':
1901 elif st == 'iter':
1898 if count == limit: break
1902 if count == limit: break
1899 if du.hunk[rev]:
1903 if du.hunk[rev]:
1900 count += 1
1904 count += 1
1901 for args in du.hunk[rev]:
1905 for args in du.hunk[rev]:
1902 ui.write(*args)
1906 ui.write(*args)
1903
1907
1904 def manifest(ui, repo, rev=None):
1908 def manifest(ui, repo, rev=None):
1905 """output the latest or given revision of the project manifest
1909 """output the latest or given revision of the project manifest
1906
1910
1907 Print a list of version controlled files for the given revision.
1911 Print a list of version controlled files for the given revision.
1908
1912
1909 The manifest is the list of files being version controlled. If no revision
1913 The manifest is the list of files being version controlled. If no revision
1910 is given then the tip is used.
1914 is given then the tip is used.
1911 """
1915 """
1912 if rev:
1916 if rev:
1913 try:
1917 try:
1914 # assume all revision numbers are for changesets
1918 # assume all revision numbers are for changesets
1915 n = repo.lookup(rev)
1919 n = repo.lookup(rev)
1916 change = repo.changelog.read(n)
1920 change = repo.changelog.read(n)
1917 n = change[0]
1921 n = change[0]
1918 except hg.RepoError:
1922 except hg.RepoError:
1919 n = repo.manifest.lookup(rev)
1923 n = repo.manifest.lookup(rev)
1920 else:
1924 else:
1921 n = repo.manifest.tip()
1925 n = repo.manifest.tip()
1922 m = repo.manifest.read(n)
1926 m = repo.manifest.read(n)
1923 mf = repo.manifest.readflags(n)
1927 mf = repo.manifest.readflags(n)
1924 files = m.keys()
1928 files = m.keys()
1925 files.sort()
1929 files.sort()
1926
1930
1927 for f in files:
1931 for f in files:
1928 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1932 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1929
1933
1930 def outgoing(ui, repo, dest="default-push", **opts):
1934 def outgoing(ui, repo, dest="default-push", **opts):
1931 """show changesets not found in destination
1935 """show changesets not found in destination
1932
1936
1933 Show changesets not found in the specified destination repo or the
1937 Show changesets not found in the specified destination repo or the
1934 default push repo. These are the changesets that would be pushed
1938 default push repo. These are the changesets that would be pushed
1935 if a push was requested.
1939 if a push was requested.
1936
1940
1937 See pull for valid source format details.
1941 See pull for valid source format details.
1938 """
1942 """
1939 dest = ui.expandpath(dest)
1943 dest = ui.expandpath(dest)
1940 other = hg.repository(ui, dest)
1944 other = hg.repository(ui, dest)
1941 o = repo.findoutgoing(other)
1945 o = repo.findoutgoing(other)
1942 o = repo.changelog.nodesbetween(o)[0]
1946 o = repo.changelog.nodesbetween(o)[0]
1943 if opts['newest_first']:
1947 if opts['newest_first']:
1944 o.reverse()
1948 o.reverse()
1945 displayer = show_changeset(ui, repo, opts)
1949 displayer = show_changeset(ui, repo, opts)
1946 for n in o:
1950 for n in o:
1947 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1951 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1948 if opts['no_merges'] and len(parents) == 2:
1952 if opts['no_merges'] and len(parents) == 2:
1949 continue
1953 continue
1950 displayer.show(changenode=n)
1954 displayer.show(changenode=n)
1951 if opts['patch']:
1955 if opts['patch']:
1952 prev = (parents and parents[0]) or nullid
1956 prev = (parents and parents[0]) or nullid
1953 dodiff(ui, ui, repo, prev, n)
1957 dodiff(ui, ui, repo, prev, n)
1954 ui.write("\n")
1958 ui.write("\n")
1955
1959
1956 def parents(ui, repo, rev=None, branches=None, **opts):
1960 def parents(ui, repo, rev=None, branches=None, **opts):
1957 """show the parents of the working dir or revision
1961 """show the parents of the working dir or revision
1958
1962
1959 Print the working directory's parent revisions.
1963 Print the working directory's parent revisions.
1960 """
1964 """
1961 if rev:
1965 if rev:
1962 p = repo.changelog.parents(repo.lookup(rev))
1966 p = repo.changelog.parents(repo.lookup(rev))
1963 else:
1967 else:
1964 p = repo.dirstate.parents()
1968 p = repo.dirstate.parents()
1965
1969
1966 br = None
1970 br = None
1967 if branches is not None:
1971 if branches is not None:
1968 br = repo.branchlookup(p)
1972 br = repo.branchlookup(p)
1969 displayer = show_changeset(ui, repo, opts)
1973 displayer = show_changeset(ui, repo, opts)
1970 for n in p:
1974 for n in p:
1971 if n != nullid:
1975 if n != nullid:
1972 displayer.show(changenode=n, brinfo=br)
1976 displayer.show(changenode=n, brinfo=br)
1973
1977
1974 def paths(ui, repo, search=None):
1978 def paths(ui, repo, search=None):
1975 """show definition of symbolic path names
1979 """show definition of symbolic path names
1976
1980
1977 Show definition of symbolic path name NAME. If no name is given, show
1981 Show definition of symbolic path name NAME. If no name is given, show
1978 definition of available names.
1982 definition of available names.
1979
1983
1980 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1984 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.
1985 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1982 """
1986 """
1983 if search:
1987 if search:
1984 for name, path in ui.configitems("paths"):
1988 for name, path in ui.configitems("paths"):
1985 if name == search:
1989 if name == search:
1986 ui.write("%s\n" % path)
1990 ui.write("%s\n" % path)
1987 return
1991 return
1988 ui.warn(_("not found!\n"))
1992 ui.warn(_("not found!\n"))
1989 return 1
1993 return 1
1990 else:
1994 else:
1991 for name, path in ui.configitems("paths"):
1995 for name, path in ui.configitems("paths"):
1992 ui.write("%s = %s\n" % (name, path))
1996 ui.write("%s = %s\n" % (name, path))
1993
1997
1994 def pull(ui, repo, source="default", **opts):
1998 def pull(ui, repo, source="default", **opts):
1995 """pull changes from the specified source
1999 """pull changes from the specified source
1996
2000
1997 Pull changes from a remote repository to a local one.
2001 Pull changes from a remote repository to a local one.
1998
2002
1999 This finds all changes from the repository at the specified path
2003 This finds all changes from the repository at the specified path
2000 or URL and adds them to the local repository. By default, this
2004 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.
2005 does not update the copy of the project in the working directory.
2002
2006
2003 Valid URLs are of the form:
2007 Valid URLs are of the form:
2004
2008
2005 local/filesystem/path
2009 local/filesystem/path
2006 http://[user@]host[:port][/path]
2010 http://[user@]host[:port][/path]
2007 https://[user@]host[:port][/path]
2011 https://[user@]host[:port][/path]
2008 ssh://[user@]host[:port][/path]
2012 ssh://[user@]host[:port][/path]
2009
2013
2010 SSH requires an accessible shell account on the destination machine
2014 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
2015 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
2016 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.
2017 the start of a path to specify it as relative to the filesystem root.
2014 """
2018 """
2015 source = ui.expandpath(source)
2019 source = ui.expandpath(source)
2016 ui.status(_('pulling from %s\n') % (source))
2020 ui.status(_('pulling from %s\n') % (source))
2017
2021
2018 if opts['ssh']:
2022 if opts['ssh']:
2019 ui.setconfig("ui", "ssh", opts['ssh'])
2023 ui.setconfig("ui", "ssh", opts['ssh'])
2020 if opts['remotecmd']:
2024 if opts['remotecmd']:
2021 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
2025 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
2022
2026
2023 other = hg.repository(ui, source)
2027 other = hg.repository(ui, source)
2024 revs = None
2028 revs = None
2025 if opts['rev'] and not other.local():
2029 if opts['rev'] and not other.local():
2026 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2030 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2027 elif opts['rev']:
2031 elif opts['rev']:
2028 revs = [other.lookup(rev) for rev in opts['rev']]
2032 revs = [other.lookup(rev) for rev in opts['rev']]
2029 r = repo.pull(other, heads=revs)
2033 r = repo.pull(other, heads=revs)
2030 if not r:
2034 if not r:
2031 if opts['update']:
2035 if opts['update']:
2032 return update(ui, repo)
2036 return update(ui, repo)
2033 else:
2037 else:
2034 ui.status(_("(run 'hg update' to get a working copy)\n"))
2038 ui.status(_("(run 'hg update' to get a working copy)\n"))
2035
2039
2036 return r
2040 return r
2037
2041
2038 def push(ui, repo, dest="default-push", **opts):
2042 def push(ui, repo, dest="default-push", **opts):
2039 """push changes to the specified destination
2043 """push changes to the specified destination
2040
2044
2041 Push changes from the local repository to the given destination.
2045 Push changes from the local repository to the given destination.
2042
2046
2043 This is the symmetrical operation for pull. It helps to move
2047 This is the symmetrical operation for pull. It helps to move
2044 changes from the current repository to a different one. If the
2048 changes from the current repository to a different one. If the
2045 destination is local this is identical to a pull in that directory
2049 destination is local this is identical to a pull in that directory
2046 from the current one.
2050 from the current one.
2047
2051
2048 By default, push will refuse to run if it detects the result would
2052 By default, push will refuse to run if it detects the result would
2049 increase the number of remote heads. This generally indicates the
2053 increase the number of remote heads. This generally indicates the
2050 the client has forgotten to sync and merge before pushing.
2054 the client has forgotten to sync and merge before pushing.
2051
2055
2052 Valid URLs are of the form:
2056 Valid URLs are of the form:
2053
2057
2054 local/filesystem/path
2058 local/filesystem/path
2055 ssh://[user@]host[:port][/path]
2059 ssh://[user@]host[:port][/path]
2056
2060
2057 SSH requires an accessible shell account on the destination
2061 SSH requires an accessible shell account on the destination
2058 machine and a copy of hg in the remote path.
2062 machine and a copy of hg in the remote path.
2059 """
2063 """
2060 dest = ui.expandpath(dest)
2064 dest = ui.expandpath(dest)
2061 ui.status('pushing to %s\n' % (dest))
2065 ui.status('pushing to %s\n' % (dest))
2062
2066
2063 if opts['ssh']:
2067 if opts['ssh']:
2064 ui.setconfig("ui", "ssh", opts['ssh'])
2068 ui.setconfig("ui", "ssh", opts['ssh'])
2065 if opts['remotecmd']:
2069 if opts['remotecmd']:
2066 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
2070 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
2067
2071
2068 other = hg.repository(ui, dest)
2072 other = hg.repository(ui, dest)
2069 revs = None
2073 revs = None
2070 if opts['rev']:
2074 if opts['rev']:
2071 revs = [repo.lookup(rev) for rev in opts['rev']]
2075 revs = [repo.lookup(rev) for rev in opts['rev']]
2072 r = repo.push(other, opts['force'], revs=revs)
2076 r = repo.push(other, opts['force'], revs=revs)
2073 return r
2077 return r
2074
2078
2075 def rawcommit(ui, repo, *flist, **rc):
2079 def rawcommit(ui, repo, *flist, **rc):
2076 """raw commit interface (DEPRECATED)
2080 """raw commit interface (DEPRECATED)
2077
2081
2078 (DEPRECATED)
2082 (DEPRECATED)
2079 Lowlevel commit, for use in helper scripts.
2083 Lowlevel commit, for use in helper scripts.
2080
2084
2081 This command is not intended to be used by normal users, as it is
2085 This command is not intended to be used by normal users, as it is
2082 primarily useful for importing from other SCMs.
2086 primarily useful for importing from other SCMs.
2083
2087
2084 This command is now deprecated and will be removed in a future
2088 This command is now deprecated and will be removed in a future
2085 release, please use debugsetparents and commit instead.
2089 release, please use debugsetparents and commit instead.
2086 """
2090 """
2087
2091
2088 ui.warn(_("(the rawcommit command is deprecated)\n"))
2092 ui.warn(_("(the rawcommit command is deprecated)\n"))
2089
2093
2090 message = rc['message']
2094 message = rc['message']
2091 if not message and rc['logfile']:
2095 if not message and rc['logfile']:
2092 try:
2096 try:
2093 message = open(rc['logfile']).read()
2097 message = open(rc['logfile']).read()
2094 except IOError:
2098 except IOError:
2095 pass
2099 pass
2096 if not message and not rc['logfile']:
2100 if not message and not rc['logfile']:
2097 raise util.Abort(_("missing commit message"))
2101 raise util.Abort(_("missing commit message"))
2098
2102
2099 files = relpath(repo, list(flist))
2103 files = relpath(repo, list(flist))
2100 if rc['files']:
2104 if rc['files']:
2101 files += open(rc['files']).read().splitlines()
2105 files += open(rc['files']).read().splitlines()
2102
2106
2103 rc['parent'] = map(repo.lookup, rc['parent'])
2107 rc['parent'] = map(repo.lookup, rc['parent'])
2104
2108
2105 try:
2109 try:
2106 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2110 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2107 except ValueError, inst:
2111 except ValueError, inst:
2108 raise util.Abort(str(inst))
2112 raise util.Abort(str(inst))
2109
2113
2110 def recover(ui, repo):
2114 def recover(ui, repo):
2111 """roll back an interrupted transaction
2115 """roll back an interrupted transaction
2112
2116
2113 Recover from an interrupted commit or pull.
2117 Recover from an interrupted commit or pull.
2114
2118
2115 This command tries to fix the repository status after an interrupted
2119 This command tries to fix the repository status after an interrupted
2116 operation. It should only be necessary when Mercurial suggests it.
2120 operation. It should only be necessary when Mercurial suggests it.
2117 """
2121 """
2118 if repo.recover():
2122 if repo.recover():
2119 return repo.verify()
2123 return repo.verify()
2120 return False
2124 return False
2121
2125
2122 def remove(ui, repo, pat, *pats, **opts):
2126 def remove(ui, repo, pat, *pats, **opts):
2123 """remove the specified files on the next commit
2127 """remove the specified files on the next commit
2124
2128
2125 Schedule the indicated files for removal from the repository.
2129 Schedule the indicated files for removal from the repository.
2126
2130
2127 This command schedules the files to be removed at the next commit.
2131 This command schedules the files to be removed at the next commit.
2128 This only removes files from the current branch, not from the
2132 This only removes files from the current branch, not from the
2129 entire project history. If the files still exist in the working
2133 entire project history. If the files still exist in the working
2130 directory, they will be deleted from it.
2134 directory, they will be deleted from it.
2131 """
2135 """
2132 names = []
2136 names = []
2133 def okaytoremove(abs, rel, exact):
2137 def okaytoremove(abs, rel, exact):
2134 modified, added, removed, deleted, unknown = repo.changes(files=[abs])
2138 modified, added, removed, deleted, unknown = repo.changes(files=[abs])
2135 reason = None
2139 reason = None
2136 if modified and not opts['force']:
2140 if modified and not opts['force']:
2137 reason = _('is modified')
2141 reason = _('is modified')
2138 elif added:
2142 elif added:
2139 reason = _('has been marked for add')
2143 reason = _('has been marked for add')
2140 elif unknown:
2144 elif unknown:
2141 reason = _('is not managed')
2145 reason = _('is not managed')
2142 if reason:
2146 if reason:
2143 if exact:
2147 if exact:
2144 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2148 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2145 else:
2149 else:
2146 return True
2150 return True
2147 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
2151 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
2148 if okaytoremove(abs, rel, exact):
2152 if okaytoremove(abs, rel, exact):
2149 if ui.verbose or not exact:
2153 if ui.verbose or not exact:
2150 ui.status(_('removing %s\n') % rel)
2154 ui.status(_('removing %s\n') % rel)
2151 names.append(abs)
2155 names.append(abs)
2152 repo.remove(names, unlink=True)
2156 repo.remove(names, unlink=True)
2153
2157
2154 def rename(ui, repo, *pats, **opts):
2158 def rename(ui, repo, *pats, **opts):
2155 """rename files; equivalent of copy + remove
2159 """rename files; equivalent of copy + remove
2156
2160
2157 Mark dest as copies of sources; mark sources for deletion. If
2161 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
2162 dest is a directory, copies are put in that directory. If dest is
2159 a file, there can only be one source.
2163 a file, there can only be one source.
2160
2164
2161 By default, this command copies the contents of files as they
2165 By default, this command copies the contents of files as they
2162 stand in the working directory. If invoked with --after, the
2166 stand in the working directory. If invoked with --after, the
2163 operation is recorded, but no copying is performed.
2167 operation is recorded, but no copying is performed.
2164
2168
2165 This command takes effect in the next commit.
2169 This command takes effect in the next commit.
2166
2170
2167 NOTE: This command should be treated as experimental. While it
2171 NOTE: This command should be treated as experimental. While it
2168 should properly record rename files, this information is not yet
2172 should properly record rename files, this information is not yet
2169 fully used by merge, nor fully reported by log.
2173 fully used by merge, nor fully reported by log.
2170 """
2174 """
2171 try:
2175 try:
2172 wlock = repo.wlock(0)
2176 wlock = repo.wlock(0)
2173 errs, copied = docopy(ui, repo, pats, opts, wlock)
2177 errs, copied = docopy(ui, repo, pats, opts, wlock)
2174 names = []
2178 names = []
2175 for abs, rel, exact in copied:
2179 for abs, rel, exact in copied:
2176 if ui.verbose or not exact:
2180 if ui.verbose or not exact:
2177 ui.status(_('removing %s\n') % rel)
2181 ui.status(_('removing %s\n') % rel)
2178 names.append(abs)
2182 names.append(abs)
2179 repo.remove(names, True, wlock)
2183 repo.remove(names, True, wlock)
2180 except lock.LockHeld, inst:
2184 except lock.LockHeld, inst:
2181 ui.warn(_("repository lock held by %s\n") % inst.args[0])
2185 ui.warn(_("repository lock held by %s\n") % inst.args[0])
2182 errs = 1
2186 errs = 1
2183 return errs
2187 return errs
2184
2188
2185 def revert(ui, repo, *pats, **opts):
2189 def revert(ui, repo, *pats, **opts):
2186 """revert modified files or dirs back to their unmodified states
2190 """revert modified files or dirs back to their unmodified states
2187
2191
2188 In its default mode, it reverts any uncommitted modifications made
2192 In its default mode, it reverts any uncommitted modifications made
2189 to the named files or directories. This restores the contents of
2193 to the named files or directories. This restores the contents of
2190 the affected files to an unmodified state.
2194 the affected files to an unmodified state.
2191
2195
2192 Using the -r option, it reverts the given files or directories to
2196 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
2197 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.
2198 back" some or all of a change that should not have been committed.
2195
2199
2196 Revert modifies the working directory. It does not commit any
2200 Revert modifies the working directory. It does not commit any
2197 changes, or change the parent of the current working directory.
2201 changes, or change the parent of the current working directory.
2198
2202
2199 If a file has been deleted, it is recreated. If the executable
2203 If a file has been deleted, it is recreated. If the executable
2200 mode of a file was changed, it is reset.
2204 mode of a file was changed, it is reset.
2201
2205
2202 If names are given, all files matching the names are reverted.
2206 If names are given, all files matching the names are reverted.
2203
2207
2204 If no arguments are given, all files in the repository are reverted.
2208 If no arguments are given, all files in the repository are reverted.
2205 """
2209 """
2206 node = opts['rev'] and repo.lookup(opts['rev']) or \
2210 node = opts['rev'] and repo.lookup(opts['rev']) or \
2207 repo.dirstate.parents()[0]
2211 repo.dirstate.parents()[0]
2208
2212
2209 files, choose, anypats = matchpats(repo, pats, opts)
2213 files, choose, anypats = matchpats(repo, pats, opts)
2210 modified, added, removed, deleted, unknown = repo.changes(match=choose)
2214 modified, added, removed, deleted, unknown = repo.changes(match=choose)
2211 repo.forget(added)
2215 repo.forget(added)
2212 repo.undelete(removed)
2216 repo.undelete(removed)
2213
2217
2214 return repo.update(node, False, True, choose, False)
2218 return repo.update(node, False, True, choose, False)
2215
2219
2216 def root(ui, repo):
2220 def root(ui, repo):
2217 """print the root (top) of the current working dir
2221 """print the root (top) of the current working dir
2218
2222
2219 Print the root directory of the current repository.
2223 Print the root directory of the current repository.
2220 """
2224 """
2221 ui.write(repo.root + "\n")
2225 ui.write(repo.root + "\n")
2222
2226
2223 def serve(ui, repo, **opts):
2227 def serve(ui, repo, **opts):
2224 """export the repository via HTTP
2228 """export the repository via HTTP
2225
2229
2226 Start a local HTTP repository browser and pull server.
2230 Start a local HTTP repository browser and pull server.
2227
2231
2228 By default, the server logs accesses to stdout and errors to
2232 By default, the server logs accesses to stdout and errors to
2229 stderr. Use the "-A" and "-E" options to log to files.
2233 stderr. Use the "-A" and "-E" options to log to files.
2230 """
2234 """
2231
2235
2232 if opts["stdio"]:
2236 if opts["stdio"]:
2233 fin, fout = sys.stdin, sys.stdout
2237 fin, fout = sys.stdin, sys.stdout
2234 sys.stdout = sys.stderr
2238 sys.stdout = sys.stderr
2235
2239
2236 # Prevent insertion/deletion of CRs
2240 # Prevent insertion/deletion of CRs
2237 util.set_binary(fin)
2241 util.set_binary(fin)
2238 util.set_binary(fout)
2242 util.set_binary(fout)
2239
2243
2240 def getarg():
2244 def getarg():
2241 argline = fin.readline()[:-1]
2245 argline = fin.readline()[:-1]
2242 arg, l = argline.split()
2246 arg, l = argline.split()
2243 val = fin.read(int(l))
2247 val = fin.read(int(l))
2244 return arg, val
2248 return arg, val
2245 def respond(v):
2249 def respond(v):
2246 fout.write("%d\n" % len(v))
2250 fout.write("%d\n" % len(v))
2247 fout.write(v)
2251 fout.write(v)
2248 fout.flush()
2252 fout.flush()
2249
2253
2250 lock = None
2254 lock = None
2251
2255
2252 while 1:
2256 while 1:
2253 cmd = fin.readline()[:-1]
2257 cmd = fin.readline()[:-1]
2254 if cmd == '':
2258 if cmd == '':
2255 return
2259 return
2256 if cmd == "heads":
2260 if cmd == "heads":
2257 h = repo.heads()
2261 h = repo.heads()
2258 respond(" ".join(map(hex, h)) + "\n")
2262 respond(" ".join(map(hex, h)) + "\n")
2259 if cmd == "lock":
2263 if cmd == "lock":
2260 lock = repo.lock()
2264 lock = repo.lock()
2261 respond("")
2265 respond("")
2262 if cmd == "unlock":
2266 if cmd == "unlock":
2263 if lock:
2267 if lock:
2264 lock.release()
2268 lock.release()
2265 lock = None
2269 lock = None
2266 respond("")
2270 respond("")
2267 elif cmd == "branches":
2271 elif cmd == "branches":
2268 arg, nodes = getarg()
2272 arg, nodes = getarg()
2269 nodes = map(bin, nodes.split(" "))
2273 nodes = map(bin, nodes.split(" "))
2270 r = []
2274 r = []
2271 for b in repo.branches(nodes):
2275 for b in repo.branches(nodes):
2272 r.append(" ".join(map(hex, b)) + "\n")
2276 r.append(" ".join(map(hex, b)) + "\n")
2273 respond("".join(r))
2277 respond("".join(r))
2274 elif cmd == "between":
2278 elif cmd == "between":
2275 arg, pairs = getarg()
2279 arg, pairs = getarg()
2276 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
2280 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
2277 r = []
2281 r = []
2278 for b in repo.between(pairs):
2282 for b in repo.between(pairs):
2279 r.append(" ".join(map(hex, b)) + "\n")
2283 r.append(" ".join(map(hex, b)) + "\n")
2280 respond("".join(r))
2284 respond("".join(r))
2281 elif cmd == "changegroup":
2285 elif cmd == "changegroup":
2282 nodes = []
2286 nodes = []
2283 arg, roots = getarg()
2287 arg, roots = getarg()
2284 nodes = map(bin, roots.split(" "))
2288 nodes = map(bin, roots.split(" "))
2285
2289
2286 cg = repo.changegroup(nodes, 'serve')
2290 cg = repo.changegroup(nodes, 'serve')
2287 while 1:
2291 while 1:
2288 d = cg.read(4096)
2292 d = cg.read(4096)
2289 if not d:
2293 if not d:
2290 break
2294 break
2291 fout.write(d)
2295 fout.write(d)
2292
2296
2293 fout.flush()
2297 fout.flush()
2294
2298
2295 elif cmd == "addchangegroup":
2299 elif cmd == "addchangegroup":
2296 if not lock:
2300 if not lock:
2297 respond("not locked")
2301 respond("not locked")
2298 continue
2302 continue
2299 respond("")
2303 respond("")
2300
2304
2301 r = repo.addchangegroup(fin)
2305 r = repo.addchangegroup(fin)
2302 respond("")
2306 respond("")
2303
2307
2304 optlist = "name templates style address port ipv6 accesslog errorlog"
2308 optlist = "name templates style address port ipv6 accesslog errorlog"
2305 for o in optlist.split():
2309 for o in optlist.split():
2306 if opts[o]:
2310 if opts[o]:
2307 ui.setconfig("web", o, opts[o])
2311 ui.setconfig("web", o, opts[o])
2308
2312
2309 if opts['daemon'] and not opts['daemon_pipefds']:
2313 if opts['daemon'] and not opts['daemon_pipefds']:
2310 rfd, wfd = os.pipe()
2314 rfd, wfd = os.pipe()
2311 args = sys.argv[:]
2315 args = sys.argv[:]
2312 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2316 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2313 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2317 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2314 args[0], args)
2318 args[0], args)
2315 os.close(wfd)
2319 os.close(wfd)
2316 os.read(rfd, 1)
2320 os.read(rfd, 1)
2317 os._exit(0)
2321 os._exit(0)
2318
2322
2319 try:
2323 try:
2320 httpd = hgweb.create_server(repo)
2324 httpd = hgweb.create_server(repo)
2321 except socket.error, inst:
2325 except socket.error, inst:
2322 raise util.Abort(_('cannot start server: ') + inst.args[1])
2326 raise util.Abort(_('cannot start server: ') + inst.args[1])
2323
2327
2324 if ui.verbose:
2328 if ui.verbose:
2325 addr, port = httpd.socket.getsockname()
2329 addr, port = httpd.socket.getsockname()
2326 if addr == '0.0.0.0':
2330 if addr == '0.0.0.0':
2327 addr = socket.gethostname()
2331 addr = socket.gethostname()
2328 else:
2332 else:
2329 try:
2333 try:
2330 addr = socket.gethostbyaddr(addr)[0]
2334 addr = socket.gethostbyaddr(addr)[0]
2331 except socket.error:
2335 except socket.error:
2332 pass
2336 pass
2333 if port != 80:
2337 if port != 80:
2334 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2338 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2335 else:
2339 else:
2336 ui.status(_('listening at http://%s/\n') % addr)
2340 ui.status(_('listening at http://%s/\n') % addr)
2337
2341
2338 if opts['pid_file']:
2342 if opts['pid_file']:
2339 fp = open(opts['pid_file'], 'w')
2343 fp = open(opts['pid_file'], 'w')
2340 fp.write(str(os.getpid()))
2344 fp.write(str(os.getpid()))
2341 fp.close()
2345 fp.close()
2342
2346
2343 if opts['daemon_pipefds']:
2347 if opts['daemon_pipefds']:
2344 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2348 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2345 os.close(rfd)
2349 os.close(rfd)
2346 os.write(wfd, 'y')
2350 os.write(wfd, 'y')
2347 os.close(wfd)
2351 os.close(wfd)
2348 sys.stdout.flush()
2352 sys.stdout.flush()
2349 sys.stderr.flush()
2353 sys.stderr.flush()
2350 fd = os.open(util.nulldev, os.O_RDWR)
2354 fd = os.open(util.nulldev, os.O_RDWR)
2351 if fd != 0: os.dup2(fd, 0)
2355 if fd != 0: os.dup2(fd, 0)
2352 if fd != 1: os.dup2(fd, 1)
2356 if fd != 1: os.dup2(fd, 1)
2353 if fd != 2: os.dup2(fd, 2)
2357 if fd != 2: os.dup2(fd, 2)
2354 if fd not in (0, 1, 2): os.close(fd)
2358 if fd not in (0, 1, 2): os.close(fd)
2355
2359
2356 httpd.serve_forever()
2360 httpd.serve_forever()
2357
2361
2358 def status(ui, repo, *pats, **opts):
2362 def status(ui, repo, *pats, **opts):
2359 """show changed files in the working directory
2363 """show changed files in the working directory
2360
2364
2361 Show changed files in the repository. If names are
2365 Show changed files in the repository. If names are
2362 given, only files that match are shown.
2366 given, only files that match are shown.
2363
2367
2364 The codes used to show the status of files are:
2368 The codes used to show the status of files are:
2365 M = modified
2369 M = modified
2366 A = added
2370 A = added
2367 R = removed
2371 R = removed
2368 ! = deleted, but still tracked
2372 ! = deleted, but still tracked
2369 ? = not tracked
2373 ? = not tracked
2370 """
2374 """
2371
2375
2372 files, matchfn, anypats = matchpats(repo, pats, opts)
2376 files, matchfn, anypats = matchpats(repo, pats, opts)
2373 cwd = (pats and repo.getcwd()) or ''
2377 cwd = (pats and repo.getcwd()) or ''
2374 modified, added, removed, deleted, unknown = [
2378 modified, added, removed, deleted, unknown = [
2375 [util.pathto(cwd, x) for x in n]
2379 [util.pathto(cwd, x) for x in n]
2376 for n in repo.changes(files=files, match=matchfn)]
2380 for n in repo.changes(files=files, match=matchfn)]
2377
2381
2378 changetypes = [(_('modified'), 'M', modified),
2382 changetypes = [(_('modified'), 'M', modified),
2379 (_('added'), 'A', added),
2383 (_('added'), 'A', added),
2380 (_('removed'), 'R', removed),
2384 (_('removed'), 'R', removed),
2381 (_('deleted'), '!', deleted),
2385 (_('deleted'), '!', deleted),
2382 (_('unknown'), '?', unknown)]
2386 (_('unknown'), '?', unknown)]
2383
2387
2384 end = opts['print0'] and '\0' or '\n'
2388 end = opts['print0'] and '\0' or '\n'
2385
2389
2386 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
2390 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
2387 or changetypes):
2391 or changetypes):
2388 if opts['no_status']:
2392 if opts['no_status']:
2389 format = "%%s%s" % end
2393 format = "%%s%s" % end
2390 else:
2394 else:
2391 format = "%s %%s%s" % (char, end);
2395 format = "%s %%s%s" % (char, end);
2392
2396
2393 for f in changes:
2397 for f in changes:
2394 ui.write(format % f)
2398 ui.write(format % f)
2395
2399
2396 def tag(ui, repo, name, rev_=None, **opts):
2400 def tag(ui, repo, name, rev_=None, **opts):
2397 """add a tag for the current tip or a given revision
2401 """add a tag for the current tip or a given revision
2398
2402
2399 Name a particular revision using <name>.
2403 Name a particular revision using <name>.
2400
2404
2401 Tags are used to name particular revisions of the repository and are
2405 Tags are used to name particular revisions of the repository and are
2402 very useful to compare different revision, to go back to significant
2406 very useful to compare different revision, to go back to significant
2403 earlier versions or to mark branch points as releases, etc.
2407 earlier versions or to mark branch points as releases, etc.
2404
2408
2405 If no revision is given, the tip is used.
2409 If no revision is given, the tip is used.
2406
2410
2407 To facilitate version control, distribution, and merging of tags,
2411 To facilitate version control, distribution, and merging of tags,
2408 they are stored as a file named ".hgtags" which is managed
2412 they are stored as a file named ".hgtags" which is managed
2409 similarly to other project files and can be hand-edited if
2413 similarly to other project files and can be hand-edited if
2410 necessary. The file '.hg/localtags' is used for local tags (not
2414 necessary. The file '.hg/localtags' is used for local tags (not
2411 shared among repositories).
2415 shared among repositories).
2412 """
2416 """
2413 if name == "tip":
2417 if name == "tip":
2414 raise util.Abort(_("the name 'tip' is reserved"))
2418 raise util.Abort(_("the name 'tip' is reserved"))
2415 if rev_ is not None:
2419 if rev_ is not None:
2416 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2420 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2417 "please use 'hg tag [-r REV] NAME' instead\n"))
2421 "please use 'hg tag [-r REV] NAME' instead\n"))
2418 if opts['rev']:
2422 if opts['rev']:
2419 raise util.Abort(_("use only one form to specify the revision"))
2423 raise util.Abort(_("use only one form to specify the revision"))
2420 if opts['rev']:
2424 if opts['rev']:
2421 rev_ = opts['rev']
2425 rev_ = opts['rev']
2422 if rev_:
2426 if rev_:
2423 r = hex(repo.lookup(rev_))
2427 r = hex(repo.lookup(rev_))
2424 else:
2428 else:
2425 r = hex(repo.changelog.tip())
2429 r = hex(repo.changelog.tip())
2426
2430
2427 disallowed = (revrangesep, '\r', '\n')
2431 disallowed = (revrangesep, '\r', '\n')
2428 for c in disallowed:
2432 for c in disallowed:
2429 if name.find(c) >= 0:
2433 if name.find(c) >= 0:
2430 raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
2434 raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
2431
2435
2432 repo.hook('pretag', throw=True, node=r, tag=name,
2436 repo.hook('pretag', throw=True, node=r, tag=name,
2433 local=int(not not opts['local']))
2437 local=int(not not opts['local']))
2434
2438
2435 if opts['local']:
2439 if opts['local']:
2436 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2440 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2437 repo.hook('tag', node=r, tag=name, local=1)
2441 repo.hook('tag', node=r, tag=name, local=1)
2438 return
2442 return
2439
2443
2440 for x in repo.changes():
2444 for x in repo.changes():
2441 if ".hgtags" in x:
2445 if ".hgtags" in x:
2442 raise util.Abort(_("working copy of .hgtags is changed "
2446 raise util.Abort(_("working copy of .hgtags is changed "
2443 "(please commit .hgtags manually)"))
2447 "(please commit .hgtags manually)"))
2444
2448
2445 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2449 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2446 if repo.dirstate.state(".hgtags") == '?':
2450 if repo.dirstate.state(".hgtags") == '?':
2447 repo.add([".hgtags"])
2451 repo.add([".hgtags"])
2448
2452
2449 message = (opts['message'] or
2453 message = (opts['message'] or
2450 _("Added tag %s for changeset %s") % (name, r))
2454 _("Added tag %s for changeset %s") % (name, r))
2451 try:
2455 try:
2452 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2456 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2453 repo.hook('tag', node=r, tag=name, local=0)
2457 repo.hook('tag', node=r, tag=name, local=0)
2454 except ValueError, inst:
2458 except ValueError, inst:
2455 raise util.Abort(str(inst))
2459 raise util.Abort(str(inst))
2456
2460
2457 def tags(ui, repo):
2461 def tags(ui, repo):
2458 """list repository tags
2462 """list repository tags
2459
2463
2460 List the repository tags.
2464 List the repository tags.
2461
2465
2462 This lists both regular and local tags.
2466 This lists both regular and local tags.
2463 """
2467 """
2464
2468
2465 l = repo.tagslist()
2469 l = repo.tagslist()
2466 l.reverse()
2470 l.reverse()
2467 for t, n in l:
2471 for t, n in l:
2468 try:
2472 try:
2469 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2473 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2470 except KeyError:
2474 except KeyError:
2471 r = " ?:?"
2475 r = " ?:?"
2472 ui.write("%-30s %s\n" % (t, r))
2476 ui.write("%-30s %s\n" % (t, r))
2473
2477
2474 def tip(ui, repo, **opts):
2478 def tip(ui, repo, **opts):
2475 """show the tip revision
2479 """show the tip revision
2476
2480
2477 Show the tip revision.
2481 Show the tip revision.
2478 """
2482 """
2479 n = repo.changelog.tip()
2483 n = repo.changelog.tip()
2480 br = None
2484 br = None
2481 if opts['branches']:
2485 if opts['branches']:
2482 br = repo.branchlookup([n])
2486 br = repo.branchlookup([n])
2483 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2487 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2484 if opts['patch']:
2488 if opts['patch']:
2485 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
2489 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
2486
2490
2487 def unbundle(ui, repo, fname, **opts):
2491 def unbundle(ui, repo, fname, **opts):
2488 """apply a changegroup file
2492 """apply a changegroup file
2489
2493
2490 Apply a compressed changegroup file generated by the bundle
2494 Apply a compressed changegroup file generated by the bundle
2491 command.
2495 command.
2492 """
2496 """
2493 f = urllib.urlopen(fname)
2497 f = urllib.urlopen(fname)
2494
2498
2495 if f.read(4) != "HG10":
2499 if f.read(4) != "HG10":
2496 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2500 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2497
2501
2498 def bzgenerator(f):
2502 def bzgenerator(f):
2499 zd = bz2.BZ2Decompressor()
2503 zd = bz2.BZ2Decompressor()
2500 for chunk in f:
2504 for chunk in f:
2501 yield zd.decompress(chunk)
2505 yield zd.decompress(chunk)
2502
2506
2503 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2507 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2504 if repo.addchangegroup(util.chunkbuffer(bzgen)):
2508 if repo.addchangegroup(util.chunkbuffer(bzgen)):
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