##// END OF EJS Templates
manifests: push down expected node length into the parser...
Joerg Sonnenberger -
r47817:12450fbe default
parent child Browse files
Show More
@@ -28,6 +28,7 b' typedef struct {'
28 typedef struct {
28 typedef struct {
29 PyObject_HEAD
29 PyObject_HEAD
30 PyObject *pydata;
30 PyObject *pydata;
31 Py_ssize_t nodelen;
31 line *lines;
32 line *lines;
32 int numlines; /* number of line entries */
33 int numlines; /* number of line entries */
33 int livelines; /* number of non-deleted lines */
34 int livelines; /* number of non-deleted lines */
@@ -49,12 +50,11 b' static Py_ssize_t pathlen(line *l)'
49 }
50 }
50
51
51 /* get the node value of a single line */
52 /* get the node value of a single line */
52 static PyObject *nodeof(line *l, char *flag)
53 static PyObject *nodeof(Py_ssize_t nodelen, line *l, char *flag)
53 {
54 {
54 char *s = l->start;
55 char *s = l->start;
55 Py_ssize_t llen = pathlen(l);
56 Py_ssize_t llen = pathlen(l);
56 Py_ssize_t hlen = l->len - llen - 2;
57 Py_ssize_t hlen = l->len - llen - 2;
57 Py_ssize_t hlen_raw;
58 PyObject *hash;
58 PyObject *hash;
59 if (llen + 1 + 40 + 1 > l->len) { /* path '\0' hash '\n' */
59 if (llen + 1 + 40 + 1 > l->len) { /* path '\0' hash '\n' */
60 PyErr_SetString(PyExc_ValueError, "manifest line too short");
60 PyErr_SetString(PyExc_ValueError, "manifest line too short");
@@ -73,36 +73,29 b' static PyObject *nodeof(line *l, char *f'
73 break;
73 break;
74 }
74 }
75
75
76 switch (hlen) {
76 if (hlen != 2 * nodelen) {
77 case 40: /* sha1 */
78 hlen_raw = 20;
79 break;
80 case 64: /* new hash */
81 hlen_raw = 32;
82 break;
83 default:
84 PyErr_SetString(PyExc_ValueError, "invalid node length in manifest");
77 PyErr_SetString(PyExc_ValueError, "invalid node length in manifest");
85 return NULL;
78 return NULL;
86 }
79 }
87 hash = unhexlify(s + llen + 1, hlen_raw * 2);
80 hash = unhexlify(s + llen + 1, nodelen * 2);
88 if (!hash) {
81 if (!hash) {
89 return NULL;
82 return NULL;
90 }
83 }
91 if (l->hash_suffix != '\0') {
84 if (l->hash_suffix != '\0') {
92 char newhash[33];
85 char newhash[33];
93 memcpy(newhash, PyBytes_AsString(hash), hlen_raw);
86 memcpy(newhash, PyBytes_AsString(hash), nodelen);
94 Py_DECREF(hash);
87 Py_DECREF(hash);
95 newhash[hlen_raw] = l->hash_suffix;
88 newhash[nodelen] = l->hash_suffix;
96 hash = PyBytes_FromStringAndSize(newhash, hlen_raw+1);
89 hash = PyBytes_FromStringAndSize(newhash, nodelen + 1);
97 }
90 }
98 return hash;
91 return hash;
99 }
92 }
100
93
101 /* get the node hash and flags of a line as a tuple */
94 /* get the node hash and flags of a line as a tuple */
102 static PyObject *hashflags(line *l)
95 static PyObject *hashflags(Py_ssize_t nodelen, line *l)
103 {
96 {
104 char flag;
97 char flag;
105 PyObject *hash = nodeof(l, &flag);
98 PyObject *hash = nodeof(nodelen, l, &flag);
106 PyObject *flags;
99 PyObject *flags;
107 PyObject *tup;
100 PyObject *tup;
108
101
@@ -190,17 +183,23 b' static void lazymanifest_init_early(lazy'
190 static int lazymanifest_init(lazymanifest *self, PyObject *args)
183 static int lazymanifest_init(lazymanifest *self, PyObject *args)
191 {
184 {
192 char *data;
185 char *data;
193 Py_ssize_t len;
186 Py_ssize_t nodelen, len;
194 int err, ret;
187 int err, ret;
195 PyObject *pydata;
188 PyObject *pydata;
196
189
197 lazymanifest_init_early(self);
190 lazymanifest_init_early(self);
198 if (!PyArg_ParseTuple(args, "S", &pydata)) {
191 if (!PyArg_ParseTuple(args, "nS", &nodelen, &pydata)) {
199 return -1;
192 return -1;
200 }
193 }
201 err = PyBytes_AsStringAndSize(pydata, &data, &len);
194 if (nodelen != 20 && nodelen != 32) {
195 /* See fixed buffer in nodeof */
196 PyErr_Format(PyExc_ValueError, "Unsupported node length");
197 return -1;
198 }
199 self->nodelen = nodelen;
200 self->dirty = false;
202
201
203 self->dirty = false;
202 err = PyBytes_AsStringAndSize(pydata, &data, &len);
204 if (err == -1)
203 if (err == -1)
205 return -1;
204 return -1;
206 self->pydata = pydata;
205 self->pydata = pydata;
@@ -291,17 +290,18 b' static line *lmiter_nextline(lmIter *sel'
291
290
292 static PyObject *lmiter_iterentriesnext(PyObject *o)
291 static PyObject *lmiter_iterentriesnext(PyObject *o)
293 {
292 {
293 lmIter *self = (lmIter *)o;
294 Py_ssize_t pl;
294 Py_ssize_t pl;
295 line *l;
295 line *l;
296 char flag;
296 char flag;
297 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
297 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
298 l = lmiter_nextline((lmIter *)o);
298 l = lmiter_nextline(self);
299 if (!l) {
299 if (!l) {
300 goto done;
300 goto done;
301 }
301 }
302 pl = pathlen(l);
302 pl = pathlen(l);
303 path = PyBytes_FromStringAndSize(l->start, pl);
303 path = PyBytes_FromStringAndSize(l->start, pl);
304 hash = nodeof(l, &flag);
304 hash = nodeof(self->m->nodelen, l, &flag);
305 if (!path || !hash) {
305 if (!path || !hash) {
306 goto done;
306 goto done;
307 }
307 }
@@ -471,7 +471,7 b' static PyObject *lazymanifest_getitem(la'
471 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
471 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
472 return NULL;
472 return NULL;
473 }
473 }
474 return hashflags(hit);
474 return hashflags(self->nodelen, hit);
475 }
475 }
476
476
477 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
477 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
@@ -568,13 +568,13 b' static int lazymanifest_setitem('
568 pyhash = PyTuple_GetItem(value, 0);
568 pyhash = PyTuple_GetItem(value, 0);
569 if (!PyBytes_Check(pyhash)) {
569 if (!PyBytes_Check(pyhash)) {
570 PyErr_Format(PyExc_TypeError,
570 PyErr_Format(PyExc_TypeError,
571 "node must be a 20 or 32 bytes string");
571 "node must be a %zi bytes string", self->nodelen);
572 return -1;
572 return -1;
573 }
573 }
574 hlen = PyBytes_Size(pyhash);
574 hlen = PyBytes_Size(pyhash);
575 if (hlen != 20 && hlen != 32) {
575 if (hlen != self->nodelen) {
576 PyErr_Format(PyExc_TypeError,
576 PyErr_Format(PyExc_TypeError,
577 "node must be a 20 or 32 bytes string");
577 "node must be a %zi bytes string", self->nodelen);
578 return -1;
578 return -1;
579 }
579 }
580 hash = PyBytes_AsString(pyhash);
580 hash = PyBytes_AsString(pyhash);
@@ -739,6 +739,7 b' static lazymanifest *lazymanifest_copy(l'
739 goto nomem;
739 goto nomem;
740 }
740 }
741 lazymanifest_init_early(copy);
741 lazymanifest_init_early(copy);
742 copy->nodelen = self->nodelen;
742 copy->numlines = self->numlines;
743 copy->numlines = self->numlines;
743 copy->livelines = self->livelines;
744 copy->livelines = self->livelines;
744 copy->dirty = false;
745 copy->dirty = false;
@@ -777,6 +778,7 b' static lazymanifest *lazymanifest_filter'
777 goto nomem;
778 goto nomem;
778 }
779 }
779 lazymanifest_init_early(copy);
780 lazymanifest_init_early(copy);
781 copy->nodelen = self->nodelen;
780 copy->dirty = true;
782 copy->dirty = true;
781 copy->lines = malloc(self->maxlines * sizeof(line));
783 copy->lines = malloc(self->maxlines * sizeof(line));
782 if (!copy->lines) {
784 if (!copy->lines) {
@@ -872,7 +874,7 b' static PyObject *lazymanifest_diff(lazym'
872 if (!key)
874 if (!key)
873 goto nomem;
875 goto nomem;
874 if (result < 0) {
876 if (result < 0) {
875 PyObject *l = hashflags(left);
877 PyObject *l = hashflags(self->nodelen, left);
876 if (!l) {
878 if (!l) {
877 goto nomem;
879 goto nomem;
878 }
880 }
@@ -885,7 +887,7 b' static PyObject *lazymanifest_diff(lazym'
885 Py_DECREF(outer);
887 Py_DECREF(outer);
886 sneedle++;
888 sneedle++;
887 } else if (result > 0) {
889 } else if (result > 0) {
888 PyObject *r = hashflags(right);
890 PyObject *r = hashflags(self->nodelen, right);
889 if (!r) {
891 if (!r) {
890 goto nomem;
892 goto nomem;
891 }
893 }
@@ -902,12 +904,12 b' static PyObject *lazymanifest_diff(lazym'
902 if (left->len != right->len
904 if (left->len != right->len
903 || memcmp(left->start, right->start, left->len)
905 || memcmp(left->start, right->start, left->len)
904 || left->hash_suffix != right->hash_suffix) {
906 || left->hash_suffix != right->hash_suffix) {
905 PyObject *l = hashflags(left);
907 PyObject *l = hashflags(self->nodelen, left);
906 PyObject *r;
908 PyObject *r;
907 if (!l) {
909 if (!l) {
908 goto nomem;
910 goto nomem;
909 }
911 }
910 r = hashflags(right);
912 r = hashflags(self->nodelen, right);
911 if (!r) {
913 if (!r) {
912 Py_DECREF(l);
914 Py_DECREF(l);
913 goto nomem;
915 goto nomem;
@@ -668,7 +668,7 b' void dirs_module_init(PyObject *mod);'
668 void manifest_module_init(PyObject *mod);
668 void manifest_module_init(PyObject *mod);
669 void revlog_module_init(PyObject *mod);
669 void revlog_module_init(PyObject *mod);
670
670
671 static const int version = 17;
671 static const int version = 18;
672
672
673 static void module_init(PyObject *mod)
673 static void module_init(PyObject *mod)
674 {
674 {
@@ -29,7 +29,7 b' class dirs:'
29
29
30 # From manifest.c
30 # From manifest.c
31 class lazymanifest:
31 class lazymanifest:
32 def __init__(self, data: bytes): ...
32 def __init__(self, nodelen: int, data: bytes): ...
33 def __iter__(self) -> Iterator[bytes]: ...
33 def __iter__(self) -> Iterator[bytes]: ...
34
34
35 def __len__(self) -> int: ...
35 def __len__(self) -> int: ...
@@ -42,7 +42,7 b' propertycache = util.propertycache'
42 FASTDELTA_TEXTDIFF_THRESHOLD = 1000
42 FASTDELTA_TEXTDIFF_THRESHOLD = 1000
43
43
44
44
45 def _parse(data):
45 def _parse(nodelen, data):
46 # This method does a little bit of excessive-looking
46 # This method does a little bit of excessive-looking
47 # precondition checking. This is so that the behavior of this
47 # precondition checking. This is so that the behavior of this
48 # class exactly matches its C counterpart to try and help
48 # class exactly matches its C counterpart to try and help
@@ -63,7 +63,7 b' def _parse(data):'
63 nl -= 1
63 nl -= 1
64 else:
64 else:
65 flags = b''
65 flags = b''
66 if nl not in (40, 64):
66 if nl != 2 * nodelen:
67 raise ValueError(b'Invalid manifest line')
67 raise ValueError(b'Invalid manifest line')
68
68
69 yield f, bin(n), flags
69 yield f, bin(n), flags
@@ -131,7 +131,7 b' class lazymanifestiterentries(object):'
131 else:
131 else:
132 hlen = nlpos - zeropos - 1
132 hlen = nlpos - zeropos - 1
133 flags = b''
133 flags = b''
134 if hlen not in (40, 64):
134 if hlen != 2 * self.lm._nodelen:
135 raise error.StorageError(b'Invalid manifest line')
135 raise error.StorageError(b'Invalid manifest line')
136 hashval = unhexlify(
136 hashval = unhexlify(
137 data, self.lm.extrainfo[self.pos], zeropos + 1, hlen
137 data, self.lm.extrainfo[self.pos], zeropos + 1, hlen
@@ -176,12 +176,14 b' class _lazymanifest(object):'
176
176
177 def __init__(
177 def __init__(
178 self,
178 self,
179 nodelen,
179 data,
180 data,
180 positions=None,
181 positions=None,
181 extrainfo=None,
182 extrainfo=None,
182 extradata=None,
183 extradata=None,
183 hasremovals=False,
184 hasremovals=False,
184 ):
185 ):
186 self._nodelen = nodelen
185 if positions is None:
187 if positions is None:
186 self.positions = self.findlines(data)
188 self.positions = self.findlines(data)
187 self.extrainfo = [0] * len(self.positions)
189 self.extrainfo = [0] * len(self.positions)
@@ -288,7 +290,7 b' class _lazymanifest(object):'
288 hlen -= 1
290 hlen -= 1
289 else:
291 else:
290 flags = b''
292 flags = b''
291 if hlen not in (40, 64):
293 if hlen != 2 * self._nodelen:
292 raise error.StorageError(b'Invalid manifest line')
294 raise error.StorageError(b'Invalid manifest line')
293 hashval = unhexlify(data, self.extrainfo[needle], zeropos + 1, hlen)
295 hashval = unhexlify(data, self.extrainfo[needle], zeropos + 1, hlen)
294 return (hashval, flags)
296 return (hashval, flags)
@@ -344,6 +346,7 b' class _lazymanifest(object):'
344 def copy(self):
346 def copy(self):
345 # XXX call _compact like in C?
347 # XXX call _compact like in C?
346 return _lazymanifest(
348 return _lazymanifest(
349 self._nodelen,
347 self.data,
350 self.data,
348 self.positions,
351 self.positions,
349 self.extrainfo,
352 self.extrainfo,
@@ -454,7 +457,7 b' class _lazymanifest(object):'
454
457
455 def filtercopy(self, filterfn):
458 def filtercopy(self, filterfn):
456 # XXX should be optimized
459 # XXX should be optimized
457 c = _lazymanifest(b'')
460 c = _lazymanifest(self._nodelen, b'')
458 for f, n, fl in self.iterentries():
461 for f, n, fl in self.iterentries():
459 if filterfn(f):
462 if filterfn(f):
460 c[f] = n, fl
463 c[f] = n, fl
@@ -469,8 +472,9 b' except AttributeError:'
469
472
470 @interfaceutil.implementer(repository.imanifestdict)
473 @interfaceutil.implementer(repository.imanifestdict)
471 class manifestdict(object):
474 class manifestdict(object):
472 def __init__(self, data=b''):
475 def __init__(self, nodelen, data=b''):
473 self._lm = _lazymanifest(data)
476 self._nodelen = nodelen
477 self._lm = _lazymanifest(nodelen, data)
474
478
475 def __getitem__(self, key):
479 def __getitem__(self, key):
476 return self._lm[key][0]
480 return self._lm[key][0]
@@ -578,14 +582,14 b' class manifestdict(object):'
578 return self.copy()
582 return self.copy()
579
583
580 if self._filesfastpath(match):
584 if self._filesfastpath(match):
581 m = manifestdict()
585 m = manifestdict(self._nodelen)
582 lm = self._lm
586 lm = self._lm
583 for fn in match.files():
587 for fn in match.files():
584 if fn in lm:
588 if fn in lm:
585 m._lm[fn] = lm[fn]
589 m._lm[fn] = lm[fn]
586 return m
590 return m
587
591
588 m = manifestdict()
592 m = manifestdict(self._nodelen)
589 m._lm = self._lm.filtercopy(match)
593 m._lm = self._lm.filtercopy(match)
590 return m
594 return m
591
595
@@ -628,7 +632,7 b' class manifestdict(object):'
628 return b''
632 return b''
629
633
630 def copy(self):
634 def copy(self):
631 c = manifestdict()
635 c = manifestdict(self._nodelen)
632 c._lm = self._lm.copy()
636 c._lm = self._lm.copy()
633 return c
637 return c
634
638
@@ -795,6 +799,7 b' class treemanifest(object):'
795 self._dir = dir
799 self._dir = dir
796 self.nodeconstants = nodeconstants
800 self.nodeconstants = nodeconstants
797 self._node = self.nodeconstants.nullid
801 self._node = self.nodeconstants.nullid
802 self._nodelen = self.nodeconstants.nodelen
798 self._loadfunc = _noop
803 self._loadfunc = _noop
799 self._copyfunc = _noop
804 self._copyfunc = _noop
800 self._dirty = False
805 self._dirty = False
@@ -1322,7 +1327,7 b' class treemanifest(object):'
1322
1327
1323 def parse(self, text, readsubtree):
1328 def parse(self, text, readsubtree):
1324 selflazy = self._lazydirs
1329 selflazy = self._lazydirs
1325 for f, n, fl in _parse(text):
1330 for f, n, fl in _parse(self._nodelen, text):
1326 if fl == b't':
1331 if fl == b't':
1327 f = f + b'/'
1332 f = f + b'/'
1328 # False below means "doesn't need to be copied" and can use the
1333 # False below means "doesn't need to be copied" and can use the
@@ -2019,7 +2024,7 b' class manifestlog(object):'
2019 class memmanifestctx(object):
2024 class memmanifestctx(object):
2020 def __init__(self, manifestlog):
2025 def __init__(self, manifestlog):
2021 self._manifestlog = manifestlog
2026 self._manifestlog = manifestlog
2022 self._manifestdict = manifestdict()
2027 self._manifestdict = manifestdict(manifestlog.nodeconstants.nodelen)
2023
2028
2024 def _storage(self):
2029 def _storage(self):
2025 return self._manifestlog.getstorage(b'')
2030 return self._manifestlog.getstorage(b'')
@@ -2081,8 +2086,9 b' class manifestctx(object):'
2081
2086
2082 def read(self):
2087 def read(self):
2083 if self._data is None:
2088 if self._data is None:
2084 if self._node == self._manifestlog.nodeconstants.nullid:
2089 nc = self._manifestlog.nodeconstants
2085 self._data = manifestdict()
2090 if self._node == nc.nullid:
2091 self._data = manifestdict(nc.nodelen)
2086 else:
2092 else:
2087 store = self._storage()
2093 store = self._storage()
2088 if self._node in store.fulltextcache:
2094 if self._node in store.fulltextcache:
@@ -2091,7 +2097,7 b' class manifestctx(object):'
2091 text = store.revision(self._node)
2097 text = store.revision(self._node)
2092 arraytext = bytearray(text)
2098 arraytext = bytearray(text)
2093 store.fulltextcache[self._node] = arraytext
2099 store.fulltextcache[self._node] = arraytext
2094 self._data = manifestdict(text)
2100 self._data = manifestdict(nc.nodelen, text)
2095 return self._data
2101 return self._data
2096
2102
2097 def readfast(self, shallow=False):
2103 def readfast(self, shallow=False):
@@ -2118,7 +2124,7 b' class manifestctx(object):'
2118 store = self._storage()
2124 store = self._storage()
2119 r = store.rev(self._node)
2125 r = store.rev(self._node)
2120 d = mdiff.patchtext(store.revdiff(store.deltaparent(r), r))
2126 d = mdiff.patchtext(store.revdiff(store.deltaparent(r), r))
2121 return manifestdict(d)
2127 return manifestdict(store.nodeconstants.nodelen, d)
2122
2128
2123 def find(self, key):
2129 def find(self, key):
2124 return self.read().find(key)
2130 return self.read().find(key)
@@ -2244,7 +2250,7 b' class treemanifestctx(object):'
2244 if shallow:
2250 if shallow:
2245 r = store.rev(self._node)
2251 r = store.rev(self._node)
2246 d = mdiff.patchtext(store.revdiff(store.deltaparent(r), r))
2252 d = mdiff.patchtext(store.revdiff(store.deltaparent(r), r))
2247 return manifestdict(d)
2253 return manifestdict(store.nodeconstants.nodelen, d)
2248 else:
2254 else:
2249 # Need to perform a slow delta
2255 # Need to perform a slow delta
2250 r0 = store.deltaparent(store.rev(self._node))
2256 r0 = store.deltaparent(store.rev(self._node))
@@ -2273,7 +2279,9 b' class treemanifestctx(object):'
2273 return self.readdelta(shallow=shallow)
2279 return self.readdelta(shallow=shallow)
2274
2280
2275 if shallow:
2281 if shallow:
2276 return manifestdict(store.revision(self._node))
2282 return manifestdict(
2283 store.nodeconstants.nodelen, store.revision(self._node)
2284 )
2277 else:
2285 else:
2278 return self.read()
2286 return self.read()
2279
2287
@@ -80,7 +80,7 b' def _importfrom(pkgname, modname):'
80 ('cext', 'bdiff'): 3,
80 ('cext', 'bdiff'): 3,
81 ('cext', 'mpatch'): 1,
81 ('cext', 'mpatch'): 1,
82 ('cext', 'osutil'): 4,
82 ('cext', 'osutil'): 4,
83 ('cext', 'parsers'): 17,
83 ('cext', 'parsers'): 18,
84 }
84 }
85
85
86 # map import request to other package or module
86 # map import request to other package or module
@@ -81,12 +81,12 b' class basemanifesttests(object):'
81 raise NotImplementedError('parsemanifest not implemented by test case')
81 raise NotImplementedError('parsemanifest not implemented by test case')
82
82
83 def testEmptyManifest(self):
83 def testEmptyManifest(self):
84 m = self.parsemanifest(EMTPY_MANIFEST)
84 m = self.parsemanifest(20, EMTPY_MANIFEST)
85 self.assertEqual(0, len(m))
85 self.assertEqual(0, len(m))
86 self.assertEqual([], list(m))
86 self.assertEqual([], list(m))
87
87
88 def testManifest(self):
88 def testManifest(self):
89 m = self.parsemanifest(A_SHORT_MANIFEST)
89 m = self.parsemanifest(20, A_SHORT_MANIFEST)
90 self.assertEqual([b'bar/baz/qux.py', b'foo'], list(m))
90 self.assertEqual([b'bar/baz/qux.py', b'foo'], list(m))
91 self.assertEqual(BIN_HASH_2, m[b'bar/baz/qux.py'])
91 self.assertEqual(BIN_HASH_2, m[b'bar/baz/qux.py'])
92 self.assertEqual(b'l', m.flags(b'bar/baz/qux.py'))
92 self.assertEqual(b'l', m.flags(b'bar/baz/qux.py'))
@@ -95,20 +95,16 b' class basemanifesttests(object):'
95 with self.assertRaises(KeyError):
95 with self.assertRaises(KeyError):
96 m[b'wat']
96 m[b'wat']
97
97
98 def testManifestLongHashes(self):
99 m = self.parsemanifest(b'a\0' + b'f' * 64 + b'\n')
100 self.assertEqual(binascii.unhexlify(b'f' * 64), m[b'a'])
101
102 def testSetItem(self):
98 def testSetItem(self):
103 want = BIN_HASH_1
99 want = BIN_HASH_1
104
100
105 m = self.parsemanifest(EMTPY_MANIFEST)
101 m = self.parsemanifest(20, EMTPY_MANIFEST)
106 m[b'a'] = want
102 m[b'a'] = want
107 self.assertIn(b'a', m)
103 self.assertIn(b'a', m)
108 self.assertEqual(want, m[b'a'])
104 self.assertEqual(want, m[b'a'])
109 self.assertEqual(b'a\0' + HASH_1 + b'\n', m.text())
105 self.assertEqual(b'a\0' + HASH_1 + b'\n', m.text())
110
106
111 m = self.parsemanifest(A_SHORT_MANIFEST)
107 m = self.parsemanifest(20, A_SHORT_MANIFEST)
112 m[b'a'] = want
108 m[b'a'] = want
113 self.assertEqual(want, m[b'a'])
109 self.assertEqual(want, m[b'a'])
114 self.assertEqual(b'a\0' + HASH_1 + b'\n' + A_SHORT_MANIFEST, m.text())
110 self.assertEqual(b'a\0' + HASH_1 + b'\n' + A_SHORT_MANIFEST, m.text())
@@ -116,14 +112,14 b' class basemanifesttests(object):'
116 def testSetFlag(self):
112 def testSetFlag(self):
117 want = b'x'
113 want = b'x'
118
114
119 m = self.parsemanifest(EMTPY_MANIFEST)
115 m = self.parsemanifest(20, EMTPY_MANIFEST)
120 # first add a file; a file-less flag makes no sense
116 # first add a file; a file-less flag makes no sense
121 m[b'a'] = BIN_HASH_1
117 m[b'a'] = BIN_HASH_1
122 m.setflag(b'a', want)
118 m.setflag(b'a', want)
123 self.assertEqual(want, m.flags(b'a'))
119 self.assertEqual(want, m.flags(b'a'))
124 self.assertEqual(b'a\0' + HASH_1 + want + b'\n', m.text())
120 self.assertEqual(b'a\0' + HASH_1 + want + b'\n', m.text())
125
121
126 m = self.parsemanifest(A_SHORT_MANIFEST)
122 m = self.parsemanifest(20, A_SHORT_MANIFEST)
127 # first add a file; a file-less flag makes no sense
123 # first add a file; a file-less flag makes no sense
128 m[b'a'] = BIN_HASH_1
124 m[b'a'] = BIN_HASH_1
129 m.setflag(b'a', want)
125 m.setflag(b'a', want)
@@ -133,7 +129,7 b' class basemanifesttests(object):'
133 )
129 )
134
130
135 def testCopy(self):
131 def testCopy(self):
136 m = self.parsemanifest(A_SHORT_MANIFEST)
132 m = self.parsemanifest(20, A_SHORT_MANIFEST)
137 m[b'a'] = BIN_HASH_1
133 m[b'a'] = BIN_HASH_1
138 m2 = m.copy()
134 m2 = m.copy()
139 del m
135 del m
@@ -142,7 +138,7 b' class basemanifesttests(object):'
142 def testCompaction(self):
138 def testCompaction(self):
143 unhex = binascii.unhexlify
139 unhex = binascii.unhexlify
144 h1, h2 = unhex(HASH_1), unhex(HASH_2)
140 h1, h2 = unhex(HASH_1), unhex(HASH_2)
145 m = self.parsemanifest(A_SHORT_MANIFEST)
141 m = self.parsemanifest(20, A_SHORT_MANIFEST)
146 m[b'alpha'] = h1
142 m[b'alpha'] = h1
147 m[b'beta'] = h2
143 m[b'beta'] = h2
148 del m[b'foo']
144 del m[b'foo']
@@ -164,7 +160,7 b' class basemanifesttests(object):'
164 m[b'foo']
160 m[b'foo']
165
161
166 def testMatchException(self):
162 def testMatchException(self):
167 m = self.parsemanifest(A_SHORT_MANIFEST)
163 m = self.parsemanifest(20, A_SHORT_MANIFEST)
168 match = matchmod.match(util.localpath(b'/repo'), b'', [b're:.*'])
164 match = matchmod.match(util.localpath(b'/repo'), b'', [b're:.*'])
169
165
170 def filt(path):
166 def filt(path):
@@ -177,7 +173,7 b' class basemanifesttests(object):'
177 m._matches(match)
173 m._matches(match)
178
174
179 def testRemoveItem(self):
175 def testRemoveItem(self):
180 m = self.parsemanifest(A_SHORT_MANIFEST)
176 m = self.parsemanifest(20, A_SHORT_MANIFEST)
181 del m[b'foo']
177 del m[b'foo']
182 with self.assertRaises(KeyError):
178 with self.assertRaises(KeyError):
183 m[b'foo']
179 m[b'foo']
@@ -193,9 +189,9 b' class basemanifesttests(object):'
193 addl = b'z-only-in-left\0' + HASH_1 + b'\n'
189 addl = b'z-only-in-left\0' + HASH_1 + b'\n'
194 addr = b'z-only-in-right\0' + HASH_2 + b'x\n'
190 addr = b'z-only-in-right\0' + HASH_2 + b'x\n'
195 left = self.parsemanifest(
191 left = self.parsemanifest(
196 A_SHORT_MANIFEST.replace(HASH_1, HASH_3 + b'x') + addl
192 20, A_SHORT_MANIFEST.replace(HASH_1, HASH_3 + b'x') + addl
197 )
193 )
198 right = self.parsemanifest(A_SHORT_MANIFEST + addr)
194 right = self.parsemanifest(20, A_SHORT_MANIFEST + addr)
199 want = {
195 want = {
200 b'foo': ((BIN_HASH_3, b'x'), (BIN_HASH_1, b'')),
196 b'foo': ((BIN_HASH_3, b'x'), (BIN_HASH_1, b'')),
201 b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
197 b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
@@ -208,14 +204,18 b' class basemanifesttests(object):'
208 b'foo': (MISSING, (BIN_HASH_3, b'x')),
204 b'foo': (MISSING, (BIN_HASH_3, b'x')),
209 b'z-only-in-left': (MISSING, (BIN_HASH_1, b'')),
205 b'z-only-in-left': (MISSING, (BIN_HASH_1, b'')),
210 }
206 }
211 self.assertEqual(want, self.parsemanifest(EMTPY_MANIFEST).diff(left))
207 self.assertEqual(
208 want, self.parsemanifest(20, EMTPY_MANIFEST).diff(left)
209 )
212
210
213 want = {
211 want = {
214 b'bar/baz/qux.py': ((BIN_HASH_2, b'l'), MISSING),
212 b'bar/baz/qux.py': ((BIN_HASH_2, b'l'), MISSING),
215 b'foo': ((BIN_HASH_3, b'x'), MISSING),
213 b'foo': ((BIN_HASH_3, b'x'), MISSING),
216 b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
214 b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
217 }
215 }
218 self.assertEqual(want, left.diff(self.parsemanifest(EMTPY_MANIFEST)))
216 self.assertEqual(
217 want, left.diff(self.parsemanifest(20, EMTPY_MANIFEST))
218 )
219 copy = right.copy()
219 copy = right.copy()
220 del copy[b'z-only-in-right']
220 del copy[b'z-only-in-right']
221 del right[b'foo']
221 del right[b'foo']
@@ -225,7 +225,7 b' class basemanifesttests(object):'
225 }
225 }
226 self.assertEqual(want, right.diff(copy))
226 self.assertEqual(want, right.diff(copy))
227
227
228 short = self.parsemanifest(A_SHORT_MANIFEST)
228 short = self.parsemanifest(20, A_SHORT_MANIFEST)
229 pruned = short.copy()
229 pruned = short.copy()
230 del pruned[b'foo']
230 del pruned[b'foo']
231 want = {
231 want = {
@@ -247,27 +247,27 b' class basemanifesttests(object):'
247 l + b'\n' for l in reversed(A_SHORT_MANIFEST.split(b'\n')) if l
247 l + b'\n' for l in reversed(A_SHORT_MANIFEST.split(b'\n')) if l
248 )
248 )
249 try:
249 try:
250 self.parsemanifest(backwards)
250 self.parsemanifest(20, backwards)
251 self.fail('Should have raised ValueError')
251 self.fail('Should have raised ValueError')
252 except ValueError as v:
252 except ValueError as v:
253 self.assertIn('Manifest lines not in sorted order.', str(v))
253 self.assertIn('Manifest lines not in sorted order.', str(v))
254
254
255 def testNoTerminalNewline(self):
255 def testNoTerminalNewline(self):
256 try:
256 try:
257 self.parsemanifest(A_SHORT_MANIFEST + b'wat')
257 self.parsemanifest(20, A_SHORT_MANIFEST + b'wat')
258 self.fail('Should have raised ValueError')
258 self.fail('Should have raised ValueError')
259 except ValueError as v:
259 except ValueError as v:
260 self.assertIn('Manifest did not end in a newline.', str(v))
260 self.assertIn('Manifest did not end in a newline.', str(v))
261
261
262 def testNoNewLineAtAll(self):
262 def testNoNewLineAtAll(self):
263 try:
263 try:
264 self.parsemanifest(b'wat')
264 self.parsemanifest(20, b'wat')
265 self.fail('Should have raised ValueError')
265 self.fail('Should have raised ValueError')
266 except ValueError as v:
266 except ValueError as v:
267 self.assertIn('Manifest did not end in a newline.', str(v))
267 self.assertIn('Manifest did not end in a newline.', str(v))
268
268
269 def testHugeManifest(self):
269 def testHugeManifest(self):
270 m = self.parsemanifest(A_HUGE_MANIFEST)
270 m = self.parsemanifest(20, A_HUGE_MANIFEST)
271 self.assertEqual(HUGE_MANIFEST_ENTRIES, len(m))
271 self.assertEqual(HUGE_MANIFEST_ENTRIES, len(m))
272 self.assertEqual(len(m), len(list(m)))
272 self.assertEqual(len(m), len(list(m)))
273
273
@@ -275,7 +275,7 b' class basemanifesttests(object):'
275 """Tests matches() for a few specific files to make sure that both
275 """Tests matches() for a few specific files to make sure that both
276 the set of files as well as their flags and nodeids are correct in
276 the set of files as well as their flags and nodeids are correct in
277 the resulting manifest."""
277 the resulting manifest."""
278 m = self.parsemanifest(A_HUGE_MANIFEST)
278 m = self.parsemanifest(20, A_HUGE_MANIFEST)
279
279
280 match = matchmod.exact([b'file1', b'file200', b'file300'])
280 match = matchmod.exact([b'file1', b'file200', b'file300'])
281 m2 = m._matches(match)
281 m2 = m._matches(match)
@@ -291,7 +291,7 b' class basemanifesttests(object):'
291 """Tests matches() for a small set of specific files, including one
291 """Tests matches() for a small set of specific files, including one
292 nonexistent file to make sure in only matches against existing files.
292 nonexistent file to make sure in only matches against existing files.
293 """
293 """
294 m = self.parsemanifest(A_DEEPER_MANIFEST)
294 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
295
295
296 match = matchmod.exact(
296 match = matchmod.exact(
297 [b'a/b/c/bar.txt', b'a/b/d/qux.py', b'readme.txt', b'nonexistent']
297 [b'a/b/c/bar.txt', b'a/b/d/qux.py', b'readme.txt', b'nonexistent']
@@ -305,7 +305,7 b' class basemanifesttests(object):'
305 def testMatchesNonexistentDirectory(self):
305 def testMatchesNonexistentDirectory(self):
306 """Tests matches() for a relpath match on a directory that doesn't
306 """Tests matches() for a relpath match on a directory that doesn't
307 actually exist."""
307 actually exist."""
308 m = self.parsemanifest(A_DEEPER_MANIFEST)
308 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
309
309
310 match = matchmod.match(
310 match = matchmod.match(
311 util.localpath(b'/repo'), b'', [b'a/f'], default=b'relpath'
311 util.localpath(b'/repo'), b'', [b'a/f'], default=b'relpath'
@@ -316,7 +316,7 b' class basemanifesttests(object):'
316
316
317 def testMatchesExactLarge(self):
317 def testMatchesExactLarge(self):
318 """Tests matches() for files matching a large list of exact files."""
318 """Tests matches() for files matching a large list of exact files."""
319 m = self.parsemanifest(A_HUGE_MANIFEST)
319 m = self.parsemanifest(20, A_HUGE_MANIFEST)
320
320
321 flist = m.keys()[80:300]
321 flist = m.keys()[80:300]
322 match = matchmod.exact(flist)
322 match = matchmod.exact(flist)
@@ -326,7 +326,7 b' class basemanifesttests(object):'
326
326
327 def testMatchesFull(self):
327 def testMatchesFull(self):
328 '''Tests matches() for what should be a full match.'''
328 '''Tests matches() for what should be a full match.'''
329 m = self.parsemanifest(A_DEEPER_MANIFEST)
329 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
330
330
331 match = matchmod.match(util.localpath(b'/repo'), b'', [b''])
331 match = matchmod.match(util.localpath(b'/repo'), b'', [b''])
332 m2 = m._matches(match)
332 m2 = m._matches(match)
@@ -336,7 +336,7 b' class basemanifesttests(object):'
336 def testMatchesDirectory(self):
336 def testMatchesDirectory(self):
337 """Tests matches() on a relpath match on a directory, which should
337 """Tests matches() on a relpath match on a directory, which should
338 match against all files within said directory."""
338 match against all files within said directory."""
339 m = self.parsemanifest(A_DEEPER_MANIFEST)
339 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
340
340
341 match = matchmod.match(
341 match = matchmod.match(
342 util.localpath(b'/repo'), b'', [b'a/b'], default=b'relpath'
342 util.localpath(b'/repo'), b'', [b'a/b'], default=b'relpath'
@@ -362,7 +362,7 b' class basemanifesttests(object):'
362 """Tests matches() on an exact match on a directory, which should
362 """Tests matches() on an exact match on a directory, which should
363 result in an empty manifest because you can't perform an exact match
363 result in an empty manifest because you can't perform an exact match
364 against a directory."""
364 against a directory."""
365 m = self.parsemanifest(A_DEEPER_MANIFEST)
365 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
366
366
367 match = matchmod.exact([b'a/b'])
367 match = matchmod.exact([b'a/b'])
368 m2 = m._matches(match)
368 m2 = m._matches(match)
@@ -372,7 +372,7 b' class basemanifesttests(object):'
372 def testMatchesCwd(self):
372 def testMatchesCwd(self):
373 """Tests matches() on a relpath match with the current directory ('.')
373 """Tests matches() on a relpath match with the current directory ('.')
374 when not in the root directory."""
374 when not in the root directory."""
375 m = self.parsemanifest(A_DEEPER_MANIFEST)
375 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
376
376
377 match = matchmod.match(
377 match = matchmod.match(
378 util.localpath(b'/repo'), b'a/b', [b'.'], default=b'relpath'
378 util.localpath(b'/repo'), b'a/b', [b'.'], default=b'relpath'
@@ -397,7 +397,7 b' class basemanifesttests(object):'
397 def testMatchesWithPattern(self):
397 def testMatchesWithPattern(self):
398 """Tests matches() for files matching a pattern that reside
398 """Tests matches() for files matching a pattern that reside
399 deeper than the specified directory."""
399 deeper than the specified directory."""
400 m = self.parsemanifest(A_DEEPER_MANIFEST)
400 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
401
401
402 match = matchmod.match(util.localpath(b'/repo'), b'', [b'a/b/*/*.txt'])
402 match = matchmod.match(util.localpath(b'/repo'), b'', [b'a/b/*/*.txt'])
403 m2 = m._matches(match)
403 m2 = m._matches(match)
@@ -408,8 +408,12 b' class basemanifesttests(object):'
408
408
409
409
410 class testmanifestdict(unittest.TestCase, basemanifesttests):
410 class testmanifestdict(unittest.TestCase, basemanifesttests):
411 def parsemanifest(self, text):
411 def parsemanifest(self, nodelen, text):
412 return manifestmod.manifestdict(text)
412 return manifestmod.manifestdict(nodelen, text)
413
414 def testManifestLongHashes(self):
415 m = self.parsemanifest(32, b'a\0' + b'f' * 64 + b'\n')
416 self.assertEqual(binascii.unhexlify(b'f' * 64), m[b'a'])
413
417
414 def testObviouslyBogusManifest(self):
418 def testObviouslyBogusManifest(self):
415 # This is a 163k manifest that came from oss-fuzz. It was a
419 # This is a 163k manifest that came from oss-fuzz. It was a
@@ -433,15 +437,15 b' class testmanifestdict(unittest.TestCase'
433 b'\xac\xbe'
437 b'\xac\xbe'
434 )
438 )
435 with self.assertRaises(ValueError):
439 with self.assertRaises(ValueError):
436 self.parsemanifest(data)
440 self.parsemanifest(20, data)
437
441
438
442
439 class testtreemanifest(unittest.TestCase, basemanifesttests):
443 class testtreemanifest(unittest.TestCase, basemanifesttests):
440 def parsemanifest(self, text):
444 def parsemanifest(self, nodelen, text):
441 return manifestmod.treemanifest(sha1nodeconstants, b'', text)
445 return manifestmod.treemanifest(sha1nodeconstants, b'', text)
442
446
443 def testWalkSubtrees(self):
447 def testWalkSubtrees(self):
444 m = self.parsemanifest(A_DEEPER_MANIFEST)
448 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
445
449
446 dirs = [s._dir for s in m.walksubtrees()]
450 dirs = [s._dir for s in m.walksubtrees()]
447 self.assertEqual(
451 self.assertEqual(
General Comments 0
You need to be logged in to leave comments. Login now