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