Merged master
This commit is contained in:
commit
bb7347b03d
18
doc/patool.1
18
doc/patool.1
|
@ -15,9 +15,11 @@
|
||||||
.SH NAME
|
.SH NAME
|
||||||
patool - simple manager for file archives of various types
|
patool - simple manager for file archives of various types
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
\fBpatool\fP <\fIcommand\fP> [\fIoptions\fP] <\fIarchive-file\fP>
|
\fBpatool\fP (\fBextract\fP|\fBlist\fP|\fBtest\fP) [\fIoptions\fP] <\fIarchive-file\fP>
|
||||||
|
\fBpatool\fP \fBcreate\fP [\fIoptions\fP] <\fIarchive-file\fP> [\fIfiles..\fP]
|
||||||
|
\fBpatool\fP \fBformats\fP [\fIoptions\fP]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Various archive types can be created, extracted and listed by
|
Various archive types can be created, extracted, tested and listed by
|
||||||
\fBpatool\fP.
|
\fBpatool\fP.
|
||||||
The archive format is determined by the archive file extension and
|
The archive format is determined by the archive file extension and
|
||||||
as a fallback with file(1).
|
as a fallback with file(1).
|
||||||
|
@ -65,6 +67,14 @@ Verbose operation (if the helper application supports it).
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-help\fP
|
\fB\-\-help\fP
|
||||||
Show help for this command.
|
Show help for this command.
|
||||||
|
.SS \fBtest\fP
|
||||||
|
Test files in an archive.
|
||||||
|
.TP
|
||||||
|
\fB\-\-verbose\fP
|
||||||
|
Verbose archive testing (if the helper application supports it).
|
||||||
|
.TP
|
||||||
|
\fB\-\-help\fP
|
||||||
|
Show help for this command.
|
||||||
.SS \fBformats\fP
|
.SS \fBformats\fP
|
||||||
Show all supported archive formats.
|
Show all supported archive formats.
|
||||||
.TP
|
.TP
|
||||||
|
@ -92,7 +102,11 @@ Supported archive formats are listed by the \fBformats\fP command.
|
||||||
.TP
|
.TP
|
||||||
\fImode\fP\fB=/usr/bin/mycommand\fP
|
\fImode\fP\fB=/usr/bin/mycommand\fP
|
||||||
Set the application to handle the archive format for given mode.
|
Set the application to handle the archive format for given mode.
|
||||||
|
<<<<<<< HEAD
|
||||||
\fImode\fP can be one of (\fBextract\fP, \fBlist\fP, \fBcreate\fP).
|
\fImode\fP can be one of (\fBextract\fP, \fBlist\fP, \fBcreate\fP).
|
||||||
|
=======
|
||||||
|
\fImode\fP can be one of \fBextract\fP, \fBlist\fP, \fBtest\fP.
|
||||||
|
>>>>>>> master
|
||||||
.SH FILES
|
.SH FILES
|
||||||
\fB/etc/patool.conf\fP, \fB~/.patool.conf\fP -
|
\fB/etc/patool.conf\fP, \fB~/.patool.conf\fP -
|
||||||
configuration files
|
configuration files
|
||||||
|
|
|
@ -6,20 +6,23 @@ NAME
|
||||||
patool - simple manager for file archives of various types
|
patool - simple manager for file archives of various types
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
patool <command> [options] <archive-file>
|
patool (extract|list|test) [options] <archive-file>
|
||||||
|
patool create [options] <archive-file> [files..]
|
||||||
|
patool formats [options]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
Various archive types can be created, extracted and listed by patool. The archive format is determined by the archive file extension and as a fallback with file(1).
|
Various archive types can be created, extracted, tested and listed by patool. The archive format is determined by the archive file extension and as a fallback with
|
||||||
|
file(1).
|
||||||
|
|
||||||
patool supports 7z (.7z), ZIP (.zip, .jar), GZIP (.gz), compress (.Z), BZIP2 (.bz2), TAR (.tar), ARJ (.arj), CAB (.cab), CPIO (.cpio), RPM (.rpm), DEB (.deb), LZOP
|
patool supports 7z (.7z), ZIP (.zip, .jar), GZIP (.gz), compress (.Z), BZIP2 (.bz2), TAR (.tar), ARJ (.arj), CAB (.cab), CPIO (.cpio), RPM (.rpm), DEB (.deb), LZOP
|
||||||
(.lzo)and RAR (.rar) formats. It relies on helper applications to handle those archive formats (for example bzip2 for BZIP2 archives).
|
(.lzo)and RAR (.rar) formats. It relies on helper applications to handle those archive formats (for example bzip2 for BZIP2 archives).
|
||||||
|
|
||||||
COMMANDS
|
COMMANDS
|
||||||
Several commands and options are available.
|
Several commands and options are available.
|
||||||
|
|
||||||
extract
|
extract
|
||||||
Extract files from an archive4. Often one wants to extract all files in an archive to a single subdirectory. However, some archives contain multiple files in their
|
Extract files from an archive4. Often one wants to extract all files in an archive to a single subdirectory. However, some archives contain multiple files in their
|
||||||
root directories. The patool program overcomes this problem by first extracting files to a unique (temporary) directory, and then moving its contents back if possible.
|
root directories. The patool program overcomes this problem by first extracting files to a unique (temporary) directory, and then moving its contents back if possible.
|
||||||
This also prevents local files from being overwritten by mistake.
|
This also prevents local files from being overwritten by mistake.
|
||||||
|
|
||||||
--force
|
--force
|
||||||
|
@ -38,6 +41,14 @@ COMMANDS
|
||||||
|
|
||||||
--help Show help for this command.
|
--help Show help for this command.
|
||||||
|
|
||||||
|
test
|
||||||
|
Test files in an archive.
|
||||||
|
|
||||||
|
--verbose
|
||||||
|
Verbose archive testing (if the helper application supports it).
|
||||||
|
|
||||||
|
--help Show help for this command.
|
||||||
|
|
||||||
formats
|
formats
|
||||||
Show all supported archive formats.
|
Show all supported archive formats.
|
||||||
|
|
||||||
|
@ -61,7 +72,7 @@ CONFIGURATION
|
||||||
Supported archive formats are listed by the formats command.
|
Supported archive formats are listed by the formats command.
|
||||||
|
|
||||||
mode=/usr/bin/mycommand
|
mode=/usr/bin/mycommand
|
||||||
Set the application to handle the archive format for given mode. mode can be one of extract, list.
|
Set the application to handle the archive format for given mode. mode can be one of extract, list, test.
|
||||||
|
|
||||||
FILES
|
FILES
|
||||||
/etc/patool.conf, ~/.patool.conf - configuration files
|
/etc/patool.conf, ~/.patool.conf - configuration files
|
||||||
|
|
20
patool
20
patool
|
@ -20,17 +20,16 @@ patool [extract|list] [sub-command-options] <archive-file>
|
||||||
import sys
|
import sys
|
||||||
if not hasattr(sys, "version_info") or sys.version_info < (2, 5, 0, "final", 0):
|
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")
|
raise SystemExit("Error, this script needs Python >= 2.5 installed")
|
||||||
import baker
|
|
||||||
import patoolib
|
import patoolib
|
||||||
|
|
||||||
|
|
||||||
@baker.command
|
@patoolib.baker.command
|
||||||
def extract (archive, verbose=False, force=False):
|
def extract (archive, verbose=False, force=False):
|
||||||
"""Extract files from an archive."""
|
"""Extract files from an archive."""
|
||||||
return patoolib.handle_archive(archive, 'extract')
|
return patoolib.handle_archive(archive, 'extract')
|
||||||
|
|
||||||
|
|
||||||
@baker.command
|
@patoolib.baker.command
|
||||||
def list (archive, verbose=False):
|
def list (archive, verbose=False):
|
||||||
"""List files in an archive."""
|
"""List files in an archive."""
|
||||||
return patoolib.handle_archive(archive, 'list')
|
return patoolib.handle_archive(archive, 'list')
|
||||||
|
@ -42,9 +41,18 @@ def create (archive, *args):
|
||||||
return patoolib.handle_archive(archive, 'create', *args)
|
return patoolib.handle_archive(archive, 'create', *args)
|
||||||
|
|
||||||
|
|
||||||
@baker.command
|
@patoolib.baker.command
|
||||||
|
def test (archive, verbose=False):
|
||||||
|
"""Test files in an archive."""
|
||||||
|
return patoolib.handle_archive(archive, 'test', verbose=verbose)
|
||||||
|
|
||||||
|
|
||||||
|
@patoolib.baker.command
|
||||||
def formats ():
|
def formats ():
|
||||||
return patoolib.list_formats()
|
return patoolib.list_formats()
|
||||||
|
|
||||||
|
try:
|
||||||
sys.exit(baker.run())
|
sys.exit(patoolib.baker.run())
|
||||||
|
except patoolib.baker.CommandError, msg:
|
||||||
|
print >>sys.stderr, "patool error:", msg
|
||||||
|
sys.exit(1)
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from distutils.spawn import find_executable
|
from distutils.spawn import find_executable
|
||||||
from . import util
|
from . import util, baker
|
||||||
|
|
||||||
# Supported archive commands
|
# Supported archive commands
|
||||||
ArchiveCommands = ('list', 'extract', 'create')
|
ArchiveCommands = ('list', 'extract', 'test', 'create')
|
||||||
|
|
||||||
# Supported archive formats
|
# Supported archive formats
|
||||||
ArchiveFormats = ('gzip', 'bzip2', 'tar', 'zip', 'compress', '7z', 'rar',
|
ArchiveFormats = ('gzip', 'bzip2', 'tar', 'zip', 'compress', '7z', 'rar',
|
||||||
|
@ -55,6 +55,7 @@ ArchiveMimetypes = {
|
||||||
ArchivePrograms = {
|
ArchivePrograms = {
|
||||||
'bzip2': {
|
'bzip2': {
|
||||||
'extract': ('pbzip2', 'bzip2', '7z'),
|
'extract': ('pbzip2', 'bzip2', '7z'),
|
||||||
|
'test': ('pbzip2', 'bzip2', '7z'),
|
||||||
'list': ('7z', 'echo',),
|
'list': ('7z', 'echo',),
|
||||||
},
|
},
|
||||||
'tar': {
|
'tar': {
|
||||||
|
@ -63,6 +64,7 @@ ArchivePrograms = {
|
||||||
'zip': {
|
'zip': {
|
||||||
'extract': ('unzip', '7z'),
|
'extract': ('unzip', '7z'),
|
||||||
'list': ('unzip', '7z'),
|
'list': ('unzip', '7z'),
|
||||||
|
'test': ('unzip', '7z'),
|
||||||
},
|
},
|
||||||
'gzip': {
|
'gzip': {
|
||||||
None: ('gzip', '7z'),
|
None: ('gzip', '7z'),
|
||||||
|
@ -70,6 +72,7 @@ ArchivePrograms = {
|
||||||
'compress': {
|
'compress': {
|
||||||
'extract': ('gzip', '7z', 'uncompress.real'),
|
'extract': ('gzip', '7z', 'uncompress.real'),
|
||||||
'list': ('7z', 'echo',),
|
'list': ('7z', 'echo',),
|
||||||
|
'test': ('gzip', '7z'),
|
||||||
},
|
},
|
||||||
'7z': {
|
'7z': {
|
||||||
None: ('7z',),
|
None: ('7z',),
|
||||||
|
@ -78,27 +81,33 @@ ArchivePrograms = {
|
||||||
None: ('rar',),
|
None: ('rar',),
|
||||||
'extract': ('unrar', '7z'),
|
'extract': ('unrar', '7z'),
|
||||||
'list': ('unrar', '7z'),
|
'list': ('unrar', '7z'),
|
||||||
|
'test': ('unrar', '7z'),
|
||||||
},
|
},
|
||||||
'cab': {
|
'cab': {
|
||||||
'extract': ('cabextract', '7z'),
|
'extract': ('cabextract', '7z'),
|
||||||
'list': ('cabextract', '7z'),
|
'list': ('cabextract', '7z'),
|
||||||
|
'test': ('cabextract', '7z'),
|
||||||
},
|
},
|
||||||
'arj': {
|
'arj': {
|
||||||
'extract': ('arj', '7z'),
|
'extract': ('arj', '7z'),
|
||||||
'list': ('arj', '7z'),
|
'list': ('arj', '7z'),
|
||||||
|
'test': ('arj', '7z'),
|
||||||
},
|
},
|
||||||
'cpio': {
|
'cpio': {
|
||||||
'extract': ('cpio', '7z'),
|
'extract': ('cpio', '7z'),
|
||||||
'list': ('cpio', '7z'),
|
'list': ('cpio', '7z'),
|
||||||
|
'test': ('7z',),
|
||||||
},
|
},
|
||||||
'rpm': {
|
'rpm': {
|
||||||
# XXX rpm2cpio depends on cpio which is not checked
|
# XXX rpm2cpio depends on cpio which is not checked
|
||||||
'extract': ('rpm2cpio', '7z'),
|
'extract': ('rpm2cpio', '7z'),
|
||||||
'list': ('rpm', '7z'),
|
'list': ('rpm', '7z'),
|
||||||
|
'test': ('rpm', '7z'),
|
||||||
},
|
},
|
||||||
'deb': {
|
'deb': {
|
||||||
'extract': ('dpkg-deb', '7z'),
|
'extract': ('dpkg-deb', '7z'),
|
||||||
'list': ('dpkg-deb', '7z'),
|
'list': ('dpkg-deb', '7z'),
|
||||||
|
'test': ('dpkg-deb', '7z'),
|
||||||
},
|
},
|
||||||
'lzop': {
|
'lzop': {
|
||||||
None: ('lzop',),
|
None: ('lzop',),
|
||||||
|
|
|
@ -21,8 +21,8 @@ def extract_arj (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.append('x')
|
cmdlist.append('x')
|
||||||
cmdlist.append('-r')
|
cmdlist.append('-r')
|
||||||
cmdlist.append('-y')
|
cmdlist.append('-y')
|
||||||
if kwargs['verbose']:
|
if not kwargs['verbose']:
|
||||||
cmdlist.append('-v')
|
cmdlist.append('-i-')
|
||||||
cmdlist.extend([archive, kwargs['outdir']])
|
cmdlist.extend([archive, kwargs['outdir']])
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
@ -33,6 +33,18 @@ def list_arj (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.append('v')
|
cmdlist.append('v')
|
||||||
else:
|
else:
|
||||||
cmdlist.append('l')
|
cmdlist.append('l')
|
||||||
|
cmdlist.append('-i-')
|
||||||
|
cmdlist.append('-r')
|
||||||
|
cmdlist.append('-y')
|
||||||
|
cmdlist.extend([archive])
|
||||||
|
return cmdlist
|
||||||
|
|
||||||
|
def test_arj (archive, encoding, cmd, **kwargs):
|
||||||
|
"""Test a ARJ archive."""
|
||||||
|
cmdlist = [cmd]
|
||||||
|
cmdlist.append('t')
|
||||||
|
if not kwargs['verbose']:
|
||||||
|
cmdlist.append('-i-')
|
||||||
cmdlist.append('-r')
|
cmdlist.append('-r')
|
||||||
cmdlist.append('-y')
|
cmdlist.append('-y')
|
||||||
cmdlist.extend([archive])
|
cmdlist.extend([archive])
|
||||||
|
|
|
@ -0,0 +1,559 @@
|
||||||
|
#===============================================================================
|
||||||
|
# Copyright 2010 Matt Chaput
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
import re, sys
|
||||||
|
from inspect import getargspec
|
||||||
|
from textwrap import wrap
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_docstring(docstring):
|
||||||
|
"""Normalizes whitespace in the given string.
|
||||||
|
"""
|
||||||
|
return re.sub(r"[\r\n\t ]+", " ", docstring).strip()
|
||||||
|
|
||||||
|
|
||||||
|
param_exp = re.compile(r"^([\t ]*):param (.*?): ([^\n]*\n(\1[ \t]+[^\n]*\n)*)",
|
||||||
|
re.MULTILINE)
|
||||||
|
|
||||||
|
def find_param_docs(docstring):
|
||||||
|
"""Finds ReStructuredText-style ":param:" lines in the docstring and
|
||||||
|
returns a dictionary mapping param names to doc strings.
|
||||||
|
"""
|
||||||
|
|
||||||
|
paramdocs = {}
|
||||||
|
for match in param_exp.finditer(docstring):
|
||||||
|
name = match.group(2)
|
||||||
|
value = match.group(3)
|
||||||
|
paramdocs[name] = value
|
||||||
|
return paramdocs
|
||||||
|
|
||||||
|
def remove_param_docs(docstring):
|
||||||
|
"""Finds ReStructuredText-style ":param:" lines in the docstring and
|
||||||
|
returns a new string with the param documentation removed.
|
||||||
|
"""
|
||||||
|
return param_exp.sub("", docstring)
|
||||||
|
|
||||||
|
|
||||||
|
def process_docstring(docstring):
|
||||||
|
"""Takes a docstring and returns a list of strings representing
|
||||||
|
the paragraphs in the docstring.
|
||||||
|
"""
|
||||||
|
|
||||||
|
lines = docstring.split("\n")
|
||||||
|
paras = [[]]
|
||||||
|
for line in lines:
|
||||||
|
if not line.strip():
|
||||||
|
paras.append([])
|
||||||
|
else:
|
||||||
|
paras[-1].append(line)
|
||||||
|
paras = [normalize_docstring(" ".join(ls))
|
||||||
|
for ls in paras if ls]
|
||||||
|
return paras
|
||||||
|
|
||||||
|
|
||||||
|
def format_paras(paras, width, indent=0):
|
||||||
|
"""Takes a list of paragraph strings and formats them into a word-wrapped,
|
||||||
|
optionally indented string.
|
||||||
|
"""
|
||||||
|
|
||||||
|
output = []
|
||||||
|
for para in paras:
|
||||||
|
lines = wrap(para, width-indent)
|
||||||
|
if lines:
|
||||||
|
for line in lines:
|
||||||
|
output.append((" " * indent) + line)
|
||||||
|
output.append("")
|
||||||
|
return "\n".join(output)
|
||||||
|
|
||||||
|
|
||||||
|
def totype(v, default):
|
||||||
|
"""Tries to convert the value 'v' into the same type as 'default'.
|
||||||
|
"""
|
||||||
|
|
||||||
|
t = type(default)
|
||||||
|
if t is int:
|
||||||
|
return int(v)
|
||||||
|
elif t is float:
|
||||||
|
return float(v)
|
||||||
|
elif t is long:
|
||||||
|
return long(v)
|
||||||
|
elif t is bool:
|
||||||
|
lv = v.lower()
|
||||||
|
if lv in ("true", "yes", "on", "1"):
|
||||||
|
return True
|
||||||
|
elif lv in ("false", "no", "off", "0"):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
raise TypeError
|
||||||
|
else:
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
class CommandError(Exception): pass
|
||||||
|
|
||||||
|
|
||||||
|
class Cmd(object):
|
||||||
|
"""Stores metadata about a command.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, fn, argnames, keywords, shortopts,
|
||||||
|
has_varargs, has_kwargs, docstring, paramdocs):
|
||||||
|
self.name = name
|
||||||
|
self.fn = fn
|
||||||
|
self.argnames = argnames
|
||||||
|
self.keywords = keywords
|
||||||
|
self.shortopts = shortopts
|
||||||
|
self.has_varargs = has_varargs
|
||||||
|
self.has_kwargs = has_kwargs
|
||||||
|
self.docstring = docstring
|
||||||
|
self.paramdocs = paramdocs
|
||||||
|
|
||||||
|
|
||||||
|
class Baker(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.commands = {}
|
||||||
|
self.defaultcommand = None
|
||||||
|
|
||||||
|
def command(self, fn=None, name=None, default=False,
|
||||||
|
params=None, shortopts=None):
|
||||||
|
"""Registers a command with the bakery. This does not call the
|
||||||
|
function, it simply adds it to the list of functions this Baker
|
||||||
|
knows about.
|
||||||
|
|
||||||
|
This method is usually used as a decorator::
|
||||||
|
|
||||||
|
b = Baker()
|
||||||
|
|
||||||
|
@b.command
|
||||||
|
def test():
|
||||||
|
pass
|
||||||
|
|
||||||
|
:param fn: the function to register.
|
||||||
|
:param name: use this argument to register the command under a
|
||||||
|
different name than the function name.
|
||||||
|
:param default: if True, this command is used when a command is not
|
||||||
|
specified on the command line.
|
||||||
|
:param params: a dictionary mapping parameter names to docstrings. If
|
||||||
|
you don't specify this argument, parameter annotations will be used
|
||||||
|
(Python 3.x only), or the functions docstring will be searched for
|
||||||
|
Sphinx-style ':param' blocks.
|
||||||
|
:param shortopts: a dictionary mapping parameter names to short
|
||||||
|
options, e.g. {"verbose": "v"}.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# This method works as a decorator with or without arguments.
|
||||||
|
if fn is None:
|
||||||
|
# The decorator was given arguments, e.g. @command(default=True),
|
||||||
|
# so we have to return a function that will wrap the function when
|
||||||
|
# the decorator is applied.
|
||||||
|
return lambda fn: self.command(fn, default=default,
|
||||||
|
params=params,
|
||||||
|
shortopts=shortopts)
|
||||||
|
else:
|
||||||
|
name = name or fn.__name__
|
||||||
|
|
||||||
|
# Inspect the argument signature of the function
|
||||||
|
arglist, vargsname, kwargsname, defaults = getargspec(fn)
|
||||||
|
has_varargs = bool(vargsname)
|
||||||
|
has_kwargs = bool(kwargsname)
|
||||||
|
|
||||||
|
# Get the function's docstring
|
||||||
|
docstring = fn.__doc__ or ""
|
||||||
|
|
||||||
|
# If the user didn't specify parameter help in the decorator
|
||||||
|
# arguments, try to get it from parameter annotations (Python 3.x)
|
||||||
|
# or RST-style :param: lines in the docstring
|
||||||
|
if params is None:
|
||||||
|
if hasattr(fn, "func_annotations") and fn.func_annotations:
|
||||||
|
params = fn.func_annotations
|
||||||
|
else:
|
||||||
|
params = find_param_docs(docstring)
|
||||||
|
docstring = remove_param_docs(docstring)
|
||||||
|
|
||||||
|
# If the user didn't specify
|
||||||
|
shortopts = shortopts or {}
|
||||||
|
|
||||||
|
# Zip up the keyword argument names with their defaults
|
||||||
|
if defaults:
|
||||||
|
keywords = dict(zip(arglist[0-len(defaults):], defaults))
|
||||||
|
else:
|
||||||
|
keywords = {}
|
||||||
|
|
||||||
|
# If this is a method, remove 'self' from the argument list
|
||||||
|
if arglist and arglist[0] == "self":
|
||||||
|
arglist.pop(0)
|
||||||
|
|
||||||
|
# Create a Cmd object to represent this command and store it
|
||||||
|
cmd = Cmd(name, fn, arglist, keywords, shortopts,
|
||||||
|
has_varargs, has_kwargs,
|
||||||
|
docstring, params)
|
||||||
|
self.commands[cmd.name] = cmd
|
||||||
|
|
||||||
|
# If default is True, set this as the default command
|
||||||
|
if default: self.defaultcommand = cmd
|
||||||
|
|
||||||
|
return fn
|
||||||
|
|
||||||
|
def print_top_help(self, scriptname, file=sys.stdout):
|
||||||
|
"""Prints the documentation for the script and exits.
|
||||||
|
|
||||||
|
:param scriptname: the name of the script being executed (argv[0]).
|
||||||
|
:param file: the file to write the help to. The default is stdout.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Get a sorted list of all command names
|
||||||
|
cmdnames = sorted(self.commands.keys())
|
||||||
|
|
||||||
|
# Calculate the indent for the doc strings by taking the longest
|
||||||
|
# command name and adding 3 (one space before the name and two after)
|
||||||
|
rindent = max(len(name) for name in cmdnames) + 3
|
||||||
|
|
||||||
|
# Print the basic help for running a command
|
||||||
|
file.write("\nUsage: %s COMMAND <options>\n\n" % scriptname)
|
||||||
|
|
||||||
|
print("Available commands:\n\n")
|
||||||
|
for cmdname in cmdnames:
|
||||||
|
# Get the Cmd object for this command
|
||||||
|
cmd = self.commands[cmdname]
|
||||||
|
|
||||||
|
# Calculate the padding necessary to fill from the end of the
|
||||||
|
# command name to the documentation margin
|
||||||
|
tab = " " * (rindent - (len(cmdname)+1))
|
||||||
|
file.write(" " + cmdname + tab)
|
||||||
|
|
||||||
|
# Get the paragraphs of the command's docstring
|
||||||
|
paras = process_docstring(cmd.docstring)
|
||||||
|
if paras:
|
||||||
|
# Print the first paragraph
|
||||||
|
file.write(format_paras([paras[0]], 76, indent=rindent).lstrip())
|
||||||
|
|
||||||
|
file.write("\n")
|
||||||
|
file.write('Use "%s <command> --help" for individual command help.\n' % scriptname)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def print_command_help(self, scriptname, cmd, file=sys.stdout):
|
||||||
|
"""Prints the documentation for a specific command and exits.
|
||||||
|
|
||||||
|
:param scriptname: the name of the script being executed (argv[0]).
|
||||||
|
:param cmd: the Cmd object representing the command.
|
||||||
|
:param file: the file to write the help to. The default is stdout.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Print the usage for the command
|
||||||
|
file.write("\nUsage: %s %s" % (scriptname, cmd.name))
|
||||||
|
|
||||||
|
# Print the required and "optional" arguments (where optional
|
||||||
|
# arguments are keyword arguments with default None).
|
||||||
|
for name in cmd.argnames:
|
||||||
|
if name not in cmd.keywords:
|
||||||
|
# This is a positional argument
|
||||||
|
file.write(" <%s>" % name)
|
||||||
|
else:
|
||||||
|
# This is a keyword argument, so skip it unless the default is
|
||||||
|
# None, in which case treat it like an optional argument.
|
||||||
|
if cmd.keywords[name] is None:
|
||||||
|
file.write(" [<%s>]" % name)
|
||||||
|
|
||||||
|
if cmd.has_varargs:
|
||||||
|
# This command accepts a variable number of positional arguments
|
||||||
|
file.write(" [...]")
|
||||||
|
file.write("\n\n")
|
||||||
|
|
||||||
|
# Print the documentation for this command
|
||||||
|
paras = process_docstring(cmd.docstring)
|
||||||
|
if paras:
|
||||||
|
# Print the first paragraph with no indent (usually just a summary
|
||||||
|
# line)
|
||||||
|
file.write(format_paras([paras[0]], 76))
|
||||||
|
|
||||||
|
# Print subsequent paragraphs indented by 4 spaces
|
||||||
|
if len(paras) > 1:
|
||||||
|
file.write("\n")
|
||||||
|
file.write(format_paras(paras[1:], 76, indent=4))
|
||||||
|
file.write("\n")
|
||||||
|
|
||||||
|
# Print documentation for keyword options
|
||||||
|
if cmd.keywords:
|
||||||
|
file.write("Options:\n\n")
|
||||||
|
|
||||||
|
# Get a sorted list of keyword argument names
|
||||||
|
keynames = sorted(cmd.keywords.keys())
|
||||||
|
|
||||||
|
# Make formatted headings, e.g. " -k --keyword ", and put them in
|
||||||
|
# a list like [(name, heading), ...]
|
||||||
|
heads = []
|
||||||
|
for keyname in keynames:
|
||||||
|
if cmd.keywords[keyname] is None: continue
|
||||||
|
|
||||||
|
head = " --" + keyname
|
||||||
|
if keyname in cmd.shortopts:
|
||||||
|
head = " -" + cmd.shortopts[keyname] + head
|
||||||
|
head += " "
|
||||||
|
heads.append((keyname, head))
|
||||||
|
|
||||||
|
if heads:
|
||||||
|
# Find the length of the longest formatted heading
|
||||||
|
rindent = max(len(head) for keyname, head in heads)
|
||||||
|
# Pad the headings so they're all as long as the longest one
|
||||||
|
heads = [(keyname, head + (" " * (rindent - len(head))))
|
||||||
|
for keyname, head in heads]
|
||||||
|
|
||||||
|
# Print the option docs
|
||||||
|
for keyname, head in heads:
|
||||||
|
# Print the heading
|
||||||
|
file.write(head)
|
||||||
|
|
||||||
|
# If this parameter has documentation, print it after the
|
||||||
|
# heading
|
||||||
|
if keyname in cmd.paramdocs:
|
||||||
|
paras = process_docstring(cmd.paramdocs.get(keyname, ""))
|
||||||
|
file.write(format_paras(paras, 76, indent=rindent).lstrip())
|
||||||
|
else:
|
||||||
|
file.write("\n")
|
||||||
|
file.write("\n")
|
||||||
|
|
||||||
|
if any((cmd.keywords.get(a) is None) for a in cmd.argnames):
|
||||||
|
file.write("(specifying a single hyphen (-) in the argument list means all\n")
|
||||||
|
file.write("subsequent arguments are treated as bare arguments, not options)\n")
|
||||||
|
file.write("\n")
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def parse_args(self, scriptname, cmd, argv):
|
||||||
|
keywords = cmd.keywords
|
||||||
|
shortopts = cmd.shortopts
|
||||||
|
|
||||||
|
# shortopts maps long option names to characters. To look up short
|
||||||
|
# options, we need to create a reverse mapping.
|
||||||
|
shortchars = dict((v, k) for k, v in shortopts.iteritems())
|
||||||
|
|
||||||
|
# The *vargs list and **kwargs dict to build up from the command line
|
||||||
|
# arguments
|
||||||
|
vargs = []
|
||||||
|
kwargs = {}
|
||||||
|
|
||||||
|
while argv:
|
||||||
|
# Take the next argument
|
||||||
|
arg = argv.pop(0)
|
||||||
|
|
||||||
|
if arg == "-":
|
||||||
|
# All arguments following a single hyphen are treated as
|
||||||
|
# positional arguments
|
||||||
|
vargs.extend(argv)
|
||||||
|
break
|
||||||
|
|
||||||
|
elif arg == "--":
|
||||||
|
# What to do with a bare --? Right now, it's ignored.
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif arg.startswith("--"):
|
||||||
|
# Process long option
|
||||||
|
|
||||||
|
value = None
|
||||||
|
if "=" in arg:
|
||||||
|
# The argument was specified like --keyword=value
|
||||||
|
name, value = arg[2:].split("=", 1)
|
||||||
|
default = keywords.get(name)
|
||||||
|
try:
|
||||||
|
value = totype(value, default)
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# The argument was not specified with an equals sign...
|
||||||
|
name = arg[2:]
|
||||||
|
default = keywords.get(name)
|
||||||
|
|
||||||
|
if type(default) is bool:
|
||||||
|
# If this option is a boolean, it doesn't need a value;
|
||||||
|
# specifying it on the command line means "do the
|
||||||
|
# opposite of the default".
|
||||||
|
value = not default
|
||||||
|
else:
|
||||||
|
# The next item in the argument list is the value, i.e.
|
||||||
|
# --keyword value
|
||||||
|
if not argv or argv[0].startswith("-"):
|
||||||
|
# Oops, there isn't a value available... just use
|
||||||
|
# True, assuming this is a flag.
|
||||||
|
value = True
|
||||||
|
else:
|
||||||
|
value = argv.pop(0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
value = totype(value, default)
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Store this option
|
||||||
|
kwargs[name] = value
|
||||||
|
|
||||||
|
elif arg.startswith("-") and cmd.shortopts:
|
||||||
|
# Process short option(s)
|
||||||
|
|
||||||
|
# For each character after the '-'...
|
||||||
|
for i in xrange(1, len(arg)):
|
||||||
|
char = arg[i]
|
||||||
|
if char not in shortchars:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get the long option name corresponding to this char
|
||||||
|
name = shortchars[char]
|
||||||
|
|
||||||
|
default = keywords[name]
|
||||||
|
if type(default) is bool:
|
||||||
|
# If this option is a boolean, it doesn't need a value;
|
||||||
|
# specifying it on the command line means "do the
|
||||||
|
# opposite of the default".
|
||||||
|
kwargs[name] = not default
|
||||||
|
else:
|
||||||
|
# This option requires a value...
|
||||||
|
if i == len(arg)-1:
|
||||||
|
# This is the last character in the list, so the
|
||||||
|
# next argument on the command line is the value.
|
||||||
|
value = argv.pop(0)
|
||||||
|
else:
|
||||||
|
# There are other characters after this one, so
|
||||||
|
# the rest of the characters must represent the
|
||||||
|
# value (i.e. old-style UNIX option like -Nname)
|
||||||
|
value = totype(arg[i+1:], default)
|
||||||
|
|
||||||
|
try:
|
||||||
|
kwargs[name] = totype(value, default)
|
||||||
|
except ValueError:
|
||||||
|
raise CommandError("Couldn't convert %s value %r to type %s" % (name, value, type(default)))
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# This doesn't start with "-", so just add it to the list of
|
||||||
|
# positional arguments.
|
||||||
|
vargs.append(arg)
|
||||||
|
|
||||||
|
return vargs, kwargs
|
||||||
|
|
||||||
|
def parse(self, argv=None):
|
||||||
|
"""Parses the command and parameters to call from the list of command
|
||||||
|
line arguments. Returns a tuple of (Cmd object, position arg list,
|
||||||
|
keyword arg dict).
|
||||||
|
|
||||||
|
:param argv: the list of options passed to the command line (sys.argv).
|
||||||
|
"""
|
||||||
|
|
||||||
|
if argv is None: argv = sys.argv
|
||||||
|
|
||||||
|
scriptname = argv[0]
|
||||||
|
|
||||||
|
if (len(argv) < 2) or (argv[1] == "-h" or argv[1] == "--help"):
|
||||||
|
# Print the documentation for the script
|
||||||
|
self.print_top_help(scriptname)
|
||||||
|
|
||||||
|
if argv[1] == "help":
|
||||||
|
if len(argv) > 2 and argv[2] in self.commands:
|
||||||
|
cmd = self.commands[argv[2]]
|
||||||
|
self.print_command_help(scriptname, cmd)
|
||||||
|
self.print_top_help(scriptname)
|
||||||
|
|
||||||
|
if len(argv) > 1 and argv[1] in self.commands:
|
||||||
|
# The first argument on the command line (after the script name
|
||||||
|
# is the command to run.
|
||||||
|
cmd = self.commands[argv[1]]
|
||||||
|
|
||||||
|
if len(argv) > 2 and (argv[2] == "-h" or argv[2] == "--help"):
|
||||||
|
# Print the help for this command and exit
|
||||||
|
self.print_command_help(scriptname, cmd)
|
||||||
|
|
||||||
|
options = argv[2:]
|
||||||
|
else:
|
||||||
|
# No known command was specified. If there's a default command,
|
||||||
|
# use that.
|
||||||
|
cmd = self.defaultcommand
|
||||||
|
if cmd is None:
|
||||||
|
raise CommandError("unknown command `%s' specified" % argv[1])
|
||||||
|
|
||||||
|
options = argv[1:]
|
||||||
|
|
||||||
|
# Parse the rest of the arguments on the command line and use them to
|
||||||
|
# call the command function.
|
||||||
|
args, kwargs = self.parse_args(scriptname, cmd, options)
|
||||||
|
return (cmd, args, kwargs)
|
||||||
|
|
||||||
|
def apply(self, cmd, args, kwargs):
|
||||||
|
"""Calls the command function.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Create a list of positional arguments: arguments that are either
|
||||||
|
# required (not in keywords), or where the default is None (taken to be
|
||||||
|
# an optional positional argument). This is different from the Python
|
||||||
|
# calling convention, which will fill in keyword arguments with extra
|
||||||
|
# positional arguments.
|
||||||
|
posargs = [a for a in cmd.argnames if cmd.keywords.get(a) is None]
|
||||||
|
|
||||||
|
if len(args) > len(posargs) and not cmd.has_varargs:
|
||||||
|
raise CommandError("Too many arguments to %s: %s" % (cmd.name, " ".join(args)))
|
||||||
|
|
||||||
|
if not cmd.has_kwargs:
|
||||||
|
for k in sorted(kwargs.iterkeys()):
|
||||||
|
if k not in cmd.keywords:
|
||||||
|
raise CommandError("Unknown option --%s" % k)
|
||||||
|
|
||||||
|
# Rearrange the arguments into the order Python expects
|
||||||
|
newargs = []
|
||||||
|
newkwargs = {}
|
||||||
|
for name in cmd.argnames:
|
||||||
|
if args and cmd.keywords.get(name) is None:
|
||||||
|
# This argument is required or optional and we have a bare arg
|
||||||
|
# to fill it
|
||||||
|
newargs.append(args.pop(0))
|
||||||
|
elif name not in cmd.keywords and not args:
|
||||||
|
# This argument is required but we don't have a bare arg to
|
||||||
|
# fill it
|
||||||
|
raise CommandError("Required argument '%s' not given" % name)
|
||||||
|
else:
|
||||||
|
# This is a keyword argument
|
||||||
|
newkwargs[name] = kwargs.get(name, cmd.keywords[name])
|
||||||
|
newargs.extend(args)
|
||||||
|
|
||||||
|
return cmd.fn(*newargs, **newkwargs)
|
||||||
|
|
||||||
|
def run(self, argv=None):
|
||||||
|
"""Takes a list of command line arguments, parses it into a command
|
||||||
|
name and options, and calls the function corresponding to the command
|
||||||
|
with the given arguments.
|
||||||
|
|
||||||
|
:param argv: the list of options passed to the command line (sys.argv).
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self.apply(*self.parse(argv))
|
||||||
|
|
||||||
|
def test(self, argv=None):
|
||||||
|
"""Takes a list of command line arguments, parses it into a command
|
||||||
|
name and options, and prints what the resulting function call would
|
||||||
|
look like. This may be useful for testing how command line arguments
|
||||||
|
would be passed to your functions.
|
||||||
|
|
||||||
|
:param argv: the list of options passed to the command line (sys.argv).
|
||||||
|
"""
|
||||||
|
|
||||||
|
cmd, args, kwargs = self.parse(argv)
|
||||||
|
result = "%s(%s" % (cmd.name, ",".join(repr(a) for a in args))
|
||||||
|
if kwargs:
|
||||||
|
kws = ", ".join("%s=%r" % (k, v) for k, v in kwargs.iteritems())
|
||||||
|
result += ", " + kws
|
||||||
|
result += ")"
|
||||||
|
print result
|
||||||
|
|
||||||
|
|
||||||
|
_baker = Baker()
|
||||||
|
command = _baker.command
|
||||||
|
run = _baker.run
|
||||||
|
test = _baker.test
|
|
@ -30,3 +30,12 @@ def extract_bzip2 (archive, encoding, cmd, **kwargs):
|
||||||
# note that for shell calls the command must be a string
|
# note that for shell calls the command must be a string
|
||||||
cmd = " ".join([util.shell_quote(x) for x in cmdlist])
|
cmd = " ".join([util.shell_quote(x) for x in cmdlist])
|
||||||
return (cmd, {'shell': True})
|
return (cmd, {'shell': True})
|
||||||
|
|
||||||
|
|
||||||
|
def test_bzip2 (archive, encoding, cmd, **kwargs):
|
||||||
|
cmdlist = [cmd]
|
||||||
|
if kwargs['verbose']:
|
||||||
|
cmdlist.append('-v')
|
||||||
|
cmdlist.extend(['-t', '--'])
|
||||||
|
cmdlist.extend([archive])
|
||||||
|
return cmdlist
|
||||||
|
|
|
@ -32,3 +32,10 @@ def list_cab (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.append('-v')
|
cmdlist.append('-v')
|
||||||
cmdlist.extend([archive])
|
cmdlist.extend([archive])
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
def test_cab (archive, encoding, cmd, **kwargs):
|
||||||
|
"""Test a CAB archive."""
|
||||||
|
cmdlist = [cmd]
|
||||||
|
cmdlist.append('-t')
|
||||||
|
cmdlist.extend([archive])
|
||||||
|
return cmdlist
|
||||||
|
|
|
@ -33,3 +33,6 @@ def list_deb (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.append('--')
|
cmdlist.append('--')
|
||||||
cmdlist.extend([archive])
|
cmdlist.extend([archive])
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
test_deb = list_deb
|
||||||
|
|
||||||
|
|
|
@ -43,3 +43,15 @@ def list_gzip (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.append(archive)
|
cmdlist.append(archive)
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
|
||||||
|
def test_gzip (archive, encoding, cmd, **kwargs):
|
||||||
|
"""Test a GZIP archive."""
|
||||||
|
cmdlist = [cmd]
|
||||||
|
if kwargs['verbose']:
|
||||||
|
cmdlist.append('-v')
|
||||||
|
cmdlist.append('-t')
|
||||||
|
cmdlist.append('--')
|
||||||
|
cmdlist.append(archive)
|
||||||
|
return cmdlist
|
||||||
|
|
||||||
|
test_compress = test_gzip
|
||||||
|
|
|
@ -32,3 +32,12 @@ def list_lzop (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.append('--verbose')
|
cmdlist.append('--verbose')
|
||||||
cmdlist.extend(['--', archive])
|
cmdlist.extend(['--', archive])
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
def test_lzop (archive, encoding, cmd, **kwargs):
|
||||||
|
"""Test a LZOP archive."""
|
||||||
|
cmdlist = [cmd]
|
||||||
|
cmdlist.append('--test')
|
||||||
|
if kwargs['verbose']:
|
||||||
|
cmdlist.append('--verbose')
|
||||||
|
cmdlist.extend(['--', archive])
|
||||||
|
return cmdlist
|
||||||
|
|
|
@ -59,3 +59,26 @@ list_bzip2 = \
|
||||||
list_rpm = \
|
list_rpm = \
|
||||||
list_deb = \
|
list_deb = \
|
||||||
list_7z
|
list_7z
|
||||||
|
|
||||||
|
|
||||||
|
def test_7z (archive, encoding, cmd, **kwargs):
|
||||||
|
"""Test a 7z archive."""
|
||||||
|
cmdlist = [cmd]
|
||||||
|
cmdlist.append('t')
|
||||||
|
if not kwargs['verbose']:
|
||||||
|
cmdlist.append('-bd')
|
||||||
|
cmdlist.append('--')
|
||||||
|
cmdlist.append(archive)
|
||||||
|
return cmdlist
|
||||||
|
|
||||||
|
test_bzip2 = \
|
||||||
|
test_gzip = \
|
||||||
|
test_zip = \
|
||||||
|
test_compress = \
|
||||||
|
test_rar = \
|
||||||
|
test_cab = \
|
||||||
|
test_arj = \
|
||||||
|
test_cpio = \
|
||||||
|
test_rpm = \
|
||||||
|
test_deb = \
|
||||||
|
test_7z
|
||||||
|
|
|
@ -15,4 +15,4 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""Archive commands for the pbzip2 program."""
|
"""Archive commands for the pbzip2 program."""
|
||||||
# bzip2 and pbzip2 are compatible
|
# bzip2 and pbzip2 are compatible
|
||||||
from .bzip2 import extract_bzip2
|
from .bzip2 import extract_bzip2, test_bzip2
|
||||||
|
|
|
@ -34,3 +34,12 @@ def list_rar (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.append('-c-')
|
cmdlist.append('-c-')
|
||||||
cmdlist.extend(['--', archive])
|
cmdlist.extend(['--', archive])
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
def test_rar (archive, encoding, cmd, **kwargs):
|
||||||
|
"""Test a RAR archive."""
|
||||||
|
cmdlist = [cmd]
|
||||||
|
cmdlist.append('t')
|
||||||
|
if not kwargs['verbose']:
|
||||||
|
cmdlist.append('-c-')
|
||||||
|
cmdlist.extend(['--', archive])
|
||||||
|
return cmdlist
|
||||||
|
|
|
@ -23,3 +23,12 @@ def list_rpm (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.append('-v')
|
cmdlist.append('-v')
|
||||||
cmdlist.extend(['-p', '--', archive])
|
cmdlist.extend(['-p', '--', archive])
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
def test_rpm (archive, encoding, cmd, **kwargs):
|
||||||
|
"""Test a RPM archive."""
|
||||||
|
cmdlist = [cmd]
|
||||||
|
cmdlist.append('-V')
|
||||||
|
if kwargs['verbose']:
|
||||||
|
cmdlist.append('-v')
|
||||||
|
cmdlist.extend(['-p', '--', archive])
|
||||||
|
return cmdlist
|
||||||
|
|
|
@ -44,3 +44,5 @@ def list_tar (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.append('-v')
|
cmdlist.append('-v')
|
||||||
cmdlist.append("file=%s" % archive)
|
cmdlist.append("file=%s" % archive)
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
test_tar = list_tar
|
||||||
|
|
|
@ -35,6 +35,8 @@ def list_tar (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.extend(["--file", archive])
|
cmdlist.extend(["--file", archive])
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
test_tar = list_tar
|
||||||
|
|
||||||
def create_tar (archive, encoding, cmd, **kwargs):
|
def create_tar (archive, encoding, cmd, **kwargs):
|
||||||
"""Create a TAR archive."""
|
"""Create a TAR archive."""
|
||||||
print "XXX create", archive, encoding, cmd, kwargs
|
print "XXX create", archive, encoding, cmd, kwargs
|
||||||
|
|
|
@ -34,3 +34,12 @@ def list_rar (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.append('-c-')
|
cmdlist.append('-c-')
|
||||||
cmdlist.extend(['--', archive])
|
cmdlist.extend(['--', archive])
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
def test_rar (archive, encoding, cmd, **kwargs):
|
||||||
|
"""Test a RAR archive."""
|
||||||
|
cmdlist = [cmd]
|
||||||
|
cmdlist.append('t')
|
||||||
|
if not kwargs['verbose']:
|
||||||
|
cmdlist.append('-c-')
|
||||||
|
cmdlist.extend(['--', archive])
|
||||||
|
return cmdlist
|
||||||
|
|
|
@ -31,3 +31,12 @@ def list_zip (archive, encoding, cmd, **kwargs):
|
||||||
cmdlist.append('-v')
|
cmdlist.append('-v')
|
||||||
cmdlist.extend(['--', archive])
|
cmdlist.extend(['--', archive])
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
def test_zip (archive, encoding, cmd, **kwargs):
|
||||||
|
"""Test a ZIP archive."""
|
||||||
|
cmdlist = [cmd]
|
||||||
|
cmdlist.append('-t')
|
||||||
|
if kwargs['verbose']:
|
||||||
|
cmdlist.append('-v')
|
||||||
|
cmdlist.extend(['--', archive])
|
||||||
|
return cmdlist
|
||||||
|
|
|
@ -26,8 +26,9 @@ datadir = os.path.join(basedir, 'data')
|
||||||
class ArchiveTest (unittest.TestCase):
|
class ArchiveTest (unittest.TestCase):
|
||||||
"""Helper class for achive tests."""
|
"""Helper class for achive tests."""
|
||||||
|
|
||||||
def archive_test (self, filename, cmd):
|
def archive_commands (self, filename, cmd):
|
||||||
self.archive_list(filename, cmd)
|
self.archive_list(filename, cmd)
|
||||||
|
self.archive_test(filename, cmd)
|
||||||
self.archive_extract(filename, cmd)
|
self.archive_extract(filename, cmd)
|
||||||
|
|
||||||
def archive_extract (self, filename, cmd):
|
def archive_extract (self, filename, cmd):
|
||||||
|
@ -36,16 +37,21 @@ class ArchiveTest (unittest.TestCase):
|
||||||
tmpdir = patoolib.util.tmpdir(dir=basedir)
|
tmpdir = patoolib.util.tmpdir(dir=basedir)
|
||||||
os.chdir(tmpdir)
|
os.chdir(tmpdir)
|
||||||
try:
|
try:
|
||||||
patoolib._handle_archive(archive, 'extract', cmd=cmd)
|
patoolib._handle_archive(archive, 'extract', program=cmd)
|
||||||
patoolib._handle_archive(archive, 'extract', cmd=cmd, force=True)
|
patoolib._handle_archive(archive, 'extract', program=cmd, force=True)
|
||||||
finally:
|
finally:
|
||||||
os.chdir(basedir)
|
os.chdir(basedir)
|
||||||
shutil.rmtree(tmpdir)
|
shutil.rmtree(tmpdir)
|
||||||
|
|
||||||
def archive_list (self, filename, cmd):
|
def archive_list (self, filename, cmd):
|
||||||
archive = os.path.join(datadir, filename)
|
archive = os.path.join(datadir, filename)
|
||||||
patoolib._handle_archive(archive, 'list', cmd=cmd)
|
patoolib._handle_archive(archive, 'list', program=cmd)
|
||||||
patoolib._handle_archive(archive, 'list', cmd=cmd, verbose=True)
|
patoolib._handle_archive(archive, 'list', program=cmd, verbose=True)
|
||||||
|
|
||||||
|
def archive_test (self, filename, cmd):
|
||||||
|
archive = os.path.join(datadir, filename)
|
||||||
|
patoolib._handle_archive(archive, 'test', program=cmd)
|
||||||
|
patoolib._handle_archive(archive, 'test', program=cmd, verbose=True)
|
||||||
|
|
||||||
|
|
||||||
def needs_cmd (cmd):
|
def needs_cmd (cmd):
|
||||||
|
|
|
@ -26,19 +26,21 @@ class TestArchives (ArchiveTest):
|
||||||
self.tar_test('star')
|
self.tar_test('star')
|
||||||
|
|
||||||
def tar_test (self, cmd):
|
def tar_test (self, cmd):
|
||||||
self.archive_test('t.tar', cmd)
|
self.archive_commands('t.tar', cmd)
|
||||||
self.archive_test('t.tar.gz', cmd)
|
self.archive_commands('t.tar.gz', cmd)
|
||||||
self.archive_test('t.tar.Z', cmd)
|
self.archive_commands('t.tar.Z', cmd)
|
||||||
self.archive_test('t.tar.bz2', cmd)
|
self.archive_commands('t.tar.bz2', cmd)
|
||||||
self.archive_test('t.tbz2', cmd)
|
self.archive_commands('t.tbz2', cmd)
|
||||||
|
|
||||||
@needs_cmd('bzip2')
|
@needs_cmd('bzip2')
|
||||||
def test_bzip2 (self):
|
def test_bzip2 (self):
|
||||||
self.archive_extract('t.bz2', 'bzip2')
|
self.archive_extract('t.bz2', 'bzip2')
|
||||||
|
self.archive_test('t.bz2', 'bzip2')
|
||||||
|
|
||||||
@needs_cmd('pbzip2')
|
@needs_cmd('pbzip2')
|
||||||
def test_pbzip2 (self):
|
def test_pbzip2 (self):
|
||||||
self.archive_extract('t.bz2', 'pbzip2')
|
self.archive_extract('t.bz2', 'pbzip2')
|
||||||
|
self.archive_test('t.bz2', 'pbzip2')
|
||||||
|
|
||||||
@needs_cmd('echo')
|
@needs_cmd('echo')
|
||||||
def test_echo (self):
|
def test_echo (self):
|
||||||
|
@ -47,13 +49,13 @@ class TestArchives (ArchiveTest):
|
||||||
|
|
||||||
@needs_cmd('unzip')
|
@needs_cmd('unzip')
|
||||||
def test_unzip (self):
|
def test_unzip (self):
|
||||||
self.archive_test('t.zip', 'unzip')
|
self.archive_commands('t.zip', 'unzip')
|
||||||
self.archive_test('t.jar', 'unzip')
|
self.archive_commands('t.jar', 'unzip')
|
||||||
|
|
||||||
@needs_cmd('gzip')
|
@needs_cmd('gzip')
|
||||||
def test_gzip (self):
|
def test_gzip (self):
|
||||||
self.archive_test('t.gz', 'gzip')
|
self.archive_commands('t.gz', 'gzip')
|
||||||
self.archive_test('t.txt.gz', 'gzip')
|
self.archive_commands('t.txt.gz', 'gzip')
|
||||||
self.archive_extract('t.Z', 'gzip')
|
self.archive_extract('t.Z', 'gzip')
|
||||||
|
|
||||||
@needs_cmd('uncompress.real')
|
@needs_cmd('uncompress.real')
|
||||||
|
@ -62,7 +64,7 @@ class TestArchives (ArchiveTest):
|
||||||
|
|
||||||
@needs_cmd('7z')
|
@needs_cmd('7z')
|
||||||
def test_p7zip (self):
|
def test_p7zip (self):
|
||||||
self.archive_test('t.7z', '7z')
|
self.archive_commands('t.7z', '7z')
|
||||||
self.archive_list('t.gz', '7z')
|
self.archive_list('t.gz', '7z')
|
||||||
self.archive_list('t.bz2', '7z')
|
self.archive_list('t.bz2', '7z')
|
||||||
self.archive_list('t.zip', '7z')
|
self.archive_list('t.zip', '7z')
|
||||||
|
@ -85,6 +87,17 @@ class TestArchives (ArchiveTest):
|
||||||
self.archive_extract('t.cpio', '7z')
|
self.archive_extract('t.cpio', '7z')
|
||||||
self.archive_extract('t.rpm', '7z')
|
self.archive_extract('t.rpm', '7z')
|
||||||
self.archive_extract('t.deb', '7z')
|
self.archive_extract('t.deb', '7z')
|
||||||
|
self.archive_test('t.gz', '7z')
|
||||||
|
self.archive_test('t.bz2', '7z')
|
||||||
|
self.archive_test('t.zip', '7z')
|
||||||
|
self.archive_test('t.jar', '7z')
|
||||||
|
self.archive_test('t.Z', '7z')
|
||||||
|
self.archive_test('t.rar', '7z')
|
||||||
|
self.archive_test('t.cab', '7z')
|
||||||
|
self.archive_test('t.arj', '7z')
|
||||||
|
self.archive_test('t.cpio', '7z')
|
||||||
|
self.archive_test('t.rpm', '7z')
|
||||||
|
self.archive_test('t.deb', '7z')
|
||||||
|
|
||||||
@needs_cmd('unrar')
|
@needs_cmd('unrar')
|
||||||
def test_unrar (self):
|
def test_unrar (self):
|
||||||
|
@ -93,7 +106,7 @@ class TestArchives (ArchiveTest):
|
||||||
|
|
||||||
@needs_cmd('rar')
|
@needs_cmd('rar')
|
||||||
def test_rar (self):
|
def test_rar (self):
|
||||||
self.archive_test('t.rar', 'rar')
|
self.archive_commands('t.rar', 'rar')
|
||||||
|
|
||||||
@needs_cmd('cabextract')
|
@needs_cmd('cabextract')
|
||||||
def test_capextract (self):
|
def test_capextract (self):
|
||||||
|
@ -103,6 +116,7 @@ class TestArchives (ArchiveTest):
|
||||||
@needs_cmd('arj')
|
@needs_cmd('arj')
|
||||||
def test_arj (self):
|
def test_arj (self):
|
||||||
self.archive_list('t.arj', 'arj')
|
self.archive_list('t.arj', 'arj')
|
||||||
|
self.archive_test('t.arj', 'arj')
|
||||||
self.archive_extract('t.arj', 'arj')
|
self.archive_extract('t.arj', 'arj')
|
||||||
|
|
||||||
@needs_cmd('cpio')
|
@needs_cmd('cpio')
|
||||||
|
@ -113,6 +127,8 @@ class TestArchives (ArchiveTest):
|
||||||
@needs_cmd('rpm')
|
@needs_cmd('rpm')
|
||||||
def test_rpm (self):
|
def test_rpm (self):
|
||||||
self.archive_list('t.rpm', 'rpm')
|
self.archive_list('t.rpm', 'rpm')
|
||||||
|
# the rpm test fails on non-rpm system with missing dependencies
|
||||||
|
#self.archive_test('t.rpm', 'rpm')
|
||||||
|
|
||||||
@needs_cmd('rpm2cpio')
|
@needs_cmd('rpm2cpio')
|
||||||
@needs_cmd('cpio')
|
@needs_cmd('cpio')
|
||||||
|
@ -123,8 +139,9 @@ class TestArchives (ArchiveTest):
|
||||||
def test_dpkg (self):
|
def test_dpkg (self):
|
||||||
self.archive_list('t.deb', 'dpkg')
|
self.archive_list('t.deb', 'dpkg')
|
||||||
self.archive_extract('t.deb', 'dpkg')
|
self.archive_extract('t.deb', 'dpkg')
|
||||||
|
self.archive_test('t.deb', 'dpkg')
|
||||||
|
|
||||||
@needs_cmd('lzop')
|
@needs_cmd('lzop')
|
||||||
def test_lzop (self):
|
def test_lzop (self):
|
||||||
self.archive_test('t.lzo', 'lzop')
|
self.archive_commands('t.lzo', 'lzop')
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue