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):