Added new command "patool diff" to show differences between two archives.

This commit is contained in:
Bastian Kleineidam 2010-03-11 16:02:08 +01:00
parent 084c4ffd3d
commit a30d44c6a5
6 changed files with 67 additions and 25 deletions

View File

@ -3,6 +3,8 @@
* Fix path error by using absolute pathname for archive when changing * Fix path error by using absolute pathname for archive when changing
the current working directory to the unpack directory. the current working directory to the unpack directory.
* Fix parsing of the "-v" short option. * Fix parsing of the "-v" short option.
* Added new command "patool diff" to show differences between two
archives.
0.7 "3000 Miles to Graceland" (released 8.3.2010) 0.7 "3000 Miles to Graceland" (released 8.3.2010)

View File

@ -17,6 +17,7 @@ patool - simple manager for file archives of various types
.SH SYNOPSIS .SH SYNOPSIS
\fBpatool\fP (\fBextract\fP|\fBlist\fP|\fBtest\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 \fBcreate\fP [\fIoptions\fP] <\fIarchive-file\fP> [\fIfiles\fP...]
\fBpatool\fP \fBdiff\fP [\fIoptions\fP] <\fIarchive1\fP> <\fIarchive2\fP>
\fBpatool\fP \fBformats\fP [\fIoptions\fP] \fBpatool\fP \fBformats\fP [\fIoptions\fP]
.SH DESCRIPTION .SH DESCRIPTION
Various archive types can be created, extracted, tested and listed by Various archive types can be created, extracted, tested and listed by
@ -38,6 +39,7 @@ It relies on helper applications to handle those archive formats
\fBpatool test --verbose dist.tar.gz\fP \fBpatool test --verbose dist.tar.gz\fP
\fBpatool list package.deb\fP \fBpatool list package.deb\fP
\fPpatool create --verbose myfiles.zip file1.txt dir/\fP \fPpatool create --verbose myfiles.zip file1.txt dir/\fP
\fBpatool diff release1.0.tar.gz release2.0.zip\fP
.SH COMMANDS .SH COMMANDS
Several commands and options are available. Several commands and options are available.
.SS \fBextract\fP .SS \fBextract\fP
@ -85,6 +87,11 @@ Verbose archive testing (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 \fBdiff\fP
Show differences between two archives.
.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

View File

@ -8,6 +8,7 @@ NAME
SYNOPSIS SYNOPSIS
patool (extract|list|test) [options] <archive-file>... patool (extract|list|test) [options] <archive-file>...
patool create [options] <archive-file> [files...] patool create [options] <archive-file> [files...]
patool diff [options] <archive1> <archive2>
patool formats [options] patool formats [options]
DESCRIPTION DESCRIPTION
@ -31,6 +32,7 @@ EXAMPLES
patool test --verbose dist.tar.gz patool test --verbose dist.tar.gz
patool list package.deb patool list package.deb
patool create --verbose myfiles.zip file1.txt dir/ patool create --verbose myfiles.zip file1.txt dir/
patool diff release1.0.tar.gz release2.0.zip
COMMANDS COMMANDS
Several commands and options are available. Several commands and options are available.
@ -78,6 +80,11 @@ COMMANDS
--help Show help for this command. --help Show help for this command.
diff
Show differences between two archives.
--help Show help for this command.
formats formats
Show all supported archive formats. Show all supported archive formats.

4
patool
View File

@ -70,6 +70,10 @@ def create (archive, file1, *files, **kwargs):
allfiles = (file1,)+files allfiles = (file1,)+files
return handle_archive(archive, 'create', *allfiles, **kwargs) return handle_archive(archive, 'create', *allfiles, **kwargs)
@baker.command
def diff (archive1, archive2):
"""Show differences between two archives."""
return handle_archive(archive1, "diff", archive2)
@baker.command @baker.command
def formats (): def formats ():

View File

@ -9,7 +9,7 @@ _patool()
COMPREPLY=() COMPREPLY=()
cur=`_get_cword` cur=`_get_cword`
commands='extract list test create formats' commands='extract list test create diff formats'
if [[ $COMP_CWORD -eq 1 ]] ; then if [[ $COMP_CWORD -eq 1 ]] ; then
if [[ "$cur" == -* ]]; then if [[ "$cur" == -* ]]; then

View File

@ -160,7 +160,6 @@ ArchivePrograms = {
'create': ('cpio',), 'create': ('cpio',),
}, },
'rpm': { 'rpm': {
# XXX rpm2cpio depends on cpio whose availability is not checked
'extract': ('rpm2cpio', '7z'), 'extract': ('rpm2cpio', '7z'),
'list': ('rpm', '7z'), 'list': ('rpm', '7z'),
'test': ('rpm', '7z'), 'test': ('rpm', '7z'),
@ -367,19 +366,17 @@ def make_user_readable (directory):
make_dir_readable(os.path.join(root, dirname)) make_dir_readable(os.path.join(root, dirname))
def cleanup_outdir (archive, outdir): def cleanup_outdir (outdir):
"""Cleanup outdir after extraction and return target file name.""" """Cleanup outdir after extraction and return target file name and
result string."""
make_user_readable(outdir) make_user_readable(outdir)
if outdir:
# move single directory or file in outdir # move single directory or file in outdir
(res, msg) = move_outdir_orphan(outdir) (success, msg) = move_outdir_orphan(outdir)
if res: if success:
target = "`%s'" % msg # msg is a single directory or filename
else: return msg, "`%s'" % msg
target = "`%s' (%s)" % (outdir, msg) # outdir remains unchanged
else: return outdir, "`%s' (%s)" % (outdir, msg)
target = "`%s'" % util.stripext(archive)
return target
def _handle_archive (archive, command, *args, **kwargs): def _handle_archive (archive, command, *args, **kwargs):
@ -404,30 +401,37 @@ def _handle_archive (archive, command, *args, **kwargs):
# import archive handler (eg. patoolib.programs.star.extract_tar()) # import archive handler (eg. patoolib.programs.star.extract_tar())
exec "from patoolib.programs.%s import %s_%s as func" % (module, command, format) exec "from patoolib.programs.%s import %s_%s as func" % (module, command, format)
get_archive_cmdlist = locals()['func'] get_archive_cmdlist = locals()['func']
# prepare func() call arguments # prepare keyword arguments for command list
kwargs = dict(verbose=config['verbose']) cmd_kwargs = dict(verbose=config['verbose'])
outdir = None
origarchive = None origarchive = None
if command == 'extract': if command == 'extract':
outdir = util.tmpdir(dir=os.getcwd()) if "outdir" in kwargs:
kwargs['outdir'] = outdir cmd_kwargs["outdir"] = kwargs["outdir"]
do_cleanup_outdir = False
else:
cmd_kwargs['outdir'] = util.tmpdir(dir=os.getcwd())
do_cleanup_outdir = True
elif command == 'create' and os.path.basename(program) == 'arc' and \ elif command == 'create' and os.path.basename(program) == 'arc' and \
".arc" in archive and not archive.endswith(".arc"): ".arc" in archive and not archive.endswith(".arc"):
# the arc program mangles the archive name if it contains ".arc" # the arc program mangles the archive name if it contains ".arc"
origarchive = archive origarchive = archive
archive = util.tmpfile(dir=os.path.dirname(archive), suffix=".arc") archive = util.tmpfile(dir=os.path.dirname(archive), suffix=".arc")
try: try:
cmdlist = get_archive_cmdlist(archive, encoding, program, *args, **kwargs) cmdlist = get_archive_cmdlist(archive, encoding, program, *args, **cmd_kwargs)
run_archive_cmdlist(cmdlist) run_archive_cmdlist(cmdlist)
if command == 'extract': if command == 'extract':
target = cleanup_outdir(archive, outdir) if do_cleanup_outdir:
print "%s: extracted to %s" % (archive, target) target, msg = cleanup_outdir(cmd_kwargs["outdir"])
print "%s: extracted to %s" % (archive, msg)
else:
target, msg = cmd_kwargs["outdir"], "`%s'" % cmd_kwargs["outdir"]
return target
elif command == 'create' and origarchive: elif command == 'create' and origarchive:
shutil.move(archive, origarchive) shutil.move(archive, origarchive)
finally: finally:
if outdir: if command == "extract":
try: try:
os.rmdir(outdir) os.rmdir(cmd_kwargs["outdir"])
except OSError: except OSError:
pass pass
@ -435,6 +439,9 @@ def _handle_archive (archive, command, *args, **kwargs):
def handle_archive (archive, command, *args, **kwargs): def handle_archive (archive, command, *args, **kwargs):
"""Handle archive file command; with nice error reporting.""" """Handle archive file command; with nice error reporting."""
try: try:
if command == "diff":
_diff_archives(archive, args[0])
else:
_handle_archive(archive, command, *args, **kwargs) _handle_archive(archive, command, *args, **kwargs)
res = 0 res = 0
except util.PatoolError, msg: except util.PatoolError, msg:
@ -444,3 +451,18 @@ def handle_archive (archive, command, *args, **kwargs):
util.log_internal_error() util.log_internal_error()
res = 1 res = 1
return res return res
def _diff_archives (archive1, archive2):
diff = util.find_program("diff")
if not diff:
raise util.PatoolError("diff(1) is required for showing archive differences, please install it")
tmpdir1 = util.tmpdir(dir=os.getcwd())
tmpdir2 = util.tmpdir(dir=os.getcwd())
try:
dir1 = _handle_archive(archive1, 'extract', outdir=tmpdir1)
dir2 = _handle_archive(archive2, 'extract', outdir=tmpdir2)
util.run([diff, "-BurN", dir1, dir2])
finally:
shutil.rmtree(tmpdir1, onerror=util.log_error)
shutil.rmtree(tmpdir2, onerror=util.log_error)