1
|
|
|
#!/usr/bin/env python3 |
2
|
|
|
|
3
|
|
|
import datetime |
4
|
|
|
import sys |
5
|
|
|
import time |
6
|
|
|
|
7
|
|
|
from ActionTree import Action, execute, Hooks |
8
|
|
|
|
9
|
|
|
|
10
|
|
|
UNKNOWN = (0, "unwknown since") |
11
|
|
|
PENDING = (1, "pending since") |
12
|
|
|
READY = (2, "ready since") |
13
|
|
|
STARTED = (3, "running since") |
14
|
|
|
SUCCESSFUL = (4, "succeeded at") |
15
|
|
|
FAILED = (5, "FAILED at") |
16
|
|
|
CANCELED = (6, "canceled at") |
17
|
|
|
|
18
|
|
|
|
19
|
|
|
class DemoHooks(Hooks): |
20
|
|
|
class ActionStatus: |
21
|
|
|
num_lines = { |
22
|
|
|
UNKNOWN: 0, |
23
|
|
|
PENDING: 0, |
24
|
|
|
READY: 0, |
25
|
|
|
STARTED: 5, |
26
|
|
|
SUCCESSFUL: 2, |
27
|
|
|
FAILED: 10, |
28
|
|
|
CANCELED: 0, |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
def __init__(self, label, time, status): |
32
|
|
|
self.label = label |
33
|
|
|
self.status = status |
34
|
|
|
self.time = time |
35
|
|
|
self.lines = [] |
36
|
|
|
|
37
|
|
|
def set(self, time, status): |
38
|
|
|
self.time = time |
39
|
|
|
self.status = status |
40
|
|
|
|
41
|
|
|
def display(self): |
42
|
|
|
num_lines = self.num_lines[self.status] |
43
|
|
|
title = "\"{}\" ({} t={:.2f}s)".format(self.label, self.status[1], self.time.total_seconds()) |
44
|
|
|
print() |
45
|
|
|
print(title) |
46
|
|
|
print("-" * len(title)) |
47
|
|
|
if num_lines > 1: |
48
|
|
|
if len(self.lines) > num_lines: |
49
|
|
|
print("[... {} lines not displayed ...]".format(len(self.lines) - num_lines)) |
50
|
|
|
lines_to_display = self.lines[1 - num_lines:] |
51
|
|
|
padding = 0 |
52
|
|
|
else: |
53
|
|
|
lines_to_display = self.lines |
54
|
|
|
padding = num_lines - len(self.lines) |
55
|
|
|
for line in lines_to_display: |
56
|
|
|
print(line) |
57
|
|
|
for i in range(padding): |
58
|
|
|
print() |
59
|
|
|
|
60
|
|
|
def __init__(self, action): |
61
|
|
|
self.start_time = datetime.datetime.now() |
62
|
|
|
actions = action.get_possible_execution_order() |
63
|
|
|
self.action_statuses = [self.ActionStatus(a.label, datetime.timedelta(), UNKNOWN) for a in actions] |
64
|
|
|
self.action_indexes = {action: i for (i, action) in enumerate(actions)} |
65
|
|
|
self.display() |
66
|
|
|
|
67
|
|
|
def display(self): |
68
|
|
|
print("\x1b[2J\x1b[H") |
69
|
|
|
title = "ActionTree demo (t={:.2f}s)".format((datetime.datetime.now() - self.start_time).total_seconds()) |
70
|
|
|
print(title) |
71
|
|
|
print("=" * len(title)) |
72
|
|
|
for action_status in self.action_statuses: |
73
|
|
|
action_status.display() |
74
|
|
|
|
75
|
|
|
def set(self, action, time, status): |
76
|
|
|
self.action_statuses[self.action_indexes[action]].set(time - self.start_time, status) |
77
|
|
|
self.display() |
78
|
|
|
|
79
|
|
|
def action_pending(self, time, action): |
80
|
|
|
self.set(action, time, PENDING) |
81
|
|
|
|
82
|
|
|
def action_ready(self, time, action): |
83
|
|
|
self.set(action, time, READY) |
84
|
|
|
|
85
|
|
|
def action_canceled(self, time, action): |
86
|
|
|
self.set(action, time, CANCELED) |
87
|
|
|
|
88
|
|
|
def action_started(self, time, action): |
89
|
|
|
self.set(action, time, STARTED) |
90
|
|
|
|
91
|
|
|
def action_printed(self, time, action, text): |
92
|
|
|
self.action_statuses[self.action_indexes[action]].lines += ["> {}".format(line.rstrip()) for line in text.splitlines()] |
93
|
|
|
self.display() |
94
|
|
|
|
95
|
|
|
def action_successful(self, time, action, return_value): |
96
|
|
|
self.set(action, time, SUCCESSFUL) |
97
|
|
|
|
98
|
|
|
def action_failed(self, time, action, exception): |
99
|
|
|
self.action_statuses[self.action_indexes[action]].lines += ["Exception: {}".format(repr(exception))] |
100
|
|
|
self.set(action, time, FAILED) |
101
|
|
|
|
102
|
|
|
|
103
|
|
|
class DemoAction(Action): |
104
|
|
|
def __init__(self, label, interval, iterations, exception=None): |
105
|
|
|
super(DemoAction, self).__init__("action {}".format(label)) |
106
|
|
|
self.interval = interval |
107
|
|
|
self.iterations = iterations |
108
|
|
|
self.exception = exception |
109
|
|
|
|
110
|
|
|
def do_execute(self, dependency_statuses): |
111
|
|
|
print(self.label, "iteration 0 /", self.iterations) |
112
|
|
|
for i in range(self.iterations): |
113
|
|
|
time.sleep(self.interval) |
114
|
|
|
print(self.label, "iteration", (i + 1), "/", self.iterations) |
115
|
|
|
if self.exception: |
116
|
|
|
print(self.label, "failing") |
117
|
|
|
raise self.exception |
118
|
|
|
|
119
|
|
|
|
120
|
|
|
a = DemoAction("a", 1., 5) |
121
|
|
|
a.add_dependency(DemoAction("a1", 0.9, 7)) |
122
|
|
|
a.add_dependency(DemoAction("a2", 0.5, 12)) |
123
|
|
|
a.add_dependency(DemoAction("a3", 0.8, 10)) |
124
|
|
|
|
125
|
|
|
b = DemoAction("b", 1., 5) |
126
|
|
|
b.add_dependency(DemoAction("b1", 0.5, 14, exception=Exception())) |
127
|
|
|
b.add_dependency(DemoAction("b2", 0.3, 25)) |
128
|
|
|
b.add_dependency(DemoAction("b3", 1.7, 5)) |
129
|
|
|
|
130
|
|
|
z = DemoAction("z", 1., 5) |
131
|
|
|
z.add_dependency(a) |
132
|
|
|
z.add_dependency(b) |
133
|
|
|
|
134
|
|
|
execute(z, cpu_cores=4, hooks=DemoHooks(z), do_raise=False, keep_going=True) |
135
|
|
|
|