Coverage for src/features/actions.py: 100.00%
56 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-22 10:53 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-22 10:53 +0000
1#!/usr/bin/env python3
3# Standard libraries
4from argparse import Namespace
5from typing import List, Optional
7# Components
8from ..lib.executor import Executor
10# ActionsFeature class
11class ActionsFeature:
13 # Members
14 __actions: List[str]
15 __executor: Optional[Executor] = None
16 __result: bool
18 # Key action class, pylint: disable=too-few-public-methods
19 class ActionKey:
20 def __init__(self, key: str) -> None:
21 self.key = str(key)
23 # Key action class, pylint: disable=too-few-public-methods
24 class ActionKeyControl:
25 def __init__(self, key: str) -> None:
26 self.key = str(key)
28 # Finish action class, pylint: disable=too-few-public-methods
29 class ActionFinish:
30 def __init__(self) -> None:
31 self.finish = True
33 # Read action class, pylint: disable=too-few-public-methods
34 class ActionRead:
35 def __init__(self) -> None:
36 self.read = True
38 # Wait action class, pylint: disable=too-few-public-methods
39 class ActionWait:
40 def __init__(self, wait: str) -> None:
41 self.wait = float(wait)
43 # Constructor
44 def __init__(self, command: str, options: Namespace) -> None:
46 # Store actions
47 self.__actions = options.actions
49 # Configure executor
50 Executor.configure(
51 host=options.host,
52 tool=options.tool,
53 masks=options.masks,
54 )
56 # Create executor
57 try:
58 self.__result = False
59 self.__executor = Executor(
60 command=command, delay_init=options.delay_init,
61 delay_press=options.delay_press, delay_prompt=options.delay_prompt,
62 hold_prompt=options.hold_prompt, workdir=options.workdir)
64 # Intercept interruptions
65 except KeyboardInterrupt:
66 self.finish(force=True)
68 # Finish
69 def finish(self, force: bool = False) -> None:
71 # Finish executor
72 if self.__executor:
73 self.__result = self.__executor.finish(force=force) == 0
74 self.__executor = None
76 # Run
77 def run(self) -> bool:
79 # Wrap executor
80 try:
82 # Interact with executor
83 for index, action in enumerate(self.__actions if self.__actions else []):
85 # Validate executor
86 if not self.__executor:
87 break
89 # Key actions
90 if isinstance(action, ActionsFeature.ActionKey):
91 self.__executor.press(action.key)
93 # Ctrl+key actions
94 if isinstance(action, ActionsFeature.ActionKeyControl):
95 self.__executor.press(action.key, control=True)
97 # Read actions
98 elif isinstance(action, ActionsFeature.ActionRead):
99 self.__executor.read()
100 break
102 # Wait actions
103 elif isinstance(action, ActionsFeature.ActionWait):
104 self.__executor.wait(action.wait)
106 # Finish actions
107 elif isinstance(action, ActionsFeature.ActionFinish):
108 self.finish(force=True)
109 break
111 # Read outputs
112 next_finish = index + 1 < len(self.__actions) and isinstance(
113 self.__actions[index + 1], ActionsFeature.ActionFinish)
114 if not next_finish:
115 self.__executor.read()
117 # Catch interruptions
118 except KeyboardInterrupt:
119 self.finish(force=True)
121 # Finish executor
122 self.finish()
124 # Result
125 return self.__result