From: Michael Tremer Date: Mon, 7 Feb 2011 00:20:47 +0000 (+0100) Subject: Add new class FilePackage. X-Git-Tag: 0.9.3~199 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9e8b1d7a9ca471033b81bc7b6cbd155d64c3eb3b;p=pakfire.git Add new class FilePackage. This class is an additional wrapper to read packages of the tar format. --- diff --git a/pakfire/errors.py b/pakfire/errors.py index fa9f55c6c..ea12f4524 100644 --- a/pakfire/errors.py +++ b/pakfire/errors.py @@ -15,6 +15,9 @@ class ConfigError(Error): class DownloadError(Error): pass +class FileError(Error): + pass + class PakfireError(Error): pass diff --git a/pakfire/packages/base.py b/pakfire/packages/base.py index 88eddb86b..5d5547f1e 100644 --- a/pakfire/packages/base.py +++ b/pakfire/packages/base.py @@ -65,17 +65,6 @@ class Package(object): return "\n".join(s) - @property - def data(self): - """ - Link to the datafile that only gets established if - we need access to it. - """ - if not hasattr(self, "_data"): - self._data = io.CpioArchive(self.filename) - - return self._data - @property def info(self): info = { @@ -98,36 +87,17 @@ class Package(object): def size(self): """ Return the size of the package file. - """ - return self.data.size - - def get_file(self, filename): - """ - Get a file descriptor for the file. - Raises KeyError if file is not available. + This should be overloaded by another class and returns 0 for + virtual packages. """ - return self.data.get(filename) + return 0 ### META INFORMATION ### @property def metadata(self): - if not hasattr(self, "_metadata"): - info = self.get_file("info") - _metadata = {} - - for line in info.read().splitlines(): - m = re.match(r"^(\w+)=(.*)$", line) - if m is None: - continue - - key, val = m.groups() - _metadata[key] = val.strip("\"") - - self._metadata = _metadata - - return self._metadata + raise NotImplementedError @property def friendly_name(self): @@ -201,12 +171,7 @@ class Package(object): @property def signature(self): - f = self.get_file("signature") - f.seek(0) - sig = f.read() - f.close() - - return sig or None + raise NotImplementedError @property def build_date(self): diff --git a/pakfire/packages/binary.py b/pakfire/packages/binary.py index 92c70bb11..bb9fdc3ea 100644 --- a/pakfire/packages/binary.py +++ b/pakfire/packages/binary.py @@ -4,18 +4,15 @@ import sys import packager -from base import Package +from file import FilePackage -class BinaryPackage(Package): +class BinaryPackage(FilePackage): type = "bin" @property def arch(self): return self.metadata.get("PKG_ARCH") - def extract(self, path): - pass - @property def requires(self): ret = "" @@ -31,15 +28,6 @@ class BinaryPackage(Package): def provides(self): return self.metadata.get("PKG_PROVIDES").split() - @property - def filelist(self): - # XXX this needs to be very fast - # and is totally broken ATM - f = self.get_file("filelist") - f.seek(0) - - return f.read().split() - def get_extractor(self, pakfire): return packager.Extractor(pakfire, self) diff --git a/pakfire/packages/file.py b/pakfire/packages/file.py new file mode 100644 index 000000000..2b12674bb --- /dev/null +++ b/pakfire/packages/file.py @@ -0,0 +1,152 @@ +#!/usr/bin/python + +import tarfile +import os +import re + +from pakfire.errors import FileError + +from base import Package + +class FilePackage(Package): + """ + This class is a wrapper that reads package data from the (outer) + tarball and should never be used solely. + """ + def __init__(self, filename): + self.filename = filename + + # Place to keep the tarfile handle and cache the metadata + self._archive = None + self._metadata = {} + + self.check() + + def check(self): + """ + Initially check if the given file is of the correct type and + can be opened. + """ + if not tarfile.is_tarfile(self.filename): + raise FileError, "Given file is not of correct format: %s" % self.filename + + def __repr__(self): + return "<%s %s>" % (self.__class__.__name__, self.filename) + + def __del__(self): + # Close tarfile handle + if self._archive: + self._archive.close() + + @property + def archive(self): + if not self._archive: + self._archive = tarfile.open(self.filename) + + return self._archive + + def get_file(self, name): + """ + Return a file-object for the given filename. + + If the file does not exist KeyError is raised. + """ + return self.archive.extractfile(name) + + @property + def file_version(self): + """ + Returns the version of the package metadata. + """ + return self.metadata.get("VERSION") + + @property + def metadata(self): + """ + Read-in the metadata from the "info" file and cache it in _metadata. + """ + if not self._metadata: + f = self.get_file("info") + + for line in f.readlines(): + m = re.match(r"^(\w+)=(.*)$", line) + if m is None: + continue + + key, val = m.groups() + self._metadata[key] = val.strip("\"") + + f.close() + + return self._metadata + + @property + def size(self): + """ + Return the size of the package file. + """ + return os.path.getsize(self.filename) + + def __filelist_from_metadata(self): + f = self.get_file("filelist") + + ret = f.readlines() + + f.close() + + return ret + + def __filelist_from_payload(self): + # XXX expect uncompressed payload for now + # this is very simple and very slow + + t = tarfile.open(fileobj=self.get_file("data.img")) + + ret = ["/%s" % n for n in t.getnames()] + + t.close() + + return ret + + @property + def filelist(self): + """ + Return a list of the files that are contained in the package + payload. + + At first, we try to get them from the metadata (which is the + 'filelist' file). + If the file is not existant, we will open the payload and + read it instead. The latter is a very slow procedure and + should not be used anyway. + """ + try: + return self.__filelist_from_metadata() + except KeyError: + return self.__filelist_from_payload() + + @property + def payload_compression(self): + """ + Return the compression type of the payload. + """ + return self.metadata.get("PKG_PAYLOAD_COMP") + + @property + def signature(self): + """ + Read the signature from the archive or return None if no + signature does exist. + """ + ret = None + try: + f = self.get_file("signature") + ret = f.read() + f.close() + + except KeyError: + # signature file could not be found + pass + + return ret or None + diff --git a/pakfire/packages/source.py b/pakfire/packages/source.py index 91d5376f1..ad073ee88 100644 --- a/pakfire/packages/source.py +++ b/pakfire/packages/source.py @@ -1,8 +1,8 @@ #!/usr/bin/python -from base import Package +from file import FilePackage -class SourcePackage(Package): +class SourcePackage(FilePackage): type = "src" @property