Change the documentation for revdep-rebuild --library.
[gentoolkit.git] / pym / gentoolkit / revdep_rebuild / rebuild.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4
5 """ Rebuild module
6
7 Main program, cli parsing and api program control and operation
8
9 Author: SÅ‚awomir Lis <lis.slawek@gmail.com>
10         revdep-rebuild original author: Stanislav Brabec
11         revdep-rebuild original rewrite Author: Michael A. Smith
12 Current Maintainer: Paul Varner <fuzzyray@gentoo.org>
13 Creation date: 2010/10/17
14 License: BSD
15 """
16
17 from __future__ import print_function
18
19 import os
20 import sys
21 import getopt
22 import logging
23 from portage.output import bold, red, blue, yellow, green, nocolor
24
25 from .analyse import analyse
26 from .stuff import get_masking_status
27 from .cache import check_temp_files, read_cache
28 from .assign import get_slotted_cps
29 from .settings import DEFAULTS
30 from . import __version__
31
32
33 APP_NAME = sys.argv[0]
34 VERSION = __version__
35
36 __productname__ = "revdep-ng"
37
38
39 # functions
40
41 def print_usage():
42         """Outputs the help message"""
43         print( APP_NAME + ': (' + VERSION +')')
44         print()
45         print('This is free software; see the source for copying conditions.')
46         print()
47         print('Usage: ' + APP_NAME + ' [OPTIONS] [--] [EMERGE_OPTIONS]')
48         print()
49         print('Broken reverse dependency rebuilder, python implementation.')
50         print()
51         print('Available options:')
52         print('''
53   -C, --nocolor         Turn off colored output
54   -d, --debug           Print debug informations
55   -e, --exact           Emerge based on exact package version
56   -h, --help            Print this usage
57   -i, --ignore          Ignore temporary files from previous runs
58                         (also won't create any)
59   -L, --library NAME    Unconditionally emerge existing packages that use
60       --library=NAME    the library with NAME. NAME can be a full or partial
61                         library name
62   -l, --no-ld-path      Do not set LD_LIBRARY_PATH
63   -o, --no-order        Do not check the build order
64                         (Saves time, but may cause breakage.)
65   -p, --pretend         Do a trial run without actually emerging anything
66                         (also passed to emerge command)
67   -q, --quiet           Be less verbose (also passed to emerge command)
68   -v, --verbose         Be more verbose (also passed to emerge command)
69 ''')
70         print( 'Calls emerge, options after -- are ignored by ' + APP_NAME)
71         print('and passed directly to emerge.')
72
73
74 def init_logger(settings):
75         """Creates and iitializes our logger according to the settings"""
76         logger = logging.getLogger()
77         log_handler = logging.StreamHandler()
78         log_fmt = logging.Formatter('%(msg)s')
79         log_handler.setFormatter(log_fmt)
80         logger.addHandler(log_handler)
81         if settings['quiet']:
82                 logger.setLevel(logging.ERROR)
83         elif settings['VERBOSITY'] == 2:
84                 logger.setLevel(logging.INFO)
85         elif settings['debug']:
86                 logger.setLevel(logging.DEBUG)
87         else:
88                 logger.setLevel(logging.WARNING)
89         return logger
90
91
92 def parse_options():
93         """Parses the command line options an sets settings accordingly"""
94
95         # TODO: Verify: options: no-ld-path, no-order, no-progress
96         #are not appliable
97
98         settings = DEFAULTS.copy()
99         try:
100                 opts, args = getopt.getopt(sys.argv[1:], 
101                         'dehiklopqvCL:P', 
102                         ['nocolor', 'debug', 'exact', 'help', 'ignore',
103                         'keep-temp', 'library=', 'no-ld-path', 'no-order',
104                         'pretend', 'no-pretend', 'no-progress', 'quiet', 'verbose'])
105
106                 for key, val in opts:
107                         if key in ('-h', '--help'):
108                                 print_usage()
109                                 sys.exit(0)
110                         elif key in ('-q', '--quiet'):
111                                 settings['quiet'] = True
112                                 settings['VERBOSITY'] = 0
113                         elif key in ('-v', '--verbose'):
114                                 settings['VERBOSITY'] = 2
115                         elif key in ('-d', '--debug'):
116                                 settings['debug'] = True
117                                 settings['VERBOSITY'] = 3
118                         elif key in ('-p', '--pretend'):
119                                 settings['PRETEND'] = True
120                         elif key == '--no-pretend':
121                                 settings['NO_PRETEND'] = True
122                         elif key in ('-e', '--exact'):
123                                 settings['EXACT'] = True
124                         elif key in ('-C', '--nocolor', '--no-color'):
125                                 settings['nocolor'] = True
126                         elif key in ('-L', '--library', '--library='):
127                                 settings['library'] = settings['library'].union(val.split(','))
128                         elif key in ('-i', '--ignore'):
129                                 settings['USE_TMP_FILES'] = False
130
131                 settings['pass_through_options'] = " " + " ".join(args)
132         except getopt.GetoptError:
133                 #logging.info(red('Unrecognized option\n'))
134                 print(red('Unrecognized option\n'))
135                 print_usage()
136                 sys.exit(2)
137         return settings
138
139
140 def rebuild(logger, assigned, settings):
141         """rebuilds the assigned pkgs"""
142         
143         args = settings['pass_through_options']
144         if settings['EXACT']:
145                 emerge_command = '=' + ' ='.join(assigned)
146         else:
147                 emerge_command = ' '.join(get_slotted_cps(assigned, logger))
148         if settings['PRETEND']:
149                 args += ' --pretend'
150         if settings['VERBOSITY'] >= 2:
151                 args += ' --verbose'
152         elif settings['VERBOSITY'] < 1:
153                 args += ' --quiet'
154         if settings['nocolor']:
155                 args += ' --color n'
156
157         if len(emerge_command) == 0:
158                 logger.warn(bold('\nThere is nothing to emerge. Exiting.'))
159                 return 0
160
161         emerge_command = emerge_command
162
163         logger.warn(yellow(
164                 '\nemerge') + args + 
165                 ' --oneshot --complete-graph=y ' +
166                 bold(emerge_command))
167         
168         success = os.system(
169                 'emerge ' + args + 
170                 ' --oneshot --complete-graph=y ' + 
171                 emerge_command)
172         return success
173
174
175 def main(settings=None, logger=None):
176         """Main program operation method....
177         
178         @param settings: dict.  defaults to settings.DEFAULTS
179         @param logger: python logging module defaults to init_logger(settings)
180         @return boolean  success/failure
181         """
182
183         if settings is None:
184                 print("NO Input settings, using defaults...")
185                 settings = DEFAULTS.copy()
186
187         if logger is None:
188                 logger = init_logger(settings)
189
190         _libs_to_check = settings['library']
191
192         if not settings['stdout'].isatty() or settings['nocolor']:
193                 nocolor()
194
195         #TODO: Development warning
196         logger.warn(blue(' * ') + 
197                 yellow('This is a development version, '
198                         'so it may not work correctly'))
199         logger.warn(blue(' * ') + 
200                 yellow('The original revdep-rebuild script is '
201                         'installed as revdep-rebuild.sh'))
202
203         if os.getuid() != 0 and not settings['PRETEND']:
204                 logger.warn(blue(' * ') + 
205                         yellow('You are not root, adding --pretend to portage options'))
206                 settings['PRETEND'] = True
207
208         if settings['library']:
209                 logger.warn(green(' * ') + 
210                         "Looking for libraries: %s" % (bold(', '.join(settings['library']))))
211
212         if settings['USE_TMP_FILES'] \
213                         and check_temp_files(settings['DEFAULT_TMP_DIR'], logger=logger):
214                 libraries, la_libraries, libraries_links, binaries = read_cache(
215                         settings['DEFAULT_TMP_DIR'])
216                 assigned = analyse(
217                         settings=settings,
218                         logger=logger,
219                         libraries=libraries,
220                         la_libraries=la_libraries, 
221                         libraries_links=libraries_links,
222                         binaries=binaries,
223                         _libs_to_check=_libs_to_check)
224         else:
225                 assigned = analyse(settings, logger, _libs_to_check=_libs_to_check)
226
227         if not assigned:
228                 logger.warn('\n' + bold('Your system is consistent'))
229                 # return the correct exit code
230                 return 0
231
232         has_masked = False
233         tmp = []
234         for ebuild in assigned:
235                 if get_masking_status(ebuild):
236                         has_masked = True
237                         logger.warn('!!! ' + red('All ebuilds that could satisfy: ') + 
238                                 green(ebuild) + red(' have been masked'))
239                 else:
240                         tmp.append(ebuild)
241         assigned = tmp
242
243         if has_masked:
244                 logger.info(red(' * ') + 
245                         'Unmask all ebuild(s) listed above and call revdep-rebuild '
246                         'again or manually emerge given packages.')
247
248         success = rebuild(logger, assigned, settings)
249         logger.debug("rebuild return code = %i" %success)
250         return success