1############################################################################## 2# 3# Copyright (c) 2001, 2002 Zope Foundation and Contributors. 4# All Rights Reserved. 5# 6# This software is subject to the provisions of the Zope Public License, 7# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. 8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED 9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 11# FOR A PARTICULAR PURPOSE 12# 13############################################################################## 14"""Open database and storage from a configuration.""" 15import os 16import ZConfig 17import ZODB 18 19try: 20 from cStringIO import StringIO 21except ImportError: 22 # Py3 23 from io import StringIO 24 25 26db_schema_path = os.path.join(ZODB.__path__[0], "config.xml") 27_db_schema = None 28 29s_schema_path = os.path.join(ZODB.__path__[0], "storage.xml") 30_s_schema = None 31 32def getDbSchema(): 33 global _db_schema 34 if _db_schema is None: 35 _db_schema = ZConfig.loadSchema(db_schema_path) 36 return _db_schema 37 38def getStorageSchema(): 39 global _s_schema 40 if _s_schema is None: 41 _s_schema = ZConfig.loadSchema(s_schema_path) 42 return _s_schema 43 44def databaseFromString(s): 45 """Create a database from a database-configuration string. 46 47 The string must contain one or more :ref:`zodb 48 <database-text-configuration>` sections. 49 50 The database defined by the first section is returned. 51 52 If :ref:`more than one zodb section is provided 53 <multidatabase-text-configuration>`, a multi-database 54 configuration will be created and all of the databases will be 55 available in the returned database's ``databases`` attribute. 56 """ 57 return databaseFromFile(StringIO(s)) 58 59def databaseFromFile(f): 60 """Create a database from a file object that provides configuration. 61 62 See :func:`databaseFromString`. 63 """ 64 config, handle = ZConfig.loadConfigFile(getDbSchema(), f) 65 return databaseFromConfig(config.database) 66 67def databaseFromURL(url): 68 """Load a database from URL (or file name) that provides configuration. 69 70 See :func:`databaseFromString`. 71 """ 72 config, handler = ZConfig.loadConfig(getDbSchema(), url) 73 return databaseFromConfig(config.database) 74 75def databaseFromConfig(database_factories): 76 databases = {} 77 first = None 78 for factory in database_factories: 79 db = factory.open(databases) 80 if first is None: 81 first = db 82 83 return first 84 85def storageFromString(s): 86 """Create a storage from a storage-configuration string. 87 """ 88 return storageFromFile(StringIO(s)) 89 90def storageFromFile(f): 91 """Create a storage from a file object providing storage-configuration. 92 """ 93 config, handle = ZConfig.loadConfigFile(getStorageSchema(), f) 94 return storageFromConfig(config.storage) 95 96def storageFromURL(url): 97 """\ 98 Create a storage from a URL (or file name) providing storage-configuration. 99 """ 100 config, handler = ZConfig.loadConfig(getStorageSchema(), url) 101 return storageFromConfig(config.storage) 102 103def storageFromConfig(section): 104 return section.open() 105 106class BaseConfig(object): 107 """Object representing a configured storage or database. 108 109 Methods: 110 111 open() -- open and return the configured object 112 113 Attributes: 114 115 name -- name of the storage 116 117 """ 118 119 def __init__(self, config): 120 self.config = config 121 self.name = config.getSectionName() 122 123 def open(self, database_name='unnamed', databases=None): 124 """Open and return the storage object.""" 125 raise NotImplementedError 126 127class ZODBDatabase(BaseConfig): 128 129 def open(self, databases=None): 130 section = self.config 131 storage = section.storage.open() 132 options = {} 133 134 def _option(name, oname=None): 135 v = getattr(section, name) 136 if v is not None: 137 if oname is None: 138 oname = name 139 options[oname] = v 140 141 _option('pool_timeout') 142 _option('allow_implicit_cross_references', 'xrefs') 143 _option('large_record_size') 144 145 try: 146 return ZODB.DB( 147 storage, 148 pool_size=section.pool_size, 149 cache_size=section.cache_size, 150 cache_size_bytes=section.cache_size_bytes, 151 historical_pool_size=section.historical_pool_size, 152 historical_cache_size=section.historical_cache_size, 153 historical_cache_size_bytes=section.historical_cache_size_bytes, 154 historical_timeout=section.historical_timeout, 155 database_name=section.database_name or self.name or '', 156 databases=databases, 157 **options) 158 except: 159 storage.close() 160 raise 161 162class MappingStorage(BaseConfig): 163 164 def open(self): 165 from ZODB.MappingStorage import MappingStorage 166 return MappingStorage(self.config.name) 167 168class DemoStorage(BaseConfig): 169 170 def open(self): 171 base = changes = None 172 for factory in self.config.factories: 173 if factory.name == 'changes': 174 changes = factory.open() 175 else: 176 if base is None: 177 base = factory.open() 178 else: 179 raise ValueError("Too many base storages defined!") 180 181 from ZODB.DemoStorage import DemoStorage 182 return DemoStorage(self.config.name, base=base, changes=changes) 183 184class FileStorage(BaseConfig): 185 186 def open(self): 187 from ZODB.FileStorage import FileStorage 188 config = self.config 189 options = {} 190 if getattr(config, 'packer', None): 191 packer = config.packer 192 if ':' in packer: 193 m, expr = packer.split(':', 1) 194 m = __import__(m, {}, {}, ['*']) 195 options['packer'] = eval(expr, m.__dict__) 196 else: 197 m, name = config.packer.rsplit('.', 1) 198 m = __import__(m, {}, {}, ['*']) 199 options['packer'] = getattr(m, name) 200 201 for name in ('blob_dir', 'create', 'read_only', 'quota', 'pack_gc', 202 'pack_keep_old'): 203 v = getattr(config, name, self) 204 if v is not self: 205 options[name] = v 206 207 return FileStorage(config.path, **options) 208 209class BlobStorage(BaseConfig): 210 211 def open(self): 212 from ZODB.blob import BlobStorage 213 base = self.config.base.open() 214 return BlobStorage(self.config.blob_dir, base) 215 216 217class ZEOClient(BaseConfig): 218 219 def open(self): 220 from ZEO.ClientStorage import ClientStorage 221 # config.server is a multikey of socket-connection-address values 222 # where the value is a socket family, address tuple. 223 L = [server.address for server in self.config.server] 224 options = {} 225 if self.config.blob_cache_size is not None: 226 options['blob_cache_size'] = self.config.blob_cache_size 227 if self.config.blob_cache_size_check is not None: 228 options['blob_cache_size_check'] = self.config.blob_cache_size_check 229 if self.config.client_label is not None: 230 options['client_label'] = self.config.client_label 231 232 return ClientStorage( 233 L, 234 blob_dir=self.config.blob_dir, 235 shared_blob_dir=self.config.shared_blob_dir, 236 storage=self.config.storage, 237 cache_size=self.config.cache_size, 238 name=self.config.name, 239 client=self.config.client, 240 var=self.config.var, 241 min_disconnect_poll=self.config.min_disconnect_poll, 242 max_disconnect_poll=self.config.max_disconnect_poll, 243 wait=self.config.wait, 244 read_only=self.config.read_only, 245 read_only_fallback=self.config.read_only_fallback, 246 drop_cache_rather_verify=self.config.drop_cache_rather_verify, 247 username=self.config.username, 248 password=self.config.password, 249 realm=self.config.realm, 250 **options) 251 252class BDBStorage(BaseConfig): 253 254 def open(self): 255 from BDBStorage.BerkeleyBase import BerkeleyConfig 256 storageclass = self.get_storageclass() 257 bconf = BerkeleyConfig() 258 for name in dir(BerkeleyConfig): 259 if name.startswith('_'): 260 continue 261 setattr(bconf, name, getattr(self.config, name)) 262 return storageclass(self.config.envdir, config=bconf) 263 264class BDBMinimalStorage(BDBStorage): 265 266 def get_storageclass(self): 267 import BDBStorage.BDBMinimalStorage 268 return BDBStorage.BDBMinimalStorage.BDBMinimalStorage 269 270class BDBFullStorage(BDBStorage): 271 272 def get_storageclass(self): 273 import BDBStorage.BDBFullStorage 274 return BDBStorage.BDBFullStorage.BDBFullStorage 275