blob: 5775ce1185200f699e2f8eec449c48492790373f [file] [log] [blame]
# 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)