2000-10-11 14:03:08 +08:00
|
|
|
#############################################################################
|
|
|
|
# File : SpecCheck.py
|
|
|
|
# Package : rpmlint
|
|
|
|
# Author : Frederic Lepied
|
|
|
|
# Created on : Thu Oct 7 17:06:14 1999
|
|
|
|
# Version : $Id$
|
|
|
|
# Purpose : check the spec file of a source rpm.
|
|
|
|
#############################################################################
|
|
|
|
|
|
|
|
from Filter import *
|
|
|
|
import AbstractCheck
|
|
|
|
import re
|
|
|
|
import sys
|
2000-10-11 16:41:39 +08:00
|
|
|
import rpm
|
2002-06-01 21:17:28 +08:00
|
|
|
import string
|
2003-05-08 16:03:35 +08:00
|
|
|
import Config
|
|
|
|
|
|
|
|
# Don't check for hardcoded library paths in biarch packages
|
|
|
|
DEFAULT_BIARCH_PACKAGES='^(gcc|glibc)'
|
|
|
|
|
|
|
|
# Don't check for hardcoded library paths in packages which can have
|
|
|
|
# their noarch files in /usr/lib/<package>/*, or packages that can't
|
|
|
|
# be installed on biarch systems
|
|
|
|
DEFAULT_HARDCODED_LIB_PATH_EXCEPTIONS='/lib/(modules|cpp|perl5|rpm)($|[\s/,])'
|
2000-10-11 14:03:08 +08:00
|
|
|
|
|
|
|
spec_regex=re.compile(".spec$")
|
|
|
|
patch_regex=re.compile("^\s*Patch(.*?)\s*:\s*([^\s]+)")
|
|
|
|
applied_patch_regex=re.compile("^\s*%patch([^\s]*)\s")
|
2002-12-06 15:11:41 +08:00
|
|
|
source_dir_regex=re.compile("^[^#]*(\$RPM_SOURCE_DIR|%{?_sourcedir}?)")
|
2001-10-25 00:30:40 +08:00
|
|
|
obsolete_tags_regex=re.compile("^(Copyright|Serial)\s*:\s*([^\s]+)")
|
2001-11-14 13:11:24 +08:00
|
|
|
buildroot_regex=re.compile('Buildroot\s*:\s*([^\s]+)', re.IGNORECASE)
|
|
|
|
tmp_regex=re.compile('^/')
|
2002-01-26 05:55:59 +08:00
|
|
|
clean_regex=re.compile('^%clean')
|
2002-06-01 21:17:28 +08:00
|
|
|
changelog_regex=re.compile('^%changelog')
|
2002-06-01 22:18:31 +08:00
|
|
|
configure_start_regex=re.compile('\./configure')
|
|
|
|
configure_libdir_spec_regex=re.compile('\./configure[^#]*--libdir=([^\s]+)[^#]*')
|
2003-01-17 06:28:57 +08:00
|
|
|
lib_package_regex=re.compile('^%package.*lib')
|
|
|
|
mklibname_regex=re.compile('%mklibname')
|
2003-05-08 16:41:05 +08:00
|
|
|
ifarch_regex=re.compile('%ifarch')
|
|
|
|
if_regex=re.compile('%if\s+')
|
|
|
|
endif_regex=re.compile('%endif')
|
2003-05-08 16:03:35 +08:00
|
|
|
biarch_package_regex=re.compile(DEFAULT_BIARCH_PACKAGES)
|
|
|
|
hardcoded_lib_path_exceptions_regex=re.compile(Config.getOption('HardcodedLibPathExceptions', DEFAULT_HARDCODED_LIB_PATH_EXCEPTIONS))
|
|
|
|
|
2002-06-01 21:17:28 +08:00
|
|
|
# Only check for /lib, /usr/lib, /usr/X11R6/lib
|
|
|
|
# TODO: better handling of X libraries and modules.
|
2002-06-01 22:18:31 +08:00
|
|
|
hardcoded_library_paths='(/lib|/usr/lib|/usr/X11R6/lib/(?!([^/]+/)+)[^/]*\\.([oa]|la|so[0-9.]*))'
|
2003-05-08 16:03:35 +08:00
|
|
|
hardcoded_library_path_regex=re.compile('^[^#]*((^|\s+|\.\./\.\.|\${?RPM_BUILD_ROOT}?|%{?buildroot}?|%{?_prefix}?)' + hardcoded_library_paths + '(?=[\s;/])([^\s,;]*))')
|
2000-10-11 14:03:08 +08:00
|
|
|
|
|
|
|
def file2string(file):
|
|
|
|
fd=open(file, "r")
|
|
|
|
content=fd.readlines()
|
|
|
|
fd.close()
|
|
|
|
return content
|
|
|
|
|
|
|
|
class SpecCheck(AbstractCheck.AbstractCheck):
|
|
|
|
|
|
|
|
def __init__(self):
|
2000-10-11 14:12:27 +08:00
|
|
|
AbstractCheck.AbstractCheck.__init__(self, "SpecCheck")
|
2000-10-11 14:03:08 +08:00
|
|
|
|
2001-11-15 00:34:02 +08:00
|
|
|
def check(self, pkg):
|
2000-10-11 14:03:08 +08:00
|
|
|
if not pkg.isSource():
|
|
|
|
return
|
|
|
|
|
|
|
|
# lookup spec file
|
|
|
|
files=pkg.files()
|
|
|
|
spec_file=None
|
|
|
|
for f in files.keys():
|
|
|
|
if spec_regex.search(f):
|
|
|
|
spec_file=pkg.dirName() + "/" + f
|
|
|
|
break
|
|
|
|
if not spec_file:
|
|
|
|
printError(pkg, "no-spec-file")
|
|
|
|
else:
|
2000-10-11 16:41:39 +08:00
|
|
|
if f != pkg[rpm.RPMTAG_NAME] + ".spec":
|
|
|
|
printError(pkg, "invalid-spec-name", f)
|
|
|
|
|
2000-10-11 14:03:08 +08:00
|
|
|
# check content of spec file
|
|
|
|
spec=file2string(spec_file)
|
|
|
|
patches={}
|
|
|
|
applied_patches=[]
|
2003-05-08 16:41:05 +08:00
|
|
|
applied_patches_ifarch=[]
|
2000-10-11 14:12:27 +08:00
|
|
|
source_dir=None
|
2001-11-14 13:11:24 +08:00
|
|
|
buildroot=0
|
2002-01-26 05:55:59 +08:00
|
|
|
clean=0
|
2002-06-01 21:17:28 +08:00
|
|
|
changelog=0
|
2002-06-01 22:18:31 +08:00
|
|
|
configure=0
|
|
|
|
configure_cmdline=""
|
2003-01-17 06:28:57 +08:00
|
|
|
mklibname=0
|
|
|
|
lib=0
|
2003-05-08 16:41:05 +08:00
|
|
|
if_depth=0
|
|
|
|
ifarch_depth=-1
|
2001-11-14 13:11:24 +08:00
|
|
|
|
2000-10-11 14:03:08 +08:00
|
|
|
# gather info from spec lines
|
|
|
|
for line in spec:
|
2002-12-06 15:11:41 +08:00
|
|
|
|
|
|
|
# I assume that the changelog section is at the end of the spec
|
|
|
|
# to avoid wrong warnings
|
|
|
|
res=changelog_regex.search(line)
|
|
|
|
if res:
|
|
|
|
changelog=1
|
|
|
|
break
|
2003-05-08 16:41:05 +08:00
|
|
|
|
|
|
|
res=ifarch_regex.search(line)
|
|
|
|
if res:
|
|
|
|
if_depth = if_depth + 1
|
|
|
|
ifarch_depth = if_depth
|
|
|
|
res=if_regex.search(line)
|
|
|
|
if res:
|
|
|
|
if_depth = if_depth + 1
|
|
|
|
res=endif_regex.search(line)
|
|
|
|
if res:
|
|
|
|
if ifarch_depth == if_depth:
|
|
|
|
ifarch_depth = -1
|
|
|
|
if_depth = if_depth - 1
|
2002-12-06 15:11:41 +08:00
|
|
|
|
2000-10-11 14:03:08 +08:00
|
|
|
res=patch_regex.search(line)
|
|
|
|
if res:
|
|
|
|
patches[res.group(1)]=res.group(2)
|
|
|
|
else:
|
|
|
|
res=applied_patch_regex.search(line)
|
|
|
|
if res:
|
|
|
|
applied_patches.append(res.group(1))
|
2003-05-08 16:41:05 +08:00
|
|
|
if ifarch_depth > 0:
|
|
|
|
applied_patches_ifarch.append(res.group(1))
|
2000-10-11 14:12:27 +08:00
|
|
|
elif not source_dir:
|
|
|
|
res=source_dir_regex.search(line)
|
|
|
|
if res:
|
|
|
|
source_dir=1
|
|
|
|
printError(pkg, "use-of-RPM_SOURCE_DIR")
|
2002-12-06 15:11:41 +08:00
|
|
|
|
2001-06-20 19:33:02 +08:00
|
|
|
res=obsolete_tags_regex.search(line)
|
|
|
|
if res:
|
|
|
|
printWarning(pkg, "obsolete-tag", res.group(1))
|
2002-06-01 21:17:28 +08:00
|
|
|
|
2002-06-01 22:18:31 +08:00
|
|
|
if configure:
|
|
|
|
if configure_cmdline[-1] == "\\":
|
|
|
|
configure_cmdline=configure_cmdline[:-1] + string.strip(line)
|
|
|
|
else:
|
|
|
|
configure=0
|
|
|
|
res=configure_libdir_spec_regex.search(configure_cmdline)
|
|
|
|
if not res:
|
|
|
|
printError(pkg, "configure-without-libdir-spec")
|
|
|
|
else:
|
|
|
|
res=re.match(hardcoded_library_paths, res.group(1))
|
|
|
|
if res:
|
|
|
|
printError(pkg, "hardcoded-library-path", res.group(1), "in configure options")
|
|
|
|
|
|
|
|
res=configure_start_regex.search(line)
|
|
|
|
if not changelog and res:
|
|
|
|
configure=1
|
|
|
|
configure_cmdline=string.strip(line)
|
|
|
|
|
|
|
|
res=hardcoded_library_path_regex.search(line)
|
2003-05-08 16:03:35 +08:00
|
|
|
if not changelog and res and not (biarch_package_regex.match(pkg[rpm.RPMTAG_NAME]) or hardcoded_lib_path_exceptions_regex.search(line)):
|
2002-06-01 22:18:31 +08:00
|
|
|
printError(pkg, "hardcoded-library-path", "in", string.lstrip(res.group(1)))
|
2001-11-14 13:11:24 +08:00
|
|
|
|
|
|
|
res=buildroot_regex.search(line)
|
|
|
|
if res:
|
|
|
|
buildroot=1
|
|
|
|
if tmp_regex.search(res.group(1)):
|
|
|
|
printWarning(pkg, 'hardcoded-path-in-buildroot-tag', res.group(1))
|
2002-01-26 05:55:59 +08:00
|
|
|
|
|
|
|
if not clean and clean_regex.search(line):
|
|
|
|
clean=1
|
2003-01-17 06:28:57 +08:00
|
|
|
|
|
|
|
if mklibname_regex.search(line):
|
|
|
|
mklibname=1
|
|
|
|
|
|
|
|
if lib_package_regex.search(line):
|
|
|
|
lib=1
|
2002-01-26 05:55:59 +08:00
|
|
|
|
2001-11-14 13:11:24 +08:00
|
|
|
if not buildroot:
|
|
|
|
printError(pkg, 'no-buildroot-tag')
|
2002-01-26 05:55:59 +08:00
|
|
|
|
|
|
|
if not clean:
|
|
|
|
printError(pkg, 'no-%clean-section')
|
2003-01-17 06:28:57 +08:00
|
|
|
|
|
|
|
if lib and not mklibname:
|
|
|
|
printError(pkg, 'lib-package-without-%mklibname')
|
2002-01-26 05:55:59 +08:00
|
|
|
|
2000-10-11 14:03:08 +08:00
|
|
|
# process gathered info
|
|
|
|
for p in patches.keys():
|
2003-05-08 16:41:05 +08:00
|
|
|
if p in applied_patches_ifarch:
|
|
|
|
printError(pkg, "%ifarch-applied-patch", "Patch" + p + ":", patches[p])
|
2000-10-11 14:03:08 +08:00
|
|
|
if p not in applied_patches:
|
|
|
|
if p == "" and "0" in applied_patches:
|
|
|
|
continue
|
|
|
|
if p == "0" and "" in applied_patches:
|
|
|
|
continue
|
|
|
|
printWarning(pkg, "patch-not-applied", "Patch" + p + ":", patches[p])
|
|
|
|
|
|
|
|
# Create an object to enable the auto registration of the test
|
|
|
|
check=SpecCheck()
|
|
|
|
|
2001-06-20 19:33:02 +08:00
|
|
|
# Add information about checks
|
|
|
|
if Config.info:
|
|
|
|
addDetails(
|
2001-07-04 05:13:22 +08:00
|
|
|
'no-spec-file',
|
2001-07-16 01:01:17 +08:00
|
|
|
'''No spec file was specified in your RPM building. Please specify a valid
|
|
|
|
SPEC file to build a valid RPM package.''',
|
2001-07-04 05:13:22 +08:00
|
|
|
|
|
|
|
'invalid-spec-name',
|
2001-07-16 01:01:17 +08:00
|
|
|
'''Your spec file must finish with '.spec'. If it's not the case, rename your
|
|
|
|
file and rebuild your package.''',
|
2001-07-04 05:13:22 +08:00
|
|
|
|
|
|
|
'use-of-RPM_SOURCE_DIR',
|
2001-07-16 01:01:17 +08:00
|
|
|
'''You use RPM_SOURCE_DIR in your spec file. If you have to use a directory
|
|
|
|
for building, use RPM_BUILD_ROOT instead.''',
|
2001-07-04 05:13:22 +08:00
|
|
|
|
|
|
|
'patch-not-applied',
|
2001-07-16 01:01:17 +08:00
|
|
|
'''A patch is included in your package but was not applied. Refer to the patches
|
|
|
|
documentation to see what's wrong.''',
|
2001-07-04 05:13:22 +08:00
|
|
|
|
2001-06-20 19:33:02 +08:00
|
|
|
'obsolete-tag',
|
|
|
|
'''The following tags are obsolete: Copyright and Serial. They must
|
|
|
|
be replaced by License and Epoch respectively.''',
|
2001-07-16 01:01:17 +08:00
|
|
|
|
2001-11-14 13:11:24 +08:00
|
|
|
'no-buildroot-tag',
|
|
|
|
'''The BuildRoot tag isn't used in your spec. It must be used to
|
|
|
|
allow build as non root.''',
|
|
|
|
|
|
|
|
'hardcoded-path-in-buildroot-tag',
|
|
|
|
'''A path is hardcoded in your Buildroot tag. It should be replaced
|
|
|
|
by something like %{_tmppath}/%name-root.''',
|
|
|
|
|
2002-06-01 22:18:31 +08:00
|
|
|
'hardcoded-library-path',
|
2002-06-01 21:17:28 +08:00
|
|
|
'''A library path is hardcoded to one of the following paths: /lib,
|
|
|
|
/usr/lib. It should be replaced by something like /%{_lib} or %{_libdir}.''',
|
|
|
|
|
2002-06-01 22:18:31 +08:00
|
|
|
'configure-without-libdir-spec',
|
|
|
|
'''A configure script is run without specifying the libdir. Configure
|
|
|
|
options must be augmented with something like libdir=%{_libdir}.''',
|
|
|
|
|
2002-01-26 05:55:59 +08:00
|
|
|
'no-%clean-section',
|
|
|
|
'''The spec file doesn't contain a %clean section to remove the files installed
|
|
|
|
by the %install section.''',
|
|
|
|
|
2003-01-17 06:28:57 +08:00
|
|
|
'lib-package-without-%mklibname',
|
|
|
|
'''The package name must be built using %mklibname to allow lib64 and lib32
|
|
|
|
coexistence.''',
|
|
|
|
|
2003-05-08 16:41:05 +08:00
|
|
|
'%ifarch-applied-patch',
|
|
|
|
'''A patch is applied inside an %ifarch block. Patches must be applied
|
|
|
|
on all architectures and may contain necessary configure and/or code
|
|
|
|
patch to be effective only on a given arch.'''
|
|
|
|
|
2001-06-20 19:33:02 +08:00
|
|
|
)
|
|
|
|
|
2000-10-11 14:03:08 +08:00
|
|
|
# SpecCheck.py ends here
|