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