Added new command "patool diff" to show differences between two archives.
This commit is contained in:
parent
084c4ffd3d
commit
a30d44c6a5
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
4
patool
|
@ -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 ():
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue