summaryrefslogtreecommitdiffstats
path: root/bitbake-dev/lib/bb/persist_data.py
blob: ea921072cd75d0a9db0790ce46ecbad1af671749 (plain)
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# BitBake Persistent Data Store
#
# Copyright (C) 2007        Richard Purdie
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

import bb, os

try:
    import sqlite3
except ImportError:
    try:
        from pysqlite2 import dbapi2 as sqlite3
    except ImportError:
        bb.msg.fatal(bb.msg.domain.PersistData, "Importing sqlite3 and pysqlite2 failed, please install one of them. Python 2.5 or a 'python-pysqlite2' like package is likely to be what you need.")

sqlversion = sqlite3.sqlite_version_info
if sqlversion[0] < 3 or (sqlversion[0] == 3 and sqlversion[1] < 3):
    bb.msg.fatal(bb.msg.domain.PersistData, "sqlite3 version 3.3.0 or later is required.")

class PersistData:
    """
    BitBake Persistent Data Store

    Used to store data in a central location such that other threads/tasks can 
    access them at some future date.

    The "domain" is used as a key to isolate each data pool and in this 
    implementation corresponds to an SQL table. The SQL table consists of a 
    simple key and value pair.

    Why sqlite? It handles all the locking issues for us.
    """
    def __init__(self, d):
        self.cachedir = bb.data.getVar("PERSISTENT_DIR", d, True) or bb.data.getVar("CACHE", d, True)
        if self.cachedir in [None, '']:
            bb.msg.fatal(bb.msg.domain.PersistData, "Please set the 'PERSISTENT_DIR' or 'CACHE' variable.")
        try:
            os.stat(self.cachedir)
        except OSError:
            bb.mkdirhier(self.cachedir)

        self.cachefile = os.path.join(self.cachedir,"bb_persist_data.sqlite3")
        bb.msg.debug(1, bb.msg.domain.PersistData, "Using '%s' as the persistent data cache" % self.cachefile)

        self.connection = sqlite3.connect(self.cachefile, timeout=5, isolation_level=None)

    def addDomain(self, domain):
        """
        Should be called before any domain is used
        Creates it if it doesn't exist.
        """
        self.connection.execute("CREATE TABLE IF NOT EXISTS %s(key TEXT, value TEXT);" % domain)

    def delDomain(self, domain):
        """
        Removes a domain and all the data it contains
        """
        self.connection.execute("DROP TABLE IF EXISTS %s;" % domain)


    def renameDomain(self, domain, newdomain):
        """
        Renames a domain, removing the target if it already exists
        """
 
        self.connection.execute("DROP TABLE IF EXISTS %s;" % newdomain)
        self.connection.execute("ALTER TABLE %s RENAME TO %s;" % (domain, newdomain))

    def getKeyValues(self, domain):
        """
        Return a list of key + value pairs for a domain
        """
        ret = {}
        data = self.connection.execute("SELECT key, value from %s;" % domain)
        for row in data:
            ret[str(row[0])] = str(row[1])

	return ret

    def getValue(self, domain, key):
        """
        Return the value of a key for a domain
        """
        data = self.connection.execute("SELECT * from %s where key=?;" % domain, [key])
        for row in data:
            return row[1]

    def setValue(self, domain, key, value):
        """
        Sets the value of a key for a domain
        """
        data = self.connection.execute("SELECT * from %s where key=?;" % domain, [key])
        rows = 0
        for row in data:
            rows = rows + 1
        if rows:
            self._execute("UPDATE %s SET value=? WHERE key=?;" % domain, [value, key])
        else:
            self._execute("INSERT into %s(key, value) values (?, ?);" % domain, [key, value])

    def delValue(self, domain, key):
        """
        Deletes a key/value pair
        """
        self._execute("DELETE from %s where key=?;" % domain, [key])

    def _execute(self, *query):
        while True:	
            try:
                self.connection.execute(*query)
                return
            except sqlite3.OperationalError, e:
                if 'database is locked' in str(e):
                    continue
                raise