##// END OF EJS Templates
add easy profiling support...
mpm@selenic.com -
r309:61414da0 default
parent child Browse files
Show More
@@ -1,655 +1,667 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import os, re, sys, signal
8 import os, re, sys, signal
9 import fancyopts, ui, hg
9 import fancyopts, ui, hg
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "mdiff time hgweb traceback")
11 demandload(globals(), "mdiff time hgweb traceback")
12
12
13 class UnknownCommand(Exception): pass
13 class UnknownCommand(Exception): pass
14
14
15 def filterfiles(filters, files):
15 def filterfiles(filters, files):
16 l = [ x for x in files if x in filters ]
16 l = [ x for x in files if x in filters ]
17
17
18 for t in filters:
18 for t in filters:
19 if t and t[-1] != os.sep: t += os.sep
19 if t and t[-1] != os.sep: t += os.sep
20 l += [ x for x in files if x.startswith(t) ]
20 l += [ x for x in files if x.startswith(t) ]
21 return l
21 return l
22
22
23 def relfilter(repo, files):
23 def relfilter(repo, files):
24 if os.getcwd() != repo.root:
24 if os.getcwd() != repo.root:
25 p = os.getcwd()[len(repo.root) + 1: ]
25 p = os.getcwd()[len(repo.root) + 1: ]
26 return filterfiles([p], files)
26 return filterfiles([p], files)
27 return files
27 return files
28
28
29 def relpath(repo, args):
29 def relpath(repo, args):
30 if os.getcwd() != repo.root:
30 if os.getcwd() != repo.root:
31 p = os.getcwd()[len(repo.root) + 1: ]
31 p = os.getcwd()[len(repo.root) + 1: ]
32 return [ os.path.normpath(os.path.join(p, x)) for x in args ]
32 return [ os.path.normpath(os.path.join(p, x)) for x in args ]
33 return args
33 return args
34
34
35 def dodiff(repo, files = None, node1 = None, node2 = None):
35 def dodiff(repo, 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(repo.root, node1)
47 (c, a, d, u) = repo.diffdir(repo.root, node1)
48 if not node1:
48 if not node1:
49 node1 = repo.dirstate.parents()[0]
49 node1 = repo.dirstate.parents()[0]
50 def read(f): return file(os.path.join(repo.root, f)).read()
50 def read(f): return file(os.path.join(repo.root, f)).read()
51
51
52 change = repo.changelog.read(node1)
52 change = repo.changelog.read(node1)
53 mmap = repo.manifest.read(change[0])
53 mmap = repo.manifest.read(change[0])
54 date1 = date(change)
54 date1 = date(change)
55
55
56 if files:
56 if files:
57 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
57 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
58
58
59 for f in c:
59 for f in c:
60 to = None
60 to = None
61 if f in mmap:
61 if f in mmap:
62 to = repo.file(f).read(mmap[f])
62 to = repo.file(f).read(mmap[f])
63 tn = read(f)
63 tn = read(f)
64 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
64 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
65 for f in a:
65 for f in a:
66 to = None
66 to = None
67 tn = read(f)
67 tn = read(f)
68 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
68 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
69 for f in d:
69 for f in d:
70 to = repo.file(f).read(mmap[f])
70 to = repo.file(f).read(mmap[f])
71 tn = None
71 tn = None
72 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
72 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
73
73
74 def help(ui, cmd=None):
74 def help(ui, cmd=None):
75 '''show help for a given command or all commands'''
75 '''show help for a given command or all commands'''
76 if cmd:
76 if cmd:
77 try:
77 try:
78 i = find(cmd)
78 i = find(cmd)
79 ui.write("%s\n\n" % i[2])
79 ui.write("%s\n\n" % i[2])
80
80
81 if i[1]:
81 if i[1]:
82 for s, l, d, c in i[1]:
82 for s, l, d, c in i[1]:
83 opt=' '
83 opt=' '
84 if s: opt = opt + '-' + s + ' '
84 if s: opt = opt + '-' + s + ' '
85 if l: opt = opt + '--' + l + ' '
85 if l: opt = opt + '--' + l + ' '
86 if d: opt = opt + '(' + str(d) + ')'
86 if d: opt = opt + '(' + str(d) + ')'
87 ui.write(opt, "\n")
87 ui.write(opt, "\n")
88 if c: ui.write(' %s\n' % c)
88 if c: ui.write(' %s\n' % c)
89 ui.write("\n")
89 ui.write("\n")
90
90
91 ui.write(i[0].__doc__, "\n")
91 ui.write(i[0].__doc__, "\n")
92 except UnknownCommand:
92 except UnknownCommand:
93 ui.warn("hg: unknown command %s\n" % cmd)
93 ui.warn("hg: unknown command %s\n" % cmd)
94 sys.exit(0)
94 sys.exit(0)
95 else:
95 else:
96 ui.status('hg commands:\n\n')
96 ui.status('hg commands:\n\n')
97
97
98 h = {}
98 h = {}
99 for e in table.values():
99 for e in table.values():
100 f = e[0]
100 f = e[0]
101 if f.__name__.startswith("debug"): continue
101 if f.__name__.startswith("debug"): continue
102 d = ""
102 d = ""
103 if f.__doc__:
103 if f.__doc__:
104 d = f.__doc__.splitlines(0)[0].rstrip()
104 d = f.__doc__.splitlines(0)[0].rstrip()
105 h[f.__name__] = d
105 h[f.__name__] = d
106
106
107 fns = h.keys()
107 fns = h.keys()
108 fns.sort()
108 fns.sort()
109 m = max(map(len, fns))
109 m = max(map(len, fns))
110 for f in fns:
110 for f in fns:
111 ui.status(' %-*s %s\n' % (m, f, h[f]))
111 ui.status(' %-*s %s\n' % (m, f, h[f]))
112
112
113 # Commands start here, listed alphabetically
113 # Commands start here, listed alphabetically
114
114
115 def add(ui, repo, file, *files):
115 def add(ui, repo, file, *files):
116 '''add the specified files on the next commit'''
116 '''add the specified files on the next commit'''
117 repo.add(relpath(repo, (file,) + files))
117 repo.add(relpath(repo, (file,) + files))
118
118
119 def addremove(ui, repo):
119 def addremove(ui, repo):
120 """add all new files, delete all missing files"""
120 """add all new files, delete all missing files"""
121 (c, a, d, u) = repo.diffdir(repo.root)
121 (c, a, d, u) = repo.diffdir(repo.root)
122 repo.add(u)
122 repo.add(u)
123 repo.remove(d)
123 repo.remove(d)
124
124
125 def annotate(u, repo, file, *files, **ops):
125 def annotate(u, repo, file, *files, **ops):
126 """show changeset information per file line"""
126 """show changeset information per file line"""
127 def getnode(rev):
127 def getnode(rev):
128 return hg.short(repo.changelog.node(rev))
128 return hg.short(repo.changelog.node(rev))
129
129
130 def getname(rev):
130 def getname(rev):
131 try:
131 try:
132 return bcache[rev]
132 return bcache[rev]
133 except KeyError:
133 except KeyError:
134 cl = repo.changelog.read(repo.changelog.node(rev))
134 cl = repo.changelog.read(repo.changelog.node(rev))
135 name = cl[1]
135 name = cl[1]
136 f = name.find('@')
136 f = name.find('@')
137 if f >= 0:
137 if f >= 0:
138 name = name[:f]
138 name = name[:f]
139 bcache[rev] = name
139 bcache[rev] = name
140 return name
140 return name
141
141
142 bcache = {}
142 bcache = {}
143 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
143 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
144 if not ops['user'] and not ops['changeset']:
144 if not ops['user'] and not ops['changeset']:
145 ops['number'] = 1
145 ops['number'] = 1
146
146
147 node = repo.dirstate.parents()[0]
147 node = repo.dirstate.parents()[0]
148 if ops['revision']:
148 if ops['revision']:
149 node = repo.changelog.lookup(ops['revision'])
149 node = repo.changelog.lookup(ops['revision'])
150 change = repo.changelog.read(node)
150 change = repo.changelog.read(node)
151 mmap = repo.manifest.read(change[0])
151 mmap = repo.manifest.read(change[0])
152 maxuserlen = 0
152 maxuserlen = 0
153 maxchangelen = 0
153 maxchangelen = 0
154 for f in relpath(repo, (file,) + files):
154 for f in relpath(repo, (file,) + files):
155 lines = repo.file(f).annotate(mmap[f])
155 lines = repo.file(f).annotate(mmap[f])
156 pieces = []
156 pieces = []
157
157
158 for o, f in opmap:
158 for o, f in opmap:
159 if ops[o]:
159 if ops[o]:
160 l = [ f(n) for n,t in lines ]
160 l = [ f(n) for n,t in lines ]
161 m = max(map(len, l))
161 m = max(map(len, l))
162 pieces.append([ "%*s" % (m, x) for x in l])
162 pieces.append([ "%*s" % (m, x) for x in l])
163
163
164 for p,l in zip(zip(*pieces), lines):
164 for p,l in zip(zip(*pieces), lines):
165 u.write(" ".join(p) + ": " + l[1])
165 u.write(" ".join(p) + ": " + l[1])
166
166
167 def cat(ui, repo, file, rev = []):
167 def cat(ui, repo, file, rev = []):
168 """output the latest or given revision of a file"""
168 """output the latest or given revision of a file"""
169 r = repo.file(relpath(repo, [file])[0])
169 r = repo.file(relpath(repo, [file])[0])
170 n = r.tip()
170 n = r.tip()
171 if rev: n = r.lookup(rev)
171 if rev: n = r.lookup(rev)
172 sys.stdout.write(r.read(n))
172 sys.stdout.write(r.read(n))
173
173
174 def commit(ui, repo, *files, **opts):
174 def commit(ui, repo, *files, **opts):
175 """commit the specified files or all outstanding changes"""
175 """commit the specified files or all outstanding changes"""
176 text = opts['text']
176 text = opts['text']
177 if not text and opts['logfile']:
177 if not text and opts['logfile']:
178 try: text = open(opts['logfile']).read()
178 try: text = open(opts['logfile']).read()
179 except IOError: pass
179 except IOError: pass
180
180
181 repo.commit(relpath(repo, files), text)
181 repo.commit(relpath(repo, files), text)
182
182
183 def debugaddchangegroup(ui, repo):
183 def debugaddchangegroup(ui, repo):
184 data = sys.stdin.read()
184 data = sys.stdin.read()
185 repo.addchangegroup(data)
185 repo.addchangegroup(data)
186
186
187 def debugchangegroup(ui, repo, roots):
187 def debugchangegroup(ui, repo, roots):
188 newer = repo.newer(map(repo.lookup, roots))
188 newer = repo.newer(map(repo.lookup, roots))
189 for chunk in repo.changegroup(newer):
189 for chunk in repo.changegroup(newer):
190 sys.stdout.write(chunk)
190 sys.stdout.write(chunk)
191
191
192 def debugindex(ui, file):
192 def debugindex(ui, file):
193 r = hg.revlog(open, file, "")
193 r = hg.revlog(open, file, "")
194 print " rev offset length base linkrev"+\
194 print " rev offset length base linkrev"+\
195 " p1 p2 nodeid"
195 " p1 p2 nodeid"
196 for i in range(r.count()):
196 for i in range(r.count()):
197 e = r.index[i]
197 e = r.index[i]
198 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
198 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
199 i, e[0], e[1], e[2], e[3],
199 i, e[0], e[1], e[2], e[3],
200 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
200 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
201
201
202 def debugindexdot(ui, file):
202 def debugindexdot(ui, file):
203 r = hg.revlog(open, file, "")
203 r = hg.revlog(open, file, "")
204 print "digraph G {"
204 print "digraph G {"
205 for i in range(r.count()):
205 for i in range(r.count()):
206 e = r.index[i]
206 e = r.index[i]
207 print "\t%d -> %d" % (r.rev(e[4]), i)
207 print "\t%d -> %d" % (r.rev(e[4]), i)
208 if e[5] != hg.nullid:
208 if e[5] != hg.nullid:
209 print "\t%d -> %d" % (r.rev(e[5]), i)
209 print "\t%d -> %d" % (r.rev(e[5]), i)
210 print "}"
210 print "}"
211
211
212 def diff(ui, repo, *files, **opts):
212 def diff(ui, repo, *files, **opts):
213 """diff working directory (or selected files)"""
213 """diff working directory (or selected files)"""
214 revs = []
214 revs = []
215 if opts['rev']:
215 if opts['rev']:
216 revs = map(lambda x: repo.lookup(x), opts['rev'])
216 revs = map(lambda x: repo.lookup(x), opts['rev'])
217
217
218 if len(revs) > 2:
218 if len(revs) > 2:
219 self.ui.warn("too many revisions to diff\n")
219 self.ui.warn("too many revisions to diff\n")
220 sys.exit(1)
220 sys.exit(1)
221
221
222 if files:
222 if files:
223 files = relpath(repo, files)
223 files = relpath(repo, files)
224 else:
224 else:
225 files = relpath(repo, [""])
225 files = relpath(repo, [""])
226
226
227 dodiff(repo, files, *revs)
227 dodiff(repo, files, *revs)
228
228
229 def export(ui, repo, changeset):
229 def export(ui, repo, changeset):
230 """dump the changeset header and diffs for a revision"""
230 """dump the changeset header and diffs for a revision"""
231 node = repo.lookup(changeset)
231 node = repo.lookup(changeset)
232 prev, other = repo.changelog.parents(node)
232 prev, other = repo.changelog.parents(node)
233 change = repo.changelog.read(node)
233 change = repo.changelog.read(node)
234 print "# HG changeset patch"
234 print "# HG changeset patch"
235 print "# User %s" % change[1]
235 print "# User %s" % change[1]
236 print "# Node ID %s" % hg.hex(node)
236 print "# Node ID %s" % hg.hex(node)
237 print "# Parent %s" % hg.hex(prev)
237 print "# Parent %s" % hg.hex(prev)
238 print
238 print
239 if other != hg.nullid:
239 if other != hg.nullid:
240 print "# Parent %s" % hg.hex(other)
240 print "# Parent %s" % hg.hex(other)
241 print change[4].rstrip()
241 print change[4].rstrip()
242 print
242 print
243
243
244 dodiff(repo, None, prev, node)
244 dodiff(repo, None, prev, node)
245
245
246 def forget(ui, repo, file, *files):
246 def forget(ui, repo, file, *files):
247 """don't add the specified files on the next commit"""
247 """don't add the specified files on the next commit"""
248 repo.forget(relpath(repo, (file,) + files))
248 repo.forget(relpath(repo, (file,) + files))
249
249
250 def heads(ui, repo):
250 def heads(ui, repo):
251 '''show current repository heads'''
251 '''show current repository heads'''
252 for n in repo.changelog.heads():
252 for n in repo.changelog.heads():
253 i = repo.changelog.rev(n)
253 i = repo.changelog.rev(n)
254 changes = repo.changelog.read(n)
254 changes = repo.changelog.read(n)
255 (p1, p2) = repo.changelog.parents(n)
255 (p1, p2) = repo.changelog.parents(n)
256 (h, h1, h2) = map(hg.hex, (n, p1, p2))
256 (h, h1, h2) = map(hg.hex, (n, p1, p2))
257 (i1, i2) = map(repo.changelog.rev, (p1, p2))
257 (i1, i2) = map(repo.changelog.rev, (p1, p2))
258 print "rev: %4d:%s" % (i, h)
258 print "rev: %4d:%s" % (i, h)
259 print "parents: %4d:%s" % (i1, h1)
259 print "parents: %4d:%s" % (i1, h1)
260 if i2: print " %4d:%s" % (i2, h2)
260 if i2: print " %4d:%s" % (i2, h2)
261 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
261 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
262 hg.hex(changes[0]))
262 hg.hex(changes[0]))
263 print "user:", changes[1]
263 print "user:", changes[1]
264 print "date:", time.asctime(
264 print "date:", time.asctime(
265 time.localtime(float(changes[2].split(' ')[0])))
265 time.localtime(float(changes[2].split(' ')[0])))
266 if ui.verbose: print "files:", " ".join(changes[3])
266 if ui.verbose: print "files:", " ".join(changes[3])
267 print "description:"
267 print "description:"
268 print changes[4]
268 print changes[4]
269
269
270 def history(ui, repo):
270 def history(ui, repo):
271 """show the changelog history"""
271 """show the changelog history"""
272 for i in range(repo.changelog.count() - 1, -1, -1):
272 for i in range(repo.changelog.count() - 1, -1, -1):
273 n = repo.changelog.node(i)
273 n = repo.changelog.node(i)
274 changes = repo.changelog.read(n)
274 changes = repo.changelog.read(n)
275 (p1, p2) = repo.changelog.parents(n)
275 (p1, p2) = repo.changelog.parents(n)
276 (h, h1, h2) = map(hg.hex, (n, p1, p2))
276 (h, h1, h2) = map(hg.hex, (n, p1, p2))
277 (i1, i2) = map(repo.changelog.rev, (p1, p2))
277 (i1, i2) = map(repo.changelog.rev, (p1, p2))
278 print "rev: %4d:%s" % (i, h)
278 print "rev: %4d:%s" % (i, h)
279 print "parents: %4d:%s" % (i1, h1)
279 print "parents: %4d:%s" % (i1, h1)
280 if i2: print " %4d:%s" % (i2, h2)
280 if i2: print " %4d:%s" % (i2, h2)
281 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
281 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
282 hg.hex(changes[0]))
282 hg.hex(changes[0]))
283 print "user:", changes[1]
283 print "user:", changes[1]
284 print "date:", time.asctime(
284 print "date:", time.asctime(
285 time.localtime(float(changes[2].split(' ')[0])))
285 time.localtime(float(changes[2].split(' ')[0])))
286 if ui.verbose: print "files:", " ".join(changes[3])
286 if ui.verbose: print "files:", " ".join(changes[3])
287 print "description:"
287 print "description:"
288 print changes[4]
288 print changes[4]
289
289
290 def init(ui, source=None):
290 def init(ui, source=None):
291 """create a new repository or copy an existing one"""
291 """create a new repository or copy an existing one"""
292
292
293 if source:
293 if source:
294 paths = {}
294 paths = {}
295 for name, path in ui.configitems("paths"):
295 for name, path in ui.configitems("paths"):
296 paths[name] = path
296 paths[name] = path
297
297
298 if source in paths: source = paths[source]
298 if source in paths: source = paths[source]
299
299
300 link = 0
300 link = 0
301 if not source.startswith("http://"):
301 if not source.startswith("http://"):
302 d1 = os.stat(os.getcwd()).st_dev
302 d1 = os.stat(os.getcwd()).st_dev
303 d2 = os.stat(source).st_dev
303 d2 = os.stat(source).st_dev
304 if d1 == d2: link = 1
304 if d1 == d2: link = 1
305
305
306 if link:
306 if link:
307 ui.debug("copying by hardlink\n")
307 ui.debug("copying by hardlink\n")
308 os.system("cp -al %s/.hg .hg" % source)
308 os.system("cp -al %s/.hg .hg" % source)
309 try:
309 try:
310 os.remove(".hg/dirstate")
310 os.remove(".hg/dirstate")
311 except: pass
311 except: pass
312 else:
312 else:
313 repo = hg.repository(ui, ".", create=1)
313 repo = hg.repository(ui, ".", create=1)
314 other = hg.repository(ui, source)
314 other = hg.repository(ui, source)
315 cg = repo.getchangegroup(other)
315 cg = repo.getchangegroup(other)
316 repo.addchangegroup(cg)
316 repo.addchangegroup(cg)
317 else:
317 else:
318 hg.repository(ui, ".", create=1)
318 hg.repository(ui, ".", create=1)
319
319
320 def log(ui, repo, f):
320 def log(ui, repo, f):
321 """show the revision history of a single file"""
321 """show the revision history of a single file"""
322 f = relpath(repo, [f])[0]
322 f = relpath(repo, [f])[0]
323
323
324 r = repo.file(f)
324 r = repo.file(f)
325 for i in range(r.count() - 1, -1, -1):
325 for i in range(r.count() - 1, -1, -1):
326 n = r.node(i)
326 n = r.node(i)
327 (p1, p2) = r.parents(n)
327 (p1, p2) = r.parents(n)
328 (h, h1, h2) = map(hg.hex, (n, p1, p2))
328 (h, h1, h2) = map(hg.hex, (n, p1, p2))
329 (i1, i2) = map(r.rev, (p1, p2))
329 (i1, i2) = map(r.rev, (p1, p2))
330 cr = r.linkrev(n)
330 cr = r.linkrev(n)
331 cn = hg.hex(repo.changelog.node(cr))
331 cn = hg.hex(repo.changelog.node(cr))
332 print "rev: %4d:%s" % (i, h)
332 print "rev: %4d:%s" % (i, h)
333 print "changeset: %4d:%s" % (cr, cn)
333 print "changeset: %4d:%s" % (cr, cn)
334 print "parents: %4d:%s" % (i1, h1)
334 print "parents: %4d:%s" % (i1, h1)
335 if i2: print " %4d:%s" % (i2, h2)
335 if i2: print " %4d:%s" % (i2, h2)
336 changes = repo.changelog.read(repo.changelog.node(cr))
336 changes = repo.changelog.read(repo.changelog.node(cr))
337 print "user: %s" % changes[1]
337 print "user: %s" % changes[1]
338 print "date: %s" % time.asctime(
338 print "date: %s" % time.asctime(
339 time.localtime(float(changes[2].split(' ')[0])))
339 time.localtime(float(changes[2].split(' ')[0])))
340 print "description:"
340 print "description:"
341 print changes[4].rstrip()
341 print changes[4].rstrip()
342 print
342 print
343
343
344 def manifest(ui, repo, rev = []):
344 def manifest(ui, repo, rev = []):
345 """output the latest or given revision of the project manifest"""
345 """output the latest or given revision of the project manifest"""
346 n = repo.manifest.tip()
346 n = repo.manifest.tip()
347 if rev:
347 if rev:
348 n = repo.manifest.lookup(rev)
348 n = repo.manifest.lookup(rev)
349 m = repo.manifest.read(n)
349 m = repo.manifest.read(n)
350 mf = repo.manifest.readflags(n)
350 mf = repo.manifest.readflags(n)
351 files = m.keys()
351 files = m.keys()
352 files.sort()
352 files.sort()
353
353
354 for f in files:
354 for f in files:
355 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
355 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
356
356
357 def parents(ui, repo, node = None):
357 def parents(ui, repo, node = None):
358 '''show the parents of the current working dir'''
358 '''show the parents of the current working dir'''
359 if node:
359 if node:
360 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
360 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
361 else:
361 else:
362 p = repo.dirstate.parents()
362 p = repo.dirstate.parents()
363
363
364 for n in p:
364 for n in p:
365 if n != hg.nullid:
365 if n != hg.nullid:
366 ui.write("%d:%s\n" % (repo.changelog.rev(n), hg.hex(n)))
366 ui.write("%d:%s\n" % (repo.changelog.rev(n), hg.hex(n)))
367
367
368 def patch(ui, repo, patch1, *patches, **opts):
368 def patch(ui, repo, patch1, *patches, **opts):
369 """import an ordered set of patches"""
369 """import an ordered set of patches"""
370 try:
370 try:
371 import psyco
371 import psyco
372 psyco.full()
372 psyco.full()
373 except:
373 except:
374 pass
374 pass
375
375
376 patches = (patch1,) + patches
376 patches = (patch1,) + patches
377
377
378 d = opts["base"]
378 d = opts["base"]
379 strip = opts["strip"]
379 strip = opts["strip"]
380 quiet = opts["quiet"] and "> /dev/null" or ""
380 quiet = opts["quiet"] and "> /dev/null" or ""
381
381
382 for patch in patches:
382 for patch in patches:
383 ui.status("applying %s\n" % patch)
383 ui.status("applying %s\n" % patch)
384 pf = os.path.join(d, patch)
384 pf = os.path.join(d, patch)
385
385
386 text = ""
386 text = ""
387 for l in file(pf):
387 for l in file(pf):
388 if l[:4] == "--- ": break
388 if l[:4] == "--- ": break
389 text += l
389 text += l
390
390
391 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
391 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
392 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
392 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
393 f.close()
393 f.close()
394
394
395 if files:
395 if files:
396 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
396 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
397 raise "patch failed!"
397 raise "patch failed!"
398 repo.commit(files, text)
398 repo.commit(files, text)
399
399
400 def pull(ui, repo, source):
400 def pull(ui, repo, source):
401 """pull changes from the specified source"""
401 """pull changes from the specified source"""
402 paths = {}
402 paths = {}
403 for name, path in ui.configitems("paths"):
403 for name, path in ui.configitems("paths"):
404 paths[name] = path
404 paths[name] = path
405
405
406 if source in paths: source = paths[source]
406 if source in paths: source = paths[source]
407
407
408 other = hg.repository(ui, source)
408 other = hg.repository(ui, source)
409 cg = repo.getchangegroup(other)
409 cg = repo.getchangegroup(other)
410 repo.addchangegroup(cg)
410 repo.addchangegroup(cg)
411
411
412 def rawcommit(ui, repo, files, **rc):
412 def rawcommit(ui, repo, files, **rc):
413 "raw commit interface"
413 "raw commit interface"
414
414
415 text = rc['text']
415 text = rc['text']
416 if not text and rc['logfile']:
416 if not text and rc['logfile']:
417 try: text = open(rc['logfile']).read()
417 try: text = open(rc['logfile']).read()
418 except IOError: pass
418 except IOError: pass
419 if not text and not rc['logfile']:
419 if not text and not rc['logfile']:
420 print "missing commit text"
420 print "missing commit text"
421 return 1
421 return 1
422
422
423 files = relpath(repo, files)
423 files = relpath(repo, files)
424 if rc['files']:
424 if rc['files']:
425 files += open(rc['files']).read().splitlines()
425 files += open(rc['files']).read().splitlines()
426
426
427 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
427 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
428
428
429 def recover(ui, repo):
429 def recover(ui, repo):
430 """roll back an interrupted transaction"""
430 """roll back an interrupted transaction"""
431 repo.recover()
431 repo.recover()
432
432
433 def remove(ui, repo, file, *files):
433 def remove(ui, repo, file, *files):
434 """remove the specified files on the next commit"""
434 """remove the specified files on the next commit"""
435 repo.remove(relpath(repo, (file,) + files))
435 repo.remove(relpath(repo, (file,) + files))
436
436
437 def serve(ui, repo, **opts):
437 def serve(ui, repo, **opts):
438 """export the repository via HTTP"""
438 """export the repository via HTTP"""
439 hgweb.server(repo.root, opts["name"], opts["templates"],
439 hgweb.server(repo.root, opts["name"], opts["templates"],
440 opts["address"], opts["port"])
440 opts["address"], opts["port"])
441
441
442 def status(ui, repo):
442 def status(ui, repo):
443 '''show changed files in the working directory
443 '''show changed files in the working directory
444
444
445 C = changed
445 C = changed
446 A = added
446 A = added
447 R = removed
447 R = removed
448 ? = not tracked'''
448 ? = not tracked'''
449
449
450 (c, a, d, u) = repo.diffdir(repo.root)
450 (c, a, d, u) = repo.diffdir(repo.root)
451 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
451 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
452
452
453 for f in c: print "C", f
453 for f in c: print "C", f
454 for f in a: print "A", f
454 for f in a: print "A", f
455 for f in d: print "R", f
455 for f in d: print "R", f
456 for f in u: print "?", f
456 for f in u: print "?", f
457
457
458 def tags(ui, repo):
458 def tags(ui, repo):
459 """list repository tags"""
459 """list repository tags"""
460 repo.lookup(0) # prime the cache
460 repo.lookup(0) # prime the cache
461 i = repo.tags.items()
461 i = repo.tags.items()
462 n = []
462 n = []
463 for e in i:
463 for e in i:
464 try:
464 try:
465 l = repo.changelog.rev(e[1])
465 l = repo.changelog.rev(e[1])
466 except KeyError:
466 except KeyError:
467 l = -2
467 l = -2
468 n.append((l, e))
468 n.append((l, e))
469
469
470 n.sort()
470 n.sort()
471 n.reverse()
471 n.reverse()
472 i = [ e[1] for e in n ]
472 i = [ e[1] for e in n ]
473 for k, n in i:
473 for k, n in i:
474 try:
474 try:
475 r = repo.changelog.rev(n)
475 r = repo.changelog.rev(n)
476 except KeyError:
476 except KeyError:
477 r = "?"
477 r = "?"
478 print "%-30s %5d:%s" % (k, repo.changelog.rev(n), hg.hex(n))
478 print "%-30s %5d:%s" % (k, repo.changelog.rev(n), hg.hex(n))
479
479
480 def tip(ui, repo):
480 def tip(ui, repo):
481 """show the tip revision"""
481 """show the tip revision"""
482 n = repo.changelog.tip()
482 n = repo.changelog.tip()
483 t = repo.changelog.rev(n)
483 t = repo.changelog.rev(n)
484 ui.status("%d:%s\n" % (t, hg.hex(n)))
484 ui.status("%d:%s\n" % (t, hg.hex(n)))
485
485
486 def undo(ui, repo):
486 def undo(ui, repo):
487 """undo the last transaction"""
487 """undo the last transaction"""
488 repo.undo()
488 repo.undo()
489
489
490 def update(ui, repo, node=None, merge=False, clean=False):
490 def update(ui, repo, node=None, merge=False, clean=False):
491 '''update or merge working directory
491 '''update or merge working directory
492
492
493 If there are no outstanding changes in the working directory and
493 If there are no outstanding changes in the working directory and
494 there is a linear relationship between the current version and the
494 there is a linear relationship between the current version and the
495 requested version, the result is the requested version.
495 requested version, the result is the requested version.
496
496
497 Otherwise the result is a merge between the contents of the
497 Otherwise the result is a merge between the contents of the
498 current working directory and the requested version. Files that
498 current working directory and the requested version. Files that
499 changed between either parent are marked as changed for the next
499 changed between either parent are marked as changed for the next
500 commit and a commit must be performed before any further updates
500 commit and a commit must be performed before any further updates
501 are allowed.
501 are allowed.
502 '''
502 '''
503 node = node and repo.lookup(node) or repo.changelog.tip()
503 node = node and repo.lookup(node) or repo.changelog.tip()
504 return repo.update(node, allow=merge, force=clean)
504 return repo.update(node, allow=merge, force=clean)
505
505
506 def verify(ui, repo):
506 def verify(ui, repo):
507 """verify the integrity of the repository"""
507 """verify the integrity of the repository"""
508 return repo.verify()
508 return repo.verify()
509
509
510 # Command options and aliases are listed here, alphabetically
510 # Command options and aliases are listed here, alphabetically
511
511
512 table = {
512 table = {
513 "add": (add, [], "hg add [files]"),
513 "add": (add, [], "hg add [files]"),
514 "addremove": (addremove, [], "hg addremove"),
514 "addremove": (addremove, [], "hg addremove"),
515 "ann|annotate": (annotate,
515 "ann|annotate": (annotate,
516 [('r', 'revision', '', 'revision'),
516 [('r', 'revision', '', 'revision'),
517 ('u', 'user', None, 'show user'),
517 ('u', 'user', None, 'show user'),
518 ('n', 'number', None, 'show revision number'),
518 ('n', 'number', None, 'show revision number'),
519 ('c', 'changeset', None, 'show changeset')],
519 ('c', 'changeset', None, 'show changeset')],
520 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
520 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
521 "cat|dump": (cat, [], 'hg cat <file> [rev]'),
521 "cat|dump": (cat, [], 'hg cat <file> [rev]'),
522 "commit|ci": (commit,
522 "commit|ci": (commit,
523 [('t', 'text', "", 'commit text'),
523 [('t', 'text', "", 'commit text'),
524 ('l', 'logfile', "", 'commit text file')],
524 ('l', 'logfile', "", 'commit text file')],
525 'hg commit [files]'),
525 'hg commit [files]'),
526 "debugaddchangegroup": (debugaddchangegroup, [], 'debugaddchangegroup'),
526 "debugaddchangegroup": (debugaddchangegroup, [], 'debugaddchangegroup'),
527 "debugchangegroup": (debugchangegroup, [], 'debugchangegroup [roots]'),
527 "debugchangegroup": (debugchangegroup, [], 'debugchangegroup [roots]'),
528 "debugindex": (debugindex, [], 'debugindex <file>'),
528 "debugindex": (debugindex, [], 'debugindex <file>'),
529 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
529 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
530 "diff": (diff, [('r', 'rev', [], 'revision')],
530 "diff": (diff, [('r', 'rev', [], 'revision')],
531 'hg diff [-r A] [-r B] [files]'),
531 'hg diff [-r A] [-r B] [files]'),
532 "export": (export, [], "hg export <changeset>"),
532 "export": (export, [], "hg export <changeset>"),
533 "forget": (forget, [], "hg forget [files]"),
533 "forget": (forget, [], "hg forget [files]"),
534 "heads": (heads, [], 'hg heads'),
534 "heads": (heads, [], 'hg heads'),
535 "history": (history, [], 'hg history'),
535 "history": (history, [], 'hg history'),
536 "help": (help, [], 'hg help [command]'),
536 "help": (help, [], 'hg help [command]'),
537 "init": (init, [], 'hg init [url]'),
537 "init": (init, [], 'hg init [url]'),
538 "log": (log, [], 'hg log <file>'),
538 "log": (log, [], 'hg log <file>'),
539 "manifest|dumpmanifest": (manifest, [], 'hg manifest [rev]'),
539 "manifest|dumpmanifest": (manifest, [], 'hg manifest [rev]'),
540 "parents": (parents, [], 'hg parents [node]'),
540 "parents": (parents, [], 'hg parents [node]'),
541 "patch|import": (patch,
541 "patch|import": (patch,
542 [('p', 'strip', 1, 'path strip'),
542 [('p', 'strip', 1, 'path strip'),
543 ('b', 'base', "", 'base path'),
543 ('b', 'base', "", 'base path'),
544 ('q', 'quiet', "", 'silence diff')],
544 ('q', 'quiet', "", 'silence diff')],
545 "hg import [options] patches"),
545 "hg import [options] patches"),
546 "pull|merge": (pull, [], 'hg pull [source]'),
546 "pull|merge": (pull, [], 'hg pull [source]'),
547 "rawcommit": (rawcommit,
547 "rawcommit": (rawcommit,
548 [('p', 'parent', [], 'parent'),
548 [('p', 'parent', [], 'parent'),
549 ('d', 'date', "", 'data'),
549 ('d', 'date', "", 'data'),
550 ('u', 'user', "", 'user'),
550 ('u', 'user', "", 'user'),
551 ('F', 'files', "", 'file list'),
551 ('F', 'files', "", 'file list'),
552 ('t', 'text', "", 'commit text'),
552 ('t', 'text', "", 'commit text'),
553 ('l', 'logfile', "", 'commit text file')],
553 ('l', 'logfile', "", 'commit text file')],
554 'hg rawcommit [options] [files]'),
554 'hg rawcommit [options] [files]'),
555 "recover": (recover, [], "hg recover"),
555 "recover": (recover, [], "hg recover"),
556 "remove": (remove, [], "hg remove [files]"),
556 "remove": (remove, [], "hg remove [files]"),
557 "serve": (serve, [('p', 'port', 8000, 'listen port'),
557 "serve": (serve, [('p', 'port', 8000, 'listen port'),
558 ('a', 'address', '', 'interface address'),
558 ('a', 'address', '', 'interface address'),
559 ('n', 'name', os.getcwd(), 'repository name'),
559 ('n', 'name', os.getcwd(), 'repository name'),
560 ('t', 'templates', "", 'template map')],
560 ('t', 'templates', "", 'template map')],
561 "hg serve [options]"),
561 "hg serve [options]"),
562 "status": (status, [], 'hg status'),
562 "status": (status, [], 'hg status'),
563 "tags": (tags, [], 'hg tags'),
563 "tags": (tags, [], 'hg tags'),
564 "tip": (tip, [], 'hg tip'),
564 "tip": (tip, [], 'hg tip'),
565 "undo": (undo, [], 'hg undo'),
565 "undo": (undo, [], 'hg undo'),
566 "update|up|checkout|co|resolve": (update,
566 "update|up|checkout|co|resolve": (update,
567 [('m', 'merge', None,
567 [('m', 'merge', None,
568 'allow merging of conflicts'),
568 'allow merging of conflicts'),
569 ('C', 'clean', None,
569 ('C', 'clean', None,
570 'overwrite locally modified files')],
570 'overwrite locally modified files')],
571 'hg update [options] [node]'),
571 'hg update [options] [node]'),
572 "verify": (verify, [], 'hg verify'),
572 "verify": (verify, [], 'hg verify'),
573 }
573 }
574
574
575 norepo = "init branch help debugindex debugindexdot"
575 norepo = "init branch help debugindex debugindexdot"
576
576
577 def find(cmd):
577 def find(cmd):
578 i = None
578 i = None
579 for e in table.keys():
579 for e in table.keys():
580 if re.match(e + "$", cmd):
580 if re.match(e + "$", cmd):
581 return table[e]
581 return table[e]
582
582
583 raise UnknownCommand(cmd)
583 raise UnknownCommand(cmd)
584
584
585 class SignalInterrupt(Exception): pass
585 class SignalInterrupt(Exception): pass
586
586
587 def catchterm(*args):
587 def catchterm(*args):
588 raise SignalInterrupt
588 raise SignalInterrupt
589
589
590 def run():
590 def run():
591 sys.exit(dispatch(sys.argv[1:]))
591 sys.exit(dispatch(sys.argv[1:]))
592
592
593 def dispatch(args):
593 def dispatch(args):
594 options = {}
594 options = {}
595 opts = [('v', 'verbose', None, 'verbose'),
595 opts = [('v', 'verbose', None, 'verbose'),
596 ('d', 'debug', None, 'debug'),
596 ('d', 'debug', None, 'debug'),
597 ('q', 'quiet', None, 'quiet'),
597 ('q', 'quiet', None, 'quiet'),
598 ('p', 'profile', None, 'profile'),
598 ('y', 'noninteractive', None, 'run non-interactively'),
599 ('y', 'noninteractive', None, 'run non-interactively'),
599 ]
600 ]
600
601
601 args = fancyopts.fancyopts(args, opts, options,
602 args = fancyopts.fancyopts(args, opts, options,
602 'hg [options] <command> [options] [files]')
603 'hg [options] <command> [options] [files]')
603
604
604 if not args:
605 if not args:
605 cmd = "help"
606 cmd = "help"
606 else:
607 else:
607 cmd, args = args[0], args[1:]
608 cmd, args = args[0], args[1:]
608
609
609 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
610 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
610 not options["noninteractive"])
611 not options["noninteractive"])
611
612
612 try:
613 try:
613 i = find(cmd)
614 i = find(cmd)
614 except UnknownCommand:
615 except UnknownCommand:
615 u.warn("hg: unknown command '%s'\n" % cmd)
616 u.warn("hg: unknown command '%s'\n" % cmd)
616 help(u)
617 help(u)
617 sys.exit(1)
618 sys.exit(1)
618
619
619 signal.signal(signal.SIGTERM, catchterm)
620 signal.signal(signal.SIGTERM, catchterm)
620
621
621 cmdoptions = {}
622 cmdoptions = {}
622 try:
623 try:
623 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
624 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
624 except fancyopts.getopt.GetoptError, inst:
625 except fancyopts.getopt.GetoptError, inst:
625 u.warn("hg %s: %s\n" % (cmd, inst))
626 u.warn("hg %s: %s\n" % (cmd, inst))
626 help(u, cmd)
627 help(u, cmd)
627 sys.exit(-1)
628 sys.exit(-1)
628
629
629 if cmd not in norepo.split():
630 if cmd not in norepo.split():
630 repo = hg.repository(ui = u)
631 repo = hg.repository(ui = u)
631 d = lambda: i[0](u, repo, *args, **cmdoptions)
632 d = lambda: i[0](u, repo, *args, **cmdoptions)
632 else:
633 else:
633 d = lambda: i[0](u, *args, **cmdoptions)
634 d = lambda: i[0](u, *args, **cmdoptions)
634
635
635 try:
636 try:
637 if options['profile']:
638 import hotshot, hotshot.stats
639 prof = hotshot.Profile("hg.prof")
640 r = prof.runcall(d)
641 prof.close()
642 stats = hotshot.stats.load("hg.prof")
643 stats.strip_dirs()
644 stats.sort_stats('time', 'calls')
645 stats.print_stats(40)
646 return r
647 else:
636 return d()
648 return d()
637 except SignalInterrupt:
649 except SignalInterrupt:
638 u.warn("killed!\n")
650 u.warn("killed!\n")
639 except KeyboardInterrupt:
651 except KeyboardInterrupt:
640 u.warn("interrupted!\n")
652 u.warn("interrupted!\n")
641 except IOError, inst:
653 except IOError, inst:
642 if inst.errno == 32:
654 if inst.errno == 32:
643 u.warn("broken pipe\n")
655 u.warn("broken pipe\n")
644 else:
656 else:
645 raise
657 raise
646 except TypeError, inst:
658 except TypeError, inst:
647 # was this an argument error?
659 # was this an argument error?
648 tb = traceback.extract_tb(sys.exc_info()[2])
660 tb = traceback.extract_tb(sys.exc_info()[2])
649 if len(tb) > 2: # no
661 if len(tb) > 2: # no
650 raise
662 raise
651 u.debug(inst, "\n")
663 u.debug(inst, "\n")
652 u.warn("%s: invalid arguments\n" % i[0].__name__)
664 u.warn("%s: invalid arguments\n" % i[0].__name__)
653 help(u, cmd)
665 help(u, cmd)
654 sys.exit(-1)
666 sys.exit(-1)
655
667
General Comments 0
You need to be logged in to leave comments. Login now