Mercurial > hg
comparison mercurial/manifest.py @ 24572:b83679eb5f86
manifestv2: add support for reading new manifest format
The new manifest format is designed to be smaller, in particular to
produce smaller deltas. It stores hashes in binary and puts the hash
on a new line (for smaller deltas). It also uses stem compression to
save space for long paths. The format has room for metadata, but
that's there only for future-proofing. The parser thus accepts any
metadata and throws it away. For more information, see
http://mercurial.selenic.com/wiki/ManifestV2Plan.
The current manifest format doesn't allow an empty filename, so we use
an empty filename on the first line to tell a manifest of the new
format from the old. Since we still never write manifests in the new
format, the added code is unused, but it is tested by
test-manifest.py.
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Fri, 27 Mar 2015 22:26:41 -0700 |
parents | 919f8ce040be |
children | 701d3554de0e |
comparison
equal
deleted
inserted
replaced
24571:919f8ce040be | 24572:b83679eb5f86 |
---|---|
9 import mdiff, parsers, error, revlog, util, scmutil | 9 import mdiff, parsers, error, revlog, util, scmutil |
10 import array, struct | 10 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 |
19 # prevent surprise breakage for anyone that develops against | 18 # prevent surprise breakage for anyone that develops against |
20 # the pure version. | 19 # the pure version. |
29 if len(n) > 40: | 28 if len(n) > 40: |
30 yield f, revlog.bin(n[:40]), n[40:] | 29 yield f, revlog.bin(n[:40]), n[40:] |
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""" |
37 files = [] | 64 files = [] |
38 lines = [] | 65 lines = [] |
114 except AttributeError: | 141 except AttributeError: |
115 pass | 142 pass |
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] |
123 | 156 |
124 def find(self, key): | 157 def find(self, key): |