baseimage-tutorial-framework/lib/tfw/yaml_fsm.py

65 lines
2.0 KiB
Python

from subprocess import Popen, run
from functools import partial
from contextlib import suppress
import yaml
from transitions import State
from tfw import FSMBase
class YamlFSM(FSMBase):
def __init__(self, config_file):
self.config = self.parse_config(config_file)
self.for_config_states_and_transitions_do(self.patch_config_callbacks)
self.setup_states()
super().__init__() # FSMBase.__init__() requires states
self.for_config_states_and_transitions_do(self.subscribe_and_remove_predicates)
self.setup_transitions()
@staticmethod
def parse_config(config_file):
with open(config_file, 'r') as ifile:
return yaml.safe_load(ifile)
def setup_states(self):
self.states = [State(**state) for state in self.config['states']]
def setup_transitions(self):
for transition in self.config['transitions']:
self.add_transition(**transition)
def for_config_states_and_transitions_do(self, what):
for array in ('states', 'transitions'):
for json_obj in self.config[array]:
what(json_obj)
@staticmethod
def patch_config_callbacks(json_obj):
topatch = ('on_enter', 'on_exit', 'prepare', 'before', 'after')
for key in json_obj:
if key in topatch:
json_obj[key] = partial(run_command_async, json_obj[key])
def subscribe_and_remove_predicates(self, json_obj):
for key in json_obj:
if key == 'predicates':
for predicate in json_obj[key]:
self.subscribe_predicate(
json_obj['trigger'],
partial(
command_statuscode_is_zero,
predicate
)
)
with suppress(KeyError):
json_obj.pop('predicates')
def run_command_async(command, event):
Popen(command, shell=True)
def command_statuscode_is_zero(command):
return run(command, shell=True).returncode == 0