31c00a114040b3f37f017b00b8a3cbcc5bcbc262
[gentoolkit.git] / pym / gentoolkit / analyse / rebuild.py
1 #!/usr/bin/python
2 #
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
6 #
7
8
9 """Provides a rebuild file of USE flags or keywords used and by
10 what packages according to the Installed package database"""
11
12 from __future__ import print_function
13
14
15 # Move to Imports section after Python 2.6 is stable
16
17
18 import sys
19
20 from portage import os
21
22 import gentoolkit
23 from gentoolkit.dbapi import PORTDB, VARDB
24 from gentoolkit.analyse.base import ModuleBase
25 from gentoolkit import pprinter as pp
26 from gentoolkit.analyse.lib import (get_installed_use, get_flags,
27         abs_flag, abs_list, FlagAnalyzer)
28 from gentoolkit.analyse.output import RebuildPrinter
29
30 import portage
31
32
33 def cpv_all_diff_use(
34                 cpvs=None,
35                 system_flags=None,
36                 #  override-able for testing
37                 _get_flags=get_flags,
38                 _get_used=get_installed_use
39                 ):
40         if cpvs is None:
41                 cpvs = VARDB.cpv_all()
42         cpvs.sort()
43         data = {}
44         # pass them in to override for tests
45         flags = FlagAnalyzer(system_flags,
46                 _get_flags=_get_flags,
47                 _get_used=get_installed_use
48         )
49         for cpv in cpvs:
50                 plus, minus, unset = flags.analyse_cpv(cpv)
51                 for flag in minus:
52                         plus.add("-"+flag)
53                 if len(plus):
54                         data[cpv] = list(plus)
55         return data
56
57
58 class Rebuild(ModuleBase):
59         """Installed db analysis tool to query the installed databse
60         and produce/output stats for USE flags or keywords/mask.
61         The 'rebuild' action output is in the form suitable for file type output
62         to create a new package.use, package.keywords, package.unmask 
63         type files in the event of needing to rebuild the
64         /etc/portage/* user configs
65         """
66         def __init__(self):
67                 ModuleBase.__init__(self)
68                 self.module_name = "rebuild"
69                 self.options = {
70                         "use": False,
71                         "keywords": False,
72                         "unmask": False,
73                         "verbose": False,
74                         "quiet": False,
75                         "exact": False,
76                         "pretend": False,
77                         #"unset": False
78                 }
79                 self.module_opts = {
80                         "-p": ("pretend", "boolean", True),
81                         "--pretend": ("pretend", "boolean", True),
82                         "-e": ("exact", "boolean", True),
83                         "--exact": ("exact", "boolean", True),
84                         "-v": ("verbose", "boolean", True),
85                         "--verbose": ("verbose", "boolean", True),
86                 }
87                 self.formatted_options = [
88                         ("    -h, --help",  "Outputs this useage message"),
89                         ("    -p, --pretend", "Does not actually create the files."),
90                         ("    ", "It directs the outputs to the screen"),
91                         ("    -e, --exact", "will atomize the package with a"),
92                         ("  ", "leading '=' and include the version")
93                 ]
94                 self.formatted_args = [
95                         ("    use", 
96                         "causes the action to analyse the installed packages USE flags"),
97                         ("    keywords",
98                         "causes the action to analyse the installed packages keywords"),
99                         ("    unmask",
100                         "causes the action to analyse the installed packages " + \
101                         "current mask status")
102                 ]
103                 self.short_opts = "hepv"
104                 self.long_opts = ("help", "exact", "pretend", "verbose")
105                 self.need_queries = True
106                 self.arg_spec = "TargetSpec"
107                 self.arg_options = ['use', 'keywords', 'unmask']
108                 self.arg_option = False
109
110
111
112         def run(self, input_args, quiet=False):
113                 """runs the module
114                 
115                 @param input_args: input arguments to be parsed
116                 """
117                 self.options['quiet'] = quiet
118                 query = self.main_setup(input_args)
119                 query = self.validate_query(query)
120                 if query in ["use"]:
121                         self.rebuild_use()
122                 elif query in ["keywords"]:
123                         self.rebuild_keywords()
124                 elif query in ["mask"]:
125                         self.rebuild_mask()
126
127
128         def rebuild_use(self):
129                 if not self.options["quiet"]:
130                         print()
131                         print("  -- Scanning installed packages for USE flag settings that")
132                         print("     do not match the default settings")
133                 system_use = portage.settings["USE"].split()
134                 output = RebuildPrinter("use", self.options["pretend"], self.options["exact"])
135                 pkgs = cpv_all_diff_use(system_flags=system_use)
136                 pkg_count = len(pkgs)
137                 if self.options["verbose"]:
138                         print()
139                         print((pp.emph("  -- Found ") +  pp.number(str(pkg_count)) +
140                                 pp.emph(" packages that need entries")))
141                         #print pp.emph("     package.use to maintain their current setting")
142                 if pkgs:
143                         pkg_keys = list(pkgs.keys())
144                         pkg_keys.sort()
145                         #print len(pkgs)
146                         if self.options["pretend"] and not self.options["quiet"]:
147                                 print() 
148                                 print(pp.globaloption(
149                                         "  -- These are the installed packages & flags " +
150                                         "that were detected"))
151                                 print(pp.globaloption("     to need flag settings other " +
152                                         "than the defaults."))
153                                 print()
154                         elif not self.options["quiet"]:
155                                 print("  -- preparing pkgs for file entries")
156                         flag_count = 0
157                         unique_flags = set()
158                         for pkg in pkg_keys:
159                                 if self.options['verbose']:
160                                         flag_count += len(pkgs[pkg])
161                                         unique_flags.update(abs_list(pkgs[pkg]))
162                                 output(pkg, pkgs[pkg])
163                         if self.options['verbose']:
164                                 message = (pp.emph("     ") +
165                                         pp.number(str(len(unique_flags))) +
166                                         pp.emph(" unique flags\n") + "     " +
167                                         pp.number(str(flag_count))+
168                                         pp.emph(" flag entries\n") + "     " +
169                                         pp.number(str(pkg_count)) +
170                                         pp.emph(" different packages"))
171                                 print()
172                                 print(pp.globaloption("  -- Totals"))
173                                 print(message)
174                                 #print
175                                 #unique = list(unique_flags)
176                                 #unique.sort()
177                                 #print unique
178                         if not self.options["pretend"]:
179                                 filepath = os.path.expanduser('~/package.use.test')
180                                 self.save_file(filepath, output.use_lines)
181
182         def rebuild_keywords(self):
183                 print("Module action not yet available")
184                 print()
185
186         def rebuild_mask(self):
187                 print("Module action not yet available")
188                 print()
189
190
191         def save_file(self, filepath, data):
192                 """Writes the data to the file determined by filepath
193                 
194                 @param filepath: string. eg. '/path/to/filename'
195                 @param data: list of lines to write to filepath
196                 """
197                 if  not self.options["quiet"]:
198                         print('   - Saving file: %s' %filepath)
199                 #print "Just kidding :)  I haven't codded it yet"
200                 with open(filepath, "w") as output:
201                         output.write('\n'.join(data))
202                 print("   - Done")
203
204
205 def main(input_args):
206         """Common starting method by the analyse master 
207         unless all modules are converted to this class method.
208         
209         @param input_args: input args as supplied by equery master module.
210         """
211         query_module = Rebuild()
212         query_module.run(input_args, gentoolkit.CONFIG['quiet'])
213
214 # vim: set ts=4 sw=4 tw=79:
215