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