##// END OF EJS Templates
hg import: better file accounting...
mpm@selenic.com -
r355:3e18360a default
parent child Browse files
Show More
@@ -1,749 +1,754 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 import os, re, sys, signal
8 import os, re, sys, signal
9 import fancyopts, ui, hg
9 import fancyopts, ui, hg
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "mdiff time hgweb traceback random signal")
11 demandload(globals(), "mdiff time hgweb traceback random signal")
12
12
13 class UnknownCommand(Exception): pass
13 class UnknownCommand(Exception): pass
14
14
15 def filterfiles(filters, files):
15 def filterfiles(filters, files):
16 l = [ x for x in files if x in filters ]
16 l = [ x for x in files if x in filters ]
17
17
18 for t in filters:
18 for t in filters:
19 if t and t[-1] != os.sep: t += os.sep
19 if t and t[-1] != os.sep: t += os.sep
20 l += [ x for x in files if x.startswith(t) ]
20 l += [ x for x in files if x.startswith(t) ]
21 return l
21 return l
22
22
23 def relfilter(repo, files):
23 def relfilter(repo, files):
24 if os.getcwd() != repo.root:
24 if os.getcwd() != repo.root:
25 p = os.getcwd()[len(repo.root) + 1: ]
25 p = os.getcwd()[len(repo.root) + 1: ]
26 return filterfiles([p], files)
26 return filterfiles([p], files)
27 return files
27 return files
28
28
29 def relpath(repo, args):
29 def relpath(repo, args):
30 if os.getcwd() != repo.root:
30 if os.getcwd() != repo.root:
31 p = os.getcwd()[len(repo.root) + 1: ]
31 p = os.getcwd()[len(repo.root) + 1: ]
32 return [ os.path.normpath(os.path.join(p, x)) for x in args ]
32 return [ os.path.normpath(os.path.join(p, x)) for x in args ]
33 return args
33 return args
34
34
35 def dodiff(repo, path, files = None, node1 = None, node2 = None):
35 def dodiff(repo, path, files = None, node1 = None, node2 = None):
36 def date(c):
36 def date(c):
37 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
37 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
38
38
39 if node2:
39 if node2:
40 change = repo.changelog.read(node2)
40 change = repo.changelog.read(node2)
41 mmap2 = repo.manifest.read(change[0])
41 mmap2 = repo.manifest.read(change[0])
42 (c, a, d) = repo.diffrevs(node1, node2)
42 (c, a, d) = repo.diffrevs(node1, node2)
43 def read(f): return repo.file(f).read(mmap2[f])
43 def read(f): return repo.file(f).read(mmap2[f])
44 date2 = date(change)
44 date2 = date(change)
45 else:
45 else:
46 date2 = time.asctime()
46 date2 = time.asctime()
47 (c, a, d, u) = repo.diffdir(path, node1)
47 (c, a, d, u) = repo.diffdir(path, node1)
48 if not node1:
48 if not node1:
49 node1 = repo.dirstate.parents()[0]
49 node1 = repo.dirstate.parents()[0]
50 def read(f): return file(os.path.join(repo.root, f)).read()
50 def read(f): return file(os.path.join(repo.root, f)).read()
51
51
52 change = repo.changelog.read(node1)
52 change = repo.changelog.read(node1)
53 mmap = repo.manifest.read(change[0])
53 mmap = repo.manifest.read(change[0])
54 date1 = date(change)
54 date1 = date(change)
55
55
56 if files:
56 if files:
57 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
57 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
58
58
59 for f in c:
59 for f in c:
60 to = None
60 to = None
61 if f in mmap:
61 if f in mmap:
62 to = repo.file(f).read(mmap[f])
62 to = repo.file(f).read(mmap[f])
63 tn = read(f)
63 tn = read(f)
64 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
64 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
65 for f in a:
65 for f in a:
66 to = None
66 to = None
67 tn = read(f)
67 tn = read(f)
68 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
68 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
69 for f in d:
69 for f in d:
70 to = repo.file(f).read(mmap[f])
70 to = repo.file(f).read(mmap[f])
71 tn = None
71 tn = None
72 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
72 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
73
73
74 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
74 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
75 """show a single changeset or file revision"""
75 """show a single changeset or file revision"""
76 changelog = repo.changelog
76 changelog = repo.changelog
77 if filelog:
77 if filelog:
78 log = filelog
78 log = filelog
79 filerev = rev
79 filerev = rev
80 node = filenode = filelog.node(filerev)
80 node = filenode = filelog.node(filerev)
81 changerev = filelog.linkrev(filenode)
81 changerev = filelog.linkrev(filenode)
82 changenode = changenode or changelog.node(changerev)
82 changenode = changenode or changelog.node(changerev)
83 else:
83 else:
84 log = changelog
84 log = changelog
85 changerev = rev
85 changerev = rev
86 if changenode is None:
86 if changenode is None:
87 changenode = changelog.node(changerev)
87 changenode = changelog.node(changerev)
88 elif not changerev:
88 elif not changerev:
89 rev = changerev = changelog.rev(changenode)
89 rev = changerev = changelog.rev(changenode)
90 node = changenode
90 node = changenode
91
91
92 if ui.quiet:
92 if ui.quiet:
93 ui.write("%d:%s\n" % (rev, hg.hex(node)))
93 ui.write("%d:%s\n" % (rev, hg.hex(node)))
94 return
94 return
95
95
96 changes = changelog.read(changenode)
96 changes = changelog.read(changenode)
97
97
98 parents = [(log.rev(parent), hg.hex(parent))
98 parents = [(log.rev(parent), hg.hex(parent))
99 for parent in log.parents(node)
99 for parent in log.parents(node)
100 if ui.debugflag or parent != hg.nullid]
100 if ui.debugflag or parent != hg.nullid]
101 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
101 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
102 parents = []
102 parents = []
103
103
104 if filelog:
104 if filelog:
105 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
105 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
106 for parent in parents:
106 for parent in parents:
107 ui.write("parent: %d:%s\n" % parent)
107 ui.write("parent: %d:%s\n" % parent)
108 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
108 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
109 else:
109 else:
110 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
110 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
111 for parent in parents:
111 for parent in parents:
112 ui.write("parent: %d:%s\n" % parent)
112 ui.write("parent: %d:%s\n" % parent)
113 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
113 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
114 hg.hex(changes[0])))
114 hg.hex(changes[0])))
115 ui.status("user: %s\n" % changes[1])
115 ui.status("user: %s\n" % changes[1])
116 ui.status("date: %s\n" % time.asctime(
116 ui.status("date: %s\n" % time.asctime(
117 time.localtime(float(changes[2].split(' ')[0]))))
117 time.localtime(float(changes[2].split(' ')[0]))))
118 ui.note("files: %s\n" % " ".join(changes[3]))
118 ui.note("files: %s\n" % " ".join(changes[3]))
119 description = changes[4].strip()
119 description = changes[4].strip()
120 if description:
120 if description:
121 if ui.verbose:
121 if ui.verbose:
122 ui.status("description:\n")
122 ui.status("description:\n")
123 ui.status(description)
123 ui.status(description)
124 ui.status("\n\n")
124 ui.status("\n\n")
125 else:
125 else:
126 ui.status("summary: %s\n" % description.splitlines()[0])
126 ui.status("summary: %s\n" % description.splitlines()[0])
127 ui.status("\n")
127 ui.status("\n")
128
128
129 def help(ui, cmd=None):
129 def help(ui, cmd=None):
130 '''show help for a given command or all commands'''
130 '''show help for a given command or all commands'''
131 if cmd:
131 if cmd:
132 try:
132 try:
133 i = find(cmd)
133 i = find(cmd)
134 ui.write("%s\n\n" % i[2])
134 ui.write("%s\n\n" % i[2])
135
135
136 if i[1]:
136 if i[1]:
137 for s, l, d, c in i[1]:
137 for s, l, d, c in i[1]:
138 opt=' '
138 opt=' '
139 if s: opt = opt + '-' + s + ' '
139 if s: opt = opt + '-' + s + ' '
140 if l: opt = opt + '--' + l + ' '
140 if l: opt = opt + '--' + l + ' '
141 if d: opt = opt + '(' + str(d) + ')'
141 if d: opt = opt + '(' + str(d) + ')'
142 ui.write(opt, "\n")
142 ui.write(opt, "\n")
143 if c: ui.write(' %s\n' % c)
143 if c: ui.write(' %s\n' % c)
144 ui.write("\n")
144 ui.write("\n")
145
145
146 ui.write(i[0].__doc__, "\n")
146 ui.write(i[0].__doc__, "\n")
147 except UnknownCommand:
147 except UnknownCommand:
148 ui.warn("hg: unknown command %s\n" % cmd)
148 ui.warn("hg: unknown command %s\n" % cmd)
149 sys.exit(0)
149 sys.exit(0)
150 else:
150 else:
151 ui.status('hg commands:\n\n')
151 ui.status('hg commands:\n\n')
152
152
153 h = {}
153 h = {}
154 for e in table.values():
154 for e in table.values():
155 f = e[0]
155 f = e[0]
156 if f.__name__.startswith("debug"): continue
156 if f.__name__.startswith("debug"): continue
157 d = ""
157 d = ""
158 if f.__doc__:
158 if f.__doc__:
159 d = f.__doc__.splitlines(0)[0].rstrip()
159 d = f.__doc__.splitlines(0)[0].rstrip()
160 h[f.__name__] = d
160 h[f.__name__] = d
161
161
162 fns = h.keys()
162 fns = h.keys()
163 fns.sort()
163 fns.sort()
164 m = max(map(len, fns))
164 m = max(map(len, fns))
165 for f in fns:
165 for f in fns:
166 ui.status(' %-*s %s\n' % (m, f, h[f]))
166 ui.status(' %-*s %s\n' % (m, f, h[f]))
167
167
168 # Commands start here, listed alphabetically
168 # Commands start here, listed alphabetically
169
169
170 def add(ui, repo, file, *files):
170 def add(ui, repo, file, *files):
171 '''add the specified files on the next commit'''
171 '''add the specified files on the next commit'''
172 repo.add(relpath(repo, (file,) + files))
172 repo.add(relpath(repo, (file,) + files))
173
173
174 def addremove(ui, repo, *files):
174 def addremove(ui, repo, *files):
175 """add all new files, delete all missing files"""
175 """add all new files, delete all missing files"""
176 if files:
176 if files:
177 files = relpath(repo, files)
177 files = relpath(repo, files)
178 d = []
178 d = []
179 u = []
179 u = []
180 for f in files:
180 for f in files:
181 p = repo.wjoin(f)
181 p = repo.wjoin(f)
182 s = repo.dirstate.state(f)
182 s = repo.dirstate.state(f)
183 isfile = os.path.isfile(p)
183 isfile = os.path.isfile(p)
184 if s != 'r' and not isfile:
184 if s != 'r' and not isfile:
185 d.append(f)
185 d.append(f)
186 elif s not in 'nmai' and isfile:
186 elif s not in 'nmai' and isfile:
187 u.append(f)
187 u.append(f)
188 else:
188 else:
189 (c, a, d, u) = repo.diffdir(repo.root)
189 (c, a, d, u) = repo.diffdir(repo.root)
190 repo.add(u)
190 repo.add(u)
191 repo.remove(d)
191 repo.remove(d)
192
192
193 def annotate(u, repo, file, *files, **ops):
193 def annotate(u, repo, file, *files, **ops):
194 """show changeset information per file line"""
194 """show changeset information per file line"""
195 def getnode(rev):
195 def getnode(rev):
196 return hg.short(repo.changelog.node(rev))
196 return hg.short(repo.changelog.node(rev))
197
197
198 def getname(rev):
198 def getname(rev):
199 try:
199 try:
200 return bcache[rev]
200 return bcache[rev]
201 except KeyError:
201 except KeyError:
202 cl = repo.changelog.read(repo.changelog.node(rev))
202 cl = repo.changelog.read(repo.changelog.node(rev))
203 name = cl[1]
203 name = cl[1]
204 f = name.find('@')
204 f = name.find('@')
205 if f >= 0:
205 if f >= 0:
206 name = name[:f]
206 name = name[:f]
207 bcache[rev] = name
207 bcache[rev] = name
208 return name
208 return name
209
209
210 bcache = {}
210 bcache = {}
211 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
211 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
212 if not ops['user'] and not ops['changeset']:
212 if not ops['user'] and not ops['changeset']:
213 ops['number'] = 1
213 ops['number'] = 1
214
214
215 node = repo.dirstate.parents()[0]
215 node = repo.dirstate.parents()[0]
216 if ops['revision']:
216 if ops['revision']:
217 node = repo.changelog.lookup(ops['revision'])
217 node = repo.changelog.lookup(ops['revision'])
218 change = repo.changelog.read(node)
218 change = repo.changelog.read(node)
219 mmap = repo.manifest.read(change[0])
219 mmap = repo.manifest.read(change[0])
220 maxuserlen = 0
220 maxuserlen = 0
221 maxchangelen = 0
221 maxchangelen = 0
222 for f in relpath(repo, (file,) + files):
222 for f in relpath(repo, (file,) + files):
223 lines = repo.file(f).annotate(mmap[f])
223 lines = repo.file(f).annotate(mmap[f])
224 pieces = []
224 pieces = []
225
225
226 for o, f in opmap:
226 for o, f in opmap:
227 if ops[o]:
227 if ops[o]:
228 l = [ f(n) for n,t in lines ]
228 l = [ f(n) for n,t in lines ]
229 m = max(map(len, l))
229 m = max(map(len, l))
230 pieces.append([ "%*s" % (m, x) for x in l])
230 pieces.append([ "%*s" % (m, x) for x in l])
231
231
232 for p,l in zip(zip(*pieces), lines):
232 for p,l in zip(zip(*pieces), lines):
233 u.write(" ".join(p) + ": " + l[1])
233 u.write(" ".join(p) + ": " + l[1])
234
234
235 def cat(ui, repo, file, rev = []):
235 def cat(ui, repo, file, rev = []):
236 """output the latest or given revision of a file"""
236 """output the latest or given revision of a file"""
237 r = repo.file(relpath(repo, [file])[0])
237 r = repo.file(relpath(repo, [file])[0])
238 n = r.tip()
238 n = r.tip()
239 if rev: n = r.lookup(rev)
239 if rev: n = r.lookup(rev)
240 sys.stdout.write(r.read(n))
240 sys.stdout.write(r.read(n))
241
241
242 def commit(ui, repo, *files, **opts):
242 def commit(ui, repo, *files, **opts):
243 """commit the specified files or all outstanding changes"""
243 """commit the specified files or all outstanding changes"""
244 text = opts['text']
244 text = opts['text']
245 if not text and opts['logfile']:
245 if not text and opts['logfile']:
246 try: text = open(opts['logfile']).read()
246 try: text = open(opts['logfile']).read()
247 except IOError: pass
247 except IOError: pass
248
248
249 if opts['addremove']:
249 if opts['addremove']:
250 addremove(ui, repo, *files)
250 addremove(ui, repo, *files)
251 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
251 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
252
252
253 def debugaddchangegroup(ui, repo):
253 def debugaddchangegroup(ui, repo):
254 data = sys.stdin.read()
254 data = sys.stdin.read()
255 repo.addchangegroup(data)
255 repo.addchangegroup(data)
256
256
257 def debugchangegroup(ui, repo, roots):
257 def debugchangegroup(ui, repo, roots):
258 newer = repo.newer(map(repo.lookup, roots))
258 newer = repo.newer(map(repo.lookup, roots))
259 for chunk in repo.changegroup(newer):
259 for chunk in repo.changegroup(newer):
260 sys.stdout.write(chunk)
260 sys.stdout.write(chunk)
261
261
262 def debugindex(ui, file):
262 def debugindex(ui, file):
263 r = hg.revlog(open, file, "")
263 r = hg.revlog(open, file, "")
264 print " rev offset length base linkrev"+\
264 print " rev offset length base linkrev"+\
265 " p1 p2 nodeid"
265 " p1 p2 nodeid"
266 for i in range(r.count()):
266 for i in range(r.count()):
267 e = r.index[i]
267 e = r.index[i]
268 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
268 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
269 i, e[0], e[1], e[2], e[3],
269 i, e[0], e[1], e[2], e[3],
270 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
270 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
271
271
272 def debugindexdot(ui, file):
272 def debugindexdot(ui, file):
273 r = hg.revlog(open, file, "")
273 r = hg.revlog(open, file, "")
274 print "digraph G {"
274 print "digraph G {"
275 for i in range(r.count()):
275 for i in range(r.count()):
276 e = r.index[i]
276 e = r.index[i]
277 print "\t%d -> %d" % (r.rev(e[4]), i)
277 print "\t%d -> %d" % (r.rev(e[4]), i)
278 if e[5] != hg.nullid:
278 if e[5] != hg.nullid:
279 print "\t%d -> %d" % (r.rev(e[5]), i)
279 print "\t%d -> %d" % (r.rev(e[5]), i)
280 print "}"
280 print "}"
281
281
282 def diff(ui, repo, *files, **opts):
282 def diff(ui, repo, *files, **opts):
283 """diff working directory (or selected files)"""
283 """diff working directory (or selected files)"""
284 revs = []
284 revs = []
285 if opts['rev']:
285 if opts['rev']:
286 revs = map(lambda x: repo.lookup(x), opts['rev'])
286 revs = map(lambda x: repo.lookup(x), opts['rev'])
287
287
288 if len(revs) > 2:
288 if len(revs) > 2:
289 self.ui.warn("too many revisions to diff\n")
289 self.ui.warn("too many revisions to diff\n")
290 sys.exit(1)
290 sys.exit(1)
291
291
292 if files:
292 if files:
293 files = relpath(repo, files)
293 files = relpath(repo, files)
294 else:
294 else:
295 files = relpath(repo, [""])
295 files = relpath(repo, [""])
296
296
297 dodiff(repo, os.getcwd(), files, *revs)
297 dodiff(repo, os.getcwd(), files, *revs)
298
298
299 def export(ui, repo, changeset):
299 def export(ui, repo, changeset):
300 """dump the changeset header and diffs for a revision"""
300 """dump the changeset header and diffs for a revision"""
301 node = repo.lookup(changeset)
301 node = repo.lookup(changeset)
302 prev, other = repo.changelog.parents(node)
302 prev, other = repo.changelog.parents(node)
303 change = repo.changelog.read(node)
303 change = repo.changelog.read(node)
304 print "# HG changeset patch"
304 print "# HG changeset patch"
305 print "# User %s" % change[1]
305 print "# User %s" % change[1]
306 print "# Node ID %s" % hg.hex(node)
306 print "# Node ID %s" % hg.hex(node)
307 print "# Parent %s" % hg.hex(prev)
307 print "# Parent %s" % hg.hex(prev)
308 print
308 print
309 if other != hg.nullid:
309 if other != hg.nullid:
310 print "# Parent %s" % hg.hex(other)
310 print "# Parent %s" % hg.hex(other)
311 print change[4].rstrip()
311 print change[4].rstrip()
312 print
312 print
313
313
314 dodiff(repo, "", None, prev, node)
314 dodiff(repo, "", None, prev, node)
315
315
316 def forget(ui, repo, file, *files):
316 def forget(ui, repo, file, *files):
317 """don't add the specified files on the next commit"""
317 """don't add the specified files on the next commit"""
318 repo.forget(relpath(repo, (file,) + files))
318 repo.forget(relpath(repo, (file,) + files))
319
319
320 def heads(ui, repo):
320 def heads(ui, repo):
321 """show current repository heads"""
321 """show current repository heads"""
322 for n in repo.changelog.heads():
322 for n in repo.changelog.heads():
323 show_changeset(ui, repo, changenode=n)
323 show_changeset(ui, repo, changenode=n)
324
324
325 def history(ui, repo):
325 def history(ui, repo):
326 """show the changelog history"""
326 """show the changelog history"""
327 for i in range(repo.changelog.count() - 1, -1, -1):
327 for i in range(repo.changelog.count() - 1, -1, -1):
328 show_changeset(ui, repo, rev=i)
328 show_changeset(ui, repo, rev=i)
329
329
330 def identify(ui, repo):
330 def identify(ui, repo):
331 """print information about the working copy"""
331 """print information about the working copy"""
332 (c, a, d, u) = repo.diffdir(repo.root)
332 (c, a, d, u) = repo.diffdir(repo.root)
333 mflag = (c or a or d or u) and "+" or ""
333 mflag = (c or a or d or u) and "+" or ""
334 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
334 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
335 if not parents:
335 if not parents:
336 ui.write("unknown\n")
336 ui.write("unknown\n")
337 return
337 return
338
338
339 tstring = ''
339 tstring = ''
340 if not ui.quiet:
340 if not ui.quiet:
341 tags = sum(map(repo.nodetags, parents), [])
341 tags = sum(map(repo.nodetags, parents), [])
342 tstring = " " + ' + '.join(tags)
342 tstring = " " + ' + '.join(tags)
343
343
344 hexfunc = ui.verbose and hg.hex or hg.short
344 hexfunc = ui.verbose and hg.hex or hg.short
345 pstring = '+'.join([hexfunc(parent) for parent in parents])
345 pstring = '+'.join([hexfunc(parent) for parent in parents])
346 ui.write("%s%s%s\n" % (pstring, mflag, tstring))
346 ui.write("%s%s%s\n" % (pstring, mflag, tstring))
347
347
348 def init(ui, source=None):
348 def init(ui, source=None):
349 """create a new repository or copy an existing one"""
349 """create a new repository or copy an existing one"""
350
350
351 if source:
351 if source:
352 paths = {}
352 paths = {}
353 for name, path in ui.configitems("paths"):
353 for name, path in ui.configitems("paths"):
354 paths[name] = path
354 paths[name] = path
355
355
356 if source in paths: source = paths[source]
356 if source in paths: source = paths[source]
357
357
358 link = 0
358 link = 0
359 if not source.startswith("http://"):
359 if not source.startswith("http://"):
360 d1 = os.stat(os.getcwd()).st_dev
360 d1 = os.stat(os.getcwd()).st_dev
361 d2 = os.stat(source).st_dev
361 d2 = os.stat(source).st_dev
362 if d1 == d2: link = 1
362 if d1 == d2: link = 1
363
363
364 if link:
364 if link:
365 ui.debug("copying by hardlink\n")
365 ui.debug("copying by hardlink\n")
366 os.system("cp -al %s/.hg .hg" % source)
366 os.system("cp -al %s/.hg .hg" % source)
367 try:
367 try:
368 os.remove(".hg/dirstate")
368 os.remove(".hg/dirstate")
369 except: pass
369 except: pass
370
370
371 repo = hg.repository(ui, ".")
371 repo = hg.repository(ui, ".")
372
372
373 else:
373 else:
374 repo = hg.repository(ui, ".", create=1)
374 repo = hg.repository(ui, ".", create=1)
375 other = hg.repository(ui, source)
375 other = hg.repository(ui, source)
376 cg = repo.getchangegroup(other)
376 cg = repo.getchangegroup(other)
377 repo.addchangegroup(cg)
377 repo.addchangegroup(cg)
378 else:
378 else:
379 repo = hg.repository(ui, ".", create=1)
379 repo = hg.repository(ui, ".", create=1)
380
380
381 f = repo.opener("hgrc", "w")
381 f = repo.opener("hgrc", "w")
382 f.write("[paths]\n")
382 f.write("[paths]\n")
383 f.write("default = %s\n" % source)
383 f.write("default = %s\n" % source)
384
384
385 def log(ui, repo, f):
385 def log(ui, repo, f):
386 """show the revision history of a single file"""
386 """show the revision history of a single file"""
387 f = relpath(repo, [f])[0]
387 f = relpath(repo, [f])[0]
388
388
389 r = repo.file(f)
389 r = repo.file(f)
390 for i in range(r.count() - 1, -1, -1):
390 for i in range(r.count() - 1, -1, -1):
391 show_changeset(ui, repo, filelog=r, rev=i)
391 show_changeset(ui, repo, filelog=r, rev=i)
392
392
393 def manifest(ui, repo, rev = []):
393 def manifest(ui, repo, rev = []):
394 """output the latest or given revision of the project manifest"""
394 """output the latest or given revision of the project manifest"""
395 n = repo.manifest.tip()
395 n = repo.manifest.tip()
396 if rev:
396 if rev:
397 n = repo.manifest.lookup(rev)
397 n = repo.manifest.lookup(rev)
398 m = repo.manifest.read(n)
398 m = repo.manifest.read(n)
399 mf = repo.manifest.readflags(n)
399 mf = repo.manifest.readflags(n)
400 files = m.keys()
400 files = m.keys()
401 files.sort()
401 files.sort()
402
402
403 for f in files:
403 for f in files:
404 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
404 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
405
405
406 def parents(ui, repo, node = None):
406 def parents(ui, repo, node = None):
407 '''show the parents of the current working dir'''
407 '''show the parents of the current working dir'''
408 if node:
408 if node:
409 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
409 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
410 else:
410 else:
411 p = repo.dirstate.parents()
411 p = repo.dirstate.parents()
412
412
413 for n in p:
413 for n in p:
414 if n != hg.nullid:
414 if n != hg.nullid:
415 show_changeset(ui, repo, changenode=n)
415 show_changeset(ui, repo, changenode=n)
416
416
417 def patch(ui, repo, patch1, *patches, **opts):
417 def patch(ui, repo, patch1, *patches, **opts):
418 """import an ordered set of patches"""
418 """import an ordered set of patches"""
419 try:
419 try:
420 import psyco
420 import psyco
421 psyco.full()
421 psyco.full()
422 except:
422 except:
423 pass
423 pass
424
424
425 patches = (patch1,) + patches
425 patches = (patch1,) + patches
426
426
427 d = opts["base"]
427 d = opts["base"]
428 strip = opts["strip"]
428 strip = opts["strip"]
429 quiet = opts["quiet"] and "> /dev/null" or ""
429 quiet = opts["quiet"] and "> /dev/null" or ""
430
430
431 for patch in patches:
431 for patch in patches:
432 ui.status("applying %s\n" % patch)
432 ui.status("applying %s\n" % patch)
433 pf = os.path.join(d, patch)
433 pf = os.path.join(d, patch)
434
434
435 text = ""
435 text = ""
436 for l in file(pf):
436 for l in file(pf):
437 if l[:4] == "--- ": break
437 if l[:4] == "--- ": break
438 text += l
438 text += l
439
439
440 # make sure text isn't empty
440 # make sure text isn't empty
441 if not text: text = "imported patch %s\n" % patch
441 if not text: text = "imported patch %s\n" % patch
442
442
443 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
443 f = os.popen("patch -p%d < %s" % (strip, pf))
444 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
444 files = []
445 for l in f.read().splitlines():
446 l.rstrip('\r\n');
447 if not quiet:
448 print l
449 if l[:14] == 'patching file ':
450 files.append(l[14:])
445 f.close()
451 f.close()
446
452
447 if files:
453 if len(files) > 0:
448 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
454 addremove(ui, repo, *files)
449 raise "patch failed!"
450 repo.commit(files, text)
455 repo.commit(files, text)
451
456
452 def pull(ui, repo, source="default"):
457 def pull(ui, repo, source="default"):
453 """pull changes from the specified source"""
458 """pull changes from the specified source"""
454 paths = {}
459 paths = {}
455 for name, path in ui.configitems("paths"):
460 for name, path in ui.configitems("paths"):
456 paths[name] = path
461 paths[name] = path
457
462
458 if source in paths: source = paths[source]
463 if source in paths: source = paths[source]
459
464
460 other = hg.repository(ui, source)
465 other = hg.repository(ui, source)
461 cg = repo.getchangegroup(other)
466 cg = repo.getchangegroup(other)
462 repo.addchangegroup(cg)
467 repo.addchangegroup(cg)
463
468
464 def push(ui, repo, dest):
469 def push(ui, repo, dest):
465 """push changes to the specified destination"""
470 """push changes to the specified destination"""
466 paths = {}
471 paths = {}
467 for name, path in ui.configitems("paths"):
472 for name, path in ui.configitems("paths"):
468 paths[name] = path
473 paths[name] = path
469
474
470 if dest in paths: dest = paths[dest]
475 if dest in paths: dest = paths[dest]
471
476
472 if not dest.startswith("ssh://"):
477 if not dest.startswith("ssh://"):
473 ui.warn("abort: can only push to ssh:// destinations currently\n")
478 ui.warn("abort: can only push to ssh:// destinations currently\n")
474 return 1
479 return 1
475
480
476 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
481 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
477 if not m:
482 if not m:
478 ui.warn("abort: couldn't parse destination %s\n" % dest)
483 ui.warn("abort: couldn't parse destination %s\n" % dest)
479 return 1
484 return 1
480
485
481 user, host, port, path = map(m.group, (2, 3, 5, 7))
486 user, host, port, path = map(m.group, (2, 3, 5, 7))
482 host = user and ("%s@%s" % (user, host)) or host
487 host = user and ("%s@%s" % (user, host)) or host
483 port = port and (" -p %s") % port or ""
488 port = port and (" -p %s") % port or ""
484 path = path or ""
489 path = path or ""
485
490
486 sport = random.randrange(30000, 60000)
491 sport = random.randrange(30000, 60000)
487 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
492 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
488 cmd = cmd % (host, port, sport+1, sport, path, sport+1)
493 cmd = cmd % (host, port, sport+1, sport, path, sport+1)
489
494
490 child = os.fork()
495 child = os.fork()
491 if not child:
496 if not child:
492 sys.stdout = file("/dev/null", "w")
497 sys.stdout = file("/dev/null", "w")
493 sys.stderr = sys.stdout
498 sys.stderr = sys.stdout
494 hgweb.server(repo.root, "pull", "", "localhost", sport)
499 hgweb.server(repo.root, "pull", "", "localhost", sport)
495 else:
500 else:
496 r = os.system(cmd)
501 r = os.system(cmd)
497 os.kill(child, signal.SIGTERM)
502 os.kill(child, signal.SIGTERM)
498 return r
503 return r
499
504
500 def rawcommit(ui, repo, flist, **rc):
505 def rawcommit(ui, repo, flist, **rc):
501 "raw commit interface"
506 "raw commit interface"
502
507
503 text = rc['text']
508 text = rc['text']
504 if not text and rc['logfile']:
509 if not text and rc['logfile']:
505 try: text = open(rc['logfile']).read()
510 try: text = open(rc['logfile']).read()
506 except IOError: pass
511 except IOError: pass
507 if not text and not rc['logfile']:
512 if not text and not rc['logfile']:
508 print "missing commit text"
513 print "missing commit text"
509 return 1
514 return 1
510
515
511 files = relpath(repo, flist)
516 files = relpath(repo, flist)
512 if rc['files']:
517 if rc['files']:
513 files += open(rc['files']).read().splitlines()
518 files += open(rc['files']).read().splitlines()
514
519
515 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
520 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
516
521
517 def recover(ui, repo):
522 def recover(ui, repo):
518 """roll back an interrupted transaction"""
523 """roll back an interrupted transaction"""
519 repo.recover()
524 repo.recover()
520
525
521 def remove(ui, repo, file, *files):
526 def remove(ui, repo, file, *files):
522 """remove the specified files on the next commit"""
527 """remove the specified files on the next commit"""
523 repo.remove(relpath(repo, (file,) + files))
528 repo.remove(relpath(repo, (file,) + files))
524
529
525 def serve(ui, repo, **opts):
530 def serve(ui, repo, **opts):
526 """export the repository via HTTP"""
531 """export the repository via HTTP"""
527 hgweb.server(repo.root, opts["name"], opts["templates"],
532 hgweb.server(repo.root, opts["name"], opts["templates"],
528 opts["address"], opts["port"])
533 opts["address"], opts["port"])
529
534
530 def status(ui, repo):
535 def status(ui, repo):
531 '''show changed files in the working directory
536 '''show changed files in the working directory
532
537
533 C = changed
538 C = changed
534 A = added
539 A = added
535 R = removed
540 R = removed
536 ? = not tracked'''
541 ? = not tracked'''
537
542
538 (c, a, d, u) = repo.diffdir(os.getcwd())
543 (c, a, d, u) = repo.diffdir(os.getcwd())
539 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
544 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
540
545
541 for f in c: print "C", f
546 for f in c: print "C", f
542 for f in a: print "A", f
547 for f in a: print "A", f
543 for f in d: print "R", f
548 for f in d: print "R", f
544 for f in u: print "?", f
549 for f in u: print "?", f
545
550
546 def tags(ui, repo):
551 def tags(ui, repo):
547 """list repository tags"""
552 """list repository tags"""
548
553
549 l = repo.tagslist()
554 l = repo.tagslist()
550 l.reverse()
555 l.reverse()
551 for t,n in l:
556 for t,n in l:
552 try:
557 try:
553 r = repo.changelog.rev(n)
558 r = repo.changelog.rev(n)
554 except KeyError:
559 except KeyError:
555 r = "?"
560 r = "?"
556 print "%-30s %5d:%s" % (t, repo.changelog.rev(n), hg.hex(n))
561 print "%-30s %5d:%s" % (t, repo.changelog.rev(n), hg.hex(n))
557
562
558 def tip(ui, repo):
563 def tip(ui, repo):
559 """show the tip revision"""
564 """show the tip revision"""
560 n = repo.changelog.tip()
565 n = repo.changelog.tip()
561 show_changeset(ui, repo, changenode=n)
566 show_changeset(ui, repo, changenode=n)
562
567
563 def undo(ui, repo):
568 def undo(ui, repo):
564 """undo the last transaction"""
569 """undo the last transaction"""
565 repo.undo()
570 repo.undo()
566
571
567 def update(ui, repo, node=None, merge=False, clean=False):
572 def update(ui, repo, node=None, merge=False, clean=False):
568 '''update or merge working directory
573 '''update or merge working directory
569
574
570 If there are no outstanding changes in the working directory and
575 If there are no outstanding changes in the working directory and
571 there is a linear relationship between the current version and the
576 there is a linear relationship between the current version and the
572 requested version, the result is the requested version.
577 requested version, the result is the requested version.
573
578
574 Otherwise the result is a merge between the contents of the
579 Otherwise the result is a merge between the contents of the
575 current working directory and the requested version. Files that
580 current working directory and the requested version. Files that
576 changed between either parent are marked as changed for the next
581 changed between either parent are marked as changed for the next
577 commit and a commit must be performed before any further updates
582 commit and a commit must be performed before any further updates
578 are allowed.
583 are allowed.
579 '''
584 '''
580 node = node and repo.lookup(node) or repo.changelog.tip()
585 node = node and repo.lookup(node) or repo.changelog.tip()
581 return repo.update(node, allow=merge, force=clean)
586 return repo.update(node, allow=merge, force=clean)
582
587
583 def verify(ui, repo):
588 def verify(ui, repo):
584 """verify the integrity of the repository"""
589 """verify the integrity of the repository"""
585 return repo.verify()
590 return repo.verify()
586
591
587 # Command options and aliases are listed here, alphabetically
592 # Command options and aliases are listed here, alphabetically
588
593
589 table = {
594 table = {
590 "add": (add, [], "hg add [files]"),
595 "add": (add, [], "hg add [files]"),
591 "addremove": (addremove, [], "hg addremove [files]"),
596 "addremove": (addremove, [], "hg addremove [files]"),
592 "ann|annotate": (annotate,
597 "ann|annotate": (annotate,
593 [('r', 'revision', '', 'revision'),
598 [('r', 'revision', '', 'revision'),
594 ('u', 'user', None, 'show user'),
599 ('u', 'user', None, 'show user'),
595 ('n', 'number', None, 'show revision number'),
600 ('n', 'number', None, 'show revision number'),
596 ('c', 'changeset', None, 'show changeset')],
601 ('c', 'changeset', None, 'show changeset')],
597 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
602 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
598 "cat|dump": (cat, [], 'hg cat <file> [rev]'),
603 "cat|dump": (cat, [], 'hg cat <file> [rev]'),
599 "commit|ci": (commit,
604 "commit|ci": (commit,
600 [('t', 'text', "", 'commit text'),
605 [('t', 'text', "", 'commit text'),
601 ('A', 'addremove', None, 'run add/remove during commit'),
606 ('A', 'addremove', None, 'run add/remove during commit'),
602 ('l', 'logfile', "", 'commit text file'),
607 ('l', 'logfile', "", 'commit text file'),
603 ('d', 'date', "", 'data'),
608 ('d', 'date', "", 'data'),
604 ('u', 'user', "", 'user')],
609 ('u', 'user', "", 'user')],
605 'hg commit [files]'),
610 'hg commit [files]'),
606 "debugaddchangegroup": (debugaddchangegroup, [], 'debugaddchangegroup'),
611 "debugaddchangegroup": (debugaddchangegroup, [], 'debugaddchangegroup'),
607 "debugchangegroup": (debugchangegroup, [], 'debugchangegroup [roots]'),
612 "debugchangegroup": (debugchangegroup, [], 'debugchangegroup [roots]'),
608 "debugindex": (debugindex, [], 'debugindex <file>'),
613 "debugindex": (debugindex, [], 'debugindex <file>'),
609 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
614 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
610 "diff": (diff, [('r', 'rev', [], 'revision')],
615 "diff": (diff, [('r', 'rev', [], 'revision')],
611 'hg diff [-r A] [-r B] [files]'),
616 'hg diff [-r A] [-r B] [files]'),
612 "export": (export, [], "hg export <changeset>"),
617 "export": (export, [], "hg export <changeset>"),
613 "forget": (forget, [], "hg forget [files]"),
618 "forget": (forget, [], "hg forget [files]"),
614 "heads": (heads, [], 'hg heads'),
619 "heads": (heads, [], 'hg heads'),
615 "history": (history, [], 'hg history'),
620 "history": (history, [], 'hg history'),
616 "help": (help, [], 'hg help [command]'),
621 "help": (help, [], 'hg help [command]'),
617 "identify|id": (identify, [], 'hg identify'),
622 "identify|id": (identify, [], 'hg identify'),
618 "init": (init, [], 'hg init [url]'),
623 "init": (init, [], 'hg init [url]'),
619 "log": (log, [], 'hg log <file>'),
624 "log": (log, [], 'hg log <file>'),
620 "manifest|dumpmanifest": (manifest, [], 'hg manifest [rev]'),
625 "manifest|dumpmanifest": (manifest, [], 'hg manifest [rev]'),
621 "parents": (parents, [], 'hg parents [node]'),
626 "parents": (parents, [], 'hg parents [node]'),
622 "patch|import": (patch,
627 "patch|import": (patch,
623 [('p', 'strip', 1, 'path strip'),
628 [('p', 'strip', 1, 'path strip'),
624 ('b', 'base', "", 'base path'),
629 ('b', 'base', "", 'base path'),
625 ('q', 'quiet', "", 'silence diff')],
630 ('q', 'quiet', "", 'silence diff')],
626 "hg import [options] patches"),
631 "hg import [options] patches"),
627 "pull|merge": (pull, [], 'hg pull [source]'),
632 "pull|merge": (pull, [], 'hg pull [source]'),
628 "push": (push, [], 'hg push <destination>'),
633 "push": (push, [], 'hg push <destination>'),
629 "rawcommit": (rawcommit,
634 "rawcommit": (rawcommit,
630 [('p', 'parent', [], 'parent'),
635 [('p', 'parent', [], 'parent'),
631 ('d', 'date', "", 'data'),
636 ('d', 'date', "", 'data'),
632 ('u', 'user', "", 'user'),
637 ('u', 'user', "", 'user'),
633 ('F', 'files', "", 'file list'),
638 ('F', 'files', "", 'file list'),
634 ('t', 'text', "", 'commit text'),
639 ('t', 'text', "", 'commit text'),
635 ('l', 'logfile', "", 'commit text file')],
640 ('l', 'logfile', "", 'commit text file')],
636 'hg rawcommit [options] [files]'),
641 'hg rawcommit [options] [files]'),
637 "recover": (recover, [], "hg recover"),
642 "recover": (recover, [], "hg recover"),
638 "remove": (remove, [], "hg remove [files]"),
643 "remove": (remove, [], "hg remove [files]"),
639 "serve": (serve, [('p', 'port', 8000, 'listen port'),
644 "serve": (serve, [('p', 'port', 8000, 'listen port'),
640 ('a', 'address', '', 'interface address'),
645 ('a', 'address', '', 'interface address'),
641 ('n', 'name', os.getcwd(), 'repository name'),
646 ('n', 'name', os.getcwd(), 'repository name'),
642 ('t', 'templates', "", 'template map')],
647 ('t', 'templates', "", 'template map')],
643 "hg serve [options]"),
648 "hg serve [options]"),
644 "status": (status, [], 'hg status'),
649 "status": (status, [], 'hg status'),
645 "tags": (tags, [], 'hg tags'),
650 "tags": (tags, [], 'hg tags'),
646 "tip": (tip, [], 'hg tip'),
651 "tip": (tip, [], 'hg tip'),
647 "undo": (undo, [], 'hg undo'),
652 "undo": (undo, [], 'hg undo'),
648 "update|up|checkout|co|resolve": (update,
653 "update|up|checkout|co|resolve": (update,
649 [('m', 'merge', None,
654 [('m', 'merge', None,
650 'allow merging of conflicts'),
655 'allow merging of conflicts'),
651 ('C', 'clean', None,
656 ('C', 'clean', None,
652 'overwrite locally modified files')],
657 'overwrite locally modified files')],
653 'hg update [options] [node]'),
658 'hg update [options] [node]'),
654 "verify": (verify, [], 'hg verify'),
659 "verify": (verify, [], 'hg verify'),
655 }
660 }
656
661
657 norepo = "init branch help debugindex debugindexdot"
662 norepo = "init branch help debugindex debugindexdot"
658
663
659 def find(cmd):
664 def find(cmd):
660 i = None
665 i = None
661 for e in table.keys():
666 for e in table.keys():
662 if re.match("(%s)$" % e, cmd):
667 if re.match("(%s)$" % e, cmd):
663 return table[e]
668 return table[e]
664
669
665 raise UnknownCommand(cmd)
670 raise UnknownCommand(cmd)
666
671
667 class SignalInterrupt(Exception): pass
672 class SignalInterrupt(Exception): pass
668
673
669 def catchterm(*args):
674 def catchterm(*args):
670 raise SignalInterrupt
675 raise SignalInterrupt
671
676
672 def run():
677 def run():
673 sys.exit(dispatch(sys.argv[1:]))
678 sys.exit(dispatch(sys.argv[1:]))
674
679
675 def dispatch(args):
680 def dispatch(args):
676 options = {}
681 options = {}
677 opts = [('v', 'verbose', None, 'verbose'),
682 opts = [('v', 'verbose', None, 'verbose'),
678 ('d', 'debug', None, 'debug'),
683 ('d', 'debug', None, 'debug'),
679 ('q', 'quiet', None, 'quiet'),
684 ('q', 'quiet', None, 'quiet'),
680 ('p', 'profile', None, 'profile'),
685 ('p', 'profile', None, 'profile'),
681 ('y', 'noninteractive', None, 'run non-interactively'),
686 ('y', 'noninteractive', None, 'run non-interactively'),
682 ]
687 ]
683
688
684 args = fancyopts.fancyopts(args, opts, options,
689 args = fancyopts.fancyopts(args, opts, options,
685 'hg [options] <command> [options] [files]')
690 'hg [options] <command> [options] [files]')
686
691
687 if not args:
692 if not args:
688 cmd = "help"
693 cmd = "help"
689 else:
694 else:
690 cmd, args = args[0], args[1:]
695 cmd, args = args[0], args[1:]
691
696
692 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
697 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
693 not options["noninteractive"])
698 not options["noninteractive"])
694
699
695 try:
700 try:
696 i = find(cmd)
701 i = find(cmd)
697 except UnknownCommand:
702 except UnknownCommand:
698 u.warn("hg: unknown command '%s'\n" % cmd)
703 u.warn("hg: unknown command '%s'\n" % cmd)
699 help(u)
704 help(u)
700 sys.exit(1)
705 sys.exit(1)
701
706
702 signal.signal(signal.SIGTERM, catchterm)
707 signal.signal(signal.SIGTERM, catchterm)
703
708
704 cmdoptions = {}
709 cmdoptions = {}
705 try:
710 try:
706 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
711 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
707 except fancyopts.getopt.GetoptError, inst:
712 except fancyopts.getopt.GetoptError, inst:
708 u.warn("hg %s: %s\n" % (cmd, inst))
713 u.warn("hg %s: %s\n" % (cmd, inst))
709 help(u, cmd)
714 help(u, cmd)
710 sys.exit(-1)
715 sys.exit(-1)
711
716
712 if cmd not in norepo.split():
717 if cmd not in norepo.split():
713 repo = hg.repository(ui = u)
718 repo = hg.repository(ui = u)
714 d = lambda: i[0](u, repo, *args, **cmdoptions)
719 d = lambda: i[0](u, repo, *args, **cmdoptions)
715 else:
720 else:
716 d = lambda: i[0](u, *args, **cmdoptions)
721 d = lambda: i[0](u, *args, **cmdoptions)
717
722
718 try:
723 try:
719 if options['profile']:
724 if options['profile']:
720 import hotshot, hotshot.stats
725 import hotshot, hotshot.stats
721 prof = hotshot.Profile("hg.prof")
726 prof = hotshot.Profile("hg.prof")
722 r = prof.runcall(d)
727 r = prof.runcall(d)
723 prof.close()
728 prof.close()
724 stats = hotshot.stats.load("hg.prof")
729 stats = hotshot.stats.load("hg.prof")
725 stats.strip_dirs()
730 stats.strip_dirs()
726 stats.sort_stats('time', 'calls')
731 stats.sort_stats('time', 'calls')
727 stats.print_stats(40)
732 stats.print_stats(40)
728 return r
733 return r
729 else:
734 else:
730 return d()
735 return d()
731 except SignalInterrupt:
736 except SignalInterrupt:
732 u.warn("killed!\n")
737 u.warn("killed!\n")
733 except KeyboardInterrupt:
738 except KeyboardInterrupt:
734 u.warn("interrupted!\n")
739 u.warn("interrupted!\n")
735 except IOError, inst:
740 except IOError, inst:
736 if inst.errno == 32:
741 if inst.errno == 32:
737 u.warn("broken pipe\n")
742 u.warn("broken pipe\n")
738 else:
743 else:
739 raise
744 raise
740 except TypeError, inst:
745 except TypeError, inst:
741 # was this an argument error?
746 # was this an argument error?
742 tb = traceback.extract_tb(sys.exc_info()[2])
747 tb = traceback.extract_tb(sys.exc_info()[2])
743 if len(tb) > 2: # no
748 if len(tb) > 2: # no
744 raise
749 raise
745 u.debug(inst, "\n")
750 u.debug(inst, "\n")
746 u.warn("%s: invalid arguments\n" % i[0].__name__)
751 u.warn("%s: invalid arguments\n" % i[0].__name__)
747 help(u, cmd)
752 help(u, cmd)
748 sys.exit(-1)
753 sys.exit(-1)
749
754
General Comments 0
You need to be logged in to leave comments. Login now