From e5ca34ab98e44a4c4897fd4c2450a9842a55779f Mon Sep 17 00:00:00 2001 From: Stanislav Ochotnicky Date: Thu, 9 Jul 2009 19:13:47 +0200 Subject: Added implementation of basic db functions Using Django backend for ORM mapping. Django ORM may not be best, but we can reuse it later in web application --- src/matchbox/db/__init__.py | 166 ++++++++++++++++++++++++++++++--- src/matchbox/db/main/__init__.py | 0 src/matchbox/db/main/initial_data.json | 23 +++++ src/matchbox/db/main/models.py | 50 ++++++++++ src/matchbox/db/manage.py | 11 +++ src/matchbox/db/settings.py | 8 ++ 6 files changed, 244 insertions(+), 14 deletions(-) create mode 100644 src/matchbox/db/main/__init__.py create mode 100644 src/matchbox/db/main/initial_data.json create mode 100644 src/matchbox/db/main/models.py create mode 100644 src/matchbox/db/manage.py create mode 100644 src/matchbox/db/settings.py (limited to 'src/matchbox') diff --git a/src/matchbox/db/__init__.py b/src/matchbox/db/__init__.py index acd8323..dc2171c 100644 --- a/src/matchbox/db/__init__.py +++ b/src/matchbox/db/__init__.py @@ -1,10 +1,14 @@ -try: - import psycopg2 as dbapi -except ImportError: - print "Error importing psycopg package. Check your dependencies!!" - sys.exit(1) +import sys +import os +import settings as config +from django.conf import settings +os.environ["DJANGO_SETTINGS_MODULE"]="matchbox.db.settings" + +from main.models import * +from django.db import reset_queries, close_connection, _rollback_on_exception + class DbIface(object): """ Class representing interface to database for Matchbox @@ -142,14 +146,148 @@ class DbIface(object): """ @param packageproperties_id: id of row in packageproperties table @type packageproperties_id: integer - @param contents: dict of files in packageproperties (path is key, ) - @param path: path to add to database - @type path: string - @param type: type of file to add as returned from dblink.getcontents() (e.g. 'dir', 'obj' or 'sym') - @type type: string - @param size: size of file or 0 if not regular file - @type size: integer - @param hash: hash of file or None if not regular file - @type hash: 32 character string + @param contents: dict of files in packageproperties (path is key, value is list of information about path) + see dblink.getcontents() for more info + @type contents: dict """ pass + +class DjangoDB(object): + + def dbquery(f): + def newfunc(*args, **kwargs): + reset_queries() + try: + return f(*args, **kwargs) + except Exception, e: + _rollback_on_exception() + raise e + return newfunc + + @dbquery + def add_package(self, name): + p = Package.objects.filter(name=name) + if len(p) > 0: + return p[0].id + p = Package(name=name) + p.save() + return p.id + + + @dbquery + def add_category(self, name): + c = PackageCategory.objects.filter(name=name) + if len(c) > 0: + return c[0].id + c = PackageCategory(name=name) + c.save() + return c.id + + @dbquery + def add_package_version(self, package_id, category_id, version): + p = Package.objects.get(pk=package_id) + c = PackageCategory.objects.get(pk=category_id) + + v = PackageVersion.objects.filter(version=version, category=c, package=p) + if len(v) > 0: + return v[0].id + v = PackageVersion(version=version, package=p, category=c) + v.save() + return v.id + + @dbquery + def add_dependency(self, packageversion_id, dependency_id): + p = Package.objects.get(pk=packageversion_id) + dep = Package.objects.get(pk=dependency_id) + p.dependencies.add(dep) + + @dbquery + def add_tinderbox(self, ip): + t = Tinderbox.objects.filter(ip=ip) + if len(t) > 0: + return t[0].id + + t = Tinderbox(ip=ip) + t.save() + return t.id + + @dbquery + def add_attachment(self, packageproperties_id, name, content, mimetype): + pp = PackageProperties.objects.get(pk=packageproperties_id) + + attachments = Attachment.objects.filter(packageproperties=pp, name=name) + if len(attachments) > 0: + return attachments[0].id + + a = Attachment(packageproperties=pp, name=name, content=content, mimetype=mimetype) + a.save() + return a.id + + @dbquery + def add_portage_profile(self, name): + pp = PortageProfile.objects.filter(name=name) + if len(pp) > 0: + return pp[0].id + pp = PortageProfile(name=name) + pp.save() + return pp.id + + @dbquery + def add_useflag(self, name): + u = Useflag.objects.filter(name=name) + if len(u) > 0: + return u[0].id + u = Useflag(name=name) + u.save() + return u.id + + @dbquery + def add_packageproperties(self, packageversion_id, profile_id, tinderbox_id, error_code): + pv = PackageVersion.objects.get(pk=packageversion_id) + profile = PortageProfile.objects.get(pk=profile_id) + tinderbox = Tinderbox.objects.get(pk=tinderbox_id) + + pp = PackageProperties(packageversion=pv, + profile=profile, + tinderbox=tinderbox, + error_code=error_code) + pp.save() + + @dbquery + def add_useflags_to_packageproperies(self, packageproperties_id, useflag_ids): + pp = PackageProperties.objects.get(pk=packageproperties_id) + + for id in useflag_ids: + useflag = Useflag.objects.get(pk=id) + pp.useflags.add(useflag) + + @dbquery + def add_contents_to_packageproperties(self, packageproperties_id, contents): + pp = PackageProperties.objects.get(pk=packageproperties_id) + + for path in contents.keys(): + type = contents[path][0] + file = File.objects.filter(path=path) + if len(file) == 0: + file = File(path=path) + file.save() + else: + file = file[0] + + filetype = FileType.objects.filter(name=type) + if len(filetype) == 0: + raise DatabaseError ("Database not initialized from fixtures!!\nFile type loading failed (for type %s)" % type) + filetype = filetype[0] + hash = None + size = None + if type == 'obj': + hash = contents[path][1] + size = contents[path][2] + + ppf = PackageProperties_File(file=file, + filetype=filetype, + packageproperties=pp, + hash=hash, + size=size) + ppf.save() + diff --git a/src/matchbox/db/main/__init__.py b/src/matchbox/db/main/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/matchbox/db/main/initial_data.json b/src/matchbox/db/main/initial_data.json new file mode 100644 index 0000000..613b7a5 --- /dev/null +++ b/src/matchbox/db/main/initial_data.json @@ -0,0 +1,23 @@ +[ + { + "model": "main.FileType", + "pk": 1, + "fields": { + "name": "obj" + } + }, + { + "model": "main.FileType", + "pk": 2, + "fields": { + "name": "sym" + } + }, + { + "model": "main.FileType", + "pk": 3, + "fields": { + "name": "dir" + } + } +] diff --git a/src/matchbox/db/main/models.py b/src/matchbox/db/main/models.py new file mode 100644 index 0000000..5448269 --- /dev/null +++ b/src/matchbox/db/main/models.py @@ -0,0 +1,50 @@ +from django.db import models + +# Create your models here. +class Package(models.Model): + name = models.CharField(max_length=255,unique=True) + +class PackageVersion(models.Model): + version = models.CharField(max_length=255) + package = models.ForeignKey('Package') + category = models.ForeignKey('PackageCategory') + dependencies = models.ManyToManyField('self', symmetrical=False) + +class PackageCategory(models.Model): + name = models.CharField(max_length=255,unique=True) + +class PortageProfile(models.Model): + name = models.CharField(max_length=255,unique=True) + +class Tinderbox(models.Model): + ip = models.IPAddressField() + +class PackageProperties(models.Model): + packageversion = models.ForeignKey('PackageVersion') + profile = models.ForeignKey('PortageProfile') + tinderbox = models.ForeignKey('Tinderbox') + error_code = models.IntegerField() + contents = models.ManyToManyField('File',through='PackageProperties_File') + useflags = models.ManyToManyField('Useflag') + +class Attachment(models.Model): + packageproperties = models.ForeignKey('PackageProperties') + name = models.CharField(max_length=255) + mimetype = models.CharField(max_length=255) + content = models.TextField() + +class Useflag(models.Model): + name = models.CharField(max_length=255, unique=True) + +class File(models.Model): + path = models.CharField(max_length=65535, unique=True) + +class FileType(models.Model): + name = models.CharField(max_length=20, unique=True) + +class PackageProperties_File(models.Model): + file = models.ForeignKey('File') + filetype = models.ForeignKey('FileType') + packageproperties = models.ForeignKey('PackageProperties') + hash = models.CharField(max_length=32,blank=True) + size = models.IntegerField(blank=True) diff --git a/src/matchbox/db/manage.py b/src/matchbox/db/manage.py new file mode 100644 index 0000000..5e78ea9 --- /dev/null +++ b/src/matchbox/db/manage.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python +from django.core.management import execute_manager +try: + import settings # Assumed to be in the same directory. +except ImportError: + import sys + sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) + sys.exit(1) + +if __name__ == "__main__": + execute_manager(settings) diff --git a/src/matchbox/db/settings.py b/src/matchbox/db/settings.py new file mode 100644 index 0000000..bd20bac --- /dev/null +++ b/src/matchbox/db/settings.py @@ -0,0 +1,8 @@ + +DATABASE_ENGINE = 'postgresql_psycopg2' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. +DATABASE_NAME = 'collagen' # Or path to database file if using sqlite3. +DATABASE_USER = 'username' # Not used with sqlite3. +DATABASE_PASSWORD = 'password' # Not used with sqlite3. +DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. +DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. +INSTALLED_APPS = ('db.main') -- cgit v1.2.3-65-gdbad