Implemented create command

This commit is contained in:
Bastian Kleineidam 2010-02-21 15:48:52 +01:00
parent dde435cc16
commit 6790380c70
20 changed files with 228 additions and 52 deletions

View File

@ -1,2 +1,2 @@
- add create mode?
- add test mode?
- add create command
- move all program modules into subpackage

24
patool
View File

@ -20,39 +20,39 @@ patool [extract|list] [sub-command-options] <archive-file>
import sys
if not hasattr(sys, "version_info") or sys.version_info < (2, 5, 0, "final", 0):
raise SystemExit("Error, this script needs Python >= 2.5 installed")
import patoolib
from patoolib import handle_archive, list_formats, baker
@patoolib.baker.command
@baker.command
def extract (archive, verbose=False, force=False):
"""Extract files from an archive."""
return patoolib.handle_archive(archive, 'extract')
return handle_archive(archive, 'extract')
@patoolib.baker.command
@baker.command
def list (archive, verbose=False):
"""List files in an archive."""
return patoolib.handle_archive(archive, 'list')
return handle_archive(archive, 'list')
@baker.command
def create (archive, *args):
"""Create an archive from given files."""
return patoolib.handle_archive(archive, 'create', *args)
return handle_archive(archive, 'create', *args)
@patoolib.baker.command
@baker.command
def test (archive, verbose=False):
"""Test files in an archive."""
return patoolib.handle_archive(archive, 'test', verbose=verbose)
return handle_archive(archive, 'test', verbose=verbose)
@patoolib.baker.command
@baker.command
def formats ():
return patoolib.list_formats()
return list_formats()
try:
sys.exit(patoolib.baker.run())
except patoolib.baker.CommandError, msg:
sys.exit(baker.run())
except baker.CommandError, msg:
print >>sys.stderr, "patool error:", msg
sys.exit(1)

View File

@ -16,7 +16,7 @@
import os
import shutil
from distutils.spawn import find_executable
from . import util, baker
from . import util
# Supported archive commands
ArchiveCommands = ('list', 'extract', 'test', 'create')
@ -56,6 +56,7 @@ ArchivePrograms = {
'bzip2': {
'extract': ('pbzip2', 'bzip2', '7z'),
'test': ('pbzip2', 'bzip2', '7z'),
'create': ('pbzip2', 'bzip2', '7z'),
'list': ('7z', 'echo',),
},
'tar': {
@ -73,6 +74,7 @@ ArchivePrograms = {
'extract': ('gzip', '7z', 'uncompress.real'),
'list': ('7z', 'echo',),
'test': ('gzip', '7z'),
'create': ('compress',),
},
'7z': {
None: ('7z',),
@ -89,14 +91,16 @@ ArchivePrograms = {
'test': ('cabextract', '7z'),
},
'arj': {
'extract': ('arj', '7z'),
'list': ('arj', '7z'),
'test': ('arj', '7z'),
None: ('arj',),
'extract': ('7z',),
'list': ('7z',),
'test': ('7z',),
},
'cpio': {
'extract': ('cpio', '7z'),
'list': ('cpio', '7z'),
'test': ('7z',),
'create': ('cpio',),
},
'rpm': {
# XXX rpm2cpio depends on cpio which is not checked
@ -125,7 +129,7 @@ ProgramModules = {
def get_archive_format (filename):
"""Detect filename archive format."""
mime, encoding = util.guess_mime(filename)
if not mime:
if not (mime or encoding):
raise util.PatoolError("unknown archive format for file `%s'" % filename)
if mime in ArchiveMimetypes:
format = ArchiveMimetypes[mime]
@ -158,6 +162,8 @@ def find_archive_program (format, command):
for key in (None, command):
if key in commands:
programs.extend(commands[key])
if not programs:
raise util.PatoolError("%s archive format `%s' is not supported" % (command, format))
# return the first existing program
for program in programs:
exe = find_executable(program)
@ -272,6 +278,10 @@ def _handle_archive (archive, command, *args, **kwargs):
check_archive_format(format, encoding)
check_archive_command(command)
config = parse_config(format, command, **kwargs)
if command == 'create':
# check if archive already exists
if os.path.exists(archive) and not config['force']:
raise util.PatoolError("archive `%s' already exists, and --force option was not given" % archive)
program = config['program']
# get python module for given archive program
key = os.path.basename(program).lower()
@ -286,7 +296,7 @@ def _handle_archive (archive, command, *args, **kwargs):
outdir = util.tmpdir(dir=os.getcwd())
kwargs['outdir'] = outdir
try:
cmdlist = get_archive_cmdlist(archive, encoding, program, **kwargs)
cmdlist = get_archive_cmdlist(archive, encoding, program, *args, **kwargs)
run_archive_cmdlist(cmdlist)
if command == 'extract':
target = cleanup_outdir(archive, outdir, config['force'])

View File

@ -26,6 +26,7 @@ def extract_arj (archive, encoding, cmd, **kwargs):
cmdlist.extend([archive, kwargs['outdir']])
return cmdlist
def list_arj (archive, encoding, cmd, **kwargs):
"""List a ARJ archive."""
cmdlist = [cmd]
@ -39,6 +40,7 @@ def list_arj (archive, encoding, cmd, **kwargs):
cmdlist.extend([archive])
return cmdlist
def test_arj (archive, encoding, cmd, **kwargs):
"""Test a ARJ archive."""
cmdlist = [cmd]
@ -49,3 +51,16 @@ def test_arj (archive, encoding, cmd, **kwargs):
cmdlist.append('-y')
cmdlist.extend([archive])
return cmdlist
def create_arj (archive, encoding, cmd, *args, **kwargs):
"""Create a ARJ archive."""
cmdlist = [cmd]
cmdlist.append('a')
cmdlist.append('-r')
cmdlist.append('-y')
if not kwargs['verbose']:
cmdlist.append('-i-')
cmdlist.append(archive)
cmdlist.extend(args)
return cmdlist

View File

@ -33,9 +33,24 @@ def extract_bzip2 (archive, encoding, cmd, **kwargs):
def test_bzip2 (archive, encoding, cmd, **kwargs):
"""Test a BZIP2 archive."""
cmdlist = [cmd]
if kwargs['verbose']:
cmdlist.append('-v')
cmdlist.extend(['-t', '--'])
cmdlist.extend([archive])
return cmdlist
def create_bzip2 (archive, encoding, cmd, *args, **kwargs):
"""Create a BZIP2 archive."""
cmdlist = [cmd]
if kwargs['verbose']:
cmdlist.append('-v')
cmdlist.extend(['-c', '-z'])
cmdlist.append('--')
cmdlist.extend(args)
cmdlist.extend(['>', archive])
# note that for shell calls the command must be a string
cmd = " ".join([util.shell_quote(x) for x in cmdlist])
return (cmd, {'shell': True})

30
patoolib/compress.py Normal file
View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2010 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 <http://www.gnu.org/licenses/>.
"""Archive commands for the uncompress.real program."""
from . import util
def create_compress (archive, encoding, cmd, *args, **kwargs):
"""Create a compressed archive."""
cmdlist = [cmd]
if kwargs['verbose']:
cmdlist.append('-v')
cmdlist.append('-c')
cmdlist.extend(args)
cmdlist.extend(['>', archive])
# note that for shell calls the command must be a string
cmd = " ".join([util.shell_quote(x) for x in cmdlist])
return (cmd, {'shell': True})

View File

@ -40,3 +40,20 @@ def list_cpio (archive, encoding, cmd, **kwargs):
cmdlist.append('-v')
cmdlist.extend(['-F', archive])
return cmdlist
test_cpio = list_cpio
def create_cpio(archive, encoding, cmd, *args, **kwargs):
"""Create a CPIO archive."""
cmdlist = [cmd, '--create']
if kwargs['verbose']:
cmdlist.append('-v')
if len(args) != 0:
findcmd = ['find', '-print0']
findcmd.extend(args)
findcmd.append('|')
cmdlist[0:0] = findcmd
cmdlist.append('-0')
cmdlist.extend([">", archive])
cmd = " ".join([util.shell_quote(x) for x in cmdlist])
return (cmd, {'shell': True})

View File

@ -55,3 +55,16 @@ def test_gzip (archive, encoding, cmd, **kwargs):
return cmdlist
test_compress = test_gzip
def create_gzip (archive, encoding, cmd, *args, **kwargs):
"""Create a GZIP archive."""
cmdlist = [cmd]
if kwargs['verbose']:
cmdlist.append('-v')
cmdlist.append('-c')
cmdlist.append('--')
cmdlist.extend(args)
cmdlist.extend(['>', archive])
# note that for shell calls the command must be a string
cmd = " ".join([util.shell_quote(x) for x in cmdlist])
return (cmd, {'shell': True})

View File

@ -41,3 +41,13 @@ def test_lzop (archive, encoding, cmd, **kwargs):
cmdlist.append('--verbose')
cmdlist.extend(['--', archive])
return cmdlist
def create_lzop (archive, encoding, cmd, *args, **kwargs):
"""Create a LZOP archive."""
cmdlist = [cmd]
if kwargs['verbose']:
cmdlist.append('-v')
cmdlist.extend(['-o', archive])
cmdlist.append('--')
cmdlist.extend(args)
return cmdlist

View File

@ -82,3 +82,15 @@ test_bzip2 = \
test_rpm = \
test_deb = \
test_7z
def create_7z (archive, encoding, cmd, *args, **kwargs):
"""Create a 7z archive."""
cmdlist = [cmd]
cmdlist.append('a')
if not kwargs['verbose']:
cmdlist.append('-bd')
cmdlist.append('--')
cmdlist.append(archive)
cmdlist.extend(args)
return cmdlist

View File

@ -15,4 +15,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Archive commands for the pbzip2 program."""
# bzip2 and pbzip2 are compatible
from .bzip2 import extract_bzip2, test_bzip2
from .bzip2 import extract_bzip2, test_bzip2, create_bzip2

View File

@ -43,3 +43,14 @@ def test_rar (archive, encoding, cmd, **kwargs):
cmdlist.append('-c-')
cmdlist.extend(['--', archive])
return cmdlist
def create_rar (archive, encoding, cmd, *args, **kwargs):
"""Create a RAR archive."""
cmdlist = [cmd]
cmdlist.append('a')
if not kwargs['verbose']:
cmdlist.append('-c-')
cmdlist.extend(['-r', '--', archive])
cmdlist.extend(args)
return cmdlist

View File

@ -18,6 +18,28 @@
def extract_tar (archive, encoding, cmd, **kwargs):
"""Extract a TAR archive."""
cmdlist = [cmd, '-x']
add_star_opts(cmdlist, encoding, kwargs['verbose'])
cmdlist.extend(['-C', kwargs['outdir'], 'file=%s' % archive])
return cmdlist
def list_tar (archive, encoding, cmd, **kwargs):
"""List a TAR archive."""
cmdlist = [cmd, '-n']
add_star_opts(cmdlist, encoding, kwargs['verbose'])
cmdlist.append("file=%s" % archive)
return cmdlist
test_tar = list_tar
def create_tar (archive, encoding, cmd, *args, **kwargs):
"""Create a TAR archive."""
cmdlist = [cmd, '-c']
add_star_opts(cmdlist, encoding, kwargs['verbose'])
cmdlist.append("file=%s" % archive)
cmdlist.extend(args)
return cmdlist
def add_star_opts (cmdlist, encoding, verbose):
# Note that star autodetects encoding compression, but displays a warning
# which we want to avoie.
if encoding == 'gzip':
@ -26,23 +48,5 @@ def extract_tar (archive, encoding, cmd, **kwargs):
cmdlist.append('-Z')
elif encoding == 'bzip2':
cmdlist.append('-bz')
if kwargs['verbose']:
if verbose:
cmdlist.append('-v')
cmdlist.extend(['-C', kwargs['outdir'], 'file=%s' % archive])
return cmdlist
def list_tar (archive, encoding, cmd, **kwargs):
"""List a TAR archive."""
cmdlist = [cmd, '-n']
if encoding == 'gzip':
cmdlist.append('-z')
elif encoding == 'compress':
cmdlist.append('-Z')
elif encoding == 'bzip2':
cmdlist.append('-bz')
if kwargs['verbose']:
cmdlist.append('-v')
cmdlist.append("file=%s" % archive)
return cmdlist
test_tar = list_tar

View File

@ -37,6 +37,11 @@ def list_tar (archive, encoding, cmd, **kwargs):
test_tar = list_tar
def create_tar (archive, encoding, cmd, **kwargs):
def create_tar (archive, encoding, cmd, *args, **kwargs):
"""Create a TAR archive."""
print "XXX create", archive, encoding, cmd, kwargs
cmdlist = [cmd, '--create']
if encoding:
cmdlist.append('--%s' % encoding)
cmdlist.extend(["--file", archive, '--'])
cmdlist.extend(args)
return cmdlist

View File

@ -26,6 +26,7 @@ mimedb = mimetypes.MimeTypes(strict=False)
mimedb.encodings_map['.bz2'] = 'bzip2'
mimedb.suffix_map['.tbz2'] = '.tar.bz2'
mimedb.add_type('application/x-lzop', '.lzo', strict=False)
mimedb.add_type('application/x-arj', '.arj', strict=False)
class PatoolError (StandardError):

View File

@ -26,10 +26,11 @@ datadir = os.path.join(basedir, 'data')
class ArchiveTest (unittest.TestCase):
"""Helper class for achive tests."""
def archive_commands (self, filename, cmd):
def archive_commands (self, filename, cmd, singlefile=False):
self.archive_list(filename, cmd)
self.archive_test(filename, cmd)
self.archive_extract(filename, cmd)
self.archive_create(filename, cmd, singlefile=singlefile)
def archive_extract (self, filename, cmd):
archive = os.path.join(datadir, filename)
@ -53,6 +54,26 @@ class ArchiveTest (unittest.TestCase):
patoolib._handle_archive(archive, 'test', program=cmd)
patoolib._handle_archive(archive, 'test', program=cmd, verbose=True)
def archive_create (self, filename, cmd, singlefile=False):
# the file or directory to pack
if singlefile:
topack = os.path.join(datadir, 'foo.txt')
else:
topack = os.path.join(datadir, 'foo')
# create a temporary directory for creation
tmpdir = patoolib.util.tmpdir(dir=basedir)
archive = os.path.join(tmpdir, filename)
os.chdir(tmpdir)
try:
patoolib._handle_archive(archive, 'create', topack, program=cmd)
# not all programs can test what they create
if cmd == 'compress':
cmd = 'gzip'
patoolib._handle_archive(archive, 'test', program=cmd)
finally:
os.chdir(basedir)
shutil.rmtree(tmpdir)
def needs_cmd (cmd):
"""Decorator skipping test if given command is not available."""

1
tests/data/foo.txt Normal file
View File

@ -0,0 +1 @@
42

1
tests/data/foo/bar/t.txt Normal file
View File

@ -0,0 +1 @@
42

1
tests/data/foo/t.txt Normal file
View File

@ -0,0 +1 @@
42

View File

@ -36,11 +36,13 @@ class TestArchives (ArchiveTest):
def test_bzip2 (self):
self.archive_extract('t.bz2', 'bzip2')
self.archive_test('t.bz2', 'bzip2')
self.archive_create('t.bz2', 'bzip2', singlefile=True)
@needs_cmd('pbzip2')
def test_pbzip2 (self):
self.archive_extract('t.bz2', 'pbzip2')
self.archive_test('t.bz2', 'pbzip2')
self.archive_create('t.bz2', 'pbzip2', singlefile=True)
@needs_cmd('echo')
def test_echo (self):
@ -49,19 +51,27 @@ class TestArchives (ArchiveTest):
@needs_cmd('unzip')
def test_unzip (self):
self.archive_commands('t.zip', 'unzip')
self.archive_commands('t.jar', 'unzip')
self.archive_extract('t.zip', 'unzip')
self.archive_list('t.zip', 'unzip')
self.archive_test('t.zip', 'unzip')
self.archive_extract('t.jar', 'unzip')
self.archive_list('t.jar', 'unzip')
self.archive_test('t.jar', 'unzip')
@needs_cmd('gzip')
def test_gzip (self):
self.archive_commands('t.gz', 'gzip')
self.archive_commands('t.txt.gz', 'gzip')
self.archive_commands('t.gz', 'gzip', singlefile=True)
self.archive_commands('t.txt.gz', 'gzip', singlefile=True)
self.archive_extract('t.Z', 'gzip')
@needs_cmd('uncompress.real')
def test_uncompress (self):
self.archive_extract('t.Z', 'uncompress.real')
@needs_cmd('compress')
def test_compress (self):
self.archive_create('t.Z', 'compress', singlefile=True)
@needs_cmd('7z')
def test_p7zip (self):
self.archive_commands('t.7z', '7z')
@ -109,20 +119,19 @@ class TestArchives (ArchiveTest):
self.archive_commands('t.rar', 'rar')
@needs_cmd('cabextract')
def test_capextract (self):
def test_cabextract (self):
self.archive_list('t.cab', 'cabextract')
self.archive_extract('t.cab', 'cabextract')
@needs_cmd('arj')
def test_arj (self):
self.archive_list('t.arj', 'arj')
self.archive_test('t.arj', 'arj')
self.archive_extract('t.arj', 'arj')
self.archive_commands('t.arj', 'arj')
@needs_cmd('cpio')
def test_cpio (self):
self.archive_list('t.cpio', 'cpio')
self.archive_extract('t.cpio', 'cpio')
self.archive_create('t.cpio', 'cpio')
@needs_cmd('rpm')
def test_rpm (self):
@ -143,5 +152,5 @@ class TestArchives (ArchiveTest):
@needs_cmd('lzop')
def test_lzop (self):
self.archive_commands('t.lzo', 'lzop')
self.archive_commands('t.lzo', 'lzop', singlefile=True)