Commit 0a0ebca7 authored by Lisa's avatar Lisa

Database conversion program ready

parent d6c8e1f9
#!/usr/bin/python
# -*- coding: utf8 -*-
# A script to convert the Pacman local database into an Akabei one
#
# Copyright (C) 2011 Lisa Vitolo <shainer@chakra-project.org>
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
import sys
import os
import getopt
from akabeipackage import *
from akabeipackageparser import *
from akabeidbwriter import *
from akabeiprogressbar import *
# Try to read the DBPath config line from pacman.conf
# to see if the user set a different value from the default one
def getDatabasePath(pf):
try:
conf = open(pf, "r")
except IOError, err:
print str(err)
print "[!!] This script needs your pacman config file to perform the conversion."
print "[!!] Use " + sys.argv[0] + " -p <path to your pacman.conf> to specify a different configuration file."
sys.exit(-1)
for pacmanLine in conf.readlines():
separatedLine = pacmanLine.partition("=")
optname = separatedLine[0]
# Deletes trailing whitespaces on both sides
optname = optname.lstrip()
optname = optname.rstrip()
if (optname == "DBPath"):
optvalue = separatedLine[2].partition("#")[0] # leaves out comments after the db path
optvalue = optvalue.lstrip()
optvalue = optvalue.rstrip()
conf.close()
return optvalue
conf.close()
return ""
# Each local package is represented in pacman as a directory in the form name-version
# in this path. This directory contains: desc, files (always), install (not always).
def parseLocalDatabase(path):
desc = ""
install = ""
files = ""
packages = []
progress = 0.0
progressReach100 = False
# Since the number of packages will surely be more than 100,
# we need to figure out what fraction we should make the progress bar advance
# for each package parsed
step = 1.0 / (len(os.listdir(path)) / 100)
showProgress(progress)
for pkgDir in os.listdir(path):
for pkgFile in os.listdir(path + "/" + pkgDir):
if pkgFile == "desc":
desc = path + "/" + pkgDir + "/" + pkgFile
elif pkgFile == "install":
install = path + "/" + pkgDir + "/" + pkgFile
elif pkgFile == "files":
files = path + "/" + pkgDir + "/" + pkgFile
progress += step # update progress
if progress == 100:
progressReach100 = True
# progress can surpass 100 by little quantities
# this is seen when the progress bar reaching 100% but the cycle is still working on the last packages
if progress <= 100:
showProgress(progress)
# Calls the package parser
parser = PacmanPackageParser(desc, install, files)
packages.append(parser.getPackage())
# show last progress in case the progress never became exactly 100 (almost always)
# If you remove the condition block, if progress reaches 100 then two bars will be displayed.
if not progressReach100:
showProgress(100)
return packages
def usage():
print "usage: " + sys.argv[0] + " [-h] [-p=<path to pacman.conf>] [-o=<akabei db file>] [-s=<akabei db scheme file>]"
print
print "Options:"
print " -h, --help Prints this help message"
print " -p, --pacman <file> Reads pacman configuration from <file> (default: /etc/pacman.conf)"
print " -o, --db-output <file> Prints the Akabei database on <file> (default: local.db)"
print " -s, --db-scheme <file> Reads the database scheme from <file> (default: dbschema.sql)"
# Start point
if __name__ == "__main__":
# Default values for files
pacmanConf = "/etc/pacman.conf"
outputFile = "local.db"
schemeFile = "/usr/share/akabei/dbschema.sql"
opts = None
# Reads options from command line
try:
opts = getopt.getopt(sys.argv[1:], "hp:o:s:", ["help", "--pacman" "--db-output=", "--db-scheme="])
except getopt.GetoptError, error:
print str(error)
usage()
sys.exit(-1)
# Parse options and overrides defaults if needed
for opt, arg in opts[0]:
if opt in ("-h", "--help"):
usage()
sys.exit(0)
elif opt in ("-p", "--pacman"):
pacmanConf = arg
elif opt in ("-o", "--db-output"):
outputFile = arg
elif opt in ("-s", "--db-scheme"):
schemeFile = arg
print "==== Akabei database conversion script v0.1 ==== "
print "This script may take some time to finish."
print
# Gets the database path from the pacman configuration
print "[**] Reading Pacman database path from " + pacmanConf + "...",
dbpath = getDatabasePath(pacmanConf)
print "done."
if len(dbpath) == 0:
dbpath = "/var/lib/pacman" # if not explicitly set there, then go back to the default value
localPath = dbpath + "/local"
# Get local packages from pacman, then write them into the akabei database in the right format
print "[**] Parsing Pacman local database..."
localPackages = parseLocalDatabase(localPath)
print "done."
dbwriter = AkabeiDbWriter(outputFile, schemeFile)
dbwriter.addPackages(localPackages)
print "[**] Database converted successfully. Now enjoy akabei!"
\ No newline at end of file
#!/usr/bin/python
# Class to write into the Akabei SQLite database
#
# Copyright (C) 2011 Lisa Vitolo <shainer@chakra-project.org>
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
import sys
import os
from akabeiprogressbar import *
try:
from pysqlite2 import dbapi2 as sqlite
except ImportError:
print "[!!] You need to install the python-pysqlite package to execute this script. Quitting..."
sys.exit(-1)
class AkabeiDbWriter:
def __init__(self, dbname, dbSchemeName):
# If exists, I cannot write again the scheme on it
# so I just wipe out all the content,
# plus I check if there are some permission problems for writing on the file
try:
db = open(dbname, "w")
db.close()
except IOError, error:
print str(error)
print "[!!] Error opening the database output file for writing. Quitting..."
sys.exit(-1)
print "[**] The Akabei database will be written in '" + dbname + "'"
self.dbconnection = sqlite.connect(dbname)
self.dbconnection.text_factory = str # needed for some fields
self.dbcursor = self.dbconnection.cursor()
self.writeDbScheme(dbSchemeName)
# Reads the scheme file and apply it into the newly created database
def writeDbScheme(self, dbSchemeName):
print "[**] Setting up the database scheme from " + dbSchemeName + " ... ",
try:
dbscheme = open(dbSchemeName, "r")
except IOError, error:
print str(error)
print "[!!] This script needs a database scheme file to perform the conversion."
print "[!!] Use " + sys.argv[0] + " -s <path to the scheme> to specify a different one."
sys.exit(-1)
query = ""
for line in dbscheme.readlines():
if line == "\n":
self.dbcursor.execute(query)
query = ""
else:
query += line
self.dbconnection.commit()
print "done."
def addPackages(self, pkgs):
query = ""
print "[**] Writing packages on the Akabei database..."
# See __main__.py for an explanation about how the progress bar works
progress = 0.0
progressReach100 = False
step = 1.0 / (len(pkgs) / 100)
showProgress(progress)
# Insert packages into the database
for p in pkgs:
query = "INSERT INTO packages ("\
"'name', 'version', 'filename', 'description', 'size',"\
"'installedsize', 'md5sum', 'url', 'builddate', 'arch', 'packager',"\
"'license', 'flags', 'screenshoturl', 'installreason', 'installdate') "\
"VALUES ("\
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
self.dbcursor.execute(query, (p.name, p.version, p.filename, p.description, p.size, p.installedsize, p.md5sum, p.url, p.builddate, p.arch, p.packager, p.license, p.flags, p.screenshoturl, p.installreason, p.installdate))
pkgid = self.dbcursor.lastrowid
for scriptlet in p.scriptlets:
query = "INSERT INTO scriptlets ('package', 'scriptlet') VALUES (?, ?)"
self.dbcursor.execute(query, (pkgid, scriptlet))
for dep in p.dependencies:
query = "INSERT INTO depends ('package', 'dependency') VALUES (?, ?)"
self.dbcursor.execute(query, (pkgid, dep))
for conflict in p.conflicts:
query = "INSERT INTO conflicts ('package', 'conflict') VALUES (?, ?)"
self.dbcursor.execute(query, (pkgid, conflict))
for provide in p.provides:
query = "INSERT INTO provides ('package', 'provides') VALUES (?, ?)"
self.dbcursor.execute(query, (pkgid, provide))
for opt in p.optionals:
query = "INSERT INTO optional ('package', 'dependency') VALUES (?, ?)"
self.dbcursor.execute(query, (pkgid, opt))
for rep in p.replaces:
query = "INSERT INTO replaces ('package', 'replaces') VALUES (?, ?)"
self.dbcursor.execute(query, (pkgid, rep))
for mime in p.mimetypes:
query = "INSERT INTO providesmimetype ('package', 'mimetype') VALUES (?, ?)"
self.dbcursor.execute(query, (pkgid, mime))
for group in p.groups:
# Add the group too if not already present
if not self.groupExist(group):
query = "INSERT INTO groups ('name') VALUES (?)"
self.dbcursor.execute(query, (group,))
query = "INSERT INTO belongsgroup ('package', 'groupname') VALUES (?, ?)"
self.dbcursor.execute(query, (pkgid, group))
for f in p.files:
query = "INSERT INTO files ('package', 'file', 'prefix', 'backup') VALUES (?, ?, ?, ?)"
self.dbcursor.execute(query, (pkgid, f.name, f.prefix, f.backup))
progress += step
if progress == 100:
progressReach100 = True
if progress <= 100:
showProgress(progress)
if not progressReach100:
showProgress(100)
print "done."
print "[**] Committing to database... ",
self.dbconnection.commit()
print "done."
def groupExist(self, gname):
query = "SELECT * FROM groups WHERE name='" + gname + "'"
self.dbcursor.execute(query)
return len(self.dbcursor.fetchall()) > 0
#!/usr/bin/python
# Classes representing objects that will go in the Akabei database
#
# Copyright (C) 2011 Lisa Vitolo <shainer@chakra-project.org>
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
class AkabeiFile(object):
def __init__(self, name, backup=""):
self.name = name
self.backup = backup
self.prefix = ""
def __str__(self):
return self.name
class AkabeiPackage(object):
def __init__(self):
self.name = ""
self.version = ""
self.filename = ""
self.description = ""
self.size = 0
self.installedsize = 0
self.md5sum = ""
self.url = ""
self.builddate = 0
self.arch = ""
self.packager = ""
self.license = ""
self.flags = ""
self.screenshoturl = ""
self.installreason = 0
self.installdate = 0
self.scriptlets = []
self.dependencies = []
self.conflicts = []
self.provides = []
self.optionals = []
self.replaces = []
self.mimetypes = []
self.groups = []
self.files = []
def addScriptlet(self, scriptlet):
self.scriptlets.append(scriptlet)
def addDependency(self, dep):
self.dependencies.append(dep)
def addConflict(self, c):
self.conflicts.append(c)
def addProvide(self, p):
self.provides.append(p)
def addOptional(self, opt):
self.optionals.append(opt)
def addReplace(self, rep):
self.replaces.append(rep)
def addMimeType(self, mime):
self.mimetypes.append(mime)
def addGroup(self, groupname):
self.groups.append(groupname)
def addFile(self, filename, backup):
f = AkabeiFile(filename, backup)
self.files.append(f)
def __str__(self):
return self.name + "-" + self.version
\ No newline at end of file
#!/usr/bin/python
# A script to create an AkabeiPackage object from the information Pacman stores.
#
# Copyright (C) 2011 Lisa Vitolo <shainer@chakra-project.org>
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
from akabeipackage import *
import sys
import os
class PacmanPackageParser:
def __init__(self, d, i, f):
self.desc = None
self.install = None
self.files = None
if len(d) > 0:
self.desc = open(d, "r")
else:
print "[!!] Error: this package doesn't contain a desc file."
print "[!!] Your local database may be broken. Quitting now..."
sys.exit(-1)
if len(i) > 0:
self.install = open(i, "r")
if len(f) > 0:
self.files = open(f, "r")
self.package = AkabeiPackage()
# Used by the parse* functions
self.state = ""
self.parseDescription()
self.parseInstall()
self.parseFiles()
def parseDescription(self):
self.state = ""
for line in self.desc.readlines():
line = line[:-1] # delete newline at the end
if len(line) == 0:
self.state = ""
continue
# lines in the form %SOMETHING% starts a section in the file
if line[0] == "%":
self.state = line[1:len(line)-1]
else:
if self.state == "NAME":
self.package.name = line
elif self.state == "VERSION":
self.package.version = line
elif self.state == "DESC":
self.package.description = line
elif self.state == "GROUPS":
self.package.addGroup(line)
elif self.state == "URL":
self.package.url = line
elif self.state == "LICENSE":
self.package.license = line
elif self.state == "ARCH":
self.package.arch = line
elif self.state == "BUILDDATE":
self.package.builddate = int(line)
elif self.state == "INSTALLDATE":
self.package.installdate = int(line)
elif self.state == "PACKAGER":
self.package.packager = line
elif self.state == "SIZE":
self.package.size = int(line)
elif self.state == "DEPENDS":
self.package.addDependency(line)
elif self.state == "OPTDEPENDS":
self.package.addOptional(line)
elif self.state == "REASON":
self.package.reason = int(line)
elif self.state == "PROVIDES":
self.package.addProvide(line)
elif self.state == "REPLACES":
self.package.addReplace(line)
elif self.state == "CONFLICTS":
self.package.addConflict(line)
# Installation scriptlet
def parseInstall(self):
if self.install == None:
return
self.package.addScriptlet(self.install.read())
def parseFiles(self):
if self.files == None:
return
self.state = ""
packagefiles = {}
for line in self.files.readlines():
line = line[:-1]
if len(line) == 0:
self.state = ""
continue
if line[0] == "%":
self.state = line[1:len(line)-1]
else:
if self.state == "FILES":
packagefiles[line] = ""
if self.state == "BACKUP":
separatedLine = line.partition("\t")
packagefiles[separatedLine[0]] = separatedLine[2]
for pf in packagefiles:
self.package.addFile(pf, packagefiles[pf])
def getPackage(self):
return self.package
def __del__(self):
if self.desc != None:
self.desc.close()
if self.install != None:
self.install.close()
if self.files != None:
self.files.close()
\ No newline at end of file
#!/usr/bin/python
# Convenience method to show a progress bar in the command line.
#
# Copyright (C) 2011 Lisa Vitolo <shainer@chakra-project.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
import math
import sys
# The actual method wasn't written by me.
def showProgress(percent):
width = 50
marks = math.floor(width * (percent / 100.0))
spaces = math.floor(width - marks)
loader = '[' + ('=' * int(marks)) + (' ' * int(spaces)) + ']'
sys.stdout.write("%s %d%%\r" % (loader, percent))
if percent >= 100:
sys.stdout.write("\n")
sys.stdout.flush()
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment