1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
"""
This library provides a set of functions that can be used to
process the spread output.
"""
import re
from enum import Enum
class ListedEnum(Enum):
@classmethod
def list(cls) -> list[str]:
return list(map(lambda c: c.value, cls))
class ExecutionPhase(ListedEnum):
PREPARING = "Preparing"
EXECUTING = "Executing"
RESTORING = "Restoring"
class ExecutionInfo(ListedEnum):
DEBUG = "Debug"
ERROR = "Error"
WARNING = "WARNING:"
class ExecutionLevel(ListedEnum):
TASK = "task"
SUITE = "suite"
PROJECT = "project"
class GeneralAction(ListedEnum):
REBOOTING = "Rebooting"
DISCARDING = "Discarding"
ALLOCATING = "Allocating"
WAITING = "Waiting"
CONNECTING = "Connecting"
SENDING = "Sending"
class GeneralActionStatus(ListedEnum):
ALLOCATED = "Allocated"
CONNECTED = "Connected"
class Result(ListedEnum):
FAILED = "Failed"
SUCCESSFUL = "Successful"
ABORTED = "Aborted"
OPERATIONS = (
ExecutionPhase.list()
+ GeneralAction.list()
+ GeneralActionStatus.list()
+ ExecutionInfo.list()
+ Result.list()
)
# Start line
START_LINE = ".*Project content is packed for delivery.*"
def _match_date(date: str) -> bool:
return re.match(r"\d{4}-\d{2}-\d{2}", date) is not None
def _match_time(time: str) -> bool:
return re.match(r"\d{2}:\d{2}:\d{2}", time) is not None
def is_initial_line(line: str) -> bool:
if not line:
return False
pattern = re.compile(START_LINE)
parts = line.strip().split(" ")
return (
len(parts) > 2
and _match_date(parts[0])
and _match_time(parts[1])
and re.match(pattern, line) is not None
)
# Debug line starts with the operation
def is_operation(line: str, operation: Enum) -> bool:
if not line:
return False
parts = line.strip().split(" ")
return (
len(parts) > 2
and _match_date(parts[0])
and _match_time(parts[1])
and parts[2] == operation.value
)
# Check if the line contains any operation
def is_any_operation(line: str) -> bool:
if not line:
return False
parts = line.strip().split(" ")
return (
len(parts) > 2
and _match_date(parts[0])
and _match_time(parts[1])
and parts[2] in OPERATIONS
)
# Return the date in the line
def get_date(line: str) -> str:
if not line:
raise RuntimeError("Empty line provided")
parts = line.strip().split(" ")
if len(parts) <= 2 or not _match_date(parts[0]):
raise ValueError("Incorrect format for line provided: {}".format(line))
return parts[0]
# Return the time in the line
def get_time(line: str) -> str:
if not line:
raise RuntimeError("Empty line provided")
parts = line.strip().split(" ")
if len(parts) <= 2 or not _match_date(parts[0]) or not _match_time(parts[1]):
raise ValueError("Incorrect format for line provided: {}".format(line))
return parts[1]
# Return the operation in the line
def get_operation(line: str) -> str:
if not line:
raise RuntimeError("Empty line provided")
parts = line.strip().split(" ")
if len(parts) <= 2 or not _match_date(parts[0]) or not _match_time(parts[1]):
raise ValueError("Incorrect format for line provided: {}".format(line))
return parts[2]
# Return the information that comes after the operation
def get_operation_info(line: str) -> str:
if not line:
raise RuntimeError("Empty line provided")
parts = line.strip().split(" ")
if len(parts) <= 3 or not _match_date(parts[0]) or not _match_time(parts[1]):
raise ValueError("Incorrect format for line provided: {}".format(line))
return " ".join(parts[3:])
# Details are displayed after Error/Debug/Failed/Warning operations
def is_detail_start(line: str) -> bool:
return (
is_operation(line, ExecutionInfo.DEBUG)
or is_operation(line, ExecutionInfo.ERROR)
or is_operation(line, ExecutionInfo.WARNING)
or is_operation(line, Result.FAILED)
)
# Error/Debug/Failed output sometimes finish with either EOF error or a log file
# and no detail displayed
def is_detail(line: str) -> bool:
return (
is_operation(line, ExecutionInfo.DEBUG)
or is_operation(line, ExecutionInfo.ERROR)
or is_operation(line, ExecutionInfo.WARNING)
) and line.strip()[-1:] == ":"
# Error/Debug/Failed output finishes when a new other line starts
def is_detail_finished(line: str) -> bool:
parts = line.strip().split(" ")
return (
len(parts) > 3
and _match_date(parts[0])
and _match_time(parts[1])
and parts[2] in OPERATIONS
)
|