mirror of
https://github.com/gryf/fs-uae-wrapper.git
synced 2025-12-19 12:28:12 +01:00
This changeset fixes tar behavior on creating archive, like: tar cf foo.tar . which include also archive file itself, so that tar reports an error `file changed as we read it` during appending archive file to itself. This changest is fixing that by replacing dot with list of items to be added to the archive (similar as in RarArchive.create).
187 lines
5.1 KiB
Python
187 lines
5.1 KiB
Python
"""
|
|
File archive classes
|
|
"""
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import re
|
|
|
|
from fs_uae_wrapper import path
|
|
|
|
|
|
class Archive(object):
|
|
"""Base class for archive support"""
|
|
ADD = ['a']
|
|
EXTRACT = ['x']
|
|
ARCH = 'false'
|
|
|
|
def __init__(self):
|
|
self.archiver = path.which(self.ARCH)
|
|
self._compess = self.archiver
|
|
self._decompess = self.archiver
|
|
|
|
def create(self, arch_name, files=None):
|
|
"""
|
|
Create archive. Return True on success, False otherwise.
|
|
"""
|
|
files = files if files else ['.']
|
|
result = subprocess.call([self._compess] + self.ADD + [arch_name]
|
|
+ files)
|
|
if result != 0:
|
|
sys.stderr.write("Unable to create archive `%s'\n" % arch_name)
|
|
return False
|
|
return True
|
|
|
|
def extract(self, arch_name):
|
|
"""
|
|
Extract archive. Return True on success, False otherwise.
|
|
"""
|
|
if not os.path.exists(arch_name):
|
|
sys.stderr.write("Archive `%s' doesn't exists.\n" % arch_name)
|
|
return False
|
|
|
|
result = subprocess.call([self._decompess] + self.EXTRACT +
|
|
[arch_name])
|
|
if result != 0:
|
|
sys.stderr.write("Unable to extract archive `%s'\n" % arch_name)
|
|
return False
|
|
return True
|
|
|
|
|
|
class TarArchive(Archive):
|
|
ADD = ['cf']
|
|
EXTRACT = ['xf']
|
|
ARCH = 'tar'
|
|
|
|
def create(self, arch_name, files=None):
|
|
files = files if files else sorted(os.listdir('.'))
|
|
result = subprocess.call([self._compess] + self.ADD + [arch_name] +
|
|
files)
|
|
if result != 0:
|
|
sys.stderr.write("Unable to create archive `%s'\n" % arch_name)
|
|
return False
|
|
return True
|
|
|
|
|
|
class TarGzipArchive(TarArchive):
|
|
ADD = ['zcf']
|
|
|
|
|
|
class TarBzip2Archive(TarArchive):
|
|
ADD = ['jcf']
|
|
|
|
|
|
class TarXzArchive(TarArchive):
|
|
ADD = ['Jcf']
|
|
|
|
|
|
class LhaArchive(Archive):
|
|
ARCH = 'lha'
|
|
|
|
|
|
class ZipArchive(Archive):
|
|
ADD = ['a', '-tzip']
|
|
ARCH = ['7z', 'zip']
|
|
|
|
def __init__(self):
|
|
super(ZipArchive, self).__init__()
|
|
if self.archiver == 'zip':
|
|
self._decompess = path.which('unzip')
|
|
ZipArchive.ADD = ['-r']
|
|
ZipArchive.EXTRACT = []
|
|
|
|
|
|
class SevenZArchive(Archive):
|
|
ARCH = '7z'
|
|
|
|
|
|
class LzxArchive(Archive):
|
|
EXTRACT = ['-x']
|
|
ARCH = 'unlzx'
|
|
|
|
@classmethod
|
|
def create(self, arch_name, files=None):
|
|
sys.stderr.write('Cannot create LZX archive. Only extracting is'
|
|
'supported\n')
|
|
return False
|
|
|
|
|
|
class RarArchive(Archive):
|
|
ARCH = ['rar', 'unrar']
|
|
|
|
def create(self, arch_name, files=None):
|
|
files = files if files else sorted(os.listdir('.'))
|
|
if self.archiver == 'unrar':
|
|
sys.stderr.write('Cannot create RAR archive. Only extracting is'
|
|
'supported by unrar.\n')
|
|
return False
|
|
|
|
result = subprocess.call([self._compess] + self.ADD + [arch_name] +
|
|
files)
|
|
if result != 0:
|
|
sys.stderr.write("Unable to create archive `%s'\n" % arch_name)
|
|
return False
|
|
return True
|
|
|
|
|
|
class Archivers(object):
|
|
"""Archivers class"""
|
|
archivers = [{'arch': TarArchive, 'name': 'tar', 'ext': ['tar']},
|
|
{'arch': TarGzipArchive, 'name': 'tgz',
|
|
'ext': ['tar.gz', 'tgz']},
|
|
{'arch': TarBzip2Archive, 'name': 'tar.bz2',
|
|
'ext': ['tar.bz2']},
|
|
{'arch': TarXzArchive, 'name': 'tar.xz', 'ext': ['tar.xz']},
|
|
{'arch': RarArchive, 'name': 'rar', 'ext': ['rar']},
|
|
{'arch': SevenZArchive, 'name': '7z', 'ext': ['7z']},
|
|
{'arch': ZipArchive, 'name': 'zip', 'ext': ['zip']},
|
|
{'arch': LhaArchive, 'name': 'lha', 'ext': ['lha', 'lzh']},
|
|
{'arch': LzxArchive, 'name': 'lzx', 'ext': ['lzx']}]
|
|
|
|
@classmethod
|
|
def get(cls, extension):
|
|
"""
|
|
Get the archive class or None
|
|
"""
|
|
for arch in cls.archivers:
|
|
if extension in arch['ext']:
|
|
return arch['arch']
|
|
return None
|
|
|
|
@classmethod
|
|
def get_extension_by_name(cls, name):
|
|
"""
|
|
Get the first defined extension for the archive format
|
|
"""
|
|
for arch in cls.archivers:
|
|
if name == arch['name']:
|
|
return '.' + arch['ext'][0]
|
|
return None
|
|
|
|
|
|
def get_archiver(arch_name):
|
|
"""Return right class for provided archive file name"""
|
|
|
|
_, ext = os.path.splitext(arch_name)
|
|
re_tar = re.compile('.*(.[tT][aA][rR].[^.]+$)')
|
|
result = re_tar.match(arch_name)
|
|
|
|
if result:
|
|
ext = result.groups()[0]
|
|
|
|
if ext:
|
|
ext = ext[1:]
|
|
|
|
archiver = Archivers.get(ext)
|
|
if not archiver:
|
|
sys.stderr.write("Unable find archive type for `%s'\n" % arch_name)
|
|
return None
|
|
|
|
archobj = archiver()
|
|
if archobj.archiver is None:
|
|
sys.stderr.write("Unable find executable for operating on files"
|
|
" `*%s'\n" % ext)
|
|
return None
|
|
|
|
return archobj
|