1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2025-11-13 01:19:16 +01:00
lodel2_mirror/lodel/plugin/scripts.py
2017-01-12 17:06:31 +01:00

224 lines
7.9 KiB
Python

import argparse
import sys
from lodel.context import LodelContext
LodelContext.expose_modules(globals(), {
'lodel.logger': 'logger',
'lodel.exceptions': ['LodelException', 'LodelExceptions',
'LodelFatalError', 'DataNoneValid', 'FieldValidationError']})
##@defgroup lodel2_script Administration scripts
#@ingroup lodel2_plugins
##@package lodel.plugin.script
#@brief Lodel2 utility for writting administration scripts
#@ingroup lodel2_plugins
#@ingroup lodel2_script
##@brief Stores registered scripts
#@todo store it in MetaLodelScript
__registered_scripts = dict()
##@brief LodelScript metaclass that allows to "catch" child class
#declaration
#@ingroup lodel2_script
#@ingroup lodel2_plugins
#
#Automatic action registration on child class declaration
class MetaLodelScript(type):
def __init__(self, name, bases, attrs):
#Here we can store all child classes of LodelScript
super().__init__(name, bases, attrs)
if len(bases) == 1 and bases[0] == object:
return
self.__register_script(name)
#_action initialization
if self._action is None:
logger.warning("%s._action is None. Trying to use class name as \
action identifier" % name)
self._action = name
self._action = self._action.lower()
if self._description is None:
self._description = self._default_description()
self._parser = argparse.ArgumentParser(
prog = self._prog_name(),
description = self._description)
self.argparser_config(self._parser)
##@brief Handles script registration
#@note Script list is maitained in
#lodel.plugin.admin_script.__registered_scripts
def __register_script(self, name):
if self._action is None:
logger.warning("%s._action is None. Trying to use class name as \
action identifier" % name)
self._action = name
self._action = self._action.lower()
script_registration(self._action, self)
def __str__(self):
return '%s : %s' % (self._action, self._description)
##@brief Class designed to facilitate custom script writting
#@ingroup lodel2_plugins
#@ingroup lodel2_script
class LodelScript(object, metaclass=MetaLodelScript):
##@brief A string to identify the action
_action = None
##@brief Script descripiton (argparse argument)
_description = None
##@brief argparse.ArgumentParser instance
_parser = None
##@brief No instanciation
def __init__(self):
raise NotImplementedError("Static class")
##@brief Virtual method. Designed to initialize arguement parser.
#@param parser ArgumentParser : Child class argument parser instance
#@return MUST return the argument parser (NOT SURE ABOUT THAT !! Maybe it \
#works by reference)
@classmethod
def argparser_config(cls, parser):
raise LodelScriptError("LodelScript.argparser_config() is a pure \
virtual method! MUST be implemented by ALL child classes")
##@brief Virtual method. Run the script
#@return None or an integer that will be the script return code
@classmethod
def run(cls, args):
raise LodelScriptError("LodelScript.run() is a pure virtual method. \
MUST be implemented by ALL child classes")
##@brief Called by main_run() to execute a script.
#
#Handles argument parsing and then call LodelScript.run()
@classmethod
def _run(cls):
args = cls._parser.parse_args()
return cls.run(args)
##@brief Append action name to the prog name
#@note See argparse.ArgumentParser() prog argument
@classmethod
def _prog_name(cls):
return '%s %s' % (sys.argv[0], cls._action)
##@brief Return the default description for an action
@classmethod
def _default_description(cls):
return "Lodel2 script : %s" % cls._action
@classmethod
def help_exit(cls,msg = None, return_code = 1, exit_after = True):
if not (msg is None):
print(msg, file=sys.stderr)
cls._parser.print_help()
if exit_after:
exit(1)
def script_registration(action_name, cls):
__registered_scripts[action_name] = cls
logger.info("New script registered : %s" % action_name)
##@brief Return a list containing all available actions
def _available_actions():
return [ act for act in __registered_scripts ]
##@brief Returns default runner argument parser
def _default_parser():
action_list = _available_actions()
if len(action_list) > 0:
action_list = ', '.join(sorted(action_list))
else:
action_list = 'NO SCRIPT FOUND !'
parser = argparse.ArgumentParser(description = "Lodel2 script runner")
parser.add_argument('-L', '--list-actions', action='store_true',
default=False, help="List available actions")
parser.add_argument('action', metavar="ACTION", type=str,
help="One of the following actions : %s" % action_list, nargs='?')
parser.add_argument('option', metavar="OPTIONS", type=str, nargs='*',
help="Action options. Use %s ACTION -h to have help on a specific \
action" % sys.argv[0])
return parser
##@brief Main function of lodel_admin.py script
#
#This function take care to run the good plugins and clean sys.argv from
#action name before running script
#
#@return DO NOT RETURN BUT exit() ONCE SCRIPT EXECUTED !!
def main_run():
default_parser = _default_parser()
if len(sys.argv) == 1:
default_parser.print_help()
exit(1)
#preparing sys.argv (deleting action)
action = sys.argv[1].lower()
if action not in __registered_scripts:
#Trying to parse argument with default parser
args = default_parser.parse_args()
if args.list_actions:
print("Available actions :")
for sname in sorted(__registered_scripts.keys()):
print("\t- %s" % __registered_scripts[sname])
exit(0)
print("Unknow action '%s'\n" % action, file=sys.stderr)
default_parser.print_help()
exit(1)
#OK action is known, preparing argv to pass it to the action script
del(sys.argv[1])
script = __registered_scripts[action]
ret = script._run()
ret = 0 if ret is None else ret
exit(ret)
##@page lodel2_script_doc Lodel2 scripting
#@ingroup lodel2_script
#
#@section lodel2_script_adm Lodel2 instance administration scripts
#
#Lodel2 provides instance administration operation using Makefiles or
#lodel_admin.py script ( see @ref lodel2_instance_admin ).
#
#The lodel_admin.py script take as first option an action. Each action
#correspond to a sub-script with it's own options etc. To get a list
#of all available action run <code>python3 lodel_admin.py -L</code>.
#
#@section lodel2_script_action lodel_admin.py actions
#
#Action implementation is done by class inheritance. To create a new action
#write a @ref lodel.plugin.scripts.LodelScript "LodelScript" derived class (
#see @ref lodel.plugin.core_scripts "core_scripts.py" file as example )
#
#@subsection lodel2_script_inheritance LodelScript inheritance
#
#In order to implement properly a new action you have to write a new
#@ref lodel.plugin.scripts.LodelScript "LodelScript" derivated class.
#Some methods and attributes are mandatory to write a fully functionnal
#derivated class. Here is a list :
#
#- mandatory methods
# - @ref plugin.scripts.LodelScript.argparser_config() "argparser_config()" :
#(classmethod) initialize argparse.Parser
# - @ref plugin.scripts.LodelScript.run() "run()" : (classmethod) contains the
#code that runs to perform the action
#- mandatory attributes
# - @ref plugin.scripts.LodelScript::_action "_action" : (class attribute)
#stores action name
# - @ref plugin.scripts.LodelScript::_description "_description" : (class
#attribute) sotres a short action description
#
#@note On script's action registration : once child class is written you only
#need to import it to trigger script's action registration (see
#@ref plugin.scripts.MetaLodelScript )
#