3 # Copyright 2010 Brian Dolbec <brian.dolbec@gmail.com>
4 # Copyright(c) 2010, Gentoo Foundation
5 # Distributed under the terms of the GNU General Public License v2
8 """Provides a breakdown list of USE flags or keywords used and by
9 what packages according to the Installed package database"""
11 from __future__ import print_function
16 from gentoolkit.dbapi import PORTDB, VARDB
17 from gentoolkit.analyse.base import ModuleBase
18 from gentoolkit import pprinter as pp
19 from gentoolkit.flag import get_installed_use, get_flags
20 from gentoolkit.analyse.lib import FlagAnalyzer, KeywordAnalyser
21 from gentoolkit.analyse.output import nl, AnalysisPrinter
22 from gentoolkit.package import Package
23 from gentoolkit.helpers import get_installed_cpvs
28 def gather_flags_info(
34 # override-able for testing
36 _get_used=get_installed_use
38 """Analyse the installed pkgs USE flags for frequency of use
41 @param cpvs: optional list of [cat/pkg-ver,...] to analyse or
42 defaults to entire installed pkg db
43 @type: system_flags: list
44 @param system_flags: the current default USE flags as defined
45 by portage.settings["USE"].split()
46 @type include_unset: bool
47 @param include_unset: controls the inclusion of unset USE flags in the report.
49 @param target: the environment variable being analysed
50 one of ["USE", "PKGUSE"]
51 @type _get_flags: function
52 @param _get_flags: ovride-able for testing,
53 defaults to gentoolkit.analyse.lib.get_flags
54 @param _get_used: ovride-able for testing,
55 defaults to gentoolkit.analyse.lib.get_installed_use
56 @rtype dict. {flag:{"+":[cat/pkg-ver,...], "-":[cat/pkg-ver,...], "unset":[]}
59 cpvs = VARDB.cpv_all()
60 # pass them in to override for tests
61 flags = FlagAnalyzer(system_flags,
62 filter_defaults=False,
64 _get_flags=_get_flags,
65 _get_used=get_installed_use
69 if cpv.startswith("virtual"):
72 plus, minus, unset = flags.analyse_cpv(cpv)
75 plus, minus, unset = flags.analyse_pkg(pkg)
77 if flag in flag_users:
78 flag_users[flag]["+"].append(cpv)
80 flag_users[flag] = {"+": [cpv], "-": []}
82 if flag in flag_users:
83 flag_users[flag]["-"].append(cpv)
85 flag_users[flag] = {"+":[], "-": [cpv]}
88 if flag in flag_users:
89 if "unset" in flag_users[flag]:
90 flag_users[flag]["unset"].append(cpv)
92 flag_users[flag]["unset"] = [cpv]
94 flag_users[flag] = {"+": [], "-": [], "unset": [cpv]}
98 def gather_keywords_info(
100 system_keywords=None,
102 # override-able for testing
103 keywords=portage.settings["ACCEPT_KEYWORDS"],
106 """Analyse the installed pkgs 'keywords' for frequency of use
108 @param cpvs: optional list of [cat/pkg-ver,...] to analyse or
109 defaults to entire installed pkg db
110 @param system_keywords: list of the system keywords
111 @param keywords: user defined list of keywords to check and report on
112 or reports on all relevant keywords found to have been used.
113 @param _get_kwds: overridable function for testing
114 @param _get_used: overridable function for testing
115 @rtype dict. {keyword:{"stable":[cat/pkg-ver,...], "testing":[cat/pkg-ver,...]}
118 cpvs = VARDB.cpv_all()
121 if cpv.startswith("virtual"):
124 keyword = analyser.get_inst_keyword_cpv(cpv)
127 keyword = analyser.get_inst_keyword_pkg(pkg)
128 #print "returned keyword =", cpv, keyword, keyword[0]
130 if key in ["~", "-"]:
132 if _kwd in keyword_users:
134 keyword_users[_kwd]["testing"].append(cpv)
136 #print "adding cpv to missing:", cpv
137 keyword_users[_kwd]["missing"].append(cpv)
140 keyword_users[_kwd] = {"stable": [],
141 "testing": [cpv], "missing": []}
143 keyword_users[_kwd] = {"stable": [],
144 "testing": [], "missing": [cpv]}
146 keyword_users[_kwd] = {"stable": [cpv],
147 "testing": [], "missing": []}
148 elif keyword in keyword_users:
149 keyword_users[keyword]["stable"].append(cpv)
151 keyword_users[keyword] = {
159 class Analyse(ModuleBase):
160 """Installed db analysis tool to query the installed databse
161 and produce/output stats for USE flags or keywords/mask.
162 The 'rebuild' action output is in the form suitable for file type output
163 to create a new package.use, package.keywords, package.unmask
164 type files in the event of needing to rebuild the
165 /etc/portage/* user configs
168 ModuleBase.__init__(self)
169 self.module_name = "analyse"
181 "-f": ("flags", "boolean", True),
182 "--flags": ("flags", "boolean", True),
183 "-k": ("keywords", "boolean", True),
184 "--keywords": ("keywords", "boolean", True),
185 "-u": ("unset", "boolean", True),
186 "--unset": ("unset", "boolean", True),
187 "-v": ("verbose", "boolean", True),
188 "--verbose": ("verbose", "boolean", True),
189 "-p": ("prefix", "boolean", True),
190 "--prefix": ("prefix", "boolean", True),
191 "-G": ("portage", "boolean", False),
192 "--portage": ("portage", "boolean", False),
194 self.formatted_options = [
195 (" -h, --help", "Outputs this useage message"),
197 "Action, sets the module to gather data and output the"),
198 ("", "formatted stats/information to the screen"),
200 "Additionally include any unset USE flags and the packages"),
201 ("", "that could use them"),
203 "Used in the analyse action to output more detailed information"),
205 "Used for testing purposes only, runs report using " +
206 "a prefix keyword and 'prefix' USE flag"),
208 #"Use portage directly instead of gentoolkit's Package " +
209 #"object for some operations. Usually a little faster."),
211 self.formatted_args = [
213 "Causes the action to analyse the installed packages USE flags"),
215 "Causes the action to analyse the installed packages PKGUSE flags"),
217 "These are flags that have been set in /etc/portage/package.use"),
219 "Causes the action to analyse the installed packages keywords"),
221 "Causes the action to analyse the installed packages and the"),
223 "USE flags they were installed with"),
225 self.short_opts = "huvpG"
226 self.long_opts = ("help", "unset", "verbose", "prefix") #, "portage")
227 self.need_queries = True
228 self.arg_spec = "Target"
229 self.arg_options = ['use', 'pkguse','keywords', 'packages']
230 self.arg_option = False
233 "This is beta software and some features/options are incomplete,",
234 "some features may change in future releases includig its name.",
235 "Feedback will be appreciated, http://bugs.gentoo.org")
238 def run(self, input_args, quiet=False):
241 @param input_args: input arguments to be parsed
243 query = self.main_setup(input_args)
244 query = self.validate_query(query)
245 if query in ["use", "pkguse"]:
246 self.analyse_flags(query)
247 elif query in ["keywords"]:
248 self.analyse_keywords()
249 elif query in ["packages"]:
250 self.analyse_packages()
252 def analyse_flags(self, target):
253 """This will scan the installed packages db and analyse the
254 USE flags used for installation and produce a report on how
258 @param target: the target to be analysed, one of ["use", "pkguse"]
260 system_use = portage.settings["USE"].split()
261 self.printer = AnalysisPrinter(
263 self.options["verbose"],
265 if self.options["verbose"]:
266 cpvs = VARDB.cpv_all()
267 #cpvs = get_installed_cpvs()
268 #print "Total number of installed ebuilds =", len(cpvs)
269 flag_users = gather_flags_info(cpvs, system_use,
270 self.options["unset"], target=target.upper(),
271 use_portage=self.options['portage'])
273 cpvs = get_installed_cpvs()
274 flag_users = gather_flags_info(cpvs, system_flags=system_use,
275 include_unset=self.options["unset"], target=target.upper(),
276 use_portage=self.options['portage'])
278 flag_keys = sorted(flag_users)
279 if self.options["verbose"]:
280 print(" Flag System #pkgs cat/pkg-ver")
282 elif not self.options['quiet']:
283 print(" Flag System #pkgs")
284 blankline = lambda: None
285 for flag in flag_keys:
286 flag_pos = flag_users[flag]["+"]
288 self.printer(flag, "+", flag_pos)
290 flag_neg = flag_users[flag]["-"]
292 self.printer(flag, "-", flag_neg)
294 if "unset" in flag_users[flag] and flag_users[flag]["unset"]:
295 flag_unset = flag_users[flag]["unset"]
296 self.printer(flag, "unset", flag_unset)
298 if not self.options['quiet']:
299 print("===================================================")
300 print("Total number of flags in report =",
301 pp.output.red(str(len(flag_keys))))
302 if self.options["verbose"]:
303 print("Total number of installed ebuilds =",
304 pp.output.red(str(len([x for x in cpvs]))))
308 def analyse_keywords(self, keywords=None):
309 """This will scan the installed packages db and analyse the
310 keywords used for installation and produce a report on them.
313 system_keywords = portage.settings["ACCEPT_KEYWORDS"]
314 arch = portage.settings["ARCH"]
315 if self.options["prefix"]:
316 # build a new keyword for testing
317 system_keywords = "~" + arch + "-linux"
318 if self.options["verbose"] or self.options["prefix"]:
319 print("Current system ARCH =", arch)
320 print("Current system ACCEPT_KEYWORDS =", system_keywords)
321 system_keywords = system_keywords.split()
322 self.printer = AnalysisPrinter(
324 self.options["verbose"],
326 self.analyser = KeywordAnalyser( arch, system_keywords, VARDB)
327 #self.analyser.set_order(portage.settings["USE"].split())
329 test_use = portage.settings["USE"].split()
330 if self.options['prefix'] and 'prefix' not in test_use:
331 print("ANALYSE_KEYWORDS() 'prefix' flag not found in system",
332 "USE flags!!! appending for testing")
334 test_use.append('prefix')
335 self.analyser.set_order(test_use)
338 if self.options["verbose"]:
339 cpvs = VARDB.cpv_all()
340 #print "Total number of installed ebuilds =", len(cpvs)
341 keyword_users = gather_keywords_info(
343 system_keywords=system_keywords,
344 use_portage=self.options['portage'],
345 keywords=keywords, analyser = self.analyser
349 keyword_users = gather_keywords_info(
350 system_keywords=system_keywords,
351 use_portage=self.options['portage'],
353 analyser = self.analyser
355 blankline = lambda: None
357 keyword_keys = sorted(keyword_users)
358 if self.options["verbose"]:
359 print(" Keyword System #pkgs cat/pkg-ver")
360 elif not self.options['quiet']:
361 print(" Keyword System #pkgs")
362 for keyword in keyword_keys:
363 kwd_stable = keyword_users[keyword]["stable"]
365 self.printer(keyword, " ", kwd_stable)
367 kwd_testing = keyword_users[keyword]["testing"]
369 self.printer(keyword, "~", kwd_testing)
371 kwd_missing = keyword_users[keyword]["missing"]
373 self.printer(keyword, "-", kwd_missing)
375 if not self.options['quiet']:
376 if self.analyser.mismatched:
377 print("_________________________________________________")
378 print(("The following packages were found to have a \n" +
379 "different recorded ARCH than the current system ARCH"))
380 for cpv in self.analyser.mismatched:
381 print("\t", pp.cpv(cpv))
382 print("===================================================")
383 print("Total number of keywords in report =",
384 pp.output.red(str(len(keyword_keys))))
385 if self.options["verbose"]:
386 print("Total number of installed ebuilds =",
387 pp.output.red(str(len(cpvs))))
391 def analyse_packages(self):
392 """This will scan the installed packages db and analyse the
393 USE flags used for installation and produce a report.
396 @param target: the target to be analysed, one of ["use", "pkguse"]
398 system_use = portage.settings["USE"].split()
399 if self.options["verbose"]:
400 cpvs = VARDB.cpv_all()
403 cpvs = get_installed_cpvs()
406 self.printer = AnalysisPrinter(
408 self.options["verbose"],
412 flags = FlagAnalyzer(
414 filter_defaults=False,
418 if self.options["verbose"]:
419 print(" cat/pkg-ver USE Flags")
420 # "app-emulation/emul-linux-x86-sdl-20100915 ...."
422 elif not self.options['quiet']:
423 print(" cat/pkg-ver USE Flags")
424 blankline = lambda: None
426 (flag_plus, flag_neg, cleaned) = flags.analyse_cpv(cpv)
427 if self.options["unset"]:
428 self.printer(cpv, "", (flag_plus, flag_neg, cleaned))
430 self.printer(cpv, "", (flag_plus, [], cleaned))
431 if not self.options['quiet']:
432 print("===================================================")
433 print("Total number of installed ebuilds =",
434 pp.output.red(str(len([x for x in cpvs]))))
438 def main(input_args):
439 """Common starting method by the analyse master
440 unless all modules are converted to this class method.
442 @param input_args: input args as supplied by equery master module.
444 query_module = Analyse()
445 query_module.run(input_args, gentoolkit.CONFIG['quiet'])
447 # vim: set ts=4 sw=4 tw=79: