Show More
@@ -0,0 +1,41 b'' | |||
|
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 b' from __future__ import absolute_import' | |||
|
16 | 16 | import collections |
|
17 | 17 | import contextlib |
|
18 | 18 | import errno |
|
19 | import hashlib | |
|
20 | 19 | import os |
|
21 | 20 | import re |
|
22 | 21 | import struct |
@@ -74,6 +73,7 b' from .revlogutils import (' | |||
|
74 | 73 | ) |
|
75 | 74 | from .utils import ( |
|
76 | 75 | interfaceutil, |
|
76 | storageutil, | |
|
77 | 77 | stringutil, |
|
78 | 78 | ) |
|
79 | 79 | |
@@ -197,33 +197,6 b' def offset_type(offset, type):' | |||
|
197 | 197 | raise ValueError('unknown revlog index flags') |
|
198 | 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 | 200 | @attr.s(slots=True, frozen=True) |
|
228 | 201 | class _revisioninfo(object): |
|
229 | 202 | """Information about a revision that allows building its fulltext |
@@ -1383,7 +1356,7 b' class revlog(object):' | |||
|
1383 | 1356 | returns True if text is different than what is stored. |
|
1384 | 1357 | """ |
|
1385 | 1358 | p1, p2 = self.parents(node) |
|
1386 | return hash(text, p1, p2) != node | |
|
1359 | return storageutil.hashrevisionsha1(text, p1, p2) != node | |
|
1387 | 1360 | |
|
1388 | 1361 | def _cachesegment(self, offset, data): |
|
1389 | 1362 | """Add a segment to the revlog cache. |
@@ -1672,7 +1645,7 b' class revlog(object):' | |||
|
1672 | 1645 | Available as a function so that subclasses can replace the hash |
|
1673 | 1646 | as needed. |
|
1674 | 1647 | """ |
|
1675 | return hash(text, p1, p2) | |
|
1648 | return storageutil.hashrevisionsha1(text, p1, p2) | |
|
1676 | 1649 | |
|
1677 | 1650 | def _processflags(self, text, flags, operation, raw=False): |
|
1678 | 1651 | """Inspect revision data flags and applies transforms defined by |
@@ -40,6 +40,7 b' from mercurial import (' | |||
|
40 | 40 | ) |
|
41 | 41 | from mercurial.utils import ( |
|
42 | 42 | interfaceutil, |
|
43 | storageutil, | |
|
43 | 44 | ) |
|
44 | 45 | |
|
45 | 46 | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for |
@@ -285,7 +286,7 b' class filestorage(object):' | |||
|
285 | 286 | def checkhash(self, text, node, p1=None, p2=None, rev=None): |
|
286 | 287 | if p1 is None and p2 is None: |
|
287 | 288 | p1, p2 = self.parents(node) |
|
288 |
if node != |
|
|
289 | if node != storageutil.hashrevisionsha1(text, p1, p2): | |
|
289 | 290 | raise simplestoreerror(_("integrity check failed on %s") % |
|
290 | 291 | self._path) |
|
291 | 292 | |
@@ -342,7 +343,7 b' class filestorage(object):' | |||
|
342 | 343 | |
|
343 | 344 | p1, p2 = self.parents(node) |
|
344 | 345 | |
|
345 |
if |
|
|
346 | if storageutil.hashrevisionsha1(t, p1, p2) == node: | |
|
346 | 347 | return False |
|
347 | 348 | |
|
348 | 349 | if self.iscensored(self.rev(node)): |
@@ -420,11 +421,11 b' class filestorage(object):' | |||
|
420 | 421 | validatenode(p2) |
|
421 | 422 | |
|
422 | 423 | if flags: |
|
423 |
node = node or |
|
|
424 | node = node or storageutil.hashrevisionsha1(text, p1, p2) | |
|
424 | 425 | |
|
425 | 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 | 430 | if node in self._indexbynode: |
|
430 | 431 | return node |
General Comments 0
You need to be logged in to leave comments.
Login now