##// END OF EJS Templates
filelog: use censored revlog flag bit to quickly check if a node is censored
Mike Edgar -
r23858:22a979d1 default
parent child Browse files
Show More
@@ -1,116 +1,112
1 # filelog.py - file history class for mercurial
1 # filelog.py - file history class for mercurial
2 #
2 #
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, revlog
9 import re
9 import re
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
15 if text[:2] != '\1\n':
15 if text[:2] != '\1\n':
16 return None, None
16 return None, None
17 s = _mdre.search(text, 2).start()
17 s = _mdre.search(text, 2).start()
18 mtext = text[2:s]
18 mtext = text[2:s]
19 meta = {}
19 meta = {}
20 for l in mtext.splitlines():
20 for l in mtext.splitlines():
21 k, v = l.split(": ", 1)
21 k, v = l.split(": ", 1)
22 meta[k] = v
22 meta[k] = v
23 return meta, (s + 2)
23 return meta, (s + 2)
24
24
25 def packmeta(meta, text):
25 def packmeta(meta, text):
26 keys = sorted(meta.iterkeys())
26 keys = sorted(meta.iterkeys())
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 and not text[offs:]
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")))
38
38
39 def read(self, node):
39 def read(self, node):
40 t = self.revision(node)
40 t = self.revision(node)
41 if not t.startswith('\1\n'):
41 if not t.startswith('\1\n'):
42 return t
42 return t
43 s = t.index('\1\n', 2)
43 s = t.index('\1\n', 2)
44 return t[s + 2:]
44 return t[s + 2:]
45
45
46 def add(self, text, meta, transaction, link, p1=None, p2=None):
46 def add(self, text, meta, transaction, link, p1=None, p2=None):
47 if meta or text.startswith('\1\n'):
47 if meta or text.startswith('\1\n'):
48 text = packmeta(meta, text)
48 text = packmeta(meta, text)
49 return self.addrevision(text, transaction, link, p1, p2)
49 return self.addrevision(text, transaction, link, p1, p2)
50
50
51 def renamed(self, node):
51 def renamed(self, node):
52 if self.parents(node)[0] != revlog.nullid:
52 if self.parents(node)[0] != revlog.nullid:
53 return False
53 return False
54 t = self.revision(node)
54 t = self.revision(node)
55 m = parsemeta(t)[0]
55 m = parsemeta(t)[0]
56 if m and "copy" in m:
56 if m and "copy" in m:
57 return (m["copy"], revlog.bin(m["copyrev"]))
57 return (m["copy"], revlog.bin(m["copyrev"]))
58 return False
58 return False
59
59
60 def size(self, rev):
60 def size(self, rev):
61 """return the size of a given revision"""
61 """return the size of a given revision"""
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
73 def cmp(self, node, text):
73 def cmp(self, node, text):
74 """compare text with a given file revision
74 """compare text with a given file revision
75
75
76 returns True if text is different than what is stored.
76 returns True if text is different than what is stored.
77 """
77 """
78
78
79 t = text
79 t = text
80 if text.startswith('\1\n'):
80 if text.startswith('\1\n'):
81 t = '\1\n\1\n' + text
81 t = '\1\n\1\n' + text
82
82
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(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):
94 t2 = self.read(node)
94 t2 = self.read(node)
95 return t2 != text
95 return t2 != text
96
96
97 return True
97 return True
98
98
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)
105 raise
105 raise
106
106
107 def _file(self, f):
107 def _file(self, f):
108 return filelog(self.opener, f)
108 return filelog(self.opener, f)
109
109
110 def _iscensored(self, revornode):
110 def _iscensored(self, rev):
111 """Check if a file revision is censored."""
111 """Check if a file revision is censored."""
112 try:
112 return self.flags(rev) & revlog.REVIDX_ISCENSORED
113 self.revision(revornode)
114 return False
115 except error.CensoredNodeError:
116 return True
General Comments 0
You need to be logged in to leave comments. Login now