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