Skip to content
database.py 3.45 KiB
Newer Older
# -*- python -*-
# -*- coding: utf-8 -*-

# This file is part of Installsystems.
# Installsystems is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# Installsystems 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 Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with Installsystems.  If not, see <http://www.gnu.org/licenses/>.

'''
Database stuff
'''

import math
import os
Seblu's avatar
Seblu committed
import sqlite3
import uuid
import installsystems.tools as istools
Seblu's avatar
Seblu committed
import installsystems.template as istemplate
from installsystems.tarball import Tarball
from installsystems.exception import *
from installsystems.printer import *

class Database(object):
    '''
    Abstract repo database stuff
Seblu's avatar
Seblu committed
    It needs to be local cause of sqlite3 which need to open a file
    '''
    version = 2.0

    @classmethod
Seblu's avatar
Seblu committed
    def create(cls, path):
        arrow("Creating repository database")
        # check locality
        if not istools.isfile(path):
            raise ISError("Database creation must be local")
Seblu's avatar
Seblu committed
        path = os.path.abspath(path)
        if os.path.exists(path):
            raise ISError("Database already exists. Remove it before")
Seblu's avatar
Seblu committed
            conn = sqlite3.connect(path, isolation_level=None)
            conn.execute("PRAGMA foreign_keys = ON")
            conn.executescript(istemplate.createdb)
            conn.execute("INSERT INTO repository values (?,?,?)",
                         (str(uuid.uuid4()), Database.version, "",))
Seblu's avatar
Seblu committed
            conn.commit()
            conn.close()
        except Exception as e:
            raise ISError(u"Create database failed", e)
Seblu's avatar
Seblu committed
        return cls(path)
Seblu's avatar
Seblu committed
    def __init__(self, path):
Seblu's avatar
Seblu committed
        # check locality
        if not istools.isfile(path):
            raise ISError("Database must be local")
Seblu's avatar
Seblu committed
        self.path = os.path.abspath(path)
Sebastien Luttringer's avatar
Sebastien Luttringer committed
        if not os.path.exists(self.path):
            raise ISError("Database not exists")
Seblu's avatar
Seblu committed
        self.conn = sqlite3.connect(self.path, isolation_level=None)
        self.conn.execute("PRAGMA foreign_keys = ON")
        # get database version
        try:
            r = self.ask("SELECT version FROM repository").fetchone()
            if r is None:
                raise TypeError()
            self.version = float(r[0])
        if math.floor(self.version) >= math.floor(Database.version) + 1.0:
            raise ISWarning(u"New database format (%s), please upgrade "
                            "your Installsystems version" % self.version)
        # we make a query to be sure format is valid
        try:
            self.ask("SELECT * FROM image")
        except:
            debug(u"Invalid database format: %s" % self.version)
            raise ISError("Invalid database format")
Seblu's avatar
Seblu committed
    def begin(self):
        '''
        Start a db transaction
        '''
        self.conn.execute("BEGIN TRANSACTION")

    def commit(self):
        '''
        Commit current db transaction
        '''
        self.conn.execute("COMMIT TRANSACTION")

Seblu's avatar
Seblu committed
    def ask(self, sql, args=()):
Seblu's avatar
Seblu committed
        '''
        Ask question to db
        '''
Seblu's avatar
Seblu committed
        return self.conn.execute(sql, args)