##// END OF EJS Templates
manifest: use absolute_import
Gregory Szorc -
r27502:2df7f5c0 default
parent child Browse files
Show More
@@ -1,1042 +1,1052 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 __future__ import absolute_import
9 import mdiff, parsers, error, revlog, util
9
10 import array, struct
10 import array
11 import heapq
11 import os
12 import os
12 import heapq
13 import struct
14
15 from .i18n import _
16 from . import (
17 error,
18 mdiff,
19 parsers,
20 revlog,
21 util,
22 )
13
23
14 propertycache = util.propertycache
24 propertycache = util.propertycache
15
25
16 def _parsev1(data):
26 def _parsev1(data):
17 # This method does a little bit of excessive-looking
27 # This method does a little bit of excessive-looking
18 # precondition checking. This is so that the behavior of this
28 # precondition checking. This is so that the behavior of this
19 # class exactly matches its C counterpart to try and help
29 # class exactly matches its C counterpart to try and help
20 # prevent surprise breakage for anyone that develops against
30 # prevent surprise breakage for anyone that develops against
21 # the pure version.
31 # the pure version.
22 if data and data[-1] != '\n':
32 if data and data[-1] != '\n':
23 raise ValueError('Manifest did not end in a newline.')
33 raise ValueError('Manifest did not end in a newline.')
24 prev = None
34 prev = None
25 for l in data.splitlines():
35 for l in data.splitlines():
26 if prev is not None and prev > l:
36 if prev is not None and prev > l:
27 raise ValueError('Manifest lines not in sorted order.')
37 raise ValueError('Manifest lines not in sorted order.')
28 prev = l
38 prev = l
29 f, n = l.split('\0')
39 f, n = l.split('\0')
30 if len(n) > 40:
40 if len(n) > 40:
31 yield f, revlog.bin(n[:40]), n[40:]
41 yield f, revlog.bin(n[:40]), n[40:]
32 else:
42 else:
33 yield f, revlog.bin(n), ''
43 yield f, revlog.bin(n), ''
34
44
35 def _parsev2(data):
45 def _parsev2(data):
36 metadataend = data.find('\n')
46 metadataend = data.find('\n')
37 # Just ignore metadata for now
47 # Just ignore metadata for now
38 pos = metadataend + 1
48 pos = metadataend + 1
39 prevf = ''
49 prevf = ''
40 while pos < len(data):
50 while pos < len(data):
41 end = data.find('\n', pos + 1) # +1 to skip stem length byte
51 end = data.find('\n', pos + 1) # +1 to skip stem length byte
42 if end == -1:
52 if end == -1:
43 raise ValueError('Manifest ended with incomplete file entry.')
53 raise ValueError('Manifest ended with incomplete file entry.')
44 stemlen = ord(data[pos])
54 stemlen = ord(data[pos])
45 items = data[pos + 1:end].split('\0')
55 items = data[pos + 1:end].split('\0')
46 f = prevf[:stemlen] + items[0]
56 f = prevf[:stemlen] + items[0]
47 if prevf > f:
57 if prevf > f:
48 raise ValueError('Manifest entries not in sorted order.')
58 raise ValueError('Manifest entries not in sorted order.')
49 fl = items[1]
59 fl = items[1]
50 # Just ignore metadata (items[2:] for now)
60 # Just ignore metadata (items[2:] for now)
51 n = data[end + 1:end + 21]
61 n = data[end + 1:end + 21]
52 yield f, n, fl
62 yield f, n, fl
53 pos = end + 22
63 pos = end + 22
54 prevf = f
64 prevf = f
55
65
56 def _parse(data):
66 def _parse(data):
57 """Generates (path, node, flags) tuples from a manifest text"""
67 """Generates (path, node, flags) tuples from a manifest text"""
58 if data.startswith('\0'):
68 if data.startswith('\0'):
59 return iter(_parsev2(data))
69 return iter(_parsev2(data))
60 else:
70 else:
61 return iter(_parsev1(data))
71 return iter(_parsev1(data))
62
72
63 def _text(it, usemanifestv2):
73 def _text(it, usemanifestv2):
64 """Given an iterator over (path, node, flags) tuples, returns a manifest
74 """Given an iterator over (path, node, flags) tuples, returns a manifest
65 text"""
75 text"""
66 if usemanifestv2:
76 if usemanifestv2:
67 return _textv2(it)
77 return _textv2(it)
68 else:
78 else:
69 return _textv1(it)
79 return _textv1(it)
70
80
71 def _textv1(it):
81 def _textv1(it):
72 files = []
82 files = []
73 lines = []
83 lines = []
74 _hex = revlog.hex
84 _hex = revlog.hex
75 for f, n, fl in it:
85 for f, n, fl in it:
76 files.append(f)
86 files.append(f)
77 # if this is changed to support newlines in filenames,
87 # if this is changed to support newlines in filenames,
78 # be sure to check the templates/ dir again (especially *-raw.tmpl)
88 # be sure to check the templates/ dir again (especially *-raw.tmpl)
79 lines.append("%s\0%s%s\n" % (f, _hex(n), fl))
89 lines.append("%s\0%s%s\n" % (f, _hex(n), fl))
80
90
81 _checkforbidden(files)
91 _checkforbidden(files)
82 return ''.join(lines)
92 return ''.join(lines)
83
93
84 def _textv2(it):
94 def _textv2(it):
85 files = []
95 files = []
86 lines = ['\0\n']
96 lines = ['\0\n']
87 prevf = ''
97 prevf = ''
88 for f, n, fl in it:
98 for f, n, fl in it:
89 files.append(f)
99 files.append(f)
90 stem = os.path.commonprefix([prevf, f])
100 stem = os.path.commonprefix([prevf, f])
91 stemlen = min(len(stem), 255)
101 stemlen = min(len(stem), 255)
92 lines.append("%c%s\0%s\n%s\n" % (stemlen, f[stemlen:], fl, n))
102 lines.append("%c%s\0%s\n%s\n" % (stemlen, f[stemlen:], fl, n))
93 prevf = f
103 prevf = f
94 _checkforbidden(files)
104 _checkforbidden(files)
95 return ''.join(lines)
105 return ''.join(lines)
96
106
97 class _lazymanifest(dict):
107 class _lazymanifest(dict):
98 """This is the pure implementation of lazymanifest.
108 """This is the pure implementation of lazymanifest.
99
109
100 It has not been optimized *at all* and is not lazy.
110 It has not been optimized *at all* and is not lazy.
101 """
111 """
102
112
103 def __init__(self, data):
113 def __init__(self, data):
104 dict.__init__(self)
114 dict.__init__(self)
105 for f, n, fl in _parse(data):
115 for f, n, fl in _parse(data):
106 self[f] = n, fl
116 self[f] = n, fl
107
117
108 def __setitem__(self, k, v):
118 def __setitem__(self, k, v):
109 node, flag = v
119 node, flag = v
110 assert node is not None
120 assert node is not None
111 if len(node) > 21:
121 if len(node) > 21:
112 node = node[:21] # match c implementation behavior
122 node = node[:21] # match c implementation behavior
113 dict.__setitem__(self, k, (node, flag))
123 dict.__setitem__(self, k, (node, flag))
114
124
115 def __iter__(self):
125 def __iter__(self):
116 return iter(sorted(dict.keys(self)))
126 return iter(sorted(dict.keys(self)))
117
127
118 def iterkeys(self):
128 def iterkeys(self):
119 return iter(sorted(dict.keys(self)))
129 return iter(sorted(dict.keys(self)))
120
130
121 def iterentries(self):
131 def iterentries(self):
122 return ((f, e[0], e[1]) for f, e in sorted(self.iteritems()))
132 return ((f, e[0], e[1]) for f, e in sorted(self.iteritems()))
123
133
124 def copy(self):
134 def copy(self):
125 c = _lazymanifest('')
135 c = _lazymanifest('')
126 c.update(self)
136 c.update(self)
127 return c
137 return c
128
138
129 def diff(self, m2, clean=False):
139 def diff(self, m2, clean=False):
130 '''Finds changes between the current manifest and m2.'''
140 '''Finds changes between the current manifest and m2.'''
131 diff = {}
141 diff = {}
132
142
133 for fn, e1 in self.iteritems():
143 for fn, e1 in self.iteritems():
134 if fn not in m2:
144 if fn not in m2:
135 diff[fn] = e1, (None, '')
145 diff[fn] = e1, (None, '')
136 else:
146 else:
137 e2 = m2[fn]
147 e2 = m2[fn]
138 if e1 != e2:
148 if e1 != e2:
139 diff[fn] = e1, e2
149 diff[fn] = e1, e2
140 elif clean:
150 elif clean:
141 diff[fn] = None
151 diff[fn] = None
142
152
143 for fn, e2 in m2.iteritems():
153 for fn, e2 in m2.iteritems():
144 if fn not in self:
154 if fn not in self:
145 diff[fn] = (None, ''), e2
155 diff[fn] = (None, ''), e2
146
156
147 return diff
157 return diff
148
158
149 def filtercopy(self, filterfn):
159 def filtercopy(self, filterfn):
150 c = _lazymanifest('')
160 c = _lazymanifest('')
151 for f, n, fl in self.iterentries():
161 for f, n, fl in self.iterentries():
152 if filterfn(f):
162 if filterfn(f):
153 c[f] = n, fl
163 c[f] = n, fl
154 return c
164 return c
155
165
156 def text(self):
166 def text(self):
157 """Get the full data of this manifest as a bytestring."""
167 """Get the full data of this manifest as a bytestring."""
158 return _textv1(self.iterentries())
168 return _textv1(self.iterentries())
159
169
160 try:
170 try:
161 _lazymanifest = parsers.lazymanifest
171 _lazymanifest = parsers.lazymanifest
162 except AttributeError:
172 except AttributeError:
163 pass
173 pass
164
174
165 class manifestdict(object):
175 class manifestdict(object):
166 def __init__(self, data=''):
176 def __init__(self, data=''):
167 if data.startswith('\0'):
177 if data.startswith('\0'):
168 #_lazymanifest can not parse v2
178 #_lazymanifest can not parse v2
169 self._lm = _lazymanifest('')
179 self._lm = _lazymanifest('')
170 for f, n, fl in _parsev2(data):
180 for f, n, fl in _parsev2(data):
171 self._lm[f] = n, fl
181 self._lm[f] = n, fl
172 else:
182 else:
173 self._lm = _lazymanifest(data)
183 self._lm = _lazymanifest(data)
174
184
175 def __getitem__(self, key):
185 def __getitem__(self, key):
176 return self._lm[key][0]
186 return self._lm[key][0]
177
187
178 def find(self, key):
188 def find(self, key):
179 return self._lm[key]
189 return self._lm[key]
180
190
181 def __len__(self):
191 def __len__(self):
182 return len(self._lm)
192 return len(self._lm)
183
193
184 def __setitem__(self, key, node):
194 def __setitem__(self, key, node):
185 self._lm[key] = node, self.flags(key, '')
195 self._lm[key] = node, self.flags(key, '')
186
196
187 def __contains__(self, key):
197 def __contains__(self, key):
188 return key in self._lm
198 return key in self._lm
189
199
190 def __delitem__(self, key):
200 def __delitem__(self, key):
191 del self._lm[key]
201 del self._lm[key]
192
202
193 def __iter__(self):
203 def __iter__(self):
194 return self._lm.__iter__()
204 return self._lm.__iter__()
195
205
196 def iterkeys(self):
206 def iterkeys(self):
197 return self._lm.iterkeys()
207 return self._lm.iterkeys()
198
208
199 def keys(self):
209 def keys(self):
200 return list(self.iterkeys())
210 return list(self.iterkeys())
201
211
202 def filesnotin(self, m2):
212 def filesnotin(self, m2):
203 '''Set of files in this manifest that are not in the other'''
213 '''Set of files in this manifest that are not in the other'''
204 files = set(self)
214 files = set(self)
205 files.difference_update(m2)
215 files.difference_update(m2)
206 return files
216 return files
207
217
208 @propertycache
218 @propertycache
209 def _dirs(self):
219 def _dirs(self):
210 return util.dirs(self)
220 return util.dirs(self)
211
221
212 def dirs(self):
222 def dirs(self):
213 return self._dirs
223 return self._dirs
214
224
215 def hasdir(self, dir):
225 def hasdir(self, dir):
216 return dir in self._dirs
226 return dir in self._dirs
217
227
218 def _filesfastpath(self, match):
228 def _filesfastpath(self, match):
219 '''Checks whether we can correctly and quickly iterate over matcher
229 '''Checks whether we can correctly and quickly iterate over matcher
220 files instead of over manifest files.'''
230 files instead of over manifest files.'''
221 files = match.files()
231 files = match.files()
222 return (len(files) < 100 and (match.isexact() or
232 return (len(files) < 100 and (match.isexact() or
223 (match.prefix() and all(fn in self for fn in files))))
233 (match.prefix() and all(fn in self for fn in files))))
224
234
225 def walk(self, match):
235 def walk(self, match):
226 '''Generates matching file names.
236 '''Generates matching file names.
227
237
228 Equivalent to manifest.matches(match).iterkeys(), but without creating
238 Equivalent to manifest.matches(match).iterkeys(), but without creating
229 an entirely new manifest.
239 an entirely new manifest.
230
240
231 It also reports nonexistent files by marking them bad with match.bad().
241 It also reports nonexistent files by marking them bad with match.bad().
232 '''
242 '''
233 if match.always():
243 if match.always():
234 for f in iter(self):
244 for f in iter(self):
235 yield f
245 yield f
236 return
246 return
237
247
238 fset = set(match.files())
248 fset = set(match.files())
239
249
240 # avoid the entire walk if we're only looking for specific files
250 # avoid the entire walk if we're only looking for specific files
241 if self._filesfastpath(match):
251 if self._filesfastpath(match):
242 for fn in sorted(fset):
252 for fn in sorted(fset):
243 yield fn
253 yield fn
244 return
254 return
245
255
246 for fn in self:
256 for fn in self:
247 if fn in fset:
257 if fn in fset:
248 # specified pattern is the exact name
258 # specified pattern is the exact name
249 fset.remove(fn)
259 fset.remove(fn)
250 if match(fn):
260 if match(fn):
251 yield fn
261 yield fn
252
262
253 # for dirstate.walk, files=['.'] means "walk the whole tree".
263 # for dirstate.walk, files=['.'] means "walk the whole tree".
254 # follow that here, too
264 # follow that here, too
255 fset.discard('.')
265 fset.discard('.')
256
266
257 for fn in sorted(fset):
267 for fn in sorted(fset):
258 if not self.hasdir(fn):
268 if not self.hasdir(fn):
259 match.bad(fn, None)
269 match.bad(fn, None)
260
270
261 def matches(self, match):
271 def matches(self, match):
262 '''generate a new manifest filtered by the match argument'''
272 '''generate a new manifest filtered by the match argument'''
263 if match.always():
273 if match.always():
264 return self.copy()
274 return self.copy()
265
275
266 if self._filesfastpath(match):
276 if self._filesfastpath(match):
267 m = manifestdict()
277 m = manifestdict()
268 lm = self._lm
278 lm = self._lm
269 for fn in match.files():
279 for fn in match.files():
270 if fn in lm:
280 if fn in lm:
271 m._lm[fn] = lm[fn]
281 m._lm[fn] = lm[fn]
272 return m
282 return m
273
283
274 m = manifestdict()
284 m = manifestdict()
275 m._lm = self._lm.filtercopy(match)
285 m._lm = self._lm.filtercopy(match)
276 return m
286 return m
277
287
278 def diff(self, m2, clean=False):
288 def diff(self, m2, clean=False):
279 '''Finds changes between the current manifest and m2.
289 '''Finds changes between the current manifest and m2.
280
290
281 Args:
291 Args:
282 m2: the manifest to which this manifest should be compared.
292 m2: the manifest to which this manifest should be compared.
283 clean: if true, include files unchanged between these manifests
293 clean: if true, include files unchanged between these manifests
284 with a None value in the returned dictionary.
294 with a None value in the returned dictionary.
285
295
286 The result is returned as a dict with filename as key and
296 The result is returned as a dict with filename as key and
287 values of the form ((n1,fl1),(n2,fl2)), where n1/n2 is the
297 values of the form ((n1,fl1),(n2,fl2)), where n1/n2 is the
288 nodeid in the current/other manifest and fl1/fl2 is the flag
298 nodeid in the current/other manifest and fl1/fl2 is the flag
289 in the current/other manifest. Where the file does not exist,
299 in the current/other manifest. Where the file does not exist,
290 the nodeid will be None and the flags will be the empty
300 the nodeid will be None and the flags will be the empty
291 string.
301 string.
292 '''
302 '''
293 return self._lm.diff(m2._lm, clean)
303 return self._lm.diff(m2._lm, clean)
294
304
295 def setflag(self, key, flag):
305 def setflag(self, key, flag):
296 self._lm[key] = self[key], flag
306 self._lm[key] = self[key], flag
297
307
298 def get(self, key, default=None):
308 def get(self, key, default=None):
299 try:
309 try:
300 return self._lm[key][0]
310 return self._lm[key][0]
301 except KeyError:
311 except KeyError:
302 return default
312 return default
303
313
304 def flags(self, key, default=''):
314 def flags(self, key, default=''):
305 try:
315 try:
306 return self._lm[key][1]
316 return self._lm[key][1]
307 except KeyError:
317 except KeyError:
308 return default
318 return default
309
319
310 def copy(self):
320 def copy(self):
311 c = manifestdict()
321 c = manifestdict()
312 c._lm = self._lm.copy()
322 c._lm = self._lm.copy()
313 return c
323 return c
314
324
315 def iteritems(self):
325 def iteritems(self):
316 return (x[:2] for x in self._lm.iterentries())
326 return (x[:2] for x in self._lm.iterentries())
317
327
318 def text(self, usemanifestv2=False):
328 def text(self, usemanifestv2=False):
319 if usemanifestv2:
329 if usemanifestv2:
320 return _textv2(self._lm.iterentries())
330 return _textv2(self._lm.iterentries())
321 else:
331 else:
322 # use (probably) native version for v1
332 # use (probably) native version for v1
323 return self._lm.text()
333 return self._lm.text()
324
334
325 def fastdelta(self, base, changes):
335 def fastdelta(self, base, changes):
326 """Given a base manifest text as an array.array and a list of changes
336 """Given a base manifest text as an array.array and a list of changes
327 relative to that text, compute a delta that can be used by revlog.
337 relative to that text, compute a delta that can be used by revlog.
328 """
338 """
329 delta = []
339 delta = []
330 dstart = None
340 dstart = None
331 dend = None
341 dend = None
332 dline = [""]
342 dline = [""]
333 start = 0
343 start = 0
334 # zero copy representation of base as a buffer
344 # zero copy representation of base as a buffer
335 addbuf = util.buffer(base)
345 addbuf = util.buffer(base)
336
346
337 changes = list(changes)
347 changes = list(changes)
338 if len(changes) < 1000:
348 if len(changes) < 1000:
339 # start with a readonly loop that finds the offset of
349 # start with a readonly loop that finds the offset of
340 # each line and creates the deltas
350 # each line and creates the deltas
341 for f, todelete in changes:
351 for f, todelete in changes:
342 # bs will either be the index of the item or the insert point
352 # bs will either be the index of the item or the insert point
343 start, end = _msearch(addbuf, f, start)
353 start, end = _msearch(addbuf, f, start)
344 if not todelete:
354 if not todelete:
345 h, fl = self._lm[f]
355 h, fl = self._lm[f]
346 l = "%s\0%s%s\n" % (f, revlog.hex(h), fl)
356 l = "%s\0%s%s\n" % (f, revlog.hex(h), fl)
347 else:
357 else:
348 if start == end:
358 if start == end:
349 # item we want to delete was not found, error out
359 # item we want to delete was not found, error out
350 raise AssertionError(
360 raise AssertionError(
351 _("failed to remove %s from manifest") % f)
361 _("failed to remove %s from manifest") % f)
352 l = ""
362 l = ""
353 if dstart is not None and dstart <= start and dend >= start:
363 if dstart is not None and dstart <= start and dend >= start:
354 if dend < end:
364 if dend < end:
355 dend = end
365 dend = end
356 if l:
366 if l:
357 dline.append(l)
367 dline.append(l)
358 else:
368 else:
359 if dstart is not None:
369 if dstart is not None:
360 delta.append([dstart, dend, "".join(dline)])
370 delta.append([dstart, dend, "".join(dline)])
361 dstart = start
371 dstart = start
362 dend = end
372 dend = end
363 dline = [l]
373 dline = [l]
364
374
365 if dstart is not None:
375 if dstart is not None:
366 delta.append([dstart, dend, "".join(dline)])
376 delta.append([dstart, dend, "".join(dline)])
367 # apply the delta to the base, and get a delta for addrevision
377 # apply the delta to the base, and get a delta for addrevision
368 deltatext, arraytext = _addlistdelta(base, delta)
378 deltatext, arraytext = _addlistdelta(base, delta)
369 else:
379 else:
370 # For large changes, it's much cheaper to just build the text and
380 # For large changes, it's much cheaper to just build the text and
371 # diff it.
381 # diff it.
372 arraytext = array.array('c', self.text())
382 arraytext = array.array('c', self.text())
373 deltatext = mdiff.textdiff(base, arraytext)
383 deltatext = mdiff.textdiff(base, arraytext)
374
384
375 return arraytext, deltatext
385 return arraytext, deltatext
376
386
377 def _msearch(m, s, lo=0, hi=None):
387 def _msearch(m, s, lo=0, hi=None):
378 '''return a tuple (start, end) that says where to find s within m.
388 '''return a tuple (start, end) that says where to find s within m.
379
389
380 If the string is found m[start:end] are the line containing
390 If the string is found m[start:end] are the line containing
381 that string. If start == end the string was not found and
391 that string. If start == end the string was not found and
382 they indicate the proper sorted insertion point.
392 they indicate the proper sorted insertion point.
383
393
384 m should be a buffer or a string
394 m should be a buffer or a string
385 s is a string'''
395 s is a string'''
386 def advance(i, c):
396 def advance(i, c):
387 while i < lenm and m[i] != c:
397 while i < lenm and m[i] != c:
388 i += 1
398 i += 1
389 return i
399 return i
390 if not s:
400 if not s:
391 return (lo, lo)
401 return (lo, lo)
392 lenm = len(m)
402 lenm = len(m)
393 if not hi:
403 if not hi:
394 hi = lenm
404 hi = lenm
395 while lo < hi:
405 while lo < hi:
396 mid = (lo + hi) // 2
406 mid = (lo + hi) // 2
397 start = mid
407 start = mid
398 while start > 0 and m[start - 1] != '\n':
408 while start > 0 and m[start - 1] != '\n':
399 start -= 1
409 start -= 1
400 end = advance(start, '\0')
410 end = advance(start, '\0')
401 if m[start:end] < s:
411 if m[start:end] < s:
402 # we know that after the null there are 40 bytes of sha1
412 # we know that after the null there are 40 bytes of sha1
403 # this translates to the bisect lo = mid + 1
413 # this translates to the bisect lo = mid + 1
404 lo = advance(end + 40, '\n') + 1
414 lo = advance(end + 40, '\n') + 1
405 else:
415 else:
406 # this translates to the bisect hi = mid
416 # this translates to the bisect hi = mid
407 hi = start
417 hi = start
408 end = advance(lo, '\0')
418 end = advance(lo, '\0')
409 found = m[lo:end]
419 found = m[lo:end]
410 if s == found:
420 if s == found:
411 # we know that after the null there are 40 bytes of sha1
421 # we know that after the null there are 40 bytes of sha1
412 end = advance(end + 40, '\n')
422 end = advance(end + 40, '\n')
413 return (lo, end + 1)
423 return (lo, end + 1)
414 else:
424 else:
415 return (lo, lo)
425 return (lo, lo)
416
426
417 def _checkforbidden(l):
427 def _checkforbidden(l):
418 """Check filenames for illegal characters."""
428 """Check filenames for illegal characters."""
419 for f in l:
429 for f in l:
420 if '\n' in f or '\r' in f:
430 if '\n' in f or '\r' in f:
421 raise error.RevlogError(
431 raise error.RevlogError(
422 _("'\\n' and '\\r' disallowed in filenames: %r") % f)
432 _("'\\n' and '\\r' disallowed in filenames: %r") % f)
423
433
424
434
425 # apply the changes collected during the bisect loop to our addlist
435 # apply the changes collected during the bisect loop to our addlist
426 # return a delta suitable for addrevision
436 # return a delta suitable for addrevision
427 def _addlistdelta(addlist, x):
437 def _addlistdelta(addlist, x):
428 # for large addlist arrays, building a new array is cheaper
438 # for large addlist arrays, building a new array is cheaper
429 # than repeatedly modifying the existing one
439 # than repeatedly modifying the existing one
430 currentposition = 0
440 currentposition = 0
431 newaddlist = array.array('c')
441 newaddlist = array.array('c')
432
442
433 for start, end, content in x:
443 for start, end, content in x:
434 newaddlist += addlist[currentposition:start]
444 newaddlist += addlist[currentposition:start]
435 if content:
445 if content:
436 newaddlist += array.array('c', content)
446 newaddlist += array.array('c', content)
437
447
438 currentposition = end
448 currentposition = end
439
449
440 newaddlist += addlist[currentposition:]
450 newaddlist += addlist[currentposition:]
441
451
442 deltatext = "".join(struct.pack(">lll", start, end, len(content))
452 deltatext = "".join(struct.pack(">lll", start, end, len(content))
443 + content for start, end, content in x)
453 + content for start, end, content in x)
444 return deltatext, newaddlist
454 return deltatext, newaddlist
445
455
446 def _splittopdir(f):
456 def _splittopdir(f):
447 if '/' in f:
457 if '/' in f:
448 dir, subpath = f.split('/', 1)
458 dir, subpath = f.split('/', 1)
449 return dir + '/', subpath
459 return dir + '/', subpath
450 else:
460 else:
451 return '', f
461 return '', f
452
462
453 _noop = lambda s: None
463 _noop = lambda s: None
454
464
455 class treemanifest(object):
465 class treemanifest(object):
456 def __init__(self, dir='', text=''):
466 def __init__(self, dir='', text=''):
457 self._dir = dir
467 self._dir = dir
458 self._node = revlog.nullid
468 self._node = revlog.nullid
459 self._loadfunc = _noop
469 self._loadfunc = _noop
460 self._copyfunc = _noop
470 self._copyfunc = _noop
461 self._dirty = False
471 self._dirty = False
462 self._dirs = {}
472 self._dirs = {}
463 # Using _lazymanifest here is a little slower than plain old dicts
473 # Using _lazymanifest here is a little slower than plain old dicts
464 self._files = {}
474 self._files = {}
465 self._flags = {}
475 self._flags = {}
466 if text:
476 if text:
467 def readsubtree(subdir, subm):
477 def readsubtree(subdir, subm):
468 raise AssertionError('treemanifest constructor only accepts '
478 raise AssertionError('treemanifest constructor only accepts '
469 'flat manifests')
479 'flat manifests')
470 self.parse(text, readsubtree)
480 self.parse(text, readsubtree)
471 self._dirty = True # Mark flat manifest dirty after parsing
481 self._dirty = True # Mark flat manifest dirty after parsing
472
482
473 def _subpath(self, path):
483 def _subpath(self, path):
474 return self._dir + path
484 return self._dir + path
475
485
476 def __len__(self):
486 def __len__(self):
477 self._load()
487 self._load()
478 size = len(self._files)
488 size = len(self._files)
479 for m in self._dirs.values():
489 for m in self._dirs.values():
480 size += m.__len__()
490 size += m.__len__()
481 return size
491 return size
482
492
483 def _isempty(self):
493 def _isempty(self):
484 self._load() # for consistency; already loaded by all callers
494 self._load() # for consistency; already loaded by all callers
485 return (not self._files and (not self._dirs or
495 return (not self._files and (not self._dirs or
486 all(m._isempty() for m in self._dirs.values())))
496 all(m._isempty() for m in self._dirs.values())))
487
497
488 def __repr__(self):
498 def __repr__(self):
489 return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s at 0x%x>' %
499 return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s at 0x%x>' %
490 (self._dir, revlog.hex(self._node),
500 (self._dir, revlog.hex(self._node),
491 bool(self._loadfunc is _noop),
501 bool(self._loadfunc is _noop),
492 self._dirty, id(self)))
502 self._dirty, id(self)))
493
503
494 def dir(self):
504 def dir(self):
495 '''The directory that this tree manifest represents, including a
505 '''The directory that this tree manifest represents, including a
496 trailing '/'. Empty string for the repo root directory.'''
506 trailing '/'. Empty string for the repo root directory.'''
497 return self._dir
507 return self._dir
498
508
499 def node(self):
509 def node(self):
500 '''This node of this instance. nullid for unsaved instances. Should
510 '''This node of this instance. nullid for unsaved instances. Should
501 be updated when the instance is read or written from a revlog.
511 be updated when the instance is read or written from a revlog.
502 '''
512 '''
503 assert not self._dirty
513 assert not self._dirty
504 return self._node
514 return self._node
505
515
506 def setnode(self, node):
516 def setnode(self, node):
507 self._node = node
517 self._node = node
508 self._dirty = False
518 self._dirty = False
509
519
510 def iteritems(self):
520 def iteritems(self):
511 self._load()
521 self._load()
512 for p, n in sorted(self._dirs.items() + self._files.items()):
522 for p, n in sorted(self._dirs.items() + self._files.items()):
513 if p in self._files:
523 if p in self._files:
514 yield self._subpath(p), n
524 yield self._subpath(p), n
515 else:
525 else:
516 for f, sn in n.iteritems():
526 for f, sn in n.iteritems():
517 yield f, sn
527 yield f, sn
518
528
519 def iterkeys(self):
529 def iterkeys(self):
520 self._load()
530 self._load()
521 for p in sorted(self._dirs.keys() + self._files.keys()):
531 for p in sorted(self._dirs.keys() + self._files.keys()):
522 if p in self._files:
532 if p in self._files:
523 yield self._subpath(p)
533 yield self._subpath(p)
524 else:
534 else:
525 for f in self._dirs[p].iterkeys():
535 for f in self._dirs[p].iterkeys():
526 yield f
536 yield f
527
537
528 def keys(self):
538 def keys(self):
529 return list(self.iterkeys())
539 return list(self.iterkeys())
530
540
531 def __iter__(self):
541 def __iter__(self):
532 return self.iterkeys()
542 return self.iterkeys()
533
543
534 def __contains__(self, f):
544 def __contains__(self, f):
535 if f is None:
545 if f is None:
536 return False
546 return False
537 self._load()
547 self._load()
538 dir, subpath = _splittopdir(f)
548 dir, subpath = _splittopdir(f)
539 if dir:
549 if dir:
540 if dir not in self._dirs:
550 if dir not in self._dirs:
541 return False
551 return False
542 return self._dirs[dir].__contains__(subpath)
552 return self._dirs[dir].__contains__(subpath)
543 else:
553 else:
544 return f in self._files
554 return f in self._files
545
555
546 def get(self, f, default=None):
556 def get(self, f, default=None):
547 self._load()
557 self._load()
548 dir, subpath = _splittopdir(f)
558 dir, subpath = _splittopdir(f)
549 if dir:
559 if dir:
550 if dir not in self._dirs:
560 if dir not in self._dirs:
551 return default
561 return default
552 return self._dirs[dir].get(subpath, default)
562 return self._dirs[dir].get(subpath, default)
553 else:
563 else:
554 return self._files.get(f, default)
564 return self._files.get(f, default)
555
565
556 def __getitem__(self, f):
566 def __getitem__(self, f):
557 self._load()
567 self._load()
558 dir, subpath = _splittopdir(f)
568 dir, subpath = _splittopdir(f)
559 if dir:
569 if dir:
560 return self._dirs[dir].__getitem__(subpath)
570 return self._dirs[dir].__getitem__(subpath)
561 else:
571 else:
562 return self._files[f]
572 return self._files[f]
563
573
564 def flags(self, f):
574 def flags(self, f):
565 self._load()
575 self._load()
566 dir, subpath = _splittopdir(f)
576 dir, subpath = _splittopdir(f)
567 if dir:
577 if dir:
568 if dir not in self._dirs:
578 if dir not in self._dirs:
569 return ''
579 return ''
570 return self._dirs[dir].flags(subpath)
580 return self._dirs[dir].flags(subpath)
571 else:
581 else:
572 if f in self._dirs:
582 if f in self._dirs:
573 return ''
583 return ''
574 return self._flags.get(f, '')
584 return self._flags.get(f, '')
575
585
576 def find(self, f):
586 def find(self, f):
577 self._load()
587 self._load()
578 dir, subpath = _splittopdir(f)
588 dir, subpath = _splittopdir(f)
579 if dir:
589 if dir:
580 return self._dirs[dir].find(subpath)
590 return self._dirs[dir].find(subpath)
581 else:
591 else:
582 return self._files[f], self._flags.get(f, '')
592 return self._files[f], self._flags.get(f, '')
583
593
584 def __delitem__(self, f):
594 def __delitem__(self, f):
585 self._load()
595 self._load()
586 dir, subpath = _splittopdir(f)
596 dir, subpath = _splittopdir(f)
587 if dir:
597 if dir:
588 self._dirs[dir].__delitem__(subpath)
598 self._dirs[dir].__delitem__(subpath)
589 # If the directory is now empty, remove it
599 # If the directory is now empty, remove it
590 if self._dirs[dir]._isempty():
600 if self._dirs[dir]._isempty():
591 del self._dirs[dir]
601 del self._dirs[dir]
592 else:
602 else:
593 del self._files[f]
603 del self._files[f]
594 if f in self._flags:
604 if f in self._flags:
595 del self._flags[f]
605 del self._flags[f]
596 self._dirty = True
606 self._dirty = True
597
607
598 def __setitem__(self, f, n):
608 def __setitem__(self, f, n):
599 assert n is not None
609 assert n is not None
600 self._load()
610 self._load()
601 dir, subpath = _splittopdir(f)
611 dir, subpath = _splittopdir(f)
602 if dir:
612 if dir:
603 if dir not in self._dirs:
613 if dir not in self._dirs:
604 self._dirs[dir] = treemanifest(self._subpath(dir))
614 self._dirs[dir] = treemanifest(self._subpath(dir))
605 self._dirs[dir].__setitem__(subpath, n)
615 self._dirs[dir].__setitem__(subpath, n)
606 else:
616 else:
607 self._files[f] = n[:21] # to match manifestdict's behavior
617 self._files[f] = n[:21] # to match manifestdict's behavior
608 self._dirty = True
618 self._dirty = True
609
619
610 def _load(self):
620 def _load(self):
611 if self._loadfunc is not _noop:
621 if self._loadfunc is not _noop:
612 lf, self._loadfunc = self._loadfunc, _noop
622 lf, self._loadfunc = self._loadfunc, _noop
613 lf(self)
623 lf(self)
614 elif self._copyfunc is not _noop:
624 elif self._copyfunc is not _noop:
615 cf, self._copyfunc = self._copyfunc, _noop
625 cf, self._copyfunc = self._copyfunc, _noop
616 cf(self)
626 cf(self)
617
627
618 def setflag(self, f, flags):
628 def setflag(self, f, flags):
619 """Set the flags (symlink, executable) for path f."""
629 """Set the flags (symlink, executable) for path f."""
620 assert 't' not in flags
630 assert 't' not in flags
621 self._load()
631 self._load()
622 dir, subpath = _splittopdir(f)
632 dir, subpath = _splittopdir(f)
623 if dir:
633 if dir:
624 if dir not in self._dirs:
634 if dir not in self._dirs:
625 self._dirs[dir] = treemanifest(self._subpath(dir))
635 self._dirs[dir] = treemanifest(self._subpath(dir))
626 self._dirs[dir].setflag(subpath, flags)
636 self._dirs[dir].setflag(subpath, flags)
627 else:
637 else:
628 self._flags[f] = flags
638 self._flags[f] = flags
629 self._dirty = True
639 self._dirty = True
630
640
631 def copy(self):
641 def copy(self):
632 copy = treemanifest(self._dir)
642 copy = treemanifest(self._dir)
633 copy._node = self._node
643 copy._node = self._node
634 copy._dirty = self._dirty
644 copy._dirty = self._dirty
635 if self._copyfunc is _noop:
645 if self._copyfunc is _noop:
636 def _copyfunc(s):
646 def _copyfunc(s):
637 self._load()
647 self._load()
638 for d in self._dirs:
648 for d in self._dirs:
639 s._dirs[d] = self._dirs[d].copy()
649 s._dirs[d] = self._dirs[d].copy()
640 s._files = dict.copy(self._files)
650 s._files = dict.copy(self._files)
641 s._flags = dict.copy(self._flags)
651 s._flags = dict.copy(self._flags)
642 if self._loadfunc is _noop:
652 if self._loadfunc is _noop:
643 _copyfunc(copy)
653 _copyfunc(copy)
644 else:
654 else:
645 copy._copyfunc = _copyfunc
655 copy._copyfunc = _copyfunc
646 else:
656 else:
647 copy._copyfunc = self._copyfunc
657 copy._copyfunc = self._copyfunc
648 return copy
658 return copy
649
659
650 def filesnotin(self, m2):
660 def filesnotin(self, m2):
651 '''Set of files in this manifest that are not in the other'''
661 '''Set of files in this manifest that are not in the other'''
652 files = set()
662 files = set()
653 def _filesnotin(t1, t2):
663 def _filesnotin(t1, t2):
654 if t1._node == t2._node and not t1._dirty and not t2._dirty:
664 if t1._node == t2._node and not t1._dirty and not t2._dirty:
655 return
665 return
656 t1._load()
666 t1._load()
657 t2._load()
667 t2._load()
658 for d, m1 in t1._dirs.iteritems():
668 for d, m1 in t1._dirs.iteritems():
659 if d in t2._dirs:
669 if d in t2._dirs:
660 m2 = t2._dirs[d]
670 m2 = t2._dirs[d]
661 _filesnotin(m1, m2)
671 _filesnotin(m1, m2)
662 else:
672 else:
663 files.update(m1.iterkeys())
673 files.update(m1.iterkeys())
664
674
665 for fn in t1._files.iterkeys():
675 for fn in t1._files.iterkeys():
666 if fn not in t2._files:
676 if fn not in t2._files:
667 files.add(t1._subpath(fn))
677 files.add(t1._subpath(fn))
668
678
669 _filesnotin(self, m2)
679 _filesnotin(self, m2)
670 return files
680 return files
671
681
672 @propertycache
682 @propertycache
673 def _alldirs(self):
683 def _alldirs(self):
674 return util.dirs(self)
684 return util.dirs(self)
675
685
676 def dirs(self):
686 def dirs(self):
677 return self._alldirs
687 return self._alldirs
678
688
679 def hasdir(self, dir):
689 def hasdir(self, dir):
680 self._load()
690 self._load()
681 topdir, subdir = _splittopdir(dir)
691 topdir, subdir = _splittopdir(dir)
682 if topdir:
692 if topdir:
683 if topdir in self._dirs:
693 if topdir in self._dirs:
684 return self._dirs[topdir].hasdir(subdir)
694 return self._dirs[topdir].hasdir(subdir)
685 return False
695 return False
686 return (dir + '/') in self._dirs
696 return (dir + '/') in self._dirs
687
697
688 def walk(self, match):
698 def walk(self, match):
689 '''Generates matching file names.
699 '''Generates matching file names.
690
700
691 Equivalent to manifest.matches(match).iterkeys(), but without creating
701 Equivalent to manifest.matches(match).iterkeys(), but without creating
692 an entirely new manifest.
702 an entirely new manifest.
693
703
694 It also reports nonexistent files by marking them bad with match.bad().
704 It also reports nonexistent files by marking them bad with match.bad().
695 '''
705 '''
696 if match.always():
706 if match.always():
697 for f in iter(self):
707 for f in iter(self):
698 yield f
708 yield f
699 return
709 return
700
710
701 fset = set(match.files())
711 fset = set(match.files())
702
712
703 for fn in self._walk(match):
713 for fn in self._walk(match):
704 if fn in fset:
714 if fn in fset:
705 # specified pattern is the exact name
715 # specified pattern is the exact name
706 fset.remove(fn)
716 fset.remove(fn)
707 yield fn
717 yield fn
708
718
709 # for dirstate.walk, files=['.'] means "walk the whole tree".
719 # for dirstate.walk, files=['.'] means "walk the whole tree".
710 # follow that here, too
720 # follow that here, too
711 fset.discard('.')
721 fset.discard('.')
712
722
713 for fn in sorted(fset):
723 for fn in sorted(fset):
714 if not self.hasdir(fn):
724 if not self.hasdir(fn):
715 match.bad(fn, None)
725 match.bad(fn, None)
716
726
717 def _walk(self, match):
727 def _walk(self, match):
718 '''Recursively generates matching file names for walk().'''
728 '''Recursively generates matching file names for walk().'''
719 if not match.visitdir(self._dir[:-1] or '.'):
729 if not match.visitdir(self._dir[:-1] or '.'):
720 return
730 return
721
731
722 # yield this dir's files and walk its submanifests
732 # yield this dir's files and walk its submanifests
723 self._load()
733 self._load()
724 for p in sorted(self._dirs.keys() + self._files.keys()):
734 for p in sorted(self._dirs.keys() + self._files.keys()):
725 if p in self._files:
735 if p in self._files:
726 fullp = self._subpath(p)
736 fullp = self._subpath(p)
727 if match(fullp):
737 if match(fullp):
728 yield fullp
738 yield fullp
729 else:
739 else:
730 for f in self._dirs[p]._walk(match):
740 for f in self._dirs[p]._walk(match):
731 yield f
741 yield f
732
742
733 def matches(self, match):
743 def matches(self, match):
734 '''generate a new manifest filtered by the match argument'''
744 '''generate a new manifest filtered by the match argument'''
735 if match.always():
745 if match.always():
736 return self.copy()
746 return self.copy()
737
747
738 return self._matches(match)
748 return self._matches(match)
739
749
740 def _matches(self, match):
750 def _matches(self, match):
741 '''recursively generate a new manifest filtered by the match argument.
751 '''recursively generate a new manifest filtered by the match argument.
742 '''
752 '''
743
753
744 visit = match.visitdir(self._dir[:-1] or '.')
754 visit = match.visitdir(self._dir[:-1] or '.')
745 if visit == 'all':
755 if visit == 'all':
746 return self.copy()
756 return self.copy()
747 ret = treemanifest(self._dir)
757 ret = treemanifest(self._dir)
748 if not visit:
758 if not visit:
749 return ret
759 return ret
750
760
751 self._load()
761 self._load()
752 for fn in self._files:
762 for fn in self._files:
753 fullp = self._subpath(fn)
763 fullp = self._subpath(fn)
754 if not match(fullp):
764 if not match(fullp):
755 continue
765 continue
756 ret._files[fn] = self._files[fn]
766 ret._files[fn] = self._files[fn]
757 if fn in self._flags:
767 if fn in self._flags:
758 ret._flags[fn] = self._flags[fn]
768 ret._flags[fn] = self._flags[fn]
759
769
760 for dir, subm in self._dirs.iteritems():
770 for dir, subm in self._dirs.iteritems():
761 m = subm._matches(match)
771 m = subm._matches(match)
762 if not m._isempty():
772 if not m._isempty():
763 ret._dirs[dir] = m
773 ret._dirs[dir] = m
764
774
765 if not ret._isempty():
775 if not ret._isempty():
766 ret._dirty = True
776 ret._dirty = True
767 return ret
777 return ret
768
778
769 def diff(self, m2, clean=False):
779 def diff(self, m2, clean=False):
770 '''Finds changes between the current manifest and m2.
780 '''Finds changes between the current manifest and m2.
771
781
772 Args:
782 Args:
773 m2: the manifest to which this manifest should be compared.
783 m2: the manifest to which this manifest should be compared.
774 clean: if true, include files unchanged between these manifests
784 clean: if true, include files unchanged between these manifests
775 with a None value in the returned dictionary.
785 with a None value in the returned dictionary.
776
786
777 The result is returned as a dict with filename as key and
787 The result is returned as a dict with filename as key and
778 values of the form ((n1,fl1),(n2,fl2)), where n1/n2 is the
788 values of the form ((n1,fl1),(n2,fl2)), where n1/n2 is the
779 nodeid in the current/other manifest and fl1/fl2 is the flag
789 nodeid in the current/other manifest and fl1/fl2 is the flag
780 in the current/other manifest. Where the file does not exist,
790 in the current/other manifest. Where the file does not exist,
781 the nodeid will be None and the flags will be the empty
791 the nodeid will be None and the flags will be the empty
782 string.
792 string.
783 '''
793 '''
784 result = {}
794 result = {}
785 emptytree = treemanifest()
795 emptytree = treemanifest()
786 def _diff(t1, t2):
796 def _diff(t1, t2):
787 if t1._node == t2._node and not t1._dirty and not t2._dirty:
797 if t1._node == t2._node and not t1._dirty and not t2._dirty:
788 return
798 return
789 t1._load()
799 t1._load()
790 t2._load()
800 t2._load()
791 for d, m1 in t1._dirs.iteritems():
801 for d, m1 in t1._dirs.iteritems():
792 m2 = t2._dirs.get(d, emptytree)
802 m2 = t2._dirs.get(d, emptytree)
793 _diff(m1, m2)
803 _diff(m1, m2)
794
804
795 for d, m2 in t2._dirs.iteritems():
805 for d, m2 in t2._dirs.iteritems():
796 if d not in t1._dirs:
806 if d not in t1._dirs:
797 _diff(emptytree, m2)
807 _diff(emptytree, m2)
798
808
799 for fn, n1 in t1._files.iteritems():
809 for fn, n1 in t1._files.iteritems():
800 fl1 = t1._flags.get(fn, '')
810 fl1 = t1._flags.get(fn, '')
801 n2 = t2._files.get(fn, None)
811 n2 = t2._files.get(fn, None)
802 fl2 = t2._flags.get(fn, '')
812 fl2 = t2._flags.get(fn, '')
803 if n1 != n2 or fl1 != fl2:
813 if n1 != n2 or fl1 != fl2:
804 result[t1._subpath(fn)] = ((n1, fl1), (n2, fl2))
814 result[t1._subpath(fn)] = ((n1, fl1), (n2, fl2))
805 elif clean:
815 elif clean:
806 result[t1._subpath(fn)] = None
816 result[t1._subpath(fn)] = None
807
817
808 for fn, n2 in t2._files.iteritems():
818 for fn, n2 in t2._files.iteritems():
809 if fn not in t1._files:
819 if fn not in t1._files:
810 fl2 = t2._flags.get(fn, '')
820 fl2 = t2._flags.get(fn, '')
811 result[t2._subpath(fn)] = ((None, ''), (n2, fl2))
821 result[t2._subpath(fn)] = ((None, ''), (n2, fl2))
812
822
813 _diff(self, m2)
823 _diff(self, m2)
814 return result
824 return result
815
825
816 def unmodifiedsince(self, m2):
826 def unmodifiedsince(self, m2):
817 return not self._dirty and not m2._dirty and self._node == m2._node
827 return not self._dirty and not m2._dirty and self._node == m2._node
818
828
819 def parse(self, text, readsubtree):
829 def parse(self, text, readsubtree):
820 for f, n, fl in _parse(text):
830 for f, n, fl in _parse(text):
821 if fl == 't':
831 if fl == 't':
822 f = f + '/'
832 f = f + '/'
823 self._dirs[f] = readsubtree(self._subpath(f), n)
833 self._dirs[f] = readsubtree(self._subpath(f), n)
824 elif '/' in f:
834 elif '/' in f:
825 # This is a flat manifest, so use __setitem__ and setflag rather
835 # This is a flat manifest, so use __setitem__ and setflag rather
826 # than assigning directly to _files and _flags, so we can
836 # than assigning directly to _files and _flags, so we can
827 # assign a path in a subdirectory, and to mark dirty (compared
837 # assign a path in a subdirectory, and to mark dirty (compared
828 # to nullid).
838 # to nullid).
829 self[f] = n
839 self[f] = n
830 if fl:
840 if fl:
831 self.setflag(f, fl)
841 self.setflag(f, fl)
832 else:
842 else:
833 # Assigning to _files and _flags avoids marking as dirty,
843 # Assigning to _files and _flags avoids marking as dirty,
834 # and should be a little faster.
844 # and should be a little faster.
835 self._files[f] = n
845 self._files[f] = n
836 if fl:
846 if fl:
837 self._flags[f] = fl
847 self._flags[f] = fl
838
848
839 def text(self, usemanifestv2=False):
849 def text(self, usemanifestv2=False):
840 """Get the full data of this manifest as a bytestring."""
850 """Get the full data of this manifest as a bytestring."""
841 self._load()
851 self._load()
842 flags = self.flags
852 flags = self.flags
843 return _text(((f, self[f], flags(f)) for f in self.keys()),
853 return _text(((f, self[f], flags(f)) for f in self.keys()),
844 usemanifestv2)
854 usemanifestv2)
845
855
846 def dirtext(self, usemanifestv2=False):
856 def dirtext(self, usemanifestv2=False):
847 """Get the full data of this directory as a bytestring. Make sure that
857 """Get the full data of this directory as a bytestring. Make sure that
848 any submanifests have been written first, so their nodeids are correct.
858 any submanifests have been written first, so their nodeids are correct.
849 """
859 """
850 self._load()
860 self._load()
851 flags = self.flags
861 flags = self.flags
852 dirs = [(d[:-1], self._dirs[d]._node, 't') for d in self._dirs]
862 dirs = [(d[:-1], self._dirs[d]._node, 't') for d in self._dirs]
853 files = [(f, self._files[f], flags(f)) for f in self._files]
863 files = [(f, self._files[f], flags(f)) for f in self._files]
854 return _text(sorted(dirs + files), usemanifestv2)
864 return _text(sorted(dirs + files), usemanifestv2)
855
865
856 def read(self, gettext, readsubtree):
866 def read(self, gettext, readsubtree):
857 def _load_for_read(s):
867 def _load_for_read(s):
858 s.parse(gettext(), readsubtree)
868 s.parse(gettext(), readsubtree)
859 s._dirty = False
869 s._dirty = False
860 self._loadfunc = _load_for_read
870 self._loadfunc = _load_for_read
861
871
862 def writesubtrees(self, m1, m2, writesubtree):
872 def writesubtrees(self, m1, m2, writesubtree):
863 self._load() # for consistency; should never have any effect here
873 self._load() # for consistency; should never have any effect here
864 emptytree = treemanifest()
874 emptytree = treemanifest()
865 for d, subm in self._dirs.iteritems():
875 for d, subm in self._dirs.iteritems():
866 subp1 = m1._dirs.get(d, emptytree)._node
876 subp1 = m1._dirs.get(d, emptytree)._node
867 subp2 = m2._dirs.get(d, emptytree)._node
877 subp2 = m2._dirs.get(d, emptytree)._node
868 if subp1 == revlog.nullid:
878 if subp1 == revlog.nullid:
869 subp1, subp2 = subp2, subp1
879 subp1, subp2 = subp2, subp1
870 writesubtree(subm, subp1, subp2)
880 writesubtree(subm, subp1, subp2)
871
881
872 class manifest(revlog.revlog):
882 class manifest(revlog.revlog):
873 def __init__(self, opener, dir='', dirlogcache=None):
883 def __init__(self, opener, dir='', dirlogcache=None):
874 '''The 'dir' and 'dirlogcache' arguments are for internal use by
884 '''The 'dir' and 'dirlogcache' arguments are for internal use by
875 manifest.manifest only. External users should create a root manifest
885 manifest.manifest only. External users should create a root manifest
876 log with manifest.manifest(opener) and call dirlog() on it.
886 log with manifest.manifest(opener) and call dirlog() on it.
877 '''
887 '''
878 # During normal operations, we expect to deal with not more than four
888 # During normal operations, we expect to deal with not more than four
879 # revs at a time (such as during commit --amend). When rebasing large
889 # revs at a time (such as during commit --amend). When rebasing large
880 # stacks of commits, the number can go up, hence the config knob below.
890 # stacks of commits, the number can go up, hence the config knob below.
881 cachesize = 4
891 cachesize = 4
882 usetreemanifest = False
892 usetreemanifest = False
883 usemanifestv2 = False
893 usemanifestv2 = False
884 opts = getattr(opener, 'options', None)
894 opts = getattr(opener, 'options', None)
885 if opts is not None:
895 if opts is not None:
886 cachesize = opts.get('manifestcachesize', cachesize)
896 cachesize = opts.get('manifestcachesize', cachesize)
887 usetreemanifest = opts.get('treemanifest', usetreemanifest)
897 usetreemanifest = opts.get('treemanifest', usetreemanifest)
888 usemanifestv2 = opts.get('manifestv2', usemanifestv2)
898 usemanifestv2 = opts.get('manifestv2', usemanifestv2)
889 self._mancache = util.lrucachedict(cachesize)
899 self._mancache = util.lrucachedict(cachesize)
890 self._treeinmem = usetreemanifest
900 self._treeinmem = usetreemanifest
891 self._treeondisk = usetreemanifest
901 self._treeondisk = usetreemanifest
892 self._usemanifestv2 = usemanifestv2
902 self._usemanifestv2 = usemanifestv2
893 indexfile = "00manifest.i"
903 indexfile = "00manifest.i"
894 if dir:
904 if dir:
895 assert self._treeondisk
905 assert self._treeondisk
896 if not dir.endswith('/'):
906 if not dir.endswith('/'):
897 dir = dir + '/'
907 dir = dir + '/'
898 indexfile = "meta/" + dir + "00manifest.i"
908 indexfile = "meta/" + dir + "00manifest.i"
899 revlog.revlog.__init__(self, opener, indexfile)
909 revlog.revlog.__init__(self, opener, indexfile)
900 self._dir = dir
910 self._dir = dir
901 # The dirlogcache is kept on the root manifest log
911 # The dirlogcache is kept on the root manifest log
902 if dir:
912 if dir:
903 self._dirlogcache = dirlogcache
913 self._dirlogcache = dirlogcache
904 else:
914 else:
905 self._dirlogcache = {'': self}
915 self._dirlogcache = {'': self}
906
916
907 def _newmanifest(self, data=''):
917 def _newmanifest(self, data=''):
908 if self._treeinmem:
918 if self._treeinmem:
909 return treemanifest(self._dir, data)
919 return treemanifest(self._dir, data)
910 return manifestdict(data)
920 return manifestdict(data)
911
921
912 def dirlog(self, dir):
922 def dirlog(self, dir):
913 assert self._treeondisk
923 assert self._treeondisk
914 if dir not in self._dirlogcache:
924 if dir not in self._dirlogcache:
915 self._dirlogcache[dir] = manifest(self.opener, dir,
925 self._dirlogcache[dir] = manifest(self.opener, dir,
916 self._dirlogcache)
926 self._dirlogcache)
917 return self._dirlogcache[dir]
927 return self._dirlogcache[dir]
918
928
919 def _slowreaddelta(self, node):
929 def _slowreaddelta(self, node):
920 r0 = self.deltaparent(self.rev(node))
930 r0 = self.deltaparent(self.rev(node))
921 m0 = self.read(self.node(r0))
931 m0 = self.read(self.node(r0))
922 m1 = self.read(node)
932 m1 = self.read(node)
923 md = self._newmanifest()
933 md = self._newmanifest()
924 for f, ((n0, fl0), (n1, fl1)) in m0.diff(m1).iteritems():
934 for f, ((n0, fl0), (n1, fl1)) in m0.diff(m1).iteritems():
925 if n1:
935 if n1:
926 md[f] = n1
936 md[f] = n1
927 if fl1:
937 if fl1:
928 md.setflag(f, fl1)
938 md.setflag(f, fl1)
929 return md
939 return md
930
940
931 def readdelta(self, node):
941 def readdelta(self, node):
932 if self._usemanifestv2 or self._treeondisk:
942 if self._usemanifestv2 or self._treeondisk:
933 return self._slowreaddelta(node)
943 return self._slowreaddelta(node)
934 r = self.rev(node)
944 r = self.rev(node)
935 d = mdiff.patchtext(self.revdiff(self.deltaparent(r), r))
945 d = mdiff.patchtext(self.revdiff(self.deltaparent(r), r))
936 return self._newmanifest(d)
946 return self._newmanifest(d)
937
947
938 def readfast(self, node):
948 def readfast(self, node):
939 '''use the faster of readdelta or read
949 '''use the faster of readdelta or read
940
950
941 This will return a manifest which is either only the files
951 This will return a manifest which is either only the files
942 added/modified relative to p1, or all files in the
952 added/modified relative to p1, or all files in the
943 manifest. Which one is returned depends on the codepath used
953 manifest. Which one is returned depends on the codepath used
944 to retrieve the data.
954 to retrieve the data.
945 '''
955 '''
946 r = self.rev(node)
956 r = self.rev(node)
947 deltaparent = self.deltaparent(r)
957 deltaparent = self.deltaparent(r)
948 if deltaparent != revlog.nullrev and deltaparent in self.parentrevs(r):
958 if deltaparent != revlog.nullrev and deltaparent in self.parentrevs(r):
949 return self.readdelta(node)
959 return self.readdelta(node)
950 return self.read(node)
960 return self.read(node)
951
961
952 def read(self, node):
962 def read(self, node):
953 if node == revlog.nullid:
963 if node == revlog.nullid:
954 return self._newmanifest() # don't upset local cache
964 return self._newmanifest() # don't upset local cache
955 if node in self._mancache:
965 if node in self._mancache:
956 return self._mancache[node][0]
966 return self._mancache[node][0]
957 if self._treeondisk:
967 if self._treeondisk:
958 def gettext():
968 def gettext():
959 return self.revision(node)
969 return self.revision(node)
960 def readsubtree(dir, subm):
970 def readsubtree(dir, subm):
961 return self.dirlog(dir).read(subm)
971 return self.dirlog(dir).read(subm)
962 m = self._newmanifest()
972 m = self._newmanifest()
963 m.read(gettext, readsubtree)
973 m.read(gettext, readsubtree)
964 m.setnode(node)
974 m.setnode(node)
965 arraytext = None
975 arraytext = None
966 else:
976 else:
967 text = self.revision(node)
977 text = self.revision(node)
968 m = self._newmanifest(text)
978 m = self._newmanifest(text)
969 arraytext = array.array('c', text)
979 arraytext = array.array('c', text)
970 self._mancache[node] = (m, arraytext)
980 self._mancache[node] = (m, arraytext)
971 return m
981 return m
972
982
973 def find(self, node, f):
983 def find(self, node, f):
974 '''look up entry for a single file efficiently.
984 '''look up entry for a single file efficiently.
975 return (node, flags) pair if found, (None, None) if not.'''
985 return (node, flags) pair if found, (None, None) if not.'''
976 m = self.read(node)
986 m = self.read(node)
977 try:
987 try:
978 return m.find(f)
988 return m.find(f)
979 except KeyError:
989 except KeyError:
980 return None, None
990 return None, None
981
991
982 def add(self, m, transaction, link, p1, p2, added, removed):
992 def add(self, m, transaction, link, p1, p2, added, removed):
983 if (p1 in self._mancache and not self._treeinmem
993 if (p1 in self._mancache and not self._treeinmem
984 and not self._usemanifestv2):
994 and not self._usemanifestv2):
985 # If our first parent is in the manifest cache, we can
995 # If our first parent is in the manifest cache, we can
986 # compute a delta here using properties we know about the
996 # compute a delta here using properties we know about the
987 # manifest up-front, which may save time later for the
997 # manifest up-front, which may save time later for the
988 # revlog layer.
998 # revlog layer.
989
999
990 _checkforbidden(added)
1000 _checkforbidden(added)
991 # combine the changed lists into one sorted iterator
1001 # combine the changed lists into one sorted iterator
992 work = heapq.merge([(x, False) for x in added],
1002 work = heapq.merge([(x, False) for x in added],
993 [(x, True) for x in removed])
1003 [(x, True) for x in removed])
994
1004
995 arraytext, deltatext = m.fastdelta(self._mancache[p1][1], work)
1005 arraytext, deltatext = m.fastdelta(self._mancache[p1][1], work)
996 cachedelta = self.rev(p1), deltatext
1006 cachedelta = self.rev(p1), deltatext
997 text = util.buffer(arraytext)
1007 text = util.buffer(arraytext)
998 n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
1008 n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
999 else:
1009 else:
1000 # The first parent manifest isn't already loaded, so we'll
1010 # The first parent manifest isn't already loaded, so we'll
1001 # just encode a fulltext of the manifest and pass that
1011 # just encode a fulltext of the manifest and pass that
1002 # through to the revlog layer, and let it handle the delta
1012 # through to the revlog layer, and let it handle the delta
1003 # process.
1013 # process.
1004 if self._treeondisk:
1014 if self._treeondisk:
1005 m1 = self.read(p1)
1015 m1 = self.read(p1)
1006 m2 = self.read(p2)
1016 m2 = self.read(p2)
1007 n = self._addtree(m, transaction, link, m1, m2)
1017 n = self._addtree(m, transaction, link, m1, m2)
1008 arraytext = None
1018 arraytext = None
1009 else:
1019 else:
1010 text = m.text(self._usemanifestv2)
1020 text = m.text(self._usemanifestv2)
1011 n = self.addrevision(text, transaction, link, p1, p2)
1021 n = self.addrevision(text, transaction, link, p1, p2)
1012 arraytext = array.array('c', text)
1022 arraytext = array.array('c', text)
1013
1023
1014 self._mancache[n] = (m, arraytext)
1024 self._mancache[n] = (m, arraytext)
1015
1025
1016 return n
1026 return n
1017
1027
1018 def _addtree(self, m, transaction, link, m1, m2):
1028 def _addtree(self, m, transaction, link, m1, m2):
1019 # If the manifest is unchanged compared to one parent,
1029 # If the manifest is unchanged compared to one parent,
1020 # don't write a new revision
1030 # don't write a new revision
1021 if m.unmodifiedsince(m1) or m.unmodifiedsince(m2):
1031 if m.unmodifiedsince(m1) or m.unmodifiedsince(m2):
1022 return m.node()
1032 return m.node()
1023 def writesubtree(subm, subp1, subp2):
1033 def writesubtree(subm, subp1, subp2):
1024 sublog = self.dirlog(subm.dir())
1034 sublog = self.dirlog(subm.dir())
1025 sublog.add(subm, transaction, link, subp1, subp2, None, None)
1035 sublog.add(subm, transaction, link, subp1, subp2, None, None)
1026 m.writesubtrees(m1, m2, writesubtree)
1036 m.writesubtrees(m1, m2, writesubtree)
1027 text = m.dirtext(self._usemanifestv2)
1037 text = m.dirtext(self._usemanifestv2)
1028 # Double-check whether contents are unchanged to one parent
1038 # Double-check whether contents are unchanged to one parent
1029 if text == m1.dirtext(self._usemanifestv2):
1039 if text == m1.dirtext(self._usemanifestv2):
1030 n = m1.node()
1040 n = m1.node()
1031 elif text == m2.dirtext(self._usemanifestv2):
1041 elif text == m2.dirtext(self._usemanifestv2):
1032 n = m2.node()
1042 n = m2.node()
1033 else:
1043 else:
1034 n = self.addrevision(text, transaction, link, m1.node(), m2.node())
1044 n = self.addrevision(text, transaction, link, m1.node(), m2.node())
1035 # Save nodeid so parent manifest can calculate its nodeid
1045 # Save nodeid so parent manifest can calculate its nodeid
1036 m.setnode(n)
1046 m.setnode(n)
1037 return n
1047 return n
1038
1048
1039 def clearcaches(self):
1049 def clearcaches(self):
1040 super(manifest, self).clearcaches()
1050 super(manifest, self).clearcaches()
1041 self._mancache.clear()
1051 self._mancache.clear()
1042 self._dirlogcache = {'': self}
1052 self._dirlogcache = {'': self}
@@ -1,198 +1,197 b''
1 #require test-repo
1 #require test-repo
2
2
3 $ cd "$TESTDIR"/..
3 $ cd "$TESTDIR"/..
4
4
5 $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs python contrib/check-py3-compat.py
5 $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs python contrib/check-py3-compat.py
6 contrib/casesmash.py not using absolute_import
6 contrib/casesmash.py not using absolute_import
7 contrib/check-code.py not using absolute_import
7 contrib/check-code.py not using absolute_import
8 contrib/check-code.py requires print_function
8 contrib/check-code.py requires print_function
9 contrib/check-config.py not using absolute_import
9 contrib/check-config.py not using absolute_import
10 contrib/check-config.py requires print_function
10 contrib/check-config.py requires print_function
11 contrib/debugcmdserver.py not using absolute_import
11 contrib/debugcmdserver.py not using absolute_import
12 contrib/debugcmdserver.py requires print_function
12 contrib/debugcmdserver.py requires print_function
13 contrib/debugshell.py not using absolute_import
13 contrib/debugshell.py not using absolute_import
14 contrib/fixpax.py not using absolute_import
14 contrib/fixpax.py not using absolute_import
15 contrib/fixpax.py requires print_function
15 contrib/fixpax.py requires print_function
16 contrib/hgclient.py not using absolute_import
16 contrib/hgclient.py not using absolute_import
17 contrib/hgclient.py requires print_function
17 contrib/hgclient.py requires print_function
18 contrib/hgfixes/fix_bytes.py not using absolute_import
18 contrib/hgfixes/fix_bytes.py not using absolute_import
19 contrib/hgfixes/fix_bytesmod.py not using absolute_import
19 contrib/hgfixes/fix_bytesmod.py not using absolute_import
20 contrib/hgfixes/fix_leftover_imports.py not using absolute_import
20 contrib/hgfixes/fix_leftover_imports.py not using absolute_import
21 contrib/import-checker.py not using absolute_import
21 contrib/import-checker.py not using absolute_import
22 contrib/import-checker.py requires print_function
22 contrib/import-checker.py requires print_function
23 contrib/memory.py not using absolute_import
23 contrib/memory.py not using absolute_import
24 contrib/perf.py not using absolute_import
24 contrib/perf.py not using absolute_import
25 contrib/python-hook-examples.py not using absolute_import
25 contrib/python-hook-examples.py not using absolute_import
26 contrib/revsetbenchmarks.py not using absolute_import
26 contrib/revsetbenchmarks.py not using absolute_import
27 contrib/revsetbenchmarks.py requires print_function
27 contrib/revsetbenchmarks.py requires print_function
28 contrib/showstack.py not using absolute_import
28 contrib/showstack.py not using absolute_import
29 contrib/synthrepo.py not using absolute_import
29 contrib/synthrepo.py not using absolute_import
30 contrib/win32/hgwebdir_wsgi.py not using absolute_import
30 contrib/win32/hgwebdir_wsgi.py not using absolute_import
31 doc/check-seclevel.py not using absolute_import
31 doc/check-seclevel.py not using absolute_import
32 doc/gendoc.py not using absolute_import
32 doc/gendoc.py not using absolute_import
33 doc/hgmanpage.py not using absolute_import
33 doc/hgmanpage.py not using absolute_import
34 hgext/__init__.py not using absolute_import
34 hgext/__init__.py not using absolute_import
35 hgext/acl.py not using absolute_import
35 hgext/acl.py not using absolute_import
36 hgext/blackbox.py not using absolute_import
36 hgext/blackbox.py not using absolute_import
37 hgext/bugzilla.py not using absolute_import
37 hgext/bugzilla.py not using absolute_import
38 hgext/censor.py not using absolute_import
38 hgext/censor.py not using absolute_import
39 hgext/children.py not using absolute_import
39 hgext/children.py not using absolute_import
40 hgext/churn.py not using absolute_import
40 hgext/churn.py not using absolute_import
41 hgext/clonebundles.py not using absolute_import
41 hgext/clonebundles.py not using absolute_import
42 hgext/color.py not using absolute_import
42 hgext/color.py not using absolute_import
43 hgext/convert/__init__.py not using absolute_import
43 hgext/convert/__init__.py not using absolute_import
44 hgext/convert/bzr.py not using absolute_import
44 hgext/convert/bzr.py not using absolute_import
45 hgext/convert/common.py not using absolute_import
45 hgext/convert/common.py not using absolute_import
46 hgext/convert/convcmd.py not using absolute_import
46 hgext/convert/convcmd.py not using absolute_import
47 hgext/convert/cvs.py not using absolute_import
47 hgext/convert/cvs.py not using absolute_import
48 hgext/convert/cvsps.py not using absolute_import
48 hgext/convert/cvsps.py not using absolute_import
49 hgext/convert/darcs.py not using absolute_import
49 hgext/convert/darcs.py not using absolute_import
50 hgext/convert/filemap.py not using absolute_import
50 hgext/convert/filemap.py not using absolute_import
51 hgext/convert/git.py not using absolute_import
51 hgext/convert/git.py not using absolute_import
52 hgext/convert/gnuarch.py not using absolute_import
52 hgext/convert/gnuarch.py not using absolute_import
53 hgext/convert/hg.py not using absolute_import
53 hgext/convert/hg.py not using absolute_import
54 hgext/convert/monotone.py not using absolute_import
54 hgext/convert/monotone.py not using absolute_import
55 hgext/convert/p4.py not using absolute_import
55 hgext/convert/p4.py not using absolute_import
56 hgext/convert/subversion.py not using absolute_import
56 hgext/convert/subversion.py not using absolute_import
57 hgext/convert/transport.py not using absolute_import
57 hgext/convert/transport.py not using absolute_import
58 hgext/eol.py not using absolute_import
58 hgext/eol.py not using absolute_import
59 hgext/extdiff.py not using absolute_import
59 hgext/extdiff.py not using absolute_import
60 hgext/factotum.py not using absolute_import
60 hgext/factotum.py not using absolute_import
61 hgext/fetch.py not using absolute_import
61 hgext/fetch.py not using absolute_import
62 hgext/gpg.py not using absolute_import
62 hgext/gpg.py not using absolute_import
63 hgext/graphlog.py not using absolute_import
63 hgext/graphlog.py not using absolute_import
64 hgext/hgcia.py not using absolute_import
64 hgext/hgcia.py not using absolute_import
65 hgext/hgk.py not using absolute_import
65 hgext/hgk.py not using absolute_import
66 hgext/highlight/__init__.py not using absolute_import
66 hgext/highlight/__init__.py not using absolute_import
67 hgext/highlight/highlight.py not using absolute_import
67 hgext/highlight/highlight.py not using absolute_import
68 hgext/histedit.py not using absolute_import
68 hgext/histedit.py not using absolute_import
69 hgext/keyword.py not using absolute_import
69 hgext/keyword.py not using absolute_import
70 hgext/largefiles/__init__.py not using absolute_import
70 hgext/largefiles/__init__.py not using absolute_import
71 hgext/largefiles/basestore.py not using absolute_import
71 hgext/largefiles/basestore.py not using absolute_import
72 hgext/largefiles/lfcommands.py not using absolute_import
72 hgext/largefiles/lfcommands.py not using absolute_import
73 hgext/largefiles/lfutil.py not using absolute_import
73 hgext/largefiles/lfutil.py not using absolute_import
74 hgext/largefiles/localstore.py not using absolute_import
74 hgext/largefiles/localstore.py not using absolute_import
75 hgext/largefiles/overrides.py not using absolute_import
75 hgext/largefiles/overrides.py not using absolute_import
76 hgext/largefiles/proto.py not using absolute_import
76 hgext/largefiles/proto.py not using absolute_import
77 hgext/largefiles/remotestore.py not using absolute_import
77 hgext/largefiles/remotestore.py not using absolute_import
78 hgext/largefiles/reposetup.py not using absolute_import
78 hgext/largefiles/reposetup.py not using absolute_import
79 hgext/largefiles/uisetup.py not using absolute_import
79 hgext/largefiles/uisetup.py not using absolute_import
80 hgext/largefiles/wirestore.py not using absolute_import
80 hgext/largefiles/wirestore.py not using absolute_import
81 hgext/mq.py not using absolute_import
81 hgext/mq.py not using absolute_import
82 hgext/notify.py not using absolute_import
82 hgext/notify.py not using absolute_import
83 hgext/pager.py not using absolute_import
83 hgext/pager.py not using absolute_import
84 hgext/patchbomb.py not using absolute_import
84 hgext/patchbomb.py not using absolute_import
85 hgext/purge.py not using absolute_import
85 hgext/purge.py not using absolute_import
86 hgext/rebase.py not using absolute_import
86 hgext/rebase.py not using absolute_import
87 hgext/record.py not using absolute_import
87 hgext/record.py not using absolute_import
88 hgext/relink.py not using absolute_import
88 hgext/relink.py not using absolute_import
89 hgext/schemes.py not using absolute_import
89 hgext/schemes.py not using absolute_import
90 hgext/share.py not using absolute_import
90 hgext/share.py not using absolute_import
91 hgext/shelve.py not using absolute_import
91 hgext/shelve.py not using absolute_import
92 hgext/strip.py not using absolute_import
92 hgext/strip.py not using absolute_import
93 hgext/transplant.py not using absolute_import
93 hgext/transplant.py not using absolute_import
94 hgext/win32mbcs.py not using absolute_import
94 hgext/win32mbcs.py not using absolute_import
95 hgext/win32text.py not using absolute_import
95 hgext/win32text.py not using absolute_import
96 hgext/zeroconf/Zeroconf.py not using absolute_import
96 hgext/zeroconf/Zeroconf.py not using absolute_import
97 hgext/zeroconf/Zeroconf.py requires print_function
97 hgext/zeroconf/Zeroconf.py requires print_function
98 hgext/zeroconf/__init__.py not using absolute_import
98 hgext/zeroconf/__init__.py not using absolute_import
99 i18n/check-translation.py not using absolute_import
99 i18n/check-translation.py not using absolute_import
100 i18n/polib.py not using absolute_import
100 i18n/polib.py not using absolute_import
101 mercurial/byterange.py not using absolute_import
101 mercurial/byterange.py not using absolute_import
102 mercurial/cmdutil.py not using absolute_import
102 mercurial/cmdutil.py not using absolute_import
103 mercurial/commands.py not using absolute_import
103 mercurial/commands.py not using absolute_import
104 mercurial/context.py not using absolute_import
104 mercurial/context.py not using absolute_import
105 mercurial/dirstate.py not using absolute_import
105 mercurial/dirstate.py not using absolute_import
106 mercurial/dispatch.py requires print_function
106 mercurial/dispatch.py requires print_function
107 mercurial/exchange.py not using absolute_import
107 mercurial/exchange.py not using absolute_import
108 mercurial/httpclient/__init__.py not using absolute_import
108 mercurial/httpclient/__init__.py not using absolute_import
109 mercurial/httpclient/_readers.py not using absolute_import
109 mercurial/httpclient/_readers.py not using absolute_import
110 mercurial/httpclient/socketutil.py not using absolute_import
110 mercurial/httpclient/socketutil.py not using absolute_import
111 mercurial/httpconnection.py not using absolute_import
111 mercurial/httpconnection.py not using absolute_import
112 mercurial/keepalive.py not using absolute_import
112 mercurial/keepalive.py not using absolute_import
113 mercurial/keepalive.py requires print_function
113 mercurial/keepalive.py requires print_function
114 mercurial/localrepo.py not using absolute_import
114 mercurial/localrepo.py not using absolute_import
115 mercurial/lsprof.py requires print_function
115 mercurial/lsprof.py requires print_function
116 mercurial/lsprofcalltree.py not using absolute_import
116 mercurial/lsprofcalltree.py not using absolute_import
117 mercurial/lsprofcalltree.py requires print_function
117 mercurial/lsprofcalltree.py requires print_function
118 mercurial/mail.py requires print_function
118 mercurial/mail.py requires print_function
119 mercurial/manifest.py not using absolute_import
120 setup.py not using absolute_import
119 setup.py not using absolute_import
121 tests/filterpyflakes.py requires print_function
120 tests/filterpyflakes.py requires print_function
122 tests/generate-working-copy-states.py requires print_function
121 tests/generate-working-copy-states.py requires print_function
123 tests/get-with-headers.py requires print_function
122 tests/get-with-headers.py requires print_function
124 tests/heredoctest.py requires print_function
123 tests/heredoctest.py requires print_function
125 tests/hypothesishelpers.py not using absolute_import
124 tests/hypothesishelpers.py not using absolute_import
126 tests/hypothesishelpers.py requires print_function
125 tests/hypothesishelpers.py requires print_function
127 tests/killdaemons.py not using absolute_import
126 tests/killdaemons.py not using absolute_import
128 tests/md5sum.py not using absolute_import
127 tests/md5sum.py not using absolute_import
129 tests/mockblackbox.py not using absolute_import
128 tests/mockblackbox.py not using absolute_import
130 tests/printenv.py not using absolute_import
129 tests/printenv.py not using absolute_import
131 tests/readlink.py not using absolute_import
130 tests/readlink.py not using absolute_import
132 tests/readlink.py requires print_function
131 tests/readlink.py requires print_function
133 tests/revlog-formatv0.py not using absolute_import
132 tests/revlog-formatv0.py not using absolute_import
134 tests/run-tests.py not using absolute_import
133 tests/run-tests.py not using absolute_import
135 tests/seq.py not using absolute_import
134 tests/seq.py not using absolute_import
136 tests/seq.py requires print_function
135 tests/seq.py requires print_function
137 tests/silenttestrunner.py not using absolute_import
136 tests/silenttestrunner.py not using absolute_import
138 tests/silenttestrunner.py requires print_function
137 tests/silenttestrunner.py requires print_function
139 tests/sitecustomize.py not using absolute_import
138 tests/sitecustomize.py not using absolute_import
140 tests/svn-safe-append.py not using absolute_import
139 tests/svn-safe-append.py not using absolute_import
141 tests/svnxml.py not using absolute_import
140 tests/svnxml.py not using absolute_import
142 tests/test-ancestor.py requires print_function
141 tests/test-ancestor.py requires print_function
143 tests/test-atomictempfile.py not using absolute_import
142 tests/test-atomictempfile.py not using absolute_import
144 tests/test-batching.py not using absolute_import
143 tests/test-batching.py not using absolute_import
145 tests/test-batching.py requires print_function
144 tests/test-batching.py requires print_function
146 tests/test-bdiff.py not using absolute_import
145 tests/test-bdiff.py not using absolute_import
147 tests/test-bdiff.py requires print_function
146 tests/test-bdiff.py requires print_function
148 tests/test-context.py not using absolute_import
147 tests/test-context.py not using absolute_import
149 tests/test-context.py requires print_function
148 tests/test-context.py requires print_function
150 tests/test-demandimport.py not using absolute_import
149 tests/test-demandimport.py not using absolute_import
151 tests/test-demandimport.py requires print_function
150 tests/test-demandimport.py requires print_function
152 tests/test-dispatch.py not using absolute_import
151 tests/test-dispatch.py not using absolute_import
153 tests/test-dispatch.py requires print_function
152 tests/test-dispatch.py requires print_function
154 tests/test-doctest.py not using absolute_import
153 tests/test-doctest.py not using absolute_import
155 tests/test-duplicateoptions.py not using absolute_import
154 tests/test-duplicateoptions.py not using absolute_import
156 tests/test-duplicateoptions.py requires print_function
155 tests/test-duplicateoptions.py requires print_function
157 tests/test-filecache.py not using absolute_import
156 tests/test-filecache.py not using absolute_import
158 tests/test-filecache.py requires print_function
157 tests/test-filecache.py requires print_function
159 tests/test-filelog.py not using absolute_import
158 tests/test-filelog.py not using absolute_import
160 tests/test-filelog.py requires print_function
159 tests/test-filelog.py requires print_function
161 tests/test-hg-parseurl.py not using absolute_import
160 tests/test-hg-parseurl.py not using absolute_import
162 tests/test-hg-parseurl.py requires print_function
161 tests/test-hg-parseurl.py requires print_function
163 tests/test-hgweb-auth.py not using absolute_import
162 tests/test-hgweb-auth.py not using absolute_import
164 tests/test-hgweb-auth.py requires print_function
163 tests/test-hgweb-auth.py requires print_function
165 tests/test-hgwebdir-paths.py not using absolute_import
164 tests/test-hgwebdir-paths.py not using absolute_import
166 tests/test-hybridencode.py not using absolute_import
165 tests/test-hybridencode.py not using absolute_import
167 tests/test-hybridencode.py requires print_function
166 tests/test-hybridencode.py requires print_function
168 tests/test-lrucachedict.py not using absolute_import
167 tests/test-lrucachedict.py not using absolute_import
169 tests/test-lrucachedict.py requires print_function
168 tests/test-lrucachedict.py requires print_function
170 tests/test-manifest.py not using absolute_import
169 tests/test-manifest.py not using absolute_import
171 tests/test-minirst.py not using absolute_import
170 tests/test-minirst.py not using absolute_import
172 tests/test-minirst.py requires print_function
171 tests/test-minirst.py requires print_function
173 tests/test-parseindex2.py not using absolute_import
172 tests/test-parseindex2.py not using absolute_import
174 tests/test-parseindex2.py requires print_function
173 tests/test-parseindex2.py requires print_function
175 tests/test-pathencode.py not using absolute_import
174 tests/test-pathencode.py not using absolute_import
176 tests/test-pathencode.py requires print_function
175 tests/test-pathencode.py requires print_function
177 tests/test-propertycache.py not using absolute_import
176 tests/test-propertycache.py not using absolute_import
178 tests/test-propertycache.py requires print_function
177 tests/test-propertycache.py requires print_function
179 tests/test-revlog-ancestry.py not using absolute_import
178 tests/test-revlog-ancestry.py not using absolute_import
180 tests/test-revlog-ancestry.py requires print_function
179 tests/test-revlog-ancestry.py requires print_function
181 tests/test-run-tests.py not using absolute_import
180 tests/test-run-tests.py not using absolute_import
182 tests/test-simplemerge.py not using absolute_import
181 tests/test-simplemerge.py not using absolute_import
183 tests/test-status-inprocess.py not using absolute_import
182 tests/test-status-inprocess.py not using absolute_import
184 tests/test-status-inprocess.py requires print_function
183 tests/test-status-inprocess.py requires print_function
185 tests/test-symlink-os-yes-fs-no.py not using absolute_import
184 tests/test-symlink-os-yes-fs-no.py not using absolute_import
186 tests/test-trusted.py not using absolute_import
185 tests/test-trusted.py not using absolute_import
187 tests/test-trusted.py requires print_function
186 tests/test-trusted.py requires print_function
188 tests/test-ui-color.py not using absolute_import
187 tests/test-ui-color.py not using absolute_import
189 tests/test-ui-color.py requires print_function
188 tests/test-ui-color.py requires print_function
190 tests/test-ui-config.py not using absolute_import
189 tests/test-ui-config.py not using absolute_import
191 tests/test-ui-config.py requires print_function
190 tests/test-ui-config.py requires print_function
192 tests/test-ui-verbosity.py not using absolute_import
191 tests/test-ui-verbosity.py not using absolute_import
193 tests/test-ui-verbosity.py requires print_function
192 tests/test-ui-verbosity.py requires print_function
194 tests/test-url.py not using absolute_import
193 tests/test-url.py not using absolute_import
195 tests/test-url.py requires print_function
194 tests/test-url.py requires print_function
196 tests/test-walkrepo.py requires print_function
195 tests/test-walkrepo.py requires print_function
197 tests/test-wireproto.py requires print_function
196 tests/test-wireproto.py requires print_function
198 tests/tinyproxy.py requires print_function
197 tests/tinyproxy.py requires print_function
General Comments 0
You need to be logged in to leave comments. Login now