1 # -*- coding: utf-8 -*-
2 #############################################################################
5 # Author : Frederic Lepied
6 # Created on : Thu Oct 7 17:06:14 1999
7 # Version : $Id: SpecCheck.py 1892 2011-11-23 20:21:05Z scop $
8 # Purpose : check the spec file of a source rpm.
9 #############################################################################
13 from urlparse import urlparse
14 except ImportError: # Python 3
15 from urllib.parse import urlparse
19 from Filter import addDetails, printError, printWarning
20 from TagsCheck import VALID_GROUPS
26 # Don't check for hardcoded library paths in biarch packages
27 DEFAULT_BIARCH_PACKAGES = '^(gcc|glibc)'
29 # Don't check for hardcoded library paths in packages which can have
30 # their noarch files in /usr/lib/<package>/*, or packages that can't
31 # be installed on biarch systems
32 DEFAULT_HARDCODED_LIB_PATH_EXCEPTIONS = '/lib/(modules|cpp|perl5|rpm|hotplug|firmware)($|[\s/,])'
33 patch_regex = re.compile("^Patch(\d*)\s*:\s*(\S+)", re.IGNORECASE)
34 applied_patch_regex = re.compile("^%patch(\d*)")
35 applied_patch_p_regex = re.compile("\s-P\s+(\d+)\\b")
36 applied_patch_pipe_regex = re.compile(r'\s%\{PATCH(\d+)\}\s*\|\s*(%\{?__)?patch\b')
37 source_dir_regex = re.compile("^[^#]*(\$RPM_SOURCE_DIR|%{?_sourcedir}?)")
38 obsolete_tags_regex = re.compile("^(Copyright|Serial)\s*:\s*(\S+)")
39 buildroot_regex = re.compile('^BuildRoot\s*:\s*(\S+)', re.IGNORECASE)
40 prefix_regex = re.compile('^Prefix\s*:\s*(\S+)', re.IGNORECASE)
41 packager_regex = re.compile('^Packager\s*:\s*(\S+)', re.IGNORECASE)
42 buildarch_regex = re.compile('^BuildArch(itectures)?\s*:\s*(.+?)\s*$', re.IGNORECASE)
43 make_check_regex = re.compile('(^|\s|%{?__)make}?\s+(check|test)')
44 rm_regex = re.compile('(^|\s)((.*/)?rm|%{?__rm}?) ')
45 rpm_buildroot_regex = re.compile('^[^#]*(?:(\\\*)\${?RPM_BUILD_ROOT}?|(%+){?buildroot}?)')
46 configure_libdir_spec_regex = re.compile('ln |\./configure[^#]*--libdir=(\S+)[^#]*')
47 lib_package_regex = re.compile('^%package.*\Wlib')
48 ifarch_regex = re.compile('^\s*%ifn?arch\s')
49 if_regex = re.compile('^\s*%if\s')
50 endif_regex = re.compile('^\s*%endif\\b')
51 biarch_package_regex = re.compile(DEFAULT_BIARCH_PACKAGES)
52 hardcoded_lib_path_exceptions_regex = re.compile(Config.getOption('HardcodedLibPathExceptions', DEFAULT_HARDCODED_LIB_PATH_EXCEPTIONS))
53 prereq_regex = re.compile('^PreReq(\(.*\))?:\s*(.+?)\s*$', re.IGNORECASE)
54 buildprereq_regex = re.compile('^BuildPreReq:\s*(.+?)\s*$', re.IGNORECASE)
55 use_utf8 = Config.getOption('UseUTF8', Config.USEUTF8_DEFAULT)
56 libdir_regex = re.compile('%{?_lib(?:dir)?\}?\\b')
57 comment_or_empty_regex = re.compile('^\s*(#|$)')
58 defattr_regex = re.compile('^\s*%defattr\\b')
59 attr_regex = re.compile('^\s*%attr\\b')
60 suse_version_regex = re.compile('%suse_version\s*[<>=]+\s*(\d+)')
61 section_regexs = dict(
62 ([x, re.compile('^%' + x + '(?:\s|$)')]
63 for x in ('build', 'changelog', 'check', 'clean', 'description', 'files',
64 'install', 'package', 'prep', 'pre', 'post', 'preun', 'postun',
65 'trigger', 'triggerin', 'triggerun', 'triggerprein',
66 'triggerpostun', 'pretrans', 'posttrans')))
67 deprecated_grep_regex = re.compile(r'\b[ef]grep\b')
69 # Only check for /lib, /usr/lib, /usr/X11R6/lib
70 # TODO: better handling of X libraries and modules.
71 hardcoded_library_paths = '(/lib|/usr/lib|/usr/X11R6/lib/(?!([^/]+/)+)[^/]*\\.([oa]|la|so[0-9.]*))'
72 hardcoded_library_path_regex = re.compile('^[^#]*((^|\s+|\.\./\.\.|\${?RPM_BUILD_ROOT}?|%{?buildroot}?|%{?_prefix}?)' + hardcoded_library_paths + '(?=[\s;/])([^\s,;]*))')
74 # Requires(pre,post) is broken in some rpm versions, see
75 # https://bugzilla.redhat.com/118780 and bugs linked to that one.
76 scriptlet_requires_regex = re.compile('^(PreReq|Requires)\([^\)]*,', re.IGNORECASE)
78 depscript_override_regex = re.compile('(^|\s)%(define|global)\s+__find_(requires|provides)\s')
79 depgen_disable_regex = re.compile('(^|\s)%(define|global)\s+_use_internal_dependency_generator\s+0')
81 # See https://bugzilla.redhat.com/488146 for details
82 indent_spaces_regex = re.compile('( \t|(^|\t)([^\t]{8})*[^\t]{4}[^\t]?([^\t][^\t.!?]|[^\t]?[.!?] ) )')
84 requires_regex = re.compile('^(?:Build)?(?:Pre)?Req(?:uires)?(?:\([^\)]+\))?:\s*(.*)', re.IGNORECASE)
85 provides_regex = re.compile('^Provides(?:\([^\)]+\))?:\s*(.*)', re.IGNORECASE)
86 obsoletes_regex = re.compile('^Obsoletes:\s*(.*)', re.IGNORECASE)
87 conflicts_regex = re.compile('^(?:Build)?Conflicts:\s*(.*)', re.IGNORECASE)
89 compop_regex = re.compile('[<>=]')
91 setup_q_regex = re.compile(' -[A-Za-z]*q')
92 setup_t_regex = re.compile(' -[A-Za-z]*T')
93 setup_ab_regex = re.compile(' -[A-Za-z]*[ab]')
95 filelist_regex = re.compile('\s+-f\s+\S+')
96 pkgname_regex = re.compile('\s+(?:-n\s+)?(\S+)')
97 tarball_regex = re.compile('\.(?:t(?:ar|[glx]z|bz2?)|zip)\\b', re.IGNORECASE)
100 def unversioned(deps):
101 '''Yield unversioned dependency names from the given list.'''
106 def contains_buildroot(line):
107 '''Check if the given line contains use of rpm buildroot.'''
108 res = rpm_buildroot_regex.search(line)
110 (not res.group(1) or len(res.group(1)) % 2 == 0) and \
111 (not res.group(2) or len(res.group(2)) % 2 != 0):
116 class SpecCheck(AbstractCheck.AbstractCheck):
119 AbstractCheck.AbstractCheck.__init__(self, "SpecCheck")
120 self._spec_file = None
122 def check(self, pkg):
123 if not pkg.isSource():
129 for fname, pkgfile in pkg.files().items():
130 if fname.endswith('.spec'):
131 self._spec_file = pkgfile.path
132 if fname == pkg.name + ".spec":
137 if not self._spec_file:
138 printError(pkg, "no-spec-file")
141 printError(pkg, "invalid-spec-name")
143 # check content of spec file
144 self.check_spec(pkg, self._spec_file)
146 def check_spec(self, pkg, spec_file, spec_lines=[]):
147 self._spec_file = spec_file
148 spec_only = isinstance(pkg, Pkg.FakePkg)
150 spec_lines = Pkg.readlines(spec_file)
153 applied_patches_ifarch = []
156 configure_linenum = None
157 configure_cmdline = ""
162 current_section = 'package'
163 buildroot_clean = {'clean': False, 'install' : False}
164 depscript_override = False
165 depgen_disabled = False
168 files_has_defattr = False
170 # None == main package
171 current_package = None
175 if self._spec_file and use_utf8:
176 if Pkg.is_utf8(self._spec_file):
179 printError(pkg, "non-utf8-spec-file", self._spec_file)
181 # gather info from spec lines
183 pkg.current_linenum = 0
189 for line in spec_lines:
191 pkg.current_linenum += 1
194 line = unicode(line, "utf-8", "replace")
196 char = line.find(nbsp)
198 printWarning(pkg, "non-break-space", "line %s, char %d" %
199 (pkg.current_linenum, char))
201 section_marker = False
202 for sec, regex in section_regexs.items():
203 res = regex.search(line)
205 current_section = sec
206 section_marker = True
207 section[sec] = section.get(sec, 0) + 1
208 if sec in ('package', 'files'):
209 rest = filelist_regex.sub('', line[res.end()-1:])
210 res = pkgname_regex.search(rest)
212 current_package = res.group(1)
214 current_package = None
219 if current_section == 'files':
220 files_has_defattr = False
222 if not is_lib_pkg and lib_package_regex.search(line):
227 if current_section in ('prep', 'build','pre', 'post', 'postun',
228 'trigger', 'triggerin', 'triggerprein', 'triggerun', 'triggerpostun',
229 'pretrans', 'posttrans') and \
230 contains_buildroot(line):
231 printWarning(pkg, 'rpm-buildroot-usage', '%' + current_section,
234 if make_check_regex.search(line) and current_section not in \
235 ('check', 'changelog', 'package', 'description'):
236 printWarning(pkg, 'make-check-outside-check-section', line[:-1])
238 if current_section in buildroot_clean and \
239 not buildroot_clean[current_section] and \
240 contains_buildroot(line) and rm_regex.search(line):
241 buildroot_clean[current_section] = True
243 if ifarch_regex.search(line):
244 if_depth = if_depth + 1
245 ifarch_depth = if_depth
247 if if_regex.search(line):
248 if_depth = if_depth + 1
250 if line.startswith('%setup'):
251 if not setup_q_regex.search(line):
252 # Don't warn if there's a -T without -a or -b
253 if setup_t_regex.search(line):
254 if setup_ab_regex.search(line):
255 printWarning(pkg, 'setup-not-quiet')
257 printWarning(pkg, 'setup-not-quiet')
258 if current_section != 'prep':
259 printWarning(pkg, 'setup-not-in-prep')
261 if endif_regex.search(line):
262 if ifarch_depth == if_depth:
264 if_depth = if_depth - 1
266 res = applied_patch_regex.search(line)
268 pnum = res.group(1) or 0
269 for tmp in applied_patch_p_regex.findall(line) or [pnum]:
271 applied_patches.append(pnum)
273 applied_patches_ifarch.append(pnum)
275 res = applied_patch_pipe_regex.search(line)
277 pnum = int(res.group(1))
278 applied_patches.append(pnum)
280 applied_patches_ifarch.append(pnum)
281 if not res and not source_dir:
282 res = source_dir_regex.search(line)
285 printError(pkg, "use-of-RPM_SOURCE_DIR")
287 if configure_linenum:
288 if configure_cmdline[-1] == "\\":
289 configure_cmdline = configure_cmdline[:-1] + line.strip()
291 res = configure_libdir_spec_regex.search(configure_cmdline)
293 # Hack to get the correct (start of ./configure) line
295 real_linenum = pkg.current_linenum
296 pkg.current_linenum = configure_linenum
297 printWarning(pkg, "configure-without-libdir-spec")
298 pkg.current_linenum = real_linenum
300 res = re.match(hardcoded_library_paths, res.group(1))
302 printError(pkg, "hardcoded-library-path",
303 res.group(1), "in configure options")
304 configure_linenum = None
306 hashPos = line.find("#")
308 if current_section != 'changelog':
309 cfgPos = line.find('./configure')
310 if cfgPos != -1 and (hashPos == -1 or hashPos > cfgPos):
311 # store line where it started
312 configure_linenum = pkg.current_linenum
313 configure_cmdline = line.strip()
315 res = hardcoded_library_path_regex.search(line)
316 if current_section != 'changelog' and res and not \
317 (biarch_package_regex.match(pkg.name) or
318 hardcoded_lib_path_exceptions_regex.search(
319 res.group(1).lstrip())):
320 printError(pkg, "hardcoded-library-path", "in",
321 res.group(1).lstrip())
323 if '%mklibname' in line:
326 if current_section == 'package':
328 # Would be cleaner to get sources and patches from the
329 # specfile parsed in Python (see below), but we want to
330 # catch %ifarch'd etc ones as well, and also catch these when
331 # the specfile is not parseable.
333 res = patch_regex.search(line)
335 pnum = int(res.group(1) or 0)
336 patches[pnum] = res.group(2)
338 res = obsolete_tags_regex.search(line)
340 printWarning(pkg, "obsolete-tag", res.group(1))
342 res = buildroot_regex.search(line)
345 if res.group(1).startswith('/'):
346 printWarning(pkg, 'hardcoded-path-in-buildroot-tag',
349 res = buildarch_regex.search(line)
351 if res.group(2) != "noarch":
352 printError(pkg, 'buildarch-instead-of-exclusivearch-tag', res.group(2))
354 package_noarch[current_package] = True
356 res = packager_regex.search(line)
358 printWarning(pkg, 'hardcoded-packager-tag', res.group(1))
360 res = prefix_regex.search(line)
362 if not res.group(1).startswith('%'):
363 printWarning(pkg, 'hardcoded-prefix-tag', res.group(1))
365 res = suse_version_regex.search(line)
366 if res and int(res.group(1)) > 0 and int(res.group(1)) < 1130:
367 printWarning(pkg, "obsolete-suse-version-check", res.group(1))
368 elif res and int(res.group(1)) > 1230:
369 printError(pkg, "invalid-suse-version-check", res.group(1))
371 res = prereq_regex.search(line)
373 printError(pkg, 'prereq-use', res.group(2))
375 res = buildprereq_regex.search(line)
377 printError(pkg, 'buildprereq-use', res.group(1))
379 if scriptlet_requires_regex.search(line):
380 printError(pkg, 'broken-syntax-in-scriptlet-requires',
383 res = requires_regex.search(line)
385 reqs = Pkg.parse_deps(res.group(1))
386 for req in unversioned(reqs):
387 if compop_regex.search(req):
388 printWarning(pkg, 'comparison-operator-in-deptoken',
391 res = provides_regex.search(line)
393 provs = Pkg.parse_deps(res.group(1))
394 for prov in unversioned(provs):
395 printWarning(pkg, 'unversioned-explicit-provides', prov)
396 if compop_regex.search(prov):
397 printWarning(pkg, 'comparison-operator-in-deptoken',
400 res = obsoletes_regex.search(line)
402 obses = Pkg.parse_deps(res.group(1))
403 for obs in unversioned(obses):
404 printWarning(pkg, 'unversioned-explicit-obsoletes', obs)
405 if compop_regex.search(obs):
406 printWarning(pkg, 'comparison-operator-in-deptoken',
409 res = conflicts_regex.search(line)
411 confs = Pkg.parse_deps(res.group(1))
412 for conf in unversioned(confs):
413 if compop_regex.search(conf):
414 printWarning(pkg, 'comparison-operator-in-deptoken',
417 if current_section == 'changelog':
418 for match in AbstractCheck.macro_regex.findall(line):
419 res = re.match('%+', match)
420 if len(res.group(0)) % 2:
421 printWarning(pkg, 'macro-in-%changelog', match)
423 if not depscript_override:
424 depscript_override = \
425 depscript_override_regex.search(line) is not None
426 if not depgen_disabled:
428 depgen_disable_regex.search(line) is not None
430 if current_section == 'files':
432 if not comment_or_empty_regex.search(line) and not \
433 (ifarch_regex.search(line) or if_regex.search(line) or
434 endif_regex.search(line)):
435 if defattr_regex.search(line):
436 files_has_defattr = True
437 elif not (files_has_defattr or attr_regex.search(line)):
438 printWarning(pkg, 'files-attr-not-set')
440 # TODO: check scriptlets for these too?
441 if package_noarch.get(current_package) or \
442 (current_package not in package_noarch and
443 package_noarch.get(None)):
444 res = libdir_regex.search(line)
446 pkgname = current_package
448 pkgname = '(main package)'
449 printWarning(pkg, 'libdir-macro-in-noarch-package',
450 pkgname, line.rstrip())
452 if not indent_tabs and '\t' in line:
453 indent_tabs = pkg.current_linenum
454 if not indent_spaces and indent_spaces_regex.search(line):
455 indent_spaces = pkg.current_linenum
457 # Check if egrep or fgrep is used
458 if current_section not in \
459 ('package', 'changelog', 'description', 'files'):
460 greps = deprecated_grep_regex.findall(line)
462 printWarning(pkg, "deprecated-grep", greps)
464 # If not checking spec file only, we're checking one inside a
465 # SRPM -> skip this check to avoid duplicate warnings (#167)
466 if spec_only and VALID_GROUPS and \
467 line.lower().startswith("group:"):
468 group = line[6:].strip()
469 if group not in VALID_GROUPS:
470 printWarning(pkg, 'non-standard-group', group)
472 # Test if there are macros in comments
473 if hashPos != -1 and \
474 (hashPos == 0 or line[hashPos-1] in (" ", "\t")):
475 for match in AbstractCheck.macro_regex.findall(
477 res = re.match('%+', match)
478 if len(res.group(0)) % 2:
479 printWarning(pkg, 'macro-in-comment', match)
481 # Last line read is not useful after this point
482 pkg.current_linenum = None
484 for sect in (x for x in buildroot_clean if not buildroot_clean[x]):
485 printWarning(pkg, 'no-cleaning-of-buildroot', '%' + sect)
488 printWarning(pkg, 'no-buildroot-tag')
490 for sec in ('prep', 'build', 'install', 'clean'):
491 if not section.get(sec):
492 printWarning(pkg, 'no-%%%s-section' % sec)
493 for sec in ('changelog',):
494 # prep, build, install, clean, check prevented by rpmbuild 4.4
495 if section.get(sec, 0) > 1:
496 printWarning(pkg, 'more-than-one-%%%s-section' % sec)
498 if is_lib_pkg and not mklibname:
499 printError(pkg, 'lib-package-without-%mklibname')
501 if depscript_override and not depgen_disabled:
502 printWarning(pkg, 'depscript-without-disabling-depgen')
504 if indent_spaces and indent_tabs:
505 pkg.current_linenum = max(indent_spaces, indent_tabs)
506 printWarning(pkg, 'mixed-use-of-spaces-and-tabs',
507 '(spaces: line %d, tab: line %d)' %
508 (indent_spaces, indent_tabs))
509 pkg.current_linenum = None
511 # process gathered info
512 for pnum, pfile in patches.items():
513 if pnum in applied_patches_ifarch:
514 printWarning(pkg, "%ifarch-applied-patch", "Patch%d:" % pnum,
516 if pnum not in applied_patches:
517 printWarning(pkg, "patch-not-applied", "Patch%d:" % pnum,
520 # Rest of the checks require a real spec file
521 if not self._spec_file:
524 # We'd like to parse the specfile only once using python bindings,
525 # but it seems errors from rpmlib get logged to stderr and we can't
526 # capture and print them nicely, so we do it once each way :P
528 out = Pkg.getstatusoutput(('env', 'LC_ALL=C', 'rpm', '-q',
529 '--qf=', '--specfile', self._spec_file))
531 for line in out[1].splitlines():
532 # No such file or dir hack: https://bugzilla.redhat.com/487855
533 if 'No such file or directory' not in line:
535 printError(pkg, 'specfile-error', line)
538 # grab sources and patches from parsed spec object to get
539 # them with macros expanded for URL checking
543 ts = rpm.TransactionSet()
544 spec_obj = ts.parseSpec(self._spec_file)
546 # errors logged above already
551 sources = spec_obj.sources()
554 sources = spec_obj.sources
556 (url, num, flags) = src
557 (scheme, netloc) = urlparse(url)[0:2]
558 if flags & 1: # rpmspec.h, rpm.org ticket #123
562 tag = '%s%s' % (srctype, num)
563 if scheme and netloc:
564 info = self.check_url(pkg, tag, url)
565 if not info or not hasattr(pkg, 'files'):
567 clen = info.get("Content-Length")
570 cmd5 = info.get("Content-MD5")
573 if clen is not None or cmd5 is not None:
574 # Not using path from urlparse results to match how
575 # rpm itself parses the basename.
576 pkgfile = pkg.files()[url.split("/")[-1]]
578 if clen is not None and pkgfile.size != clen:
579 printWarning(pkg, 'file-size-mismatch',
581 (pkgfile.name, pkgfile.size,
583 # pkgfile.md5 could be some other digest than
584 # MD5, treat as MD5 only if it's 32 chars long
585 if cmd5 and len(pkgfile.md5) == 32 \
586 and pkgfile.md5 != cmd5:
587 printWarning(pkg, 'file-md5-mismatch',
589 (pkgfile.name, pkgfile.md5,
591 elif srctype == "Source" and tarball_regex.search(url):
592 printWarning(pkg, 'invalid-url', '%s:' % tag, url)
594 # Create an object to enable the auto registration of the test
597 # Add information about checks
600 '''No spec file was specified in your RPM building. Please specify a valid
601 SPEC file to build a valid RPM package.''',
604 '''Your spec filename must end with '.spec'. If it's not the case, rename your
605 file and rebuild your package.''',
607 'non-utf8-spec-file',
608 '''The character encoding of the spec file is not UTF-8. Convert it for
609 example using iconv(1).''',
611 'use-of-RPM_SOURCE_DIR',
612 '''You use $RPM_SOURCE_DIR or %{_sourcedir} in your spec file. If you have to
613 use a directory for building, use $RPM_BUILD_ROOT instead.''',
616 '''A patch is included in your package but was not applied. Refer to the patches
617 documentation to see what's wrong.''',
620 '''The following tags are obsolete: Copyright and Serial. They must
621 be replaced by License and Epoch respectively.''',
624 '''Direct use of grep as egrep or fgrep is deprecated in GNU grep and
625 historical in POSIX, use grep -E and grep -F instead.''',
628 '''The BuildRoot tag isn't used in your spec. It must be used in order to
629 allow building the package as non root on some systems. For some rpm versions
630 (e.g. rpm.org >= 4.6) the BuildRoot tag is not necessary in specfiles and is
631 ignored by rpmbuild; if your package is only going to be built with such rpm
632 versions you can ignore this warning.''',
634 'hardcoded-path-in-buildroot-tag',
635 '''A path is hardcoded in your Buildroot tag. It should be replaced
636 by %{_tmppath}/%{name}-%{version}-build.''',
638 'hardcoded-packager-tag',
639 '''The Packager tag is hardcoded in your spec file. It should be removed, so
640 as to use rebuilder's own defaults.''',
642 'buildarch-instead-of-exclusivearch-tag',
643 '''Use ExclusiveArch instead of BuildArch (or BuildArchitectures)
644 to restrict build on some specific architectures.
645 Only use BuildArch with noarch''',
647 'hardcoded-prefix-tag',
648 '''The Prefix tag is hardcoded in your spec file. It should be removed, so as
649 to allow package relocation.''',
651 'hardcoded-library-path',
652 '''A library path is hardcoded to one of the following paths: /lib,
653 /usr/lib. It should be replaced by something like /%{_lib} or %{_libdir}.''',
655 'configure-without-libdir-spec',
656 '''A configure script is run without specifying the libdir. configure
657 options must be augmented with something like --libdir=%{_libdir} whenever
658 the script supports it.''',
661 '''The spec file does not contain a %prep section. Even if some packages don't
662 directly need it, section markers may be overridden in rpm's configuration
663 to provide additional "under the hood" functionality. Add the section, even
667 '''The spec file does not contain a %build section. Even if some packages
668 don't directly need it, section markers may be overridden in rpm's
669 configuration to provide additional "under the hood" functionality, such as
670 injection of automatic -debuginfo subpackages. Add the section, even if
673 'no-%install-section',
674 '''The spec file does not contain an %install section. Even if some packages
675 don't directly need it, section markers may be overridden in rpm's
676 configuration to provide additional "under the hood" functionality. Add the
677 section, even if empty.''',
680 '''The spec file doesn't contain a %clean section to remove the files installed
681 by the %install section.''',
683 'more-than-one-%changelog-section',
684 '''The spec file unnecessarily contains more than one %changelog section;
685 remove the extra ones.''',
687 'lib-package-without-%mklibname',
688 '''The package name must be built using %mklibname to allow lib64 and lib32
691 '%ifarch-applied-patch',
692 '''A patch is applied inside an %ifarch block. Patches must be applied
693 on all architectures and may contain necessary configure and/or code
694 patch to be effective only on a given arch.''',
697 '''The use of PreReq is deprecated. In the majority of cases, a plain Requires
698 is enough and the right thing to do. Sometimes Requires(pre), Requires(post),
699 Requires(preun) and/or Requires(postun) can also be used instead of PreReq.''',
702 '''The use of BuildPreReq is deprecated, build dependencies are always required
703 before a package can be built. Use plain BuildRequires instead.''',
705 'broken-syntax-in-scriptlet-requires',
706 '''Comma separated context marked dependencies are silently broken in some
707 versions of rpm. One way to work around it is to split them into several ones,
708 eg. replace "Requires(post,preun): foo" with "Requires(post): foo" and
709 "Requires(preun): foo".''',
712 '''The %setup macro should only be used within the %prep section because it may
713 not expand to anything outside of it and can break the build in unpredictable
717 '''Use the -q option to the %setup macro to avoid useless build output from
718 unpacking the sources.''',
720 'no-cleaning-of-buildroot',
721 '''You should clean $RPM_BUILD_ROOT in the %clean section and in the beginning
722 of the %install section. Use "rm -rf $RPM_BUILD_ROOT". Some rpm configurations
723 do this automatically; if your package is only going to be built in such
724 configurations, you can ignore this warning for the section(s) where your rpm
725 takes care of it.''',
727 'rpm-buildroot-usage',
728 '''$RPM_BUILD_ROOT should not be touched during %build or %prep stage, as it
729 may break short circuit builds.''',
731 'make-check-outside-check-section',
732 '''Make check or other automated regression test should be run in %check, as
733 they can be disabled with a rpm macro for short circuiting purposes.''',
735 'macro-in-%changelog',
736 '''Macros are expanded in %changelog too, which can in unfortunate cases lead
737 to the package not building at all, or other subtle unexpected conditions that
738 affect the build. Even when that doesn\'t happen, the expansion results in
739 possibly "rewriting history" on subsequent package revisions and generally
740 odd entries eg. in source rpms, which is rarely wanted. Avoid use of macros
741 in %changelog altogether, or use two '%'s to escape them, like '%%foo'.''',
743 'depscript-without-disabling-depgen',
744 '''In some common rpm configurations/versions, defining __find_provides and/or
745 __find_requires has no effect if rpm's internal dependency generator has not
746 been disabled for the build. %define _use_internal_dependency_generator to 0
747 to disable it in the specfile, or don't define __find_provides/requires.''',
749 'mixed-use-of-spaces-and-tabs',
750 '''The specfile mixes use of spaces and tabs for indentation, which is a
751 cosmetic annoyance. Use either spaces or tabs for indentation, not both.''',
753 'unversioned-explicit-provides',
754 '''The specfile contains an unversioned Provides: token, which will match all
755 older, equal, and newer versions of the provided thing. This may cause
756 update problems and will make versioned dependencies, obsoletions and conflicts
757 on the provided thing useless -- make the Provides versioned if possible.''',
759 'unversioned-explicit-obsoletes',
760 '''The specfile contains an unversioned Obsoletes: token, which will match all
761 older, equal and newer versions of the obsoleted thing. This may cause update
762 problems, restrict future package/provides naming, and may match something it
763 was originally not inteded to match -- make the Obsoletes versioned if
766 'libdir-macro-in-noarch-package',
767 '''The %{_libdir} or %{_lib} macro was found in a noarch package in a section
768 that gets included in binary packages. This is most likely an error because
769 these macros are expanded on the build host and their values vary between
770 architectures, probably resulting in a package that does not work properly
771 on all architectures at runtime. Investigate whether the package is really
772 architecture independent or if some other dir/macro should be instead.''',
775 '''The spec file contains a non-break space, which looks like a regular space
776 in some editors but can lead to obscure errors. It should be replaced by a
779 'files-attr-not-set',
780 '''A file or a directory entry in a %files section does not have attributes
781 set which may result in unexpected file permissions and thus security issues
782 in the resulting binary package depending on the build environment and rpmbuild
783 version (typically < 4.4). Add default attributes using %defattr before it in
784 the %files section, or use per entry %attr's.''',
786 'obsolete-suse-version-check',
787 '''The specfile contains a comparison of %suse_version against a suse release
788 that is no longer in maintenance. Consider removing obsolete parts of your
789 spec file to make it more readable.''',
791 'invalid-suse-version-check',
792 '''The specfile contains a comparison of %suse_version against a suse release
793 that does not exist. Please double check.''',
795 'non-standard-group',
796 '''The value of the Group tag in the package is not valid. Valid groups are:
797 "%s".''' % '", "'.join(VALID_GROUPS),
800 '''This error occurred when rpmlint used rpm to query the specfile. The error
801 is output by rpm and the message should contain more information.''',
803 'comparison-operator-in-deptoken',
804 '''This dependency token contains a comparison operator (<, > or =). This is
805 usually not intended and may be caused by missing whitespace between the token's
806 name, the comparison operator and the version string.''',
809 '''There is a unescaped macro after a shell style comment in the specfile.
810 Macros are expanded everywhere, so check if it can cause a problem in this
811 case and escape the macro with another leading % if appropriate.''',
813 'file-size-mismatch',
814 '''The size of the file in the package does not match the size indicated by
815 peeking at its URL. Verify that the file in the package has the intended
819 '''The MD5 hash of the file in the package does not match the MD5 hash
820 indicated by peeking at its URL. Verify that the file in the package has the
821 intended contents.''',
824 # SpecCheck.py ends here
827 # indent-tabs-mode: nil
828 # py-indent-offset: 4