blob: cd232adad6ea6c1f27b028a86c3a408545df2df2 [file] [log] [blame]
#
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Configuration store classes."""
import os
import sqlite3
import string
from core import properties
class Store(properties.PropBase):
"""A sqlite3-backed dict interface for storing persistent data.
Usage:
cd = config.Store('data.db')
cs['mykey'] = 'my val'
print cs['mykey']
'mykey'
"""
PREFIX = 'data_'
CACHING = True
def __init__(self, file_path, table='data'):
super(Store, self).__init__()
self._conn = None
self._path = file_path
self._table = table
self._initialized = False
def _setup(self):
if self._initialized:
return True
if self._path != ':memory:':
db_dir = os.path.dirname(self._path)
if not os.path.isdir(db_dir):
os.makedirs(db_dir)
self._conn = sqlite3.connect(self._path)
self._conn.execute('create table if not exists %s '
'(key text PRIMARY KEY, val text)' % self._table)
self._initialized = True
def dict(self):
"""Dumps the entire table as a dict."""
if not self._initialized:
self._setup()
c = self._conn.cursor()
d = {}
for row in c.execute("select key, val from %s" % self._table):
d[row[0]] = row[1]
return d
def _Get(self, key):
if not self._initialized:
self._setup()
c = self._conn.cursor()
c.execute("select val from %s where key=?" % self._table, (key, ))
ret = c.fetchone()
if ret:
return ret[0]
return None
def _Set(self, key, val):
if not self._initialized:
self._setup()
c = self._conn.cursor()
c.execute("insert or replace into %s values (?, ?)" % self._table,
(key, val))
self._conn.commit()
return val
def _load(self, key):
if key in self.properties():
key = self.PREFIX + key
return self._Get(key)
def _save(self, key, value):
if key in self.properties():
key = self.PREFIX + key
return self._Set(key, value)
class DictStore(properties.PropBase):
"""A dict-backed store primarily used for in-memory replacement for other
stores in tests.
"""
REQUIRED_PROPS = {}
OPTIONAL_PROPS = {}
def __init__(self):
super(DictStore, self).__init__()
self._d = {}
def _save(self, key, value):
self._d[key] = value
return value
def _load(self, key):
if not key in self._d:
return ''
return self._d[key]
class FileStore(properties.PropBase):
"""A file-backed dict interface for storing persistent data.
Usage:
cd = config.FileStore(os.path.join(PRODUCT_DIR, 'data_dir'))
cd['myprefix/mykey'] = 'my val'
print cd['myprefix/mykey']
'my val'
"""
CACHING = True
def __init__(self, path_prefix='config'):
self._prefix = path_prefix
super(FileStore, self).__init__()
def _remove_comments(self, string_):
"""Returns |string_| with comments removed and whitespace adjusted.
Removes whitespace from beginning and end of all lines,
newline characters are replaced with ' '.
"""
value = ''
lines = string_.split('\n')
for line in lines:
stripped_line = line.strip()
if len(stripped_line) > 0 and stripped_line[0] == '#':
continue
value += line + ' '
return value.strip()
def _load_from_file(self, keyfile):
"""Reads in the contents of |keyfile| stripping out comments and
newlines
"""
value = ''
if not os.path.exists(keyfile):
return value
with open(keyfile, 'r') as f:
value = f.read()
return self._remove_comments(value)
def _save_to_file(self, keyfile, value):
"""Write |value| to |keyfile|"""
if type(value) != str:
raise TypeError, 'value must be a str'
if not os.path.exists(os.path.dirname(keyfile)):
os.makedirs(os.path.dirname(keyfile))
with open(keyfile, 'w') as f:
# Note, if comments are written, they will not be read back in!
f.write(value)
return self._remove_comments(value)
def _key_to_path(self, key):
"""Converts a key of [key0/[key2/[.../]]key to a host-compatible path"""
return os.path.join(self._prefix, *string.split(key, '/'))
def _load(self, key):
"""Returns the value for |key|"""
keyfile = self._key_to_path(key)
return self._load_from_file(keyfile)
def _save(self, key, value):
"""Assignes |value| to |key|"""
keyfile = self._key_to_path(key)
return self._save_to_file(keyfile, value)
class ProductFileStore(FileStore):
REQUIRED_PROPS = {'name': [], 'brand': [], 'device': [], 'manufacturer': []}
OPTIONAL_PROPS = {
'bdk/version': [], 'bdk/buildtype': ['eng', 'user', 'userdebug'],
'bdk/java': ['0', '1'], 'bdk/allowed_environ': [],
'brillo/product_id': [], 'copy_files': [],
'brillo/crash_server': [], 'packages': []}
def __init__(self, product_path):
if product_path is None:
raise ValueError, 'The product path must not be None.'
super(ProductFileStore, self).__init__(os.path.join(product_path,
'config'))