#!/usr/bin/env python
"""fpm2db - refresh a Frugalware database from a repository
Usage: python fpm2db [options]

Options:
        -D, --delete            The specified pkg can be deleted with this command.
        -f ..., --fpm=...       The .fpm package. (optional when using -D)
        -m ..., --mainpkg=...   The name of the parent .fpm package. (required when using -D)
        -g ..., --maingrp=...   The group of the .fpm package. (optional)
        -h ..., --host=...      The host where the database is located. (optional)
        -u ..., --user=...      The user of the database. (optional)
        -p ..., --password=...  The password for the database. (optional)
        -d ..., --dbname=...    The name of the database. (optional)
"""

import getopt, re, os, sha, string, sys, time
import MySQLdb

class package:
        def __init__(self, fpm, parent=None, parentgrp=None):
                self.cursor=None
                self.id=None
                self.uploader_id=0
                self.parent=parent
                self.parentgrp=parentgrp
                self.parent_id=0

                self.pkgname = re.sub("-[^-]+-[^-]+-[^-]+.fpm", "", fpm)
                if not self.parent:
                        self.parent = self.pkgname
                self.pkgver = re.sub('.*-([^-]+-[^-]+)-[^-]+.fpm', r'\1', fpm)
                self.arch = os.getcwd().split('-')[-1]
                self.fwver = os.getcwd().split('/')[-2].split('-')[1]
                self.uploader = os.environ['HOME'].split('/')[-1]

                try:
                        os.stat(fpm)
                except OSError:
                        return

                self.files=[]
                socket = os.popen("pacman -Ql -p %s" % fpm)
                while True:
                        file = socket.readline().strip().replace("%s " % self.pkgname, "")
                        if not file:
                                break
                        else:
                                self.files.append(file)
                socket.close()

                self.conflicts=[]
                self.depends=[]
                self.groups=[]
                self.licenses=[]
                self.provides=[]
                self.desc=None
                self.url=None
                self.builddate=None
                self.usize=None
                socket = os.popen("pacman -Qi -p %s" % fpm)
                while True:
                        line = socket.readline().strip()
                        if not line:
                                break
                        key = line.split(':')[0].strip()
                        if key == "Conflicts With":
                                self.conflicts = line.split(' : ')[1].split(' ')
                        elif key == "Depends On":
                                self.depends = line.split(' : ')[1].split(' ')
                        elif key == "Groups":
                                self.groups = line.split(' : ')[1].split(' ')
                        elif key == "License":
                                try:
                                        self.licenses = line.split(' : ')[1].split(' ')
                                except IndexError:
                                        pass
                        elif key == "Provides":
                                self.provides = line.split(' : ')[1].split(' ')
                        elif key == "Description":
                                self.desc = "".join(line.split(' : ')[1:])
                        elif key == "URL":
                                self.url = "".join(line.split(' : ')[1:])
                        elif key == "Build Date":
                                self.builddate = "".join(line.split(' : ')[1:])[:-4]
                        elif key == "Size":
                                self.usize = string.atoi(line.split(' : ')[1])
                socket.close()
                if not self.parentgrp:
                        self.parentgrp = self.groups[0]

                self.maintainer=None
                socket = open("../source/%s/%s/FrugalBuild" % (self.parentgrp, self.parent))
                while True:
                        line = socket.readline()
                        if not line:
                                break
                        if line[:14] != "# Maintainer: ":
                                continue
                        self.maintainer = line[14:].strip()
                        break
                socket.close()

                ctx = sha.new()
                socket = open(fpm)
                while True:
                        buf = socket.read(16384)
                        if not buf:
                                break
                        ctx.update(buf)
                self.sha1sum = ctx.hexdigest()

                self.size=os.stat(fpm).st_size

        def splitver(self, pkg):
                for i in ['>=', '<=', '=']:
                        try:
                                pos = pkg.index(i)
                        except ValueError:
                                continue
                        return pkg[:pos], pkg[pos:]
                return pkg, None

        def insertlist(self, member):
                li = getattr(self, member)
                for i in li:
                        if i == "None":
                                return
                        self.cursor.execute("""insert into %s (pkg_id, %s)
                                        values ('%d', '%s');""" % (member,
                                                member[:-1], self.id, i))

        def insertgroups(self):
                for i in self.groups:
                        # get the group id or insert it if necessary
                        self.cursor.execute("select id from groups where name = '%s' limit 1" % i)
                        row = self.cursor.fetchone()
                        if row:
                                gid = row['id']
                        else:
                                self.cursor.execute("insert into groups (name) values ('%s');" % (i))
                                self.cursor.execute("SELECT LAST_INSERT_ID()")
                                row = self.cursor.fetchone()
                                gid = row['LAST_INSERT_ID()']
                        # now link the pkg with this group
                        self.cursor.execute("""insert into ct_groups (pkg_id,
                                        group_id) values ('%d', '%d');""" %
                                        (self.id, gid))

        def dellist(self, member):
                self.cursor.execute("delete from %s where pkg_id = %d" % (member, self.id))

        def insertlistid(self, member):
                li = getattr(self, member)
                for i in li:
                        if i == "None":
                                return
                        # slice the version if found
                        if member == "depends":
                                i, ver = self.splitver(i)
                        else:
                                ver=None
                        # get the id of i
                        self.cursor.execute("""select id from packages where pkgname = '%s'
                                and arch = '%s' and fwver = '%s' limit 1""" %
                                (i, self.arch, self.fwver))
                        row = self.cursor.fetchone()
                        if row:
                                id = row['id']
                        else:
                                # print "WARNING: can't find %s '%s'!" % (member, i)
                                continue
                        if not ver:
                                self.cursor.execute("""insert into %s (pkg_id,
                                                %s_id) values ('%d', '%d');""" %
                                                (member, member[:-1], self.id,
                                                        id))
                        else:
                                self.cursor.execute("""insert into %s (pkg_id,
                                %s_id, version) values ('%d', '%d', '%s');""" %
                                (member, member[:-1], self.id, id, ver))

        def insertlists(self):
                for i in ["depends", "conflicts", "provides"]:
                        self.insertlistid(i)
                for i in ["files", "licenses"]:
                        self.insertlist(i)
                self.insertgroups()

        def dellists(self):
                for i in ["depends", "conflicts", "provides", "files", "licenses", "ct_groups"]:
                        self.dellist(i)

        def delete(self):
                # check if there is such a package & get the id
                self.cursor.execute("""select id from packages where pkgname =
                                '%s' and arch = '%s' and fwver = '%s'""" %
                                (self.parent, self.arch, self.fwver))
                row = self.cursor.fetchone()
                if row:
                        self.id = row['id']
                else:
                        print 'WARNING: package %s not found, probably already deleted!' % (self.parent)
                        return

                self.cursor.execute("delete from packages where id = %d" % self.id)
                self.dellists()

        def update(self):
                # do we really need this update?
                self.cursor.execute("""select id, pkgver from packages where pkgname = '%s'
                        and arch = '%s' and fwver = '%s' limit 1""" %
                        (self.pkgname, self.arch, self.fwver))
                row = self.cursor.fetchone()
                if row and row['pkgver'] == self.pkgver:
                        return
                elif row:
                        self.id = row['id']
                # uploader_id and parent_id
                self.cursor.execute("select id from uploaders where login = '%s' limit 1" % (self.uploader))
                row = self.cursor.fetchone()
                if row:
                        self.uploader_id = row['id']
                else:
                        self.cursor.execute("insert into uploaders (login) values ('%s');" % (self.uploader))
                        self.cursor.execute("SELECT LAST_INSERT_ID()")
                        row = self.cursor.fetchone()
                        self.uploader_id = row['LAST_INSERT_ID()']

                if self.parent:
                        self.cursor.execute("""select id from packages where pkgname = '%s'
                                and arch = '%s' and fwver = '%s' limit 1""" %
                                (self.parent, self.arch, self.fwver))
                        row = self.cursor.fetchone()
                        if row:
                                self.parent_id = row['id']

                # time to insert to the packages table
                if not self.id:
                        self.cursor.execute('''
                        insert into packages
                        (pkgname, pkgver, `desc`, url, sha1sum, arch,
                        size, usize, parent_id, maintainer, uploader_id, fwver, builddate)
                        VALUES ('%s', '%s', '%s', '%s', '%s', '%s',
                        '%d', '%d', '%d', '%s', '%d',
                        '%s', '%s');
                        ''' % (self.pkgname, self.pkgver, self.desc, self.url, self.sha1sum, self.arch,
                                self.size, self.usize, self.parent_id, self.maintainer, self.uploader_id,
                                self.fwver, time.strftime("%Y-%m-%d %H:%M:%S", time.strptime(self.builddate))))
                        self.cursor.execute("SELECT LAST_INSERT_ID()")
                        row = self.cursor.fetchone()
                        self.id = row['LAST_INSERT_ID()']
                        self.insertlists()
                else:
                        self.cursor.execute(''' update packages set pkgname = '%s',
                        pkgver = '%s', `desc` = '%s', url = '%s', sha1sum =
                        '%s', arch = '%s', size = '%d', usize = '%d', parent_id
                        = '%d', maintainer = '%s', uploader_id = '%d', fwver =
                        '%s', builddate = '%s' where id = '%d' ''' %
                        (self.pkgname, self.pkgver, self.desc, self.url,
                        self.sha1sum, self.arch, self.size, self.usize,
                        self.parent_id, self.maintainer, self.uploader_id,
                        self.fwver, time.strftime("%Y-%m-%d %H:%M:%S",
                                time.strptime(self.builddate)), self.id))
                        self.dellists()
                        self.insertlists()

def usage():
        print __doc__

def main(argv):
        # defaults
        update = True
        fpm = ""
        mainpkg = None
        maingrp = None
        host = ""
        user = ""
        password = ""
        dbname = ""

        # option parsing
        try:
                opts, args = getopt.getopt(argv, "Df:h:u:p:d:m:g:", ["delete",
                        "fpm=", "host=", "user=", "password=", "dbname=",
                        "mainpkg=", "maingrp="])
        except getopt.GetoptError:
                usage()
                sys.exit(1)
        for opt, arg in opts:
                if opt in ("-D", "--delete"):
                        update = False
                elif opt in ("-f", "--file"):
                        fpm = arg
                elif opt in ("-m", "--mainpkg"):
                        mainpkg = arg
                elif opt in ("-g", "--maingrp"):
                        maingrp = arg
                elif opt in ("-h", "--host"):
                        host = arg
                elif opt in ("-u", "--user"):
                        user = arg
                elif opt in ("-p", "--password"):
                        password = arg
                elif opt in ("-d", "--dbname"):
                        dbname = arg

        # check for missing options
        if fpm != "" or (mainpkg != "" and not update):
                pass
        else:
                raise "missing -f package!"
        if host == "":
                host = "localhost"
        if user == "":
                user = "fpm2db"
        if password == "":
                password = "C6fO?o3qy"
        if dbname == "":
                dbname = "frugalware2"

        # autodetection
        os.unsetenv("LANG")
        os.unsetenv("LC_ALL")
        pkg = package(fpm, mainpkg, maingrp)

        conn = MySQLdb.connect(host=host, user=user, passwd=password,
                        db=dbname)
        pkg.cursor = conn.cursor(MySQLdb.cursors.DictCursor)
        if update:
                pkg.update()
        else:
                pkg.delete()
        conn.close()

if __name__ == "__main__":
        main(sys.argv[1:])