* dir'leri yeniden organize ediyoruz,
bir sonraki adim python package'i yapmak tam olarak
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
# PISI package version
|
||||||
|
__version__ = "0.1"
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
# pisi.actionsapi version
|
||||||
|
__version__ = "0.1"
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
from pisi.context import Constants
|
||||||
|
const = Constants.c
|
||||||
|
|
||||||
|
def configure(parameters = None):
|
||||||
|
''' FIXME: Düzgün hale getirilecek '''
|
||||||
|
''' {EXTRA} = '--with-nls --with-libusb --with-something-usefull '''
|
||||||
|
|
||||||
|
# FIXME: I don't think its feasible to write all these parameters
|
||||||
|
# here. There should be a way to get all these... pisi.context.Constants?
|
||||||
|
configure_string = './configure --prefix=/usr \
|
||||||
|
--host=i686-pc-linux-gnu \
|
||||||
|
--mandir=/usr/share/man \
|
||||||
|
--infodir=/usr/share/info \
|
||||||
|
--datadir=/usr/share \
|
||||||
|
--sysconfdir=/etc \
|
||||||
|
--localstatedir=/var/lib {EXTRA}'
|
||||||
|
|
||||||
|
cmd = configure_string.replace('{EXTRA}', parameters)
|
||||||
|
os.system(cmd)
|
||||||
|
|
||||||
|
def make():
|
||||||
|
''' FIXME: Düzgün hale getirilecek '''
|
||||||
|
os.system('make')
|
||||||
|
|
||||||
|
def install():
|
||||||
|
''' FIXME: Düzgün hale getirilecek '''
|
||||||
|
''' {D} = /var/tmp/pisi/ _paket_adı_ /image/ '''
|
||||||
|
global const
|
||||||
|
|
||||||
|
install_string = 'make prefix={D}/usr \
|
||||||
|
datadir={D}/usr/share \
|
||||||
|
infodir={D}/usr/share/info \
|
||||||
|
localstatedir={D}/var/lib \
|
||||||
|
mandir={D}/usr/share/man \
|
||||||
|
sysconfdir={D}/etc \
|
||||||
|
install'
|
||||||
|
|
||||||
|
cmd = os.path.dirname(os.path.dirname(os.getcwd())) + \
|
||||||
|
const.install_dir_suffix
|
||||||
|
cmd = install_string.replace('{D}', cmd)
|
||||||
|
os.system(cmd)
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os, string, re, shutil
|
||||||
|
from shell import *
|
||||||
|
|
||||||
|
def gnuconfig_findnewest():
|
||||||
|
''' find the newest config.* file according to
|
||||||
|
timestamp and return it'''
|
||||||
|
|
||||||
|
locations = ['/usr/share/gnuconfig/config.sub',
|
||||||
|
'/usr/share/automake-1.8/config.sub',
|
||||||
|
'/usr/share/automake-1.7/config.sub',
|
||||||
|
'/usr/share/automake-1.6/config.sub',
|
||||||
|
'/usr/share/automake-1.5/config.sub',
|
||||||
|
'/usr/share/automake-1.4/config.sub']
|
||||||
|
|
||||||
|
newer_location = {}
|
||||||
|
|
||||||
|
for i in locations:
|
||||||
|
newer_location[i] = re.sub('\'',
|
||||||
|
'',
|
||||||
|
string.split((cat(i) |
|
||||||
|
tr(str.rstrip) |
|
||||||
|
grep ('^timestamp') |
|
||||||
|
join), '=')[1])
|
||||||
|
|
||||||
|
keys = newer_location.keys()
|
||||||
|
keys.sort()
|
||||||
|
map(newer_location.get, keys)
|
||||||
|
|
||||||
|
return os.path.dirname(newer_location.popitem()[0])
|
||||||
|
|
||||||
|
def gnuconfig_update():
|
||||||
|
''' copy newest config.* onto source's '''
|
||||||
|
|
||||||
|
newer_location = gnuconfig_findnewest()
|
||||||
|
|
||||||
|
try:
|
||||||
|
shutil.copyfile(newer_location + '/config.sub',
|
||||||
|
os.getcwd() + '/config.sub')
|
||||||
|
shutil.copyfile(newer_location + '/config.guess',
|
||||||
|
os.getcwd() + '/config.guess')
|
||||||
|
except IOError:
|
||||||
|
print 'Hata mata...'
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
print 'GNU Config Update Finished...'
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
def libtoolize():
|
||||||
|
''' FIXME: Düzgün hale getirilecek '''
|
||||||
|
''' patch source with ltmain patches '''
|
||||||
|
|
||||||
|
# This is wrong! Action files should only operate on the build
|
||||||
|
# directory. And shouldn't depend on external files. If a patch is
|
||||||
|
# need to be applied it is PisiBuild's job to do it!
|
||||||
|
os.system('patch -sN < ' + Context.lib_dir() + '/portage-1.4.1.patch')
|
||||||
|
os.system('patch -sN < ' + Context.lib_dir() + '/sed-1.4.0.patch')
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys, re
|
||||||
|
from itertools import izip, imap, count, ifilter, ifilterfalse
|
||||||
|
|
||||||
|
def cat(filename):
|
||||||
|
return file(filename).xreadlines()
|
||||||
|
|
||||||
|
class grep:
|
||||||
|
"""keep only lines that match the regexp"""
|
||||||
|
def __init__(self,pat, flags = 0):
|
||||||
|
self.fun = re.compile(pat, flags).match
|
||||||
|
def __ror__(self, input):
|
||||||
|
return ifilter(self.fun, input)
|
||||||
|
|
||||||
|
class tr:
|
||||||
|
"""apply arbitrary transform to each sequence element"""
|
||||||
|
def __init__(self, transform):
|
||||||
|
self.tr = transform
|
||||||
|
def __ror__(self, input):
|
||||||
|
return imap(self.tr, input)
|
||||||
|
|
||||||
|
class printto:
|
||||||
|
"""print sequence elements one per line"""
|
||||||
|
def __init__(self, out = sys.stdout):
|
||||||
|
self.out = out
|
||||||
|
def __ror__(self,input):
|
||||||
|
for l in input:
|
||||||
|
print >> self.out, l
|
||||||
|
|
||||||
|
printlines = printto(sys.stdout)
|
||||||
|
|
||||||
|
class terminator:
|
||||||
|
def __init__(self,method):
|
||||||
|
self.process = method
|
||||||
|
def __ror__(self,input):
|
||||||
|
return self.process(input)
|
||||||
|
|
||||||
|
aslist = terminator(list)
|
||||||
|
asdict = terminator(dict)
|
||||||
|
astuple = terminator(tuple)
|
||||||
|
join = terminator("".join)
|
||||||
|
enum = terminator(enumerate)
|
||||||
|
|
||||||
|
class sort:
|
||||||
|
def __ror__(self,input):
|
||||||
|
ll = list(input)
|
||||||
|
ll.sort()
|
||||||
|
return ll
|
||||||
|
sort = sort()
|
||||||
|
|
||||||
|
class uniq:
|
||||||
|
def __ror__(self,input):
|
||||||
|
for i in input:
|
||||||
|
try:
|
||||||
|
if i == prev:
|
||||||
|
continue
|
||||||
|
except NameError:
|
||||||
|
pass
|
||||||
|
prev = i
|
||||||
|
yield i
|
||||||
|
uniq = uniq()
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import time
|
||||||
|
from tempfile import mkstemp, mkdtemp
|
||||||
|
|
||||||
|
def sleep(sleep_time = 5):
|
||||||
|
time.sleep(sleep_time)
|
||||||
|
|
||||||
|
def createTmpFile():
|
||||||
|
handle, path = mkstemp()
|
||||||
|
return path
|
||||||
|
|
||||||
|
def createTmpDir():
|
||||||
|
path = mkdtemp()
|
||||||
|
return path
|
||||||
|
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
Note that if you update this patch, please update this one as well:
|
||||||
|
|
||||||
|
eclass/ELT-patches/portage/1.4.1
|
||||||
|
|
||||||
|
The file name can stay 1.4.1, as it will still apply to all versions. Only
|
||||||
|
when a new version of libtool comes out that it do not apply to, then the
|
||||||
|
name should be bumped, but the patch content should stay fairly the same.
|
||||||
|
|
||||||
|
--- ltmain.sh Wed Apr 3 01:19:37 2002
|
||||||
|
+++ ltmain.sh Sun May 26 19:50:52 2002
|
||||||
|
@@ -3940,9 +3940,50 @@
|
||||||
|
$echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
- newdependency_libs="$newdependency_libs $libdir/$name"
|
||||||
|
+ # We do not want portage's install root ($D) present. Check only for
|
||||||
|
+ # this if the .la is being installed.
|
||||||
|
+ if test "$installed" = yes && test "$D"; then
|
||||||
|
+ eval mynewdependency_lib=`echo "$libdir/$name" |sed -e "s:$D:/:g" -e 's:/\+:/:g'`
|
||||||
|
+ else
|
||||||
|
+ mynewdependency_lib="$libdir/$name"
|
||||||
|
+ fi
|
||||||
|
+ # Do not add duplicates
|
||||||
|
+ if test "$mynewdependency_lib"; then
|
||||||
|
+ my_little_ninja_foo_1=`echo $newdependency_libs |$EGREP -e "$mynewdependency_lib"`
|
||||||
|
+ if test -z "$my_little_ninja_foo_1"; then
|
||||||
|
+ newdependency_libs="$newdependency_libs $mynewdependency_lib"
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+ ;;
|
||||||
|
+ *)
|
||||||
|
+ if test "$installed" = yes; then
|
||||||
|
+ # Rather use S=WORKDIR if our version of portage supports it.
|
||||||
|
+ # This is because some ebuild (gcc) do not use $S as buildroot.
|
||||||
|
+ if test "$PWORKDIR"; then
|
||||||
|
+ S="$PWORKDIR"
|
||||||
|
+ fi
|
||||||
|
+ # We do not want portage's build root ($S) present.
|
||||||
|
+ my_little_ninja_foo_2=`echo $deplib |$EGREP -e "$S"`
|
||||||
|
+ if test -n "$my_little_ninja_foo_2" && test "$S"; then
|
||||||
|
+ mynewdependency_lib=""
|
||||||
|
+ # We do not want portage's install root ($D) present.
|
||||||
|
+ my_little_ninja_foo_3=`echo $deplib |$EGREP -e "$D"`
|
||||||
|
+ elif test -n "$my_little_ninja_foo_3" && test "$D"; then
|
||||||
|
+ eval mynewdependency_lib=`echo "$deplib" |sed -e "s:$D:/:g" -e 's:/\+:/:g'`
|
||||||
|
+ else
|
||||||
|
+ mynewdependency_lib="$deplib"
|
||||||
|
+ fi
|
||||||
|
+ else
|
||||||
|
+ mynewdependency_lib="$deplib"
|
||||||
|
+ fi
|
||||||
|
+ # Do not add duplicates
|
||||||
|
+ if test "$mynewdependency_lib"; then
|
||||||
|
+ my_little_ninja_foo_4=`echo $newdependency_libs |$EGREP -e "$mynewdependency_lib"`
|
||||||
|
+ if test -z "$my_little_ninja_foo_4"; then
|
||||||
|
+ newdependency_libs="$newdependency_libs $mynewdependency_lib"
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
;;
|
||||||
|
- *) newdependency_libs="$newdependency_libs $deplib" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
dependency_libs="$newdependency_libs"
|
||||||
|
@@ -3975,6 +4005,10 @@
|
||||||
|
case $host,$output,$installed,$module,$dlname in
|
||||||
|
*cygwin*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
|
||||||
|
esac
|
||||||
|
+ # Do not add duplicates
|
||||||
|
+ if test "$installed" = yes && test "$D"; then
|
||||||
|
+ install_libdir=`echo "$install_libdir" |sed -e "s:$D:/:g" -e 's:/\+:/:g'`
|
||||||
|
+ fi
|
||||||
|
$echo > $output "\
|
||||||
|
# $outputname - a libtool library file
|
||||||
|
# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
--- ltmain.sh 2003-02-13 14:54:24.000000000 +0100
|
||||||
|
+++ ltmain.sh 2003-02-13 15:24:49.000000000 +0100
|
||||||
|
@@ -48,6 +48,11 @@ EOF
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
+# define variables for historic ltconfig's generated by Libtool 1.3
|
||||||
|
+test -z "$SED" && SED=sed
|
||||||
|
+test -z "$EGREP" && EGREP=egrep
|
||||||
|
+test -z "$LTCC" && LTCC=${CC-gcc}
|
||||||
|
+
|
||||||
|
# The name of this program.
|
||||||
|
progname=`$echo "$0" | ${SED} 's%^.*/%%'`
|
||||||
|
modename="$progname"
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# unpack magic
|
||||||
|
# maintainer baris and meren
|
||||||
|
|
||||||
|
#standart lisbrary modules
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import tarfile
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
#pisi modules
|
||||||
|
import util
|
||||||
|
|
||||||
|
class ArchiveBase(object):
|
||||||
|
def __init__(self, ctx):
|
||||||
|
self.type = ctx.spec.source.archiveType
|
||||||
|
self.fileName = os.path.basename(ctx.spec.source.archiveUri)
|
||||||
|
self.filePath = ctx.archives_dir() + '/' + self.fileName
|
||||||
|
|
||||||
|
def unpack(self, targetDir):
|
||||||
|
self.targetDir = targetDir
|
||||||
|
# first we check if we need to clean-up our working env.
|
||||||
|
if os.path.exists(self.targetDir):
|
||||||
|
util.clean_dir(self.targetDir)
|
||||||
|
else:
|
||||||
|
os.makedirs(self.targetDir)
|
||||||
|
|
||||||
|
class ArchiveTarFile(ArchiveBase):
|
||||||
|
def __init__(self, ctx):
|
||||||
|
super(ArchiveTarFile, self).__init__(ctx)
|
||||||
|
|
||||||
|
def unpack(self, targetDir):
|
||||||
|
super(ArchiveTarFile, self).unpack(targetDir)
|
||||||
|
|
||||||
|
rmode = ""
|
||||||
|
if self.type == 'tar':
|
||||||
|
rmode = 'r:'
|
||||||
|
elif self.type == 'targz':
|
||||||
|
rmode = 'r:gz'
|
||||||
|
elif self.type == 'tarbz2':
|
||||||
|
rmode = 'r:bz2'
|
||||||
|
tar = tarfile.open(self.filePath, rmode)
|
||||||
|
oldwd = os.getcwd()
|
||||||
|
os.chdir(self.targetDir)
|
||||||
|
for tarinfo in tar:
|
||||||
|
tar.extract(tarinfo)
|
||||||
|
os.chdir(oldwd)
|
||||||
|
tar.close()
|
||||||
|
|
||||||
|
class ArchiveZip(ArchiveBase):
|
||||||
|
def __init__(self, ctx):
|
||||||
|
super(ArchiveZip, self).__init__(ctx)
|
||||||
|
|
||||||
|
def unpack(self, targetDir):
|
||||||
|
super(ArchiveZip, self).unpack(targetDir)
|
||||||
|
|
||||||
|
zip = zipfile.ZipFile(self.filePath, 'r')
|
||||||
|
for file in zip.namelist():
|
||||||
|
ofile = self.targetDir + '/' + file
|
||||||
|
|
||||||
|
# a directory is present. lets continue
|
||||||
|
if os.path.isdir(ofile):
|
||||||
|
continue
|
||||||
|
# do we need to create parent directory for our file?
|
||||||
|
if not os.path.exists(os.path.dirname(ofile)):
|
||||||
|
os.mkdir(ofile)
|
||||||
|
continue
|
||||||
|
info = zip.getinfo(file)
|
||||||
|
# O.K. we know following line is dull. What we wanted to
|
||||||
|
# do was to compare the equality to 0xa0000000. But there
|
||||||
|
# is a known problem in Python regarding the hex/oct
|
||||||
|
# constants. Please see Guido's explanation at
|
||||||
|
# http://mail.python.org/pipermail/python-dev/2003-February/033029.html
|
||||||
|
if hex(info.external_attr)[2] == 'A':
|
||||||
|
target = zip.read(file)
|
||||||
|
os.symlink(target, ofile)
|
||||||
|
else:
|
||||||
|
buff = open (ofile, 'wb')
|
||||||
|
fileContent = zip.read(file)
|
||||||
|
buff.write(fileContent)
|
||||||
|
buff.close()
|
||||||
|
|
||||||
|
zip.close()
|
||||||
|
|
||||||
|
class Archive:
|
||||||
|
"""Unpack magic for Archive files..."""
|
||||||
|
|
||||||
|
def __init__(self, ctx):
|
||||||
|
"""accepted archive types:
|
||||||
|
targz, tarbz2, zip, tar"""
|
||||||
|
|
||||||
|
handlers = {
|
||||||
|
'targz': ArchiveTarFile,
|
||||||
|
'tarbz2': ArchiveTarFile,
|
||||||
|
'tar': ArchiveTarFile,
|
||||||
|
'zip': ArchiveZip
|
||||||
|
}
|
||||||
|
|
||||||
|
type = ctx.spec.source.archiveType
|
||||||
|
self.archive = handlers.get(type)(ctx)
|
||||||
|
|
||||||
|
def unpack(self, targetDir):
|
||||||
|
self.archive.unpack(targetDir)
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# package bulding stuff
|
||||||
|
# maintainer: baris and meren
|
||||||
|
|
||||||
|
# python standard library
|
||||||
|
import os
|
||||||
|
|
||||||
|
from fetcher import Fetcher
|
||||||
|
from archive import Archive
|
||||||
|
|
||||||
|
# import pisipackage
|
||||||
|
import util
|
||||||
|
from ui import ui
|
||||||
|
|
||||||
|
class PisiBuildError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# FIXME: this eventually has to go to ui module
|
||||||
|
# Infact all ui calls has nothing to do with this build process.
|
||||||
|
# There more of them in PisiBuild...
|
||||||
|
# And maybe we should consider moving PisiBuild.build() back to pisi-build
|
||||||
|
# CLI too.
|
||||||
|
# exa: This, like all others, will have a GUI or CLI, interchangeably
|
||||||
|
def displayProgress(pd):
|
||||||
|
out = '\r%-30.30s %3d%% %12.2f %s' % \
|
||||||
|
(pd['filename'], pd['percent'], pd['rate'], pd['symbol'])
|
||||||
|
ui.info(out)
|
||||||
|
|
||||||
|
class PisiBuild:
|
||||||
|
"""PisiBuild class, provides the package build and creation routines"""
|
||||||
|
def __init__(self, context):
|
||||||
|
self.ctx = context
|
||||||
|
self.work_dir = self.ctx.pkg_work_dir()
|
||||||
|
|
||||||
|
self.spec = self.ctx.spec
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
ui.info("Building PISI source package: %s\n" % self.spec.source.name)
|
||||||
|
|
||||||
|
ui.info("Fetching source from: %s\n" % self.spec.source.archiveUri)
|
||||||
|
self.fetchArchive(displayProgress)
|
||||||
|
ui.info("Source archive is stored: %s/%s\n"
|
||||||
|
%(self.ctx.archives_dir(), self.spec.source.archiveName))
|
||||||
|
|
||||||
|
self.solveBuildDependencies()
|
||||||
|
|
||||||
|
ui.info("Unpacking archive...")
|
||||||
|
self.unpackArchive()
|
||||||
|
ui.info(" unpacked (%s)\n" % self.ctx.pkg_work_dir())
|
||||||
|
|
||||||
|
self.applyPatches()
|
||||||
|
|
||||||
|
try:
|
||||||
|
specdir = os.path.dirname(self.ctx.pspecfile)
|
||||||
|
self.actionScript = open("/".join([specdir,self.ctx.const.actions_file])).read()
|
||||||
|
except IOError, e:
|
||||||
|
ui.error ("Action Script: %s\n" % e)
|
||||||
|
return
|
||||||
|
|
||||||
|
# FIXME: It's wrong to assume that unpacked archive
|
||||||
|
# will create a name-version top-level directory.
|
||||||
|
# Archive module should give the exact location.
|
||||||
|
# (from the assumption is evil dept.)
|
||||||
|
os.chdir(self.ctx.pkg_work_dir() + "/" + self.spec.source.name + "-" + self.spec.source.version)
|
||||||
|
locals = globals = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
exec compile(self.actionScript , "error", "exec") in locals,globals
|
||||||
|
except SyntaxError, e:
|
||||||
|
ui.error ("Error : %s\n" % e)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.configureSource(locals)
|
||||||
|
self.buildSource(locals)
|
||||||
|
self.installSource(locals)
|
||||||
|
|
||||||
|
# after all, we are ready to build/prepare the packages
|
||||||
|
self.buildPackages()
|
||||||
|
|
||||||
|
def fetchArchive(self, percentHook=None):
|
||||||
|
"""fetch an archive and store to ctx.archives_dir()
|
||||||
|
using fether.Fetcher"""
|
||||||
|
fetch = Fetcher(self.ctx)
|
||||||
|
|
||||||
|
# check if source already cached
|
||||||
|
destpath = fetch.filedest + "/" + fetch.filename
|
||||||
|
if os.access(destpath, os.R_OK):
|
||||||
|
if util.md5_file(destpath) == self.spec.source.archiveMD5:
|
||||||
|
ui.info('%s [cached]\n' % self.spec.source.archiveName)
|
||||||
|
return
|
||||||
|
|
||||||
|
if percentHook:
|
||||||
|
fetch.percentHook = percentHook
|
||||||
|
|
||||||
|
fetch.fetch()
|
||||||
|
|
||||||
|
# FIXME: What a ugly hack! We should really find a cleaner way for output.
|
||||||
|
if percentHook:
|
||||||
|
ui.info('\n')
|
||||||
|
|
||||||
|
def solveBuildDependencies(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def unpackArchive(self):
|
||||||
|
archive = Archive(self.ctx)
|
||||||
|
archive.unpack(self.work_dir)
|
||||||
|
|
||||||
|
def applyPatches(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def configureSource(self, locals):
|
||||||
|
func = self.ctx.const.setup_func
|
||||||
|
if func in locals:
|
||||||
|
ui.info("Configuring %s...\n" % self.spec.source.name)
|
||||||
|
locals[func]()
|
||||||
|
|
||||||
|
def buildSource(self, locals):
|
||||||
|
func = self.ctx.const.build_func
|
||||||
|
if func in locals:
|
||||||
|
ui.info("Building %s...\n" % self.spec.source.name)
|
||||||
|
locals[func]()
|
||||||
|
|
||||||
|
def installSource(self, locals):
|
||||||
|
func = self.ctx.const.install_func
|
||||||
|
if func in locals:
|
||||||
|
ui.info("Installing %s...\n" % self.spec.source.name)
|
||||||
|
locals[func]()
|
||||||
|
|
||||||
|
def buildPackages(self):
|
||||||
|
for package in self.spec.packages:
|
||||||
|
ui.info("** Building package %s\n" % package.name);
|
||||||
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
|
||||||
|
colors = {'black' : "\033[30m",
|
||||||
|
'red' : "\033[31m",
|
||||||
|
'green' : "\033[32m",
|
||||||
|
'yellow' : "\033[33m",
|
||||||
|
'blue' : "\033[34m",
|
||||||
|
'purple' : "\033[35m",
|
||||||
|
'cyan' : "\033[36m",
|
||||||
|
'white' : "\033[37m",
|
||||||
|
'brightblack' : "\033[01;30m",
|
||||||
|
'brightred' : "\033[01;31m",
|
||||||
|
'brightgreen' : "\033[01;32m",
|
||||||
|
'brightyellow' : "\033[01;33m",
|
||||||
|
'brightblue' : "\033[01;34m",
|
||||||
|
'brightmagenta' : "\033[01;35m",
|
||||||
|
'brightcyan' : "\033[01;36m",
|
||||||
|
'brightwhite' : "\033[01;37m",
|
||||||
|
'underlineblack' : "\033[04;30m",
|
||||||
|
'underlinered' : "\033[04;31m",
|
||||||
|
'underlinegreen' : "\033[04;32m",
|
||||||
|
'underlineyellow' : "\033[04;33m",
|
||||||
|
'underlineblue' : "\033[04;34m",
|
||||||
|
'underlinemagenta' : "\033[04;35m",
|
||||||
|
'underlinecyan' : "\033[04;36m",
|
||||||
|
'underlinewhite' : "\033[04;37m",
|
||||||
|
'blinkingblack' : "\033[05;30m",
|
||||||
|
'blinkingred' : "\033[05;31m",
|
||||||
|
'blinkinggreen' : "\033[05;32m",
|
||||||
|
'blinkingyellow' : "\033[05;33m",
|
||||||
|
'blinkingblue' : "\033[05;34m",
|
||||||
|
'blinkingmagenta' : "\033[05;35m",
|
||||||
|
'blinkingcyan' : "\033[05;36m",
|
||||||
|
'blinkingwhite' : "\033[05;37m",
|
||||||
|
'backgroundblack' : "\033[07;30m",
|
||||||
|
'backgroundred' : "\033[07;31m",
|
||||||
|
'backgroundgreen' : "\033[07;32m",
|
||||||
|
'backgroundyellow' : "\033[07;33m",
|
||||||
|
'backgroundblue' : "\033[07;34m",
|
||||||
|
'backgroundmagenta' : "\033[07;35m",
|
||||||
|
'backgroundcyan' : "\033[07;36m",
|
||||||
|
'backgroundwhite' : "\033[07;37m",
|
||||||
|
'default' : "\033[0m" }
|
||||||
|
|
||||||
|
def colorize(msg, color):
|
||||||
|
if colors.has_key(color):
|
||||||
|
return colors[color] + msg + colors['default']
|
||||||
|
else:
|
||||||
|
return msg
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# PISI configuration (static and dynamic)
|
||||||
|
|
||||||
|
from specfile import SpecFile
|
||||||
|
import oo
|
||||||
|
|
||||||
|
class Constants:
|
||||||
|
"Pisi constants"
|
||||||
|
|
||||||
|
c = oo.const()
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.c.lib_dir_suffix = "/var/lib/pisi"
|
||||||
|
self.c.db_dir_suffix = "/var/db/pisi"
|
||||||
|
self.c.archives_dir_suffix = "/var/cache/pisi/archives"
|
||||||
|
self.c.tmp_dir_suffix = "/var/tmp/pisi"
|
||||||
|
|
||||||
|
# directory suffixes for build
|
||||||
|
self.c.work_dir_suffix = "/work"
|
||||||
|
self.c.install_dir_suffix = "/install"
|
||||||
|
|
||||||
|
# file/directory names
|
||||||
|
self.c.actions_file = "actions.py"
|
||||||
|
self.c.files_dir = "files"
|
||||||
|
|
||||||
|
# functions in actions_file
|
||||||
|
self.c.setup_func = "setup"
|
||||||
|
self.c.build_func = "build"
|
||||||
|
self.c.install_func = "install"
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return getattr(self.c, attr)
|
||||||
|
|
||||||
|
def __setattr__(self, attr, value):
|
||||||
|
return setattr(self.c, attr, value)
|
||||||
|
|
||||||
|
def __delattr__(self, attr):
|
||||||
|
return delattr(self.c, attr)
|
||||||
|
|
||||||
|
class Context(object):
|
||||||
|
"""Config/Context Singleton"""
|
||||||
|
class __impl:
|
||||||
|
def __init__(self):
|
||||||
|
self.const = Constants()
|
||||||
|
# self.c.destdir = '' # install default to root by default
|
||||||
|
self.destdir = './tmp' # only for ALPHA
|
||||||
|
# the idea is that destdir can be set with --destdir=...
|
||||||
|
|
||||||
|
def setSpecFile(self, pspecfile):
|
||||||
|
self.pspecfile = pspecfile
|
||||||
|
spec = SpecFile()
|
||||||
|
spec.read(pspecfile)
|
||||||
|
spec.verify() # check pspec integrity
|
||||||
|
self.spec = spec
|
||||||
|
|
||||||
|
# directory accessor functions
|
||||||
|
# here is how it goes
|
||||||
|
# x_dir: system wide directory for storing info type x
|
||||||
|
# pkg_x_dir: per package directory for storing info type x
|
||||||
|
|
||||||
|
def lib_dir(self):
|
||||||
|
return self.destdir + self.const.lib_dir_suffix
|
||||||
|
|
||||||
|
def db_dir(self):
|
||||||
|
return self.destdir + self.const.db_dir_suffix
|
||||||
|
|
||||||
|
def archives_dir(self):
|
||||||
|
return self.destdir + self.const.archives_dir_suffix
|
||||||
|
|
||||||
|
def tmp_dir(self):
|
||||||
|
return self.destdir + self.const.tmp_dir_suffix
|
||||||
|
|
||||||
|
def pkg_work_dir(self):
|
||||||
|
packageDir = self.spec.source.name + '-' \
|
||||||
|
+ self.spec.source.version + '-' + self.spec.source.release
|
||||||
|
|
||||||
|
return self.destdir + self.const.tmp_dir_suffix \
|
||||||
|
+ '/' + packageDir + self.const.work_dir_suffix
|
||||||
|
|
||||||
|
def install_dir(self):
|
||||||
|
return self.tmp_dir() + self.const.install_dir_suffix
|
||||||
|
|
||||||
|
def pkg_install_dir(self):
|
||||||
|
packageDir = self.spec.source.name + '-' \
|
||||||
|
+ self.spec.source.version + '-' + self.spec.source.release
|
||||||
|
|
||||||
|
return self.destdir + self.const.tmp_dir_suffix \
|
||||||
|
+ '/' + packageDir + self.const.install_dir_suffix
|
||||||
|
|
||||||
|
__instance = __impl()
|
||||||
|
|
||||||
|
def __init__(self, pspecfile = None):
|
||||||
|
if pspecfile != None:
|
||||||
|
self.__instance.setSpecFile(pspecfile)
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return getattr(self.__instance, attr)
|
||||||
|
|
||||||
|
def __setattr__(self, attr, value):
|
||||||
|
return setattr(self.__instance, attr, value)
|
||||||
|
|
||||||
|
|
||||||
|
# create a default context WITH NO PSPEC
|
||||||
|
ctx = Context()
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# dependency analyzer
|
||||||
|
# maintainer: eray and caglar
|
||||||
|
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# download magic
|
||||||
|
# maintainer: baris and meren
|
||||||
|
|
||||||
|
# python standard library modules
|
||||||
|
import urlparse
|
||||||
|
import urllib2
|
||||||
|
import os
|
||||||
|
|
||||||
|
# pisi modules
|
||||||
|
import util
|
||||||
|
|
||||||
|
class FetchError (Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Fetcher:
|
||||||
|
"""Yet another Pisi tool for fetching files from various sources.."""
|
||||||
|
def __init__(self, ctx):
|
||||||
|
self.uri = ctx.spec.source.archiveUri
|
||||||
|
self.filedest = ctx.archives_dir()
|
||||||
|
util.check_dir(self.filedest)
|
||||||
|
self.scheme = "file"
|
||||||
|
self.netloc = ""
|
||||||
|
self.filepath = ""
|
||||||
|
self.filename = ""
|
||||||
|
self.percent = 0
|
||||||
|
self.rate = 0.0
|
||||||
|
self.percentHook = None
|
||||||
|
from string import split
|
||||||
|
u = urlparse.urlparse(self.uri)
|
||||||
|
self.scheme, self.netloc, self.filepath = u[0], u[1], u[2]
|
||||||
|
self.filename = os.path.basename(self.uri)
|
||||||
|
|
||||||
|
def fetch (self):
|
||||||
|
"""Return value: Fetched file's full path.."""
|
||||||
|
|
||||||
|
if self.filename == "":
|
||||||
|
self.err("filename error")
|
||||||
|
|
||||||
|
if os.access(self.filedest, os.W_OK) == False:
|
||||||
|
self.err("no perm to write to dest dir")
|
||||||
|
|
||||||
|
scheme_err = lambda: self.err("unexpected scheme")
|
||||||
|
|
||||||
|
handlers = {
|
||||||
|
'file': self.fetchLocalFile,
|
||||||
|
'http': self.fetchRemoteFile,
|
||||||
|
'ftp' : self.fetchRemoteFile
|
||||||
|
}; handlers.get(self.scheme, scheme_err)()
|
||||||
|
|
||||||
|
return self.filedest + "/" + self.filename
|
||||||
|
|
||||||
|
def doGrab(self, file, dest, totalsize):
|
||||||
|
symbols = [' B/s', 'KB/s', 'MB/s', 'GB/s']
|
||||||
|
from time import time
|
||||||
|
tt, oldsize = int(time()), 0
|
||||||
|
p = Progress(totalsize)
|
||||||
|
bs, size = 1024, 0
|
||||||
|
symbol, depth = "B/s", 0
|
||||||
|
st = time()
|
||||||
|
chunk = file.read(bs)
|
||||||
|
size = size + len(chunk)
|
||||||
|
self.percent = p.update(size)
|
||||||
|
while chunk:
|
||||||
|
dest.write(chunk)
|
||||||
|
chunk = file.read(bs)
|
||||||
|
size = size + len(chunk)
|
||||||
|
ct = time()
|
||||||
|
if int(tt) != int(ct):
|
||||||
|
self.rate = size / (ct - st)
|
||||||
|
while self.rate > 1000 and depth < 3:
|
||||||
|
self.rate /= 1024
|
||||||
|
depth += 1
|
||||||
|
symbol, depth = symbols[depth], 0
|
||||||
|
oldsize, tt = size, time()
|
||||||
|
if p.update(size):
|
||||||
|
self.percent = p.percent
|
||||||
|
if self.percentHook != None:
|
||||||
|
retval = {'filename': self.filename,
|
||||||
|
'percent' : self.percent,
|
||||||
|
'rate': self.rate,
|
||||||
|
'symbol': symbol}
|
||||||
|
self.percentHook(retval)
|
||||||
|
|
||||||
|
dest.close()
|
||||||
|
|
||||||
|
|
||||||
|
def fetchLocalFile (self):
|
||||||
|
from shutil import copyfile
|
||||||
|
|
||||||
|
if os.access(self.filepath, os.F_OK) == False:
|
||||||
|
self.err("no such file or no perm to read")
|
||||||
|
|
||||||
|
dest = open(self.filedest + "/" + self.filename , "w")
|
||||||
|
totalsize = os.path.getsize(self.filepath)
|
||||||
|
file = open(self.filepath)
|
||||||
|
self.doGrab(file, dest, totalsize)
|
||||||
|
|
||||||
|
|
||||||
|
def fetchRemoteFile (self):
|
||||||
|
from httplib import HTTPException
|
||||||
|
|
||||||
|
try:
|
||||||
|
file = urllib2.urlopen(self.uri)
|
||||||
|
headers = file.info()
|
||||||
|
|
||||||
|
except ValueError, e:
|
||||||
|
self.err('%s' % (e, ))
|
||||||
|
except IOError, e:
|
||||||
|
self.err('%s' % (e, ))
|
||||||
|
except OSError, e:
|
||||||
|
self.err('%s' % (e, ))
|
||||||
|
except HTTPException, e:
|
||||||
|
self.err(('(%s): %s') % (e.__class__.__name__, e))
|
||||||
|
|
||||||
|
if not headers is None and not headers.has_key('Content-Length'):
|
||||||
|
self.err('file not found')
|
||||||
|
else: totalsize = int(headers['Content-Length'])
|
||||||
|
|
||||||
|
dest = open(self.filedest + "/" + self.filename , "w")
|
||||||
|
self.doGrab(file, dest, totalsize)
|
||||||
|
|
||||||
|
|
||||||
|
def err (self, error):
|
||||||
|
raise FetchError(error)
|
||||||
|
|
||||||
|
class Progress:
|
||||||
|
def __init__(self, totalsize):
|
||||||
|
self.totalsize = totalsize
|
||||||
|
self.percent = 0
|
||||||
|
|
||||||
|
def update(self, size):
|
||||||
|
percent = (size * 100) / self.totalsize
|
||||||
|
if percent and self.percent is not percent:
|
||||||
|
self.percent = percent
|
||||||
|
return percent
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#import package
|
||||||
|
from specfile import *
|
||||||
|
from package import Package
|
||||||
|
import util
|
||||||
|
from context import ctx
|
||||||
|
from ui import ui
|
||||||
|
import installdb
|
||||||
|
import packagedb
|
||||||
|
import dependency
|
||||||
|
#import conflicts
|
||||||
|
|
||||||
|
class InstallError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def install_package_file(package_fn):
|
||||||
|
|
||||||
|
package = Package(package_fn, 'r')
|
||||||
|
# extract control files
|
||||||
|
util.clean_dir(ctx.install_dir())
|
||||||
|
ui.info('extracting files\n')
|
||||||
|
package.extract_PISI_files(ctx.install_dir())
|
||||||
|
|
||||||
|
# verify package
|
||||||
|
# check if we have all required files
|
||||||
|
|
||||||
|
metadata = MetaData()
|
||||||
|
metadata.read(ctx.install_dir() + '/metadata.xml')
|
||||||
|
# check package semantics
|
||||||
|
if not metadata.verify():
|
||||||
|
raise InstallError("MetaData format wrong")
|
||||||
|
|
||||||
|
# check file system requirements
|
||||||
|
# what to do if / is split into /usr, /var, etc.?
|
||||||
|
|
||||||
|
# check conflicts
|
||||||
|
# check dependencies
|
||||||
|
|
||||||
|
# unzip package in place
|
||||||
|
|
||||||
|
# update databases
|
||||||
|
|
||||||
|
# installdb
|
||||||
|
installdb.install(spec.spec.install_dir() + '/files.xml')
|
||||||
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# installation database
|
||||||
|
# maintainer: eray and caglar
|
||||||
|
|
||||||
|
import os
|
||||||
|
import bsddb.dbshelve as shelve
|
||||||
|
|
||||||
|
from context import ctx
|
||||||
|
import util
|
||||||
|
|
||||||
|
util.check_dir(ctx.db_dir())
|
||||||
|
d = shelve.open(ctx.db_dir() + '/install.bdb')
|
||||||
|
files_dir = ctx.archives_dir() + "/files"
|
||||||
|
|
||||||
|
class InstallDBError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def files_name(name, version, release):
|
||||||
|
return files_dir + '/' + name + '-' + version + '-' + release
|
||||||
|
|
||||||
|
def files(n, v, r):
|
||||||
|
return file(files_name(n,v,r))
|
||||||
|
|
||||||
|
def is_recorded(name, version, release):
|
||||||
|
key = name + version + release
|
||||||
|
return d.has_key(key)
|
||||||
|
|
||||||
|
def is_installed(name, version, release):
|
||||||
|
key = name + version + release
|
||||||
|
return is_recorded(name,version,release) and d[key]=='i'
|
||||||
|
|
||||||
|
def is_removed(name, version, release):
|
||||||
|
key = name + version + release
|
||||||
|
return is_recorded(name,version,release) and d[key]=='r'
|
||||||
|
|
||||||
|
def install(name, version, release, files_xml):
|
||||||
|
key = name + version + release
|
||||||
|
if is_installed(name, version, release):
|
||||||
|
raise InstallDBError("already installed")
|
||||||
|
d[key] = 'i'
|
||||||
|
util.copy_file(files_xml, files_name(name, version, release))
|
||||||
|
|
||||||
|
def remove(name, version, release):
|
||||||
|
key = name + version + release
|
||||||
|
d[key] = 'r'
|
||||||
|
|
||||||
|
def purge(name, version, release):
|
||||||
|
os.unlink(files_name(name, version, release))
|
||||||
|
key = name + version + release
|
||||||
|
del d[key]
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# OO extensions
|
||||||
|
# thes are really cool, you can't do this in C++ :)
|
||||||
|
|
||||||
|
class const:
|
||||||
|
"Constant members implementation"
|
||||||
|
class ConstError(TypeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
if self.__dict__.has_key(name):
|
||||||
|
raise self.ConstError, "Can't rebind constant: %s" % name
|
||||||
|
# Binding an attribute once to a const is available
|
||||||
|
self.__dict__[name] = value
|
||||||
|
|
||||||
|
def __delattr__(self, name):
|
||||||
|
if self.__dict__.has_key(name):
|
||||||
|
raise self.ConstError, "Can't unbind constant: %s" % name
|
||||||
|
# we don't have an attribute by this name
|
||||||
|
raise NameError, name
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# package abstraction
|
||||||
|
# provides methods to add/remove files, extract control files
|
||||||
|
# maintainer: baris and meren
|
||||||
|
|
||||||
|
class Package:
|
||||||
|
"""Package: PISI package class"""
|
||||||
|
def __init__(self, packagefn, mode):
|
||||||
|
self.filename = packagefn
|
||||||
|
self.mode = mode # bu gerekli mi?
|
||||||
|
# etc. etc.
|
||||||
|
|
||||||
|
def add_file(self, fn):
|
||||||
|
"""add a file to package"""
|
||||||
|
|
||||||
|
def extract(self, outdir):
|
||||||
|
"""extract entire package contents to directory"""
|
||||||
|
extract_dir('', outdir) # means package root
|
||||||
|
|
||||||
|
def extract_file(self, path, outdir):
|
||||||
|
"""extract file with path to outdir"""
|
||||||
|
|
||||||
|
def extract_dir(self, dir, outdir):
|
||||||
|
"""extract directory recursively"""
|
||||||
|
|
||||||
|
def extract_PISI_files(self, outdir):
|
||||||
|
"""extract PISI control files: metadata.xml, files.xml,
|
||||||
|
action scripts, etc."""
|
||||||
|
self.extract_file('metadata.xml', outdir)
|
||||||
|
self.extract_file('files.xml', outdir)
|
||||||
|
self.extract_dir('Config', outdir)
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# package database
|
||||||
|
# interface for update/query to local package repository
|
||||||
|
# maintainer: eray and caglar
|
||||||
|
|
||||||
|
# we basically store everything in PackageInfo class
|
||||||
|
# yes, we are cheap
|
||||||
|
|
||||||
|
import bsddb.dbshelve as shelve
|
||||||
|
|
||||||
|
import util
|
||||||
|
from context import ctx
|
||||||
|
|
||||||
|
util.check_dir(ctx.db_dir())
|
||||||
|
d = shelve.open(ctx.db_dir() + '/package.bdb')
|
||||||
|
|
||||||
|
def has_package(name):
|
||||||
|
return d.has_key(name)
|
||||||
|
|
||||||
|
def get_package(name):
|
||||||
|
return d[name]
|
||||||
|
|
||||||
|
def add_package(name, package_info):
|
||||||
|
d[name] = package_info
|
||||||
|
|
||||||
|
def remove_package(name):
|
||||||
|
del d[name]
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# package source database
|
||||||
|
# interface for update/query to local package repository
|
||||||
|
# maintainer: eray and caglar
|
||||||
|
|
||||||
|
# we basically store everything in sourceinfo class
|
||||||
|
# yes, we are cheap
|
||||||
|
|
||||||
|
import bsddb.dbshelve as shelve
|
||||||
|
|
||||||
|
util.check_dir(config.db_dir())
|
||||||
|
d = shelve.open(config.db_dir() + '/source.bdb')
|
||||||
|
|
||||||
|
def add_source(name, source_info):
|
||||||
|
d[name] = source_info
|
||||||
|
|
||||||
|
def remove_source(name):
|
||||||
|
del d[name]
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# read/write PISI source package specification file
|
||||||
|
|
||||||
|
import xml.dom.minidom
|
||||||
|
from xmlfile import *
|
||||||
|
from os.path import basename
|
||||||
|
|
||||||
|
class PatchInfo:
|
||||||
|
def __init__(self, filenm, ctype):
|
||||||
|
self.filename = filenm
|
||||||
|
self.compressionType = ctype
|
||||||
|
|
||||||
|
def __init__(self, node):
|
||||||
|
self.filename = getNodeText(node)
|
||||||
|
self.compressionType = getNodeAttribute(node, "compressionType")
|
||||||
|
|
||||||
|
class DepInfo:
|
||||||
|
def __init__(self, node):
|
||||||
|
self.package = getNodeText(node).strip()
|
||||||
|
self.versionFrom = getNodeAttribute(node, "versionFrom")
|
||||||
|
|
||||||
|
class HistoryInfo:
|
||||||
|
def __init__(self, node):
|
||||||
|
self.date = getNodeText(getNode(node, "Date"))
|
||||||
|
self.version = getNodeText(getNode(node, "Version"))
|
||||||
|
self.release = getNodeText(getNode(node, "Release"))
|
||||||
|
|
||||||
|
class PathInfo:
|
||||||
|
def __init__(self, node):
|
||||||
|
self.pathname = getNodeText(node)
|
||||||
|
self.fileType = getNodeAttribute(node, "fileType")
|
||||||
|
|
||||||
|
# a structure to hold source information
|
||||||
|
class SourceInfo:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class PackageInfo:
|
||||||
|
def __init__(self, node):
|
||||||
|
self.name = getNodeText(getNode(node, "Name"))
|
||||||
|
self.summary = getNodeText(getNode(node, "Summary"))
|
||||||
|
self.description = getNodeText(getNode(node, "Description"))
|
||||||
|
self.category = getNodeText(getNode(node, "Category"))
|
||||||
|
iDepElts = getAllNodes(node, "InstallDependencies")
|
||||||
|
self.installDeps = [DepInfo(x) for x in iDepElts]
|
||||||
|
rtDepElts = getAllNodes(node, "RuntimeDependencies")
|
||||||
|
self.runtimeDeps = [DepInfo(x) for x in rtDepElts]
|
||||||
|
self.paths = [PathInfo(x) for x in getAllNodes(node, "Files/Path")]
|
||||||
|
|
||||||
|
class SpecFile(XmlFile):
|
||||||
|
"""A class for reading/writing from/to a PSPEC (PISI SPEC) file."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
XmlFile.__init__(self,"PSPEC")
|
||||||
|
|
||||||
|
def read(self, filename):
|
||||||
|
"""Read PSPEC file"""
|
||||||
|
|
||||||
|
self.readxml(filename)
|
||||||
|
|
||||||
|
self.source = SourceInfo()
|
||||||
|
self.source.name = self.getChildText("Source/Name")
|
||||||
|
archiveNode = self.getNode("Source/Archive")
|
||||||
|
self.source.archiveUri = getNodeText(archiveNode).strip()
|
||||||
|
self.source.archiveName = basename(self.source.archiveUri)
|
||||||
|
self.source.archiveType = getNodeAttribute(archiveNode, "archType")
|
||||||
|
self.source.archiveMD5 = getNodeAttribute(archiveNode, "md5sum")
|
||||||
|
patchElts = self.getChildElts("Source/Patches")
|
||||||
|
if patchElts:
|
||||||
|
self.source.patches = [PatchInfo(p) for p in patchElts]
|
||||||
|
|
||||||
|
buildDepElts = self.getChildElts("Source/BuildDependencies")
|
||||||
|
if buildDepElts:
|
||||||
|
self.source.buildDeps = [DepInfo(d) for d in buildDepElts]
|
||||||
|
|
||||||
|
historyElts = self.getAllNodes("History/Update")
|
||||||
|
self.source.history = [HistoryInfo(x) for x in historyElts]
|
||||||
|
|
||||||
|
# As we have no Source/Version tag we need to get
|
||||||
|
# the last version and release information
|
||||||
|
# from the first child of History/Update. And it works :)
|
||||||
|
self.source.version = self.source.history[0].version
|
||||||
|
self.source.release = self.source.history[0].release
|
||||||
|
|
||||||
|
# find all binary packages
|
||||||
|
packageElts = self.getAllNodes("Package")
|
||||||
|
self.packages = [PackageInfo(p) for p in packageElts]
|
||||||
|
|
||||||
|
def verify(self):
|
||||||
|
"""Verify PSPEC structures, are they what we want of them?"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
def write(self, filename):
|
||||||
|
"""Write PSPEC file"""
|
||||||
|
self.writexml(filename)
|
||||||
|
|
||||||
|
class MetaData(SpecFile):
|
||||||
|
"""This is a superset of the source spec definition"""
|
||||||
|
|
||||||
|
def read(self, filename):
|
||||||
|
SpecFile.read(filename)
|
||||||
|
distribution = self.getNodeText("Source/Distribution")
|
||||||
|
distributionRelease = self.getNodeText("Source/DistributionRelease")
|
||||||
|
architecture = self.getNodeText("Source/Architecture")
|
||||||
|
installSize = self.getNodeText("Source/InstallSize")
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# generic user interface
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from colors import colorize
|
||||||
|
|
||||||
|
def register(_impl):
|
||||||
|
""" Register a UI implementation"""
|
||||||
|
ui = _impl
|
||||||
|
|
||||||
|
# default UI implementation
|
||||||
|
class CLI:
|
||||||
|
def __init__(self, debuggy = True):
|
||||||
|
self.showDebug = debuggy
|
||||||
|
|
||||||
|
def info(self, msg):
|
||||||
|
sys.stdout.write(colorize(msg, 'blue'))
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
def debug(self, msg):
|
||||||
|
if showDebug:
|
||||||
|
sys.stdout.write(msg)
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
def error(self,msg):
|
||||||
|
sys.stdout.write(colorize(msg, 'red'))
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
# default UI is CLI
|
||||||
|
ui = CLI()
|
||||||
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# misc. utility functions, including process and file utils
|
||||||
|
# maintainer: eray and caglar and baris and meren!
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import md5
|
||||||
|
from ui import ui
|
||||||
|
|
||||||
|
class FileError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class UtilError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# shorthand to check if a file exists
|
||||||
|
def check_file(file, mode = os.F_OK):
|
||||||
|
if not os.access(file, mode):
|
||||||
|
raise FileError("File " + file + " not found")
|
||||||
|
|
||||||
|
# check if directory exists, and create if it doesn't
|
||||||
|
# works recursively
|
||||||
|
# FIXME: could have a better name
|
||||||
|
def check_dir(dir):
|
||||||
|
dir = dir.strip().rstrip("/")
|
||||||
|
if not os.access(dir, os.F_OK):
|
||||||
|
os.makedirs(dir)
|
||||||
|
|
||||||
|
def clean_dir(top):
|
||||||
|
"""Remove all content of a directory (top)"""
|
||||||
|
for root, dirs, files in os.walk(top, topdown=False):
|
||||||
|
for name in files:
|
||||||
|
os.remove(os.path.join(root, name))
|
||||||
|
for name in dirs:
|
||||||
|
os.rmdir(os.path.join(root, name))
|
||||||
|
|
||||||
|
def copy_file(s,d):
|
||||||
|
check_file(s)
|
||||||
|
check_dir(os.path.dirname(d))
|
||||||
|
fs = file(s, 'rb')
|
||||||
|
fd = file(d, 'wb')
|
||||||
|
for l in fs:
|
||||||
|
fd.write(l)
|
||||||
|
|
||||||
|
def copy_dir():
|
||||||
|
raise UtilError("not implemented")
|
||||||
|
|
||||||
|
def md5_file(filename):
|
||||||
|
m = md5.new()
|
||||||
|
f = file(filename, 'rb')
|
||||||
|
for l in f:
|
||||||
|
m.update(l)
|
||||||
|
return m.hexdigest()
|
||||||
|
|
||||||
|
# run a command non-interactively
|
||||||
|
def run_batch(cmd):
|
||||||
|
ui.info('running ' + cmd)
|
||||||
|
a = os.popen(cmd)
|
||||||
|
lines = a.readlines()
|
||||||
|
ret = a.close()
|
||||||
|
ui.debug('return value ' + ret)
|
||||||
|
successful = ret == None
|
||||||
|
if not successful:
|
||||||
|
ui.error('ERROR: executing command: ' + cmd + '\n' + strlist(lines))
|
||||||
|
return (successful,lines)
|
||||||
|
|
||||||
|
# print a list
|
||||||
|
def strlist(l):
|
||||||
|
return string.join(map(lambda x: str(x) + ' ', l))
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# some helper functions for using minidom
|
||||||
|
|
||||||
|
import xml.dom.minidom as mdom
|
||||||
|
|
||||||
|
class XmlError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# static functions
|
||||||
|
|
||||||
|
def getNodeAttribute(node, attrname):
|
||||||
|
for i in range(node.attributes.length):
|
||||||
|
attr = node.attributes.item(i)
|
||||||
|
if attr.name == attrname:
|
||||||
|
return attr.childNodes[0].data
|
||||||
|
|
||||||
|
def getNodeText(node):
|
||||||
|
# get the first child
|
||||||
|
try:
|
||||||
|
child = node.childNodes[0]
|
||||||
|
except IndexError:
|
||||||
|
return None
|
||||||
|
except AttributeError: # no node by that name
|
||||||
|
return None
|
||||||
|
if child.nodeType == child.TEXT_NODE:
|
||||||
|
return child.data
|
||||||
|
else:
|
||||||
|
raise XmlError("getNodeText: Expected text node, got something else!")
|
||||||
|
|
||||||
|
def getChildText(node_s, tagpath):
|
||||||
|
node = getNode(node_s, tagpath)
|
||||||
|
if not node:
|
||||||
|
return None
|
||||||
|
return getNodeText(node)
|
||||||
|
|
||||||
|
def getChildElts(node):
|
||||||
|
"""get only child elements"""
|
||||||
|
return filter(lambda x:x.nodeType == x.ELEMENT_NODE, node.childNodes)
|
||||||
|
|
||||||
|
def getNode(node, tagpath):
|
||||||
|
"""returns the *first* matching node for given tag path."""
|
||||||
|
|
||||||
|
tags = tagpath.split('/')
|
||||||
|
|
||||||
|
# iterative code to search for the path
|
||||||
|
|
||||||
|
# get DOM for top node
|
||||||
|
nodeList = node.getElementsByTagName(tags[0])
|
||||||
|
if len(nodeList) == 0:
|
||||||
|
return None # not found
|
||||||
|
|
||||||
|
node = nodeList[0] # discard other matches
|
||||||
|
for tag in tags[1:]:
|
||||||
|
nodeList = node.getElementsByTagName(tag)
|
||||||
|
if len(nodeList) == 0:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
node = nodeList[0]
|
||||||
|
|
||||||
|
return node
|
||||||
|
|
||||||
|
def getAllNodes(node, tags):
|
||||||
|
"""retrieve all nodes that match a given tag path."""
|
||||||
|
|
||||||
|
if len(tags) == 0:
|
||||||
|
return []
|
||||||
|
|
||||||
|
nodeList = node.getElementsByTagName(tags[0])
|
||||||
|
if len(nodeList) == 0:
|
||||||
|
return []
|
||||||
|
|
||||||
|
for tag in tags[1:]:
|
||||||
|
results = map(lambda x: x.getElementsByTagName(tag),nodeList)
|
||||||
|
nodeList = []
|
||||||
|
for x in results:
|
||||||
|
nodeList.extend(x)
|
||||||
|
pass # emacs indentation error, keep it here
|
||||||
|
|
||||||
|
if len(nodeList) == 0:
|
||||||
|
return []
|
||||||
|
|
||||||
|
return nodeList
|
||||||
|
|
||||||
|
|
||||||
|
# xmlfile class that further abstracts a dom object
|
||||||
|
|
||||||
|
class XmlFile(object):
|
||||||
|
"""A class for retrieving information from an XML file"""
|
||||||
|
|
||||||
|
def __init__(self, rootTag):
|
||||||
|
self.rootTag = rootTag
|
||||||
|
|
||||||
|
def readxml(self, fileName):
|
||||||
|
self.dom = mdom.parse(fileName)
|
||||||
|
|
||||||
|
def writexml(self, fileName):
|
||||||
|
f = file(fileName,'w')
|
||||||
|
self.dom.writexml(f)
|
||||||
|
|
||||||
|
def verifyRootTag(self):
|
||||||
|
if self.dom.documentElement.tagName != self.rootTag:
|
||||||
|
raise XmlError("Root tagname not " + self.rootTag + " as expected")
|
||||||
|
|
||||||
|
def getNode(self, tagPath):
|
||||||
|
"""returns the *first* matching node for given tag path."""
|
||||||
|
self.verifyRootTag()
|
||||||
|
return getNode(self.dom.documentElement, tagPath)
|
||||||
|
|
||||||
|
def getAllNodes(self, tagPath):
|
||||||
|
"""returns all nodes matching a given tag path."""
|
||||||
|
self.verifyRootTag()
|
||||||
|
tags = tagPath.split('/')
|
||||||
|
return getAllNodes(self.dom.documentElement, tags)
|
||||||
|
|
||||||
|
def getChildren(self, tagpath):
|
||||||
|
""" returns the children of the given path"""
|
||||||
|
node = self.getNode(tagpath)
|
||||||
|
return node.childNodes
|
||||||
|
|
||||||
|
# get only elements of a given type
|
||||||
|
# BUG: this doesn't work
|
||||||
|
def getChildrenWithType(self, tagpath, type):
|
||||||
|
""" returns the children of the given path, only with given type """
|
||||||
|
node = self.getNode(tagpath)
|
||||||
|
return filter(lambda x:x.nodeType == type, node.childNodes)
|
||||||
|
|
||||||
|
# get only child elements
|
||||||
|
def getChildElts(self, tagpath):
|
||||||
|
""" returns the children of the given path, only with given type """
|
||||||
|
node = self.getNode(tagpath)
|
||||||
|
try:
|
||||||
|
return filter(lambda x:x.nodeType == x.ELEMENT_NODE, node.childNodes)
|
||||||
|
except AttributeError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def getChildText(self, tagpath):
|
||||||
|
node = self.getNode(tagpath)
|
||||||
|
if not node:
|
||||||
|
return None
|
||||||
|
return getNodeText(node)
|
||||||
|
|
||||||
Reference in New Issue
Block a user