# Copyright 2005-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import print_function import sys import textwrap from optparse import OptionParser, OptionValueError import portage from portage import os from portage.emaint.module import Modules from portage.emaint.progress import ProgressBar from portage.emaint.defaults import DEFAULT_OPTIONS class OptionItem(object): """class to hold module OptionParser options data """ def __init__(self, opt, parser): """ @type opt: dictionary @param opt: options parser options """ self.parser = parser self.short = opt['short'] self.long = opt['long'] self.help = opt['help'] self.status = opt['status'] self.func = opt['func'] self.action = opt.get('action', "callback") self.type = opt.get('type', None) self.dest = opt.get('dest', None) self.callback = opt.get('callback', self._exclusive) self.callback_kwargs = opt.get('callback_kwargs', {"var":"action"}) def _exclusive(self, option, *args, **kw): """Generic check for the 2 default options """ var = kw.get("var", None) if var is None: raise ValueError("var not specified to exclusive()") if getattr(self.parser, var, ""): raise OptionValueError("%s and %s are exclusive options" % (getattr(self.parser, var), option)) setattr(self.parser, var, str(option)) def check_action(self, action): """Checks if 'action' is the same as this option @type action: string @param action: the action to compare @rtype: boolean """ if action == self.action: return True elif action == '/'.join([self.short, self.long]): return True return False def usage(module_controller): _usage = "usage: emaint [options] COMMAND" desc = "The emaint program provides an interface to system health " + \ "checks and maintenance. See the emaint(1) man page " + \ "for additional information about the following commands:" _usage += "\n\n" for line in textwrap.wrap(desc, 65): _usage += "%s\n" % line _usage += "\nCommands:\n" _usage += " %s" % "all".ljust(15) + \ "Perform all supported commands\n" textwrap.subsequent_indent = ' '.ljust(17) for mod in module_controller.module_names: desc = textwrap.wrap(module_controller.get_description(mod), 65) _usage += " %s%s\n" % (mod.ljust(15), desc[0]) for d in desc[1:]: _usage += " %s%s\n" % (' '.ljust(15), d) return _usage def module_opts(module_controller, module): _usage = " %s module options:\n" % module opts = module_controller.get_func_descriptions(module) if opts == {}: opts = DEFAULT_OPTIONS for opt in sorted(opts): optd = opts[opt] opto = " %s, %s" %(optd['short'], optd['long']) _usage += '%s %s\n' % (opto.ljust(15),optd['help']) _usage += '\n' return _usage class TaskHandler(object): """Handles the running of the tasks it is given """ def __init__(self, show_progress_bar=True, verbose=True, callback=None): self.show_progress_bar = show_progress_bar self.verbose = verbose self.callback = callback self.isatty = os.environ.get('TERM') != 'dumb' and sys.stdout.isatty() self.progress_bar = ProgressBar(self.isatty, title="Emaint", max_desc_length=27) def run_tasks(self, tasks, func, status=None, verbose=True, options=None): """Runs the module tasks""" if tasks is None or func is None: return for task in tasks: inst = task() show_progress = self.show_progress_bar and self.isatty # check if the function is capable of progressbar # and possibly override it off if show_progress and hasattr(inst, 'can_progressbar'): show_progress = inst.can_progressbar(func) if show_progress: self.progress_bar.reset() self.progress_bar.set_label(func + " " + inst.name()) onProgress = self.progress_bar.start() else: onProgress = None kwargs = { 'onProgress': onProgress, # pass in a copy of the options so a module can not pollute or change # them for other tasks if there is more to do. 'options': options.copy() } result = getattr(inst, func)(**kwargs) if show_progress: # make sure the final progress is displayed self.progress_bar.display() print() self.progress_bar.stop() if self.callback: self.callback(result) def print_results(results): if results: print() print("\n".join(results)) print("\n") def emaint_main(myargv): # Similar to emerge, emaint needs a default umask so that created # files (such as the world file) have sane permissions. os.umask(0o22) module_controller = Modules(namepath="portage.emaint.modules") module_names = module_controller.module_names[:] module_names.insert(0, "all") parser = OptionParser(usage=usage(module_controller), version=portage.VERSION) # add default options parser_options = [] for opt in DEFAULT_OPTIONS: parser_options.append(OptionItem(DEFAULT_OPTIONS[opt], parser)) for mod in module_names[1:]: desc = module_controller.get_func_descriptions(mod) if desc: for opt in desc: parser_options.append(OptionItem(desc[opt], parser)) for opt in parser_options: parser.add_option(opt.short, opt.long, help=opt.help, action=opt.action, type=opt.type, dest=opt.dest, callback=opt.callback, callback_kwargs=opt.callback_kwargs) parser.action = None (options, args) = parser.parse_args(args=myargv) #print('options', options, '\nargs', args, '\naction', parser.action) if len(args) != 1: parser.error("Incorrect number of arguments") if args[0] not in module_names: parser.error("%s target is not a known target" % args[0]) if parser.action: action = parser.action else: action = "-c/--check" long_action = action.split('/')[1].lstrip('-') #print("DEBUG: action = ", action, long_action) if args[0] == "all": tasks = [] for m in module_names[1:]: #print("DEBUG: module: %s, functions: " %(m, str(module_controller.get_functions(m)))) if long_action in module_controller.get_functions(m): tasks.append(module_controller.get_class(m)) elif long_action in module_controller.get_functions(args[0]): tasks = [module_controller.get_class(args[0] )] else: print("\nERROR: module '%s' does not have option '%s'\n" %(args[0], action)) print(module_opts(module_controller, args[0])) sys.exit(1) func = status = None for opt in parser_options: if opt.check_action(action): status = opt.status func = opt.func break # need to pass the parser options dict to the modules # so they are available if needed. task_opts = options.__dict__ taskmaster = TaskHandler(callback=print_results) taskmaster.run_tasks(tasks, func, status, options=task_opts)