##// END OF EJS Templates
hgk: Allow specifying hgk path in [hgk]path
mpm@selenic.com -
r1345:c5594ff3 default
parent child Browse files
Show More
@@ -1,341 +1,341
1 1 #!/usr/bin/env python
2 2 #
3 3 # Minimal support for git commands on an hg repository
4 4 #
5 5 # Copyright 2005 Chris Mason <mason@suse.com>
6 6 #
7 7 # This software may be used and distributed according to the terms
8 8 # of the GNU General Public License, incorporated herein by reference.
9 9
10 10 import time, sys, signal, os
11 11 from mercurial import hg, mdiff, fancyopts, commands, ui, util
12 12
13 13 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
14 14 changes=None, text=False):
15 15 def date(c):
16 16 return time.asctime(time.gmtime(c[2][0]))
17 17
18 18 if not changes:
19 19 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
20 20 else:
21 21 (c, a, d, u) = changes
22 22 if files:
23 23 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
24 24
25 25 if not c and not a and not d:
26 26 return
27 27
28 28 if node2:
29 29 change = repo.changelog.read(node2)
30 30 mmap2 = repo.manifest.read(change[0])
31 31 date2 = date(change)
32 32 def read(f):
33 33 return repo.file(f).read(mmap2[f])
34 34 else:
35 35 date2 = time.asctime()
36 36 if not node1:
37 37 node1 = repo.dirstate.parents()[0]
38 38 def read(f):
39 39 return repo.wfile(f).read()
40 40
41 41 change = repo.changelog.read(node1)
42 42 mmap = repo.manifest.read(change[0])
43 43 date1 = date(change)
44 44
45 45 for f in c:
46 46 to = None
47 47 if f in mmap:
48 48 to = repo.file(f).read(mmap[f])
49 49 tn = read(f)
50 50 fp.write("diff --git a/%s b/%s\n" % (f, f))
51 51 fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
52 52 for f in a:
53 53 to = None
54 54 tn = read(f)
55 55 fp.write("diff --git /dev/null b/%s\n" % (f))
56 56 fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
57 57 for f in d:
58 58 to = repo.file(f).read(mmap[f])
59 59 tn = None
60 60 fp.write("diff --git a/%s /dev/null\n" % (f))
61 61 fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
62 62
63 63 def difftree(ui, repo, node1=None, node2=None, **opts):
64 64 """diff trees from two commits"""
65 65 def __difftree(repo, node1, node2):
66 66 def date(c):
67 67 return time.asctime(time.gmtime(c[2][0]))
68 68
69 69 if node2:
70 70 change = repo.changelog.read(node2)
71 71 mmap2 = repo.manifest.read(change[0])
72 72 (c, a, d, u) = repo.changes(node1, node2)
73 73 def read(f): return repo.file(f).read(mmap2[f])
74 74 date2 = date(change)
75 75 else:
76 76 date2 = time.asctime()
77 77 (c, a, d, u) = repo.changes(node1, None)
78 78 if not node1:
79 79 node1 = repo.dirstate.parents()[0]
80 80 def read(f): return file(os.path.join(repo.root, f)).read()
81 81
82 82 change = repo.changelog.read(node1)
83 83 mmap = repo.manifest.read(change[0])
84 84 date1 = date(change)
85 85 empty = "0" * 40;
86 86
87 87 for f in c:
88 88 # TODO get file permissions
89 89 print ":100664 100664 %s %s M\t%s\t%s" % (hg.hex(mmap[f]),
90 90 hg.hex(mmap2[f]), f, f)
91 91 for f in a:
92 92 print ":000000 100664 %s %s N\t%s\t%s" % (empty, hg.hex(mmap2[f]), f, f)
93 93 for f in d:
94 94 print ":100664 000000 %s %s D\t%s\t%s" % (hg.hex(mmap[f]), empty, f, f)
95 95 ##
96 96
97 97 while True:
98 98 if opts['stdin']:
99 99 try:
100 100 line = raw_input().split(' ')
101 101 node1 = line[0]
102 102 if len(line) > 1:
103 103 node2 = line[1]
104 104 else:
105 105 node2 = None
106 106 except EOFError:
107 107 break
108 108 node1 = repo.lookup(node1)
109 109 if node2:
110 110 node2 = repo.lookup(node2)
111 111 else:
112 112 node2 = node1
113 113 node1 = repo.changelog.parents(node1)[0]
114 114 if opts['patch']:
115 115 if opts['pretty']:
116 116 catcommit(repo, node2, "")
117 117 dodiff(sys.stdout, ui, repo, node1, node2)
118 118 else:
119 119 __difftree(repo, node1, node2)
120 120 if not opts['stdin']:
121 121 break
122 122
123 123 def catcommit(repo, n, prefix, changes=None):
124 124 nlprefix = '\n' + prefix;
125 125 (p1, p2) = repo.changelog.parents(n)
126 126 (h, h1, h2) = map(hg.hex, (n, p1, p2))
127 127 (i1, i2) = map(repo.changelog.rev, (p1, p2))
128 128 if not changes:
129 129 changes = repo.changelog.read(n)
130 130 print "tree %s" % (hg.hex(changes[0]))
131 131 if i1 != -1: print "parent %s" % (h1)
132 132 if i2 != -1: print "parent %s" % (h2)
133 133 date_ar = changes[2]
134 134 date = int(float(date_ar[0]))
135 135 lines = changes[4].splitlines()
136 136 if lines[-1].startswith('committer:'):
137 137 committer = lines[-1].split(': ')[1].rstrip()
138 138 else:
139 139 committer = "%s %s %s" % (changes[1], date, date_ar[1])
140 140
141 141 print "author %s %s %s" % (changes[1], date, date_ar[1])
142 142 print "committer %s" % (committer)
143 143 print ""
144 144 if prefix != "":
145 145 print "%s%s" % (prefix, changes[4].replace('\n', nlprefix).strip())
146 146 else:
147 147 print changes[4]
148 148 if prefix:
149 149 sys.stdout.write('\0')
150 150
151 151 def base(ui, repo, node1, node2):
152 152 """Output common ancestor information"""
153 153 node1 = repo.lookup(node1)
154 154 node2 = repo.lookup(node2)
155 155 n = repo.changelog.ancestor(node1, node2)
156 156 print hg.hex(n)
157 157
158 158 def catfile(ui, repo, type=None, r=None, **opts):
159 159 """cat a specific revision"""
160 160 # in stdin mode, every line except the commit is prefixed with two
161 161 # spaces. This way the our caller can find the commit without magic
162 162 # strings
163 163 #
164 164 prefix = ""
165 165 if opts['stdin']:
166 166 try:
167 167 (type, r) = raw_input().split(' ');
168 168 prefix = " "
169 169 except EOFError:
170 170 return
171 171
172 172 else:
173 173 if not type or not r:
174 174 ui.warn("cat-file: type or revision not supplied\n")
175 175 commands.help_(ui, 'cat-file')
176 176
177 177 while r:
178 178 if type != "commit":
179 179 sys.stderr.write("aborting hg cat-file only understands commits\n")
180 180 sys.exit(1);
181 181 n = repo.lookup(r)
182 182 catcommit(repo, n, prefix)
183 183 if opts['stdin']:
184 184 try:
185 185 (type, r) = raw_input().split(' ');
186 186 except EOFError:
187 187 break
188 188 else:
189 189 break
190 190
191 191 # git rev-tree is a confusing thing. You can supply a number of
192 192 # commit sha1s on the command line, and it walks the commit history
193 193 # telling you which commits are reachable from the supplied ones via
194 194 # a bitmask based on arg position.
195 195 # you can specify a commit to stop at by starting the sha1 with ^
196 196 def revtree(args, repo, full="tree", maxnr=0, parents=False):
197 197 def chlogwalk():
198 198 ch = repo.changelog
199 199 count = ch.count()
200 200 i = count
201 201 l = [0] * 100
202 202 chunk = 100
203 203 while True:
204 204 if chunk > i:
205 205 chunk = i
206 206 i = 0
207 207 else:
208 208 i -= chunk
209 209
210 210 for x in xrange(0, chunk):
211 211 if i + x >= count:
212 212 l[chunk - x:] = [0] * (chunk - x)
213 213 break
214 214 if full != None:
215 215 l[x] = ch.read(ch.node(i + x))
216 216 else:
217 217 l[x] = 1
218 218 for x in xrange(chunk-1, -1, -1):
219 219 if l[x] != 0:
220 220 yield (i + x, full != None and l[x] or None)
221 221 if i == 0:
222 222 break
223 223
224 224 # calculate and return the reachability bitmask for sha
225 225 def is_reachable(ar, reachable, sha):
226 226 if len(ar) == 0:
227 227 return 1
228 228 mask = 0
229 229 for i in range(len(ar)):
230 230 if sha in reachable[i]:
231 231 mask |= 1 << i
232 232
233 233 return mask
234 234
235 235 reachable = []
236 236 stop_sha1 = []
237 237 want_sha1 = []
238 238 count = 0
239 239
240 240 # figure out which commits they are asking for and which ones they
241 241 # want us to stop on
242 242 for i in range(len(args)):
243 243 if args[i].startswith('^'):
244 244 s = repo.lookup(args[i][1:])
245 245 stop_sha1.append(s)
246 246 want_sha1.append(s)
247 247 elif args[i] != 'HEAD':
248 248 want_sha1.append(repo.lookup(args[i]))
249 249
250 250 # calculate the graph for the supplied commits
251 251 for i in range(len(want_sha1)):
252 252 reachable.append({});
253 253 n = want_sha1[i];
254 254 visit = [n];
255 255 reachable[i][n] = 1
256 256 while visit:
257 257 n = visit.pop(0)
258 258 if n in stop_sha1:
259 259 continue
260 260 for p in repo.changelog.parents(n):
261 261 if p not in reachable[i]:
262 262 reachable[i][p] = 1
263 263 visit.append(p)
264 264 if p in stop_sha1:
265 265 continue
266 266
267 267 # walk the repository looking for commits that are in our
268 268 # reachability graph
269 269 #for i in range(repo.changelog.count()-1, -1, -1):
270 270 for i, changes in chlogwalk():
271 271 n = repo.changelog.node(i)
272 272 mask = is_reachable(want_sha1, reachable, n)
273 273 if mask:
274 274 parentstr = ""
275 275 if parents:
276 276 pp = repo.changelog.parents(n)
277 277 if pp[0] != hg.nullid:
278 278 parentstr += " " + hg.hex(pp[0])
279 279 if pp[1] != hg.nullid:
280 280 parentstr += " " + hg.hex(pp[1])
281 281 if not full:
282 282 print hg.hex(n) + parentstr
283 283 elif full is "commit":
284 284 print hg.hex(n) + parentstr
285 285 catcommit(repo, n, ' ', changes)
286 286 else:
287 287 (p1, p2) = repo.changelog.parents(n)
288 288 (h, h1, h2) = map(hg.hex, (n, p1, p2))
289 289 (i1, i2) = map(repo.changelog.rev, (p1, p2))
290 290
291 291 date = changes[2][0]
292 292 print "%s %s:%s" % (date, h, mask),
293 293 mask = is_reachable(want_sha1, reachable, p1)
294 294 if i1 != -1 and mask > 0:
295 295 print "%s:%s " % (h1, mask),
296 296 mask = is_reachable(want_sha1, reachable, p2)
297 297 if i2 != -1 and mask > 0:
298 298 print "%s:%s " % (h2, mask),
299 299 print ""
300 300 if maxnr and count >= maxnr:
301 301 break
302 302 count += 1
303 303
304 304 # git rev-list tries to order things by date, and has the ability to stop
305 305 # at a given commit without walking the whole repo. TODO add the stop
306 306 # parameter
307 307 def revlist(ui, repo, *revs, **opts):
308 308 """print revisions"""
309 309 if opts['header']:
310 310 full = "commit"
311 311 else:
312 312 full = None
313 313 copy = [x for x in revs]
314 314 revtree(copy, repo, full, opts['max_count'], opts['parents'])
315 315
316 316 def view(ui, repo, *etc):
317 317 "start interactive history viewer"
318 318 os.chdir(repo.root)
319 os.system("hgk " + " ".join(etc))
319 os.system(ui.config("hgk", "path", "hgk") + " " + " ".join(etc))
320 320
321 321 cmdtable = {
322 322 "view": (view, [], 'hg view'),
323 323 "debug-diff-tree": (difftree, [('p', 'patch', None, 'generate patch'),
324 324 ('r', 'recursive', None, 'recursive'),
325 325 ('P', 'pretty', None, 'pretty'),
326 326 ('s', 'stdin', None, 'stdin'),
327 327 ('C', 'copy', None, 'detect copies'),
328 328 ('S', 'search', "", 'search')],
329 329 "hg git-diff-tree [options] node1 node2"),
330 330 "debug-cat-file": (catfile, [('s', 'stdin', None, 'stdin')],
331 331 "hg debug-cat-file [options] type file"),
332 332 "debug-merge-base": (base, [], "hg debug-merge-base node node"),
333 333 "debug-rev-list": (revlist, [('H', 'header', None, 'header'),
334 334 ('t', 'topo-order', None, 'topo-order'),
335 335 ('p', 'parents', None, 'parents'),
336 336 ('n', 'max-count', 0, 'max-count')],
337 337 "hg debug-rev-list [options] revs"),
338 338 }
339 339
340 340 def reposetup(ui, repo):
341 341 pass
General Comments 0
You need to be logged in to leave comments. Login now