archive: Use pyliblzma for (de)compression with lzma

Pisi does not need "lzma" executable any more.
This commit is contained in:
Fatih Aşıcı
2010-06-12 23:02:18 +00:00
parent 2d1a022951
commit 2e8d677f94
+112 -24
View File
@@ -30,11 +30,105 @@ import pisi
import pisi.util as util import pisi.util as util
import pisi.context as ctx import pisi.context as ctx
class UnknownArchiveType(Exception): class UnknownArchiveType(Exception):
pass pass
class LzmaRuntimeError(Exception):
pass # Proxy class inspired from tarfile._BZ2Proxy
class _LZMAProxy(object):
blocksize = 16 * 1024
def __init__(self, fileobj, mode):
self.fileobj = fileobj
self.mode = mode
self.name = getattr(self.fileobj, "name", None)
self.init()
def init(self):
import lzma
self.pos = 0
if self.mode == "r":
self.lzmaobj = lzma.LZMADecompressor()
if hasattr(self.fileobj, "seek"):
self.fileobj.seek(0)
self.buf = ""
else:
self.lzmaobj = lzma.LZMACompressor()
def read(self, size):
b = [self.buf]
x = len(self.buf)
while x < size:
raw = self.fileobj.read(self.blocksize)
if not raw:
break
try:
data = self.lzmaobj.decompress(raw)
except EOFError:
break
b.append(data)
x += len(data)
self.buf = "".join(b)
buf = self.buf[:size]
self.buf = self.buf[size:]
self.pos += len(buf)
return buf
def seek(self, pos):
if pos < self.pos:
self.init()
self.read(pos - self.pos)
def tell(self):
return self.pos
def write(self, data):
self.pos += len(data)
raw = self.lzmaobj.compress(data)
self.fileobj.write(raw)
def close(self):
if self.mode == "w":
raw = self.lzmaobj.flush()
self.fileobj.write(raw)
class TarFile(tarfile.TarFile):
@classmethod
def lzmaopen(cls, name=None, mode="r", fileobj=None,
compresslevel=9, **kwargs):
"""Open lzma compressed tar archive name for reading or writing.
Appending is not allowed.
"""
if len(mode) > 1 or mode not in "rw":
raise ValueError("mode must be 'r' or 'w'.")
try:
import lzma
except ImportError:
raise tarfile.CompressionError("lzma module is not available")
if fileobj is not None:
fileobj = _LZMAProxy(fileobj, mode)
else:
options = {
"format": "alone",
"level": compresslevel,
#"extreme": compresslevel == 9
}
fileobj = lzma.LZMAFile(name, mode, options=options)
try:
t = cls.taropen(name, mode, fileobj, **kwargs)
except IOError:
raise ReadError("not a lzma file")
t._extfileobj = False
return t
class ArchiveBase(object): class ArchiveBase(object):
"""Base class for Archive classes.""" """Base class for Archive classes."""
@@ -67,6 +161,7 @@ class ArchiveBinary(ArchiveBase):
target_file = os.path.join(target_dir, os.path.basename(self.file_path)) target_file = os.path.join(target_dir, os.path.basename(self.file_path))
shutil.copyfile(self.file_path, target_file) shutil.copyfile(self.file_path, target_file)
class ArchiveBzip2(ArchiveBase): class ArchiveBzip2(ArchiveBase):
"""ArchiveBzip2 handles Bzip2 archive files""" """ArchiveBzip2 handles Bzip2 archive files"""
def __init__(self, file_path, arch_type = "bz2"): def __init__(self, file_path, arch_type = "bz2"):
@@ -89,6 +184,7 @@ class ArchiveBzip2(ArchiveBase):
os.chdir(oldwd) os.chdir(oldwd)
class ArchiveGzip(ArchiveBase): class ArchiveGzip(ArchiveBase):
"""ArchiveGzip handles Gzip archive files""" """ArchiveGzip handles Gzip archive files"""
def __init__(self, file_path, arch_type = "gz"): def __init__(self, file_path, arch_type = "gz"):
@@ -111,6 +207,7 @@ class ArchiveGzip(ArchiveBase):
os.chdir(oldwd) os.chdir(oldwd)
class ArchiveTar(ArchiveBase): class ArchiveTar(ArchiveBase):
"""ArchiveTar handles tar archives depending on the compression """ArchiveTar handles tar archives depending on the compression
type. Provides access to tar, tar.gz and tar.bz2 files. type. Provides access to tar, tar.gz and tar.bz2 files.
@@ -129,6 +226,7 @@ class ArchiveTar(ArchiveBase):
def unpack_dir(self, target_dir): def unpack_dir(self, target_dir):
rmode = "" rmode = ""
self.tar = None
if self.type == 'tar': if self.type == 'tar':
rmode = 'r:' rmode = 'r:'
elif self.type == 'targz': elif self.type == 'targz':
@@ -136,11 +234,7 @@ class ArchiveTar(ArchiveBase):
elif self.type == 'tarbz2': elif self.type == 'tarbz2':
rmode = 'r:bz2' rmode = 'r:bz2'
elif self.type == 'tarlzma': elif self.type == 'tarlzma':
rmode = 'r:' self.tar = TarFile.lzmaopen(self.file_path)
self.file_path = self.file_path.rstrip(ctx.const.lzma_suffix)
ret, out, err = util.run_batch("lzma -k -f -d %s%s" % (self.file_path,ctx.const.lzma_suffix))
if ret != 0:
raise LzmaRuntimeError(err)
elif self.type == 'tarZ': elif self.type == 'tarZ':
rmode = 'r:' rmode = 'r:'
self.file_path = self.file_path.rstrip('.Z') self.file_path = self.file_path.rstrip('.Z')
@@ -150,7 +244,9 @@ class ArchiveTar(ArchiveBase):
else: else:
raise UnknownArchiveType raise UnknownArchiveType
self.tar = tarfile.open(self.file_path, rmode) if self.tar is None:
self.tar = tarfile.open(self.file_path, rmode)
oldwd = None oldwd = None
try: try:
# Don't fail if CWD doesn't exist (#6748) # Don't fail if CWD doesn't exist (#6748)
@@ -173,7 +269,7 @@ class ArchiveTar(ArchiveBase):
# #
# Also, tar.extract() doesn't write on symlinks... Not any # Also, tar.extract() doesn't write on symlinks... Not any
# more :). # more :).
if self.file_path == install_tar_path: if self.file_path.startswith(install_tar_path):
if os.path.isfile(tarinfo.name) or os.path.islink(tarinfo.name): if os.path.isfile(tarinfo.name) or os.path.islink(tarinfo.name):
try: try:
os.unlink(tarinfo.name) os.unlink(tarinfo.name)
@@ -202,7 +298,7 @@ class ArchiveTar(ArchiveBase):
ctx.ui.notify(pisi.ui.desktopfile, desktopfile=tarinfo.name) ctx.ui.notify(pisi.ui.desktopfile, desktopfile=tarinfo.name)
# Bug #10680 and addition for tarZ files # Bug #10680 and addition for tarZ files
if self.type == 'tarlzma' or self.type == 'tarZ': if self.type == 'tarZ':
os.unlink(self.file_path) os.unlink(self.file_path)
try: try:
@@ -223,31 +319,23 @@ class ArchiveTar(ArchiveBase):
elif self.type == 'tarbz2': elif self.type == 'tarbz2':
wmode = 'w:bz2' wmode = 'w:bz2'
elif self.type == 'tarlzma': elif self.type == 'tarlzma':
wmode = 'w:' level = int(ctx.config.values.build.compressionlevel)
self.file_path = self.file_path.rstrip(ctx.const.lzma_suffix) self.tar = TarFile.lzmaopen(self.file_path, "w",
compresslevel=level)
elif self.type == 'tarZ': elif self.type == 'tarZ':
wmode = 'w:' wmode = 'w:'
self.file_path = self.file_path.rstrip(".Z") self.file_path = self.file_path.rstrip(".Z")
else: else:
raise UnknownArchiveType raise UnknownArchiveType
self.tar = tarfile.open(self.file_path, wmode)
if self.tar is None:
self.tar = tarfile.open(self.file_path, wmode)
self.tar.add(file_name, arc_name) self.tar.add(file_name, arc_name)
def close(self): def close(self):
self.tar.close() self.tar.close()
if 'w' in str(self.tar.mode) and self.type == 'tarlzma':
batch = None
if ctx.config.values.build.compressionlevel:
batch = "lzma -%s -z %s" % (ctx.config.values.build.compressionlevel, self.file_path)
else:
batch = "lzma -z %s" % self.file_path
ret, out, err = util.run_batch(batch)
if ret != 0:
raise LzmaRuntimeError(err)
class ArchiveZip(ArchiveBase): class ArchiveZip(ArchiveBase):
"""ArchiveZip handles zip archives. """ArchiveZip handles zip archives.