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) |
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): |
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 |
146 |
147 # figure out which commits they are asking for and which ones they |
147 # figure out which commits they are asking for and which ones they |
148 # want us to stop on |
148 # want us to stop on |
149 for i in range(len(args)): |
149 for i in range(len(args)): |
150 if args[i].count('^'): |
150 if args[i].count('^'): |
151 s = args[i].split('^')[1] |
151 s = args[i].split('^')[1] |
152 stop_sha1.append(repo.changelog.lookup(s)) |
152 stop_sha1.append(repo.changelog.lookup(s)) |
153 want_sha1.append(s) |
153 want_sha1.append(s) |
154 elif args[i] != 'HEAD': |
154 elif args[i] != 'HEAD': |
155 want_sha1.append(args[i]) |
155 want_sha1.append(args[i]) |
156 # calculate the graph for the supplied commits |
156 # calculate the graph for the supplied commits |
157 for i in range(len(want_sha1)): |
157 for i in range(len(want_sha1)): |
158 reachable.append({}); |
158 reachable.append({}); |
159 n = repo.changelog.lookup(want_sha1[i]); |
159 n = repo.changelog.lookup(want_sha1[i]); |
160 visit = [n]; |
160 visit = [n]; |
161 reachable[i][n] = 1 |
161 reachable[i][n] = 1 |
162 while visit: |
162 while visit: |
163 n = visit.pop(0) |
163 n = visit.pop(0) |
164 if n in stop_sha1: |
164 if n in stop_sha1: |
165 break |
165 break |
166 for p in repo.changelog.parents(n): |
166 for p in repo.changelog.parents(n): |
167 if p not in reachable[i]: |
167 if p not in reachable[i]: |
168 reachable[i][p] = 1 |
168 reachable[i][p] = 1 |
169 visit.append(p) |
169 visit.append(p) |
170 if p in stop_sha1: |
170 if p in stop_sha1: |
171 break |
171 break |
172 # walk the repository looking for commits that are in our |
172 # walk the repository looking for commits that are in our |
173 # reachability graph |
173 # reachability graph |
174 for i in range(repo.changelog.count()): |
174 for i in range(repo.changelog.count()): |
175 n = repo.changelog.node(i) |
175 n = repo.changelog.node(i) |
176 mask = is_reachable(want_sha1, reachable, n) |
176 mask = is_reachable(want_sha1, reachable, n) |
177 if mask: |
177 if mask: |
178 changes = repo.changelog.read(n) |
178 changes = repo.changelog.read(n) |
179 (p1, p2) = repo.changelog.parents(n) |
179 (p1, p2) = repo.changelog.parents(n) |
180 (h, h1, h2) = map(hg.hex, (n, p1, p2)) |
180 (h, h1, h2) = map(hg.hex, (n, p1, p2)) |
181 (i1, i2) = map(repo.changelog.rev, (p1, p2)) |
181 (i1, i2) = map(repo.changelog.rev, (p1, p2)) |
182 |
182 |
183 date = changes[2].split(' ')[0] |
183 date = changes[2].split(' ')[0] |
184 print "%s %s:%s" % (date, h, mask), |
184 print "%s %s:%s" % (date, h, mask), |
185 mask = is_reachable(want_sha1, reachable, p1) |
185 mask = is_reachable(want_sha1, reachable, p1) |
186 if i1 != -1 and mask > 0: |
186 if i1 != -1 and mask > 0: |
187 print "%s:%s " % (h1, mask), |
187 print "%s:%s " % (h1, mask), |
188 mask = is_reachable(want_sha1, reachable, p2) |
188 mask = is_reachable(want_sha1, reachable, p2) |
189 if i2 != -1 and mask > 0: |
189 if i2 != -1 and mask > 0: |
190 print "%s:%s " % (h2, mask), |
190 print "%s:%s " % (h2, mask), |
191 print "" |
191 print "" |
192 |
192 |
193 # git rev-list tries to order things by date, and has the ability to stop |
193 # 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 |
194 # at a given commit without walking the whole repo. TODO add the stop |
195 # parameter |
195 # parameter |
196 def revlist(args, repo): |
196 def revlist(args, repo): |
197 doptions = {} |
197 doptions = {} |
198 opts = [('c', 'commit', None, 'commit')] |
198 opts = [('c', 'commit', None, 'commit')] |
199 args = fancyopts.fancyopts(args, opts, doptions, |
199 args = fancyopts.fancyopts(args, opts, doptions, |
200 'hg rev-list') |
200 'hg rev-list') |
201 for i in range(repo.changelog.count()): |
201 for i in range(repo.changelog.count()): |
202 n = repo.changelog.node(i) |
202 n = repo.changelog.node(i) |
203 print hg.hex(n) |
203 print hg.hex(n) |
204 if doptions['commit']: |
204 if doptions['commit']: |
205 catcommit(repo, n, ' ') |
205 catcommit(repo, n, ' ') |
206 |
206 |
207 def catchterm(*args): |
207 def catchterm(*args): |
208 raise SignalInterrupt |
208 raise SignalInterrupt |
209 |
209 |
210 def help(): |
210 def help(): |