From c854102908f9b6e3e9022434c81bed4d92222e41 Mon Sep 17 00:00:00 2001 From: Bastian Kleineidam Date: Fri, 22 Feb 2013 18:38:52 +0100 Subject: [PATCH] Add search command. --- doc/changelog.txt | 7 ++++++ doc/patool.1 | 57 +++++++++++++++++++++++--------------------- doc/patool.txt | 49 ++++++++++++++++++------------------- patool | 12 +++++++--- patoolib/__init__.py | 40 ++++++++++++++++++++++++++++++- tests/test_search.py | 31 ++++++++++++++++++++++++ 6 files changed, 141 insertions(+), 55 deletions(-) create mode 100644 tests/test_search.py diff --git a/doc/changelog.txt b/doc/changelog.txt index 7c3597e..610da98 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -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) * Support the lzma module in Python >= 3.3 diff --git a/doc/patool.1 b/doc/patool.1 index 5f152a0..973cdd6 100644 --- a/doc/patool.1 +++ b/doc/patool.1 @@ -1,5 +1,5 @@ .\" -*- 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 .\" 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 .\" GNU General Public License for more details. .\" -.TH PATOOL "1" "February 2010" "patool" +.TH PATOOL "1" "February 2013" "patool" .SH NAME patool - portable command line archive file manager .SH SYNOPSIS \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 \fBcreate\fP [\fB\-\-verbose\fP] <\fIarchive-file\fP> [\fIfiles\fP...] - \fBpatool\fP \fBdiff\fP <\fIarchive1\fP> <\fIarchive2\fP> - \fBpatool\fP \fBrepack\fP <\fIarchive1\fP> <\fIarchive2\fP> + \fBpatool\fP \fBdiff\fP [\fB\-\-verbose\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 .SH DESCRIPTION Various archive types can be created, extracted, tested and listed by @@ -47,10 +48,20 @@ installed. \fBpatool list package.deb\fP \fPpatool create --verbose myfiles.zip file1.txt dir/\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 .SH COMMANDS -Several commands and options are available. -.SS \fBextract\fP +The following rules apply to all commands: +.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 be removed and is left as it is. .br @@ -68,35 +79,27 @@ of files from the extracted archive. .PP All extracted files are ensured that they are readable by the current user. -.TP -\fB\-v\fP, \fB\-\-verbose\fP -Be verbose when extracting (if the helper application supports it). -.SS \fBlist\fP +.SS list List files in an archive. -.TP -\fB\-v\fP, \fB\-\-verbose\fP -Verbose archive listing (if the helper application supports it). -.SS \fBcreate\fP +.SS create 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). The format of the archive to create is determined by the archive file extension. -.TP -\fB\-v\fP, \fB\-\-verbose\fP -Verbose operation (if the helper application supports it). -.SS \fBtest\fP +.SS test Test files in an archive. If the helper application does not support testing, the archive contents are listed instead. -.TP -\fB\-v\fP, \fB\-\-verbose\fP -Verbose archive testing (if the helper application supports it). -.SS \fBdiff\fP -Show differences between two archives with the \fBdiff(1)\fP utility. +.SS diff +Show differences between two archives with the \fBdiff(1)\fP program. 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 determined by the file extension. -.SS \fBformats\fP +.SS formats Show all supported archive formats (ie. which helper applications are available). .SH HELP OPTION @@ -107,6 +110,6 @@ For example: \fBpatool \-\-help\fP - display help for patool \fBpatool extract \-\-help\fP - display help for the extract command .SH AUTHOR -Bastian Kleineidam +Bastian Kleineidam .SH COPYRIGHT -Copyright \(co 2010-2012 Bastian Kleineidam +Copyright \(co 2010-2013 Bastian Kleineidam diff --git a/doc/patool.txt b/doc/patool.txt index 01d05a9..765ddb0 100644 --- a/doc/patool.txt +++ b/doc/patool.txt @@ -10,8 +10,9 @@ SYNOPSIS patool extract [--verbose] [--outdir=DIRNAME] ... patool create [--verbose] [files...] - patool diff - patool repack + patool diff [--verbose] + patool search [--verbose] ... + patool repack [--verbose] patool formats DESCRIPTION @@ -42,10 +43,21 @@ EXAMPLES patool list package.deb patool create --verbose myfiles.zip file1.txt dir/ 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 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 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 current user. - -v, --verbose - Be verbose when extracting (if the helper application - supports it). - list List files in an archive. - -v, --verbose - Verbose archive listing (if the helper application sup‐ - ports it). - create 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). The format of the archive to create is deter‐ mined by the archive file extension. - -v, --verbose - Verbose operation (if the helper application supports - it). - 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. - -v, --verbose - Verbose archive testing (if the helper application sup‐ - ports it). - 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. + 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 Repackage archive to a different format. The target archive format is determined by the file extension. @@ -112,11 +113,11 @@ HELP OPTION patool extract --help - display help for the extract command AUTHOR - Bastian Kleineidam + Bastian Kleineidam COPYRIGHT - Copyright © 2010-2012 Bastian Kleineidam + Copyright © 2010-2013 Bastian Kleineidam -patool February 2010 PATOOL(1) +patool February 2013 PATOOL(1) diff --git a/patool b/patool index ab44c61..662c3e5 100755 --- a/patool +++ b/patool @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- 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 # 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) def create (archive, file1, *files, **kwargs): """Create an archive from given files.""" - allfiles = (file1,)+files - return handle_archive(archive, 'create', *allfiles, **kwargs) + return handle_archive(archive, 'create', file1, *files, **kwargs) @baker.command(shortopts=shortopts, params=params) @@ -81,6 +80,13 @@ def 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) def repack (archive1, archive2, **kwargs): """Repackage one archive in another format.""" diff --git a/patoolib/__init__.py b/patoolib/__init__.py index 103752c..0b859cf 100644 --- a/patoolib/__init__.py +++ b/patoolib/__init__.py @@ -473,6 +473,12 @@ def check_archive_arguments (archive, command, *args): if not args: raise util.PatoolError("missing second archive filename for diff") 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: util.check_existing_filename(archive) @@ -563,7 +569,6 @@ def _diff_archives (archive1, archive2, **kwargs): return 0 diff = util.find_program("diff") if not diff: - # XXX more helpful error message msg = "The diff(1) program is required for showing archive differences, please install it." raise util.PatoolError(msg) tmpdir1 = util.tmpdir() @@ -579,6 +584,32 @@ def _diff_archives (archive1, archive2, **kwargs): 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): """Repackage an archive to a different format.""" format1, compression1 = get_archive_format(archive1) @@ -619,6 +650,8 @@ def handle_archive (archive, command, *args, **kwargs): try: if command == "diff": res = _diff_archives(archive, args[0], **kwargs) + elif command == "search": + res = _search_archives(archive, *args, **kwargs) elif command == "repack": res = _repack_archive(archive, args[0], **kwargs) else: @@ -663,6 +696,11 @@ def diff (archive1, archive2, verbose=False): 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): """Repack archive to different file and/or format.""" return handle_archive(archive1, 'repack', archive2, verbose=verbose) diff --git a/tests/test_search.py b/tests/test_search.py new file mode 100644 index 0000000..586a4cf --- /dev/null +++ b/tests/test_search.py @@ -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 . +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)