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