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