#!/usr/bin/python -ttOu # -*- coding: utf-8 -*- ############################################################################# # File : rpmlint # Package : rpmlint # Author : Frederic Lepied # Created on : Mon Sep 27 19:20:18 1999 # Version : $Id: rpmlint 1870 2011-06-18 09:19:24Z scop $ # Purpose : main entry point: process options, load the checks and run # the checks. ############################################################################# import getopt import glob import imp import locale import os import re import stat import sys import tempfile # 1 instead of 0 here because we want the script dir to be looked up first, # e.g. for in-place from tarball or SCM checkout sys.path.insert(1, '/usr/share/rpmlint') # Do not import anything that initializes its global variables from # Config at load time here (or anything that imports such a thing), # that results in those variables initialized before config files are # loaded which is too early - settings from config files won't take # place for those variables. from Filter import badnessScore, badnessThreshold, printAllReasons, \ printDescriptions, printInfo, printed_messages, setRawOut import AbstractCheck import Config import Pkg _default_user_conf = '%s/rpmlint' % \ (os.environ.get('XDG_CONFIG_HOME') or '~/.config') # Print usage information def usage(name): print ('''usage: %s [] options: \t[-i|--info] \t[-I|--explain ] \t[-c|--check ] \t[-a|--all] \t[-C|--checkdir ] \t[-h|--help] \t[-v|--verbose] \t[-E|--extractdir ] \t[-V|--version] \t[-n|--noexception] \t[ --rawout ] \t[-f|--file ]''' \ % (name, _default_user_conf)) # Print version information def printVersion(): print ('rpmlint version %s Copyright (C) 1999-2007 Frederic Lepied, Mandriva' % Config.__version__) def loadCheck(name): '''Load a (check) module by its name, unless it is already loaded.''' # Avoid loading more than once (initialization costs) loaded = sys.modules.get(name) if loaded: return loaded (fobj, pathname, description) = imp.find_module(name) try: imp.load_module(name, fobj, pathname, description) finally: fobj.close() ############################################################################# # main program ############################################################################# def main(): locale.setlocale(locale.LC_COLLATE, '') # Add check dirs to the front of load path sys.path[0:0] = Config.checkDirs() # Load all checks for c in Config.allChecks(): loadCheck(c) packages_checked = 0 specfiles_checked = 0 do_spec_check = 'SpecCheck' in Config.allChecks() if do_spec_check: # See comments in "top level import section" for why this isn't # imported earlier. import SpecCheck try: # Loop over all file names given in arguments dirs = [] for arg in args: pkgs = [] isfile = False try: if arg == "-": arg = "(standard input)" # Short-circuit stdin spec file check if do_spec_check: stdin = sys.stdin.readlines() if not stdin: continue pkg = Pkg.FakePkg(arg) check = SpecCheck.SpecCheck() check.verbose = verbose check.check_spec(pkg, None, spec_lines=stdin) pkg.cleanup() specfiles_checked += 1 continue try: st = os.stat(arg) isfile = True if stat.S_ISREG(st[stat.ST_MODE]): if arg.endswith(".spec"): if do_spec_check: # Short-circuit spec file checks pkg = Pkg.FakePkg(arg) check = SpecCheck.SpecCheck() check.verbose = verbose check.check_spec(pkg, arg) pkg.cleanup() specfiles_checked += 1 elif "/" in arg or arg.endswith(".rpm") or \ arg.endswith(".spm"): pkgs.append(Pkg.Pkg(arg, extract_dir)) else: raise OSError elif stat.S_ISDIR(st[stat.ST_MODE]): dirs.append(arg) continue else: raise OSError except OSError: ipkgs = Pkg.getInstalledPkgs(arg) if not ipkgs: Pkg.warn( '(none): E: no installed packages by name %s' % arg) else: ipkgs.sort(key = lambda x: locale.strxfrm( x.header.sprintf("%{NAME}.%{ARCH}"))) pkgs.extend(ipkgs) except KeyboardInterrupt: if isfile: arg = os.path.abspath(arg) Pkg.warn( '(none): E: interrupted, exiting while reading %s' % arg) sys.exit(2) except Exception, e: if isfile: arg = os.path.abspath(arg) Pkg.warn('(none): E: error while reading %s: %s' % (arg, e)) pkgs = [] continue for pkg in pkgs: runChecks(pkg) packages_checked += 1 for dname in dirs: try: for path, dirs, files in os.walk(dname): for fname in files: fname = os.path.abspath(os.path.join(path, fname)) try: if fname.endswith('.rpm') or \ fname.endswith('.spm'): pkg = Pkg.Pkg(fname, extract_dir) runChecks(pkg) packages_checked += 1 elif do_spec_check and fname.endswith('.spec'): pkg = Pkg.FakePkg(fname) check = SpecCheck.SpecCheck() check.verbose = verbose check.check_spec(pkg, fname) pkg.cleanup() specfiles_checked += 1 except KeyboardInterrupt: Pkg.warn('(none): E: interrupted, exiting while ' + 'reading %s' % fname) sys.exit(2) except Exception, e: Pkg.warn( '(none): E: while reading %s: %s' % (fname, e)) continue except Exception, e: Pkg.warn( '(none): E: error while reading dir %s: %s' % (dname, e)) continue if printAllReasons(): Pkg.warn('(none): E: badness %d exceeds threshold %d, aborting.' % (badnessScore(), badnessThreshold())) sys.exit(66) finally: print "%d packages and %d specfiles checked; %d errors, %d warnings." \ % (packages_checked, specfiles_checked, printed_messages["E"], printed_messages["W"]) if badnessThreshold() < 0 and printed_messages["E"] > 0: sys.exit(64) sys.exit(0) def runChecks(pkg): try: if verbose: printInfo(pkg, 'checking') for name in Config.allChecks(): check = AbstractCheck.AbstractCheck.known_checks.get(name) if check: check.verbose = verbose check.check(pkg) else: Pkg.warn('(none): W: unknown check %s, skipping' % name) finally: pkg.cleanup() ############################################################################# # ############################################################################# sys.argv[0] = os.path.basename(sys.argv[0]) # parse options try: (opt, args) = getopt.getopt(sys.argv[1:], 'iI:c:C:hVvanE:f:o:', ['info', 'explain=', 'check=', 'checkdir=', 'help', 'version', 'verbose', 'all', 'noexception', 'extractdir=', 'file=', 'option=', 'rawout=', ]) except getopt.GetoptError, e: Pkg.warn("%s: %s" % (sys.argv[0], e)) usage(sys.argv[0]) sys.exit(1) # process options checkdir = '/usr/share/rpmlint' checks = [] verbose = False extract_dir = None conf_file = _default_user_conf if not os.path.exists(os.path.expanduser(conf_file)): # deprecated backwards compatibility with < 0.88 conf_file = '~/.rpmlintrc' info_error = set() # load global config files configs = glob.glob('/etc/rpmlint/*config') configs.sort() # Was rpmlint invoked as a prefixed variant? m = re.match(r"(?P[\w-]+)-rpmlint(\.py)?", sys.argv[0]) if m: # Okay, we're a prefixed variant. Look for the variant config. # If we find it, use it. If not, fallback to the default. prefix = m.group('prefix') if os.path.isfile('/usr/share/rpmlint/config.%s' % prefix): configs.insert(0, '/usr/share/rpmlint/config.%s' % prefix) else: configs.insert(0, '/usr/share/rpmlint/config') else: configs.insert(0, '/usr/share/rpmlint/config') for f in configs: try: execfile(f) except IOError: pass except Exception, E: Pkg.warn('(none): W: error loading %s, skipping: %s' % (f, E)) # pychecker fix del f config_overrides = {} # process command line options for o in opt: if o[0] in ('-c', '--check'): checks.append(o[1]) elif o[0] in ('-i', '--info'): Config.info = True elif o[0] in ('-I', '--explain'): # split by comma for deprecated backwards compatibility with < 1.2 info_error.update(o[1].split(',')) elif o[0] in ('-h', '--help'): usage(sys.argv[0]) sys.exit(0) elif o[0] in ('-C', '--checkdir'): Config.addCheckDir(o[1]) elif o[0] in ('-v', '--verbose'): verbose = True elif o[0] in ('-V', '--version'): printVersion() sys.exit(0) elif o[0] in ('-E', '--extractdir'): extract_dir = o[1] Config.setOption('ExtractDir', extract_dir) elif o[0] in ('-n', '--noexception'): Config.no_exception = True elif o[0] in ('-a', '--all'): if '*' not in args: args.append('*') elif o[0] in ('-f', '--file'): conf_file = o[1] elif o[0] in ('-o', '--option'): kv = o[1].split(None, 1) if len(kv) == 1: config_overrides[kv[0]] = None else: config_overrides[kv[0]] = eval(kv[1]) elif o[0] in ('--rawout',): setRawOut(o[1]) # load user config file try: execfile(os.path.expanduser(conf_file)) except IOError: pass except Exception,E: Pkg.warn('(none): W: error loading %s, skipping: %s' % (conf_file, E)) # apply config overrides for key, value in config_overrides.items(): Config.setOption(key, value) if not extract_dir: extract_dir = Config.getOption('ExtractDir', tempfile.gettempdir()) if info_error: Config.info = True sys.path[0:0] = Config.checkDirs() for c in checks: Config.addCheck(c) for c in Config.allChecks(): loadCheck(c) for e in sorted(info_error): print "%s:" % e printDescriptions(e) sys.exit(0) # if no argument print usage if not args: usage(sys.argv[0]) sys.exit(1) if __name__ == '__main__': if checks: Config.resetChecks() for check in checks: Config.addCheck(check) main() # rpmlint ends here # Local variables: # indent-tabs-mode: nil # py-indent-offset: 4 # End: # ex: ts=4 sw=4 et