1 # (Be in -*- python -*- mode.)
3 # ====================================================================
4 # Copyright (c) 2000-2009 CollabNet. All rights reserved.
6 # This software is licensed as described in the file COPYING, which
7 # you should have received as part of this distribution. The terms
8 # are also available at http://subversion.tigris.org/license-1.html.
9 # If newer versions of this license are posted there, you may use a
10 # newer version instead, at your option.
12 # This software consists of voluntary contributions made by many
13 # individuals. For exact contribution history, see the revision
14 # history and logs, available at http://cvs2svn.tigris.org/.
15 # ====================================================================
17 """This module contains database facilities used by cvs2svn."""
24 from cvs2svn_lib
.common
import DB_OPEN_NEW
25 from cvs2svn_lib
.common
import warning_prefix
26 from cvs2svn_lib
.common
import error_prefix
27 from cvs2svn_lib
.log
import logger
30 # DBM module selection
32 # 1. If we have bsddb3, it is probably newer than bsddb. Fake bsddb = bsddb3,
33 # so that the dbhash module used by anydbm will use bsddb3.
36 sys
.modules
['bsddb'] = bsddb3
40 # 2. These DBM modules are not good for cvs2svn.
42 if anydbm
._defaultmod
.__name
__ in ['dumbdbm', 'dbm']:
44 '%s: cvs2svn uses the anydbm package, which depends on lower level '
46 'libraries. Your system has %s, with which cvs2svn is known to have\n'
47 'problems. To use cvs2svn, you must install a Python dbm library '
49 'dumbdbm or dbm. See '
50 'http://python.org/doc/current/lib/module-anydbm.html\n'
51 'for more information.\n'
52 % (error_prefix
, anydbm
._defaultmod
.__name
__,)
56 # 3. If we are using the old bsddb185 module, then try prefer gdbm instead.
57 # Unfortunately, gdbm appears not to be trouble free, either.
58 if hasattr(anydbm
._defaultmod
, 'bsddb') \
59 and not hasattr(anydbm
._defaultmod
.bsddb
, '__version__'):
61 gdbm
= __import__('gdbm')
64 '%s: The version of the bsddb module found on your computer '
66 'reported to malfunction on some datasets, causing KeyError '
71 anydbm
._defaultmod
= gdbm
75 """A database that uses a Serializer to store objects of a certain type.
77 The serializer is stored in the database under the key
78 self.serializer_key. (This implies that self.serializer_key may not
79 be used as a key for normal entries.)
81 The backing database is an anydbm-based DBM.
85 serializer_key
= '_.%$1\t;_ '
87 def __init__(self
, filename
, mode
, serializer
=None):
90 The database stores its Serializer, so none needs to be supplied
91 when opening an existing database."""
93 # pybsddb3 has a bug which prevents it from working with
94 # Berkeley DB 4.2 if you open the db with 'n' ("new"). This
95 # causes the DB_TRUNCATE flag to be passed, which is disallowed
96 # for databases protected by lock and transaction support
97 # (bsddb databases use locking from bsddb version 4.2.4 onwards).
99 # Therefore, manually perform the removal (we can do this, because
100 # we know that for bsddb - but *not* anydbm in general - the database
101 # consists of one file with the name we specify, rather than several
102 # based on that name).
103 if mode
== DB_OPEN_NEW
and anydbm
._defaultmod
.__name
__ == 'dbhash':
104 if os
.path
.isfile(filename
):
106 self
.db
= anydbm
.open(filename
, 'c')
108 self
.db
= anydbm
.open(filename
, mode
)
110 # Import implementations for many mapping interface methods.
111 for meth_name
in ('__delitem__',
112 '__iter__', 'has_key', '__contains__', 'iterkeys', 'clear'):
113 meth_ref
= getattr(self
.db
, meth_name
, None)
115 setattr(self
, meth_name
, meth_ref
)
117 if mode
== DB_OPEN_NEW
:
118 self
.serializer
= serializer
119 self
.db
[self
.serializer_key
] = cPickle
.dumps(self
.serializer
)
121 self
.serializer
= cPickle
.loads(self
.db
[self
.serializer_key
])
123 def __getitem__(self
, key
):
124 return self
.serializer
.loads(self
.db
[key
])
126 def __setitem__(self
, key
, value
):
127 self
.db
[key
] = self
.serializer
.dumps(value
)
129 def __delitem__(self
, key
):
130 # gdbm defines a __delitem__ method, but it cannot be assigned. So
131 # this method provides a fallback definition via explicit delegation:
135 retval
= self
.db
.keys()
136 retval
.remove(self
.serializer_key
)
140 for key
in self
.keys():
143 def has_key(self
, key
):
150 def __contains__(self
, key
):
151 return self
.has_key(key
)
154 return self
.__iter
__()
157 for key
in self
.keys():
161 return [(key
, self
[key
],) for key
in self
.keys()]
164 return [self
[key
] for key
in self
.keys()]
166 def get(self
, key
, default
=None):