1 # Copyright (C) 2006-2007 Jelmer Vernooij <jelmer@samba.org>
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.
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.
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
17 """Branch property access and caching."""
19 from bzrlib.errors import NoSuchRevision
20 from bzrlib.trace import mutter
22 from svn.core import SubversionException, Pool
25 class BranchPropertyList:
26 """Simple class that retrieves file properties set on branches."""
27 def __init__(self, log, cachedb):
29 self.cachedb = cachedb
31 self.cachedb.executescript("""
32 create table if not exists branchprop (name text, value text, branchpath text, revnum integer);
33 create index if not exists branch_path_revnum on branchprop (branchpath, revnum);
34 create index if not exists branch_path_revnum_name on branchprop (branchpath, revnum, name);
39 def _get_dir_props(self, path, revnum):
40 """Obtain all the directory properties set on a path/revnum pair.
42 :param path: Subversion path
43 :param revnum: Subversion revision number
44 :return: Dictionary with properties
46 assert isinstance(path, str)
47 path = path.lstrip("/")
50 (_, _, props) = self.log._get_transport().get_dir(path,
51 revnum, pool=self.pool)
52 except SubversionException, (_, num):
53 if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION:
54 raise NoSuchRevision(self, revnum)
59 def get_properties(self, path, origrevnum):
60 """Obtain the file properties set on a path/revnum pair.
64 :param path: Subversion path.
65 :param origrevnum: Subversion revision number.
66 :return: Dictionary with properties
68 assert path is not None
69 assert isinstance(path, str)
70 assert isinstance(origrevnum, int) and origrevnum >= 0
71 revnum = self.log.find_latest_change(path, origrevnum,
73 assert revnum is not None, \
74 "can't find latest change for %r:%r" % (path, origrevnum)
76 if revnum == 0: # no properties are set in revision 0
80 for (name, value) in self.cachedb.execute("select name, value from branchprop where revnum=%d and branchpath='%s'" % (revnum, path)):
81 proplist[name] = value.encode("utf-8")
86 proplist = self._get_dir_props(path, revnum)
88 self.cachedb.execute("insert into branchprop (name, value, revnum, branchpath) values (?,?,?,?)", (name, proplist[name], revnum, path))
93 def get_property(self, path, revnum, name, default=None):
94 """Get the contents of a Subversion file property.
98 :param path: Subversion path.
99 :param revnum: Subversion revision number.
100 :param default: Default value to return if property wasn't found.
101 :return: Contents of property or default if property didn't exist.
103 assert isinstance(revnum, int)
104 assert isinstance(path, str)
105 props = self.get_properties(path, revnum)
106 if props.has_key(name):
110 def touches_property(self, path, revnum, name):
111 """Check whether a property was modified in a revision."""
112 assert isinstance(path, str)
113 assert isinstance(revnum, int)
114 assert isinstance(name, str)
115 # If the path this property is set on didn't change, then
116 # the property can't have changed.
117 if not self.log.touches_path(path, revnum):
120 current = self.get_property(path, revnum, name, None)
121 (prev_path, prev_revnum) = self.log.get_previous(path, revnum)
122 if prev_path is None and prev_revnum == -1:
123 return (current is not None)
124 previous = self.get_property(prev_path.encode("utf-8"),
125 prev_revnum, name, None)
126 return (previous != current)
128 def get_property_diff(self, path, revnum, name):
129 """Returns the new lines that were added to a particular property."""
130 assert isinstance(path, str)
131 # If the path this property is set on didn't change, then
132 # the property can't have changed.
133 if not self.log.touches_path(path, revnum):
136 current = self.get_property(path, revnum, name, "")
137 (prev_path, prev_revnum) = self.log.get_previous(path, revnum)
138 if prev_path is None and prev_revnum == -1:
141 previous = self.get_property(prev_path.encode("utf-8"),
142 prev_revnum, name, "")
143 if len(previous) > len(current) or current[0:len(previous)] != previous:
144 mutter('original part changed for %r between %s:%d -> %s:%d' % (name, prev_path, prev_revnum, path, revnum))
146 return current[len(previous):]