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