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