Show More
@@ -0,0 +1,41 | |||||
|
1 | # storageutil.py - Storage functionality agnostic of backend implementation. | |||
|
2 | # | |||
|
3 | # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com> | |||
|
4 | # | |||
|
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. | |||
|
7 | ||||
|
8 | from __future__ import absolute_import | |||
|
9 | ||||
|
10 | import hashlib | |||
|
11 | ||||
|
12 | from ..node import ( | |||
|
13 | nullid, | |||
|
14 | ) | |||
|
15 | ||||
|
16 | _nullhash = hashlib.sha1(nullid) | |||
|
17 | ||||
|
18 | def hashrevisionsha1(text, p1, p2): | |||
|
19 | """Compute the SHA-1 for revision data and its parents. | |||
|
20 | ||||
|
21 | This hash combines both the current file contents and its history | |||
|
22 | in a manner that makes it easy to distinguish nodes with the same | |||
|
23 | content in the revision graph. | |||
|
24 | """ | |||
|
25 | # As of now, if one of the parent node is null, p2 is null | |||
|
26 | if p2 == nullid: | |||
|
27 | # deep copy of a hash is faster than creating one | |||
|
28 | s = _nullhash.copy() | |||
|
29 | s.update(p1) | |||
|
30 | else: | |||
|
31 | # none of the parent nodes are nullid | |||
|
32 | if p1 < p2: | |||
|
33 | a = p1 | |||
|
34 | b = p2 | |||
|
35 | else: | |||
|
36 | a = p2 | |||
|
37 | b = p1 | |||
|
38 | s = hashlib.sha1(a) | |||
|
39 | s.update(b) | |||
|
40 | s.update(text) | |||
|
41 | return s.digest() |
@@ -16,7 +16,6 from __future__ import absolute_import | |||||
16 | import collections |
|
16 | import collections | |
17 | import contextlib |
|
17 | import contextlib | |
18 | import errno |
|
18 | import errno | |
19 | import hashlib |
|
|||
20 | import os |
|
19 | import os | |
21 | import re |
|
20 | import re | |
22 | import struct |
|
21 | import struct | |
@@ -74,6 +73,7 from .revlogutils import ( | |||||
74 | ) |
|
73 | ) | |
75 | from .utils import ( |
|
74 | from .utils import ( | |
76 | interfaceutil, |
|
75 | interfaceutil, | |
|
76 | storageutil, | |||
77 | stringutil, |
|
77 | stringutil, | |
78 | ) |
|
78 | ) | |
79 |
|
79 | |||
@@ -197,33 +197,6 def offset_type(offset, type): | |||||
197 | raise ValueError('unknown revlog index flags') |
|
197 | raise ValueError('unknown revlog index flags') | |
198 | return int(int(offset) << 16 | type) |
|
198 | return int(int(offset) << 16 | type) | |
199 |
|
199 | |||
200 | _nullhash = hashlib.sha1(nullid) |
|
|||
201 |
|
||||
202 | def hash(text, p1, p2): |
|
|||
203 | """generate a hash from the given text and its parent hashes |
|
|||
204 |
|
||||
205 | This hash combines both the current file contents and its history |
|
|||
206 | in a manner that makes it easy to distinguish nodes with the same |
|
|||
207 | content in the revision graph. |
|
|||
208 | """ |
|
|||
209 | # As of now, if one of the parent node is null, p2 is null |
|
|||
210 | if p2 == nullid: |
|
|||
211 | # deep copy of a hash is faster than creating one |
|
|||
212 | s = _nullhash.copy() |
|
|||
213 | s.update(p1) |
|
|||
214 | else: |
|
|||
215 | # none of the parent nodes are nullid |
|
|||
216 | if p1 < p2: |
|
|||
217 | a = p1 |
|
|||
218 | b = p2 |
|
|||
219 | else: |
|
|||
220 | a = p2 |
|
|||
221 | b = p1 |
|
|||
222 | s = hashlib.sha1(a) |
|
|||
223 | s.update(b) |
|
|||
224 | s.update(text) |
|
|||
225 | return s.digest() |
|
|||
226 |
|
||||
227 | @attr.s(slots=True, frozen=True) |
|
200 | @attr.s(slots=True, frozen=True) | |
228 | class _revisioninfo(object): |
|
201 | class _revisioninfo(object): | |
229 | """Information about a revision that allows building its fulltext |
|
202 | """Information about a revision that allows building its fulltext | |
@@ -1383,7 +1356,7 class revlog(object): | |||||
1383 | returns True if text is different than what is stored. |
|
1356 | returns True if text is different than what is stored. | |
1384 | """ |
|
1357 | """ | |
1385 | p1, p2 = self.parents(node) |
|
1358 | p1, p2 = self.parents(node) | |
1386 | return hash(text, p1, p2) != node |
|
1359 | return storageutil.hashrevisionsha1(text, p1, p2) != node | |
1387 |
|
1360 | |||
1388 | def _cachesegment(self, offset, data): |
|
1361 | def _cachesegment(self, offset, data): | |
1389 | """Add a segment to the revlog cache. |
|
1362 | """Add a segment to the revlog cache. | |
@@ -1672,7 +1645,7 class revlog(object): | |||||
1672 | Available as a function so that subclasses can replace the hash |
|
1645 | Available as a function so that subclasses can replace the hash | |
1673 | as needed. |
|
1646 | as needed. | |
1674 | """ |
|
1647 | """ | |
1675 | return hash(text, p1, p2) |
|
1648 | return storageutil.hashrevisionsha1(text, p1, p2) | |
1676 |
|
1649 | |||
1677 | def _processflags(self, text, flags, operation, raw=False): |
|
1650 | def _processflags(self, text, flags, operation, raw=False): | |
1678 | """Inspect revision data flags and applies transforms defined by |
|
1651 | """Inspect revision data flags and applies transforms defined by |
@@ -40,6 +40,7 from mercurial import ( | |||||
40 | ) |
|
40 | ) | |
41 | from mercurial.utils import ( |
|
41 | from mercurial.utils import ( | |
42 | interfaceutil, |
|
42 | interfaceutil, | |
|
43 | storageutil, | |||
43 | ) |
|
44 | ) | |
44 |
|
45 | |||
45 | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for |
|
46 | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for | |
@@ -285,7 +286,7 class filestorage(object): | |||||
285 | def checkhash(self, text, node, p1=None, p2=None, rev=None): |
|
286 | def checkhash(self, text, node, p1=None, p2=None, rev=None): | |
286 | if p1 is None and p2 is None: |
|
287 | if p1 is None and p2 is None: | |
287 | p1, p2 = self.parents(node) |
|
288 | p1, p2 = self.parents(node) | |
288 |
if node != |
|
289 | if node != storageutil.hashrevisionsha1(text, p1, p2): | |
289 | raise simplestoreerror(_("integrity check failed on %s") % |
|
290 | raise simplestoreerror(_("integrity check failed on %s") % | |
290 | self._path) |
|
291 | self._path) | |
291 |
|
292 | |||
@@ -342,7 +343,7 class filestorage(object): | |||||
342 |
|
343 | |||
343 | p1, p2 = self.parents(node) |
|
344 | p1, p2 = self.parents(node) | |
344 |
|
345 | |||
345 |
if |
|
346 | if storageutil.hashrevisionsha1(t, p1, p2) == node: | |
346 | return False |
|
347 | return False | |
347 |
|
348 | |||
348 | if self.iscensored(self.rev(node)): |
|
349 | if self.iscensored(self.rev(node)): | |
@@ -420,11 +421,11 class filestorage(object): | |||||
420 | validatenode(p2) |
|
421 | validatenode(p2) | |
421 |
|
422 | |||
422 | if flags: |
|
423 | if flags: | |
423 |
node = node or |
|
424 | node = node or storageutil.hashrevisionsha1(text, p1, p2) | |
424 |
|
425 | |||
425 | rawtext, validatehash = self._processflags(text, flags, 'write') |
|
426 | rawtext, validatehash = self._processflags(text, flags, 'write') | |
426 |
|
427 | |||
427 |
node = node or |
|
428 | node = node or storageutil.hashrevisionsha1(text, p1, p2) | |
428 |
|
429 | |||
429 | if node in self._indexbynode: |
|
430 | if node in self._indexbynode: | |
430 | return node |
|
431 | return node |
General Comments 0
You need to be logged in to leave comments.
Login now