diff --git a/DocFilesCheck.py b/DocFilesCheck.py new file mode 100644 index 0000000..50b32fb --- /dev/null +++ b/DocFilesCheck.py @@ -0,0 +1,108 @@ +# Copyright (C) 2005 Enrico Scholz +# +# 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; version 2 of the License. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from Filter import * + +import sys +import rpm + +import AbstractCheck + +# remove version from deps like ['foo', '>', '3'] +def _stripVersionedDeps(deps): + deps = deps[:] + j = len(deps) + while j>=3: + j = j-1 + if deps[j-1] in ('<', '<=', '=', '>=', '>'): + del deps[j-1:j+1] + + return deps + +class DocFilesCheck(AbstractCheck.AbstractCheck): + def __init__(self): + AbstractCheck.AbstractCheck.__init__(self, 'DocFilesCheck') + + def __checkRequirements(this, pkg): + file_reqs = pkg.header[rpm.RPMTAG_FILEREQUIRE] + files = pkg.header[rpm.RPMTAG_FILENAMES] + doc_files = pkg.docFiles() + + assert(len(file_reqs) == len(files)) + + reqs = {} + for i in xrange(0,len(files)): + tmp = file_reqs[i].split() + tmp = _stripVersionedDeps(tmp) + reqs[files[i]] = tmp + + core_reqs = {} # dependencies of non-doc files + doc_reqs = {} # dependencies of doc files + + for dep in pkg.header.dsFromHeader(): + # skip deps which were found by find-requires + if (dep.Flags() & (rpm.RPMSENSE_FIND_REQUIRES))!=0: continue + core_reqs[dep.N()] = [] + + # register things which are provided by the package + for i in pkg.header[rpm.RPMTAG_PROVIDES] + files: + core_reqs[i] = [] + + for i in files: + if not reqs[i]: continue # skip empty dependencies + elif i in doc_files: target = doc_reqs + else: target = core_reqs + + for r in reqs[i]: + if not target.has_key(r): + target[r] = [] + + target[r].append(i) + + + # go through the calculated requirements of the %doc files + for (dep,req_files) in doc_reqs.items(): + if dep not in core_reqs: + for f in req_files: + printWarning(pkg, "doc-file-dependency", f, dep) + + def check(self, pkg): + if pkg.isSource(): + return + + self.__checkRequirements(pkg) + + + +check = DocFilesCheck() + +if Config.info: + addDetails( +'doc-file-dependency', +'''An included file marked as %doc creates a possible additional dependency in +the package. Usually, this is not wanted and may be caused by eg. example +scripts with executable bits set included in the package's documentation.''', +) + +def test(): + for (arg,exp) in ((['a'],['a']), + ([], []), + (['a','b'], ['a', 'b']), + (['a','b', 'c', 'd'], ['a', 'b', 'c', 'd']), + (['a','>', '0'], ['a']), + (['a','>', '0', 'b'], ['a', 'b']), + (['a','>', '0', 'b', '>', '0'], ['a', 'b']), + ): + assert(_stripVersionedDeps(arg) == exp) diff --git a/rpmlint-0.71-docfilescheck.patch b/rpmlint-0.71-docfilescheck.patch new file mode 100644 index 0000000..c7e469c --- /dev/null +++ b/rpmlint-0.71-docfilescheck.patch @@ -0,0 +1,10 @@ +--- Config.py 17 Aug 2005 05:11:24 -0000 1.125 ++++ Config.py 20 Nov 2005 10:39:57 -0000 +@@ -16,6 +16,7 @@ + "BinariesCheck", + "ConfigCheck", + "FilesCheck", ++ "DocFilesCheck", + "FHSCheck", + "SignatureCheck", + "I18NCheck", diff --git a/rpmlint-0.71-errmsg.patch b/rpmlint-0.71-errmsg.patch new file mode 100644 index 0000000..29efa77 --- /dev/null +++ b/rpmlint-0.71-errmsg.patch @@ -0,0 +1,13 @@ +--- rpmlint.py 15 Apr 2005 20:01:46 -0000 1.62 ++++ rpmlint.py 26 Aug 2005 16:17:20 -0000 +@@ -71,6 +71,10 @@ + except KeyboardInterrupt: + sys.stderr.write('Interrupted, exiting while reading ' + f + '\n') + sys.exit(2) ++ except rpm.error, e: ++ sys.stderr.write('Error while reading %s: %s\n' % (f, e)) ++ pkg=None ++ continue + except: + sys.stderr.write('Error while reading ' + f + '\n') + pkg=None diff --git a/rpmlint-0.71-locale.patch b/rpmlint-0.71-locale.patch new file mode 100644 index 0000000..ffe5421 --- /dev/null +++ b/rpmlint-0.71-locale.patch @@ -0,0 +1,10 @@ +--- rpmlint 6 Oct 1999 13:03:45 -0000 1.2 ++++ rpmlint 20 Nov 2005 12:48:00 -0000 +@@ -13,6 +13,6 @@ + + PYTHONPATH=${PYTHONPATH}:/usr/share/rpmlint + +-exec python -u -O /usr/share/rpmlint/rpmlint.py $* ++LC_ALL=C exec python -u -O /usr/share/rpmlint/rpmlint.py $* + + # rpmlint ends here diff --git a/rpmlint-0.71-objdump.patch b/rpmlint-0.71-objdump.patch new file mode 100644 index 0000000..a5218e2 --- /dev/null +++ b/rpmlint-0.71-objdump.patch @@ -0,0 +1,84 @@ +--- BinariesCheck.py 17 Jun 2005 09:10:36 -0000 1.32 ++++ BinariesCheck.py 20 Nov 2005 17:42:33 -0000 +@@ -32,7 +32,8 @@ + pic_regex=re.compile('^\s+\d+\s+\.rela?\.(data|text)') + non_pic_regex=re.compile('TEXTREL', re.MULTILINE) + +- def __init__(self, path, file): ++ def __init__(self, pkg, path, file): ++ self.error=0 + self.needed=[] + self.rpath=[] + self.comment=0 +@@ -40,9 +41,9 @@ + self.soname=0 + self.non_pic=1 + +- res=commands.getoutput('objdump --headers --private-headers -T ' + path) +- if res: +- for l in string.split(res, '\n'): ++ res=commands.getstatusoutput('objdump --headers --private-headers -T ' + path) ++ if not res[0]: ++ for l in string.split(res[1], '\n'): + needed=BinaryInfo.needed_regex.search(l) + if needed: + self.needed.append(needed.group(1)) +@@ -57,16 +58,14 @@ + self.dynsyms=1 + elif BinaryInfo.pic_regex.search(l): + self.non_pic=0 +- else: +- r=BinaryInfo.unrecognized_regex.search(l) +- if r: +- sys.stderr.write('file format not recognized for %s in %s\n' % (r.group(1), file)) +- #sys.exit(1) + r=BinaryInfo.soname_regex.search(l) + if r: + self.soname=r.group(1) + if self.non_pic: +- self.non_pic=BinaryInfo.non_pic_regex.search(res) ++ self.non_pic=BinaryInfo.non_pic_regex.search(res[1]) ++ else: ++ self.error=1 ++ printWarning(pkg, 'objdump-failed', res[1]) + + path_regex=re.compile('(.*/)([^/]+)') + numeric_dir_regex=re.compile('/usr(?:/share)/man/man./(.*)\.[0-9](?:\.gz|\.bz2)') +@@ -156,12 +155,14 @@ + printWarning(pkg, 'unstripped-binary-or-object', i[0]) + + # inspect binary file +- bin_info=BinaryInfo(pkg.dirName()+i[0], i[0]) ++ bin_info=BinaryInfo(pkg, pkg.dirName()+i[0], i[0]) + + # so name in library + if so_regex.search(i[0]): + has_lib.append(i[0]) +- if not bin_info.soname: ++ if bin_info.error: ++ pass ++ elif not bin_info.soname: + printWarning(pkg, 'no-soname', i[0]) + else: + if not validso_regex.search(bin_info.soname): +@@ -201,7 +202,9 @@ + if is_exec and bin_regex.search(i[0]): + exec_files.append(i[0]) + +- if not bin_info.needed and \ ++ if bin_info.error: ++ pass ++ elif not bin_info.needed and \ + not (bin_info.soname and \ + ldso_soname_regex.search(bin_info.soname)): + if shared_object_regex.search(i[1]): +@@ -333,6 +336,9 @@ + 'only-non-binary-in-usr-lib', + '''There are only non binary files in /usr/lib so they should be in /usr/share.''', + ++'objdump-failed', ++'''Running objdump on some files failed, all checks could not be done.''', ++ + ) + + # BinariesCheck.py ends here diff --git a/rpmlint-0.71-paths.patch b/rpmlint-0.71-paths.patch new file mode 100644 index 0000000..cdbaf0f --- /dev/null +++ b/rpmlint-0.71-paths.patch @@ -0,0 +1,17 @@ +--- FilesCheck.py 10 Aug 2005 01:46:30 -0000 1.88 ++++ FilesCheck.py 21 Aug 2005 07:42:30 -0000 +@@ -151,3 +151,3 @@ + points_regex=re.compile('^../(.*)') +-doc_regex=re.compile('^/usr/(doc|man|info)|^/usr/share/(doc|man|info)') ++doc_regex=re.compile('^/usr(/share)?/(doc|man|info)/') + bin_regex=re.compile('^(/usr)?/s?bin/') +@@ -160,3 +160,3 @@ + depmod_regex=re.compile('^[^#]*depmod', re.MULTILINE) +-info_regex=re.compile('^/usr/share/info') ++info_regex=re.compile('^/usr/share/info/') + install_info_regex=re.compile('^[^#]*install-info', re.MULTILINE) +@@ -165,3 +165,3 @@ + htaccess_regex=re.compile('\.htaccess$') +-games_path_regex=re.compile('/usr/(lib/)?/games') ++games_path_regex=re.compile('/usr(/lib(64)?)?/games/') + games_group_regex=re.compile(Config.getOption('RpmGamesGroups', DEFAULT_GAMES_GROUPS)) diff --git a/rpmlint-0.71-scriptinfo.patch b/rpmlint-0.71-scriptinfo.patch new file mode 100644 index 0000000..083a394 --- /dev/null +++ b/rpmlint-0.71-scriptinfo.patch @@ -0,0 +1,23 @@ +--- FilesCheck.py 10 Sep 2005 23:00:31 -0000 1.89 ++++ FilesCheck.py 20 Nov 2005 19:50:57 -0000 +@@ -833,10 +834,18 @@ + '''This script uses an incorrect interpreter.''', + + 'non-executable-script', +-'''This script is not executable.''', ++'''This file is a non-executable text file which contains a shebang. Often ++this is a sign of a spurious shebang in files that are not meant to be ++executed, but can also be a case of missing executable bits for a script. ++To fix this warning, find out which case of the above it is, and either remove ++the unneeded shebang or add the executable bits.''', + + 'script-without-shellbang', +-'''This script does not begins with a shellbang. It will prevent its execution.''', ++'''This file is an executable text file, but does not contain a shebang, thus ++it cannot be properly executed. Often this is a sign of spurious executable ++bits for a non-script file, but can also be a case of a missing shebang. ++To fix this warning, find out which case of the above it is, and either remove ++the executable bits or add the shebang.''', + + 'wrong-script-end-of-line-encoding', + '''This script has wrong end-of-line encoding, usually caused by creation on a diff --git a/rpmlint-0.71-symlinks.patch b/rpmlint-0.71-symlinks.patch new file mode 100644 index 0000000..8a085dd --- /dev/null +++ b/rpmlint-0.71-symlinks.patch @@ -0,0 +1,28 @@ +--- FilesCheck.py 10 Sep 2005 23:00:31 -0000 1.89 ++++ FilesCheck.py 20 Nov 2005 09:00:33 -0000 +@@ -477,7 +477,7 @@ + printWarning(pkg, 'devel-file-in-non-devel-package', f) + # absolute link + if r: +- if (not is_so) and link not in files.keys(): ++ if (not is_so) and link not in files.keys() and link not in req_names: + is_exception=0 + for e in dangling_exceptions: + if e[0].search(link): +@@ -502,14 +502,14 @@ + file = os.path.normpath(file) + pkgfile = '%s/%s' % (os.path.dirname(f), link) + pkgfile = os.path.normpath(pkgfile) +- if not (files.has_key(pkgfile) or os.path.exists(file)): ++ if not (files.has_key(pkgfile) or os.path.exists(file) or pkgfile in req_names): + is_exception=0 + for e in dangling_exceptions: + if e[0].search(link): + is_exception=e[1] + break + if is_exception: +- if not is_exception in map(lambda x: x[0], pkg.requires() + pkg.prereq()): ++ if not is_exception in req_names: + printWarning(pkg, 'no-dependency-on', is_exception) + else: + printWarning(pkg, 'dangling-relative-symlink', f, link) diff --git a/rpmlint-fedora-config b/rpmlint-fedora-config index c3f0903..c4dcf88 100644 --- a/rpmlint-fedora-config +++ b/rpmlint-fedora-config @@ -92,6 +92,7 @@ addFilter("E: .* invalid-build-requires .*") addFilter("W: .* ghost-files-without-postin") addFilter("W: .* postin-without-ghost-file-creation .*") addFilter("W: .* no-major-in-name .*") +addFilter("W: .* no-provides .*") addFilter("E: .* executable-in-library-package .*") addFilter("E: .* non-versioned-file-in-library-package .*") addFilter("E: .* requires-on-release .*") diff --git a/rpmlint.spec b/rpmlint.spec index c134570..063e706 100644 --- a/rpmlint.spec +++ b/rpmlint.spec @@ -1,6 +1,6 @@ Name: rpmlint Version: 0.71 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Tool for checking common errors in RPM packages Group: Development/Tools @@ -8,12 +8,20 @@ License: GPL URL: http://people.mandriva.com/~flepied/projects/rpmlint/ Source0: http://people.mandriva.com/~flepied/projects/rpmlint/dist/%{name}-%{version}.tar.bz2 Source1: %{name}-fedora-config +Source2: DocFilesCheck.py Patch0: %{name}-svcdefault.patch Patch1: %{name}-prereq.patch Patch2: %{name}-disttag.patch Patch3: %{name}-initvars.patch Patch4: %{name}-execs.patch Patch5: %{name}-perl-bs.patch +Patch6: %{name}-0.71-paths.patch +Patch7: %{name}-0.71-errmsg.patch +Patch8: %{name}-0.71-symlinks.patch +Patch9: %{name}-0.71-docfilescheck.patch +Patch10: %{name}-0.71-objdump.patch +Patch11: %{name}-0.71-locale.patch +Patch12: %{name}-0.71-scriptinfo.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildArch: noarch @@ -31,12 +39,20 @@ and source packages can be checked. %prep %setup -q +install -pm 644 %{SOURCE2} . %patch0 %patch1 %patch2 %patch3 %patch4 %patch5 +%patch6 +%patch7 +%patch8 +%patch9 +%patch10 +%patch11 +%patch12 sed -i -e 's|/etc/httpd/webapps\.d|%{_sysconfdir}/httpd/conf.d|' \ FilesCheck.py I18NCheck.py for f in AUTHORS ChangeLog ; do @@ -51,6 +67,7 @@ make %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT +rm $RPM_BUILD_ROOT%{_datadir}/rpmlint/check-install.py* install -Dpm 644 rpmlint.bash-completion \ $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/rpmlint install -pm 644 %{SOURCE1} $RPM_BUILD_ROOT%{_sysconfdir}/rpmlint/config @@ -79,15 +96,32 @@ rm -rf $RPM_BUILD_ROOT %files -f %{name}-%{version}-files.list %defattr(-,root,root,0755) %doc AUTHORS COPYING ChangeLog README -%{_bindir}/rpm* -%dir %{_datadir}/rpmlint/ -%exclude %{_datadir}/rpmlint/check-install.py* %dir %{_sysconfdir}/rpmlint/ %config(noreplace) %{_sysconfdir}/rpmlint/config +%{_bindir}/rpmdiff +%{_bindir}/rpmlint +%dir %{_datadir}/rpmlint/ %{_sysconfdir}/bash_completion.d/ %changelog +* Sun Nov 20 2005 Ville Skyttä - 0.71-2 +- Take file based dependencies into account in dangling symlink checks + (completes the fix for #165839). +- Skip some checks for binaries not understood by objdump (#165173). +- Improve long descriptions of some script warnings. +- Fix command output parsing in non-English locales. +- Import Enrico's latest DocFilesCheck (with some local tweaks). +- Use rm instead of %%exclude. + +* Wed Nov 16 2005 Ville Skyttä +- Add DocFilesCheck from Enrico Scholz. + +* Sat Sep 3 2005 Ville Skyttä +- Improve accuracy of doc, info and games path regexps. +- Improve error message when invoked on non-rpm files. +- Filter more Mandriva specific warnings. + * Sat Aug 13 2005 Ville Skyttä - Add dangling symlink exceptions tuned for Fedora to default config (partially fixes #165839).