diff --git a/doc/changelog.txt b/doc/changelog.txt index 9e0aa98..4691e2a 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -14,6 +14,7 @@ * Support extraction of BZIP2 (.bz2) files with the Python bz2 module. * Support extraction of GZIP (.gz) files with the Python gzip module. * Support extraction of ZIP (.zip) files with the Python zipfile module. +* Support extraction of TAR (.tar) files with the Python tarfile module. 0.15 "Contraband" (released 8.4.2012) diff --git a/patoolib/__init__.py b/patoolib/__init__.py index 60f2afd..068c2b2 100644 --- a/patoolib/__init__.py +++ b/patoolib/__init__.py @@ -106,7 +106,7 @@ ArchivePrograms = { 'list': ('echo',), }, 'tar': { - None: ('tar', 'star',), + None: ('tar', 'star', 'pytarfile'), }, 'zip': { None: ('7z', '7za', 'pyzipfile'), @@ -272,6 +272,8 @@ def find_encoding_program (program, encoding): found = util.find_program(enc_program) if found: return found + elif program == 'pytarfile': + return encoding in ('gzip', 'bzip2') return None diff --git a/patoolib/programs/pytarfile.py b/patoolib/programs/pytarfile.py new file mode 100644 index 0000000..ce80b5b --- /dev/null +++ b/patoolib/programs/pytarfile.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2012 Bastian Kleineidam +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +"""Archive commands for the tarfile Python module.""" +from patoolib import util +import tarfile + +READ_SIZE_BYTES = 1024*1024 + + +def list_tar (archive, encoding, cmd, **kwargs): + """List a TAR archive with the tarfile Python module.""" + verbose = kwargs['verbose'] + if verbose: + util.log_info('listing %s...' % archive) + tfile = tarfile.open(archive) + try: + tfile.list(verbose=verbose) + finally: + tfile.close() + return None + +test_tar = list_tar + +def extract_tar (archive, encoding, cmd, **kwargs): + """Extract a TAR archive with the tarfile Python module.""" + verbose = kwargs['verbose'] + outdir = kwargs['outdir'] + # XXX honor outdir + if verbose: + util.log_info('extracting %s...' % archive) + tfile = tarfile.open(archive) + try: + tfile.extractall() + finally: + tfile.close() + if verbose: + util.log_info('... extracted to %s' % outdir) + return None + + +def create_tar (archive, encoding, cmd, *args, **kwargs): + """Create a TAR archive with the tarfile Python module.""" + verbose = kwargs['verbose'] + if verbose: + util.log_info('creating %s...' % archive) + mode = get_tar_mode(encoding) + tfile = tarfile.open(archive, mode) + try: + for filename in args: + tfile.add(filename) + finally: + tfile.close() + return None + + +def get_tar_mode (compression): + """Determine tarfile open mode according to the given compression.""" + if compression == 'gzip': + return 'w:gz' + if compression == 'bzip2': + return 'w:bz2' + if compression: + msg = 'pytarfile does not support %s for tar compression' + util.log_error(msg % compression) + # no compression + return 'w' diff --git a/patoolib/programs/pyzipfile.py b/patoolib/programs/pyzipfile.py index dcadb3f..8955679 100644 --- a/patoolib/programs/pyzipfile.py +++ b/patoolib/programs/pyzipfile.py @@ -13,7 +13,7 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -"""Archive commands for the bz2 Python module.""" +"""Archive commands for the zipfile Python module.""" from patoolib import util import zipfile @@ -21,6 +21,7 @@ READ_SIZE_BYTES = 1024*1024 def list_zip (archive, encoding, cmd, **kwargs): + """List member of a ZIP archive with the zipfile Python module.""" verbose = kwargs['verbose'] if verbose: util.log_info('listing %s...' % archive) diff --git a/tests/__init__.py b/tests/__init__.py index 22bd06e..0e63f7b 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -102,8 +102,10 @@ class ArchiveTest (unittest.TestCase): command = 'test' program = self.program # special case for programs that cannot test what they create - if self.program == 'compress': + if self.program in ('compress', 'pygzip'): program = 'gzip' + elif self.program == 'pybz2': + program = 'bzip2' elif self.program == 'zip': program = 'unzip' elif self.program == 'rzip': diff --git a/tests/test_archives.py b/tests/test_archives.py index 1e963b9..a3da9f9 100644 --- a/tests/test_archives.py +++ b/tests/test_archives.py @@ -96,6 +96,20 @@ class TestArchives (ArchiveTest): self.program = 'star' self.archive_commands('t.tar.xz') + def test_pytarfile (self): + self.program = 'pytarfile' + self.archive_commands('t.tar') + + def test_pytarfile_gz (self): + self.program = 'pytarfile' + self.archive_commands('t.tar.gz') + self.archive_commands('t.tgz') + + def test_pytarfile_bz2 (self): + self.program = 'pytarfile' + self.archive_commands('t.tar.bz2') + self.archive_commands('t.tbz2') + @needs_program('bzip2') def test_bzip2 (self): self.program = 'bzip2' @@ -103,9 +117,12 @@ class TestArchives (ArchiveTest): self.archive_test('t .bz2') self.archive_create('t .bz2', singlefile=True) + @needs_program('bzip2') def test_pybz2 (self): self.program = 'pybz2' self.archive_extract('t .bz2') + # bzip2 is used to test the created archive + self.archive_create('t .bz2', singlefile=True) @needs_program('pbzip2') def test_pbzip2 (self): @@ -147,9 +164,7 @@ class TestArchives (ArchiveTest): def test_pyzipfile (self): self.program = 'pyzipfile' - self.archive_create('t.zip') - self.archive_extract('t.zip') - self.archive_list('t.zip') + self.archive_commands('t.zip') @needs_program('gzip') def test_gzip (self): @@ -158,10 +173,13 @@ class TestArchives (ArchiveTest): self.archive_commands('t.txt.gz', singlefile=True) self.archive_extract('t.Z') + @needs_program('gzip') def test_pygzip (self): self.program = 'pygzip' self.archive_extract('t.gz') self.archive_extract('t.txt.gz') + # gzip is used to test the created archive + self.archive_create('t.gz', singlefile=True) @needs_program('pigz') def test_pigz (self):