Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/filelog.py @ 24803:e89f909edffa stable 3.4-rc
merge default into stable for 3.4 freeze
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Thu, 16 Apr 2015 20:57:51 -0500 |
parents | 4bfe9f2d9761 |
children | 34bd1a5eef5b |
comparison
equal
deleted
inserted
replaced
24753:612ed41ae359 | 24803:e89f909edffa |
---|---|
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> | 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> |
4 # | 4 # |
5 # This software may be used and distributed according to the terms of the | 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. | 6 # GNU General Public License version 2 or any later version. |
7 | 7 |
8 import error, revlog | 8 import error, mdiff, revlog |
9 import re | 9 import re, struct |
10 | 10 |
11 _mdre = re.compile('\1\n') | 11 _mdre = re.compile('\1\n') |
12 def parsemeta(text): | 12 def parsemeta(text): |
13 """return (metadatadict, keylist, metadatasize)""" | 13 """return (metadatadict, keylist, metadatasize)""" |
14 # text can be buffer, so we can't use .startswith or .index | 14 # text can be buffer, so we can't use .startswith or .index |
27 metatext = "".join("%s: %s\n" % (k, meta[k]) for k in keys) | 27 metatext = "".join("%s: %s\n" % (k, meta[k]) for k in keys) |
28 return "\1\n%s\1\n%s" % (metatext, text) | 28 return "\1\n%s\1\n%s" % (metatext, text) |
29 | 29 |
30 def _censoredtext(text): | 30 def _censoredtext(text): |
31 m, offs = parsemeta(text) | 31 m, offs = parsemeta(text) |
32 return m and "censored" in m and not text[offs:] | 32 return m and "censored" in m |
33 | 33 |
34 class filelog(revlog.revlog): | 34 class filelog(revlog.revlog): |
35 def __init__(self, opener, path): | 35 def __init__(self, opener, path): |
36 super(filelog, self).__init__(opener, | 36 super(filelog, self).__init__(opener, |
37 "/".join(("data", path + ".i"))) | 37 "/".join(("data", path + ".i"))) |
62 | 62 |
63 # for revisions with renames, we have to go the slow way | 63 # for revisions with renames, we have to go the slow way |
64 node = self.node(rev) | 64 node = self.node(rev) |
65 if self.renamed(node): | 65 if self.renamed(node): |
66 return len(self.read(node)) | 66 return len(self.read(node)) |
67 if self._iscensored(rev): | 67 if self.iscensored(rev): |
68 return 0 | 68 return 0 |
69 | 69 |
70 # XXX if self.read(node).startswith("\1\n"), this returns (size+4) | 70 # XXX if self.read(node).startswith("\1\n"), this returns (size+4) |
71 return super(filelog, self).size(rev) | 71 return super(filelog, self).size(rev) |
72 | 72 |
83 samehashes = not super(filelog, self).cmp(node, t) | 83 samehashes = not super(filelog, self).cmp(node, t) |
84 if samehashes: | 84 if samehashes: |
85 return False | 85 return False |
86 | 86 |
87 # censored files compare against the empty file | 87 # censored files compare against the empty file |
88 if self._iscensored(self.rev(node)): | 88 if self.iscensored(self.rev(node)): |
89 return text != '' | 89 return text != '' |
90 | 90 |
91 # renaming a file produces a different hash, even if the data | 91 # renaming a file produces a different hash, even if the data |
92 # remains unchanged. Check if it's the case (slow): | 92 # remains unchanged. Check if it's the case (slow): |
93 if self.renamed(node): | 93 if self.renamed(node): |
99 def checkhash(self, text, p1, p2, node, rev=None): | 99 def checkhash(self, text, p1, p2, node, rev=None): |
100 try: | 100 try: |
101 super(filelog, self).checkhash(text, p1, p2, node, rev=rev) | 101 super(filelog, self).checkhash(text, p1, p2, node, rev=rev) |
102 except error.RevlogError: | 102 except error.RevlogError: |
103 if _censoredtext(text): | 103 if _censoredtext(text): |
104 raise error.CensoredNodeError(self.indexfile, node) | 104 raise error.CensoredNodeError(self.indexfile, node, text) |
105 raise | 105 raise |
106 | 106 |
107 def _file(self, f): | 107 def iscensored(self, rev): |
108 return filelog(self.opener, f) | |
109 | |
110 def _iscensored(self, rev): | |
111 """Check if a file revision is censored.""" | 108 """Check if a file revision is censored.""" |
112 return self.flags(rev) & revlog.REVIDX_ISCENSORED | 109 return self.flags(rev) & revlog.REVIDX_ISCENSORED |
110 | |
111 def _peek_iscensored(self, baserev, delta, flush): | |
112 """Quickly check if a delta produces a censored revision.""" | |
113 # Fragile heuristic: unless new file meta keys are added alphabetically | |
114 # preceding "censored", all censored revisions are prefixed by | |
115 # "\1\ncensored:". A delta producing such a censored revision must be a | |
116 # full-replacement delta, so we inspect the first and only patch in the | |
117 # delta for this prefix. | |
118 hlen = struct.calcsize(">lll") | |
119 if len(delta) <= hlen: | |
120 return False | |
121 | |
122 oldlen = self.rawsize(baserev) | |
123 newlen = len(delta) - hlen | |
124 if delta[:hlen] != mdiff.replacediffheader(oldlen, newlen): | |
125 return False | |
126 | |
127 add = "\1\ncensored:" | |
128 addlen = len(add) | |
129 return newlen >= addlen and delta[hlen:hlen + addlen] == add |