Fix bug in revid caching.
[jelmer/subvertpy.git] / branchprops.py
1 # Copyright (C) 2006-2007 Jelmer Vernooij <jelmer@samba.org>
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17 """Branch property access and caching."""
18
19 from bzrlib.errors import NoSuchRevision
20 from bzrlib.trace import mutter
21
22 from svn.core import SubversionException, Pool
23 import svn.core
24
25 class BranchPropertyList:
26     def __init__(self, log, cachedb):
27         self.log = log
28         self.cachedb = cachedb
29
30         self.cachedb.executescript("""
31             create table if not exists branchprop (name text, value text, branchpath text, revnum integer);
32             create index if not exists branch_path_revnum on branchprop (branchpath, revnum);
33             create index if not exists branch_path_revnum_name on branchprop (branchpath, revnum, name);
34         """)
35
36         self.pool = Pool()
37
38     def _get_dir_props(self, path, revnum):
39         assert path != None
40         path = path.lstrip("/")
41
42         try:
43             (_, _, props) = self.log.transport.get_dir(path.encode('utf8'), 
44                 revnum, pool=self.pool)
45         except SubversionException, (_, num):
46             if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION:
47                 raise NoSuchRevision(self, revnum)
48             raise
49
50         return props
51
52     def get_properties(self, path, origrevnum):
53         assert path is not None
54         assert isinstance(origrevnum, int) and origrevnum >= 0
55         proplist = {}
56         revnum = self.log.find_latest_change(path, origrevnum)
57         assert revnum is not None, \
58                 "can't find latest change for %r:%r" % (path, origrevnum)
59
60         proplist = {}
61         for (name, value) in self.cachedb.execute("select name, value from branchprop where revnum=%d and branchpath='%s'" % (revnum, path)):
62             proplist[name] = value
63
64         if proplist != {}:
65             return proplist
66
67         proplist = self._get_dir_props(path, revnum)
68         for name in proplist:
69             self.cachedb.execute("insert into branchprop (name, value, revnum, branchpath) values (?,?,?,?)", (name, proplist[name], revnum, path))
70         self.cachedb.commit()
71
72         return proplist
73
74     def get_property(self, path, revnum, name, default=None):
75         assert isinstance(revnum, int)
76         assert isinstance(path, basestring)
77         props = self.get_properties(path, revnum)
78         if props.has_key(name):
79             return props[name]
80         return default
81
82     def get_property_diff(self, path, revnum, name):
83         """Returns the new lines that were added to a particular property."""
84         # If the path this property is set on didn't change, then 
85         # the property can't have changed.
86         if not self.log.touches_path(path, revnum):
87             return ""
88
89         current = self.get_property(path, revnum, name, "")
90         (prev_path, prev_revnum) = self.log.get_previous(path, revnum)
91         if prev_path is None and prev_revnum == -1:
92             previous = ""
93         else:
94             previous = self.get_property(prev_path, prev_revnum, name, "")
95         if len(previous) > len(current) or current[0:len(previous)] != previous:
96             mutter('original part changed!')
97             return ""
98         return current[len(previous):]