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