##// END OF EJS Templates
manifestv2: add support for reading new manifest format...
Martin von Zweigbergk -
r24572:b83679eb default
parent child Browse files
Show More
@@ -11,8 +11,7 b' import array, struct'
11
11
12 propertycache = util.propertycache
12 propertycache = util.propertycache
13
13
14 def _parse(data):
14 def _parsev1(data):
15 """Generates (path, node, flags) tuples from a manifest text"""
16 # This method does a little bit of excessive-looking
15 # This method does a little bit of excessive-looking
17 # precondition checking. This is so that the behavior of this
16 # precondition checking. This is so that the behavior of this
18 # class exactly matches its C counterpart to try and help
17 # class exactly matches its C counterpart to try and help
@@ -31,6 +30,34 b' def _parse(data):'
31 else:
30 else:
32 yield f, revlog.bin(n), ''
31 yield f, revlog.bin(n), ''
33
32
33 def _parsev2(data):
34 metadataend = data.find('\n')
35 # Just ignore metadata for now
36 pos = metadataend + 1
37 prevf = ''
38 while pos < len(data):
39 end = data.find('\n', pos + 1) # +1 to skip stem length byte
40 if end == -1:
41 raise ValueError('Manifest ended with incomplete file entry.')
42 stemlen = ord(data[pos])
43 items = data[pos + 1:end].split('\0')
44 f = prevf[:stemlen] + items[0]
45 if prevf > f:
46 raise ValueError('Manifest entries not in sorted order.')
47 fl = items[1]
48 # Just ignore metadata (items[2:] for now)
49 n = data[end + 1:end + 21]
50 yield f, n, fl
51 pos = end + 22
52 prevf = f
53
54 def _parse(data):
55 """Generates (path, node, flags) tuples from a manifest text"""
56 if data.startswith('\0'):
57 return iter(_parsev2(data))
58 else:
59 return iter(_parsev1(data))
60
34 def _text(it):
61 def _text(it):
35 """Given an iterator over (path, node, flags) tuples, returns a manifest
62 """Given an iterator over (path, node, flags) tuples, returns a manifest
36 text"""
63 text"""
@@ -116,7 +143,13 b' except AttributeError:'
116
143
117 class manifestdict(object):
144 class manifestdict(object):
118 def __init__(self, data=''):
145 def __init__(self, data=''):
119 self._lm = _lazymanifest(data)
146 if data.startswith('\0'):
147 #_lazymanifest can not parse v2
148 self._lm = _lazymanifest('')
149 for f, n, fl in _parsev2(data):
150 self._lm[f] = n, fl
151 else:
152 self._lm = _lazymanifest(data)
120
153
121 def __getitem__(self, key):
154 def __getitem__(self, key):
122 return self._lm[key][0]
155 return self._lm[key][0]
@@ -8,6 +8,7 b' from mercurial import manifest as manife'
8 from mercurial import match as matchmod
8 from mercurial import match as matchmod
9
9
10 EMTPY_MANIFEST = ''
10 EMTPY_MANIFEST = ''
11 EMTPY_MANIFEST_V2 = '\0\n'
11
12
12 HASH_1 = '1' * 40
13 HASH_1 = '1' * 40
13 BIN_HASH_1 = binascii.unhexlify(HASH_1)
14 BIN_HASH_1 = binascii.unhexlify(HASH_1)
@@ -24,6 +25,42 b' A_SHORT_MANIFEST = ('
24 'flag2': 'l',
25 'flag2': 'l',
25 }
26 }
26
27
28 # Same data as A_SHORT_MANIFEST
29 A_SHORT_MANIFEST_V2 = (
30 '\0\n'
31 '\x00bar/baz/qux.py\0%(flag2)s\n%(hash2)s\n'
32 '\x00foo\0%(flag1)s\n%(hash1)s\n'
33 ) % {'hash1': BIN_HASH_1,
34 'flag1': '',
35 'hash2': BIN_HASH_2,
36 'flag2': 'l',
37 }
38
39 # Same data as A_SHORT_MANIFEST
40 A_METADATA_MANIFEST = (
41 '\0foo\0bar\n'
42 '\x00bar/baz/qux.py\0%(flag2)s\0foo\0bar\n%(hash2)s\n' # flag and metadata
43 '\x00foo\0%(flag1)s\0foo\n%(hash1)s\n' # no flag, but metadata
44 ) % {'hash1': BIN_HASH_1,
45 'flag1': '',
46 'hash2': BIN_HASH_2,
47 'flag2': 'l',
48 }
49
50 A_STEM_COMPRESSED_MANIFEST = (
51 '\0\n'
52 '\x00bar/baz/qux.py\0%(flag2)s\n%(hash2)s\n'
53 '\x04qux/foo.py\0%(flag1)s\n%(hash1)s\n' # simple case of 4 stem chars
54 '\x0az.py\0%(flag1)s\n%(hash1)s\n' # tricky newline = 10 stem characters
55 '\x00%(verylongdir)sx/x\0\n%(hash1)s\n'
56 '\xffx/y\0\n%(hash2)s\n' # more than 255 stem chars
57 ) % {'hash1': BIN_HASH_1,
58 'flag1': '',
59 'hash2': BIN_HASH_2,
60 'flag2': 'l',
61 'verylongdir': 255 * 'x',
62 }
63
27 A_DEEPER_MANIFEST = (
64 A_DEEPER_MANIFEST = (
28 'a/b/c/bar.py\0%(hash3)s%(flag1)s\n'
65 'a/b/c/bar.py\0%(hash3)s%(flag1)s\n'
29 'a/b/c/bar.txt\0%(hash1)s%(flag1)s\n'
66 'a/b/c/bar.txt\0%(hash1)s%(flag1)s\n'
@@ -77,6 +114,11 b' class testmanifest(unittest.TestCase):'
77 self.assertEqual(0, len(m))
114 self.assertEqual(0, len(m))
78 self.assertEqual([], list(m))
115 self.assertEqual([], list(m))
79
116
117 def testEmptyManifestv2(self):
118 m = parsemanifest(EMTPY_MANIFEST_V2)
119 self.assertEqual(0, len(m))
120 self.assertEqual([], list(m))
121
80 def testManifest(self):
122 def testManifest(self):
81 m = parsemanifest(A_SHORT_MANIFEST)
123 m = parsemanifest(A_SHORT_MANIFEST)
82 self.assertEqual(['bar/baz/qux.py', 'foo'], list(m))
124 self.assertEqual(['bar/baz/qux.py', 'foo'], list(m))
@@ -86,6 +128,25 b' class testmanifest(unittest.TestCase):'
86 self.assertEqual('', m.flags('foo'))
128 self.assertEqual('', m.flags('foo'))
87 self.assertRaises(KeyError, lambda : m['wat'])
129 self.assertRaises(KeyError, lambda : m['wat'])
88
130
131 def testParseManifestV2(self):
132 m1 = parsemanifest(A_SHORT_MANIFEST)
133 m2 = parsemanifest(A_SHORT_MANIFEST_V2)
134 # Should have same content as A_SHORT_MANIFEST
135 self.assertEqual(m1.text(), m2.text())
136
137 def testParseManifestMetadata(self):
138 # Metadata is for future-proofing and should be accepted but ignored
139 m = parsemanifest(A_METADATA_MANIFEST)
140 self.assertEqual(A_SHORT_MANIFEST, m.text())
141
142 def testParseManifestStemCompression(self):
143 m = parsemanifest(A_STEM_COMPRESSED_MANIFEST)
144 self.assertIn('bar/baz/qux.py', m)
145 self.assertIn('bar/qux/foo.py', m)
146 self.assertIn('bar/qux/foz.py', m)
147 self.assertIn(256 * 'x' + '/x', m)
148 self.assertIn(256 * 'x' + '/y', m)
149
89 def testSetItem(self):
150 def testSetItem(self):
90 want = BIN_HASH_1
151 want = BIN_HASH_1
91
152
General Comments 0
You need to be logged in to leave comments. Login now