Fix bug in revid caching.
[jelmer/subvertpy.git] / revids.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 from bzrlib.errors import (InvalidRevisionId, NoSuchRevision, 
18                            NotBranchError, UninitializableFormat)
19
20 MAPPING_VERSION = 3
21 REVISION_ID_PREFIX = "svn-v%d-" % MAPPING_VERSION
22
23 import urllib
24
25 def escape_svn_path(x):
26     if isinstance(x, unicode):
27         x = x.encode("utf-8")
28     return urllib.quote(x, "")
29 unescape_svn_path = urllib.unquote
30
31
32 def parse_svn_revision_id(revid):
33     """Parse an existing Subversion-based revision id.
34
35     :param revid: The revision id.
36     :raises: InvalidRevisionId
37     :return: Tuple with uuid, branch path and revision number.
38     """
39
40     assert revid is not None
41     assert isinstance(revid, basestring)
42
43     if not revid.startswith(REVISION_ID_PREFIX):
44         raise InvalidRevisionId(revid, "")
45
46     try:
47         (version, uuid, branch_path, srevnum)= revid.split(":")
48     except ValueError:
49         raise InvalidRevisionId(revid, "")
50
51     revid = revid[len(REVISION_ID_PREFIX):]
52
53     return (uuid, unescape_svn_path(branch_path), int(srevnum))
54
55
56 def generate_svn_revision_id(uuid, revnum, path, scheme="undefined"):
57     """Generate a unambiguous revision id. 
58     
59     :param uuid: UUID of the repository.
60     :param revnum: Subversion revision number.
61     :param path: Branch path.
62     :param scheme: Name of the branching scheme in use
63
64     :return: New revision id.
65     """
66     assert isinstance(revnum, int)
67     assert isinstance(path, basestring)
68     assert revnum >= 0
69     assert revnum > 0 or path == "", \
70             "Trying to generate revid for (%r,%r)" % (path, revnum)
71     return "%s%s:%s:%s:%d" % (REVISION_ID_PREFIX, scheme, uuid, \
72                    escape_svn_path(path.strip("/")), revnum)
73
74
75 class RevidMap(object):
76     """Revision id mapping store. 
77
78     Stores mapping from revid -> (path, revnum, scheme)
79     """
80     def __init__(self, cache_db=None):
81         if cache_db is None:
82             from cache import sqlite3
83             self.cachedb = sqlite3.connect(":memory:")
84         else:
85             self.cachedb = cache_db
86         self.cachedb.executescript("""
87         create table if not exists revmap (revid text, path text, min_revnum integer, max_revnum integer, scheme text);
88         create index if not exists revid on revmap (revid);
89         """)
90         self.cachedb.commit()
91     
92     def lookup_revid(self, revid):
93         ret = self.cachedb.execute(
94             "select path, min_revnum, max_revnum, scheme from revmap where revid='%s'" % revid).fetchone()
95         if ret is None:
96             raise NoSuchRevision(self, revid)
97         return (str(ret[0]), ret[1], ret[2], ret[3])
98
99     def lookup_branch_revnum(self, revnum, path):
100         # FIXME: SCHEME MISSING
101         revid = self.cachedb.execute(
102                 "select revid from revmap where max_revnum = min_revnum and min_revnum='%s' and path='%s'" % (revnum, path)).fetchone()
103         if revid is not None:
104             return str(revid[0])
105         return None
106
107     def insert_revid(self, revid, branch, min_revnum, max_revnum, scheme):
108         assert revid is not None and revid != ""
109         self.cachedb.execute("insert into revmap (revid, path, min_revnum, max_revnum, scheme) VALUES (?, ?, ?, ?, ?)", (revid, branch, min_revnum, max_revnum, scheme))