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