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