Show More
@@ -0,0 +1,137 b'' | |||||
|
1 | # coding=UTF-8 | |||
|
2 | ||||
|
3 | from __future__ import absolute_import | |||
|
4 | ||||
|
5 | import base64 | |||
|
6 | import zlib | |||
|
7 | ||||
|
8 | from mercurial import ( | |||
|
9 | changegroup, | |||
|
10 | extensions, | |||
|
11 | filelog, | |||
|
12 | revlog, | |||
|
13 | util, | |||
|
14 | ) | |||
|
15 | ||||
|
16 | # Test only: These flags are defined here only in the context of testing the | |||
|
17 | # behavior of the flag processor. The canonical way to add flags is to get in | |||
|
18 | # touch with the community and make them known in revlog. | |||
|
19 | REVIDX_NOOP = (1 << 3) | |||
|
20 | REVIDX_BASE64 = (1 << 2) | |||
|
21 | REVIDX_GZIP = (1 << 1) | |||
|
22 | REVIDX_FAIL = 1 | |||
|
23 | ||||
|
24 | def validatehash(self, text): | |||
|
25 | return True | |||
|
26 | ||||
|
27 | def bypass(self, text): | |||
|
28 | return False | |||
|
29 | ||||
|
30 | def noopdonothing(self, text): | |||
|
31 | return (text, True) | |||
|
32 | ||||
|
33 | def b64encode(self, text): | |||
|
34 | return (base64.b64encode(text), False) | |||
|
35 | ||||
|
36 | def b64decode(self, text): | |||
|
37 | return (base64.b64decode(text), True) | |||
|
38 | ||||
|
39 | def gzipcompress(self, text): | |||
|
40 | return (zlib.compress(text), False) | |||
|
41 | ||||
|
42 | def gzipdecompress(self, text): | |||
|
43 | return (zlib.decompress(text), True) | |||
|
44 | ||||
|
45 | def supportedoutgoingversions(orig, repo): | |||
|
46 | versions = orig(repo) | |||
|
47 | versions.discard('01') | |||
|
48 | versions.discard('02') | |||
|
49 | versions.add('03') | |||
|
50 | return versions | |||
|
51 | ||||
|
52 | def allsupportedversions(orig, ui): | |||
|
53 | versions = orig(ui) | |||
|
54 | versions.add('03') | |||
|
55 | return versions | |||
|
56 | ||||
|
57 | def noopaddrevision(orig, self, text, transaction, link, p1, p2, | |||
|
58 | cachedelta=None, node=None, | |||
|
59 | flags=revlog.REVIDX_DEFAULT_FLAGS): | |||
|
60 | if '[NOOP]' in text: | |||
|
61 | flags |= REVIDX_NOOP | |||
|
62 | return orig(self, text, transaction, link, p1, p2, cachedelta=cachedelta, | |||
|
63 | node=node, flags=flags) | |||
|
64 | ||||
|
65 | def b64addrevision(orig, self, text, transaction, link, p1, p2, | |||
|
66 | cachedelta=None, node=None, | |||
|
67 | flags=revlog.REVIDX_DEFAULT_FLAGS): | |||
|
68 | if '[BASE64]' in text: | |||
|
69 | flags |= REVIDX_BASE64 | |||
|
70 | return orig(self, text, transaction, link, p1, p2, cachedelta=cachedelta, | |||
|
71 | node=node, flags=flags) | |||
|
72 | ||||
|
73 | def gzipaddrevision(orig, self, text, transaction, link, p1, p2, | |||
|
74 | cachedelta=None, node=None, | |||
|
75 | flags=revlog.REVIDX_DEFAULT_FLAGS): | |||
|
76 | if '[GZIP]' in text: | |||
|
77 | flags |= REVIDX_GZIP | |||
|
78 | return orig(self, text, transaction, link, p1, p2, cachedelta=cachedelta, | |||
|
79 | node=node, flags=flags) | |||
|
80 | ||||
|
81 | def failaddrevision(orig, self, text, transaction, link, p1, p2, | |||
|
82 | cachedelta=None, node=None, | |||
|
83 | flags=revlog.REVIDX_DEFAULT_FLAGS): | |||
|
84 | # This addrevision wrapper is meant to add a flag we will not have | |||
|
85 | # transforms registered for, ensuring we handle this error case. | |||
|
86 | if '[FAIL]' in text: | |||
|
87 | flags |= REVIDX_FAIL | |||
|
88 | return orig(self, text, transaction, link, p1, p2, cachedelta=cachedelta, | |||
|
89 | node=node, flags=flags) | |||
|
90 | ||||
|
91 | def extsetup(ui): | |||
|
92 | # Enable changegroup3 for flags to be sent over the wire | |||
|
93 | wrapfunction = extensions.wrapfunction | |||
|
94 | wrapfunction(changegroup, | |||
|
95 | 'supportedoutgoingversions', | |||
|
96 | supportedoutgoingversions) | |||
|
97 | wrapfunction(changegroup, | |||
|
98 | 'allsupportedversions', | |||
|
99 | allsupportedversions) | |||
|
100 | ||||
|
101 | # Teach revlog about our test flags | |||
|
102 | flags = [REVIDX_NOOP, REVIDX_BASE64, REVIDX_GZIP, REVIDX_FAIL] | |||
|
103 | revlog.REVIDX_KNOWN_FLAGS |= util.bitsfrom(flags) | |||
|
104 | revlog.REVIDX_FLAGS_ORDER.extend(flags) | |||
|
105 | ||||
|
106 | # Add wrappers for addrevision, responsible to set flags depending on the | |||
|
107 | # revision data contents. | |||
|
108 | wrapfunction(filelog.filelog, 'addrevision', noopaddrevision) | |||
|
109 | wrapfunction(filelog.filelog, 'addrevision', b64addrevision) | |||
|
110 | wrapfunction(filelog.filelog, 'addrevision', gzipaddrevision) | |||
|
111 | wrapfunction(filelog.filelog, 'addrevision', failaddrevision) | |||
|
112 | ||||
|
113 | # Register flag processors for each extension | |||
|
114 | revlog.addflagprocessor( | |||
|
115 | REVIDX_NOOP, | |||
|
116 | ( | |||
|
117 | noopdonothing, | |||
|
118 | noopdonothing, | |||
|
119 | validatehash, | |||
|
120 | ) | |||
|
121 | ) | |||
|
122 | revlog.addflagprocessor( | |||
|
123 | REVIDX_BASE64, | |||
|
124 | ( | |||
|
125 | b64decode, | |||
|
126 | b64encode, | |||
|
127 | bypass, | |||
|
128 | ), | |||
|
129 | ) | |||
|
130 | revlog.addflagprocessor( | |||
|
131 | REVIDX_GZIP, | |||
|
132 | ( | |||
|
133 | gzipdecompress, | |||
|
134 | gzipcompress, | |||
|
135 | bypass | |||
|
136 | ) | |||
|
137 | ) |
@@ -0,0 +1,165 b'' | |||||
|
1 | # Create server | |||
|
2 | $ hg init server | |||
|
3 | $ cd server | |||
|
4 | $ cat >> .hg/hgrc << EOF | |||
|
5 | > [extensions] | |||
|
6 | > extension=$TESTDIR/flagprocessorext.py | |||
|
7 | > EOF | |||
|
8 | $ cd ../ | |||
|
9 | ||||
|
10 | # Clone server and enable extensions | |||
|
11 | $ hg clone -q server client | |||
|
12 | $ cd client | |||
|
13 | $ cat >> .hg/hgrc << EOF | |||
|
14 | > [extensions] | |||
|
15 | > extension=$TESTDIR/flagprocessorext.py | |||
|
16 | > EOF | |||
|
17 | ||||
|
18 | # Commit file that will trigger the noop extension | |||
|
19 | $ echo '[NOOP]' > noop | |||
|
20 | $ hg commit -Aqm "noop" | |||
|
21 | ||||
|
22 | # Commit file that will trigger the base64 extension | |||
|
23 | $ echo '[BASE64]' > base64 | |||
|
24 | $ hg commit -Aqm 'base64' | |||
|
25 | ||||
|
26 | # Commit file that will trigger the gzip extension | |||
|
27 | $ echo '[GZIP]' > gzip | |||
|
28 | $ hg commit -Aqm 'gzip' | |||
|
29 | ||||
|
30 | # Commit file that will trigger noop and base64 | |||
|
31 | $ echo '[NOOP][BASE64]' > noop-base64 | |||
|
32 | $ hg commit -Aqm 'noop+base64' | |||
|
33 | ||||
|
34 | # Commit file that will trigger noop and gzip | |||
|
35 | $ echo '[NOOP][GZIP]' > noop-gzip | |||
|
36 | $ hg commit -Aqm 'noop+gzip' | |||
|
37 | ||||
|
38 | # Commit file that will trigger base64 and gzip | |||
|
39 | $ echo '[BASE64][GZIP]' > base64-gzip | |||
|
40 | $ hg commit -Aqm 'base64+gzip' | |||
|
41 | ||||
|
42 | # Commit file that will trigger base64, gzip and noop | |||
|
43 | $ echo '[BASE64][GZIP][NOOP]' > base64-gzip-noop | |||
|
44 | $ hg commit -Aqm 'base64+gzip+noop' | |||
|
45 | ||||
|
46 | # TEST: ensure the revision data is consistent | |||
|
47 | $ hg cat noop | |||
|
48 | [NOOP] | |||
|
49 | $ hg debugdata noop 0 | |||
|
50 | [NOOP] | |||
|
51 | ||||
|
52 | $ hg cat -r . base64 | |||
|
53 | [BASE64] | |||
|
54 | $ hg debugdata base64 0 | |||
|
55 | W0JBU0U2NF0K (no-eol) | |||
|
56 | ||||
|
57 | $ hg cat -r . gzip | |||
|
58 | [GZIP] | |||
|
59 | $ hg debugdata gzip 0 | |||
|
60 | x\x9c\x8bv\x8f\xf2\x0c\x88\xe5\x02\x00\x08\xc8\x01\xfd (no-eol) (esc) | |||
|
61 | ||||
|
62 | $ hg cat -r . noop-base64 | |||
|
63 | [NOOP][BASE64] | |||
|
64 | $ hg debugdata noop-base64 0 | |||
|
65 | W05PT1BdW0JBU0U2NF0K (no-eol) | |||
|
66 | ||||
|
67 | $ hg cat -r . noop-gzip | |||
|
68 | [NOOP][GZIP] | |||
|
69 | $ hg debugdata noop-gzip 0 | |||
|
70 | x\x9c\x8b\xf6\xf3\xf7\x0f\x88\x8dv\x8f\xf2\x0c\x88\xe5\x02\x00\x1dH\x03\xf1 (no-eol) (esc) | |||
|
71 | ||||
|
72 | $ hg cat -r . base64-gzip | |||
|
73 | [BASE64][GZIP] | |||
|
74 | $ hg debugdata base64-gzip 0 | |||
|
75 | eJyLdnIMdjUziY12j/IMiOUCACLBBDo= (no-eol) | |||
|
76 | ||||
|
77 | $ hg cat -r . base64-gzip-noop | |||
|
78 | [BASE64][GZIP][NOOP] | |||
|
79 | $ hg debugdata base64-gzip-noop 0 | |||
|
80 | eJyLdnIMdjUziY12j/IMiI328/cPiOUCAESjBi4= (no-eol) | |||
|
81 | ||||
|
82 | # Push to the server | |||
|
83 | $ hg push | |||
|
84 | pushing to $TESTTMP/server (glob) | |||
|
85 | searching for changes | |||
|
86 | adding changesets | |||
|
87 | adding manifests | |||
|
88 | adding file changes | |||
|
89 | added 7 changesets with 7 changes to 7 files | |||
|
90 | ||||
|
91 | # Initialize new client (not cloning) and setup extension | |||
|
92 | $ cd .. | |||
|
93 | $ hg init client2 | |||
|
94 | $ cd client2 | |||
|
95 | $ cat >> .hg/hgrc << EOF | |||
|
96 | > [paths] | |||
|
97 | > default = $TESTTMP/server | |||
|
98 | > [extensions] | |||
|
99 | > extension=$TESTDIR/flagprocessorext.py | |||
|
100 | > EOF | |||
|
101 | ||||
|
102 | # Pull from server and update to latest revision | |||
|
103 | $ hg pull default | |||
|
104 | pulling from $TESTTMP/server (glob) | |||
|
105 | requesting all changes | |||
|
106 | adding changesets | |||
|
107 | adding manifests | |||
|
108 | adding file changes | |||
|
109 | added 7 changesets with 7 changes to 7 files | |||
|
110 | (run 'hg update' to get a working copy) | |||
|
111 | $ hg update | |||
|
112 | 7 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
113 | ||||
|
114 | # TEST: ensure the revision data is consistent | |||
|
115 | $ hg cat noop | |||
|
116 | [NOOP] | |||
|
117 | $ hg debugdata noop 0 | |||
|
118 | [NOOP] | |||
|
119 | ||||
|
120 | $ hg cat -r . base64 | |||
|
121 | [BASE64] | |||
|
122 | $ hg debugdata base64 0 | |||
|
123 | W0JBU0U2NF0K (no-eol) | |||
|
124 | ||||
|
125 | $ hg cat -r . gzip | |||
|
126 | [GZIP] | |||
|
127 | $ hg debugdata gzip 0 | |||
|
128 | x\x9c\x8bv\x8f\xf2\x0c\x88\xe5\x02\x00\x08\xc8\x01\xfd (no-eol) (esc) | |||
|
129 | ||||
|
130 | $ hg cat -r . noop-base64 | |||
|
131 | [NOOP][BASE64] | |||
|
132 | $ hg debugdata noop-base64 0 | |||
|
133 | W05PT1BdW0JBU0U2NF0K (no-eol) | |||
|
134 | ||||
|
135 | $ hg cat -r . noop-gzip | |||
|
136 | [NOOP][GZIP] | |||
|
137 | $ hg debugdata noop-gzip 0 | |||
|
138 | x\x9c\x8b\xf6\xf3\xf7\x0f\x88\x8dv\x8f\xf2\x0c\x88\xe5\x02\x00\x1dH\x03\xf1 (no-eol) (esc) | |||
|
139 | ||||
|
140 | $ hg cat -r . base64-gzip | |||
|
141 | [BASE64][GZIP] | |||
|
142 | $ hg debugdata base64-gzip 0 | |||
|
143 | eJyLdnIMdjUziY12j/IMiOUCACLBBDo= (no-eol) | |||
|
144 | ||||
|
145 | $ hg cat -r . base64-gzip-noop | |||
|
146 | [BASE64][GZIP][NOOP] | |||
|
147 | $ hg debugdata base64-gzip-noop 0 | |||
|
148 | eJyLdnIMdjUziY12j/IMiI328/cPiOUCAESjBi4= (no-eol) | |||
|
149 | ||||
|
150 | # TEST: ensure a missing processor is handled | |||
|
151 | $ echo '[FAIL][BASE64][GZIP][NOOP]' > fail-base64-gzip-noop | |||
|
152 | $ hg commit -Aqm 'fail+base64+gzip+noop' | |||
|
153 | abort: missing processor for flag '0x1'! | |||
|
154 | [255] | |||
|
155 | ||||
|
156 | # TEST: ensure we cannot register several flag processors on the same flag | |||
|
157 | $ cat >> .hg/hgrc << EOF | |||
|
158 | > [extensions] | |||
|
159 | > extension=$TESTDIR/flagprocessorext.py | |||
|
160 | > duplicate=$TESTDIR/flagprocessorext.py | |||
|
161 | > EOF | |||
|
162 | $ echo 'this should fail' > file | |||
|
163 | $ hg commit -Aqm 'add file' | |||
|
164 | abort: cannot register multiple processors on flag '0x8'. | |||
|
165 | [255] |
@@ -148,6 +148,9 b' class bundlerevlog(revlog.revlog):' | |||||
148 | delta = self._chunk(chain.pop()) |
|
148 | delta = self._chunk(chain.pop()) | |
149 | text = mdiff.patches(text, [delta]) |
|
149 | text = mdiff.patches(text, [delta]) | |
150 |
|
150 | |||
|
151 | text, validatehash = self._processflags(text, self.flags(rev), | |||
|
152 | 'read', raw=raw) | |||
|
153 | if validatehash: | |||
151 | self.checkhash(text, node, rev=rev) |
|
154 | self.checkhash(text, node, rev=rev) | |
152 | self._cache = (node, rev, text) |
|
155 | self._cache = (node, rev, text) | |
153 | return text |
|
156 | return text |
@@ -55,7 +55,11 b' REVLOGNG_FLAGS = REVLOGNGINLINEDATA | RE' | |||||
55 | # revlog index flags |
|
55 | # revlog index flags | |
56 | REVIDX_ISCENSORED = (1 << 15) # revision has censor metadata, must be verified |
|
56 | REVIDX_ISCENSORED = (1 << 15) # revision has censor metadata, must be verified | |
57 | REVIDX_DEFAULT_FLAGS = 0 |
|
57 | REVIDX_DEFAULT_FLAGS = 0 | |
58 | REVIDX_KNOWN_FLAGS = REVIDX_ISCENSORED |
|
58 | # stable order in which flags need to be processed and their processors applied | |
|
59 | REVIDX_FLAGS_ORDER = [ | |||
|
60 | REVIDX_ISCENSORED, | |||
|
61 | ] | |||
|
62 | REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER) | |||
59 |
|
63 | |||
60 | # max size of revlog with inline data |
|
64 | # max size of revlog with inline data | |
61 | _maxinline = 131072 |
|
65 | _maxinline = 131072 | |
@@ -64,6 +68,41 b' REVIDX_KNOWN_FLAGS = REVIDX_ISCENSORED' | |||||
64 | RevlogError = error.RevlogError |
|
68 | RevlogError = error.RevlogError | |
65 | LookupError = error.LookupError |
|
69 | LookupError = error.LookupError | |
66 | CensoredNodeError = error.CensoredNodeError |
|
70 | CensoredNodeError = error.CensoredNodeError | |
|
71 | ProgrammingError = error.ProgrammingError | |||
|
72 | ||||
|
73 | # Store flag processors (cf. 'addflagprocessor()' to register) | |||
|
74 | _flagprocessors = { | |||
|
75 | REVIDX_ISCENSORED: None, | |||
|
76 | } | |||
|
77 | ||||
|
78 | def addflagprocessor(flag, processor): | |||
|
79 | """Register a flag processor on a revision data flag. | |||
|
80 | ||||
|
81 | Invariant: | |||
|
82 | - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER. | |||
|
83 | - Only one flag processor can be registered on a specific flag. | |||
|
84 | - flagprocessors must be 3-tuples of functions (read, write, raw) with the | |||
|
85 | following signatures: | |||
|
86 | - (read) f(self, text) -> newtext, bool | |||
|
87 | - (write) f(self, text) -> newtext, bool | |||
|
88 | - (raw) f(self, text) -> bool | |||
|
89 | The boolean returned by these transforms is used to determine whether | |||
|
90 | 'newtext' can be used for hash integrity checking. | |||
|
91 | ||||
|
92 | Note: The 'raw' transform is used for changegroup generation and in some | |||
|
93 | debug commands. In this case the transform only indicates whether the | |||
|
94 | contents can be used for hash integrity checks. | |||
|
95 | """ | |||
|
96 | if not flag & REVIDX_KNOWN_FLAGS: | |||
|
97 | msg = _("cannot register processor on unknown flag '%#x'.") % (flag) | |||
|
98 | raise ProgrammingError(msg) | |||
|
99 | if flag not in REVIDX_FLAGS_ORDER: | |||
|
100 | msg = _("flag '%#x' undefined in REVIDX_FLAGS_ORDER.") % (flag) | |||
|
101 | raise ProgrammingError(msg) | |||
|
102 | if flag in _flagprocessors: | |||
|
103 | msg = _("cannot register multiple processors on flag '%#x'.") % (flag) | |||
|
104 | raise error.Abort(msg) | |||
|
105 | _flagprocessors[flag] = processor | |||
67 |
|
106 | |||
68 | def getoffset(q): |
|
107 | def getoffset(q): | |
69 | return int(q >> 16) |
|
108 | return int(q >> 16) | |
@@ -1231,11 +1270,6 b' class revlog(object):' | |||||
1231 | if rev is None: |
|
1270 | if rev is None: | |
1232 | rev = self.rev(node) |
|
1271 | rev = self.rev(node) | |
1233 |
|
1272 | |||
1234 | # check rev flags |
|
|||
1235 | if self.flags(rev) & ~REVIDX_KNOWN_FLAGS: |
|
|||
1236 | raise RevlogError(_('incompatible revision flag %x') % |
|
|||
1237 | (self.flags(rev) & ~REVIDX_KNOWN_FLAGS)) |
|
|||
1238 |
|
||||
1239 | chain, stopped = self._deltachain(rev, stoprev=cachedrev) |
|
1273 | chain, stopped = self._deltachain(rev, stoprev=cachedrev) | |
1240 | if stopped: |
|
1274 | if stopped: | |
1241 | text = self._cache[2] |
|
1275 | text = self._cache[2] | |
@@ -1249,7 +1283,12 b' class revlog(object):' | |||||
1249 | bins = bins[1:] |
|
1283 | bins = bins[1:] | |
1250 |
|
1284 | |||
1251 | text = mdiff.patches(text, bins) |
|
1285 | text = mdiff.patches(text, bins) | |
|
1286 | ||||
|
1287 | text, validatehash = self._processflags(text, self.flags(rev), 'read', | |||
|
1288 | raw=raw) | |||
|
1289 | if validatehash: | |||
1252 | self.checkhash(text, node, rev=rev) |
|
1290 | self.checkhash(text, node, rev=rev) | |
|
1291 | ||||
1253 | self._cache = (node, rev, text) |
|
1292 | self._cache = (node, rev, text) | |
1254 | return text |
|
1293 | return text | |
1255 |
|
1294 | |||
@@ -1261,6 +1300,65 b' class revlog(object):' | |||||
1261 | """ |
|
1300 | """ | |
1262 | return hash(text, p1, p2) |
|
1301 | return hash(text, p1, p2) | |
1263 |
|
1302 | |||
|
1303 | def _processflags(self, text, flags, operation, raw=False): | |||
|
1304 | """Inspect revision data flags and applies transforms defined by | |||
|
1305 | registered flag processors. | |||
|
1306 | ||||
|
1307 | ``text`` - the revision data to process | |||
|
1308 | ``flags`` - the revision flags | |||
|
1309 | ``operation`` - the operation being performed (read or write) | |||
|
1310 | ``raw`` - an optional argument describing if the raw transform should be | |||
|
1311 | applied. | |||
|
1312 | ||||
|
1313 | This method processes the flags in the order (or reverse order if | |||
|
1314 | ``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the | |||
|
1315 | flag processors registered for present flags. The order of flags defined | |||
|
1316 | in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity. | |||
|
1317 | ||||
|
1318 | Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the | |||
|
1319 | processed text and ``validatehash`` is a bool indicating whether the | |||
|
1320 | returned text should be checked for hash integrity. | |||
|
1321 | ||||
|
1322 | Note: If the ``raw`` argument is set, it has precedence over the | |||
|
1323 | operation and will only update the value of ``validatehash``. | |||
|
1324 | """ | |||
|
1325 | if not operation in ('read', 'write'): | |||
|
1326 | raise ProgrammingError(_("invalid '%s' operation ") % (operation)) | |||
|
1327 | # Check all flags are known. | |||
|
1328 | if flags & ~REVIDX_KNOWN_FLAGS: | |||
|
1329 | raise RevlogError(_("incompatible revision flag '%#x'") % | |||
|
1330 | (flags & ~REVIDX_KNOWN_FLAGS)) | |||
|
1331 | validatehash = True | |||
|
1332 | # Depending on the operation (read or write), the order might be | |||
|
1333 | # reversed due to non-commutative transforms. | |||
|
1334 | orderedflags = REVIDX_FLAGS_ORDER | |||
|
1335 | if operation == 'write': | |||
|
1336 | orderedflags = reversed(orderedflags) | |||
|
1337 | ||||
|
1338 | for flag in orderedflags: | |||
|
1339 | # If a flagprocessor has been registered for a known flag, apply the | |||
|
1340 | # related operation transform and update result tuple. | |||
|
1341 | if flag & flags: | |||
|
1342 | vhash = True | |||
|
1343 | ||||
|
1344 | if flag not in _flagprocessors: | |||
|
1345 | message = _("missing processor for flag '%#x'") % (flag) | |||
|
1346 | raise RevlogError(message) | |||
|
1347 | ||||
|
1348 | processor = _flagprocessors[flag] | |||
|
1349 | if processor is not None: | |||
|
1350 | readtransform, writetransform, rawtransform = processor | |||
|
1351 | ||||
|
1352 | if raw: | |||
|
1353 | vhash = rawtransform(self, text) | |||
|
1354 | elif operation == 'read': | |||
|
1355 | text, vhash = readtransform(self, text) | |||
|
1356 | else: # write operation | |||
|
1357 | text, vhash = writetransform(self, text) | |||
|
1358 | validatehash = validatehash and vhash | |||
|
1359 | ||||
|
1360 | return text, validatehash | |||
|
1361 | ||||
1264 | def checkhash(self, text, node, p1=None, p2=None, rev=None): |
|
1362 | def checkhash(self, text, node, p1=None, p2=None, rev=None): | |
1265 | """Check node hash integrity. |
|
1363 | """Check node hash integrity. | |
1266 |
|
1364 | |||
@@ -1345,6 +1443,17 b' class revlog(object):' | |||||
1345 | raise RevlogError(_("attempted to add linkrev -1 to %s") |
|
1443 | raise RevlogError(_("attempted to add linkrev -1 to %s") | |
1346 | % self.indexfile) |
|
1444 | % self.indexfile) | |
1347 |
|
1445 | |||
|
1446 | if flags: | |||
|
1447 | node = node or self.hash(text, p1, p2) | |||
|
1448 | ||||
|
1449 | newtext, validatehash = self._processflags(text, flags, 'write') | |||
|
1450 | ||||
|
1451 | # If the flag processor modifies the revision data, ignore any provided | |||
|
1452 | # cachedelta. | |||
|
1453 | if newtext != text: | |||
|
1454 | cachedelta = None | |||
|
1455 | text = newtext | |||
|
1456 | ||||
1348 | if len(text) > _maxentrysize: |
|
1457 | if len(text) > _maxentrysize: | |
1349 | raise RevlogError( |
|
1458 | raise RevlogError( | |
1350 | _("%s: size of %d bytes exceeds maximum revlog storage of 2GiB") |
|
1459 | _("%s: size of %d bytes exceeds maximum revlog storage of 2GiB") | |
@@ -1354,6 +1463,9 b' class revlog(object):' | |||||
1354 | if node in self.nodemap: |
|
1463 | if node in self.nodemap: | |
1355 | return node |
|
1464 | return node | |
1356 |
|
1465 | |||
|
1466 | if validatehash: | |||
|
1467 | self.checkhash(text, node, p1=p1, p2=p2) | |||
|
1468 | ||||
1357 | dfh = None |
|
1469 | dfh = None | |
1358 | if not self._inline: |
|
1470 | if not self._inline: | |
1359 | dfh = self.opener(self.datafile, "a+") |
|
1471 | dfh = self.opener(self.datafile, "a+") | |
@@ -1448,6 +1560,9 b' class revlog(object):' | |||||
1448 | btext[0] = mdiff.patch(basetext, delta) |
|
1560 | btext[0] = mdiff.patch(basetext, delta) | |
1449 |
|
1561 | |||
1450 | try: |
|
1562 | try: | |
|
1563 | res = self._processflags(btext[0], flags, 'read', raw=raw) | |||
|
1564 | btext[0], validatehash = res | |||
|
1565 | if validatehash: | |||
1451 | self.checkhash(btext[0], node, p1=p1, p2=p2) |
|
1566 | self.checkhash(btext[0], node, p1=p1, p2=p2) | |
1452 | if flags & REVIDX_ISCENSORED: |
|
1567 | if flags & REVIDX_ISCENSORED: | |
1453 | raise RevlogError(_('node %s is not censored') % node) |
|
1568 | raise RevlogError(_('node %s is not censored') % node) |
@@ -138,6 +138,12 b' os.stat_float_times(False)' | |||||
138 | def safehasattr(thing, attr): |
|
138 | def safehasattr(thing, attr): | |
139 | return getattr(thing, attr, _notset) is not _notset |
|
139 | return getattr(thing, attr, _notset) is not _notset | |
140 |
|
140 | |||
|
141 | def bitsfrom(container): | |||
|
142 | bits = 0 | |||
|
143 | for bit in container: | |||
|
144 | bits |= bit | |||
|
145 | return bits | |||
|
146 | ||||
141 | DIGESTS = { |
|
147 | DIGESTS = { | |
142 | 'md5': hashlib.md5, |
|
148 | 'md5': hashlib.md5, | |
143 | 'sha1': hashlib.sha1, |
|
149 | 'sha1': hashlib.sha1, |
General Comments 0
You need to be logged in to leave comments.
Login now