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