fmartingr
/
jeeves
Archived
1
0
Fork 0

Using better action ids

This commit is contained in:
Felipe Martin 2020-03-04 23:25:12 +01:00
parent 2487078c8e
commit 33af22443e
Signed by: fmartingr
GPG Key ID: 716BC147715E716F
6 changed files with 41 additions and 35 deletions

View File

@ -5,10 +5,13 @@ import click
from jeeves.cli.echo import info, error, title, success from jeeves.cli.echo import info, error, title, success
from jeeves.core.parsers import FlowParser from jeeves.core.parsers import FlowParser
from jeeves.core.executor import Executor from jeeves.core.executor import Executor
from jeeves.core.registry import ActionRegistry
@click.group() @click.group()
def main(): def main():
# TODO: Check if Jeevesfile in cwd, execute directly
ActionRegistry.autodiscover()
pass pass

View File

@ -1,4 +1,12 @@
PROVIDED_ACTIONS = [ from jeeves.core.actions.shell import ScriptAction
"jeeves.core.actions.shell:ScriptAction", from jeeves.core.actions.docker import DockerBuildAction, DockerRunAction
"jeeves.core.actions.docker:DockerAction",
__all__ = [
# Shell
ScriptAction,
# Docker
DockerBuildAction,
DockerRunAction,
] ]
PROVIDED_ACTIONS = {action.id: action for action in __all__}

View File

@ -6,7 +6,7 @@ from typing import Text
import pydantic import pydantic
from jeeves.core.objects import Result from jeeves.core.objects import Result
from .base import Action from jeeves.core.actions.base import Action
class ScriptAction(Action): class ScriptAction(Action):

View File

@ -1,6 +1,7 @@
import traceback import traceback
from jeeves.core.objects import Flow, Result, Execution, ExecutionStep from jeeves.core.objects import Flow, Result, Execution, ExecutionStep
from jeeves.core.registry import ActionRegistry
class Executor: class Executor:
@ -20,7 +21,8 @@ class Executor:
def execute_step(self, step: ExecutionStep): def execute_step(self, step: ExecutionStep):
try: try:
step.result = step.task.action.execute(workspace=self._execution.workspace) action = ActionRegistry.get_action_cls(step.task.type)(parameters=step.task.parameters)
step.result = action.execute(workspace=self._execution.workspace)
except Exception as error: except Exception as error:
# Catch unhandled exceptions, mark the result as unsuccessful # Catch unhandled exceptions, mark the result as unsuccessful
# and append the error as output. # and append the error as output.

View File

@ -6,8 +6,6 @@ from dataclasses import field
import pydantic import pydantic
from jeeves.core.registry import ActionRegistry
class BaseObject(pydantic.BaseModel): class BaseObject(pydantic.BaseModel):
pass pass
@ -23,12 +21,12 @@ class Task(BaseObject):
type: Text type: Text
parameters: Optional[Dict[Any, Any]] = None parameters: Optional[Dict[Any, Any]] = None
@property
def action(self): class Argument(BaseObject):
""" name: Text
Returns the instanced :any:`jeeves.core.actions.base.Action` defined in ``type`` for this ``Task``. default: Any
""" type: Text = "text"
return ActionRegistry.get_action_cls(self.type)(parameters=self.parameters) required: bool = False
class Flow(BaseObject): class Flow(BaseObject):

View File

@ -27,47 +27,42 @@ class ActionRegistry(metaclass=Singleton):
"""Loads all provided actions.""" """Loads all provided actions."""
# TODO: Third party plugins # TODO: Third party plugins
registry = cls() registry = cls()
for action_namespace in PROVIDED_ACTIONS: for action_id, action_cls in PROVIDED_ACTIONS.items():
registry.register_action(cls.get_action_cls(action_namespace)) registry.register_action(action_id, action_cls)
@classmethod @classmethod
def register_action(cls, action_cls): def register_action(cls, action_id, action_cls):
registry = cls() registry = cls()
# namespace = action_cls.id
namespace = f"{action_cls.__module__}:{action_cls.__name__}"
if namespace in registry.actions: if action_id in registry.actions:
raise cls.ActionNamespaceConflict( raise cls.ActionIDConflict(
f"Namespace {namespace} is already registered" f"Action ID '{action_id}' is already registered"
) )
registry.actions[namespace] = action_cls registry.actions[action_id] = action_cls
@classmethod @classmethod
def get_action_cls(cls, namespace) -> Type[Action]: def get_action_cls(cls, action_id) -> Type[Action]:
"""Returns the class for the provided action namespace""" """Returns the class for the provided action ID"""
# Right now actions are being imported and returned dinamically because it's easier, # Right now actions are being imported and returned dinamically because it's easier,
# but we will need a way of autodiscover all (or register them manually) and # but we will need a way of autodiscover all (or register them manually) and
# referencing them on a list so the user knows which actions are available. # referencing them on a list so the user knows which actions are available.
modulename, clsname = namespace.split(":")
try: try:
module = __import__(f"{modulename}", fromlist=(clsname,), level=0) return cls.actions[action_id]
action_cls = getattr(module, clsname) except IndexError as error:
return action_cls raise cls.ActionDoesNotExist(f"Error importing action {action_id}: {error}")
except ModuleNotFoundError as error:
raise cls.ActionDoesNotExist(f"Error importing action {namespace}: {error}")
@classmethod @classmethod
def get_action( def get_action(
cls, namespace: Text, parameters: Optional[Dict[Any, Any]] = None cls, action_id: Text, parameters: Optional[Dict[Any, Any]] = None
) -> Action: ) -> Action:
"""Returns the instanced action for the provided namespace""" """Returns the instanced action for the provided action_id"""
action_cls: Type[Action] = cls.get_action_cls(namespace) action_cls: Type[Action] = cls.get_action_cls(action_id)
return action_cls(parameters=parameters or {}) return action_cls(parameters=parameters or {})
class ActionNamespaceConflict(Exception): class ActionIDConflict(Exception):
"""Raised when an action is defined with an already registered namespace""" """Raised when an action is defined with an already registered action id"""
pass pass