--- SpecCheck.py +++ SpecCheck.py @@ -45,7 +45,8 @@ biarch_package_regex = re.compile(DEFAULT_BIARCH_PACKAGES) hardcoded_lib_path_exceptions_regex = re.compile(Config.getOption('HardcodedLibPathExceptions', DEFAULT_HARDCODED_LIB_PATH_EXCEPTIONS)) prereq_regex = re.compile('^PreReq(\(.*\))?:\s*(.+?)\s*$', re.IGNORECASE) -buildprereq_regex = re.compile('^BuildPreReq:\s*(.+?)\s*$', re.IGNORECASE) +buildprereq_regex = re.compile('^BuildPreReq\s*:\s*(.+)\s*$', re.IGNORECASE) +buildrequires_regex = re.compile('^\s*BuildRequires\s*:\s*(.+)\s*$', re.IGNORECASE) use_utf8 = Config.getOption('UseUTF8', Config.USEUTF8_DEFAULT) macro_regex = re.compile('(%+)[{(]?(\w+)') libdir_regex = re.compile('%{?_lib(?:dir)?\}?\\b') @@ -126,6 +127,25 @@ res.append(tok) return res +def find_reverse_requires(): + reverse_requires = dict() + try: + f = file("/.builtinfo/rpmdeps", "r") + except: + return reverse_requires + + for line in f: + if line.startswith('R:'): + package = "-".join(line.split(':')[1].split('-')[:-3]) + deps = deptokens(line.split(':')[2]) + for dep in deps: + name = dep.split(' ')[0] + if name.startswith('/') or name.find('(') != -1 or name == dep: + continue + reverse_requires.setdefault(name, set()).add(package) + + return reverse_requires + def contains_buildroot(line): '''Check if the given line contains use of rpm buildroot.''' res = rpm_buildroot_regex.search(line) @@ -188,6 +208,8 @@ indent_tabs = 0 files_has_defattr = 0 section = {} + buildrequires = set() + for sec in ['description', 'prep', 'build', 'install', 'clean', 'files', 'changelog', 'package', 'check']: section[sec] = { @@ -348,6 +370,14 @@ if res: printError(pkg, 'buildprereq-use', res.group(1)) + res = buildrequires_regex.search(line) + if not if_depth and res: + for r in deptokens(res.group(1)): + name = r.split(' ')[0] + if name in buildrequires: + printWarning(pkg, 'duplicate-buildrequires', name) + buildrequires.add(name) + if scriptlet_requires_regex.search(line): printError(pkg, 'broken-syntax-in-scriptlet-requires', string.strip(line)) @@ -420,6 +450,24 @@ '(spaces: line %d, tab: line %d)' % (indent_spaces, indent_tabs)) + reverse_requires = find_reverse_requires() + for r in buildrequires: + if r in reverse_requires: + for rev in reverse_requires[r]: + if rev in buildrequires: + printWarning(pkg, 'unnecessary-buildrequires', r, 'already included by', rev) + + if not r.endswith("-devel"): + develr = [ r + "-devel" ] + # libfoo-4_2 -> libfoo-devel + dr2 = re.sub(r'-?[0-9_]+$', '', r) + "-devel" + if dr2 != develr[0]: + develr.append(dr2); + for dr in develr: + if r in reverse_requires and dr in reverse_requires[r] \ + and not dr in buildrequires: + printWarning(pkg, "non-devel-buildrequires", r, "- did you mean", dr, "?") + # process gathered info for p in patches.keys(): if p in applied_patches_ifarch: @@ -557,6 +605,17 @@ odd entries eg. in source rpms, which is rarely wanted. Avoid use of macros in %changelog altogether, or use two '%'s to escape them, like '%%foo'.''', +'unnecessary-buildrequires', +''' The specfile contains a buildrequires entry that seems to be already +requires by one of the other buildrequires. Please consider reducing your +buildrequires definitions in case this is a real implicit dependency.''', + +'non-devel-buildrequires', +'''The specfile contains a buildrequires entry that has a -devel package. +Please carefully check if you want to buildrequire the -devel subpackage or if +this is an unnecessary dependency that is already required by one of the other +buildrequires.''', + 'depscript-without-disabling-depgen', '''In some common rpm configurations/versions, defining __find_provides and/or __find_requires has no effect if rpm's internal dependency generator has not