From: Michael Tremer Date: Tue, 5 Apr 2011 15:07:33 +0000 (+0200) Subject: Add support to build source packages and fix for empty requires on source packages. X-Git-Tag: 0.9.3~54 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4496b1600d6d2423aad96f3752fd6b0c71578165;p=pakfire.git Add support to build source packages and fix for empty requires on source packages. --- diff --git a/pakfire/builder.py b/pakfire/builder.py index eb6b363e5..effe71a30 100644 --- a/pakfire/builder.py +++ b/pakfire/builder.py @@ -19,6 +19,7 @@ import transaction import util from constants import * +from i18n import _ from errors import BuildError, BuildRootLocked, Error @@ -169,6 +170,10 @@ class Builder(object): if isinstance(self.pkg, packages.Makefile): self.pkg.extract(self) + elif isinstance(self.pkg, packages.SourcePackage): + self.pkg.extract(_("Extracting: %s (source)") % self.pkg.name, + prefix=os.path.join(self.path, "build")) + # If we have a makefile, we can only get the build dependencies # after we have extracted all the rest. if build_deps and isinstance(self.pkg, packages.Makefile): @@ -501,8 +506,12 @@ class Builder(object): return ret def make(self, *args, **kwargs): - return self.do("make -f /build/%s %s" % \ - (os.path.basename(self.pkg.filename), " ".join(args)), + if isinstance(self.pkg, packages.Makefile): + filename = os.path.basename(self.pkg.filename) + elif isinstance(self.pkg, packages.SourcePackage): + filename = "%s.%s" % (self.pkg.name, MAKEFILE_EXTENSION) + + return self.do("make -f /build/%s %s" % (filename, " ".join(args)), **kwargs) @property diff --git a/pakfire/cli.py b/pakfire/cli.py index 2241fcc3d..d0649ade5 100644 --- a/pakfire/cli.py +++ b/pakfire/cli.py @@ -29,7 +29,6 @@ def ask_user(question): return ret in ("y", "Y") - class Cli(object): def __init__(self): self.parser = argparse.ArgumentParser( diff --git a/pakfire/packages/base.py b/pakfire/packages/base.py index 8f926c1a0..f2c5ad9b1 100644 --- a/pakfire/packages/base.py +++ b/pakfire/packages/base.py @@ -281,6 +281,24 @@ class Package(object): def uuid(self): return self.metadata.get("PKG_UUID", None) + @property + def requires(self): + ret = "" + + # The default attributes, that are process for the requires. + attrs = ("PKG_REQUIRES", "PKG_DEPS") + + # Source packages do depend on their build dependencies. + if self.arch == "src": + attrs = ("PKG_BUILD_DEPS",) + + for i in attrs: + ret = self.metadata.get(i, ret) + if ret: + break + + return ret.split() + @property def _provides(self): # Make package identifyable by its name and version/release tuples. diff --git a/pakfire/packages/binary.py b/pakfire/packages/binary.py index 3ce9ef5c3..89d41049f 100644 --- a/pakfire/packages/binary.py +++ b/pakfire/packages/binary.py @@ -9,17 +9,6 @@ class BinaryPackage(FilePackage): def arch(self): return self.metadata.get("PKG_ARCH") - @property - def requires(self): - ret = "" - - for i in ("PKG_REQUIRES", "PKG_DEPS"): - ret = self.metadata.get(i, ret) - if ret: - break - - return ret.split() - @property def provides(self): if not hasattr(self, "__provides"): diff --git a/pakfire/packages/file.py b/pakfire/packages/file.py index c8d35bc8b..cb70bb45f 100644 --- a/pakfire/packages/file.py +++ b/pakfire/packages/file.py @@ -4,11 +4,15 @@ import logging import os import re import tarfile +import tempfile import xattr import util +import pakfire.util as util +import pakfire.compress as compress from pakfire.errors import FileError +from pakfire.constants import * from base import Package @@ -118,6 +122,99 @@ class FilePackage(Package): def open_archive(self): return tarfile.open(self.filename) + def extract(self, message=None, prefix=None): + logging.debug("Extracting package %s" % self.friendly_name) + + if prefix is None: + prefix = "" + + # A place to store temporary data. + tempf = None + + # Open package data for read. + archive = self.open_archive() + + # Get the package payload. + payload = archive.extractfile("data.img") + + # Decompress the payload if needed. + logging.debug("Compression: %s" % self.payload_compression) + + # Create a temporary file to store the decompressed output. + garbage, tempf = tempfile.mkstemp(prefix="pakfire") + + i = payload + o = open(tempf, "w") + + # Decompress the package payload. + if self.payload_compression: + compress.decompressobj(i, o, algo=self.payload_compression) + + else: + buf = i.read(BUFFER_SIZE) + while buf: + o.write(buf) + buf = i.read(BUFFER_SIZE) + + i.close() + o.close() + + payload = open(tempf) + + # Open the tarball in the package. + payload_archive = InnerTarFile.open(fileobj=payload) + + members = payload_archive.getmembers() + + # Load progressbar. + pb = None + if message: + pb = util.make_progress("%-40s" % message, len(members)) + + i = 0 + for member in members: + # Update progress. + if pb: + i += 1 + pb.update(i) + + target = os.path.join(prefix, member.name) + + # If the member is a directory and if it already exists, we + # don't need to create it again. + + if os.path.exists(target): + if member.isdir(): + continue + + else: + # Remove file if it has been existant + os.unlink(target) + + #if self.pakfire.config.get("debug"): + # msg = "Creating file (%s:%03d:%03d) " % \ + # (tarfile.filemode(member.mode), member.uid, member.gid) + # if member.issym(): + # msg += "/%s -> %s" % (member.name, member.linkname) + # elif member.islnk(): + # msg += "/%s link to /%s" % (member.name, member.linkname) + # else: + # msg += "/%s" % member.name + # logging.debug(msg) + + payload_archive.extract(member, path=prefix) + + # Close all open files. + payload_archive.close() + payload.close() + archive.close() + + if tempf: + os.unlink(tempf) + + if pb: + pb.finish() + @property def file_version(self): """ @@ -218,10 +315,6 @@ class FilePackage(Package): if comp == "X"*3: comp = None - # XXX remove that later, because of compatibility for naoki. - elif not comp: - comp = "xz" - return comp @property diff --git a/pakfire/packages/packager.py b/pakfire/packages/packager.py index a3b1a9577..28d150194 100644 --- a/pakfire/packages/packager.py +++ b/pakfire/packages/packager.py @@ -88,6 +88,10 @@ class Packager(object): self.info[key] = " ".join(sorted(val)) + elif self.type == "source": + # Save the build requirements. + self.info["requires"] = " ".join(self.pkg.requires) + self.create_info() # Create the outer tarball. diff --git a/pakfire/packages/source.py b/pakfire/packages/source.py index 1e53f5752..9bea3b13c 100644 --- a/pakfire/packages/source.py +++ b/pakfire/packages/source.py @@ -7,9 +7,6 @@ class SourcePackage(FilePackage): def arch(self): return "src" - def extract(self, path): - pass - @property def requires(self): """ diff --git a/pakfire/transaction.py b/pakfire/transaction.py index 9ba103c94..d2dc90bec 100644 --- a/pakfire/transaction.py +++ b/pakfire/transaction.py @@ -5,9 +5,7 @@ import os import progressbar import sys import tarfile -import tempfile -import compress import depsolve import packages import util @@ -49,30 +47,6 @@ class Action(object): """ return self.pakfire.repos.local - @staticmethod - def make_progress(message, maxval): - # Return nothing if stdout is not a terminal. - if not sys.stdout.isatty(): - return - - widgets = [ - " ", - message, - " ", - progressbar.Bar(left="[", right="]"), - " ", - progressbar.ETA(), - " ", - ] - - if not maxval: - maxval = 1 - - pb = progressbar.ProgressBar(widgets=widgets, maxval=maxval) - pb.start() - - return pb - class ActionCleanup(Action): def gen_files(self): @@ -99,7 +73,7 @@ class ActionCleanup(Action): if not files: return - pb = self.make_progress(message, len(files)) + pb = util.make_progress(message, len(files)) i = 0 for f in self.gen_files(): @@ -161,88 +135,11 @@ class ActionInstall(Action): if prefix is None: prefix = self.pakfire.path - # A place to store temporary data. - tempf = None - - # Open package data for read. - archive = self.pkg.open_archive() - - # Get the package payload. - payload = archive.extractfile("data.img") - - # Decompress the payload if needed. - if self.pkg.payload_compression: - # Create a temporary file to store the decompressed output. - garbage, tempf = tempfile.mkstemp(prefix="pakfire") - - i = payload - o = open(tempf, "w") - - # Decompress the package payload. - compress.decompressobj(i, o, algo=self.pkg.payload_compression) - - i.close() - o.close() - - payload = open(tempf) - - # Open the tarball in the package. - payload_archive = packages.InnerTarFile.open(fileobj=payload) - - members = payload_archive.getmembers() - - # Load progressbar. - pb = self.make_progress("%-40s" % message, len(members)) - - i = 0 - for member in members: - # Update progress. - if pb: - i += 1 - pb.update(i) - - target = os.path.join(prefix, member.name) - - # If the member is a directory and if it already exists, we - # don't need to create it again. - - if os.path.exists(target): - if member.isdir(): - continue - - else: - # Remove file if it has been existant - os.unlink(target) - - #if self.pakfire.config.get("debug"): - # msg = "Creating file (%s:%03d:%03d) " % \ - # (tarfile.filemode(member.mode), member.uid, member.gid) - # if member.issym(): - # msg += "/%s -> %s" % (member.name, member.linkname) - # elif member.islnk(): - # msg += "/%s link to /%s" % (member.name, member.linkname) - # else: - # msg += "/%s" % member.name - # logging.debug(msg) - - payload_archive.extract(member, path=prefix) - - # XXX implement setting of xattrs/acls here - - # Close all open files. - payload_archive.close() - payload.close() - archive.close() - - if tempf: - os.unlink(tempf) + self.pkg.extract(message, prefix=prefix) # Create package in the database self.local.index.add_package(self.pkg) - if pb: - pb.finish() - def run(self): self.extract(_("Installing: %s") % self.pkg.name) diff --git a/pakfire/util.py b/pakfire/util.py index ced8ca01d..99c8999d7 100644 --- a/pakfire/util.py +++ b/pakfire/util.py @@ -3,6 +3,7 @@ import ctypes import fcntl import os +import progressbar import random import select import shutil @@ -27,6 +28,29 @@ def cli_is_interactive(): return False +def make_progress(message, maxval): + # Return nothing if stdout is not a terminal. + if not sys.stdout.isatty(): + return + + widgets = [ + " ", + "%-40s" % message, + " ", + progressbar.Bar(left="[", right="]"), + " ", + progressbar.ETA(), + " ", + ] + + if not maxval: + maxval = 1 + + pb = progressbar.ProgressBar(widgets=widgets, maxval=maxval) + pb.start() + + return pb + def rm(path, *args, **kargs): """ version of shutil.rmtree that ignores no-such-file-or-directory errors,