Skip to content

Commit

Permalink
refactor(launcher): add RunningStep interface (#728)
Browse files Browse the repository at this point in the history
  • Loading branch information
miltolstoy authored Aug 3, 2022
1 parent 84ccad4 commit 704a180
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 23 deletions.
28 changes: 17 additions & 11 deletions universum/modules/launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from . import automation_server, api_support, artifact_collector, reporter, code_report_collector
from .output import HasOutput, Output
from .project_directory import ProjectDirectory
from .structure_handler import HasStructure
from .structure_handler import HasStructure, RunningStepBase

__all__ = [
"Launcher",
Expand Down Expand Up @@ -159,7 +159,7 @@ def get_match_patterns(filters: Union[str, List[str]]) -> Tuple[List[str], List[
return include, exclude


class RunningStep:
class RunningStep(RunningStepBase):
# TODO: change to non-singleton module and get all dependencies by ourselves
def __init__(self, item: configuration_support.Step,
out: Output,
Expand All @@ -184,6 +184,7 @@ def __init__(self, item: configuration_support.Step,
self._is_background = background
self._postponed_out: List[Tuple[Callable[[str], None], str]] = []
self._needs_finalization: bool = True
self._error: Optional[str] = None

def prepare_command(self) -> bool: # FIXME: refactor
if not self.configuration.command:
Expand All @@ -199,13 +200,15 @@ def prepare_command(self) -> bool: # FIXME: refactor

return True

def start(self) -> Optional[str]:
def start(self):
self._error = None
try:
if not self.prepare_command():
self._needs_finalization = False
return None
return
except CiException as ex:
return str(ex)
self._error = str(ex)
return

self._postponed_out = []
self.process = self.cmd(*self.configuration.command[1:],
Expand All @@ -222,8 +225,6 @@ def start(self) -> Optional[str]:
if self.file:
self.file.write("$ " + log_cmd + "\n")

return None

def handle_stdout(self, line: str = "") -> None:
line = utils.trim_and_convert_to_unicode(line)

Expand Down Expand Up @@ -253,12 +254,13 @@ def add_tag(self, tag: str) -> None:
else:
self.out.log("Tag '" + tag + "' added to build.")

def finalize(self) -> Optional[str]:
def finalize(self) -> None:
self._error = None
if not self._needs_finalization:
if self._is_background:
self._is_background = False
self.out.log("Nothing was executed: this background step had no command")
return None
return
try:
text = ""
try:
Expand All @@ -277,17 +279,21 @@ def finalize(self) -> Optional[str]:
if self.file:
self.file.write(text + "\n")
self.add_tag(self.configuration.fail_tag)
return text
self._error = text
return

self.add_tag(self.configuration.pass_tag)
return None
return

finally:
self.handle_stdout()
if self.file:
self.file.close()
self._is_background = False

def get_error(self) -> Optional[str]:
return self._error

def _handle_postponed_out(self) -> None:
for item in self._postponed_out:
item[0](item[1])
Expand Down
41 changes: 29 additions & 12 deletions universum/modules/structure_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import contextlib
import copy

from abc import ABC, abstractmethod
from typing import Callable, ClassVar, List, Optional, TypeVar, Union, Generator
from typing_extensions import TypedDict
from ..configuration_support import Step, Configuration
Expand Down Expand Up @@ -66,10 +67,25 @@ def is_successful(self) -> bool:
class BackgroundStepInfo(TypedDict):
name: str
block: Block
finalizer: Callable[[], None]
process: RunningStepBase
is_critical: bool


class RunningStepBase(ABC):

@abstractmethod
def start(self) -> None:
pass

@abstractmethod
def finalize(self) -> None:
pass

@abstractmethod
def get_error(self) -> Optional[str]:
pass


class StructureHandler(HasOutput):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
Expand Down Expand Up @@ -136,27 +152,28 @@ def block(self, *, block_name: str, pass_errors: bool) -> Generator:
self.close_block()

def execute_one_step(self, configuration: Step,
step_executor: Callable) -> Optional[str]:
# step_executor is [[Step], Step], but referring to Step creates circular dependency
process = step_executor(configuration)
step_executor: Callable[[Step], RunningStepBase]) -> Optional[str]:
process: RunningStepBase = step_executor(configuration)

error: Optional[str] = process.start()
if error is not None:
return error
process.start()
if process.get_error() is not None:
return process.get_error()

if not configuration.background:
error = process.finalize()
return error # could be None or error message
process.finalize()
return process.get_error() # could be None or error message

self.out.log("This step is marked to be executed in background")
self.active_background_steps.append({'name': configuration.name,
'block': self.get_current_block(),
'finalizer': process.finalize,
'process': process,
'is_critical': configuration.critical})
return None

def finalize_background_step(self, background_step: BackgroundStepInfo):
error = background_step['finalizer']()
def finalize_background_step(self, background_step: BackgroundStepInfo) -> bool:
process: RunningStepBase = background_step['process']
process.finalize()
error: Optional[str] = process.get_error()
if error is not None:
self.fail_block(background_step['block'], error)
self.fail_current_block()
Expand Down

0 comments on commit 704a180

Please sign in to comment.