##// END OF EJS Templates
manifest: removed usage of the global cmp function...
Renato Cunha -
r11763:69e0bcf3 default
parent child Browse files
Show More
@@ -1,200 +1,200 b''
1 # manifest.py - manifest revision class for mercurial
1 # manifest.py - manifest revision class for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import mdiff, parsers, error, revlog
9 import mdiff, parsers, error, revlog
10 import array, struct
10 import array, struct
11
11
12 class manifestdict(dict):
12 class manifestdict(dict):
13 def __init__(self, mapping=None, flags=None):
13 def __init__(self, mapping=None, flags=None):
14 if mapping is None:
14 if mapping is None:
15 mapping = {}
15 mapping = {}
16 if flags is None:
16 if flags is None:
17 flags = {}
17 flags = {}
18 dict.__init__(self, mapping)
18 dict.__init__(self, mapping)
19 self._flags = flags
19 self._flags = flags
20 def flags(self, f):
20 def flags(self, f):
21 return self._flags.get(f, "")
21 return self._flags.get(f, "")
22 def set(self, f, flags):
22 def set(self, f, flags):
23 self._flags[f] = flags
23 self._flags[f] = flags
24 def copy(self):
24 def copy(self):
25 return manifestdict(self, dict.copy(self._flags))
25 return manifestdict(self, dict.copy(self._flags))
26
26
27 class manifest(revlog.revlog):
27 class manifest(revlog.revlog):
28 def __init__(self, opener):
28 def __init__(self, opener):
29 self._mancache = None
29 self._mancache = None
30 revlog.revlog.__init__(self, opener, "00manifest.i")
30 revlog.revlog.__init__(self, opener, "00manifest.i")
31
31
32 def parse(self, lines):
32 def parse(self, lines):
33 mfdict = manifestdict()
33 mfdict = manifestdict()
34 parsers.parse_manifest(mfdict, mfdict._flags, lines)
34 parsers.parse_manifest(mfdict, mfdict._flags, lines)
35 return mfdict
35 return mfdict
36
36
37 def readdelta(self, node):
37 def readdelta(self, node):
38 r = self.rev(node)
38 r = self.rev(node)
39 return self.parse(mdiff.patchtext(self.revdiff(r - 1, r)))
39 return self.parse(mdiff.patchtext(self.revdiff(r - 1, r)))
40
40
41 def read(self, node):
41 def read(self, node):
42 if node == revlog.nullid:
42 if node == revlog.nullid:
43 return manifestdict() # don't upset local cache
43 return manifestdict() # don't upset local cache
44 if self._mancache and self._mancache[0] == node:
44 if self._mancache and self._mancache[0] == node:
45 return self._mancache[1]
45 return self._mancache[1]
46 text = self.revision(node)
46 text = self.revision(node)
47 arraytext = array.array('c', text)
47 arraytext = array.array('c', text)
48 mapping = self.parse(text)
48 mapping = self.parse(text)
49 self._mancache = (node, mapping, arraytext)
49 self._mancache = (node, mapping, arraytext)
50 return mapping
50 return mapping
51
51
52 def _search(self, m, s, lo=0, hi=None):
52 def _search(self, m, s, lo=0, hi=None):
53 '''return a tuple (start, end) that says where to find s within m.
53 '''return a tuple (start, end) that says where to find s within m.
54
54
55 If the string is found m[start:end] are the line containing
55 If the string is found m[start:end] are the line containing
56 that string. If start == end the string was not found and
56 that string. If start == end the string was not found and
57 they indicate the proper sorted insertion point. This was
57 they indicate the proper sorted insertion point. This was
58 taken from bisect_left, and modified to find line start/end as
58 taken from bisect_left, and modified to find line start/end as
59 it goes along.
59 it goes along.
60
60
61 m should be a buffer or a string
61 m should be a buffer or a string
62 s is a string'''
62 s is a string'''
63 def advance(i, c):
63 def advance(i, c):
64 while i < lenm and m[i] != c:
64 while i < lenm and m[i] != c:
65 i += 1
65 i += 1
66 return i
66 return i
67 if not s:
67 if not s:
68 return (lo, lo)
68 return (lo, lo)
69 lenm = len(m)
69 lenm = len(m)
70 if not hi:
70 if not hi:
71 hi = lenm
71 hi = lenm
72 while lo < hi:
72 while lo < hi:
73 mid = (lo + hi) // 2
73 mid = (lo + hi) // 2
74 start = mid
74 start = mid
75 while start > 0 and m[start - 1] != '\n':
75 while start > 0 and m[start - 1] != '\n':
76 start -= 1
76 start -= 1
77 end = advance(start, '\0')
77 end = advance(start, '\0')
78 if m[start:end] < s:
78 if m[start:end] < s:
79 # we know that after the null there are 40 bytes of sha1
79 # we know that after the null there are 40 bytes of sha1
80 # this translates to the bisect lo = mid + 1
80 # this translates to the bisect lo = mid + 1
81 lo = advance(end + 40, '\n') + 1
81 lo = advance(end + 40, '\n') + 1
82 else:
82 else:
83 # this translates to the bisect hi = mid
83 # this translates to the bisect hi = mid
84 hi = start
84 hi = start
85 end = advance(lo, '\0')
85 end = advance(lo, '\0')
86 found = m[lo:end]
86 found = m[lo:end]
87 if cmp(s, found) == 0:
87 if s == found:
88 # we know that after the null there are 40 bytes of sha1
88 # we know that after the null there are 40 bytes of sha1
89 end = advance(end + 40, '\n')
89 end = advance(end + 40, '\n')
90 return (lo, end + 1)
90 return (lo, end + 1)
91 else:
91 else:
92 return (lo, lo)
92 return (lo, lo)
93
93
94 def find(self, node, f):
94 def find(self, node, f):
95 '''look up entry for a single file efficiently.
95 '''look up entry for a single file efficiently.
96 return (node, flags) pair if found, (None, None) if not.'''
96 return (node, flags) pair if found, (None, None) if not.'''
97 if self._mancache and self._mancache[0] == node:
97 if self._mancache and self._mancache[0] == node:
98 return self._mancache[1].get(f), self._mancache[1].flags(f)
98 return self._mancache[1].get(f), self._mancache[1].flags(f)
99 text = self.revision(node)
99 text = self.revision(node)
100 start, end = self._search(text, f)
100 start, end = self._search(text, f)
101 if start == end:
101 if start == end:
102 return None, None
102 return None, None
103 l = text[start:end]
103 l = text[start:end]
104 f, n = l.split('\0')
104 f, n = l.split('\0')
105 return revlog.bin(n[:40]), n[40:-1]
105 return revlog.bin(n[:40]), n[40:-1]
106
106
107 def add(self, map, transaction, link, p1=None, p2=None,
107 def add(self, map, transaction, link, p1=None, p2=None,
108 changed=None):
108 changed=None):
109 # apply the changes collected during the bisect loop to our addlist
109 # apply the changes collected during the bisect loop to our addlist
110 # return a delta suitable for addrevision
110 # return a delta suitable for addrevision
111 def addlistdelta(addlist, x):
111 def addlistdelta(addlist, x):
112 # start from the bottom up
112 # start from the bottom up
113 # so changes to the offsets don't mess things up.
113 # so changes to the offsets don't mess things up.
114 for start, end, content in reversed(x):
114 for start, end, content in reversed(x):
115 if content:
115 if content:
116 addlist[start:end] = array.array('c', content)
116 addlist[start:end] = array.array('c', content)
117 else:
117 else:
118 del addlist[start:end]
118 del addlist[start:end]
119 return "".join(struct.pack(">lll", start, end, len(content)) + content
119 return "".join(struct.pack(">lll", start, end, len(content)) + content
120 for start, end, content in x)
120 for start, end, content in x)
121
121
122 def checkforbidden(l):
122 def checkforbidden(l):
123 for f in l:
123 for f in l:
124 if '\n' in f or '\r' in f:
124 if '\n' in f or '\r' in f:
125 raise error.RevlogError(
125 raise error.RevlogError(
126 _("'\\n' and '\\r' disallowed in filenames: %r") % f)
126 _("'\\n' and '\\r' disallowed in filenames: %r") % f)
127
127
128 # if we're using the cache, make sure it is valid and
128 # if we're using the cache, make sure it is valid and
129 # parented by the same node we're diffing against
129 # parented by the same node we're diffing against
130 if not (changed and self._mancache and p1 and self._mancache[0] == p1):
130 if not (changed and self._mancache and p1 and self._mancache[0] == p1):
131 files = sorted(map)
131 files = sorted(map)
132 checkforbidden(files)
132 checkforbidden(files)
133
133
134 # if this is changed to support newlines in filenames,
134 # if this is changed to support newlines in filenames,
135 # be sure to check the templates/ dir again (especially *-raw.tmpl)
135 # be sure to check the templates/ dir again (especially *-raw.tmpl)
136 hex, flags = revlog.hex, map.flags
136 hex, flags = revlog.hex, map.flags
137 text = ''.join("%s\000%s%s\n" % (f, hex(map[f]), flags(f))
137 text = ''.join("%s\000%s%s\n" % (f, hex(map[f]), flags(f))
138 for f in files)
138 for f in files)
139 arraytext = array.array('c', text)
139 arraytext = array.array('c', text)
140 cachedelta = None
140 cachedelta = None
141 else:
141 else:
142 added, removed = changed
142 added, removed = changed
143 addlist = self._mancache[2]
143 addlist = self._mancache[2]
144
144
145 checkforbidden(added)
145 checkforbidden(added)
146 # combine the changed lists into one list for sorting
146 # combine the changed lists into one list for sorting
147 work = [(x, False) for x in added]
147 work = [(x, False) for x in added]
148 work.extend((x, True) for x in removed)
148 work.extend((x, True) for x in removed)
149 # this could use heapq.merge() (from python2.6+) or equivalent
149 # this could use heapq.merge() (from python2.6+) or equivalent
150 # since the lists are already sorted
150 # since the lists are already sorted
151 work.sort()
151 work.sort()
152
152
153 delta = []
153 delta = []
154 dstart = None
154 dstart = None
155 dend = None
155 dend = None
156 dline = [""]
156 dline = [""]
157 start = 0
157 start = 0
158 # zero copy representation of addlist as a buffer
158 # zero copy representation of addlist as a buffer
159 addbuf = buffer(addlist)
159 addbuf = buffer(addlist)
160
160
161 # start with a readonly loop that finds the offset of
161 # start with a readonly loop that finds the offset of
162 # each line and creates the deltas
162 # each line and creates the deltas
163 for f, todelete in work:
163 for f, todelete in work:
164 # bs will either be the index of the item or the insert point
164 # bs will either be the index of the item or the insert point
165 start, end = self._search(addbuf, f, start)
165 start, end = self._search(addbuf, f, start)
166 if not todelete:
166 if not todelete:
167 l = "%s\000%s%s\n" % (f, revlog.hex(map[f]), map.flags(f))
167 l = "%s\000%s%s\n" % (f, revlog.hex(map[f]), map.flags(f))
168 else:
168 else:
169 if start == end:
169 if start == end:
170 # item we want to delete was not found, error out
170 # item we want to delete was not found, error out
171 raise AssertionError(
171 raise AssertionError(
172 _("failed to remove %s from manifest") % f)
172 _("failed to remove %s from manifest") % f)
173 l = ""
173 l = ""
174 if dstart != None and dstart <= start and dend >= start:
174 if dstart != None and dstart <= start and dend >= start:
175 if dend < end:
175 if dend < end:
176 dend = end
176 dend = end
177 if l:
177 if l:
178 dline.append(l)
178 dline.append(l)
179 else:
179 else:
180 if dstart != None:
180 if dstart != None:
181 delta.append([dstart, dend, "".join(dline)])
181 delta.append([dstart, dend, "".join(dline)])
182 dstart = start
182 dstart = start
183 dend = end
183 dend = end
184 dline = [l]
184 dline = [l]
185
185
186 if dstart != None:
186 if dstart != None:
187 delta.append([dstart, dend, "".join(dline)])
187 delta.append([dstart, dend, "".join(dline)])
188 # apply the delta to the addlist, and get a delta for addrevision
188 # apply the delta to the addlist, and get a delta for addrevision
189 cachedelta = addlistdelta(addlist, delta)
189 cachedelta = addlistdelta(addlist, delta)
190
190
191 # the delta is only valid if we've been processing the tip revision
191 # the delta is only valid if we've been processing the tip revision
192 if p1 != self.tip():
192 if p1 != self.tip():
193 cachedelta = None
193 cachedelta = None
194 arraytext = addlist
194 arraytext = addlist
195 text = buffer(arraytext)
195 text = buffer(arraytext)
196
196
197 n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
197 n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
198 self._mancache = (n, map, arraytext)
198 self._mancache = (n, map, arraytext)
199
199
200 return n
200 return n
General Comments 0
You need to be logged in to leave comments. Login now