1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
# Copyright 2005-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
# Author(s): Brian Harring (ferringb@gentoo.org)
import dbm
try:
import dbm.gnu as gdbm
except ImportError:
gdbm = None
import pickle
from portage import _unicode_encode
from portage import os
from portage.cache import fs_template
from portage.cache import cache_errors
class database(fs_template.FsBased):
validation_chf = "md5"
chf_types = ("md5", "mtime")
autocommits = True
cleanse_keys = True
serialize_eclasses = False
def __init__(self, *args, **config):
super().__init__(*args, **config)
default_db = config.get("dbtype", "anydbm")
if not default_db.startswith("."):
default_db = "." + default_db
self._db_path = os.path.join(
self.location, fs_template.gen_label(self.location, self.label) + default_db
)
self.__db = None
mode = "w"
if dbm.whichdb(self._db_path) in ("dbm.gnu", "gdbm"):
# Allow multiple concurrent writers (see bug #53607).
mode += "u"
try:
# dbm.open() will not work with bytes in python-3.1:
# TypeError: can't concat bytes to str
self.__db = dbm.open(self._db_path, mode, self._perms)
except dbm.error:
# XXX handle this at some point
try:
self._ensure_dirs()
self._ensure_dirs(self._db_path)
except OSError as e:
raise cache_errors.InitializationError(self.__class__, e)
# try again if failed
try:
if self.__db is None:
# dbm.open() will not work with bytes in python-3.1:
# TypeError: can't concat bytes to str
if gdbm is None:
self.__db = dbm.open(self._db_path, "c", self._perms)
else:
# Prefer gdbm type if available, since it allows
# multiple concurrent writers (see bug #53607).
self.__db = gdbm.open(self._db_path, "cu", self._perms)
except dbm.error as e:
raise cache_errors.InitializationError(self.__class__, e)
self._ensure_access(self._db_path)
def __getstate__(self):
state = self.__dict__.copy()
# These attributes are not picklable, so they are automatically
# regenerated after unpickling.
state["_database__db"] = None
return state
def __setstate__(self, state):
self.__dict__.update(state)
mode = "w"
if dbm.whichdb(self._db_path) in ("dbm.gnu", "gdbm"):
# Allow multiple concurrent writers (see bug #53607).
mode += "u"
self.__db = dbm.open(self._db_path, mode, self._perms)
def iteritems(self):
# dbm doesn't implement items()
for k in self.__db.keys():
yield (k, self[k])
def _getitem(self, cpv):
# we override getitem because it's just a cpickling of the data handed in.
return pickle.loads(self.__db[_unicode_encode(cpv)])
def _setitem(self, cpv, values):
self.__db[_unicode_encode(cpv)] = pickle.dumps(values, pickle.HIGHEST_PROTOCOL)
def _delitem(self, cpv):
del self.__db[cpv]
def __iter__(self):
return iter(list(self.__db.keys()))
def __contains__(self, cpv):
return cpv in self.__db
def __del__(self):
if "__db" in self.__dict__ and self.__db is not None:
self.__db.sync()
self.__db.close()
# TODO: do we need iteritems()?
items = iteritems
|