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