##// END OF EJS Templates
hgit rev-list support...
mpm@selenic.com -
r356:7dec9a46 default
parent child Browse files
Show More
@@ -1,243 +1,258 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # Minimal support for git commands on an hg repository
3 # Minimal support for git commands on an hg repository
4 #
4 #
5 # Copyright 2005 Chris Mason <mason@suse.com>
5 # Copyright 2005 Chris Mason <mason@suse.com>
6 #
6 #
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
9
9
10 import time, sys, signal
10 import time, sys, signal
11 from mercurial import hg, mdiff, fancyopts, commands, ui
11 from mercurial import hg, mdiff, fancyopts, commands, ui
12
12
13 def difftree(args, repo):
13 def difftree(args, repo):
14 def __difftree(repo, files = None, node1 = None, node2 = None):
14 def __difftree(repo, files = None, node1 = None, node2 = None):
15 def date(c):
15 def date(c):
16 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
16 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
17
17
18 if node2:
18 if node2:
19 change = repo.changelog.read(node2)
19 change = repo.changelog.read(node2)
20 mmap2 = repo.manifest.read(change[0])
20 mmap2 = repo.manifest.read(change[0])
21 (c, a, d) = repo.diffrevs(node1, node2)
21 (c, a, d) = repo.diffrevs(node1, node2)
22 def read(f): return repo.file(f).read(mmap2[f])
22 def read(f): return repo.file(f).read(mmap2[f])
23 date2 = date(change)
23 date2 = date(change)
24 else:
24 else:
25 date2 = time.asctime()
25 date2 = time.asctime()
26 (c, a, d, u) = repo.diffdir(repo.root, node1)
26 (c, a, d, u) = repo.diffdir(repo.root, node1)
27 if not node1:
27 if not node1:
28 node1 = repo.dirstate.parents()[0]
28 node1 = repo.dirstate.parents()[0]
29 def read(f): return file(os.path.join(repo.root, f)).read()
29 def read(f): return file(os.path.join(repo.root, f)).read()
30
30
31 change = repo.changelog.read(node1)
31 change = repo.changelog.read(node1)
32 mmap = repo.manifest.read(change[0])
32 mmap = repo.manifest.read(change[0])
33 date1 = date(change)
33 date1 = date(change)
34 empty = "0" * 40;
34 empty = "0" * 40;
35
35
36 if files:
36 if files:
37 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
37 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
38
38
39 for f in c:
39 for f in c:
40 # TODO get file permissions
40 # TODO get file permissions
41 print ":100664 100664 %s %s %s %s" % (hg.hex(mmap[f]),
41 print ":100664 100664 %s %s %s %s" % (hg.hex(mmap[f]),
42 hg.hex(mmap2[f]), f, f)
42 hg.hex(mmap2[f]), f, f)
43 for f in a:
43 for f in a:
44 print ":000000 100664 %s %s %s %s" % (empty, hg.hex(mmap2[f]), f, f)
44 print ":000000 100664 %s %s %s %s" % (empty, hg.hex(mmap2[f]), f, f)
45 for f in d:
45 for f in d:
46 print ":100664 000000 %s %s %s %s" % (hg.hex(mmap[f]), empty, f, f)
46 print ":100664 000000 %s %s %s %s" % (hg.hex(mmap[f]), empty, f, f)
47 ##
47 ##
48
48
49 revs = []
49 revs = []
50 if args:
50 if args:
51 doptions = {}
51 doptions = {}
52 opts = [('p', 'patch', None, 'patch'),
52 opts = [('p', 'patch', None, 'patch'),
53 ('r', 'recursive', None, 'recursive')]
53 ('r', 'recursive', None, 'recursive')]
54 args = fancyopts.fancyopts(args, opts, doptions,
54 args = fancyopts.fancyopts(args, opts, doptions,
55 'hg diff-tree [options] sha1 sha1')
55 'hg diff-tree [options] sha1 sha1')
56
56
57 if len(args) < 2:
57 if len(args) < 2:
58 help()
58 help()
59 sys.exit(1)
59 sys.exit(1)
60 revs.append(repo.lookup(args[0]))
60 revs.append(repo.lookup(args[0]))
61 revs.append(repo.lookup(args[1]))
61 revs.append(repo.lookup(args[1]))
62 args = args[2:]
62 args = args[2:]
63 if doptions['patch']:
63 if doptions['patch']:
64 commands.dodiff(repo, args, *revs)
64 commands.dodiff(repo, args, *revs)
65 else:
65 else:
66 __difftree(repo, args, *revs)
66 __difftree(repo, args, *revs)
67
67
68 def catcommit(repo, n, prefix):
68 def catcommit(repo, n, prefix):
69 nlprefix = '\n' + prefix;
69 nlprefix = '\n' + prefix;
70 changes = repo.changelog.read(n)
70 changes = repo.changelog.read(n)
71 (p1, p2) = repo.changelog.parents(n)
71 (p1, p2) = repo.changelog.parents(n)
72 (h, h1, h2) = map(hg.hex, (n, p1, p2))
72 (h, h1, h2) = map(hg.hex, (n, p1, p2))
73 (i1, i2) = map(repo.changelog.rev, (p1, p2))
73 (i1, i2) = map(repo.changelog.rev, (p1, p2))
74 print "tree %s" % (h)
74 print "tree %s" % (h)
75 if i1 != -1: print "%sparent %s" % (prefix, h1)
75 if i1 != -1: print "%sparent %s" % (prefix, h1)
76 if i2 != -1: print "%sparent %s" % (prefix, h2)
76 if i2 != -1: print "%sparent %s" % (prefix, h2)
77 date_ar = changes[2].split(' ')
77 date_ar = changes[2].split(' ')
78 date = int(float(date_ar[0]))
78 date = int(float(date_ar[0]))
79 print "%sauthor <%s> %s %s" % (prefix, changes[1], date, date_ar[1])
79 print "%sauthor <%s> %s %s" % (prefix, changes[1], date, date_ar[1])
80 print "%scommitter <%s> %s %s" % (prefix, changes[1], date, date_ar[1])
80 print "%scommitter <%s> %s %s" % (prefix, changes[1], date, date_ar[1])
81 print prefix
81 print prefix
82 if prefix != "":
82 if prefix != "":
83 print "%s%s" % (prefix, changes[4].replace('\n', nlprefix).strip())
83 print "%s%s" % (prefix, changes[4].replace('\n', nlprefix).strip())
84 else:
84 else:
85 print changes[4]
85 print changes[4]
86
86
87 def catfile(args, ui, repo):
87 def catfile(args, ui, repo):
88 doptions = {}
88 doptions = {}
89 opts = [('s', 'stdin', None, 'stdin')]
89 opts = [('s', 'stdin', None, 'stdin')]
90 args = fancyopts.fancyopts(args, opts, doptions,
90 args = fancyopts.fancyopts(args, opts, doptions,
91 'hg cat-file type sha1')
91 'hg cat-file type sha1')
92
92
93 # in stdin mode, every line except the commit is prefixed with two
93 # in stdin mode, every line except the commit is prefixed with two
94 # spaces. This way the our caller can find the commit without magic
94 # spaces. This way the our caller can find the commit without magic
95 # strings
95 # strings
96 #
96 #
97 prefix = ""
97 prefix = ""
98 if doptions['stdin']:
98 if doptions['stdin']:
99 try:
99 try:
100 (type, r) = raw_input().split(' ');
100 (type, r) = raw_input().split(' ');
101 prefix = " "
101 prefix = " "
102 except EOFError:
102 except EOFError:
103 return
103 return
104
104
105 else:
105 else:
106 if len(args) < 2:
106 if len(args) < 2:
107 help()
107 help()
108 sys.exit(1)
108 sys.exit(1)
109 type = args[0]
109 type = args[0]
110 r = args[1]
110 r = args[1]
111
111
112 while r:
112 while r:
113 if type != "commit":
113 if type != "commit":
114 sys.stderr.write("aborting hg cat-file only understands commits\n")
114 sys.stderr.write("aborting hg cat-file only understands commits\n")
115 sys.exit(1);
115 sys.exit(1);
116 n = repo.changelog.lookup(r)
116 n = repo.changelog.lookup(r)
117 catcommit(repo, n, prefix)
117 catcommit(repo, n, prefix)
118 if doptions['stdin']:
118 if doptions['stdin']:
119 try:
119 try:
120 (type, r) = raw_input().split(' ');
120 (type, r) = raw_input().split(' ');
121 except EOFError:
121 except EOFError:
122 break
122 break
123 else:
123 else:
124 break
124 break
125
125
126 # git rev-tree is a confusing thing. You can supply a number of
126 # git rev-tree is a confusing thing. You can supply a number of
127 # commit sha1s on the command line, and it walks the commit history
127 # commit sha1s on the command line, and it walks the commit history
128 # telling you which commits are reachable from the supplied ones via
128 # telling you which commits are reachable from the supplied ones via
129 # a bitmask based on arg position.
129 # a bitmask based on arg position.
130 # you can specify a commit to stop at by starting the sha1 with ^
130 # you can specify a commit to stop at by starting the sha1 with ^
131 def revtree(args, repo):
131 def revtree(args, repo, full="tree", maxnr=0):
132 # calculate and return the reachability bitmask for sha
132 # calculate and return the reachability bitmask for sha
133 def is_reachable(ar, reachable, sha):
133 def is_reachable(ar, reachable, sha):
134 if len(ar) == 0:
134 if len(ar) == 0:
135 return 1
135 return 1
136 mask = 0
136 mask = 0
137 for i in range(len(ar)):
137 for i in range(len(ar)):
138 if sha in reachable[i]:
138 if sha in reachable[i]:
139 mask |= 1 << i
139 mask |= 1 << i
140
140
141 return mask
141 return mask
142
142
143 reachable = []
143 reachable = []
144 stop_sha1 = []
144 stop_sha1 = []
145 want_sha1 = []
145 want_sha1 = []
146 count = 0
146
147
147 # figure out which commits they are asking for and which ones they
148 # figure out which commits they are asking for and which ones they
148 # want us to stop on
149 # want us to stop on
149 for i in range(len(args)):
150 for i in range(len(args)):
150 if args[i].count('^'):
151 if args[i].count('^'):
151 s = args[i].split('^')[1]
152 s = args[i].split('^')[1]
152 stop_sha1.append(repo.changelog.lookup(s))
153 stop_sha1.append(repo.changelog.lookup(s))
153 want_sha1.append(s)
154 want_sha1.append(s)
154 elif args[i] != 'HEAD':
155 elif args[i] != 'HEAD':
155 want_sha1.append(args[i])
156 want_sha1.append(args[i])
157
156 # calculate the graph for the supplied commits
158 # calculate the graph for the supplied commits
157 for i in range(len(want_sha1)):
159 for i in range(len(want_sha1)):
158 reachable.append({});
160 reachable.append({});
159 n = repo.changelog.lookup(want_sha1[i]);
161 n = repo.changelog.lookup(want_sha1[i]);
160 visit = [n];
162 visit = [n];
161 reachable[i][n] = 1
163 reachable[i][n] = 1
162 while visit:
164 while visit:
163 n = visit.pop(0)
165 n = visit.pop(0)
164 if n in stop_sha1:
166 if n in stop_sha1:
165 break
167 break
166 for p in repo.changelog.parents(n):
168 for p in repo.changelog.parents(n):
167 if p not in reachable[i]:
169 if p not in reachable[i]:
168 reachable[i][p] = 1
170 reachable[i][p] = 1
169 visit.append(p)
171 visit.append(p)
170 if p in stop_sha1:
172 if p in stop_sha1:
171 break
173 break
174
172 # walk the repository looking for commits that are in our
175 # walk the repository looking for commits that are in our
173 # reachability graph
176 # reachability graph
174 for i in range(repo.changelog.count()):
177 for i in range(repo.changelog.count()-1, -1, -1):
175 n = repo.changelog.node(i)
178 n = repo.changelog.node(i)
176 mask = is_reachable(want_sha1, reachable, n)
179 mask = is_reachable(want_sha1, reachable, n)
177 if mask:
180 if mask:
178 changes = repo.changelog.read(n)
181 if not full:
179 (p1, p2) = repo.changelog.parents(n)
182 print hg.hex(n)
180 (h, h1, h2) = map(hg.hex, (n, p1, p2))
183 elif full is "commit":
181 (i1, i2) = map(repo.changelog.rev, (p1, p2))
184 print hg.hex(n)
185 catcommit(repo, n, ' ')
186 else:
187 changes = repo.changelog.read(n)
188 (p1, p2) = repo.changelog.parents(n)
189 (h, h1, h2) = map(hg.hex, (n, p1, p2))
190 (i1, i2) = map(repo.changelog.rev, (p1, p2))
182
191
183 date = changes[2].split(' ')[0]
192 date = changes[2].split(' ')[0]
184 print "%s %s:%s" % (date, h, mask),
193 print "%s %s:%s" % (date, h, mask),
185 mask = is_reachable(want_sha1, reachable, p1)
194 mask = is_reachable(want_sha1, reachable, p1)
186 if i1 != -1 and mask > 0:
195 if i1 != -1 and mask > 0:
187 print "%s:%s " % (h1, mask),
196 print "%s:%s " % (h1, mask),
188 mask = is_reachable(want_sha1, reachable, p2)
197 mask = is_reachable(want_sha1, reachable, p2)
189 if i2 != -1 and mask > 0:
198 if i2 != -1 and mask > 0:
190 print "%s:%s " % (h2, mask),
199 print "%s:%s " % (h2, mask),
191 print ""
200 print ""
201 if maxnr and count >= maxnr:
202 break
203 count += 1
192
204
193 # git rev-list tries to order things by date, and has the ability to stop
205 # git rev-list tries to order things by date, and has the ability to stop
194 # at a given commit without walking the whole repo. TODO add the stop
206 # at a given commit without walking the whole repo. TODO add the stop
195 # parameter
207 # parameter
196 def revlist(args, repo):
208 def revlist(args, repo):
197 doptions = {}
209 doptions = {}
198 opts = [('c', 'commit', None, 'commit')]
210 opts = [('c', 'commit', None, 'commit'),
211 ('n', 'max-nr', 0, 'max-nr')]
199 args = fancyopts.fancyopts(args, opts, doptions,
212 args = fancyopts.fancyopts(args, opts, doptions,
200 'hg rev-list')
213 'hg rev-list')
201 for i in range(repo.changelog.count()):
214 if doptions['commit']:
202 n = repo.changelog.node(i)
215 full = "commit"
203 print hg.hex(n)
216 else:
204 if doptions['commit']:
217 full = None
205 catcommit(repo, n, ' ')
218 for i in range(1, len(args)):
219 args[i] = '^' + args[i]
220 revtree(args, repo, full, doptions['max-nr'])
206
221
207 def catchterm(*args):
222 def catchterm(*args):
208 raise SignalInterrupt
223 raise SignalInterrupt
209
224
210 def help():
225 def help():
211 sys.stderr.write("commands:\n")
226 sys.stderr.write("commands:\n")
212 sys.stderr.write(" hgit cat-file [type] sha1\n")
227 sys.stderr.write(" hgit cat-file [type] sha1\n")
213 sys.stderr.write(" hgit diff-tree [-p] [-r] sha1 sha1\n")
228 sys.stderr.write(" hgit diff-tree [-p] [-r] sha1 sha1\n")
214 sys.stderr.write(" hgit rev-tree [sha1 ... [^stop sha1]]\n")
229 sys.stderr.write(" hgit rev-tree [sha1 ... [^stop sha1]]\n")
215 sys.stderr.write(" hgit rev-list [-c]\n")
230 sys.stderr.write(" hgit rev-list [-c]\n")
216
231
217 cmd = sys.argv[1]
232 cmd = sys.argv[1]
218 args = sys.argv[2:]
233 args = sys.argv[2:]
219 u = ui.ui()
234 u = ui.ui()
220 signal.signal(signal.SIGTERM, catchterm)
235 signal.signal(signal.SIGTERM, catchterm)
221 repo = hg.repository(ui = u)
236 repo = hg.repository(ui = u)
222
237
223 if cmd == "diff-tree":
238 if cmd == "diff-tree":
224 difftree(args, repo)
239 difftree(args, repo)
225
240
226 elif cmd == "cat-file":
241 elif cmd == "cat-file":
227 catfile(args, ui, repo)
242 catfile(args, ui, repo)
228
243
229 elif cmd == "rev-tree":
244 elif cmd == "rev-tree":
230 revtree(args, repo)
245 revtree(args, repo)
231
246
232 elif cmd == "rev-list":
247 elif cmd == "rev-list":
233 revlist(args, repo)
248 revlist(args, repo)
234
249
235 elif cmd == "help":
250 elif cmd == "help":
236 help()
251 help()
237
252
238 else:
253 else:
239 if cmd: sys.stderr.write("unknown command\n\n")
254 if cmd: sys.stderr.write("unknown command\n\n")
240 help()
255 help()
241 sys.exit(1)
256 sys.exit(1)
242
257
243 sys.exit(0)
258 sys.exit(0)
General Comments 0
You need to be logged in to leave comments. Login now