11 """ |
11 """ |
12 |
12 |
13 from node import * |
13 from node import * |
14 from i18n import gettext as _ |
14 from i18n import gettext as _ |
15 from demandload import demandload |
15 from demandload import demandload |
16 demandload(globals(), "binascii changegroup errno heapq mdiff os") |
16 demandload(globals(), "binascii changegroup errno ancestor mdiff os") |
17 demandload(globals(), "sha struct util zlib") |
17 demandload(globals(), "sha struct util zlib") |
18 |
18 |
19 # revlog version strings |
19 # revlog version strings |
20 REVLOGV0 = 0 |
20 REVLOGV0 = 0 |
21 REVLOGNG = 1 |
21 REVLOGNG = 1 |
1014 return node |
1014 return node |
1015 |
1015 |
1016 def ancestor(self, a, b): |
1016 def ancestor(self, a, b): |
1017 """calculate the least common ancestor of nodes a and b""" |
1017 """calculate the least common ancestor of nodes a and b""" |
1018 |
1018 |
1019 # start with some short cuts for the linear cases |
1019 def parents(node): |
1020 if a == b: |
1020 return [p for p in self.parents(node) if p != nullid] |
1021 return a |
1021 |
1022 ra = self.rev(a) |
1022 return ancestor.ancestor(a, b, parents) or nullid |
1023 rb = self.rev(b) |
|
1024 if ra < rb: |
|
1025 last = b |
|
1026 first = a |
|
1027 else: |
|
1028 last = a |
|
1029 first = b |
|
1030 |
|
1031 # reachable won't include stop in the list, so we have to use a parent |
|
1032 reachable = self.reachable(last, stop=self.parents(first)[0]) |
|
1033 if first in reachable: |
|
1034 return first |
|
1035 |
|
1036 # calculate the distance of every node from root |
|
1037 dist = {nullid: 0} |
|
1038 for i in xrange(self.count()): |
|
1039 n = self.node(i) |
|
1040 p1, p2 = self.parents(n) |
|
1041 dist[n] = max(dist[p1], dist[p2]) + 1 |
|
1042 |
|
1043 # traverse ancestors in order of decreasing distance from root |
|
1044 def ancestors(node): |
|
1045 # we store negative distances because heap returns smallest member |
|
1046 h = [(-dist[node], node)] |
|
1047 seen = {} |
|
1048 while h: |
|
1049 d, n = heapq.heappop(h) |
|
1050 if n not in seen: |
|
1051 seen[n] = 1 |
|
1052 yield (-d, n) |
|
1053 for p in self.parents(n): |
|
1054 heapq.heappush(h, (-dist[p], p)) |
|
1055 |
|
1056 def generations(node): |
|
1057 sg, s = None, {} |
|
1058 for g,n in ancestors(node): |
|
1059 if g != sg: |
|
1060 if sg: |
|
1061 yield sg, s |
|
1062 sg, s = g, {n:1} |
|
1063 else: |
|
1064 s[n] = 1 |
|
1065 yield sg, s |
|
1066 |
|
1067 x = generations(a) |
|
1068 y = generations(b) |
|
1069 gx = x.next() |
|
1070 gy = y.next() |
|
1071 |
|
1072 # increment each ancestor list until it is closer to root than |
|
1073 # the other, or they match |
|
1074 while 1: |
|
1075 #print "ancestor gen %s %s" % (gx[0], gy[0]) |
|
1076 if gx[0] == gy[0]: |
|
1077 # find the intersection |
|
1078 i = [ n for n in gx[1] if n in gy[1] ] |
|
1079 if i: |
|
1080 return i[0] |
|
1081 else: |
|
1082 #print "next" |
|
1083 gy = y.next() |
|
1084 gx = x.next() |
|
1085 elif gx[0] < gy[0]: |
|
1086 #print "next y" |
|
1087 gy = y.next() |
|
1088 else: |
|
1089 #print "next x" |
|
1090 gx = x.next() |
|
1091 |
1023 |
1092 def group(self, nodelist, lookup, infocollect=None): |
1024 def group(self, nodelist, lookup, infocollect=None): |
1093 """calculate a delta group |
1025 """calculate a delta group |
1094 |
1026 |
1095 Given a list of changeset revs, return a set of deltas and |
1027 Given a list of changeset revs, return a set of deltas and |