Add search command.
This commit is contained in:
parent
7d0d0f9601
commit
c854102908
|
@ -1,3 +1,10 @@
|
||||||
|
1.0 "" (released xx.xx.2013)
|
||||||
|
|
||||||
|
* Add support for grepping in archive contents.
|
||||||
|
* Fixed Python lzma archive handling.
|
||||||
|
* Fixed lzop and lrzip archive handling.
|
||||||
|
|
||||||
|
|
||||||
0.19 "The Kids Are All Right" (released 21.2.2013)
|
0.19 "The Kids Are All Right" (released 21.2.2013)
|
||||||
|
|
||||||
* Support the lzma module in Python >= 3.3
|
* Support the lzma module in Python >= 3.3
|
||||||
|
|
57
doc/patool.1
57
doc/patool.1
|
@ -1,5 +1,5 @@
|
||||||
.\" -*- nroff -*-
|
.\" -*- nroff -*-
|
||||||
.\" Copyright (C) 2010-2012 Bastian Kleineidam
|
.\" Copyright (C) 2010-2013 Bastian Kleineidam
|
||||||
.\"
|
.\"
|
||||||
.\" This program is free software: you can redistribute it and/or modify
|
.\" 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
|
.\" it under the terms of the GNU General Public License as published by
|
||||||
|
@ -11,15 +11,16 @@
|
||||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
.\" GNU General Public License for more details.
|
.\" GNU General Public License for more details.
|
||||||
.\"
|
.\"
|
||||||
.TH PATOOL "1" "February 2010" "patool"
|
.TH PATOOL "1" "February 2013" "patool"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
patool - portable command line archive file manager
|
patool - portable command line archive file manager
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
\fBpatool\fP (\fBlist\fP|\fBtest\fP) [\fB\-\-verbose\fP] <\fIarchive-file\fP>...
|
\fBpatool\fP (\fBlist\fP|\fBtest\fP) [\fB\-\-verbose\fP] <\fIarchive-file\fP>...
|
||||||
\fBpatool\fP \fBextract\fP [\fB\-\-verbose\fP] [\fB\-\-outdir=\fP\fIDIRNAME\fP] <\fIarchive-file\fP>...
|
\fBpatool\fP \fBextract\fP [\fB\-\-verbose\fP] [\fB\-\-outdir=\fP\fIDIRNAME\fP] <\fIarchive-file\fP>...
|
||||||
\fBpatool\fP \fBcreate\fP [\fB\-\-verbose\fP] <\fIarchive-file\fP> [\fIfiles\fP...]
|
\fBpatool\fP \fBcreate\fP [\fB\-\-verbose\fP] <\fIarchive-file\fP> [\fIfiles\fP...]
|
||||||
\fBpatool\fP \fBdiff\fP <\fIarchive1\fP> <\fIarchive2\fP>
|
\fBpatool\fP \fBdiff\fP [\fB\-\-verbose\fP] <\fIarchive1\fP> <\fIarchive2\fP>
|
||||||
\fBpatool\fP \fBrepack\fP <\fIarchive1\fP> <\fIarchive2\fP>
|
\fBpatool\fP \fBsearch\fP [\fB\-\-verbose\fP] <\fIpattern\fP> <\fIarchive-file\fP>...
|
||||||
|
\fBpatool\fP \fBrepack\fP [\fB\-\-verbose\fP] <\fIarchive1\fP> <\fIarchive2\fP>
|
||||||
\fBpatool\fP \fBformats\fP
|
\fBpatool\fP \fBformats\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
|
||||||
|
@ -47,10 +48,20 @@ installed.
|
||||||
\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
|
\fBpatool diff release1.0.tar.gz release2.0.zip\fP
|
||||||
|
\fBpatool search "def urlopen" python-3.3.tar.gz\fP
|
||||||
\fBpatool repack linux-2.6.33.tar.gz linux-2.6.33.tar.bz2\fP
|
\fBpatool repack linux-2.6.33.tar.gz linux-2.6.33.tar.bz2\fP
|
||||||
.SH COMMANDS
|
.SH COMMANDS
|
||||||
Several commands and options are available.
|
The following rules apply to all commands:
|
||||||
.SS \fBextract\fP
|
.IP "\(bu" 4
|
||||||
|
Existing files are never overwritten.
|
||||||
|
.IP "\(bu" 4
|
||||||
|
The original archive will never be removed.
|
||||||
|
.IP "\(bu" 4
|
||||||
|
Verbose operation displays more info about what patool does. It also
|
||||||
|
displays more info from the helper application if it's supported.
|
||||||
|
.PP
|
||||||
|
Several commands are available.
|
||||||
|
.SS extract
|
||||||
Extract files from an archive. The original archive will never
|
Extract files from an archive. The original archive will never
|
||||||
be removed and is left as it is.
|
be removed and is left as it is.
|
||||||
.br
|
.br
|
||||||
|
@ -68,35 +79,27 @@ of files from the extracted archive.
|
||||||
.PP
|
.PP
|
||||||
All extracted files are ensured that they are readable by the
|
All extracted files are ensured that they are readable by the
|
||||||
current user.
|
current user.
|
||||||
.TP
|
.SS list
|
||||||
\fB\-v\fP, \fB\-\-verbose\fP
|
|
||||||
Be verbose when extracting (if the helper application supports it).
|
|
||||||
.SS \fBlist\fP
|
|
||||||
List files in an archive.
|
List files in an archive.
|
||||||
.TP
|
.SS create
|
||||||
\fB\-v\fP, \fB\-\-verbose\fP
|
|
||||||
Verbose archive listing (if the helper application supports it).
|
|
||||||
.SS \fBcreate\fP
|
|
||||||
Create an archive from given files. At least on of the given files to add
|
Create an archive from given files. At least on of the given files to add
|
||||||
to the archive has to exist (non-existing files are ignored).
|
to the archive has to exist (non-existing files are ignored).
|
||||||
The format of the archive to create is determined by the archive file
|
The format of the archive to create is determined by the archive file
|
||||||
extension.
|
extension.
|
||||||
.TP
|
.SS test
|
||||||
\fB\-v\fP, \fB\-\-verbose\fP
|
|
||||||
Verbose operation (if the helper application supports it).
|
|
||||||
.SS \fBtest\fP
|
|
||||||
Test files in an archive. If the helper application does not support
|
Test files in an archive. If the helper application does not support
|
||||||
testing, the archive contents are listed instead.
|
testing, the archive contents are listed instead.
|
||||||
.TP
|
.SS diff
|
||||||
\fB\-v\fP, \fB\-\-verbose\fP
|
Show differences between two archives with the \fBdiff(1)\fP program.
|
||||||
Verbose archive testing (if the helper application supports it).
|
|
||||||
.SS \fBdiff\fP
|
|
||||||
Show differences between two archives with the \fBdiff(1)\fP utility.
|
|
||||||
The diff options used are \fB\-urN\fP.
|
The diff options used are \fB\-urN\fP.
|
||||||
.SS \fBrepack\fP
|
.SS search
|
||||||
|
Search in archive contents for given pattern using the \fBgrep(1)\fP program.
|
||||||
|
The grep options used are \fB\-r\fP; additional options can be supplied
|
||||||
|
with the \fBGREP_OPTIONS\fP environment variable.
|
||||||
|
.SS repack
|
||||||
Repackage archive to a different format. The target archive format is
|
Repackage archive to a different format. The target archive format is
|
||||||
determined by the file extension.
|
determined by the file extension.
|
||||||
.SS \fBformats\fP
|
.SS formats
|
||||||
Show all supported archive formats (ie. which helper applications
|
Show all supported archive formats (ie. which helper applications
|
||||||
are available).
|
are available).
|
||||||
.SH HELP OPTION
|
.SH HELP OPTION
|
||||||
|
@ -107,6 +110,6 @@ For example:
|
||||||
\fBpatool \-\-help\fP - display help for patool
|
\fBpatool \-\-help\fP - display help for patool
|
||||||
\fBpatool extract \-\-help\fP - display help for the extract command
|
\fBpatool extract \-\-help\fP - display help for the extract command
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Bastian Kleineidam <calvin@users.sourceforge.net>
|
Bastian Kleineidam <bastian.kleineidam@web.de>
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright \(co 2010-2012 Bastian Kleineidam
|
Copyright \(co 2010-2013 Bastian Kleineidam
|
||||||
|
|
|
@ -10,8 +10,9 @@ SYNOPSIS
|
||||||
patool extract [--verbose] [--outdir=DIRNAME] <archive-
|
patool extract [--verbose] [--outdir=DIRNAME] <archive-
|
||||||
file>...
|
file>...
|
||||||
patool create [--verbose] <archive-file> [files...]
|
patool create [--verbose] <archive-file> [files...]
|
||||||
patool diff <archive1> <archive2>
|
patool diff [--verbose] <archive1> <archive2>
|
||||||
patool repack <archive1> <archive2>
|
patool search [--verbose] <pattern> <archive-file>...
|
||||||
|
patool repack [--verbose] <archive1> <archive2>
|
||||||
patool formats
|
patool formats
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
|
@ -42,10 +43,21 @@ EXAMPLES
|
||||||
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
|
patool diff release1.0.tar.gz release2.0.zip
|
||||||
|
patool search "def urlopen" python-3.3.tar.gz
|
||||||
patool repack linux-2.6.33.tar.gz linux-2.6.33.tar.bz2
|
patool repack linux-2.6.33.tar.gz linux-2.6.33.tar.bz2
|
||||||
|
|
||||||
COMMANDS
|
COMMANDS
|
||||||
Several commands and options are available.
|
The following rules apply to all commands:
|
||||||
|
|
||||||
|
· Existing files are never overwritten.
|
||||||
|
|
||||||
|
· The original archive will never be removed.
|
||||||
|
|
||||||
|
· Verbose operation displays more info about what patool
|
||||||
|
does. It also displays more info from the helper applica‐
|
||||||
|
tion if it's supported.
|
||||||
|
|
||||||
|
Several commands are available.
|
||||||
|
|
||||||
extract
|
extract
|
||||||
Extract files from an archive. The original archive will never
|
Extract files from an archive. The original archive will never
|
||||||
|
@ -63,39 +75,28 @@ COMMANDS
|
||||||
All extracted files are ensured that they are readable by the
|
All extracted files are ensured that they are readable by the
|
||||||
current user.
|
current user.
|
||||||
|
|
||||||
-v, --verbose
|
|
||||||
Be verbose when extracting (if the helper application
|
|
||||||
supports it).
|
|
||||||
|
|
||||||
list
|
list
|
||||||
List files in an archive.
|
List files in an archive.
|
||||||
|
|
||||||
-v, --verbose
|
|
||||||
Verbose archive listing (if the helper application sup‐
|
|
||||||
ports it).
|
|
||||||
|
|
||||||
create
|
create
|
||||||
Create an archive from given files. At least on of the given
|
Create an archive from given files. At least on of the given
|
||||||
files to add to the archive has to exist (non-existing files
|
files to add to the archive has to exist (non-existing files
|
||||||
are ignored). The format of the archive to create is deter‐
|
are ignored). The format of the archive to create is deter‐
|
||||||
mined by the archive file extension.
|
mined by the archive file extension.
|
||||||
|
|
||||||
-v, --verbose
|
|
||||||
Verbose operation (if the helper application supports
|
|
||||||
it).
|
|
||||||
|
|
||||||
test
|
test
|
||||||
Test files in an archive. If the helper application does not
|
Test files in an archive. If the helper application does not
|
||||||
support testing, the archive contents are listed instead.
|
support testing, the archive contents are listed instead.
|
||||||
|
|
||||||
-v, --verbose
|
|
||||||
Verbose archive testing (if the helper application sup‐
|
|
||||||
ports it).
|
|
||||||
|
|
||||||
diff
|
diff
|
||||||
Show differences between two archives with the diff(1) utility.
|
Show differences between two archives with the diff(1) program.
|
||||||
The diff options used are -urN.
|
The diff options used are -urN.
|
||||||
|
|
||||||
|
search
|
||||||
|
Search in archive contents for given pattern using the grep(1)
|
||||||
|
program. The grep options used are -r; additional options can
|
||||||
|
be supplied with the GREP_OPTIONS environment variable.
|
||||||
|
|
||||||
repack
|
repack
|
||||||
Repackage archive to a different format. The target archive
|
Repackage archive to a different format. The target archive
|
||||||
format is determined by the file extension.
|
format is determined by the file extension.
|
||||||
|
@ -112,11 +113,11 @@ HELP OPTION
|
||||||
patool extract --help - display help for the extract command
|
patool extract --help - display help for the extract command
|
||||||
|
|
||||||
AUTHOR
|
AUTHOR
|
||||||
Bastian Kleineidam <calvin@users.sourceforge.net>
|
Bastian Kleineidam <bastian.kleineidam@web.de>
|
||||||
|
|
||||||
COPYRIGHT
|
COPYRIGHT
|
||||||
Copyright © 2010-2012 Bastian Kleineidam
|
Copyright © 2010-2013 Bastian Kleineidam
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
patool February 2010 PATOOL(1)
|
patool February 2013 PATOOL(1)
|
||||||
|
|
12
patool
12
patool
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (C) 2010-2012 Bastian Kleineidam
|
# Copyright (C) 2010-2013 Bastian Kleineidam
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -70,8 +70,7 @@ def test (archive, *archives, **kwargs):
|
||||||
@baker.command(shortopts=shortopts, params=params)
|
@baker.command(shortopts=shortopts, params=params)
|
||||||
def create (archive, file1, *files, **kwargs):
|
def create (archive, file1, *files, **kwargs):
|
||||||
"""Create an archive from given files."""
|
"""Create an archive from given files."""
|
||||||
allfiles = (file1,)+files
|
return handle_archive(archive, 'create', file1, *files, **kwargs)
|
||||||
return handle_archive(archive, 'create', *allfiles, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
@baker.command(shortopts=shortopts, params=params)
|
@baker.command(shortopts=shortopts, params=params)
|
||||||
|
@ -81,6 +80,13 @@ def diff (archive1, archive2, **kwargs):
|
||||||
return diff(archive1, archive2, **kwargs)
|
return diff(archive1, archive2, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@baker.command(shortopts=shortopts, params=params)
|
||||||
|
def search(pattern, archive1, *archives, **kwargs):
|
||||||
|
"""Search for pattern in all given archives."""
|
||||||
|
from patoolib import search
|
||||||
|
return search(pattern, archive1, *archives, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@baker.command(shortopts=shortopts, params=params)
|
@baker.command(shortopts=shortopts, params=params)
|
||||||
def repack (archive1, archive2, **kwargs):
|
def repack (archive1, archive2, **kwargs):
|
||||||
"""Repackage one archive in another format."""
|
"""Repackage one archive in another format."""
|
||||||
|
|
|
@ -473,6 +473,12 @@ def check_archive_arguments (archive, command, *args):
|
||||||
if not args:
|
if not args:
|
||||||
raise util.PatoolError("missing second archive filename for diff")
|
raise util.PatoolError("missing second archive filename for diff")
|
||||||
util.check_existing_filename(args[0])
|
util.check_existing_filename(args[0])
|
||||||
|
elif command == 'search':
|
||||||
|
if not archive:
|
||||||
|
# archive is the search pattern
|
||||||
|
raise util.PatoolError("empty search pattern")
|
||||||
|
for arg in args:
|
||||||
|
util.check_existing_filename(arg)
|
||||||
else:
|
else:
|
||||||
util.check_existing_filename(archive)
|
util.check_existing_filename(archive)
|
||||||
|
|
||||||
|
@ -563,7 +569,6 @@ def _diff_archives (archive1, archive2, **kwargs):
|
||||||
return 0
|
return 0
|
||||||
diff = util.find_program("diff")
|
diff = util.find_program("diff")
|
||||||
if not diff:
|
if not diff:
|
||||||
# XXX more helpful error message
|
|
||||||
msg = "The diff(1) program is required for showing archive differences, please install it."
|
msg = "The diff(1) program is required for showing archive differences, please install it."
|
||||||
raise util.PatoolError(msg)
|
raise util.PatoolError(msg)
|
||||||
tmpdir1 = util.tmpdir()
|
tmpdir1 = util.tmpdir()
|
||||||
|
@ -579,6 +584,32 @@ def _diff_archives (archive1, archive2, **kwargs):
|
||||||
shutil.rmtree(tmpdir1, onerror=rmtree_log_error)
|
shutil.rmtree(tmpdir1, onerror=rmtree_log_error)
|
||||||
|
|
||||||
|
|
||||||
|
def _search_archives(pattern, *archives, **kwargs):
|
||||||
|
"""Search for given pattern in all archives."""
|
||||||
|
grep = util.find_program("grep")
|
||||||
|
if not grep:
|
||||||
|
msg = "The grep(1) program is required for searching archive contents, please install it."
|
||||||
|
raise util.PatoolError(msg)
|
||||||
|
errors = 0
|
||||||
|
for archive in archives:
|
||||||
|
try:
|
||||||
|
errors += _search_archive(grep, pattern, archive, **kwargs)
|
||||||
|
except util.PatoolError as msg:
|
||||||
|
util.log_error("grep error: %s" % msg)
|
||||||
|
errors += 1
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def _search_archive(grep, pattern, archive, **kwargs):
|
||||||
|
"""Extract one archive and search for given pattern in extracted files."""
|
||||||
|
tmpdir = util.tmpdir()
|
||||||
|
try:
|
||||||
|
_handle_archive(archive, 'extract', outdir=tmpdir, **kwargs)
|
||||||
|
return util.run([grep, "-r", "-e", pattern, "."], cwd=tmpdir)
|
||||||
|
finally:
|
||||||
|
shutil.rmtree(tmpdir, onerror=rmtree_log_error)
|
||||||
|
|
||||||
|
|
||||||
def _repack_archive (archive1, archive2, **kwargs):
|
def _repack_archive (archive1, archive2, **kwargs):
|
||||||
"""Repackage an archive to a different format."""
|
"""Repackage an archive to a different format."""
|
||||||
format1, compression1 = get_archive_format(archive1)
|
format1, compression1 = get_archive_format(archive1)
|
||||||
|
@ -619,6 +650,8 @@ def handle_archive (archive, command, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
if command == "diff":
|
if command == "diff":
|
||||||
res = _diff_archives(archive, args[0], **kwargs)
|
res = _diff_archives(archive, args[0], **kwargs)
|
||||||
|
elif command == "search":
|
||||||
|
res = _search_archives(archive, *args, **kwargs)
|
||||||
elif command == "repack":
|
elif command == "repack":
|
||||||
res = _repack_archive(archive, args[0], **kwargs)
|
res = _repack_archive(archive, args[0], **kwargs)
|
||||||
else:
|
else:
|
||||||
|
@ -663,6 +696,11 @@ def diff (archive1, archive2, verbose=False):
|
||||||
return handle_archive(archive1, 'diff', archive2, verbose=verbose)
|
return handle_archive(archive1, 'diff', archive2, verbose=verbose)
|
||||||
|
|
||||||
|
|
||||||
|
def search(pattern, *archives, **kwargs):
|
||||||
|
"""Search pattern in archive members."""
|
||||||
|
return handle_archive(pattern, 'search', *archives, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def repack (archive1, archive2, verbose=False):
|
def repack (archive1, archive2, verbose=False):
|
||||||
"""Repack archive to different file and/or format."""
|
"""Repack archive to different file and/or format."""
|
||||||
return handle_archive(archive1, 'repack', archive2, verbose=verbose)
|
return handle_archive(archive1, 'repack', archive2, verbose=verbose)
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2013 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/>.
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import patoolib
|
||||||
|
from . import datadir, needs_program
|
||||||
|
|
||||||
|
class ArchiveSearchTest (unittest.TestCase):
|
||||||
|
|
||||||
|
@needs_program('grep')
|
||||||
|
@needs_program('unzip')
|
||||||
|
@needs_program('tar')
|
||||||
|
def test_search(self):
|
||||||
|
pattern = "42"
|
||||||
|
archive1 = os.path.join(datadir, "t.tar")
|
||||||
|
archive2 = os.path.join(datadir, "t.zip")
|
||||||
|
res = patoolib.handle_archive(pattern, "search", archive1, archive2)
|
||||||
|
self.assertEqual(res, 0)
|
Loading…
Reference in New Issue