aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'layman/db_modules/sqlite_db/sqlite_db.py')
-rw-r--r--layman/db_modules/sqlite_db/sqlite_db.py332
1 files changed, 332 insertions, 0 deletions
diff --git a/layman/db_modules/sqlite_db/sqlite_db.py b/layman/db_modules/sqlite_db/sqlite_db.py
new file mode 100644
index 0000000..1d079a3
--- /dev/null
+++ b/layman/db_modules/sqlite_db/sqlite_db.py
@@ -0,0 +1,332 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN SQLite DB
+#################################################################################
+# File: sqlite_db.py
+#
+# Access SQLite overlay database(s).
+#
+# Copyright:
+# (c) 2015 Devan Franchini
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Devan Franchini <twitch153@gentoo.org>
+#
+'''Handler for sqlite overlay databases.'''
+
+from __future__ import unicode_literals
+
+__version__ = "$Id: sqlite_db.py 273 2015-08-03 20:17:30Z twitch153 $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import os
+import sys
+import sqlite3
+
+from layman.overlays.overlay import Overlay
+
+#py3.2+
+if sys.hexversion >= 0x30200f0:
+ _UNICODE = 'unicode'
+else:
+ _UNICODE = 'UTF-8'
+
+
+#===============================================================================
+#
+# Class DBHandler
+#
+#-------------------------------------------------------------------------------
+
+class DBHandler(object):
+ '''
+ Handle a SQLite overlay database.
+ '''
+
+ def __init__(self, config, overlays, paths=None, ignore=0,
+ ignore_init_read_errors=False):
+
+ self.config = config
+ self.ignore = ignore
+ self.overlays = overlays
+ self.paths = paths
+ self.output = config['output']
+ self.ignore_init_read_errors = ignore_init_read_errors
+
+ self.output.debug('Initializing SQLite overlay list handler', 8)
+
+
+ def __connect__(self, path):
+ '''
+ Establish connection with the SQLite database.
+ '''
+ if not os.path.exists(path):
+ if not self.ignore_init_read_errors:
+ msg = 'SQLite DBHandler warning; database previously '\
+ 'non-existent.\nCreating database now...'
+ self.output.warn(msg, 2)
+
+ if not os.access(os.path.dirname(path), os.W_OK):
+ msg = 'SQLite DBHandler error; cannot create database.\n'
+ errmsg = 'Write permissions are not given in dir: "%(dir)s"'\
+ % {'dir': os.path.dirname(path)}
+ self.output.error(msg + errmsg)
+
+ raise Exception(errmsg)
+
+ if os.path.exists(path) and not os.access(path, os.R_OK):
+ msg = 'SQLite DBHandler error; database lacks read permissions'\
+ ' cannot continue.'
+ self.output.error(msg)
+
+ raise Exception(msg)
+
+ self.__create_database__(path)
+
+ return sqlite3.connect(path)
+
+
+ def __create_database__(self, path):
+ '''
+ Create the LaymanOverlays database if it doesn't exist.
+ '''
+ with sqlite3.connect(path) as connection:
+ cursor = connection.cursor()
+ try:
+ cursor.execute('''CREATE TABLE IF NOT EXISTS Overlay
+ ( Overlay_ID INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT,
+ Priority TEXT, Status TEXT, Quality TEXT, Homepage
+ TEXT, IRC TEXT, License TEXT, UNIQUE (Name, Homepage, License)
+ ON CONFLICT IGNORE )''')
+ cursor.execute('''CREATE TABLE IF NOT EXISTS Owner ( Owner_ID
+ INTEGER PRIMARY KEY AUTOINCREMENT, Owner_Name TEXT,
+ Owner_Email TEXT, UNIQUE (Owner_Name, Owner_Email) ON
+ CONFLICT IGNORE )''')
+ cursor.execute('''CREATE TABLE IF NOT EXISTS Source ( Source_ID
+ INTEGER PRIMARY KEY AUTOINCREMENT, Type TEXT, Branch TEXT,
+ URL TEXT, UNIQUE (Type, URL) ON CONFLICT IGNORE )''')
+ cursor.execute('''CREATE TABLE IF NOT EXISTS Description
+ ( Description_ID INTEGER PRIMARY KEY AUTOINCREMENT,
+ Overlay_ID INTEGER, Description TEXT, FOREIGN
+ KEY(Overlay_ID) REFERENCES Overlay(Overlay_ID),
+ UNIQUE (Overlay_ID, Description) ON CONFLICT IGNORE )''')
+ cursor.execute('''CREATE TABLE IF NOT EXISTS Feed ( Feed_ID
+ INTEGER PRIMARY KEY AUTOINCREMENT, Overlay_ID INTEGER,
+ Feed TEXT, FOREIGN KEY(Overlay_ID) REFERENCES
+ Overlay(Overlay_ID), UNIQUE (Overlay_ID, Feed) ON CONFLICT
+ IGNORE )''')
+ cursor.execute('''CREATE TABLE IF NOT EXISTS Overlay_Source
+ ( Overlay_Source_ID INTEGER PRIMARY KEY AUTOINCREMENT,
+ Overlay_ID INTEGER, Source_ID INTEGER, FOREIGN KEY(Overlay_ID)
+ REFERENCES Overlay(Overlay_ID), FOREIGN KEY(Source_ID)
+ REFERENCES Source(SourceID), UNIQUE (Overlay_ID, Source_ID) ON
+ CONFLICT IGNORE )''')
+ cursor.execute('''CREATE TABLE IF NOT EXISTS Overlay_Owner
+ ( Overlay_Owner_ID INTEGER PRIMARY KEY AUTOINCREMENT,
+ Overlay_ID INTEGER, Owner_ID INTEGER, FOREIGN KEY(Overlay_ID)
+ REFERENCES Overlay(Overlay_ID), FOREIGN KEY(Owner_ID)
+ REFERENCES Owner(Owner_ID), UNIQUE (Overlay_ID, Owner_ID) ON
+ CONFLICT IGNORE )''')
+
+ connection.commit()
+ except Exception as err:
+ msg = 'SQLite DBHandler error; failed to create database.\n'\
+ 'Error was: %(msg)s' % {'msg': err}
+ self.output.error(msg)
+
+ raise err
+
+
+ def read_db(self, path, text=None):
+ '''
+ Read the overlay definitions from the database and generate overlays.
+ '''
+ connection = self.__connect__(path)
+ cursor = connection.cursor()
+ overlay_id = None
+ overlay = {}
+
+ cursor.execute('''SELECT Overlay_ID, Name, Priority, Status, Quality,
+ Homepage, IRC, License FROM Overlay''')
+ overlays_info = cursor.fetchall()
+ connection.commit()
+
+ for overlay_info in overlays_info:
+ overlay = {}
+ overlay_id = overlay_info[0]
+ overlay['name'] = overlay_info[1]
+
+ cursor.execute('''SELECT URL, Type, Branch FROM Overlay_Source
+ JOIN Overlay USING (Overlay_ID) JOIN Source USING (Source_ID)
+ WHERE Overlay_ID = ?''', (overlay_id,))
+ overlay['source'] = cursor.fetchall()
+
+ cursor.execute('''SELECT Owner_Name, Owner_Email FROM
+ Overlay_Owner JOIN Overlay USING (Overlay_ID) JOIN Owner USING
+ (Owner_ID) WHERE Overlay_ID = ?''', (overlay_id,))
+ owner_info = cursor.fetchall()
+
+ if len(owner_info):
+ owner_info = owner_info[0]
+ overlay['owner_name'] = owner_info[0]
+ overlay['owner_email'] = owner_info[1]
+
+ cursor.execute('''SELECT Description FROM Description JOIN Overlay
+ USING (Overlay_ID) WHERE Overlay_ID = ?''', (overlay_id,))
+ overlay['description'] = cursor.fetchall()
+
+ if len(overlay['description']):
+ overlay['description'] = overlay['description'][0]
+
+ overlay['status'] = overlay_info[3]
+ overlay['quality'] = overlay_info[4]
+ overlay['priority'] = overlay_info[2]
+ overlay['license'] = overlay_info[7]
+ overlay['homepage'] = overlay_info[5]
+ overlay['IRC'] = overlay_info[6]
+
+ cursor.execute('''SELECT Feed FROM Feed JOIN Overlay USING
+ (Overlay_ID) WHERE Overlay_ID = ?''', (overlay_id,))
+ overlay['feed'] = cursor.fetchall()
+
+ self.overlays[overlay_info[1]] = Overlay(self.config,
+ ovl_dict=overlay,
+ ignore=self.ignore)
+
+
+ def add_new(self, document=None, origin=None):
+ '''
+ Reads in provided sqlite text and generates overlays to populate
+ database.
+ '''
+ if not document:
+ msg = 'SQLite DBHandler - add_new() failed: can\'t add '\
+ 'non-existent overlay(s).\nOrigin: %(path)s'\
+ % {'path': origin}
+ self.output.warn(msg)
+
+ return False
+
+ return True
+
+
+ def add_ovl(self, overlay, connection):
+ '''
+ Adds an overlay to the database.
+ '''
+ overlay_id = None
+ owner_id = None
+ source_ids = []
+ cursor = None
+
+ cursor = connection.cursor()
+ cursor.execute('''INSERT INTO Overlay ( Name, Priority, Status,
+ Quality, Homepage, IRC, License ) VALUES ( ?, ?, ?, ?, ?, ?, ? )''',
+ (overlay.name, overlay.priority, overlay.status, overlay.quality,
+ overlay.homepage, overlay.irc, overlay.license,))
+ connection.commit()
+
+ cursor.execute('''SELECT Overlay_ID FROM Overlay WHERE Name = ?''',
+ (overlay.name,))
+ overlay_id = cursor.fetchone()[0]
+
+ cursor.execute('''INSERT INTO Owner ( Owner_Name, Owner_Email )
+ VALUES ( ?, ? )''', (overlay.owner_name, overlay.owner_email,))
+ connection.commit()
+
+ cursor.execute('''SELECT Owner_ID from Owner WHERE Owner_Name = ?;''',
+ (overlay.owner_name,))
+ owner_id = cursor.fetchone()[0]
+
+ for source in overlay.sources:
+ cursor.execute('''INSERT INTO Source ( Type, Branch, URL )
+ VALUES ( ?, ?, ? )''', (source.type_key, source.branch,
+ source.src,))
+ connection.commit()
+ cursor.execute('''SELECT Source_ID FROM Source WHERE URL = ?;''',
+ (source.src,))
+ source_ids.append(cursor.fetchone()[0])
+
+ for description in overlay.descriptions:
+ cursor.execute('''INSERT INTO Description ( Overlay_ID,
+ Description ) VALUES ( ?, ? )''', (overlay_id, description,))
+
+ for feed in overlay.feeds:
+ cursor.execute('''INSERT INTO Feed ( Overlay_ID, Feed ) VALUES ( ?,
+ ? )''', (overlay_id, feed,))
+
+ cursor.execute('''INSERT INTO Overlay_Owner ( Overlay_ID, Owner_ID )
+ VALUES ( ?, ? )''', (overlay_id, owner_id,))
+
+ for source_id in source_ids:
+ cursor.execute('''INSERT INTO Overlay_Source ( Overlay_ID,
+ Source_ID ) VALUES ( ?, ? )''', (overlay_id, source_id,))
+
+ connection.commit()
+
+
+ def remove(self, overlay, path):
+ '''
+ Remove an overlay from the database.
+ '''
+ cursor = None
+ overlay_id = 0
+ owner_id = 0
+ source_ids = []
+
+ with self.__connect__(path) as connection:
+ cursor = connection.cursor()
+
+ cursor.execute('''SELECT Overlay_ID FROM Overlay WHERE Name =
+ ?''', (overlay.name,))
+ overlay_id = cursor.fetchone()[0]
+
+ cursor.execute('''SELECT Owner_ID FROM Overlay_Owner WHERE
+ Overlay_ID = ?''', (overlay_id,))
+ owner_id = cursor.fetchone()[0]
+
+ cursor.execute('''SELECT Source_ID FROM Overlay_Source WHERE
+ Overlay_ID = ?''', (overlay_id,))
+ source_ids = cursor.fetchall()[0]
+
+ cursor.execute('''DELETE FROM Feed WHERE Overlay_ID = ?''',
+ (overlay_id,))
+ cursor.execute('''DELETE FROM Description WHERE Overlay_ID = ?''',
+ (overlay_id,))
+ cursor.execute('''DELETE FROM Overlay_Source WHERE Overlay_ID =
+ ?''', (overlay_id,))
+ cursor.execute('''DELETE FROM Overlay_Owner WHERE Overlay_ID =
+ ?''', (overlay_id,))
+
+ for source_id in source_ids:
+ cursor.execute('''DELETE FROM Source WHERE Source_ID = ?''',
+ (source_id,))
+
+ cursor.execute('''DELETE FROM Owner WHERE Owner_ID = ?''',
+ (owner_id,))
+ cursor.execute('''DELETE FROM Overlay WHERE Overlay_ID = ?''',
+ (overlay_id,))
+
+ connection.commit()
+
+
+ def write(self, path):
+ '''
+ Write the list of overlays to the database.
+ '''
+ try:
+ with self.__connect__(path) as connection:
+ for overlay in self.overlays:
+ self.add_ovl(self.overlays[overlay], connection)
+ except Exception as err:
+ msg = 'Failed to write to overlays database: %(path)s\nError was'\
+ ': %(err)s' % {'path': path, 'err': err}
+ self.output.error(msg)
+ raise err