1 #!/usr/bin/python -ttOu
2 # -*- coding: utf-8 -*-
3 #############################################################################
6 # Author : Frederic Lepied
7 # Created on : Mon Sep 27 19:20:18 1999
8 # Version : $Id: rpmlint 1870 2011-06-18 09:19:24Z scop $
9 # Purpose : main entry point: process options, load the checks and run
11 #############################################################################
23 # 1 instead of 0 here because we want the script dir to be looked up first,
24 # e.g. for in-place from tarball or SCM checkout
25 sys.path.insert(1, '/usr/share/rpmlint')
27 # Do not import anything that initializes its global variables from
28 # Config at load time here (or anything that imports such a thing),
29 # that results in those variables initialized before config files are
30 # loaded which is too early - settings from config files won't take
31 # place for those variables.
33 from Filter import badnessScore, badnessThreshold, printAllReasons, \
34 printDescriptions, printInfo, printed_messages, setRawOut
40 _default_user_conf = '%s/rpmlint' % \
41 (os.environ.get('XDG_CONFIG_HOME') or '~/.config')
43 # Print usage information
45 print ('''usage: %s [<options>] <rpm files|installed packages|specfiles|dirs>
48 \t[-I|--explain <messageid>]
49 \t[-c|--check <check>]
51 \t[-C|--checkdir <checkdir>]
54 \t[-E|--extractdir <dir>]
58 \t[-f|--file <user config file to use instead of %s]
59 \t[-o|--option <key value>]''' \
60 % (name, _default_user_conf))
62 # Print version information
64 print ('rpmlint version %s Copyright (C) 1999-2007 Frederic Lepied, Mandriva' % Config.__version__)
67 '''Load a (check) module by its name, unless it is already loaded.'''
68 # Avoid loading more than once (initialization costs)
69 loaded = sys.modules.get(name)
72 (fobj, pathname, description) = imp.find_module(name)
74 imp.load_module(name, fobj, pathname, description)
78 #############################################################################
80 #############################################################################
83 locale.setlocale(locale.LC_COLLATE, '')
85 # Add check dirs to the front of load path
86 sys.path[0:0] = Config.checkDirs()
89 for c in Config.allChecks():
94 do_spec_check = 'SpecCheck' in Config.allChecks()
96 # See comments in "top level import section" for why this isn't
101 # Loop over all file names given in arguments
108 arg = "(standard input)"
109 # Short-circuit stdin spec file check
111 stdin = sys.stdin.readlines()
114 pkg = Pkg.FakePkg(arg)
115 check = SpecCheck.SpecCheck()
116 check.verbose = verbose
117 check.check_spec(pkg, None, spec_lines=stdin)
119 specfiles_checked += 1
125 if stat.S_ISREG(st[stat.ST_MODE]):
126 if arg.endswith(".spec"):
128 # Short-circuit spec file checks
129 pkg = Pkg.FakePkg(arg)
130 check = SpecCheck.SpecCheck()
131 check.verbose = verbose
132 check.check_spec(pkg, arg)
134 specfiles_checked += 1
135 elif "/" in arg or arg.endswith(".rpm") or \
136 arg.endswith(".spm"):
137 pkgs.append(Pkg.Pkg(arg, extract_dir))
141 elif stat.S_ISDIR(st[stat.ST_MODE]):
147 ipkgs = Pkg.getInstalledPkgs(arg)
150 '(none): E: no installed packages by name %s' % arg)
152 ipkgs.sort(key = lambda x: locale.strxfrm(
153 x.header.sprintf("%{NAME}.%{ARCH}")))
155 except KeyboardInterrupt:
157 arg = os.path.abspath(arg)
159 '(none): E: interrupted, exiting while reading %s' % arg)
163 arg = os.path.abspath(arg)
164 Pkg.warn('(none): E: error while reading %s: %s' % (arg, e))
170 packages_checked += 1
174 for path, dirs, files in os.walk(dname):
176 fname = os.path.abspath(os.path.join(path, fname))
178 if fname.endswith('.rpm') or \
179 fname.endswith('.spm'):
180 pkg = Pkg.Pkg(fname, extract_dir)
182 packages_checked += 1
184 elif do_spec_check and fname.endswith('.spec'):
185 pkg = Pkg.FakePkg(fname)
186 check = SpecCheck.SpecCheck()
187 check.verbose = verbose
188 check.check_spec(pkg, fname)
190 specfiles_checked += 1
192 except KeyboardInterrupt:
193 Pkg.warn('(none): E: interrupted, exiting while ' +
194 'reading %s' % fname)
198 '(none): E: while reading %s: %s' % (fname, e))
202 '(none): E: error while reading dir %s: %s' % (dname, e))
205 if printAllReasons():
206 Pkg.warn('(none): E: badness %d exceeds threshold %d, aborting.' %
207 (badnessScore(), badnessThreshold()))
211 print "%d packages and %d specfiles checked; %d errors, %d warnings." \
212 % (packages_checked, specfiles_checked,
213 printed_messages["E"], printed_messages["W"])
215 if badnessThreshold() < 0 and printed_messages["E"] > 0:
223 printInfo(pkg, 'checking')
225 for name in Config.allChecks():
226 check = AbstractCheck.AbstractCheck.known_checks.get(name)
228 check.verbose = verbose
231 Pkg.warn('(none): W: unknown check %s, skipping' % name)
235 #############################################################################
237 #############################################################################
239 sys.argv[0] = os.path.basename(sys.argv[0])
243 (opt, args) = getopt.getopt(sys.argv[1:],
244 'iI:c:C:hVvanE:f:o:',
259 except getopt.GetoptError, e:
260 Pkg.warn("%s: %s" % (sys.argv[0], e))
265 checkdir = '/usr/share/rpmlint'
269 conf_file = _default_user_conf
270 if not os.path.exists(os.path.expanduser(conf_file)):
271 # deprecated backwards compatibility with < 0.88
272 conf_file = '~/.rpmlintrc'
275 # load global config files
276 configs = glob.glob('/etc/rpmlint/*config')
279 # Was rpmlint invoked as a prefixed variant?
280 m = re.match(r"(?P<prefix>[\w-]+)-rpmlint(\.py)?", sys.argv[0])
282 # Okay, we're a prefixed variant. Look for the variant config.
283 # If we find it, use it. If not, fallback to the default.
284 prefix = m.group('prefix')
285 if os.path.isfile('/usr/share/rpmlint/config.%s' % prefix):
286 configs.insert(0, '/usr/share/rpmlint/config.%s' % prefix)
288 configs.insert(0, '/usr/share/rpmlint/config')
290 configs.insert(0, '/usr/share/rpmlint/config')
298 Pkg.warn('(none): W: error loading %s, skipping: %s' % (f, E))
302 config_overrides = {}
304 # process command line options
306 if o[0] in ('-c', '--check'):
308 elif o[0] in ('-i', '--info'):
310 elif o[0] in ('-I', '--explain'):
311 # split by comma for deprecated backwards compatibility with < 1.2
312 info_error.update(o[1].split(','))
313 elif o[0] in ('-h', '--help'):
316 elif o[0] in ('-C', '--checkdir'):
317 Config.addCheckDir(o[1])
318 elif o[0] in ('-v', '--verbose'):
320 elif o[0] in ('-V', '--version'):
323 elif o[0] in ('-E', '--extractdir'):
325 Config.setOption('ExtractDir', extract_dir)
326 elif o[0] in ('-n', '--noexception'):
327 Config.no_exception = True
328 elif o[0] in ('-a', '--all'):
331 elif o[0] in ('-f', '--file'):
333 elif o[0] in ('-o', '--option'):
334 kv = o[1].split(None, 1)
336 config_overrides[kv[0]] = None
338 config_overrides[kv[0]] = eval(kv[1])
339 elif o[0] in ('--rawout',):
342 # load user config file
344 execfile(os.path.expanduser(conf_file))
348 Pkg.warn('(none): W: error loading %s, skipping: %s' % (conf_file, E))
350 # apply config overrides
351 for key, value in config_overrides.items():
352 Config.setOption(key, value)
355 extract_dir = Config.getOption('ExtractDir', tempfile.gettempdir())
359 sys.path[0:0] = Config.checkDirs()
362 for c in Config.allChecks():
364 for e in sorted(info_error):
369 # if no argument print usage
374 if __name__ == '__main__':
378 Config.addCheck(check)
384 # indent-tabs-mode: nil
385 # py-indent-offset: 4