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