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