diff --git a/pisi.e3p b/pisi.e3p index 1bf5c07d..f72ff3c2 100644 --- a/pisi.e3p +++ b/pisi.e3p @@ -1,15 +1,16 @@ - - + + Python Qt The package management software of Pardus distribution. + PiSi Development Team - + pisi@uludag.org.tr tools @@ -372,6 +373,14 @@ tests xmlexttests.py + + tests + specfileoldtests.py + + + pisi + specfileold.py + @@ -409,10 +418,10 @@ {'standardLayout': 1} - + - + diff --git a/pisi/build.py b/pisi/build.py index 220824ac..baf80ebb 100644 --- a/pisi/build.py +++ b/pisi/build.py @@ -50,8 +50,8 @@ def get_file_type(path, pinfoList): ftype = "" path = "/"+path # we need a real path. for pinfo in pinfoList: - if util.subpath(pinfo.pathname, path): - length = len(pinfo.pathname) + if util.subpath(pinfo.path, path): + length = len(pinfo.path) if depth < length: depth = length ftype = pinfo.fileType @@ -62,20 +62,20 @@ def check_path_collision(package, pkgList): the paths of packages in pkgList. The return value will be the list containing the paths that collide.""" collisions = [] - for pinfo in package.paths: + for pinfo in package.files: for pkg in pkgList: if pkg is package: continue - for path in pkg.paths: - # if pinfo.pathname is a subpath of path.pathname like - # the example below. path.patname is marked as a + for path in pkg.files: + # if pinfo.path is a subpath of path.path like + # the example below. path.path is marked as a # collide. Exp: - # pinfo.pathname: /usr/share - # path.pathname: /usr/share/doc - if util.subpath(pinfo.pathname, path.pathname): - collisions.append(path.pathname) + # pinfo.path: /usr/share + # path.path: /usr/share/doc + if util.subpath(pinfo.path, path.path): + collisions.append(path.path) ctx.ui.error(_('Path %s belongs in multiple packages') % - path.pathname) + path.path) return collisions # a dynamic build context @@ -191,10 +191,10 @@ class Builder: ctx.ui.info(_("CCache detected...")) def fetch_source_archive(self): - ctx.ui.info(_("Fetching source from: %s") % self.spec.source.archiveUri) + ctx.ui.info(_("Fetching source from: %s") % self.spec.source.archive.uri) self.sourceArchive.fetch() ctx.ui.info(_("Source archive is stored: %s/%s") - %(ctx.config.archives_dir(), self.spec.source.archiveName)) + %(ctx.config.archives_dir(), self.spec.source.archive.name)) def unpack_source_archive(self): ctx.ui.info(_("Unpacking archive...")) @@ -274,7 +274,7 @@ class Builder: # find out the build dependencies that are not satisfied... dep_unsatis = [] - for dep in self.spec.source.buildDeps: + for dep in self.spec.source.buildDependencies: if not dependency.installed_satisfies_dep(dep): dep_unsatis.append(dep) @@ -340,8 +340,8 @@ class Builder: size, d = 0, self.bctx.pkg_install_dir() - for path in package.paths: - size += util.dir_size(util.join_path(d, path.pathname)) + for path in package.files: + size += util.dir_size(util.join_path(d, path.path)) metadata.package.installedSize = str(size) @@ -377,15 +377,15 @@ class Builder: # add the files under material path for fpath, fhash in util.get_file_hashes(path, collisions, install_dir): frpath = util.removepathprefix(install_dir, fpath) # relative path - ftype = get_file_type(frpath, package.paths) + ftype = get_file_type(frpath, package.files) try: # broken links and empty dirs can cause problem fsize = str(os.path.getsize(fpath)) except OSError: fsize = None d[frpath] = FileInfo(frpath, ftype, fsize, fhash) - for pinfo in package.paths: - wildcard_path = util.join_path(install_dir, pinfo.pathname) + for pinfo in package.files: + wildcard_path = util.join_path(install_dir, pinfo.path) for path in glob.glob(wildcard_path): add_path(path) diff --git a/pisi/metadata.py b/pisi/metadata.py index 2c6eb517..813afbee 100644 --- a/pisi/metadata.py +++ b/pisi/metadata.py @@ -39,9 +39,10 @@ class Source: class Package: __metaclass__ = xmlfile.autoxml + # FIXME: copied attributes t_Name = [ xmlfile.String, xmlfile.mandatory ] - t_Summary = [ xmlfile.String, xmlfile.mandatory ] - t_Description = [ xmlfile.String, xmlfile.mandatory ] + t_Summary = [ xmlfile.LocalText, xmlfile.optional ] + t_Description = [ xmlfile.LocalText, xmlfile.optional ] t_IsA = [ [xmlfile.String], xmlfile.optional] t_PartOf = [xmlfile.String, xmlfile.optional] t_License = [ [xmlfile.String], xmlfile.optional] @@ -53,6 +54,7 @@ class Package: #t_RequiresComar = [ [xmlfile.String], xmlfile.mandatory, "Requires/COMAR"] t_AdditionalFiles = [ [specfile.AdditionalFile], xmlfile.optional] t_History = [ [specfile.Update], xmlfile.optional] + t_Build = [ xmlfile.Integer, xmlfile.optional] t_Distribution = [ xmlfile.String, xmlfile.mandatory] t_DistributionRelease = [ xmlfile.String, xmlfile.mandatory] @@ -81,25 +83,23 @@ class MetaData(xmlfile.XmlFile): #t_History = [ [Update], xmlfile.mandatory] def from_spec(self, src, pkg): - self.source = SourceInfo() self.source.name = src.name self.source.homepage = src.homepage self.source.packager = src.packager - self.package = PackageInfo() self.package.name = pkg.name self.package.summary = pkg.summary self.package.description = pkg.description self.package.icon = pkg.icon - self.package.isa = pkg.isa - self.package.partof = pkg.partof + self.package.isA = pkg.isA + self.package.partOf = pkg.partOf self.package.license = pkg.license - self.package.runtimeDeps = pkg.runtimeDeps - self.package.paths = pkg.paths + self.package.runtimeDependencies = pkg.runtimeDependencies + self.package.files = pkg.files # FIXME: no need to copy full history with comments self.package.history = src.history self.package.conflicts = pkg.conflicts self.package.providesComar = pkg.providesComar - self.package.requiresComar = pkg.requiresComar + #self.package.requiresComar = pkg.requiresComar self.package.additionalFiles = pkg.additionalFiles # FIXME: right way to do it? diff --git a/pisi/sourcearchive.py b/pisi/sourcearchive.py index 8c6d9556..61ef5409 100644 --- a/pisi/sourcearchive.py +++ b/pisi/sourcearchive.py @@ -36,11 +36,9 @@ class SourceArchive: """source archive. this is a class responsible for fetching and unpacking a source archive""" def __init__(self, bctx): - self.url = URI(bctx.spec.source.archiveUri) + self.url = URI(bctx.spec.source.archive.uri) self.archiveFile = join(ctx.config.archives_dir(), self.url.filename()) - self.archiveName = bctx.spec.source.archiveName - self.archiveType = bctx.spec.source.archiveType - self.archiveSHA1 = bctx.spec.source.archiveSHA1 + self.archive = bctx.spec.source.archive self.bctx = bctx def fetch(self, interactive=True): @@ -55,18 +53,18 @@ class SourceArchive: return False # check hash - if util.check_file_hash(self.archiveFile, self.archiveSHA1): + if util.check_file_hash(self.archiveFile, self.archive.sha1sum): if interactive: - ctx.ui.info(_('%s [cached]') % self.archiveName) + ctx.ui.info(_('%s [cached]') % self.archive.name) return True return False - def unpack(self, cleanDir=True): + def unpack(self, clean_dir=True): # check archive file's integrity - if not util.check_file_hash(self.archiveFile, self.archiveSHA1): + if not util.check_file_hash(self.archiveFile, self.archive.sha1sum): raise Error, _("unpack: check_file_hash failed") - archive = Archive(self.archiveFile, self.archiveType) - archive.unpack(self.bctx.pkg_work_dir(), cleanDir) + archive = Archive(self.archiveFile, self.archive.type) + archive.unpack(self.bctx.pkg_work_dir(), clean_dir) diff --git a/pisi/specfile.py b/pisi/specfile.py new file mode 100644 index 00000000..6de03fc7 --- /dev/null +++ b/pisi/specfile.py @@ -0,0 +1,246 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2005, TUBITAK/UEKAE +# +# 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. +# +# Please read the COPYING file. +# +# Authors: Eray Ozkural +# Baris Metin + +""" + Specfile module is our handler for PSPEC files. PSPEC (PISI SPEC) + files are specification files for PISI source packages. This module + provides read and write routines for PSPEC files. +""" + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +# standard python modules +from os.path import basename + +# pisi modules +from pisi.xmlext import * +import pisi.xmlfile as xmlfile +from pisi.xmlfile import XmlFile +import pisi.context as ctx +from pisi.dependency import DepInfo +from pisi.util import Checks + +class Error(pisi.Error): + pass + +__metaclass__ = xmlfile.autoxml + +class Packager: + + t_Name = [xmlfile.Text, xmlfile.mandatory] + t_Email = [xmlfile.String, xmlfile.mandatory] + def __str__(self): + s = "%s <%s>" % (self.name, self.email) + return s + + +class AdditionalFile: + + s_Filename = [xmlfile.String, xmlfile.mandatory] + a_Target = [xmlfile.String, xmlfile.mandatory] + a_Permission = [xmlfile.String, xmlfile.optional] + + def __str__(self): + s = "%s -> %s " % (self.filename, self.target) + if self.permission: + s += '(%s)' % self.permission + return s + + +class Patch: + + s_Filename = [xmlfile.String, xmlfile.mandatory] + a_compressionType = [xmlfile.String, xmlfile.optional] + a_level = [xmlfile.String, xmlfile.optional] + a_target = [xmlfile.String, xmlfile.optional] + + def __str__(self): + s = self.filename + if self.compressionType: + s += ' (' + self.compressionType + ')' + if self.level: + s += ' level:' + self.level + if self.target: + s += ' target:' + self.target + return s + + +class Update: + + a_release = [xmlfile.String, xmlfile.mandatory] + t_Date = [xmlfile.String, xmlfile.mandatory] + t_Version = [xmlfile.String, xmlfile.mandatory] + t_Type = [xmlfile.String, xmlfile.optional] + + def __str__(self): + s = self.date + s += ", ver=" + self.version + s += ", rel=" + self.release + if self.type: + s += ", type=" + self.type + return s + + +class Path: + + s_Path = [xmlfile.String, xmlfile.mandatory] + a_fileType = [xmlfile.String, xmlfile.optional] + + def __str__(self): + s = self.path + s += ", type=" + self.fileType + return s + +class Dependency: + + s_Package = [xmlfile.String, xmlfile.mandatory] + a_versionFrom = [xmlfile.String, xmlfile.optional] + a_versionTo = [xmlfile.String, xmlfile.optional] + a_releaseFrom = [xmlfile.String, xmlfile.optional] + a_releaseTo = [xmlfile.String, xmlfile.optional] + + def __str__(self): + s = self.package + if self.versionFrom: + s += 'ver >= ' + self.versionFrom + if self.versionTo: + s += 'ver <= ' + self.versionTo + if self.releaseFrom: + s += 'rel >= ' + self.releaseFrom + if self.releaseTo: + s += 'rel <= ' + self.releaseTo + return s + +class ComarProvide: + + s_om = [xmlfile.String, xmlfile.mandatory] + a_script = [xmlfile.String, xmlfile.mandatory] + + def __str__(self): + # FIXME: descriptive enough? + s = self.script + s += ' (' + self.om + ')' + return s + + +class Archive: + + s_uri = [ xmlfile.String, xmlfile.mandatory ] + a_type =[ xmlfile.String, xmlfile.mandatory ] + a_sha1sum =[ xmlfile.String, xmlfile.mandatory ] + + def decode_post(self): + self.name = basename(self.uri) + + +class Source: + + t_Name = [xmlfile.String, xmlfile.mandatory] + t_Homepage = [xmlfile.String, xmlfile.mandatory] + t_Packager = [Packager, xmlfile.mandatory] + t_Summary = [xmlfile.String, xmlfile.mandatory] + t_Description = [xmlfile.String, xmlfile.mandatory] + t_IsA = [ [xmlfile.String], xmlfile.mandatory] + t_PartOf = [xmlfile.String, xmlfile.mandatory] + t_Icon = [ xmlfile.String, xmlfile.optional] + t_License = [ [xmlfile.String], xmlfile.mandatory] + t_Archive = [Archive, xmlfile.mandatory ] + t_Patches = [ [Patch], xmlfile.optional] + t_BuildDependencies = [ [Dependency], xmlfile.optional] + t_Version = [ xmlfile.String, xmlfile.optional] + t_Release = [ xmlfile.String, xmlfile.optional] + + +class Package: + + t_Name = [ xmlfile.String, xmlfile.mandatory ] + t_Summary = [ xmlfile.String, xmlfile.mandatory ] + t_Description = [ xmlfile.String, xmlfile.mandatory ] + t_IsA = [ [xmlfile.String], xmlfile.optional] + t_PartOf = [xmlfile.String, xmlfile.optional] + t_License = [ [xmlfile.String], xmlfile.optional] + t_Icon = [ xmlfile.String, xmlfile.optional] + t_RuntimeDependencies = [ [Dependency], xmlfile.optional] + t_Files = [ [Path], xmlfile.optional] + t_Conflicts = [ [xmlfile.String], xmlfile.optional, "Conflicts/Package"] + t_ProvidesComar = [ [ComarProvide], xmlfile.optional, "Provides/COMAR"] + #t_RequiresComar = [ [xmlfile.String], xmlfile.mandatory, "Requires/COMAR"] + t_AdditionalFiles = [ [AdditionalFile], xmlfile.optional] + t_History = [ [Update], xmlfile.optional] + + +class SpecFile(XmlFile): + __metaclass__ = xmlfile.autoxml #needed when we specify a superclass + + tag = "PISI" + + t_Source = [ Source, xmlfile.mandatory] + t_Packages = [ [Package], xmlfile.mandatory, "Package"] + t_History = [ [Update], xmlfile.mandatory] + + #we're not doing this with the init hook right now + #def init(self, tag = "PISI"): + #ignore tag + #XmlFile.__init__(self, tag) + + def read_hook(self, errs): + """Read PSPEC file""" + self.merge_tags() + self.override_tags() + + def merge_tags(self): + """Merge tags from Source in Packages. Some tags in Packages merged + with the tags from Source. There is a more detailed + description in documents.""" + + # FIXME: copy only needed information + # no need to keep full history with comments in metadata.xml + self.source.history = self.history + + # To avoid tag duplication in PSPEC we need to get + # the last version and release information + # from the most recent History/Update. + if not self.source.version: + self.source.version = self.history[0].version + if not self.source.release: + self.source.release = self.history[0].release + + tmp = [] + for pkg in self.packages: + pkg.isA.extend(self.source.isA) + pkg.history = self.history + tmp.append(pkg) + self.packages = tmp + + def override_tags(self): + """Override tags from Source in Packages. Some tags in Packages + overrides the tags from Source. There is a more detailed + description in documents.""" + + tmp = [] + for pkg in self.packages: + if not pkg.summary: + pkg.summary = self.source.summary + if not pkg.description: + pkg.description = self.source.description + if not pkg.partOf: + pkg.partOf = self.source.partOf + if not pkg.license: + pkg.license = self.source.license + if not pkg.icon: + pkg.icon = self.source.icon + tmp.append(pkg) + self.packages = tmp diff --git a/pisi/util.py b/pisi/util.py index fab564ca..05069743 100644 --- a/pisi/util.py +++ b/pisi/util.py @@ -395,20 +395,22 @@ def uncompress(patchFile, compressType="gz", targetDir=None): return filePath -def do_patch(sourceDir, patchFile, level, target = ''): +def do_patch(sourceDir, patchFile, level = 0, target = ''): """simple function to apply patches..""" cwd = os.getcwd() os.chdir(sourceDir) + + if level == None: + level = 0 + if target == None: + target = '' check_file(patchFile) - level = int(level) - cmd = "patch -p%d %s< %s" % (level, target, patchFile) - p = os.popen(cmd) - o = p.readlines() - retval = p.close() - if retval: + (successful, lines) = run_batch("patch -p%d %s< %s" % + (level, target, patchFile)) + if not successful: raise Error(_("ERROR: patch (%s) failed: %s") % (patchFile, - strlist (o))) + strlist (lines))) os.chdir(cwd) diff --git a/pisi/xmlfile.py b/pisi/xmlfile.py index 4d5e2adc..b7e3914c 100644 --- a/pisi/xmlfile.py +++ b/pisi/xmlfile.py @@ -84,14 +84,14 @@ class LocalText(dict): nodes = getAllNodes(node, self.tag) if not nodes: if self.req == mandatory: - errs.append(where + _("LocalText '%s' should have at least one '%s' tag\n") % - self.tag) + errs.append(where + _(" At least one '%s' tag should have local text") % + self.tag ) else: for node in nodes: lang = getNodeAttribute(node, "xml:lang") c = getNodeText(node) if not c: - errs.append(where + _("'%s' language of tag '%s' should have some text data\n") % + errs.append(where + _("'%s' language of tag '%s' is empty") % (lang, self.tag)) # FIXME: check for dups and 'en' if not lang: