##// END OF EJS Templates
Add log -b to show the branch a specific revision lives in...
mason@suse.com -
r1238:6a4f1814 default
parent child Browse files
Show More
@@ -1,2068 +1,2072 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 demandload(globals(), "os re sys signal shutil imp urllib pdb")
10 demandload(globals(), "os re sys signal shutil imp urllib pdb")
11 demandload(globals(), "fancyopts ui hg util lock revlog")
11 demandload(globals(), "fancyopts ui hg util lock revlog")
12 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
12 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
13 demandload(globals(), "errno socket version struct atexit sets bz2")
13 demandload(globals(), "errno socket version struct atexit sets bz2")
14
14
15 class UnknownCommand(Exception):
15 class UnknownCommand(Exception):
16 """Exception raised if command is not in the command table."""
16 """Exception raised if command is not in the command table."""
17
17
18 def filterfiles(filters, files):
18 def filterfiles(filters, files):
19 l = [x for x in files if x in filters]
19 l = [x for x in files if x in filters]
20
20
21 for t in filters:
21 for t in filters:
22 if t and t[-1] != "/":
22 if t and t[-1] != "/":
23 t += "/"
23 t += "/"
24 l += [x for x in files if x.startswith(t)]
24 l += [x for x in files if x.startswith(t)]
25 return l
25 return l
26
26
27 def relpath(repo, args):
27 def relpath(repo, args):
28 cwd = repo.getcwd()
28 cwd = repo.getcwd()
29 if cwd:
29 if cwd:
30 return [util.normpath(os.path.join(cwd, x)) for x in args]
30 return [util.normpath(os.path.join(cwd, x)) for x in args]
31 return args
31 return args
32
32
33 def matchpats(repo, cwd, pats=[], opts={}, head=''):
33 def matchpats(repo, cwd, pats=[], opts={}, head=''):
34 return util.matcher(repo.root, cwd, pats or ['.'], opts.get('include'),
34 return util.matcher(repo.root, cwd, pats or ['.'], opts.get('include'),
35 opts.get('exclude'), head)
35 opts.get('exclude'), head)
36
36
37 def makewalk(repo, pats, opts, head=''):
37 def makewalk(repo, pats, opts, head=''):
38 cwd = repo.getcwd()
38 cwd = repo.getcwd()
39 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
39 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
40 exact = dict(zip(files, files))
40 exact = dict(zip(files, files))
41 def walk():
41 def walk():
42 for src, fn in repo.walk(files=files, match=matchfn):
42 for src, fn in repo.walk(files=files, match=matchfn):
43 yield src, fn, util.pathto(cwd, fn), fn in exact
43 yield src, fn, util.pathto(cwd, fn), fn in exact
44 return files, matchfn, walk()
44 return files, matchfn, walk()
45
45
46 def walk(repo, pats, opts, head=''):
46 def walk(repo, pats, opts, head=''):
47 files, matchfn, results = makewalk(repo, pats, opts, head)
47 files, matchfn, results = makewalk(repo, pats, opts, head)
48 for r in results:
48 for r in results:
49 yield r
49 yield r
50
50
51 def walkchangerevs(ui, repo, cwd, pats, opts):
51 def walkchangerevs(ui, repo, cwd, pats, opts):
52 '''Iterate over files and the revs they changed in.
52 '''Iterate over files and the revs they changed in.
53
53
54 Callers most commonly need to iterate backwards over the history
54 Callers most commonly need to iterate backwards over the history
55 it is interested in. Doing so has awful (quadratic-looking)
55 it is interested in. Doing so has awful (quadratic-looking)
56 performance, so we use iterators in a "windowed" way.
56 performance, so we use iterators in a "windowed" way.
57
57
58 We walk a window of revisions in the desired order. Within the
58 We walk a window of revisions in the desired order. Within the
59 window, we first walk forwards to gather data, then in the desired
59 window, we first walk forwards to gather data, then in the desired
60 order (usually backwards) to display it.
60 order (usually backwards) to display it.
61
61
62 This function returns an (iterator, getchange) pair. The
62 This function returns an (iterator, getchange) pair. The
63 getchange function returns the changelog entry for a numeric
63 getchange function returns the changelog entry for a numeric
64 revision. The iterator yields 3-tuples. They will be of one of
64 revision. The iterator yields 3-tuples. They will be of one of
65 the following forms:
65 the following forms:
66
66
67 "window", incrementing, lastrev: stepping through a window,
67 "window", incrementing, lastrev: stepping through a window,
68 positive if walking forwards through revs, last rev in the
68 positive if walking forwards through revs, last rev in the
69 sequence iterated over - use to reset state for the current window
69 sequence iterated over - use to reset state for the current window
70
70
71 "add", rev, fns: out-of-order traversal of the given file names
71 "add", rev, fns: out-of-order traversal of the given file names
72 fns, which changed during revision rev - use to gather data for
72 fns, which changed during revision rev - use to gather data for
73 possible display
73 possible display
74
74
75 "iter", rev, None: in-order traversal of the revs earlier iterated
75 "iter", rev, None: in-order traversal of the revs earlier iterated
76 over with "add" - use to display data'''
76 over with "add" - use to display data'''
77 cwd = repo.getcwd()
77 cwd = repo.getcwd()
78 if not pats and cwd:
78 if not pats and cwd:
79 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
79 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
80 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
80 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
81 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
81 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
82 pats, opts)
82 pats, opts)
83 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
83 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
84 wanted = {}
84 wanted = {}
85 slowpath = anypats
85 slowpath = anypats
86 window = 300
86 window = 300
87 fncache = {}
87 fncache = {}
88
88
89 chcache = {}
89 chcache = {}
90 def getchange(rev):
90 def getchange(rev):
91 ch = chcache.get(rev)
91 ch = chcache.get(rev)
92 if ch is None:
92 if ch is None:
93 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
93 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
94 return ch
94 return ch
95
95
96 if not slowpath and not files:
96 if not slowpath and not files:
97 # No files, no patterns. Display all revs.
97 # No files, no patterns. Display all revs.
98 wanted = dict(zip(revs, revs))
98 wanted = dict(zip(revs, revs))
99 if not slowpath:
99 if not slowpath:
100 # Only files, no patterns. Check the history of each file.
100 # Only files, no patterns. Check the history of each file.
101 def filerevgen(filelog):
101 def filerevgen(filelog):
102 for i in xrange(filelog.count() - 1, -1, -window):
102 for i in xrange(filelog.count() - 1, -1, -window):
103 revs = []
103 revs = []
104 for j in xrange(max(0, i - window), i + 1):
104 for j in xrange(max(0, i - window), i + 1):
105 revs.append(filelog.linkrev(filelog.node(j)))
105 revs.append(filelog.linkrev(filelog.node(j)))
106 revs.reverse()
106 revs.reverse()
107 for rev in revs:
107 for rev in revs:
108 yield rev
108 yield rev
109
109
110 minrev, maxrev = min(revs), max(revs)
110 minrev, maxrev = min(revs), max(revs)
111 for file in files:
111 for file in files:
112 filelog = repo.file(file)
112 filelog = repo.file(file)
113 # A zero count may be a directory or deleted file, so
113 # A zero count may be a directory or deleted file, so
114 # try to find matching entries on the slow path.
114 # try to find matching entries on the slow path.
115 if filelog.count() == 0:
115 if filelog.count() == 0:
116 slowpath = True
116 slowpath = True
117 break
117 break
118 for rev in filerevgen(filelog):
118 for rev in filerevgen(filelog):
119 if rev <= maxrev:
119 if rev <= maxrev:
120 if rev < minrev:
120 if rev < minrev:
121 break
121 break
122 fncache.setdefault(rev, [])
122 fncache.setdefault(rev, [])
123 fncache[rev].append(file)
123 fncache[rev].append(file)
124 wanted[rev] = 1
124 wanted[rev] = 1
125 if slowpath:
125 if slowpath:
126 # The slow path checks files modified in every changeset.
126 # The slow path checks files modified in every changeset.
127 def changerevgen():
127 def changerevgen():
128 for i in xrange(repo.changelog.count() - 1, -1, -window):
128 for i in xrange(repo.changelog.count() - 1, -1, -window):
129 for j in xrange(max(0, i - window), i + 1):
129 for j in xrange(max(0, i - window), i + 1):
130 yield j, getchange(j)[3]
130 yield j, getchange(j)[3]
131
131
132 for rev, changefiles in changerevgen():
132 for rev, changefiles in changerevgen():
133 matches = filter(matchfn, changefiles)
133 matches = filter(matchfn, changefiles)
134 if matches:
134 if matches:
135 fncache[rev] = matches
135 fncache[rev] = matches
136 wanted[rev] = 1
136 wanted[rev] = 1
137
137
138 def iterate():
138 def iterate():
139 for i in xrange(0, len(revs), window):
139 for i in xrange(0, len(revs), window):
140 yield 'window', revs[0] < revs[-1], revs[-1]
140 yield 'window', revs[0] < revs[-1], revs[-1]
141 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
141 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
142 if rev in wanted]
142 if rev in wanted]
143 srevs = list(nrevs)
143 srevs = list(nrevs)
144 srevs.sort()
144 srevs.sort()
145 for rev in srevs:
145 for rev in srevs:
146 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
146 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
147 yield 'add', rev, fns
147 yield 'add', rev, fns
148 for rev in nrevs:
148 for rev in nrevs:
149 yield 'iter', rev, None
149 yield 'iter', rev, None
150 return iterate(), getchange
150 return iterate(), getchange
151
151
152 revrangesep = ':'
152 revrangesep = ':'
153
153
154 def revrange(ui, repo, revs, revlog=None):
154 def revrange(ui, repo, revs, revlog=None):
155 """Yield revision as strings from a list of revision specifications."""
155 """Yield revision as strings from a list of revision specifications."""
156 if revlog is None:
156 if revlog is None:
157 revlog = repo.changelog
157 revlog = repo.changelog
158 revcount = revlog.count()
158 revcount = revlog.count()
159 def fix(val, defval):
159 def fix(val, defval):
160 if not val:
160 if not val:
161 return defval
161 return defval
162 try:
162 try:
163 num = int(val)
163 num = int(val)
164 if str(num) != val:
164 if str(num) != val:
165 raise ValueError
165 raise ValueError
166 if num < 0:
166 if num < 0:
167 num += revcount
167 num += revcount
168 if not (0 <= num < revcount):
168 if not (0 <= num < revcount):
169 raise ValueError
169 raise ValueError
170 except ValueError:
170 except ValueError:
171 try:
171 try:
172 num = repo.changelog.rev(repo.lookup(val))
172 num = repo.changelog.rev(repo.lookup(val))
173 except KeyError:
173 except KeyError:
174 try:
174 try:
175 num = revlog.rev(revlog.lookup(val))
175 num = revlog.rev(revlog.lookup(val))
176 except KeyError:
176 except KeyError:
177 raise util.Abort('invalid revision identifier %s', val)
177 raise util.Abort('invalid revision identifier %s', val)
178 return num
178 return num
179 seen = {}
179 seen = {}
180 for spec in revs:
180 for spec in revs:
181 if spec.find(revrangesep) >= 0:
181 if spec.find(revrangesep) >= 0:
182 start, end = spec.split(revrangesep, 1)
182 start, end = spec.split(revrangesep, 1)
183 start = fix(start, 0)
183 start = fix(start, 0)
184 end = fix(end, revcount - 1)
184 end = fix(end, revcount - 1)
185 step = start > end and -1 or 1
185 step = start > end and -1 or 1
186 for rev in xrange(start, end+step, step):
186 for rev in xrange(start, end+step, step):
187 if rev in seen: continue
187 if rev in seen: continue
188 seen[rev] = 1
188 seen[rev] = 1
189 yield str(rev)
189 yield str(rev)
190 else:
190 else:
191 rev = fix(spec, None)
191 rev = fix(spec, None)
192 if rev in seen: continue
192 if rev in seen: continue
193 seen[rev] = 1
193 seen[rev] = 1
194 yield str(rev)
194 yield str(rev)
195
195
196 def make_filename(repo, r, pat, node=None,
196 def make_filename(repo, r, pat, node=None,
197 total=None, seqno=None, revwidth=None):
197 total=None, seqno=None, revwidth=None):
198 node_expander = {
198 node_expander = {
199 'H': lambda: hex(node),
199 'H': lambda: hex(node),
200 'R': lambda: str(r.rev(node)),
200 'R': lambda: str(r.rev(node)),
201 'h': lambda: short(node),
201 'h': lambda: short(node),
202 }
202 }
203 expander = {
203 expander = {
204 '%': lambda: '%',
204 '%': lambda: '%',
205 'b': lambda: os.path.basename(repo.root),
205 'b': lambda: os.path.basename(repo.root),
206 }
206 }
207
207
208 try:
208 try:
209 if node:
209 if node:
210 expander.update(node_expander)
210 expander.update(node_expander)
211 if node and revwidth is not None:
211 if node and revwidth is not None:
212 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
212 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
213 if total is not None:
213 if total is not None:
214 expander['N'] = lambda: str(total)
214 expander['N'] = lambda: str(total)
215 if seqno is not None:
215 if seqno is not None:
216 expander['n'] = lambda: str(seqno)
216 expander['n'] = lambda: str(seqno)
217 if total is not None and seqno is not None:
217 if total is not None and seqno is not None:
218 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
218 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
219
219
220 newname = []
220 newname = []
221 patlen = len(pat)
221 patlen = len(pat)
222 i = 0
222 i = 0
223 while i < patlen:
223 while i < patlen:
224 c = pat[i]
224 c = pat[i]
225 if c == '%':
225 if c == '%':
226 i += 1
226 i += 1
227 c = pat[i]
227 c = pat[i]
228 c = expander[c]()
228 c = expander[c]()
229 newname.append(c)
229 newname.append(c)
230 i += 1
230 i += 1
231 return ''.join(newname)
231 return ''.join(newname)
232 except KeyError, inst:
232 except KeyError, inst:
233 raise util.Abort("invalid format spec '%%%s' in output file name",
233 raise util.Abort("invalid format spec '%%%s' in output file name",
234 inst.args[0])
234 inst.args[0])
235
235
236 def make_file(repo, r, pat, node=None,
236 def make_file(repo, r, pat, node=None,
237 total=None, seqno=None, revwidth=None, mode='wb'):
237 total=None, seqno=None, revwidth=None, mode='wb'):
238 if not pat or pat == '-':
238 if not pat or pat == '-':
239 return 'w' in mode and sys.stdout or sys.stdin
239 return 'w' in mode and sys.stdout or sys.stdin
240 if hasattr(pat, 'write') and 'w' in mode:
240 if hasattr(pat, 'write') and 'w' in mode:
241 return pat
241 return pat
242 if hasattr(pat, 'read') and 'r' in mode:
242 if hasattr(pat, 'read') and 'r' in mode:
243 return pat
243 return pat
244 return open(make_filename(repo, r, pat, node, total, seqno, revwidth),
244 return open(make_filename(repo, r, pat, node, total, seqno, revwidth),
245 mode)
245 mode)
246
246
247 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
247 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
248 changes=None, text=False):
248 changes=None, text=False):
249 def date(c):
249 def date(c):
250 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
250 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
251
251
252 if not changes:
252 if not changes:
253 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
253 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
254 else:
254 else:
255 (c, a, d, u) = changes
255 (c, a, d, u) = changes
256 if files:
256 if files:
257 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
257 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
258
258
259 if not c and not a and not d:
259 if not c and not a and not d:
260 return
260 return
261
261
262 if node2:
262 if node2:
263 change = repo.changelog.read(node2)
263 change = repo.changelog.read(node2)
264 mmap2 = repo.manifest.read(change[0])
264 mmap2 = repo.manifest.read(change[0])
265 date2 = date(change)
265 date2 = date(change)
266 def read(f):
266 def read(f):
267 return repo.file(f).read(mmap2[f])
267 return repo.file(f).read(mmap2[f])
268 else:
268 else:
269 date2 = time.asctime()
269 date2 = time.asctime()
270 if not node1:
270 if not node1:
271 node1 = repo.dirstate.parents()[0]
271 node1 = repo.dirstate.parents()[0]
272 def read(f):
272 def read(f):
273 return repo.wfile(f).read()
273 return repo.wfile(f).read()
274
274
275 if ui.quiet:
275 if ui.quiet:
276 r = None
276 r = None
277 else:
277 else:
278 hexfunc = ui.verbose and hex or short
278 hexfunc = ui.verbose and hex or short
279 r = [hexfunc(node) for node in [node1, node2] if node]
279 r = [hexfunc(node) for node in [node1, node2] if node]
280
280
281 change = repo.changelog.read(node1)
281 change = repo.changelog.read(node1)
282 mmap = repo.manifest.read(change[0])
282 mmap = repo.manifest.read(change[0])
283 date1 = date(change)
283 date1 = date(change)
284
284
285 for f in c:
285 for f in c:
286 to = None
286 to = None
287 if f in mmap:
287 if f in mmap:
288 to = repo.file(f).read(mmap[f])
288 to = repo.file(f).read(mmap[f])
289 tn = read(f)
289 tn = read(f)
290 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
290 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
291 for f in a:
291 for f in a:
292 to = None
292 to = None
293 tn = read(f)
293 tn = read(f)
294 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
294 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
295 for f in d:
295 for f in d:
296 to = repo.file(f).read(mmap[f])
296 to = repo.file(f).read(mmap[f])
297 tn = None
297 tn = None
298 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
298 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
299
299
300 def trimuser(ui, name, rev, revcache):
300 def trimuser(ui, name, rev, revcache):
301 """trim the name of the user who committed a change"""
301 """trim the name of the user who committed a change"""
302 user = revcache.get(rev)
302 user = revcache.get(rev)
303 if user is None:
303 if user is None:
304 user = revcache[rev] = ui.shortuser(name)
304 user = revcache[rev] = ui.shortuser(name)
305 return user
305 return user
306
306
307 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
307 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
308 """show a single changeset or file revision"""
308 """show a single changeset or file revision"""
309 log = repo.changelog
309 log = repo.changelog
310 if changenode is None:
310 if changenode is None:
311 changenode = log.node(rev)
311 changenode = log.node(rev)
312 elif not rev:
312 elif not rev:
313 rev = log.rev(changenode)
313 rev = log.rev(changenode)
314
314
315 if ui.quiet:
315 if ui.quiet:
316 ui.write("%d:%s\n" % (rev, short(changenode)))
316 ui.write("%d:%s\n" % (rev, short(changenode)))
317 return
317 return
318
318
319 changes = log.read(changenode)
319 changes = log.read(changenode)
320
320
321 t, tz = changes[2].split(' ')
321 t, tz = changes[2].split(' ')
322 # a conversion tool was sticking non-integer offsets into repos
322 # a conversion tool was sticking non-integer offsets into repos
323 try:
323 try:
324 tz = int(tz)
324 tz = int(tz)
325 except ValueError:
325 except ValueError:
326 tz = 0
326 tz = 0
327 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
327 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
328
328
329 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
329 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
330 for p in log.parents(changenode)
330 for p in log.parents(changenode)
331 if ui.debugflag or p != nullid]
331 if ui.debugflag or p != nullid]
332 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
332 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
333 parents = []
333 parents = []
334
334
335 if ui.verbose:
335 if ui.verbose:
336 ui.write("changeset: %d:%s\n" % (rev, hex(changenode)))
336 ui.write("changeset: %d:%s\n" % (rev, hex(changenode)))
337 else:
337 else:
338 ui.write("changeset: %d:%s\n" % (rev, short(changenode)))
338 ui.write("changeset: %d:%s\n" % (rev, short(changenode)))
339
339
340 for tag in repo.nodetags(changenode):
340 for tag in repo.nodetags(changenode):
341 ui.status("tag: %s\n" % tag)
341 ui.status("tag: %s\n" % tag)
342 for parent in parents:
342 for parent in parents:
343 ui.write("parent: %d:%s\n" % parent)
343 ui.write("parent: %d:%s\n" % parent)
344
344
345 if brinfo and changenode in brinfo:
345 if brinfo and changenode in brinfo:
346 br = brinfo[changenode]
346 br = brinfo[changenode]
347 ui.write("branch: %s\n" % " ".join(br))
347 ui.write("branch: %s\n" % " ".join(br))
348
348
349 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
349 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
350 hex(changes[0])))
350 hex(changes[0])))
351 ui.status("user: %s\n" % changes[1])
351 ui.status("user: %s\n" % changes[1])
352 ui.status("date: %s\n" % date)
352 ui.status("date: %s\n" % date)
353
353
354 if ui.debugflag:
354 if ui.debugflag:
355 files = repo.changes(log.parents(changenode)[0], changenode)
355 files = repo.changes(log.parents(changenode)[0], changenode)
356 for key, value in zip(["files:", "files+:", "files-:"], files):
356 for key, value in zip(["files:", "files+:", "files-:"], files):
357 if value:
357 if value:
358 ui.note("%-12s %s\n" % (key, " ".join(value)))
358 ui.note("%-12s %s\n" % (key, " ".join(value)))
359 else:
359 else:
360 ui.note("files: %s\n" % " ".join(changes[3]))
360 ui.note("files: %s\n" % " ".join(changes[3]))
361
361
362 description = changes[4].strip()
362 description = changes[4].strip()
363 if description:
363 if description:
364 if ui.verbose:
364 if ui.verbose:
365 ui.status("description:\n")
365 ui.status("description:\n")
366 ui.status(description)
366 ui.status(description)
367 ui.status("\n\n")
367 ui.status("\n\n")
368 else:
368 else:
369 ui.status("summary: %s\n" % description.splitlines()[0])
369 ui.status("summary: %s\n" % description.splitlines()[0])
370 ui.status("\n")
370 ui.status("\n")
371
371
372 def show_version(ui):
372 def show_version(ui):
373 """output version and copyright information"""
373 """output version and copyright information"""
374 ui.write("Mercurial Distributed SCM (version %s)\n"
374 ui.write("Mercurial Distributed SCM (version %s)\n"
375 % version.get_version())
375 % version.get_version())
376 ui.status(
376 ui.status(
377 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
377 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
378 "This is free software; see the source for copying conditions. "
378 "This is free software; see the source for copying conditions. "
379 "There is NO\nwarranty; "
379 "There is NO\nwarranty; "
380 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
380 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
381 )
381 )
382
382
383 def help_(ui, cmd=None, with_version=False):
383 def help_(ui, cmd=None, with_version=False):
384 """show help for a given command or all commands"""
384 """show help for a given command or all commands"""
385 option_lists = []
385 option_lists = []
386 if cmd and cmd != 'shortlist':
386 if cmd and cmd != 'shortlist':
387 if with_version:
387 if with_version:
388 show_version(ui)
388 show_version(ui)
389 ui.write('\n')
389 ui.write('\n')
390 key, i = find(cmd)
390 key, i = find(cmd)
391 # synopsis
391 # synopsis
392 ui.write("%s\n\n" % i[2])
392 ui.write("%s\n\n" % i[2])
393
393
394 # description
394 # description
395 doc = i[0].__doc__
395 doc = i[0].__doc__
396 if ui.quiet:
396 if ui.quiet:
397 doc = doc.splitlines(0)[0]
397 doc = doc.splitlines(0)[0]
398 ui.write("%s\n" % doc.rstrip())
398 ui.write("%s\n" % doc.rstrip())
399
399
400 if not ui.quiet:
400 if not ui.quiet:
401 # aliases
401 # aliases
402 aliases = ', '.join(key.split('|')[1:])
402 aliases = ', '.join(key.split('|')[1:])
403 if aliases:
403 if aliases:
404 ui.write("\naliases: %s\n" % aliases)
404 ui.write("\naliases: %s\n" % aliases)
405
405
406 # options
406 # options
407 if i[1]:
407 if i[1]:
408 option_lists.append(("options", i[1]))
408 option_lists.append(("options", i[1]))
409
409
410 else:
410 else:
411 # program name
411 # program name
412 if ui.verbose or with_version:
412 if ui.verbose or with_version:
413 show_version(ui)
413 show_version(ui)
414 else:
414 else:
415 ui.status("Mercurial Distributed SCM\n")
415 ui.status("Mercurial Distributed SCM\n")
416 ui.status('\n')
416 ui.status('\n')
417
417
418 # list of commands
418 # list of commands
419 if cmd == "shortlist":
419 if cmd == "shortlist":
420 ui.status('basic commands (use "hg help" '
420 ui.status('basic commands (use "hg help" '
421 'for the full list or option "-v" for details):\n\n')
421 'for the full list or option "-v" for details):\n\n')
422 elif ui.verbose:
422 elif ui.verbose:
423 ui.status('list of commands:\n\n')
423 ui.status('list of commands:\n\n')
424 else:
424 else:
425 ui.status('list of commands (use "hg help -v" '
425 ui.status('list of commands (use "hg help -v" '
426 'to show aliases and global options):\n\n')
426 'to show aliases and global options):\n\n')
427
427
428 h = {}
428 h = {}
429 cmds = {}
429 cmds = {}
430 for c, e in table.items():
430 for c, e in table.items():
431 f = c.split("|")[0]
431 f = c.split("|")[0]
432 if cmd == "shortlist" and not f.startswith("^"):
432 if cmd == "shortlist" and not f.startswith("^"):
433 continue
433 continue
434 f = f.lstrip("^")
434 f = f.lstrip("^")
435 if not ui.debugflag and f.startswith("debug"):
435 if not ui.debugflag and f.startswith("debug"):
436 continue
436 continue
437 d = ""
437 d = ""
438 if e[0].__doc__:
438 if e[0].__doc__:
439 d = e[0].__doc__.splitlines(0)[0].rstrip()
439 d = e[0].__doc__.splitlines(0)[0].rstrip()
440 h[f] = d
440 h[f] = d
441 cmds[f]=c.lstrip("^")
441 cmds[f]=c.lstrip("^")
442
442
443 fns = h.keys()
443 fns = h.keys()
444 fns.sort()
444 fns.sort()
445 m = max(map(len, fns))
445 m = max(map(len, fns))
446 for f in fns:
446 for f in fns:
447 if ui.verbose:
447 if ui.verbose:
448 commands = cmds[f].replace("|",", ")
448 commands = cmds[f].replace("|",", ")
449 ui.write(" %s:\n %s\n"%(commands,h[f]))
449 ui.write(" %s:\n %s\n"%(commands,h[f]))
450 else:
450 else:
451 ui.write(' %-*s %s\n' % (m, f, h[f]))
451 ui.write(' %-*s %s\n' % (m, f, h[f]))
452
452
453 # global options
453 # global options
454 if ui.verbose:
454 if ui.verbose:
455 option_lists.append(("global options", globalopts))
455 option_lists.append(("global options", globalopts))
456
456
457 # list all option lists
457 # list all option lists
458 opt_output = []
458 opt_output = []
459 for title, options in option_lists:
459 for title, options in option_lists:
460 opt_output.append(("\n%s:\n" % title, None))
460 opt_output.append(("\n%s:\n" % title, None))
461 for shortopt, longopt, default, desc in options:
461 for shortopt, longopt, default, desc in options:
462 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
462 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
463 longopt and " --%s" % longopt),
463 longopt and " --%s" % longopt),
464 "%s%s" % (desc,
464 "%s%s" % (desc,
465 default and " (default: %s)" % default
465 default and " (default: %s)" % default
466 or "")))
466 or "")))
467
467
468 if opt_output:
468 if opt_output:
469 opts_len = max([len(line[0]) for line in opt_output if line[1]])
469 opts_len = max([len(line[0]) for line in opt_output if line[1]])
470 for first, second in opt_output:
470 for first, second in opt_output:
471 if second:
471 if second:
472 ui.write(" %-*s %s\n" % (opts_len, first, second))
472 ui.write(" %-*s %s\n" % (opts_len, first, second))
473 else:
473 else:
474 ui.write("%s\n" % first)
474 ui.write("%s\n" % first)
475
475
476 # Commands start here, listed alphabetically
476 # Commands start here, listed alphabetically
477
477
478 def add(ui, repo, *pats, **opts):
478 def add(ui, repo, *pats, **opts):
479 '''add the specified files on the next commit'''
479 '''add the specified files on the next commit'''
480 names = []
480 names = []
481 for src, abs, rel, exact in walk(repo, pats, opts):
481 for src, abs, rel, exact in walk(repo, pats, opts):
482 if exact:
482 if exact:
483 names.append(abs)
483 names.append(abs)
484 elif repo.dirstate.state(abs) == '?':
484 elif repo.dirstate.state(abs) == '?':
485 ui.status('adding %s\n' % rel)
485 ui.status('adding %s\n' % rel)
486 names.append(abs)
486 names.append(abs)
487 repo.add(names)
487 repo.add(names)
488
488
489 def addremove(ui, repo, *pats, **opts):
489 def addremove(ui, repo, *pats, **opts):
490 """add all new files, delete all missing files"""
490 """add all new files, delete all missing files"""
491 add, remove = [], []
491 add, remove = [], []
492 for src, abs, rel, exact in walk(repo, pats, opts):
492 for src, abs, rel, exact in walk(repo, pats, opts):
493 if src == 'f' and repo.dirstate.state(abs) == '?':
493 if src == 'f' and repo.dirstate.state(abs) == '?':
494 add.append(abs)
494 add.append(abs)
495 if not exact:
495 if not exact:
496 ui.status('adding ', rel, '\n')
496 ui.status('adding ', rel, '\n')
497 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
497 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
498 remove.append(abs)
498 remove.append(abs)
499 if not exact:
499 if not exact:
500 ui.status('removing ', rel, '\n')
500 ui.status('removing ', rel, '\n')
501 repo.add(add)
501 repo.add(add)
502 repo.remove(remove)
502 repo.remove(remove)
503
503
504 def annotate(ui, repo, *pats, **opts):
504 def annotate(ui, repo, *pats, **opts):
505 """show changeset information per file line"""
505 """show changeset information per file line"""
506 def getnode(rev):
506 def getnode(rev):
507 return short(repo.changelog.node(rev))
507 return short(repo.changelog.node(rev))
508
508
509 ucache = {}
509 ucache = {}
510 def getname(rev):
510 def getname(rev):
511 cl = repo.changelog.read(repo.changelog.node(rev))
511 cl = repo.changelog.read(repo.changelog.node(rev))
512 return trimuser(ui, cl[1], rev, ucache)
512 return trimuser(ui, cl[1], rev, ucache)
513
513
514 if not pats:
514 if not pats:
515 raise util.Abort('at least one file name or pattern required')
515 raise util.Abort('at least one file name or pattern required')
516
516
517 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
517 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
518 if not opts['user'] and not opts['changeset']:
518 if not opts['user'] and not opts['changeset']:
519 opts['number'] = 1
519 opts['number'] = 1
520
520
521 if opts['rev']:
521 if opts['rev']:
522 node = repo.changelog.lookup(opts['rev'])
522 node = repo.changelog.lookup(opts['rev'])
523 else:
523 else:
524 node = repo.dirstate.parents()[0]
524 node = repo.dirstate.parents()[0]
525 change = repo.changelog.read(node)
525 change = repo.changelog.read(node)
526 mmap = repo.manifest.read(change[0])
526 mmap = repo.manifest.read(change[0])
527
527
528 for src, abs, rel, exact in walk(repo, pats, opts):
528 for src, abs, rel, exact in walk(repo, pats, opts):
529 if abs not in mmap:
529 if abs not in mmap:
530 ui.warn("warning: %s is not in the repository!\n" % rel)
530 ui.warn("warning: %s is not in the repository!\n" % rel)
531 continue
531 continue
532
532
533 f = repo.file(abs)
533 f = repo.file(abs)
534 if not opts['text'] and util.binary(f.read(mmap[abs])):
534 if not opts['text'] and util.binary(f.read(mmap[abs])):
535 ui.write("%s: binary file\n" % rel)
535 ui.write("%s: binary file\n" % rel)
536 continue
536 continue
537
537
538 lines = f.annotate(mmap[abs])
538 lines = f.annotate(mmap[abs])
539 pieces = []
539 pieces = []
540
540
541 for o, f in opmap:
541 for o, f in opmap:
542 if opts[o]:
542 if opts[o]:
543 l = [f(n) for n, dummy in lines]
543 l = [f(n) for n, dummy in lines]
544 if l:
544 if l:
545 m = max(map(len, l))
545 m = max(map(len, l))
546 pieces.append(["%*s" % (m, x) for x in l])
546 pieces.append(["%*s" % (m, x) for x in l])
547
547
548 if pieces:
548 if pieces:
549 for p, l in zip(zip(*pieces), lines):
549 for p, l in zip(zip(*pieces), lines):
550 ui.write("%s: %s" % (" ".join(p), l[1]))
550 ui.write("%s: %s" % (" ".join(p), l[1]))
551
551
552 def bundle(ui, repo, fname, dest="default-push", **opts):
552 def bundle(ui, repo, fname, dest="default-push", **opts):
553 """create a changegroup file"""
553 """create a changegroup file"""
554 f = open(fname, "wb")
554 f = open(fname, "wb")
555 dest = ui.expandpath(dest)
555 dest = ui.expandpath(dest)
556 other = hg.repository(ui, dest)
556 other = hg.repository(ui, dest)
557 o = repo.findoutgoing(other)
557 o = repo.findoutgoing(other)
558 cg = repo.changegroup(o)
558 cg = repo.changegroup(o)
559
559
560 try:
560 try:
561 f.write("HG10")
561 f.write("HG10")
562 z = bz2.BZ2Compressor(9)
562 z = bz2.BZ2Compressor(9)
563 while 1:
563 while 1:
564 chunk = cg.read(4096)
564 chunk = cg.read(4096)
565 if not chunk:
565 if not chunk:
566 break
566 break
567 f.write(z.compress(chunk))
567 f.write(z.compress(chunk))
568 f.write(z.flush())
568 f.write(z.flush())
569 except:
569 except:
570 os.unlink(fname)
570 os.unlink(fname)
571
571
572 def cat(ui, repo, file1, rev=None, **opts):
572 def cat(ui, repo, file1, rev=None, **opts):
573 """output the latest or given revision of a file"""
573 """output the latest or given revision of a file"""
574 r = repo.file(relpath(repo, [file1])[0])
574 r = repo.file(relpath(repo, [file1])[0])
575 if rev:
575 if rev:
576 try:
576 try:
577 # assume all revision numbers are for changesets
577 # assume all revision numbers are for changesets
578 n = repo.lookup(rev)
578 n = repo.lookup(rev)
579 change = repo.changelog.read(n)
579 change = repo.changelog.read(n)
580 m = repo.manifest.read(change[0])
580 m = repo.manifest.read(change[0])
581 n = m[relpath(repo, [file1])[0]]
581 n = m[relpath(repo, [file1])[0]]
582 except hg.RepoError, KeyError:
582 except hg.RepoError, KeyError:
583 n = r.lookup(rev)
583 n = r.lookup(rev)
584 else:
584 else:
585 n = r.tip()
585 n = r.tip()
586 fp = make_file(repo, r, opts['output'], node=n)
586 fp = make_file(repo, r, opts['output'], node=n)
587 fp.write(r.read(n))
587 fp.write(r.read(n))
588
588
589 def clone(ui, source, dest=None, **opts):
589 def clone(ui, source, dest=None, **opts):
590 """make a copy of an existing repository"""
590 """make a copy of an existing repository"""
591 if dest is None:
591 if dest is None:
592 dest = os.path.basename(os.path.normpath(source))
592 dest = os.path.basename(os.path.normpath(source))
593
593
594 if os.path.exists(dest):
594 if os.path.exists(dest):
595 raise util.Abort("destination '%s' already exists", dest)
595 raise util.Abort("destination '%s' already exists", dest)
596
596
597 dest = os.path.realpath(dest)
597 dest = os.path.realpath(dest)
598
598
599 class Dircleanup:
599 class Dircleanup:
600 def __init__(self, dir_):
600 def __init__(self, dir_):
601 self.rmtree = shutil.rmtree
601 self.rmtree = shutil.rmtree
602 self.dir_ = dir_
602 self.dir_ = dir_
603 os.mkdir(dir_)
603 os.mkdir(dir_)
604 def close(self):
604 def close(self):
605 self.dir_ = None
605 self.dir_ = None
606 def __del__(self):
606 def __del__(self):
607 if self.dir_:
607 if self.dir_:
608 self.rmtree(self.dir_, True)
608 self.rmtree(self.dir_, True)
609
609
610 if opts['ssh']:
610 if opts['ssh']:
611 ui.setconfig("ui", "ssh", opts['ssh'])
611 ui.setconfig("ui", "ssh", opts['ssh'])
612 if opts['remotecmd']:
612 if opts['remotecmd']:
613 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
613 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
614
614
615 d = Dircleanup(dest)
615 d = Dircleanup(dest)
616 if not os.path.exists(source):
616 if not os.path.exists(source):
617 source = ui.expandpath(source)
617 source = ui.expandpath(source)
618 abspath = source
618 abspath = source
619 other = hg.repository(ui, source)
619 other = hg.repository(ui, source)
620
620
621 if other.dev() != -1:
621 if other.dev() != -1:
622 abspath = os.path.abspath(source)
622 abspath = os.path.abspath(source)
623 copyfile = (os.stat(dest).st_dev == other.dev()
623 copyfile = (os.stat(dest).st_dev == other.dev()
624 and getattr(os, 'link', None) or shutil.copy2)
624 and getattr(os, 'link', None) or shutil.copy2)
625 if copyfile is not shutil.copy2:
625 if copyfile is not shutil.copy2:
626 ui.note("cloning by hardlink\n")
626 ui.note("cloning by hardlink\n")
627
627
628 # we use a lock here because if we race with commit, we can
628 # we use a lock here because if we race with commit, we can
629 # end up with extra data in the cloned revlogs that's not
629 # end up with extra data in the cloned revlogs that's not
630 # pointed to by changesets, thus causing verify to fail
630 # pointed to by changesets, thus causing verify to fail
631 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
631 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
632
632
633 # and here to avoid premature writing to the target
633 # and here to avoid premature writing to the target
634 os.mkdir(os.path.join(dest, ".hg"))
634 os.mkdir(os.path.join(dest, ".hg"))
635 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
635 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
636
636
637 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
637 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
638 for f in files.split():
638 for f in files.split():
639 src = os.path.join(source, ".hg", f)
639 src = os.path.join(source, ".hg", f)
640 dst = os.path.join(dest, ".hg", f)
640 dst = os.path.join(dest, ".hg", f)
641 util.copyfiles(src, dst, copyfile)
641 util.copyfiles(src, dst, copyfile)
642
642
643 repo = hg.repository(ui, dest)
643 repo = hg.repository(ui, dest)
644
644
645 else:
645 else:
646 repo = hg.repository(ui, dest, create=1)
646 repo = hg.repository(ui, dest, create=1)
647 repo.pull(other)
647 repo.pull(other)
648
648
649 f = repo.opener("hgrc", "w")
649 f = repo.opener("hgrc", "w")
650 f.write("[paths]\n")
650 f.write("[paths]\n")
651 f.write("default = %s\n" % abspath)
651 f.write("default = %s\n" % abspath)
652
652
653 if not opts['noupdate']:
653 if not opts['noupdate']:
654 update(ui, repo)
654 update(ui, repo)
655
655
656 d.close()
656 d.close()
657
657
658 def commit(ui, repo, *pats, **opts):
658 def commit(ui, repo, *pats, **opts):
659 """commit the specified files or all outstanding changes"""
659 """commit the specified files or all outstanding changes"""
660 if opts['text']:
660 if opts['text']:
661 ui.warn("Warning: -t and --text is deprecated,"
661 ui.warn("Warning: -t and --text is deprecated,"
662 " please use -m or --message instead.\n")
662 " please use -m or --message instead.\n")
663 message = opts['message'] or opts['text']
663 message = opts['message'] or opts['text']
664 logfile = opts['logfile']
664 logfile = opts['logfile']
665 if not message and logfile:
665 if not message and logfile:
666 try:
666 try:
667 if logfile == '-':
667 if logfile == '-':
668 message = sys.stdin.read()
668 message = sys.stdin.read()
669 else:
669 else:
670 message = open(logfile).read()
670 message = open(logfile).read()
671 except IOError, why:
671 except IOError, why:
672 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
672 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
673
673
674 if opts['addremove']:
674 if opts['addremove']:
675 addremove(ui, repo, *pats, **opts)
675 addremove(ui, repo, *pats, **opts)
676 cwd = repo.getcwd()
676 cwd = repo.getcwd()
677 if not pats and cwd:
677 if not pats and cwd:
678 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
678 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
679 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
679 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
680 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
680 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
681 pats, opts)
681 pats, opts)
682 if pats:
682 if pats:
683 c, a, d, u = repo.changes(files=fns, match=match)
683 c, a, d, u = repo.changes(files=fns, match=match)
684 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
684 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
685 else:
685 else:
686 files = []
686 files = []
687 try:
687 try:
688 repo.commit(files, message, opts['user'], opts['date'], match)
688 repo.commit(files, message, opts['user'], opts['date'], match)
689 except ValueError, inst:
689 except ValueError, inst:
690 raise util.Abort(str(inst))
690 raise util.Abort(str(inst))
691
691
692 def copy(ui, repo, source, dest):
692 def copy(ui, repo, source, dest):
693 """mark a file as copied or renamed for the next commit"""
693 """mark a file as copied or renamed for the next commit"""
694 return repo.copy(*relpath(repo, (source, dest)))
694 return repo.copy(*relpath(repo, (source, dest)))
695
695
696 def debugcheckstate(ui, repo):
696 def debugcheckstate(ui, repo):
697 """validate the correctness of the current dirstate"""
697 """validate the correctness of the current dirstate"""
698 parent1, parent2 = repo.dirstate.parents()
698 parent1, parent2 = repo.dirstate.parents()
699 repo.dirstate.read()
699 repo.dirstate.read()
700 dc = repo.dirstate.map
700 dc = repo.dirstate.map
701 keys = dc.keys()
701 keys = dc.keys()
702 keys.sort()
702 keys.sort()
703 m1n = repo.changelog.read(parent1)[0]
703 m1n = repo.changelog.read(parent1)[0]
704 m2n = repo.changelog.read(parent2)[0]
704 m2n = repo.changelog.read(parent2)[0]
705 m1 = repo.manifest.read(m1n)
705 m1 = repo.manifest.read(m1n)
706 m2 = repo.manifest.read(m2n)
706 m2 = repo.manifest.read(m2n)
707 errors = 0
707 errors = 0
708 for f in dc:
708 for f in dc:
709 state = repo.dirstate.state(f)
709 state = repo.dirstate.state(f)
710 if state in "nr" and f not in m1:
710 if state in "nr" and f not in m1:
711 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
711 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
712 errors += 1
712 errors += 1
713 if state in "a" and f in m1:
713 if state in "a" and f in m1:
714 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
714 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
715 errors += 1
715 errors += 1
716 if state in "m" and f not in m1 and f not in m2:
716 if state in "m" and f not in m1 and f not in m2:
717 ui.warn("%s in state %s, but not in either manifest\n" %
717 ui.warn("%s in state %s, but not in either manifest\n" %
718 (f, state))
718 (f, state))
719 errors += 1
719 errors += 1
720 for f in m1:
720 for f in m1:
721 state = repo.dirstate.state(f)
721 state = repo.dirstate.state(f)
722 if state not in "nrm":
722 if state not in "nrm":
723 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
723 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
724 errors += 1
724 errors += 1
725 if errors:
725 if errors:
726 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
726 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
727
727
728 def debugconfig(ui):
728 def debugconfig(ui):
729 """show combined config settings from all hgrc files"""
729 """show combined config settings from all hgrc files"""
730 try:
730 try:
731 repo = hg.repository(ui)
731 repo = hg.repository(ui)
732 except hg.RepoError:
732 except hg.RepoError:
733 pass
733 pass
734 for section, name, value in ui.walkconfig():
734 for section, name, value in ui.walkconfig():
735 ui.write('%s.%s=%s\n' % (section, name, value))
735 ui.write('%s.%s=%s\n' % (section, name, value))
736
736
737 def debugstate(ui, repo):
737 def debugstate(ui, repo):
738 """show the contents of the current dirstate"""
738 """show the contents of the current dirstate"""
739 repo.dirstate.read()
739 repo.dirstate.read()
740 dc = repo.dirstate.map
740 dc = repo.dirstate.map
741 keys = dc.keys()
741 keys = dc.keys()
742 keys.sort()
742 keys.sort()
743 for file_ in keys:
743 for file_ in keys:
744 ui.write("%c %3o %10d %s %s\n"
744 ui.write("%c %3o %10d %s %s\n"
745 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
745 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
746 time.strftime("%x %X",
746 time.strftime("%x %X",
747 time.localtime(dc[file_][3])), file_))
747 time.localtime(dc[file_][3])), file_))
748 for f in repo.dirstate.copies:
748 for f in repo.dirstate.copies:
749 ui.write("copy: %s -> %s\n" % (repo.dirstate.copies[f], f))
749 ui.write("copy: %s -> %s\n" % (repo.dirstate.copies[f], f))
750
750
751 def debugdata(ui, file_, rev):
751 def debugdata(ui, file_, rev):
752 """dump the contents of an data file revision"""
752 """dump the contents of an data file revision"""
753 r = revlog.revlog(file, file_[:-2] + ".i", file_)
753 r = revlog.revlog(file, file_[:-2] + ".i", file_)
754 ui.write(r.revision(r.lookup(rev)))
754 ui.write(r.revision(r.lookup(rev)))
755
755
756 def debugindex(ui, file_):
756 def debugindex(ui, file_):
757 """dump the contents of an index file"""
757 """dump the contents of an index file"""
758 r = revlog.revlog(file, file_, "")
758 r = revlog.revlog(file, file_, "")
759 ui.write(" rev offset length base linkrev" +
759 ui.write(" rev offset length base linkrev" +
760 " nodeid p1 p2\n")
760 " nodeid p1 p2\n")
761 for i in range(r.count()):
761 for i in range(r.count()):
762 e = r.index[i]
762 e = r.index[i]
763 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
763 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
764 i, e[0], e[1], e[2], e[3],
764 i, e[0], e[1], e[2], e[3],
765 short(e[6]), short(e[4]), short(e[5])))
765 short(e[6]), short(e[4]), short(e[5])))
766
766
767 def debugindexdot(ui, file_):
767 def debugindexdot(ui, file_):
768 """dump an index DAG as a .dot file"""
768 """dump an index DAG as a .dot file"""
769 r = revlog.revlog(file, file_, "")
769 r = revlog.revlog(file, file_, "")
770 ui.write("digraph G {\n")
770 ui.write("digraph G {\n")
771 for i in range(r.count()):
771 for i in range(r.count()):
772 e = r.index[i]
772 e = r.index[i]
773 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
773 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
774 if e[5] != nullid:
774 if e[5] != nullid:
775 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
775 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
776 ui.write("}\n")
776 ui.write("}\n")
777
777
778 def debugrename(ui, repo, file, rev=None):
778 def debugrename(ui, repo, file, rev=None):
779 """dump rename information"""
779 """dump rename information"""
780 r = repo.file(relpath(repo, [file])[0])
780 r = repo.file(relpath(repo, [file])[0])
781 if rev:
781 if rev:
782 try:
782 try:
783 # assume all revision numbers are for changesets
783 # assume all revision numbers are for changesets
784 n = repo.lookup(rev)
784 n = repo.lookup(rev)
785 change = repo.changelog.read(n)
785 change = repo.changelog.read(n)
786 m = repo.manifest.read(change[0])
786 m = repo.manifest.read(change[0])
787 n = m[relpath(repo, [file])[0]]
787 n = m[relpath(repo, [file])[0]]
788 except hg.RepoError, KeyError:
788 except hg.RepoError, KeyError:
789 n = r.lookup(rev)
789 n = r.lookup(rev)
790 else:
790 else:
791 n = r.tip()
791 n = r.tip()
792 m = r.renamed(n)
792 m = r.renamed(n)
793 if m:
793 if m:
794 ui.write("renamed from %s:%s\n" % (m[0], hex(m[1])))
794 ui.write("renamed from %s:%s\n" % (m[0], hex(m[1])))
795 else:
795 else:
796 ui.write("not renamed\n")
796 ui.write("not renamed\n")
797
797
798 def debugwalk(ui, repo, *pats, **opts):
798 def debugwalk(ui, repo, *pats, **opts):
799 """show how files match on given patterns"""
799 """show how files match on given patterns"""
800 items = list(walk(repo, pats, opts))
800 items = list(walk(repo, pats, opts))
801 if not items:
801 if not items:
802 return
802 return
803 fmt = '%%s %%-%ds %%-%ds %%s\n' % (
803 fmt = '%%s %%-%ds %%-%ds %%s\n' % (
804 max([len(abs) for (src, abs, rel, exact) in items]),
804 max([len(abs) for (src, abs, rel, exact) in items]),
805 max([len(rel) for (src, abs, rel, exact) in items]))
805 max([len(rel) for (src, abs, rel, exact) in items]))
806 for src, abs, rel, exact in items:
806 for src, abs, rel, exact in items:
807 ui.write(fmt % (src, abs, rel, exact and 'exact' or ''))
807 ui.write(fmt % (src, abs, rel, exact and 'exact' or ''))
808
808
809 def diff(ui, repo, *pats, **opts):
809 def diff(ui, repo, *pats, **opts):
810 """diff working directory (or selected files)"""
810 """diff working directory (or selected files)"""
811 node1, node2 = None, None
811 node1, node2 = None, None
812 revs = [repo.lookup(x) for x in opts['rev']]
812 revs = [repo.lookup(x) for x in opts['rev']]
813
813
814 if len(revs) > 0:
814 if len(revs) > 0:
815 node1 = revs[0]
815 node1 = revs[0]
816 if len(revs) > 1:
816 if len(revs) > 1:
817 node2 = revs[1]
817 node2 = revs[1]
818 if len(revs) > 2:
818 if len(revs) > 2:
819 raise util.Abort("too many revisions to diff")
819 raise util.Abort("too many revisions to diff")
820
820
821 files = []
821 files = []
822 match = util.always
822 match = util.always
823 if pats:
823 if pats:
824 roots, match, results = makewalk(repo, pats, opts)
824 roots, match, results = makewalk(repo, pats, opts)
825 for src, abs, rel, exact in results:
825 for src, abs, rel, exact in results:
826 files.append(abs)
826 files.append(abs)
827
827
828 dodiff(sys.stdout, ui, repo, node1, node2, files, match=match,
828 dodiff(sys.stdout, ui, repo, node1, node2, files, match=match,
829 text=opts['text'])
829 text=opts['text'])
830
830
831 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
831 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
832 node = repo.lookup(changeset)
832 node = repo.lookup(changeset)
833 prev, other = repo.changelog.parents(node)
833 prev, other = repo.changelog.parents(node)
834 change = repo.changelog.read(node)
834 change = repo.changelog.read(node)
835
835
836 fp = make_file(repo, repo.changelog, opts['output'],
836 fp = make_file(repo, repo.changelog, opts['output'],
837 node=node, total=total, seqno=seqno,
837 node=node, total=total, seqno=seqno,
838 revwidth=revwidth)
838 revwidth=revwidth)
839 if fp != sys.stdout:
839 if fp != sys.stdout:
840 ui.note("%s\n" % fp.name)
840 ui.note("%s\n" % fp.name)
841
841
842 fp.write("# HG changeset patch\n")
842 fp.write("# HG changeset patch\n")
843 fp.write("# User %s\n" % change[1])
843 fp.write("# User %s\n" % change[1])
844 fp.write("# Node ID %s\n" % hex(node))
844 fp.write("# Node ID %s\n" % hex(node))
845 fp.write("# Parent %s\n" % hex(prev))
845 fp.write("# Parent %s\n" % hex(prev))
846 if other != nullid:
846 if other != nullid:
847 fp.write("# Parent %s\n" % hex(other))
847 fp.write("# Parent %s\n" % hex(other))
848 fp.write(change[4].rstrip())
848 fp.write(change[4].rstrip())
849 fp.write("\n\n")
849 fp.write("\n\n")
850
850
851 dodiff(fp, ui, repo, prev, node, text=opts['text'])
851 dodiff(fp, ui, repo, prev, node, text=opts['text'])
852 if fp != sys.stdout:
852 if fp != sys.stdout:
853 fp.close()
853 fp.close()
854
854
855 def export(ui, repo, *changesets, **opts):
855 def export(ui, repo, *changesets, **opts):
856 """dump the header and diffs for one or more changesets"""
856 """dump the header and diffs for one or more changesets"""
857 if not changesets:
857 if not changesets:
858 raise util.Abort("export requires at least one changeset")
858 raise util.Abort("export requires at least one changeset")
859 seqno = 0
859 seqno = 0
860 revs = list(revrange(ui, repo, changesets))
860 revs = list(revrange(ui, repo, changesets))
861 total = len(revs)
861 total = len(revs)
862 revwidth = max(map(len, revs))
862 revwidth = max(map(len, revs))
863 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
863 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
864 for cset in revs:
864 for cset in revs:
865 seqno += 1
865 seqno += 1
866 doexport(ui, repo, cset, seqno, total, revwidth, opts)
866 doexport(ui, repo, cset, seqno, total, revwidth, opts)
867
867
868 def forget(ui, repo, *pats, **opts):
868 def forget(ui, repo, *pats, **opts):
869 """don't add the specified files on the next commit"""
869 """don't add the specified files on the next commit"""
870 forget = []
870 forget = []
871 for src, abs, rel, exact in walk(repo, pats, opts):
871 for src, abs, rel, exact in walk(repo, pats, opts):
872 if repo.dirstate.state(abs) == 'a':
872 if repo.dirstate.state(abs) == 'a':
873 forget.append(abs)
873 forget.append(abs)
874 if not exact:
874 if not exact:
875 ui.status('forgetting ', rel, '\n')
875 ui.status('forgetting ', rel, '\n')
876 repo.forget(forget)
876 repo.forget(forget)
877
877
878 def grep(ui, repo, pattern, *pats, **opts):
878 def grep(ui, repo, pattern, *pats, **opts):
879 """search for a pattern in specified files and revisions"""
879 """search for a pattern in specified files and revisions"""
880 reflags = 0
880 reflags = 0
881 if opts['ignore_case']:
881 if opts['ignore_case']:
882 reflags |= re.I
882 reflags |= re.I
883 regexp = re.compile(pattern, reflags)
883 regexp = re.compile(pattern, reflags)
884 sep, eol = ':', '\n'
884 sep, eol = ':', '\n'
885 if opts['print0']:
885 if opts['print0']:
886 sep = eol = '\0'
886 sep = eol = '\0'
887
887
888 fcache = {}
888 fcache = {}
889 def getfile(fn):
889 def getfile(fn):
890 if fn not in fcache:
890 if fn not in fcache:
891 fcache[fn] = repo.file(fn)
891 fcache[fn] = repo.file(fn)
892 return fcache[fn]
892 return fcache[fn]
893
893
894 def matchlines(body):
894 def matchlines(body):
895 begin = 0
895 begin = 0
896 linenum = 0
896 linenum = 0
897 while True:
897 while True:
898 match = regexp.search(body, begin)
898 match = regexp.search(body, begin)
899 if not match:
899 if not match:
900 break
900 break
901 mstart, mend = match.span()
901 mstart, mend = match.span()
902 linenum += body.count('\n', begin, mstart) + 1
902 linenum += body.count('\n', begin, mstart) + 1
903 lstart = body.rfind('\n', begin, mstart) + 1 or begin
903 lstart = body.rfind('\n', begin, mstart) + 1 or begin
904 lend = body.find('\n', mend)
904 lend = body.find('\n', mend)
905 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
905 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
906 begin = lend + 1
906 begin = lend + 1
907
907
908 class linestate:
908 class linestate:
909 def __init__(self, line, linenum, colstart, colend):
909 def __init__(self, line, linenum, colstart, colend):
910 self.line = line
910 self.line = line
911 self.linenum = linenum
911 self.linenum = linenum
912 self.colstart = colstart
912 self.colstart = colstart
913 self.colend = colend
913 self.colend = colend
914 def __eq__(self, other):
914 def __eq__(self, other):
915 return self.line == other.line
915 return self.line == other.line
916 def __hash__(self):
916 def __hash__(self):
917 return hash(self.line)
917 return hash(self.line)
918
918
919 matches = {}
919 matches = {}
920 def grepbody(fn, rev, body):
920 def grepbody(fn, rev, body):
921 matches[rev].setdefault(fn, {})
921 matches[rev].setdefault(fn, {})
922 m = matches[rev][fn]
922 m = matches[rev][fn]
923 for lnum, cstart, cend, line in matchlines(body):
923 for lnum, cstart, cend, line in matchlines(body):
924 s = linestate(line, lnum, cstart, cend)
924 s = linestate(line, lnum, cstart, cend)
925 m[s] = s
925 m[s] = s
926
926
927 prev = {}
927 prev = {}
928 ucache = {}
928 ucache = {}
929 def display(fn, rev, states, prevstates):
929 def display(fn, rev, states, prevstates):
930 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
930 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
931 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
931 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
932 counts = {'-': 0, '+': 0}
932 counts = {'-': 0, '+': 0}
933 filerevmatches = {}
933 filerevmatches = {}
934 for l in diff:
934 for l in diff:
935 if incrementing or not opts['all']:
935 if incrementing or not opts['all']:
936 change = ((l in prevstates) and '-') or '+'
936 change = ((l in prevstates) and '-') or '+'
937 r = rev
937 r = rev
938 else:
938 else:
939 change = ((l in states) and '-') or '+'
939 change = ((l in states) and '-') or '+'
940 r = prev[fn]
940 r = prev[fn]
941 cols = [fn, str(rev)]
941 cols = [fn, str(rev)]
942 if opts['line_number']: cols.append(str(l.linenum))
942 if opts['line_number']: cols.append(str(l.linenum))
943 if opts['all']: cols.append(change)
943 if opts['all']: cols.append(change)
944 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
944 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
945 ucache))
945 ucache))
946 if opts['files_with_matches']:
946 if opts['files_with_matches']:
947 c = (fn, rev)
947 c = (fn, rev)
948 if c in filerevmatches: continue
948 if c in filerevmatches: continue
949 filerevmatches[c] = 1
949 filerevmatches[c] = 1
950 else:
950 else:
951 cols.append(l.line)
951 cols.append(l.line)
952 ui.write(sep.join(cols), eol)
952 ui.write(sep.join(cols), eol)
953 counts[change] += 1
953 counts[change] += 1
954 return counts['+'], counts['-']
954 return counts['+'], counts['-']
955
955
956 fstate = {}
956 fstate = {}
957 skip = {}
957 skip = {}
958 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
958 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
959 count = 0
959 count = 0
960 for st, rev, fns in changeiter:
960 for st, rev, fns in changeiter:
961 if st == 'window':
961 if st == 'window':
962 incrementing = rev
962 incrementing = rev
963 matches.clear()
963 matches.clear()
964 elif st == 'add':
964 elif st == 'add':
965 change = repo.changelog.read(repo.lookup(str(rev)))
965 change = repo.changelog.read(repo.lookup(str(rev)))
966 mf = repo.manifest.read(change[0])
966 mf = repo.manifest.read(change[0])
967 matches[rev] = {}
967 matches[rev] = {}
968 for fn in fns:
968 for fn in fns:
969 if fn in skip: continue
969 if fn in skip: continue
970 fstate.setdefault(fn, {})
970 fstate.setdefault(fn, {})
971 try:
971 try:
972 grepbody(fn, rev, getfile(fn).read(mf[fn]))
972 grepbody(fn, rev, getfile(fn).read(mf[fn]))
973 except KeyError:
973 except KeyError:
974 pass
974 pass
975 elif st == 'iter':
975 elif st == 'iter':
976 states = matches[rev].items()
976 states = matches[rev].items()
977 states.sort()
977 states.sort()
978 for fn, m in states:
978 for fn, m in states:
979 if fn in skip: continue
979 if fn in skip: continue
980 if incrementing or not opts['all'] or fstate[fn]:
980 if incrementing or not opts['all'] or fstate[fn]:
981 pos, neg = display(fn, rev, m, fstate[fn])
981 pos, neg = display(fn, rev, m, fstate[fn])
982 count += pos + neg
982 count += pos + neg
983 if pos and not opts['all']:
983 if pos and not opts['all']:
984 skip[fn] = True
984 skip[fn] = True
985 fstate[fn] = m
985 fstate[fn] = m
986 prev[fn] = rev
986 prev[fn] = rev
987
987
988 if not incrementing:
988 if not incrementing:
989 fstate = fstate.items()
989 fstate = fstate.items()
990 fstate.sort()
990 fstate.sort()
991 for fn, state in fstate:
991 for fn, state in fstate:
992 if fn in skip: continue
992 if fn in skip: continue
993 display(fn, rev, {}, state)
993 display(fn, rev, {}, state)
994 return (count == 0 and 1) or 0
994 return (count == 0 and 1) or 0
995
995
996 def heads(ui, repo, **opts):
996 def heads(ui, repo, **opts):
997 """show current repository heads"""
997 """show current repository heads"""
998 heads = repo.changelog.heads()
998 heads = repo.changelog.heads()
999 br = None
999 br = None
1000 if opts['branches']:
1000 if opts['branches']:
1001 br = repo.branchlookup(heads)
1001 br = repo.branchlookup(heads)
1002 for n in repo.changelog.heads():
1002 for n in repo.changelog.heads():
1003 show_changeset(ui, repo, changenode=n, brinfo=br)
1003 show_changeset(ui, repo, changenode=n, brinfo=br)
1004
1004
1005 def identify(ui, repo):
1005 def identify(ui, repo):
1006 """print information about the working copy"""
1006 """print information about the working copy"""
1007 parents = [p for p in repo.dirstate.parents() if p != nullid]
1007 parents = [p for p in repo.dirstate.parents() if p != nullid]
1008 if not parents:
1008 if not parents:
1009 ui.write("unknown\n")
1009 ui.write("unknown\n")
1010 return
1010 return
1011
1011
1012 hexfunc = ui.verbose and hex or short
1012 hexfunc = ui.verbose and hex or short
1013 (c, a, d, u) = repo.changes()
1013 (c, a, d, u) = repo.changes()
1014 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1014 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1015 (c or a or d) and "+" or "")]
1015 (c or a or d) and "+" or "")]
1016
1016
1017 if not ui.quiet:
1017 if not ui.quiet:
1018 # multiple tags for a single parent separated by '/'
1018 # multiple tags for a single parent separated by '/'
1019 parenttags = ['/'.join(tags)
1019 parenttags = ['/'.join(tags)
1020 for tags in map(repo.nodetags, parents) if tags]
1020 for tags in map(repo.nodetags, parents) if tags]
1021 # tags for multiple parents separated by ' + '
1021 # tags for multiple parents separated by ' + '
1022 if parenttags:
1022 if parenttags:
1023 output.append(' + '.join(parenttags))
1023 output.append(' + '.join(parenttags))
1024
1024
1025 ui.write("%s\n" % ' '.join(output))
1025 ui.write("%s\n" % ' '.join(output))
1026
1026
1027 def import_(ui, repo, patch1, *patches, **opts):
1027 def import_(ui, repo, patch1, *patches, **opts):
1028 """import an ordered set of patches"""
1028 """import an ordered set of patches"""
1029 patches = (patch1,) + patches
1029 patches = (patch1,) + patches
1030
1030
1031 if not opts['force']:
1031 if not opts['force']:
1032 (c, a, d, u) = repo.changes()
1032 (c, a, d, u) = repo.changes()
1033 if c or a or d:
1033 if c or a or d:
1034 raise util.Abort("outstanding uncommitted changes")
1034 raise util.Abort("outstanding uncommitted changes")
1035
1035
1036 d = opts["base"]
1036 d = opts["base"]
1037 strip = opts["strip"]
1037 strip = opts["strip"]
1038
1038
1039 mailre = re.compile(r'(?:From |[\w-]+:)')
1039 mailre = re.compile(r'(?:From |[\w-]+:)')
1040 diffre = re.compile(r'(?:diff -|--- .*\s+\w+ \w+ +\d+ \d+:\d+:\d+ \d+)')
1040 diffre = re.compile(r'(?:diff -|--- .*\s+\w+ \w+ +\d+ \d+:\d+:\d+ \d+)')
1041
1041
1042 for patch in patches:
1042 for patch in patches:
1043 ui.status("applying %s\n" % patch)
1043 ui.status("applying %s\n" % patch)
1044 pf = os.path.join(d, patch)
1044 pf = os.path.join(d, patch)
1045
1045
1046 message = []
1046 message = []
1047 user = None
1047 user = None
1048 hgpatch = False
1048 hgpatch = False
1049 for line in file(pf):
1049 for line in file(pf):
1050 line = line.rstrip()
1050 line = line.rstrip()
1051 if (not message and not hgpatch and
1051 if (not message and not hgpatch and
1052 mailre.match(line) and not opts['force']):
1052 mailre.match(line) and not opts['force']):
1053 if len(line) > 35: line = line[:32] + '...'
1053 if len(line) > 35: line = line[:32] + '...'
1054 raise util.Abort('first line looks like a '
1054 raise util.Abort('first line looks like a '
1055 'mail header: ' + line)
1055 'mail header: ' + line)
1056 if diffre.match(line):
1056 if diffre.match(line):
1057 break
1057 break
1058 elif hgpatch:
1058 elif hgpatch:
1059 # parse values when importing the result of an hg export
1059 # parse values when importing the result of an hg export
1060 if line.startswith("# User "):
1060 if line.startswith("# User "):
1061 user = line[7:]
1061 user = line[7:]
1062 ui.debug('User: %s\n' % user)
1062 ui.debug('User: %s\n' % user)
1063 elif not line.startswith("# ") and line:
1063 elif not line.startswith("# ") and line:
1064 message.append(line)
1064 message.append(line)
1065 hgpatch = False
1065 hgpatch = False
1066 elif line == '# HG changeset patch':
1066 elif line == '# HG changeset patch':
1067 hgpatch = True
1067 hgpatch = True
1068 message = [] # We may have collected garbage
1068 message = [] # We may have collected garbage
1069 else:
1069 else:
1070 message.append(line)
1070 message.append(line)
1071
1071
1072 # make sure message isn't empty
1072 # make sure message isn't empty
1073 if not message:
1073 if not message:
1074 message = "imported patch %s\n" % patch
1074 message = "imported patch %s\n" % patch
1075 else:
1075 else:
1076 message = "%s\n" % '\n'.join(message)
1076 message = "%s\n" % '\n'.join(message)
1077 ui.debug('message:\n%s\n' % message)
1077 ui.debug('message:\n%s\n' % message)
1078
1078
1079 f = os.popen("patch -p%d < '%s'" % (strip, pf))
1079 f = os.popen("patch -p%d < '%s'" % (strip, pf))
1080 files = []
1080 files = []
1081 for l in f.read().splitlines():
1081 for l in f.read().splitlines():
1082 l.rstrip('\r\n');
1082 l.rstrip('\r\n');
1083 ui.status("%s\n" % l)
1083 ui.status("%s\n" % l)
1084 if l.startswith('patching file '):
1084 if l.startswith('patching file '):
1085 pf = l[14:]
1085 pf = l[14:]
1086 if pf not in files:
1086 if pf not in files:
1087 files.append(pf)
1087 files.append(pf)
1088 patcherr = f.close()
1088 patcherr = f.close()
1089 if patcherr:
1089 if patcherr:
1090 raise util.Abort("patch failed")
1090 raise util.Abort("patch failed")
1091
1091
1092 if len(files) > 0:
1092 if len(files) > 0:
1093 addremove(ui, repo, *files)
1093 addremove(ui, repo, *files)
1094 repo.commit(files, message, user)
1094 repo.commit(files, message, user)
1095
1095
1096 def incoming(ui, repo, source="default", **opts):
1096 def incoming(ui, repo, source="default", **opts):
1097 """show new changesets found in source"""
1097 """show new changesets found in source"""
1098 source = ui.expandpath(source)
1098 source = ui.expandpath(source)
1099 other = hg.repository(ui, source)
1099 other = hg.repository(ui, source)
1100 if not other.local():
1100 if not other.local():
1101 raise util.Abort("incoming doesn't work for remote repositories yet")
1101 raise util.Abort("incoming doesn't work for remote repositories yet")
1102 o = repo.findincoming(other)
1102 o = repo.findincoming(other)
1103 if not o:
1103 if not o:
1104 return
1104 return
1105 o = other.newer(o)
1105 o = other.newer(o)
1106 o.reverse()
1106 o.reverse()
1107 for n in o:
1107 for n in o:
1108 show_changeset(ui, other, changenode=n)
1108 show_changeset(ui, other, changenode=n)
1109 if opts['patch']:
1109 if opts['patch']:
1110 prev = other.changelog.parents(n)[0]
1110 prev = other.changelog.parents(n)[0]
1111 dodiff(ui, ui, other, prev, n)
1111 dodiff(ui, ui, other, prev, n)
1112 ui.write("\n")
1112 ui.write("\n")
1113
1113
1114 def init(ui, dest="."):
1114 def init(ui, dest="."):
1115 """create a new repository in the given directory"""
1115 """create a new repository in the given directory"""
1116 if not os.path.exists(dest):
1116 if not os.path.exists(dest):
1117 os.mkdir(dest)
1117 os.mkdir(dest)
1118 hg.repository(ui, dest, create=1)
1118 hg.repository(ui, dest, create=1)
1119
1119
1120 def locate(ui, repo, *pats, **opts):
1120 def locate(ui, repo, *pats, **opts):
1121 """locate files matching specific patterns"""
1121 """locate files matching specific patterns"""
1122 end = opts['print0'] and '\0' or '\n'
1122 end = opts['print0'] and '\0' or '\n'
1123
1123
1124 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1124 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1125 if repo.dirstate.state(abs) == '?':
1125 if repo.dirstate.state(abs) == '?':
1126 continue
1126 continue
1127 if opts['fullpath']:
1127 if opts['fullpath']:
1128 ui.write(os.path.join(repo.root, abs), end)
1128 ui.write(os.path.join(repo.root, abs), end)
1129 else:
1129 else:
1130 ui.write(rel, end)
1130 ui.write(rel, end)
1131
1131
1132 def log(ui, repo, *pats, **opts):
1132 def log(ui, repo, *pats, **opts):
1133 """show revision history of entire repository or files"""
1133 """show revision history of entire repository or files"""
1134 class dui:
1134 class dui:
1135 # Implement and delegate some ui protocol. Save hunks of
1135 # Implement and delegate some ui protocol. Save hunks of
1136 # output for later display in the desired order.
1136 # output for later display in the desired order.
1137 def __init__(self, ui):
1137 def __init__(self, ui):
1138 self.ui = ui
1138 self.ui = ui
1139 self.hunk = {}
1139 self.hunk = {}
1140 def bump(self, rev):
1140 def bump(self, rev):
1141 self.rev = rev
1141 self.rev = rev
1142 self.hunk[rev] = []
1142 self.hunk[rev] = []
1143 def note(self, *args):
1143 def note(self, *args):
1144 if self.verbose:
1144 if self.verbose:
1145 self.write(*args)
1145 self.write(*args)
1146 def status(self, *args):
1146 def status(self, *args):
1147 if not self.quiet:
1147 if not self.quiet:
1148 self.write(*args)
1148 self.write(*args)
1149 def write(self, *args):
1149 def write(self, *args):
1150 self.hunk[self.rev].append(args)
1150 self.hunk[self.rev].append(args)
1151 def __getattr__(self, key):
1151 def __getattr__(self, key):
1152 return getattr(self.ui, key)
1152 return getattr(self.ui, key)
1153 cwd = repo.getcwd()
1153 cwd = repo.getcwd()
1154 if not pats and cwd:
1154 if not pats and cwd:
1155 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1155 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1156 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1156 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1157 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1157 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1158 pats, opts)
1158 pats, opts)
1159 for st, rev, fns in changeiter:
1159 for st, rev, fns in changeiter:
1160 if st == 'window':
1160 if st == 'window':
1161 du = dui(ui)
1161 du = dui(ui)
1162 elif st == 'add':
1162 elif st == 'add':
1163 du.bump(rev)
1163 du.bump(rev)
1164 show_changeset(du, repo, rev)
1164 br = None
1165 if opts['branch']:
1166 br = repo.branchlookup([repo.changelog.node(rev)])
1167 show_changeset(du, repo, rev, brinfo=br)
1165 if opts['patch']:
1168 if opts['patch']:
1166 changenode = repo.changelog.node(rev)
1169 changenode = repo.changelog.node(rev)
1167 prev, other = repo.changelog.parents(changenode)
1170 prev, other = repo.changelog.parents(changenode)
1168 dodiff(du, du, repo, prev, changenode, fns)
1171 dodiff(du, du, repo, prev, changenode, fns)
1169 du.write("\n\n")
1172 du.write("\n\n")
1170 elif st == 'iter':
1173 elif st == 'iter':
1171 for args in du.hunk[rev]:
1174 for args in du.hunk[rev]:
1172 ui.write(*args)
1175 ui.write(*args)
1173
1176
1174 def manifest(ui, repo, rev=None):
1177 def manifest(ui, repo, rev=None):
1175 """output the latest or given revision of the project manifest"""
1178 """output the latest or given revision of the project manifest"""
1176 if rev:
1179 if rev:
1177 try:
1180 try:
1178 # assume all revision numbers are for changesets
1181 # assume all revision numbers are for changesets
1179 n = repo.lookup(rev)
1182 n = repo.lookup(rev)
1180 change = repo.changelog.read(n)
1183 change = repo.changelog.read(n)
1181 n = change[0]
1184 n = change[0]
1182 except hg.RepoError:
1185 except hg.RepoError:
1183 n = repo.manifest.lookup(rev)
1186 n = repo.manifest.lookup(rev)
1184 else:
1187 else:
1185 n = repo.manifest.tip()
1188 n = repo.manifest.tip()
1186 m = repo.manifest.read(n)
1189 m = repo.manifest.read(n)
1187 mf = repo.manifest.readflags(n)
1190 mf = repo.manifest.readflags(n)
1188 files = m.keys()
1191 files = m.keys()
1189 files.sort()
1192 files.sort()
1190
1193
1191 for f in files:
1194 for f in files:
1192 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1195 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1193
1196
1194 def outgoing(ui, repo, dest="default-push", **opts):
1197 def outgoing(ui, repo, dest="default-push", **opts):
1195 """show changesets not found in destination"""
1198 """show changesets not found in destination"""
1196 dest = ui.expandpath(dest)
1199 dest = ui.expandpath(dest)
1197 other = hg.repository(ui, dest)
1200 other = hg.repository(ui, dest)
1198 o = repo.findoutgoing(other)
1201 o = repo.findoutgoing(other)
1199 o = repo.newer(o)
1202 o = repo.newer(o)
1200 o.reverse()
1203 o.reverse()
1201 for n in o:
1204 for n in o:
1202 show_changeset(ui, repo, changenode=n)
1205 show_changeset(ui, repo, changenode=n)
1203 if opts['patch']:
1206 if opts['patch']:
1204 prev = repo.changelog.parents(n)[0]
1207 prev = repo.changelog.parents(n)[0]
1205 dodiff(ui, ui, repo, prev, n)
1208 dodiff(ui, ui, repo, prev, n)
1206 ui.write("\n")
1209 ui.write("\n")
1207
1210
1208 def parents(ui, repo, rev=None):
1211 def parents(ui, repo, rev=None):
1209 """show the parents of the working dir or revision"""
1212 """show the parents of the working dir or revision"""
1210 if rev:
1213 if rev:
1211 p = repo.changelog.parents(repo.lookup(rev))
1214 p = repo.changelog.parents(repo.lookup(rev))
1212 else:
1215 else:
1213 p = repo.dirstate.parents()
1216 p = repo.dirstate.parents()
1214
1217
1215 for n in p:
1218 for n in p:
1216 if n != nullid:
1219 if n != nullid:
1217 show_changeset(ui, repo, changenode=n)
1220 show_changeset(ui, repo, changenode=n)
1218
1221
1219 def paths(ui, search=None):
1222 def paths(ui, search=None):
1220 """show definition of symbolic path names"""
1223 """show definition of symbolic path names"""
1221 try:
1224 try:
1222 repo = hg.repository(ui=ui)
1225 repo = hg.repository(ui=ui)
1223 except hg.RepoError:
1226 except hg.RepoError:
1224 pass
1227 pass
1225
1228
1226 if search:
1229 if search:
1227 for name, path in ui.configitems("paths"):
1230 for name, path in ui.configitems("paths"):
1228 if name == search:
1231 if name == search:
1229 ui.write("%s\n" % path)
1232 ui.write("%s\n" % path)
1230 return
1233 return
1231 ui.warn("not found!\n")
1234 ui.warn("not found!\n")
1232 return 1
1235 return 1
1233 else:
1236 else:
1234 for name, path in ui.configitems("paths"):
1237 for name, path in ui.configitems("paths"):
1235 ui.write("%s = %s\n" % (name, path))
1238 ui.write("%s = %s\n" % (name, path))
1236
1239
1237 def pull(ui, repo, source="default", **opts):
1240 def pull(ui, repo, source="default", **opts):
1238 """pull changes from the specified source"""
1241 """pull changes from the specified source"""
1239 source = ui.expandpath(source)
1242 source = ui.expandpath(source)
1240 ui.status('pulling from %s\n' % (source))
1243 ui.status('pulling from %s\n' % (source))
1241
1244
1242 if opts['ssh']:
1245 if opts['ssh']:
1243 ui.setconfig("ui", "ssh", opts['ssh'])
1246 ui.setconfig("ui", "ssh", opts['ssh'])
1244 if opts['remotecmd']:
1247 if opts['remotecmd']:
1245 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1248 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1246
1249
1247 other = hg.repository(ui, source)
1250 other = hg.repository(ui, source)
1248 r = repo.pull(other)
1251 r = repo.pull(other)
1249 if not r:
1252 if not r:
1250 if opts['update']:
1253 if opts['update']:
1251 return update(ui, repo)
1254 return update(ui, repo)
1252 else:
1255 else:
1253 ui.status("(run 'hg update' to get a working copy)\n")
1256 ui.status("(run 'hg update' to get a working copy)\n")
1254
1257
1255 return r
1258 return r
1256
1259
1257 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1260 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1258 """push changes to the specified destination"""
1261 """push changes to the specified destination"""
1259 dest = ui.expandpath(dest)
1262 dest = ui.expandpath(dest)
1260 ui.status('pushing to %s\n' % (dest))
1263 ui.status('pushing to %s\n' % (dest))
1261
1264
1262 if ssh:
1265 if ssh:
1263 ui.setconfig("ui", "ssh", ssh)
1266 ui.setconfig("ui", "ssh", ssh)
1264 if remotecmd:
1267 if remotecmd:
1265 ui.setconfig("ui", "remotecmd", remotecmd)
1268 ui.setconfig("ui", "remotecmd", remotecmd)
1266
1269
1267 other = hg.repository(ui, dest)
1270 other = hg.repository(ui, dest)
1268 r = repo.push(other, force)
1271 r = repo.push(other, force)
1269 return r
1272 return r
1270
1273
1271 def rawcommit(ui, repo, *flist, **rc):
1274 def rawcommit(ui, repo, *flist, **rc):
1272 "raw commit interface"
1275 "raw commit interface"
1273 if rc['text']:
1276 if rc['text']:
1274 ui.warn("Warning: -t and --text is deprecated,"
1277 ui.warn("Warning: -t and --text is deprecated,"
1275 " please use -m or --message instead.\n")
1278 " please use -m or --message instead.\n")
1276 message = rc['message'] or rc['text']
1279 message = rc['message'] or rc['text']
1277 if not message and rc['logfile']:
1280 if not message and rc['logfile']:
1278 try:
1281 try:
1279 message = open(rc['logfile']).read()
1282 message = open(rc['logfile']).read()
1280 except IOError:
1283 except IOError:
1281 pass
1284 pass
1282 if not message and not rc['logfile']:
1285 if not message and not rc['logfile']:
1283 raise util.Abort("missing commit message")
1286 raise util.Abort("missing commit message")
1284
1287
1285 files = relpath(repo, list(flist))
1288 files = relpath(repo, list(flist))
1286 if rc['files']:
1289 if rc['files']:
1287 files += open(rc['files']).read().splitlines()
1290 files += open(rc['files']).read().splitlines()
1288
1291
1289 rc['parent'] = map(repo.lookup, rc['parent'])
1292 rc['parent'] = map(repo.lookup, rc['parent'])
1290
1293
1291 try:
1294 try:
1292 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1295 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1293 except ValueError, inst:
1296 except ValueError, inst:
1294 raise util.Abort(str(inst))
1297 raise util.Abort(str(inst))
1295
1298
1296 def recover(ui, repo):
1299 def recover(ui, repo):
1297 """roll back an interrupted transaction"""
1300 """roll back an interrupted transaction"""
1298 repo.recover()
1301 repo.recover()
1299
1302
1300 def remove(ui, repo, pat, *pats, **opts):
1303 def remove(ui, repo, pat, *pats, **opts):
1301 """remove the specified files on the next commit"""
1304 """remove the specified files on the next commit"""
1302 names = []
1305 names = []
1303 def okaytoremove(abs, rel, exact):
1306 def okaytoremove(abs, rel, exact):
1304 c, a, d, u = repo.changes(files = [abs])
1307 c, a, d, u = repo.changes(files = [abs])
1305 reason = None
1308 reason = None
1306 if c: reason = 'is modified'
1309 if c: reason = 'is modified'
1307 elif a: reason = 'has been marked for add'
1310 elif a: reason = 'has been marked for add'
1308 elif u: reason = 'not managed'
1311 elif u: reason = 'not managed'
1309 if reason and exact:
1312 if reason and exact:
1310 ui.warn('not removing %s: file %s\n' % (rel, reason))
1313 ui.warn('not removing %s: file %s\n' % (rel, reason))
1311 else:
1314 else:
1312 return True
1315 return True
1313 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1316 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1314 if okaytoremove(abs, rel, exact):
1317 if okaytoremove(abs, rel, exact):
1315 if not exact: ui.status('removing %s\n' % rel)
1318 if not exact: ui.status('removing %s\n' % rel)
1316 names.append(abs)
1319 names.append(abs)
1317 repo.remove(names)
1320 repo.remove(names)
1318
1321
1319 def revert(ui, repo, *names, **opts):
1322 def revert(ui, repo, *names, **opts):
1320 """revert modified files or dirs back to their unmodified states"""
1323 """revert modified files or dirs back to their unmodified states"""
1321 node = opts['rev'] and repo.lookup(opts['rev']) or \
1324 node = opts['rev'] and repo.lookup(opts['rev']) or \
1322 repo.dirstate.parents()[0]
1325 repo.dirstate.parents()[0]
1323 root = os.path.realpath(repo.root)
1326 root = os.path.realpath(repo.root)
1324
1327
1325 def trimpath(p):
1328 def trimpath(p):
1326 p = os.path.realpath(p)
1329 p = os.path.realpath(p)
1327 if p.startswith(root):
1330 if p.startswith(root):
1328 rest = p[len(root):]
1331 rest = p[len(root):]
1329 if not rest:
1332 if not rest:
1330 return rest
1333 return rest
1331 if p.startswith(os.sep):
1334 if p.startswith(os.sep):
1332 return rest[1:]
1335 return rest[1:]
1333 return p
1336 return p
1334
1337
1335 relnames = map(trimpath, names or [os.getcwd()])
1338 relnames = map(trimpath, names or [os.getcwd()])
1336 chosen = {}
1339 chosen = {}
1337
1340
1338 def choose(name):
1341 def choose(name):
1339 def body(name):
1342 def body(name):
1340 for r in relnames:
1343 for r in relnames:
1341 if not name.startswith(r):
1344 if not name.startswith(r):
1342 continue
1345 continue
1343 rest = name[len(r):]
1346 rest = name[len(r):]
1344 if not rest:
1347 if not rest:
1345 return r, True
1348 return r, True
1346 depth = rest.count(os.sep)
1349 depth = rest.count(os.sep)
1347 if not r:
1350 if not r:
1348 if depth == 0 or not opts['nonrecursive']:
1351 if depth == 0 or not opts['nonrecursive']:
1349 return r, True
1352 return r, True
1350 elif rest[0] == os.sep:
1353 elif rest[0] == os.sep:
1351 if depth == 1 or not opts['nonrecursive']:
1354 if depth == 1 or not opts['nonrecursive']:
1352 return r, True
1355 return r, True
1353 return None, False
1356 return None, False
1354 relname, ret = body(name)
1357 relname, ret = body(name)
1355 if ret:
1358 if ret:
1356 chosen[relname] = 1
1359 chosen[relname] = 1
1357 return ret
1360 return ret
1358
1361
1359 r = repo.update(node, False, True, choose, False)
1362 r = repo.update(node, False, True, choose, False)
1360 for n in relnames:
1363 for n in relnames:
1361 if n not in chosen:
1364 if n not in chosen:
1362 ui.warn('error: no matches for %s\n' % n)
1365 ui.warn('error: no matches for %s\n' % n)
1363 r = 1
1366 r = 1
1364 sys.stdout.flush()
1367 sys.stdout.flush()
1365 return r
1368 return r
1366
1369
1367 def root(ui, repo):
1370 def root(ui, repo):
1368 """print the root (top) of the current working dir"""
1371 """print the root (top) of the current working dir"""
1369 ui.write(repo.root + "\n")
1372 ui.write(repo.root + "\n")
1370
1373
1371 def serve(ui, repo, **opts):
1374 def serve(ui, repo, **opts):
1372 """export the repository via HTTP"""
1375 """export the repository via HTTP"""
1373
1376
1374 if opts["stdio"]:
1377 if opts["stdio"]:
1375 fin, fout = sys.stdin, sys.stdout
1378 fin, fout = sys.stdin, sys.stdout
1376 sys.stdout = sys.stderr
1379 sys.stdout = sys.stderr
1377
1380
1378 def getarg():
1381 def getarg():
1379 argline = fin.readline()[:-1]
1382 argline = fin.readline()[:-1]
1380 arg, l = argline.split()
1383 arg, l = argline.split()
1381 val = fin.read(int(l))
1384 val = fin.read(int(l))
1382 return arg, val
1385 return arg, val
1383 def respond(v):
1386 def respond(v):
1384 fout.write("%d\n" % len(v))
1387 fout.write("%d\n" % len(v))
1385 fout.write(v)
1388 fout.write(v)
1386 fout.flush()
1389 fout.flush()
1387
1390
1388 lock = None
1391 lock = None
1389
1392
1390 while 1:
1393 while 1:
1391 cmd = fin.readline()[:-1]
1394 cmd = fin.readline()[:-1]
1392 if cmd == '':
1395 if cmd == '':
1393 return
1396 return
1394 if cmd == "heads":
1397 if cmd == "heads":
1395 h = repo.heads()
1398 h = repo.heads()
1396 respond(" ".join(map(hex, h)) + "\n")
1399 respond(" ".join(map(hex, h)) + "\n")
1397 if cmd == "lock":
1400 if cmd == "lock":
1398 lock = repo.lock()
1401 lock = repo.lock()
1399 respond("")
1402 respond("")
1400 if cmd == "unlock":
1403 if cmd == "unlock":
1401 if lock:
1404 if lock:
1402 lock.release()
1405 lock.release()
1403 lock = None
1406 lock = None
1404 respond("")
1407 respond("")
1405 elif cmd == "branches":
1408 elif cmd == "branches":
1406 arg, nodes = getarg()
1409 arg, nodes = getarg()
1407 nodes = map(bin, nodes.split(" "))
1410 nodes = map(bin, nodes.split(" "))
1408 r = []
1411 r = []
1409 for b in repo.branches(nodes):
1412 for b in repo.branches(nodes):
1410 r.append(" ".join(map(hex, b)) + "\n")
1413 r.append(" ".join(map(hex, b)) + "\n")
1411 respond("".join(r))
1414 respond("".join(r))
1412 elif cmd == "between":
1415 elif cmd == "between":
1413 arg, pairs = getarg()
1416 arg, pairs = getarg()
1414 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1417 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1415 r = []
1418 r = []
1416 for b in repo.between(pairs):
1419 for b in repo.between(pairs):
1417 r.append(" ".join(map(hex, b)) + "\n")
1420 r.append(" ".join(map(hex, b)) + "\n")
1418 respond("".join(r))
1421 respond("".join(r))
1419 elif cmd == "changegroup":
1422 elif cmd == "changegroup":
1420 nodes = []
1423 nodes = []
1421 arg, roots = getarg()
1424 arg, roots = getarg()
1422 nodes = map(bin, roots.split(" "))
1425 nodes = map(bin, roots.split(" "))
1423
1426
1424 cg = repo.changegroup(nodes)
1427 cg = repo.changegroup(nodes)
1425 while 1:
1428 while 1:
1426 d = cg.read(4096)
1429 d = cg.read(4096)
1427 if not d:
1430 if not d:
1428 break
1431 break
1429 fout.write(d)
1432 fout.write(d)
1430
1433
1431 fout.flush()
1434 fout.flush()
1432
1435
1433 elif cmd == "addchangegroup":
1436 elif cmd == "addchangegroup":
1434 if not lock:
1437 if not lock:
1435 respond("not locked")
1438 respond("not locked")
1436 continue
1439 continue
1437 respond("")
1440 respond("")
1438
1441
1439 r = repo.addchangegroup(fin)
1442 r = repo.addchangegroup(fin)
1440 respond("")
1443 respond("")
1441
1444
1442 optlist = "name templates style address port ipv6 accesslog errorlog"
1445 optlist = "name templates style address port ipv6 accesslog errorlog"
1443 for o in optlist.split():
1446 for o in optlist.split():
1444 if opts[o]:
1447 if opts[o]:
1445 ui.setconfig("web", o, opts[o])
1448 ui.setconfig("web", o, opts[o])
1446
1449
1447 try:
1450 try:
1448 httpd = hgweb.create_server(repo)
1451 httpd = hgweb.create_server(repo)
1449 except socket.error, inst:
1452 except socket.error, inst:
1450 raise util.Abort('cannot start server: ' + inst.args[1])
1453 raise util.Abort('cannot start server: ' + inst.args[1])
1451
1454
1452 if ui.verbose:
1455 if ui.verbose:
1453 addr, port = httpd.socket.getsockname()
1456 addr, port = httpd.socket.getsockname()
1454 if addr == '0.0.0.0':
1457 if addr == '0.0.0.0':
1455 addr = socket.gethostname()
1458 addr = socket.gethostname()
1456 else:
1459 else:
1457 try:
1460 try:
1458 addr = socket.gethostbyaddr(addr)[0]
1461 addr = socket.gethostbyaddr(addr)[0]
1459 except socket.error:
1462 except socket.error:
1460 pass
1463 pass
1461 if port != 80:
1464 if port != 80:
1462 ui.status('listening at http://%s:%d/\n' % (addr, port))
1465 ui.status('listening at http://%s:%d/\n' % (addr, port))
1463 else:
1466 else:
1464 ui.status('listening at http://%s/\n' % addr)
1467 ui.status('listening at http://%s/\n' % addr)
1465 httpd.serve_forever()
1468 httpd.serve_forever()
1466
1469
1467 def status(ui, repo, *pats, **opts):
1470 def status(ui, repo, *pats, **opts):
1468 '''show changed files in the working directory
1471 '''show changed files in the working directory
1469
1472
1470 M = modified
1473 M = modified
1471 A = added
1474 A = added
1472 R = removed
1475 R = removed
1473 ? = not tracked
1476 ? = not tracked
1474 '''
1477 '''
1475
1478
1476 cwd = repo.getcwd()
1479 cwd = repo.getcwd()
1477 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1480 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1478 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1481 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1479 for n in repo.changes(files=files, match=matchfn)]
1482 for n in repo.changes(files=files, match=matchfn)]
1480
1483
1481 changetypes = [('modified', 'M', c),
1484 changetypes = [('modified', 'M', c),
1482 ('added', 'A', a),
1485 ('added', 'A', a),
1483 ('removed', 'R', d),
1486 ('removed', 'R', d),
1484 ('unknown', '?', u)]
1487 ('unknown', '?', u)]
1485
1488
1486 end = opts['print0'] and '\0' or '\n'
1489 end = opts['print0'] and '\0' or '\n'
1487
1490
1488 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1491 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1489 or changetypes):
1492 or changetypes):
1490 if opts['no_status']:
1493 if opts['no_status']:
1491 format = "%%s%s" % end
1494 format = "%%s%s" % end
1492 else:
1495 else:
1493 format = "%s %%s%s" % (char, end);
1496 format = "%s %%s%s" % (char, end);
1494
1497
1495 for f in changes:
1498 for f in changes:
1496 ui.write(format % f)
1499 ui.write(format % f)
1497
1500
1498 def tag(ui, repo, name, rev=None, **opts):
1501 def tag(ui, repo, name, rev=None, **opts):
1499 """add a tag for the current tip or a given revision"""
1502 """add a tag for the current tip or a given revision"""
1500 if opts['text']:
1503 if opts['text']:
1501 ui.warn("Warning: -t and --text is deprecated,"
1504 ui.warn("Warning: -t and --text is deprecated,"
1502 " please use -m or --message instead.\n")
1505 " please use -m or --message instead.\n")
1503 if name == "tip":
1506 if name == "tip":
1504 raise util.Abort("the name 'tip' is reserved")
1507 raise util.Abort("the name 'tip' is reserved")
1505 if rev:
1508 if rev:
1506 r = hex(repo.lookup(rev))
1509 r = hex(repo.lookup(rev))
1507 else:
1510 else:
1508 r = hex(repo.changelog.tip())
1511 r = hex(repo.changelog.tip())
1509
1512
1510 if name.find(revrangesep) >= 0:
1513 if name.find(revrangesep) >= 0:
1511 raise util.Abort("'%s' cannot be used in a tag name" % revrangesep)
1514 raise util.Abort("'%s' cannot be used in a tag name" % revrangesep)
1512
1515
1513 if opts['local']:
1516 if opts['local']:
1514 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1517 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1515 return
1518 return
1516
1519
1517 (c, a, d, u) = repo.changes()
1520 (c, a, d, u) = repo.changes()
1518 for x in (c, a, d, u):
1521 for x in (c, a, d, u):
1519 if ".hgtags" in x:
1522 if ".hgtags" in x:
1520 raise util.Abort("working copy of .hgtags is changed "
1523 raise util.Abort("working copy of .hgtags is changed "
1521 "(please commit .hgtags manually)")
1524 "(please commit .hgtags manually)")
1522
1525
1523 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1526 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1524 if repo.dirstate.state(".hgtags") == '?':
1527 if repo.dirstate.state(".hgtags") == '?':
1525 repo.add([".hgtags"])
1528 repo.add([".hgtags"])
1526
1529
1527 message = (opts['message'] or opts['text'] or
1530 message = (opts['message'] or opts['text'] or
1528 "Added tag %s for changeset %s" % (name, r))
1531 "Added tag %s for changeset %s" % (name, r))
1529 try:
1532 try:
1530 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1533 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1531 except ValueError, inst:
1534 except ValueError, inst:
1532 raise util.Abort(str(inst))
1535 raise util.Abort(str(inst))
1533
1536
1534 def tags(ui, repo):
1537 def tags(ui, repo):
1535 """list repository tags"""
1538 """list repository tags"""
1536
1539
1537 l = repo.tagslist()
1540 l = repo.tagslist()
1538 l.reverse()
1541 l.reverse()
1539 for t, n in l:
1542 for t, n in l:
1540 try:
1543 try:
1541 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
1544 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
1542 except KeyError:
1545 except KeyError:
1543 r = " ?:?"
1546 r = " ?:?"
1544 ui.write("%-30s %s\n" % (t, r))
1547 ui.write("%-30s %s\n" % (t, r))
1545
1548
1546 def tip(ui, repo):
1549 def tip(ui, repo):
1547 """show the tip revision"""
1550 """show the tip revision"""
1548 n = repo.changelog.tip()
1551 n = repo.changelog.tip()
1549 show_changeset(ui, repo, changenode=n)
1552 show_changeset(ui, repo, changenode=n)
1550
1553
1551 def unbundle(ui, repo, fname):
1554 def unbundle(ui, repo, fname):
1552 """apply a changegroup file"""
1555 """apply a changegroup file"""
1553 f = urllib.urlopen(fname)
1556 f = urllib.urlopen(fname)
1554
1557
1555 if f.read(4) != "HG10":
1558 if f.read(4) != "HG10":
1556 raise util.Abort("%s: not a Mercurial bundle file" % fname)
1559 raise util.Abort("%s: not a Mercurial bundle file" % fname)
1557
1560
1558 class bzread:
1561 class bzread:
1559 def __init__(self, f):
1562 def __init__(self, f):
1560 self.zd = bz2.BZ2Decompressor()
1563 self.zd = bz2.BZ2Decompressor()
1561 self.f = f
1564 self.f = f
1562 self.buf = ""
1565 self.buf = ""
1563 def read(self, l):
1566 def read(self, l):
1564 while l > len(self.buf):
1567 while l > len(self.buf):
1565 r = self.f.read(4096)
1568 r = self.f.read(4096)
1566 if r:
1569 if r:
1567 self.buf += self.zd.decompress(r)
1570 self.buf += self.zd.decompress(r)
1568 else:
1571 else:
1569 break
1572 break
1570 d, self.buf = self.buf[:l], self.buf[l:]
1573 d, self.buf = self.buf[:l], self.buf[l:]
1571 return d
1574 return d
1572
1575
1573 repo.addchangegroup(bzread(f))
1576 repo.addchangegroup(bzread(f))
1574
1577
1575 def undo(ui, repo):
1578 def undo(ui, repo):
1576 """undo the last commit or pull
1579 """undo the last commit or pull
1577
1580
1578 Roll back the last pull or commit transaction on the
1581 Roll back the last pull or commit transaction on the
1579 repository, restoring the project to its earlier state.
1582 repository, restoring the project to its earlier state.
1580
1583
1581 This command should be used with care. There is only one level of
1584 This command should be used with care. There is only one level of
1582 undo and there is no redo.
1585 undo and there is no redo.
1583
1586
1584 This command is not intended for use on public repositories. Once
1587 This command is not intended for use on public repositories. Once
1585 a change is visible for pull by other users, undoing it locally is
1588 a change is visible for pull by other users, undoing it locally is
1586 ineffective.
1589 ineffective.
1587 """
1590 """
1588 repo.undo()
1591 repo.undo()
1589
1592
1590 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1593 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1591 '''update or merge working directory
1594 '''update or merge working directory
1592
1595
1593 If there are no outstanding changes in the working directory and
1596 If there are no outstanding changes in the working directory and
1594 there is a linear relationship between the current version and the
1597 there is a linear relationship between the current version and the
1595 requested version, the result is the requested version.
1598 requested version, the result is the requested version.
1596
1599
1597 Otherwise the result is a merge between the contents of the
1600 Otherwise the result is a merge between the contents of the
1598 current working directory and the requested version. Files that
1601 current working directory and the requested version. Files that
1599 changed between either parent are marked as changed for the next
1602 changed between either parent are marked as changed for the next
1600 commit and a commit must be performed before any further updates
1603 commit and a commit must be performed before any further updates
1601 are allowed.
1604 are allowed.
1602 '''
1605 '''
1603 if branch:
1606 if branch:
1604 br = repo.branchlookup(branch=branch)
1607 br = repo.branchlookup(branch=branch)
1605 found = []
1608 found = []
1606 for x in br:
1609 for x in br:
1607 if branch in br[x]:
1610 if branch in br[x]:
1608 found.append(x)
1611 found.append(x)
1609 if len(found) > 1:
1612 if len(found) > 1:
1610 ui.warn("Found multiple heads for %s\n" % branch)
1613 ui.warn("Found multiple heads for %s\n" % branch)
1611 for x in found:
1614 for x in found:
1612 show_changeset(ui, repo, changenode=x, brinfo=br)
1615 show_changeset(ui, repo, changenode=x, brinfo=br)
1613 return 1
1616 return 1
1614 if len(found) == 1:
1617 if len(found) == 1:
1615 node = found[0]
1618 node = found[0]
1616 ui.warn("Using head %s for branch %s\n" % (short(node), branch))
1619 ui.warn("Using head %s for branch %s\n" % (short(node), branch))
1617 else:
1620 else:
1618 ui.warn("branch %s not found\n" % (branch))
1621 ui.warn("branch %s not found\n" % (branch))
1619 return 1
1622 return 1
1620 else:
1623 else:
1621 node = node and repo.lookup(node) or repo.changelog.tip()
1624 node = node and repo.lookup(node) or repo.changelog.tip()
1622 return repo.update(node, allow=merge, force=clean)
1625 return repo.update(node, allow=merge, force=clean)
1623
1626
1624 def verify(ui, repo):
1627 def verify(ui, repo):
1625 """verify the integrity of the repository"""
1628 """verify the integrity of the repository"""
1626 return repo.verify()
1629 return repo.verify()
1627
1630
1628 # Command options and aliases are listed here, alphabetically
1631 # Command options and aliases are listed here, alphabetically
1629
1632
1630 table = {
1633 table = {
1631 "^add":
1634 "^add":
1632 (add,
1635 (add,
1633 [('I', 'include', [], 'include path in search'),
1636 [('I', 'include', [], 'include path in search'),
1634 ('X', 'exclude', [], 'exclude path from search')],
1637 ('X', 'exclude', [], 'exclude path from search')],
1635 "hg add [OPTION]... [FILE]..."),
1638 "hg add [OPTION]... [FILE]..."),
1636 "addremove":
1639 "addremove":
1637 (addremove,
1640 (addremove,
1638 [('I', 'include', [], 'include path in search'),
1641 [('I', 'include', [], 'include path in search'),
1639 ('X', 'exclude', [], 'exclude path from search')],
1642 ('X', 'exclude', [], 'exclude path from search')],
1640 "hg addremove [OPTION]... [FILE]..."),
1643 "hg addremove [OPTION]... [FILE]..."),
1641 "^annotate":
1644 "^annotate":
1642 (annotate,
1645 (annotate,
1643 [('r', 'rev', '', 'revision'),
1646 [('r', 'rev', '', 'revision'),
1644 ('a', 'text', None, 'treat all files as text'),
1647 ('a', 'text', None, 'treat all files as text'),
1645 ('u', 'user', None, 'show user'),
1648 ('u', 'user', None, 'show user'),
1646 ('n', 'number', None, 'show revision number'),
1649 ('n', 'number', None, 'show revision number'),
1647 ('c', 'changeset', None, 'show changeset'),
1650 ('c', 'changeset', None, 'show changeset'),
1648 ('I', 'include', [], 'include path in search'),
1651 ('I', 'include', [], 'include path in search'),
1649 ('X', 'exclude', [], 'exclude path from search')],
1652 ('X', 'exclude', [], 'exclude path from search')],
1650 'hg annotate [OPTION]... FILE...'),
1653 'hg annotate [OPTION]... FILE...'),
1651 "bundle":
1654 "bundle":
1652 (bundle,
1655 (bundle,
1653 [],
1656 [],
1654 'hg bundle FILE DEST'),
1657 'hg bundle FILE DEST'),
1655 "cat":
1658 "cat":
1656 (cat,
1659 (cat,
1657 [('o', 'output', "", 'output to file')],
1660 [('o', 'output', "", 'output to file')],
1658 'hg cat [-o OUTFILE] FILE [REV]'),
1661 'hg cat [-o OUTFILE] FILE [REV]'),
1659 "^clone":
1662 "^clone":
1660 (clone,
1663 (clone,
1661 [('U', 'noupdate', None, 'skip update after cloning'),
1664 [('U', 'noupdate', None, 'skip update after cloning'),
1662 ('e', 'ssh', "", 'ssh command'),
1665 ('e', 'ssh', "", 'ssh command'),
1663 ('', 'remotecmd', "", 'remote hg command')],
1666 ('', 'remotecmd', "", 'remote hg command')],
1664 'hg clone [OPTION]... SOURCE [DEST]'),
1667 'hg clone [OPTION]... SOURCE [DEST]'),
1665 "^commit|ci":
1668 "^commit|ci":
1666 (commit,
1669 (commit,
1667 [('A', 'addremove', None, 'run add/remove during commit'),
1670 [('A', 'addremove', None, 'run add/remove during commit'),
1668 ('I', 'include', [], 'include path in search'),
1671 ('I', 'include', [], 'include path in search'),
1669 ('X', 'exclude', [], 'exclude path from search'),
1672 ('X', 'exclude', [], 'exclude path from search'),
1670 ('m', 'message', "", 'commit message'),
1673 ('m', 'message', "", 'commit message'),
1671 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1674 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1672 ('l', 'logfile', "", 'commit message file'),
1675 ('l', 'logfile', "", 'commit message file'),
1673 ('d', 'date', "", 'date code'),
1676 ('d', 'date', "", 'date code'),
1674 ('u', 'user', "", 'user')],
1677 ('u', 'user', "", 'user')],
1675 'hg commit [OPTION]... [FILE]...'),
1678 'hg commit [OPTION]... [FILE]...'),
1676 "copy": (copy, [], 'hg copy SOURCE DEST'),
1679 "copy": (copy, [], 'hg copy SOURCE DEST'),
1677 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1680 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1678 "debugconfig": (debugconfig, [], 'debugconfig'),
1681 "debugconfig": (debugconfig, [], 'debugconfig'),
1679 "debugstate": (debugstate, [], 'debugstate'),
1682 "debugstate": (debugstate, [], 'debugstate'),
1680 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1683 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1681 "debugindex": (debugindex, [], 'debugindex FILE'),
1684 "debugindex": (debugindex, [], 'debugindex FILE'),
1682 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1685 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1683 "debugrename": (debugrename, [], 'debugrename FILE [REV]'),
1686 "debugrename": (debugrename, [], 'debugrename FILE [REV]'),
1684 "debugwalk":
1687 "debugwalk":
1685 (debugwalk,
1688 (debugwalk,
1686 [('I', 'include', [], 'include path in search'),
1689 [('I', 'include', [], 'include path in search'),
1687 ('X', 'exclude', [], 'exclude path from search')],
1690 ('X', 'exclude', [], 'exclude path from search')],
1688 'debugwalk [OPTION]... [FILE]...'),
1691 'debugwalk [OPTION]... [FILE]...'),
1689 "^diff":
1692 "^diff":
1690 (diff,
1693 (diff,
1691 [('r', 'rev', [], 'revision'),
1694 [('r', 'rev', [], 'revision'),
1692 ('a', 'text', None, 'treat all files as text'),
1695 ('a', 'text', None, 'treat all files as text'),
1693 ('I', 'include', [], 'include path in search'),
1696 ('I', 'include', [], 'include path in search'),
1694 ('X', 'exclude', [], 'exclude path from search')],
1697 ('X', 'exclude', [], 'exclude path from search')],
1695 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1698 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1696 "^export":
1699 "^export":
1697 (export,
1700 (export,
1698 [('o', 'output', "", 'output to file'),
1701 [('o', 'output', "", 'output to file'),
1699 ('a', 'text', None, 'treat all files as text')],
1702 ('a', 'text', None, 'treat all files as text')],
1700 "hg export [-a] [-o OUTFILE] REV..."),
1703 "hg export [-a] [-o OUTFILE] REV..."),
1701 "forget":
1704 "forget":
1702 (forget,
1705 (forget,
1703 [('I', 'include', [], 'include path in search'),
1706 [('I', 'include', [], 'include path in search'),
1704 ('X', 'exclude', [], 'exclude path from search')],
1707 ('X', 'exclude', [], 'exclude path from search')],
1705 "hg forget [OPTION]... FILE..."),
1708 "hg forget [OPTION]... FILE..."),
1706 "grep":
1709 "grep":
1707 (grep,
1710 (grep,
1708 [('0', 'print0', None, 'end fields with NUL'),
1711 [('0', 'print0', None, 'end fields with NUL'),
1709 ('I', 'include', [], 'include path in search'),
1712 ('I', 'include', [], 'include path in search'),
1710 ('X', 'exclude', [], 'include path in search'),
1713 ('X', 'exclude', [], 'include path in search'),
1711 ('', 'all', None, 'print all revisions with matches'),
1714 ('', 'all', None, 'print all revisions with matches'),
1712 ('i', 'ignore-case', None, 'ignore case when matching'),
1715 ('i', 'ignore-case', None, 'ignore case when matching'),
1713 ('l', 'files-with-matches', None, 'print names of files and revs with matches'),
1716 ('l', 'files-with-matches', None, 'print names of files and revs with matches'),
1714 ('n', 'line-number', None, 'print line numbers'),
1717 ('n', 'line-number', None, 'print line numbers'),
1715 ('r', 'rev', [], 'search in revision rev'),
1718 ('r', 'rev', [], 'search in revision rev'),
1716 ('u', 'user', None, 'print user who made change')],
1719 ('u', 'user', None, 'print user who made change')],
1717 "hg grep [OPTION]... PATTERN [FILE]..."),
1720 "hg grep [OPTION]... PATTERN [FILE]..."),
1718 "heads":
1721 "heads":
1719 (heads,
1722 (heads,
1720 [('b', 'branches', None, 'find branch info')],
1723 [('b', 'branches', None, 'find branch info')],
1721 'hg heads [-b]'),
1724 'hg heads [-b]'),
1722 "help": (help_, [], 'hg help [COMMAND]'),
1725 "help": (help_, [], 'hg help [COMMAND]'),
1723 "identify|id": (identify, [], 'hg identify'),
1726 "identify|id": (identify, [], 'hg identify'),
1724 "import|patch":
1727 "import|patch":
1725 (import_,
1728 (import_,
1726 [('p', 'strip', 1, 'path strip'),
1729 [('p', 'strip', 1, 'path strip'),
1727 ('f', 'force', None, 'skip check for outstanding changes'),
1730 ('f', 'force', None, 'skip check for outstanding changes'),
1728 ('b', 'base', "", 'base path')],
1731 ('b', 'base', "", 'base path')],
1729 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1732 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1730 "incoming|in": (incoming,
1733 "incoming|in": (incoming,
1731 [('p', 'patch', None, 'show patch')],
1734 [('p', 'patch', None, 'show patch')],
1732 'hg incoming [-p] [SOURCE]'),
1735 'hg incoming [-p] [SOURCE]'),
1733 "^init": (init, [], 'hg init [DEST]'),
1736 "^init": (init, [], 'hg init [DEST]'),
1734 "locate":
1737 "locate":
1735 (locate,
1738 (locate,
1736 [('r', 'rev', '', 'revision'),
1739 [('r', 'rev', '', 'revision'),
1737 ('0', 'print0', None, 'end filenames with NUL'),
1740 ('0', 'print0', None, 'end filenames with NUL'),
1738 ('f', 'fullpath', None, 'print complete paths'),
1741 ('f', 'fullpath', None, 'print complete paths'),
1739 ('I', 'include', [], 'include path in search'),
1742 ('I', 'include', [], 'include path in search'),
1740 ('X', 'exclude', [], 'exclude path from search')],
1743 ('X', 'exclude', [], 'exclude path from search')],
1741 'hg locate [OPTION]... [PATTERN]...'),
1744 'hg locate [OPTION]... [PATTERN]...'),
1742 "^log|history":
1745 "^log|history":
1743 (log,
1746 (log,
1744 [('I', 'include', [], 'include path in search'),
1747 [('I', 'include', [], 'include path in search'),
1745 ('X', 'exclude', [], 'exclude path from search'),
1748 ('X', 'exclude', [], 'exclude path from search'),
1749 ('b', 'branch', None, 'show branches'),
1746 ('r', 'rev', [], 'revision'),
1750 ('r', 'rev', [], 'revision'),
1747 ('p', 'patch', None, 'show patch')],
1751 ('p', 'patch', None, 'show patch')],
1748 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1752 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1749 "manifest": (manifest, [], 'hg manifest [REV]'),
1753 "manifest": (manifest, [], 'hg manifest [REV]'),
1750 "outgoing|out": (outgoing,
1754 "outgoing|out": (outgoing,
1751 [('p', 'patch', None, 'show patch')],
1755 [('p', 'patch', None, 'show patch')],
1752 'hg outgoing [-p] [DEST]'),
1756 'hg outgoing [-p] [DEST]'),
1753 "parents": (parents, [], 'hg parents [REV]'),
1757 "parents": (parents, [], 'hg parents [REV]'),
1754 "paths": (paths, [], 'hg paths [NAME]'),
1758 "paths": (paths, [], 'hg paths [NAME]'),
1755 "^pull":
1759 "^pull":
1756 (pull,
1760 (pull,
1757 [('u', 'update', None, 'update working directory'),
1761 [('u', 'update', None, 'update working directory'),
1758 ('e', 'ssh', "", 'ssh command'),
1762 ('e', 'ssh', "", 'ssh command'),
1759 ('', 'remotecmd', "", 'remote hg command')],
1763 ('', 'remotecmd', "", 'remote hg command')],
1760 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1764 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1761 "^push":
1765 "^push":
1762 (push,
1766 (push,
1763 [('f', 'force', None, 'force push'),
1767 [('f', 'force', None, 'force push'),
1764 ('e', 'ssh', "", 'ssh command'),
1768 ('e', 'ssh', "", 'ssh command'),
1765 ('', 'remotecmd', "", 'remote hg command')],
1769 ('', 'remotecmd', "", 'remote hg command')],
1766 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1770 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1767 "rawcommit":
1771 "rawcommit":
1768 (rawcommit,
1772 (rawcommit,
1769 [('p', 'parent', [], 'parent'),
1773 [('p', 'parent', [], 'parent'),
1770 ('d', 'date', "", 'date code'),
1774 ('d', 'date', "", 'date code'),
1771 ('u', 'user', "", 'user'),
1775 ('u', 'user', "", 'user'),
1772 ('F', 'files', "", 'file list'),
1776 ('F', 'files', "", 'file list'),
1773 ('m', 'message', "", 'commit message'),
1777 ('m', 'message', "", 'commit message'),
1774 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1778 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1775 ('l', 'logfile', "", 'commit message file')],
1779 ('l', 'logfile', "", 'commit message file')],
1776 'hg rawcommit [OPTION]... [FILE]...'),
1780 'hg rawcommit [OPTION]... [FILE]...'),
1777 "recover": (recover, [], "hg recover"),
1781 "recover": (recover, [], "hg recover"),
1778 "^remove|rm": (remove,
1782 "^remove|rm": (remove,
1779 [('I', 'include', [], 'include path in search'),
1783 [('I', 'include', [], 'include path in search'),
1780 ('X', 'exclude', [], 'exclude path from search')],
1784 ('X', 'exclude', [], 'exclude path from search')],
1781 "hg remove [OPTION]... FILE..."),
1785 "hg remove [OPTION]... FILE..."),
1782 "^revert":
1786 "^revert":
1783 (revert,
1787 (revert,
1784 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1788 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1785 ("r", "rev", "", "revision")],
1789 ("r", "rev", "", "revision")],
1786 "hg revert [-n] [-r REV] [NAME]..."),
1790 "hg revert [-n] [-r REV] [NAME]..."),
1787 "root": (root, [], "hg root"),
1791 "root": (root, [], "hg root"),
1788 "^serve":
1792 "^serve":
1789 (serve,
1793 (serve,
1790 [('A', 'accesslog', '', 'access log file'),
1794 [('A', 'accesslog', '', 'access log file'),
1791 ('E', 'errorlog', '', 'error log file'),
1795 ('E', 'errorlog', '', 'error log file'),
1792 ('p', 'port', 0, 'listen port'),
1796 ('p', 'port', 0, 'listen port'),
1793 ('a', 'address', '', 'interface address'),
1797 ('a', 'address', '', 'interface address'),
1794 ('n', 'name', "", 'repository name'),
1798 ('n', 'name', "", 'repository name'),
1795 ('', 'stdio', None, 'for remote clients'),
1799 ('', 'stdio', None, 'for remote clients'),
1796 ('t', 'templates', "", 'template directory'),
1800 ('t', 'templates', "", 'template directory'),
1797 ('', 'style', "", 'template style'),
1801 ('', 'style', "", 'template style'),
1798 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1802 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1799 "hg serve [OPTION]..."),
1803 "hg serve [OPTION]..."),
1800 "^status":
1804 "^status":
1801 (status,
1805 (status,
1802 [('m', 'modified', None, 'show only modified files'),
1806 [('m', 'modified', None, 'show only modified files'),
1803 ('a', 'added', None, 'show only added files'),
1807 ('a', 'added', None, 'show only added files'),
1804 ('r', 'removed', None, 'show only removed files'),
1808 ('r', 'removed', None, 'show only removed files'),
1805 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1809 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1806 ('n', 'no-status', None, 'hide status prefix'),
1810 ('n', 'no-status', None, 'hide status prefix'),
1807 ('0', 'print0', None, 'end filenames with NUL'),
1811 ('0', 'print0', None, 'end filenames with NUL'),
1808 ('I', 'include', [], 'include path in search'),
1812 ('I', 'include', [], 'include path in search'),
1809 ('X', 'exclude', [], 'exclude path from search')],
1813 ('X', 'exclude', [], 'exclude path from search')],
1810 "hg status [OPTION]... [FILE]..."),
1814 "hg status [OPTION]... [FILE]..."),
1811 "tag":
1815 "tag":
1812 (tag,
1816 (tag,
1813 [('l', 'local', None, 'make the tag local'),
1817 [('l', 'local', None, 'make the tag local'),
1814 ('m', 'message', "", 'commit message'),
1818 ('m', 'message', "", 'commit message'),
1815 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1819 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1816 ('d', 'date', "", 'date code'),
1820 ('d', 'date', "", 'date code'),
1817 ('u', 'user', "", 'user')],
1821 ('u', 'user', "", 'user')],
1818 'hg tag [OPTION]... NAME [REV]'),
1822 'hg tag [OPTION]... NAME [REV]'),
1819 "tags": (tags, [], 'hg tags'),
1823 "tags": (tags, [], 'hg tags'),
1820 "tip": (tip, [], 'hg tip'),
1824 "tip": (tip, [], 'hg tip'),
1821 "unbundle":
1825 "unbundle":
1822 (unbundle,
1826 (unbundle,
1823 [],
1827 [],
1824 'hg unbundle FILE'),
1828 'hg unbundle FILE'),
1825 "undo": (undo, [], 'hg undo'),
1829 "undo": (undo, [], 'hg undo'),
1826 "^update|up|checkout|co":
1830 "^update|up|checkout|co":
1827 (update,
1831 (update,
1828 [('b', 'branch', "", 'checkout the head of a specific branch'),
1832 [('b', 'branch', "", 'checkout the head of a specific branch'),
1829 ('m', 'merge', None, 'allow merging of conflicts'),
1833 ('m', 'merge', None, 'allow merging of conflicts'),
1830 ('C', 'clean', None, 'overwrite locally modified files')],
1834 ('C', 'clean', None, 'overwrite locally modified files')],
1831 'hg update [-b TAG] [-m] [-C] [REV]'),
1835 'hg update [-b TAG] [-m] [-C] [REV]'),
1832 "verify": (verify, [], 'hg verify'),
1836 "verify": (verify, [], 'hg verify'),
1833 "version": (show_version, [], 'hg version'),
1837 "version": (show_version, [], 'hg version'),
1834 }
1838 }
1835
1839
1836 globalopts = [
1840 globalopts = [
1837 ('R', 'repository', "", 'repository root directory'),
1841 ('R', 'repository', "", 'repository root directory'),
1838 ('', 'cwd', '', 'change working directory'),
1842 ('', 'cwd', '', 'change working directory'),
1839 ('y', 'noninteractive', None, 'run non-interactively'),
1843 ('y', 'noninteractive', None, 'run non-interactively'),
1840 ('q', 'quiet', None, 'quiet mode'),
1844 ('q', 'quiet', None, 'quiet mode'),
1841 ('v', 'verbose', None, 'verbose mode'),
1845 ('v', 'verbose', None, 'verbose mode'),
1842 ('', 'debug', None, 'debug mode'),
1846 ('', 'debug', None, 'debug mode'),
1843 ('', 'debugger', None, 'start debugger'),
1847 ('', 'debugger', None, 'start debugger'),
1844 ('', 'traceback', None, 'print traceback on exception'),
1848 ('', 'traceback', None, 'print traceback on exception'),
1845 ('', 'time', None, 'time how long the command takes'),
1849 ('', 'time', None, 'time how long the command takes'),
1846 ('', 'profile', None, 'profile'),
1850 ('', 'profile', None, 'profile'),
1847 ('', 'version', None, 'output version information and exit'),
1851 ('', 'version', None, 'output version information and exit'),
1848 ('h', 'help', None, 'display help and exit'),
1852 ('h', 'help', None, 'display help and exit'),
1849 ]
1853 ]
1850
1854
1851 norepo = ("clone init version help debugconfig debugdata"
1855 norepo = ("clone init version help debugconfig debugdata"
1852 " debugindex debugindexdot paths")
1856 " debugindex debugindexdot paths")
1853
1857
1854 def find(cmd):
1858 def find(cmd):
1855 for e in table.keys():
1859 for e in table.keys():
1856 if re.match("(%s)$" % e, cmd):
1860 if re.match("(%s)$" % e, cmd):
1857 return e, table[e]
1861 return e, table[e]
1858
1862
1859 raise UnknownCommand(cmd)
1863 raise UnknownCommand(cmd)
1860
1864
1861 class SignalInterrupt(Exception):
1865 class SignalInterrupt(Exception):
1862 """Exception raised on SIGTERM and SIGHUP."""
1866 """Exception raised on SIGTERM and SIGHUP."""
1863
1867
1864 def catchterm(*args):
1868 def catchterm(*args):
1865 raise SignalInterrupt
1869 raise SignalInterrupt
1866
1870
1867 def run():
1871 def run():
1868 sys.exit(dispatch(sys.argv[1:]))
1872 sys.exit(dispatch(sys.argv[1:]))
1869
1873
1870 class ParseError(Exception):
1874 class ParseError(Exception):
1871 """Exception raised on errors in parsing the command line."""
1875 """Exception raised on errors in parsing the command line."""
1872
1876
1873 def parse(args):
1877 def parse(args):
1874 options = {}
1878 options = {}
1875 cmdoptions = {}
1879 cmdoptions = {}
1876
1880
1877 try:
1881 try:
1878 args = fancyopts.fancyopts(args, globalopts, options)
1882 args = fancyopts.fancyopts(args, globalopts, options)
1879 except fancyopts.getopt.GetoptError, inst:
1883 except fancyopts.getopt.GetoptError, inst:
1880 raise ParseError(None, inst)
1884 raise ParseError(None, inst)
1881
1885
1882 if args:
1886 if args:
1883 cmd, args = args[0], args[1:]
1887 cmd, args = args[0], args[1:]
1884 i = find(cmd)[1]
1888 i = find(cmd)[1]
1885 c = list(i[1])
1889 c = list(i[1])
1886 else:
1890 else:
1887 cmd = None
1891 cmd = None
1888 c = []
1892 c = []
1889
1893
1890 # combine global options into local
1894 # combine global options into local
1891 for o in globalopts:
1895 for o in globalopts:
1892 c.append((o[0], o[1], options[o[1]], o[3]))
1896 c.append((o[0], o[1], options[o[1]], o[3]))
1893
1897
1894 try:
1898 try:
1895 args = fancyopts.fancyopts(args, c, cmdoptions)
1899 args = fancyopts.fancyopts(args, c, cmdoptions)
1896 except fancyopts.getopt.GetoptError, inst:
1900 except fancyopts.getopt.GetoptError, inst:
1897 raise ParseError(cmd, inst)
1901 raise ParseError(cmd, inst)
1898
1902
1899 # separate global options back out
1903 # separate global options back out
1900 for o in globalopts:
1904 for o in globalopts:
1901 n = o[1]
1905 n = o[1]
1902 options[n] = cmdoptions[n]
1906 options[n] = cmdoptions[n]
1903 del cmdoptions[n]
1907 del cmdoptions[n]
1904
1908
1905 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
1909 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
1906
1910
1907 def dispatch(args):
1911 def dispatch(args):
1908 signal.signal(signal.SIGTERM, catchterm)
1912 signal.signal(signal.SIGTERM, catchterm)
1909 try:
1913 try:
1910 signal.signal(signal.SIGHUP, catchterm)
1914 signal.signal(signal.SIGHUP, catchterm)
1911 except AttributeError:
1915 except AttributeError:
1912 pass
1916 pass
1913
1917
1914 u = ui.ui()
1918 u = ui.ui()
1915 external = []
1919 external = []
1916 for x in u.extensions():
1920 for x in u.extensions():
1917 if x[1]:
1921 if x[1]:
1918 mod = imp.load_source(x[0], x[1])
1922 mod = imp.load_source(x[0], x[1])
1919 else:
1923 else:
1920 def importh(name):
1924 def importh(name):
1921 mod = __import__(name)
1925 mod = __import__(name)
1922 components = name.split('.')
1926 components = name.split('.')
1923 for comp in components[1:]:
1927 for comp in components[1:]:
1924 mod = getattr(mod, comp)
1928 mod = getattr(mod, comp)
1925 return mod
1929 return mod
1926 mod = importh(x[0])
1930 mod = importh(x[0])
1927 external.append(mod)
1931 external.append(mod)
1928 for x in external:
1932 for x in external:
1929 for t in x.cmdtable:
1933 for t in x.cmdtable:
1930 if t in table:
1934 if t in table:
1931 u.warn("module %s override %s\n" % (x.__name__, t))
1935 u.warn("module %s override %s\n" % (x.__name__, t))
1932 table.update(x.cmdtable)
1936 table.update(x.cmdtable)
1933
1937
1934 try:
1938 try:
1935 cmd, func, args, options, cmdoptions = parse(args)
1939 cmd, func, args, options, cmdoptions = parse(args)
1936 except ParseError, inst:
1940 except ParseError, inst:
1937 if inst.args[0]:
1941 if inst.args[0]:
1938 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1942 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1939 help_(u, inst.args[0])
1943 help_(u, inst.args[0])
1940 else:
1944 else:
1941 u.warn("hg: %s\n" % inst.args[1])
1945 u.warn("hg: %s\n" % inst.args[1])
1942 help_(u, 'shortlist')
1946 help_(u, 'shortlist')
1943 sys.exit(-1)
1947 sys.exit(-1)
1944 except UnknownCommand, inst:
1948 except UnknownCommand, inst:
1945 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1949 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1946 help_(u, 'shortlist')
1950 help_(u, 'shortlist')
1947 sys.exit(1)
1951 sys.exit(1)
1948
1952
1949 if options["time"]:
1953 if options["time"]:
1950 def get_times():
1954 def get_times():
1951 t = os.times()
1955 t = os.times()
1952 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1956 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1953 t = (t[0], t[1], t[2], t[3], time.clock())
1957 t = (t[0], t[1], t[2], t[3], time.clock())
1954 return t
1958 return t
1955 s = get_times()
1959 s = get_times()
1956 def print_time():
1960 def print_time():
1957 t = get_times()
1961 t = get_times()
1958 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1962 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1959 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1963 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1960 atexit.register(print_time)
1964 atexit.register(print_time)
1961
1965
1962 u.updateopts(options["verbose"], options["debug"], options["quiet"],
1966 u.updateopts(options["verbose"], options["debug"], options["quiet"],
1963 not options["noninteractive"])
1967 not options["noninteractive"])
1964
1968
1965 # enter the debugger before command execution
1969 # enter the debugger before command execution
1966 if options['debugger']:
1970 if options['debugger']:
1967 pdb.set_trace()
1971 pdb.set_trace()
1968
1972
1969 try:
1973 try:
1970 try:
1974 try:
1971 if options['help']:
1975 if options['help']:
1972 help_(u, cmd, options['version'])
1976 help_(u, cmd, options['version'])
1973 sys.exit(0)
1977 sys.exit(0)
1974 elif options['version']:
1978 elif options['version']:
1975 show_version(u)
1979 show_version(u)
1976 sys.exit(0)
1980 sys.exit(0)
1977 elif not cmd:
1981 elif not cmd:
1978 help_(u, 'shortlist')
1982 help_(u, 'shortlist')
1979 sys.exit(0)
1983 sys.exit(0)
1980
1984
1981 if options['cwd']:
1985 if options['cwd']:
1982 try:
1986 try:
1983 os.chdir(options['cwd'])
1987 os.chdir(options['cwd'])
1984 except OSError, inst:
1988 except OSError, inst:
1985 raise util.Abort('%s: %s' %
1989 raise util.Abort('%s: %s' %
1986 (options['cwd'], inst.strerror))
1990 (options['cwd'], inst.strerror))
1987
1991
1988 if cmd not in norepo.split():
1992 if cmd not in norepo.split():
1989 path = options["repository"] or ""
1993 path = options["repository"] or ""
1990 repo = hg.repository(ui=u, path=path)
1994 repo = hg.repository(ui=u, path=path)
1991 for x in external:
1995 for x in external:
1992 x.reposetup(u, repo)
1996 x.reposetup(u, repo)
1993 d = lambda: func(u, repo, *args, **cmdoptions)
1997 d = lambda: func(u, repo, *args, **cmdoptions)
1994 else:
1998 else:
1995 d = lambda: func(u, *args, **cmdoptions)
1999 d = lambda: func(u, *args, **cmdoptions)
1996
2000
1997 if options['profile']:
2001 if options['profile']:
1998 import hotshot, hotshot.stats
2002 import hotshot, hotshot.stats
1999 prof = hotshot.Profile("hg.prof")
2003 prof = hotshot.Profile("hg.prof")
2000 r = prof.runcall(d)
2004 r = prof.runcall(d)
2001 prof.close()
2005 prof.close()
2002 stats = hotshot.stats.load("hg.prof")
2006 stats = hotshot.stats.load("hg.prof")
2003 stats.strip_dirs()
2007 stats.strip_dirs()
2004 stats.sort_stats('time', 'calls')
2008 stats.sort_stats('time', 'calls')
2005 stats.print_stats(40)
2009 stats.print_stats(40)
2006 return r
2010 return r
2007 else:
2011 else:
2008 return d()
2012 return d()
2009 except:
2013 except:
2010 # enter the debugger when we hit an exception
2014 # enter the debugger when we hit an exception
2011 if options['debugger']:
2015 if options['debugger']:
2012 pdb.post_mortem(sys.exc_info()[2])
2016 pdb.post_mortem(sys.exc_info()[2])
2013 if options['traceback']:
2017 if options['traceback']:
2014 traceback.print_exc()
2018 traceback.print_exc()
2015 raise
2019 raise
2016 except hg.RepoError, inst:
2020 except hg.RepoError, inst:
2017 u.warn("abort: ", inst, "!\n")
2021 u.warn("abort: ", inst, "!\n")
2018 except revlog.RevlogError, inst:
2022 except revlog.RevlogError, inst:
2019 u.warn("abort: ", inst, "!\n")
2023 u.warn("abort: ", inst, "!\n")
2020 except SignalInterrupt:
2024 except SignalInterrupt:
2021 u.warn("killed!\n")
2025 u.warn("killed!\n")
2022 except KeyboardInterrupt:
2026 except KeyboardInterrupt:
2023 try:
2027 try:
2024 u.warn("interrupted!\n")
2028 u.warn("interrupted!\n")
2025 except IOError, inst:
2029 except IOError, inst:
2026 if inst.errno == errno.EPIPE:
2030 if inst.errno == errno.EPIPE:
2027 if u.debugflag:
2031 if u.debugflag:
2028 u.warn("\nbroken pipe\n")
2032 u.warn("\nbroken pipe\n")
2029 else:
2033 else:
2030 raise
2034 raise
2031 except IOError, inst:
2035 except IOError, inst:
2032 if hasattr(inst, "code"):
2036 if hasattr(inst, "code"):
2033 u.warn("abort: %s\n" % inst)
2037 u.warn("abort: %s\n" % inst)
2034 elif hasattr(inst, "reason"):
2038 elif hasattr(inst, "reason"):
2035 u.warn("abort: error: %s\n" % inst.reason[1])
2039 u.warn("abort: error: %s\n" % inst.reason[1])
2036 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2040 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2037 if u.debugflag:
2041 if u.debugflag:
2038 u.warn("broken pipe\n")
2042 u.warn("broken pipe\n")
2039 else:
2043 else:
2040 raise
2044 raise
2041 except OSError, inst:
2045 except OSError, inst:
2042 if hasattr(inst, "filename"):
2046 if hasattr(inst, "filename"):
2043 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
2047 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
2044 else:
2048 else:
2045 u.warn("abort: %s\n" % inst.strerror)
2049 u.warn("abort: %s\n" % inst.strerror)
2046 except util.Abort, inst:
2050 except util.Abort, inst:
2047 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
2051 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
2048 sys.exit(1)
2052 sys.exit(1)
2049 except TypeError, inst:
2053 except TypeError, inst:
2050 # was this an argument error?
2054 # was this an argument error?
2051 tb = traceback.extract_tb(sys.exc_info()[2])
2055 tb = traceback.extract_tb(sys.exc_info()[2])
2052 if len(tb) > 2: # no
2056 if len(tb) > 2: # no
2053 raise
2057 raise
2054 u.debug(inst, "\n")
2058 u.debug(inst, "\n")
2055 u.warn("%s: invalid arguments\n" % cmd)
2059 u.warn("%s: invalid arguments\n" % cmd)
2056 help_(u, cmd)
2060 help_(u, cmd)
2057 except UnknownCommand, inst:
2061 except UnknownCommand, inst:
2058 u.warn("hg: unknown command '%s'\n" % inst.args[0])
2062 u.warn("hg: unknown command '%s'\n" % inst.args[0])
2059 help_(u, 'shortlist')
2063 help_(u, 'shortlist')
2060 except SystemExit:
2064 except SystemExit:
2061 # don't catch this in the catch-all below
2065 # don't catch this in the catch-all below
2062 raise
2066 raise
2063 except:
2067 except:
2064 u.warn("** unknown exception encountered, details follow\n")
2068 u.warn("** unknown exception encountered, details follow\n")
2065 u.warn("** report bug details to mercurial@selenic.com\n")
2069 u.warn("** report bug details to mercurial@selenic.com\n")
2066 raise
2070 raise
2067
2071
2068 sys.exit(-1)
2072 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now