archive: Use pyliblzma for (de)compression with lzma
Pisi does not need "lzma" executable any more.
This commit is contained in:
+112
-24
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user