Fix svk:merge imports.
[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 isinstance(path, str)
40         path = path.lstrip("/")
41
42         try:
43             (_, _, props) = self.log.transport.get_dir(path, 
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(path, str)
55         assert isinstance(origrevnum, int) and origrevnum >= 0
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         if revnum == 0: # no properties are set in revision 0
61             return {}
62
63         proplist = {}
64         for (name, value) in self.cachedb.execute("select name, value from branchprop where revnum=%d and branchpath='%s'" % (revnum, path)):
65             proplist[name] = value.encode("utf-8")
66
67         if proplist != {}:
68             return proplist
69
70         proplist = self._get_dir_props(path, revnum)
71         for name in proplist:
72             self.cachedb.execute("insert into branchprop (name, value, revnum, branchpath) values (?,?,?,?)", (name, proplist[name], revnum, path))
73         self.cachedb.commit()
74
75         return proplist
76
77     def get_property(self, path, revnum, name, default=None):
78         assert isinstance(revnum, int)
79         assert isinstance(path, str)
80         props = self.get_properties(path, revnum)
81         if props.has_key(name):
82             return props[name]
83         return default
84
85     def get_property_diff(self, path, revnum, name):
86         """Returns the new lines that were added to a particular property."""
87         assert isinstance(path, str)
88         # If the path this property is set on didn't change, then 
89         # the property can't have changed.
90         if not self.log.touches_path(path, revnum):
91             return ""
92
93         current = self.get_property(path, revnum, name, "")
94         (prev_path, prev_revnum) = self.log.get_previous(path, revnum)
95         if prev_path is None and prev_revnum == -1:
96             previous = ""
97         else:
98             previous = self.get_property(prev_path.encode("utf-8"), 
99                                          prev_revnum, name, "")
100         if len(previous) > len(current) or current[0:len(previous)] != previous:
101             mutter('original part changed for %r between %s:%d -> %s:%d' % (name, prev_path, prev_revnum, path, revnum))
102             return ""
103         return current[len(previous):]