proj-flow 0.20.3__py3-none-any.whl → 0.22.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- proj_flow/__init__.py +1 -1
- proj_flow/api/arg.py +2 -0
- proj_flow/api/completers.py +1 -1
- proj_flow/api/env.py +45 -15
- proj_flow/api/release.py +1 -1
- proj_flow/api/step.py +20 -5
- proj_flow/{ext/cplusplus/cmake/presets.py → base/cmake_presets.py} +40 -16
- proj_flow/base/plugins.py +12 -7
- proj_flow/cli/finder.py +4 -3
- proj_flow/dependency.py +6 -2
- proj_flow/ext/cplusplus/cmake/__init__.py +2 -2
- proj_flow/ext/cplusplus/cmake/parser.py +4 -3
- proj_flow/ext/cplusplus/cmake/steps.py +9 -9
- proj_flow/ext/cplusplus/conan/__init__.py +8 -4
- proj_flow/ext/github/cli.py +1 -3
- proj_flow/ext/github/publishing.py +1 -0
- proj_flow/ext/python/rtdocs.py +37 -8
- proj_flow/ext/python/steps.py +5 -4
- proj_flow/ext/python/version.py +12 -12
- proj_flow/ext/sign/__init__.py +2 -2
- proj_flow/ext/test_runner/__init__.py +6 -0
- proj_flow/ext/test_runner/cli.py +416 -0
- proj_flow/ext/test_runner/driver/__init__.py +2 -0
- proj_flow/ext/test_runner/driver/commands.py +74 -0
- proj_flow/ext/test_runner/driver/test.py +610 -0
- proj_flow/ext/test_runner/driver/testbed.py +141 -0
- proj_flow/ext/test_runner/utils/__init__.py +2 -0
- proj_flow/ext/test_runner/utils/archives.py +56 -0
- proj_flow/log/rich_text/api.py +3 -4
- proj_flow/minimal/list.py +126 -10
- proj_flow/minimal/run.py +3 -2
- proj_flow/project/api.py +1 -0
- {proj_flow-0.20.3.dist-info → proj_flow-0.22.0.dist-info}/METADATA +17 -7
- {proj_flow-0.20.3.dist-info → proj_flow-0.22.0.dist-info}/RECORD +37 -29
- {proj_flow-0.20.3.dist-info → proj_flow-0.22.0.dist-info}/WHEEL +0 -0
- {proj_flow-0.20.3.dist-info → proj_flow-0.22.0.dist-info}/entry_points.txt +0 -0
- {proj_flow-0.20.3.dist-info → proj_flow-0.22.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Copyright (c) 2026 Marcin Zdun
|
|
2
|
+
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import pprint
|
|
6
|
+
import random
|
|
7
|
+
import string
|
|
8
|
+
import sys
|
|
9
|
+
from dataclasses import dataclass, field, replace
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import cast
|
|
12
|
+
|
|
13
|
+
from proj_flow.ext.test_runner.driver.test import Env, Test, fix_file_write, to_lines
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class color:
|
|
17
|
+
reset = "\033[m"
|
|
18
|
+
counter = "\033[2;49;92m"
|
|
19
|
+
name = "\033[0;49;90m"
|
|
20
|
+
failed = "\033[0;49;91m"
|
|
21
|
+
passed = "\033[2;49;92m"
|
|
22
|
+
skipped = "\033[0;49;34m"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TaskResult:
|
|
26
|
+
OK = 0
|
|
27
|
+
SKIPPED = 1
|
|
28
|
+
SAVED = 2
|
|
29
|
+
FAILED = 3
|
|
30
|
+
CLIP_FAILED = 4
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class Counters:
|
|
35
|
+
error_counter: int = 0
|
|
36
|
+
skip_counter: int = 0
|
|
37
|
+
save_counter: int = 0
|
|
38
|
+
echo: list[str] = field(default_factory=list)
|
|
39
|
+
|
|
40
|
+
def report(self, outcome: int, test_id: str, message: str | None):
|
|
41
|
+
if outcome == TaskResult.SKIPPED:
|
|
42
|
+
print(f"{test_id} {color.skipped}SKIPPED{color.reset}")
|
|
43
|
+
self.skip_counter += 1
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
if outcome == TaskResult.SAVED:
|
|
47
|
+
print(f"{test_id} {color.skipped}saved{color.reset}")
|
|
48
|
+
self.skip_counter += 1
|
|
49
|
+
self.save_counter += 1
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
if outcome == TaskResult.CLIP_FAILED:
|
|
53
|
+
msg = f"{test_id} {color.failed}FAILED (unknown check '{message}'){color.reset}"
|
|
54
|
+
print(msg)
|
|
55
|
+
self.echo.append(msg)
|
|
56
|
+
self.error_counter += 1
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
if outcome == TaskResult.OK:
|
|
60
|
+
print(f"{test_id} {color.passed}PASSED{color.reset}")
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
if message is not None:
|
|
64
|
+
print(message)
|
|
65
|
+
msg = f"{test_id} {color.failed}FAILED{color.reset}"
|
|
66
|
+
print(msg)
|
|
67
|
+
self.echo.append(msg)
|
|
68
|
+
self.error_counter += 1
|
|
69
|
+
|
|
70
|
+
def summary(self, counter: int):
|
|
71
|
+
print(f"Failed {self.error_counter}/{counter}")
|
|
72
|
+
if self.skip_counter > 0:
|
|
73
|
+
skip_test = "test" if self.skip_counter == 1 else "tests"
|
|
74
|
+
if self.save_counter > 0:
|
|
75
|
+
print(
|
|
76
|
+
f"Skipped {self.skip_counter} {skip_test} (including {self.save_counter} due to saving)"
|
|
77
|
+
)
|
|
78
|
+
else:
|
|
79
|
+
print(f"Skipped {self.skip_counter} {skip_test}")
|
|
80
|
+
|
|
81
|
+
if len(self.echo):
|
|
82
|
+
print()
|
|
83
|
+
for echo in self.echo:
|
|
84
|
+
print(echo)
|
|
85
|
+
|
|
86
|
+
return self.error_counter == 0
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def task(
|
|
90
|
+
env1: Env, tested: Test, current_counter: int
|
|
91
|
+
) -> tuple[int, str, str | None, str]:
|
|
92
|
+
temp_instance = "".join(random.choice(string.ascii_letters) for _ in range(16))
|
|
93
|
+
tempdir = f"{env1.tempdir}/{temp_instance}"
|
|
94
|
+
tempdir_alt = None
|
|
95
|
+
|
|
96
|
+
if env1.tempdir_alt is not None:
|
|
97
|
+
tempdir_alt = f"{env1.tempdir_alt}{os.sep}{temp_instance}"
|
|
98
|
+
|
|
99
|
+
env2 = replace(env1, tempdir=tempdir, tempdir_alt=tempdir_alt)
|
|
100
|
+
|
|
101
|
+
test_counter = f"{color.counter}[{current_counter:>{env2.counter_digits}}/{env2.counter_total}]{color.reset}"
|
|
102
|
+
test_name = f"{color.name}{tested.name}{color.reset}"
|
|
103
|
+
test_id = f"{test_counter} {test_name}"
|
|
104
|
+
|
|
105
|
+
print(test_id)
|
|
106
|
+
os.makedirs(tempdir, exist_ok=True)
|
|
107
|
+
|
|
108
|
+
actual = tested.run(env2)
|
|
109
|
+
if actual is None:
|
|
110
|
+
return (TaskResult.SKIPPED, test_id, None, tempdir)
|
|
111
|
+
|
|
112
|
+
if tested.expected is None:
|
|
113
|
+
is_json = tested.filename.suffix == ".json"
|
|
114
|
+
tested.data["expected"] = [
|
|
115
|
+
actual[0],
|
|
116
|
+
*[to_lines(stream, is_json) for stream in actual[1:3]],
|
|
117
|
+
]
|
|
118
|
+
tested.store()
|
|
119
|
+
return (TaskResult.SAVED, test_id, None, tempdir)
|
|
120
|
+
|
|
121
|
+
clipped = tested.clip(actual[:3])
|
|
122
|
+
|
|
123
|
+
if isinstance(clipped, str):
|
|
124
|
+
return (TaskResult.CLIP_FAILED, test_id, clipped, tempdir)
|
|
125
|
+
|
|
126
|
+
reports: list[str] = []
|
|
127
|
+
|
|
128
|
+
files = actual[3]
|
|
129
|
+
for file in files:
|
|
130
|
+
fixed = fix_file_write(file, env2, tested.cwd, tested.patches)
|
|
131
|
+
if fixed.generated.content != fixed.template.content:
|
|
132
|
+
reports.append(tested.report_file(fixed))
|
|
133
|
+
|
|
134
|
+
if actual[:3] != tested.expected and clipped != tested.expected:
|
|
135
|
+
reports.append(tested.report_io(actual[:3]))
|
|
136
|
+
|
|
137
|
+
if reports:
|
|
138
|
+
reports.append(tested.test_footer(env2, tempdir))
|
|
139
|
+
return (TaskResult.FAILED, test_id, "\n".join(reports), tempdir)
|
|
140
|
+
|
|
141
|
+
return (TaskResult.OK, test_id, None, tempdir)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Copyright (c) 2026 Marcin Zdun
|
|
2
|
+
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import tarfile
|
|
6
|
+
import zipfile
|
|
7
|
+
from typing import Callable
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _untar(src, dst):
|
|
11
|
+
with tarfile.open(src) as TAR:
|
|
12
|
+
|
|
13
|
+
def is_within_directory(directory, target):
|
|
14
|
+
abs_directory = os.path.abspath(directory)
|
|
15
|
+
abs_target = os.path.abspath(target)
|
|
16
|
+
|
|
17
|
+
prefix = os.path.commonprefix([abs_directory, abs_target])
|
|
18
|
+
|
|
19
|
+
return prefix == abs_directory
|
|
20
|
+
|
|
21
|
+
for member in TAR.getmembers():
|
|
22
|
+
member_path = os.path.join(dst, member.name)
|
|
23
|
+
if not is_within_directory(dst, member_path):
|
|
24
|
+
raise Exception(f"Attempted path traversal in Tar file: {member.name}")
|
|
25
|
+
|
|
26
|
+
TAR.extractall(dst)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _unzip(src, dst):
|
|
30
|
+
with zipfile.ZipFile(src) as ZIP:
|
|
31
|
+
ZIP.extractall(dst)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
_tar = (_untar, ["tar", "-xf"])
|
|
35
|
+
|
|
36
|
+
Unpacker = Callable[[str, str], None]
|
|
37
|
+
UnpackInfo = tuple[Unpacker, list[str]]
|
|
38
|
+
|
|
39
|
+
ARCHIVES: dict[str, UnpackInfo] = {
|
|
40
|
+
".tar": _tar,
|
|
41
|
+
".tar.gz": _tar,
|
|
42
|
+
".zip": (_unzip, ["unzip"]),
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def locate_unpack(archive: str) -> UnpackInfo:
|
|
47
|
+
reminder, ext = os.path.splitext(archive)
|
|
48
|
+
_, mid = os.path.splitext(reminder)
|
|
49
|
+
if mid == ".tar":
|
|
50
|
+
ext = ".tar"
|
|
51
|
+
return ARCHIVES[ext]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
del _tar
|
|
55
|
+
del _unzip
|
|
56
|
+
del _untar
|
proj_flow/log/rich_text/api.py
CHANGED
|
@@ -91,7 +91,7 @@ class ChangelogGenerator(abc.ABC):
|
|
|
91
91
|
|
|
92
92
|
entire_log.append(self.intro())
|
|
93
93
|
|
|
94
|
-
filename =
|
|
94
|
+
filename = rt.root / f"CHANGELOG{self.ext}"
|
|
95
95
|
with open(filename, "wb") as f:
|
|
96
96
|
for text in reversed(entire_log):
|
|
97
97
|
f.write(text.encode("UTF-8"))
|
|
@@ -106,8 +106,7 @@ class ChangelogGenerator(abc.ABC):
|
|
|
106
106
|
setup, commit.read_tag_date(setup.curr_tag or "HEAD", rt)
|
|
107
107
|
)
|
|
108
108
|
text = formatter.format_changelog(log)
|
|
109
|
-
|
|
110
|
-
path = os.path.join(rt.root, filename)
|
|
109
|
+
path = rt.root / self.filename
|
|
111
110
|
|
|
112
111
|
try:
|
|
113
112
|
with open(path, encoding="UTF-8") as f:
|
|
@@ -125,7 +124,7 @@ class ChangelogGenerator(abc.ABC):
|
|
|
125
124
|
if len(split) > 1:
|
|
126
125
|
new_text += "".join(split[1:])
|
|
127
126
|
|
|
128
|
-
with open(
|
|
127
|
+
with open(path, "wb") as f:
|
|
129
128
|
f.write(new_text.encode("UTF-8"))
|
|
130
129
|
|
|
131
130
|
|
proj_flow/minimal/list.py
CHANGED
|
@@ -6,12 +6,20 @@ The **proj_flow.minimal.list** implements ``./flow list`` command.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import os
|
|
9
|
-
|
|
9
|
+
import re
|
|
10
|
+
import sys
|
|
11
|
+
from typing import Annotated, Dict, Iterable, List, Set, cast
|
|
10
12
|
|
|
11
13
|
from proj_flow import cli
|
|
12
14
|
from proj_flow.api import arg, env, step
|
|
13
15
|
from proj_flow.base import matrix
|
|
14
16
|
|
|
17
|
+
if sys.platform == "win32":
|
|
18
|
+
import ctypes
|
|
19
|
+
import ctypes.wintypes
|
|
20
|
+
else:
|
|
21
|
+
import termios
|
|
22
|
+
|
|
15
23
|
|
|
16
24
|
@arg.command("list")
|
|
17
25
|
def main(
|
|
@@ -39,10 +47,7 @@ def main(
|
|
|
39
47
|
configs = True
|
|
40
48
|
|
|
41
49
|
if builtin:
|
|
42
|
-
|
|
43
|
-
while root.parent is not None:
|
|
44
|
-
root = root.parent
|
|
45
|
-
builtin_entries = list(sorted((cmd.name, cmd.doc) for cmd in root.children))
|
|
50
|
+
builtin_entries = list(sorted(_walk_menu(menu)))
|
|
46
51
|
if not pipe and len(builtin_entries) > 0:
|
|
47
52
|
print("Builtin commands")
|
|
48
53
|
print("----------------")
|
|
@@ -54,7 +59,10 @@ def main(
|
|
|
54
59
|
|
|
55
60
|
name = f"{bold}{entry_name}{reset}"
|
|
56
61
|
if entry_doc:
|
|
57
|
-
print(f"- {name}:
|
|
62
|
+
print(f"- {name}:", end=" ")
|
|
63
|
+
_write_console_para(
|
|
64
|
+
" ".join(para.split("\n")) for para in entry_doc.split("\n\n")
|
|
65
|
+
)
|
|
58
66
|
else:
|
|
59
67
|
print(f"- {name}")
|
|
60
68
|
|
|
@@ -76,7 +84,8 @@ def main(
|
|
|
76
84
|
continue
|
|
77
85
|
|
|
78
86
|
name = f"{bold}{run_alias.name}{reset}"
|
|
79
|
-
print(f"- {name}:
|
|
87
|
+
print(f"- {name}:", end=" ")
|
|
88
|
+
_write_console_para([", ".join(run_alias.steps)])
|
|
80
89
|
|
|
81
90
|
printed_something = True
|
|
82
91
|
|
|
@@ -109,8 +118,10 @@ def main(
|
|
|
109
118
|
print(f"- {name}*")
|
|
110
119
|
|
|
111
120
|
if some_unused:
|
|
112
|
-
|
|
113
|
-
|
|
121
|
+
_write_console_para(
|
|
122
|
+
[
|
|
123
|
+
f"*step can only be run by explicitly calling through {bold}run{reset}."
|
|
124
|
+
]
|
|
114
125
|
)
|
|
115
126
|
|
|
116
127
|
printed_something = True
|
|
@@ -147,7 +158,8 @@ def main(
|
|
|
147
158
|
value = ", ".join(values.get(key, empty))
|
|
148
159
|
name = f"{bold}{key}{reset}"
|
|
149
160
|
if value:
|
|
150
|
-
print(f"- {name}:
|
|
161
|
+
print(f"- {name}:", end=" ")
|
|
162
|
+
_write_console_para([value])
|
|
151
163
|
else:
|
|
152
164
|
print(f"- {name}")
|
|
153
165
|
|
|
@@ -157,6 +169,110 @@ def main(
|
|
|
157
169
|
print(f"Use {bold}--help{reset} to see, which listings are available")
|
|
158
170
|
|
|
159
171
|
|
|
172
|
+
def _iterate_levels(menu: cli.argument.Command, prefix: str):
|
|
173
|
+
yield [(f"{prefix}{cmd.name}", cmd.doc) for cmd in menu.children]
|
|
174
|
+
for cmd in menu.children:
|
|
175
|
+
child_prefix = f"{prefix}{cmd.name} "
|
|
176
|
+
for layer in _iterate_levels(cmd, child_prefix):
|
|
177
|
+
yield layer
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _walk_menu(menu: cli.argument.Command):
|
|
181
|
+
root = menu
|
|
182
|
+
while root.parent is not None:
|
|
183
|
+
root = root.parent
|
|
184
|
+
|
|
185
|
+
items: list[tuple[str, str]] = []
|
|
186
|
+
for layer in _iterate_levels(root, ""):
|
|
187
|
+
items.extend(layer)
|
|
188
|
+
|
|
189
|
+
return items
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _cursor_pos():
|
|
193
|
+
if sys.platform == "win32":
|
|
194
|
+
old_stdin_mode = ctypes.wintypes.DWORD()
|
|
195
|
+
old_stdout_mode = ctypes.wintypes.DWORD()
|
|
196
|
+
kernel32 = ctypes.windll.kernel32
|
|
197
|
+
kernel32.GetConsoleMode(
|
|
198
|
+
kernel32.GetStdHandle(-10), ctypes.byref(old_stdin_mode)
|
|
199
|
+
)
|
|
200
|
+
kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), 0)
|
|
201
|
+
kernel32.GetConsoleMode(
|
|
202
|
+
kernel32.GetStdHandle(-11), ctypes.byref(old_stdout_mode)
|
|
203
|
+
)
|
|
204
|
+
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
|
|
205
|
+
else:
|
|
206
|
+
old_stdin_mode = termios.tcgetattr(sys.stdin)
|
|
207
|
+
_ = termios.tcgetattr(sys.stdin)
|
|
208
|
+
_[3] = _[3] & ~(termios.ECHO | termios.ICANON)
|
|
209
|
+
termios.tcsetattr(sys.stdin, termios.TCSAFLUSH, _)
|
|
210
|
+
try:
|
|
211
|
+
_ = ""
|
|
212
|
+
sys.stdout.write("\x1b[6n")
|
|
213
|
+
sys.stdout.flush()
|
|
214
|
+
while not (_ := _ + sys.stdin.read(1)).endswith("R"):
|
|
215
|
+
pass
|
|
216
|
+
res = re.match(r".*\[(?P<y>\d*);(?P<x>\d*)R", _)
|
|
217
|
+
finally:
|
|
218
|
+
if sys.platform == "win32":
|
|
219
|
+
kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), old_stdin_mode)
|
|
220
|
+
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), old_stdout_mode)
|
|
221
|
+
else:
|
|
222
|
+
termios.tcsetattr(sys.stdin, termios.TCSAFLUSH, old_stdin_mode)
|
|
223
|
+
if res:
|
|
224
|
+
return (int(res.group("x")), int(res.group("y")))
|
|
225
|
+
return (1, 1)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _write_console_para(text: Iterable[str]):
|
|
229
|
+
term_width = os.get_terminal_size().columns
|
|
230
|
+
margin = min(_cursor_pos()[0], term_width // 2) - 1
|
|
231
|
+
width = term_width - 1
|
|
232
|
+
pos = margin
|
|
233
|
+
for para in text:
|
|
234
|
+
for word in para.split():
|
|
235
|
+
if not word:
|
|
236
|
+
continue
|
|
237
|
+
word_len = len(word)
|
|
238
|
+
next_pos = pos + word_len + 1
|
|
239
|
+
|
|
240
|
+
if next_pos >= width:
|
|
241
|
+
orig = pos
|
|
242
|
+
if orig == margin:
|
|
243
|
+
pos = margin - word_len
|
|
244
|
+
print(word, end="")
|
|
245
|
+
|
|
246
|
+
print()
|
|
247
|
+
print(" " * margin, end="")
|
|
248
|
+
|
|
249
|
+
if orig != margin:
|
|
250
|
+
pos = margin
|
|
251
|
+
print(word, end=" ")
|
|
252
|
+
else:
|
|
253
|
+
print(word, end=" ")
|
|
254
|
+
|
|
255
|
+
pos += word_len + 1
|
|
256
|
+
|
|
257
|
+
continue
|
|
258
|
+
if (word_len + 1) > term_width:
|
|
259
|
+
first_word = pos == margin
|
|
260
|
+
if first_word:
|
|
261
|
+
print(word, end="")
|
|
262
|
+
|
|
263
|
+
print(f"\n{' ' * margin}", end="")
|
|
264
|
+
pos = margin
|
|
265
|
+
|
|
266
|
+
if not first_word:
|
|
267
|
+
print(word, "", end="")
|
|
268
|
+
pos += word_len + 1
|
|
269
|
+
continue
|
|
270
|
+
|
|
271
|
+
print(word, "", end="")
|
|
272
|
+
pos += word_len + 1
|
|
273
|
+
print()
|
|
274
|
+
|
|
275
|
+
|
|
160
276
|
def _load_flow_data(rt: env.Runtime):
|
|
161
277
|
paths = [os.path.join(".flow", "matrix.yml")]
|
|
162
278
|
m, keys = matrix.load_matrix(*paths)
|
proj_flow/minimal/run.py
CHANGED
|
@@ -9,6 +9,7 @@ import os
|
|
|
9
9
|
import shutil
|
|
10
10
|
import sys
|
|
11
11
|
from contextlib import contextmanager
|
|
12
|
+
from pathlib import Path
|
|
12
13
|
from typing import Annotated, List, Optional, Set, cast
|
|
13
14
|
|
|
14
15
|
from proj_flow import api, dependency
|
|
@@ -69,7 +70,7 @@ def gather_dependencies_for_all_configs(
|
|
|
69
70
|
def refresh_directories(
|
|
70
71
|
configs: Configs, rt: api.env.Runtime, steps: List[api.step.Step]
|
|
71
72
|
):
|
|
72
|
-
directories_to_refresh: Set[
|
|
73
|
+
directories_to_refresh: Set[Path] = set()
|
|
73
74
|
for config in configs.usable:
|
|
74
75
|
for step in steps:
|
|
75
76
|
if step.is_active(config, rt):
|
|
@@ -80,7 +81,7 @@ def refresh_directories(
|
|
|
80
81
|
for dirname in directories_to_refresh:
|
|
81
82
|
if not rt.silent:
|
|
82
83
|
printed = True
|
|
83
|
-
print(f"[-] {dirname}", file=sys.stderr)
|
|
84
|
+
print(f"[-] {dirname.as_posix()}", file=sys.stderr)
|
|
84
85
|
if not rt.dry_run:
|
|
85
86
|
shutil.rmtree(dirname, ignore_errors=True)
|
|
86
87
|
|
proj_flow/project/api.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: proj-flow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.22.0
|
|
4
4
|
Summary: C++ project maintenance, automated
|
|
5
5
|
Project-URL: Changelog, https://github.com/mzdun/proj-flow/blob/main/CHANGELOG.rst
|
|
6
6
|
Project-URL: Documentation, https://proj-flow.readthedocs.io/en/latest/
|
|
7
7
|
Project-URL: Homepage, https://pypi.org/project/proj-flow/
|
|
8
8
|
Project-URL: Source Code, https://github.com/mzdun/proj-flow
|
|
9
9
|
Author-email: Marcin Zdun <marcin.zdun@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
10
11
|
License-File: LICENSE
|
|
11
12
|
Keywords: C/C++,build-tool,c++,ci-cd,continuous-integration,cpp,dependencies,dependency-manager,developer,developer-tools,development,meta-build-tool,pipeline,tools-and-automation
|
|
12
13
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -17,13 +18,22 @@ Classifier: Programming Language :: Python :: 3
|
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
19
|
Classifier: Topic :: Software Development :: Build Tools
|
|
19
20
|
Requires-Python: >=3.10
|
|
20
|
-
Requires-Dist: argcomplete
|
|
21
|
+
Requires-Dist: argcomplete~=3.5
|
|
21
22
|
Requires-Dist: chevron2021
|
|
22
|
-
Requires-Dist: prompt-toolkit
|
|
23
|
-
Requires-Dist: pywebidl2
|
|
24
|
-
Requires-Dist: pyyaml
|
|
25
|
-
Requires-Dist: requests-cache
|
|
26
|
-
Requires-Dist: toml
|
|
23
|
+
Requires-Dist: prompt-toolkit~=3.0
|
|
24
|
+
Requires-Dist: pywebidl2~=0.1
|
|
25
|
+
Requires-Dist: pyyaml~=6.0
|
|
26
|
+
Requires-Dist: requests-cache~=1.3
|
|
27
|
+
Requires-Dist: toml~=0.10
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: black~=25.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: build~=1.4; extra == 'dev'
|
|
31
|
+
Requires-Dist: isort~=6.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: sphinx~=9.1; extra == 'dev'
|
|
33
|
+
Requires-Dist: twine<=6.0.1; extra == 'dev'
|
|
34
|
+
Requires-Dist: types-chevron~=0.14; extra == 'dev'
|
|
35
|
+
Requires-Dist: types-pyyaml~=6.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: types-toml~=0.10; extra == 'dev'
|
|
27
37
|
Description-Content-Type: text/markdown
|
|
28
38
|
|
|
29
39
|
# Project Flow
|
|
@@ -1,51 +1,59 @@
|
|
|
1
|
-
proj_flow/__init__.py,sha256=
|
|
1
|
+
proj_flow/__init__.py,sha256=q44bLIhvwlNd00XujabnofmCmqvXybHCZSg3Fg3FFRE,277
|
|
2
2
|
proj_flow/__main__.py,sha256=HUar_qQ9Ndmchmryegtzu__5wukwCLrFN_SGRl5Ol_M,233
|
|
3
|
-
proj_flow/dependency.py,sha256=
|
|
3
|
+
proj_flow/dependency.py,sha256=f2wjr_F7Cy_3I4R5AfT6R9Q28F3G3WrLKbqyEld_CF0,4765
|
|
4
4
|
proj_flow/api/__init__.py,sha256=gV2f6kll_5JXtvkGASvnx7CbOWr34PHOdck-4ce-qEk,378
|
|
5
|
-
proj_flow/api/arg.py,sha256=
|
|
6
|
-
proj_flow/api/completers.py,sha256=
|
|
5
|
+
proj_flow/api/arg.py,sha256=0sVVEqdIOCqWmZtST_-u4rP6JkrResGJsKERQp3WYgc,5392
|
|
6
|
+
proj_flow/api/completers.py,sha256=gZ50toLTWstKQbSV24gaNUzVjmrS0IjuYujzyMbp41A,2452
|
|
7
7
|
proj_flow/api/ctx.py,sha256=IJu0q0Chivo6b2M4MKkAlV09oi7Cn9VxtDFeAeL_tnc,6646
|
|
8
|
-
proj_flow/api/env.py,sha256=
|
|
8
|
+
proj_flow/api/env.py,sha256=8XN3N91iVzcgx2urYDy2IjqCk5CIzeCvFqN6FTK6YLo,13582
|
|
9
9
|
proj_flow/api/init.py,sha256=p4ZDGfq6fw4bXbJu2iq0vEmVxbS7nALIhZfe-XnEs44,565
|
|
10
10
|
proj_flow/api/makefile.py,sha256=q0fBSsWTWfR5YwunwiRjWJKtiLeHdSKUgUTEgo5I7dE,3863
|
|
11
|
-
proj_flow/api/release.py,sha256=
|
|
12
|
-
proj_flow/api/step.py,sha256=
|
|
11
|
+
proj_flow/api/release.py,sha256=JOddtYNH7J-GfUsvc1hOgKLzf56C6qvwF748n87MQFE,2821
|
|
12
|
+
proj_flow/api/step.py,sha256=npUREdBIJb6s4CPA7snVd83YvfhsfMx6mPYKiHFhVF4,5326
|
|
13
13
|
proj_flow/base/__cmake_version__.py,sha256=imja0GnhpBvS8Crz-64eOUKhc4i6FeRrjBGRB68x_p0,239
|
|
14
14
|
proj_flow/base/__init__.py,sha256=V6IFRRtwxzvHuvtog6LIG9_6oivNpdcR5UmGobypvTo,930
|
|
15
|
+
proj_flow/base/cmake_presets.py,sha256=tBgzKk8BU1Lz9oA7o3PdB2Z4nK9ftuLb2TgeUzVhABc,5618
|
|
15
16
|
proj_flow/base/cmd.py,sha256=XJk_r4Nlq_2XGgD_w92Us4WKwItmQAB8QWdT1pKxUFA,1746
|
|
16
17
|
proj_flow/base/inspect.py,sha256=lt5P19rvSZ-wMCTrCYAaQFCt2S9fUjEQXlrKK-Tmvwc,2786
|
|
17
18
|
proj_flow/base/matrix.py,sha256=kH2BB6JRrLYdR71VJiJp58zfQSazwEOeiRXOPrayAcI,8446
|
|
18
19
|
proj_flow/base/name_list.py,sha256=KiHSnbDgYplJc25O3EehYhFAhD7Z3mHVAK6UYOdg5PQ,416
|
|
19
|
-
proj_flow/base/plugins.py,sha256=
|
|
20
|
+
proj_flow/base/plugins.py,sha256=8mQfkrdF7UncJaWz6623oa4g9XiZjJWvTgU1pCEBkr0,1078
|
|
20
21
|
proj_flow/base/registry.py,sha256=zbkB9KNfHnyPtzOurdvjwt714jrFpGHyOqeZL5sMvzI,3745
|
|
21
22
|
proj_flow/base/uname.py,sha256=7Awb3Es0jTAKMpyRawdrC16xc5X9M97BlPqEfQibqIk,2295
|
|
22
23
|
proj_flow/cli/__init__.py,sha256=cMsZpECkXeSzY4Hv_ela3Ou-FhwE5w1A3ypMSnZZikM,1196
|
|
23
24
|
proj_flow/cli/argument.py,sha256=V242x0ziuvqqXl56TDXxVhN1llCRZRT3bUnw7GfGRIE,14341
|
|
24
|
-
proj_flow/cli/finder.py,sha256=
|
|
25
|
+
proj_flow/cli/finder.py,sha256=IHnX2tkD0Hq7N6hVDArGJIK8NFzD5isMZYugkArlS6Y,1439
|
|
25
26
|
proj_flow/ext/__init__.py,sha256=XD52rUFTPz3GnyRq6KZUNeWdMce7e0bB19iTx-zU6DE,169
|
|
26
27
|
proj_flow/ext/markdown_changelog.py,sha256=fRGL09jojnv2B-8vAX2prvgNp8e7uyq5NxboSZjFCJ8,436
|
|
27
28
|
proj_flow/ext/re_structured_changelog.py,sha256=UF23W9eu_YgPO42MiaoDbEKu8In_48mQg6rH9--mI30,459
|
|
28
29
|
proj_flow/ext/store.py,sha256=zc9yh9M042V5OSLUZjWe9KazhdZ35h1JJsWvKughM0Y,3385
|
|
29
30
|
proj_flow/ext/cplusplus/__init__.py,sha256=dAmLMyGVQq586jJM_jiAuo5Ecw9U8agpvSRbzzPgh3g,245
|
|
30
|
-
proj_flow/ext/cplusplus/cmake/__init__.py,sha256=
|
|
31
|
-
proj_flow/ext/cplusplus/cmake/parser.py,sha256=
|
|
32
|
-
proj_flow/ext/cplusplus/cmake/presets.py,sha256=iYtSlkIoY3fEa6GL95zJugJbmleV5NPPB9UhME8RbSA,4922
|
|
31
|
+
proj_flow/ext/cplusplus/cmake/__init__.py,sha256=XQ8l1WsEZAgcNX_A0KgY535VhF6s7glS0TW2L0EmdVc,346
|
|
32
|
+
proj_flow/ext/cplusplus/cmake/parser.py,sha256=GsySyYC3DES-3teKPvs5PFwl3hpQkvKkNhWGbpLa-Ww,3828
|
|
33
33
|
proj_flow/ext/cplusplus/cmake/project.py,sha256=Cp-5HwEsrQW4RjDThjMBQmaVJiRHo9QvYbw7IvjHKNQ,929
|
|
34
|
-
proj_flow/ext/cplusplus/cmake/steps.py,sha256=
|
|
35
|
-
proj_flow/ext/cplusplus/conan/__init__.py,sha256=
|
|
34
|
+
proj_flow/ext/cplusplus/cmake/steps.py,sha256=Xp7d-79wi759p4OqpRPfhNplUNbNa1Oi-_18_K5-Vs4,4256
|
|
35
|
+
proj_flow/ext/cplusplus/conan/__init__.py,sha256=hHxf9-7W5KGKOv2e1EBQj6sPDD-R7LMCXx5BlLETT8w,2052
|
|
36
36
|
proj_flow/ext/cplusplus/conan/_conan.py,sha256=9xnji-f8uN7huXLqavVBUDC33CgnjBIyZX6wVcGm2RA,3352
|
|
37
37
|
proj_flow/ext/github/__init__.py,sha256=Mgx19YS6SYBXYB66_pOgIgwuB2WKRxqp5UGutq0B9Xk,282
|
|
38
|
-
proj_flow/ext/github/cli.py,sha256=
|
|
38
|
+
proj_flow/ext/github/cli.py,sha256=whK_VEUAG48tODyUYGfh3ZzZEa6vQgsNxY8yEfyDTzs,6441
|
|
39
39
|
proj_flow/ext/github/hosting.py,sha256=3iW8QjeJk7MyqKNbv92nB-5a_Yn_B5_eEIlw_cdgUT0,519
|
|
40
|
-
proj_flow/ext/github/publishing.py,sha256=
|
|
40
|
+
proj_flow/ext/github/publishing.py,sha256=IXiQ5O3dA5ctGa46rCynZofF4Ixg85QhMHBaPZ-Uk10,1947
|
|
41
41
|
proj_flow/ext/github/switches.py,sha256=Y3pqJdiHYLoveCQtqZqELR84Phb2YF4u5y78TU7n2CQ,752
|
|
42
42
|
proj_flow/ext/python/__init__.py,sha256=GbEKEJJZ3PJ4sRHEykAWjGIR6yyyrYdlUFulldvsAGI,252
|
|
43
|
-
proj_flow/ext/python/rtdocs.py,sha256=
|
|
44
|
-
proj_flow/ext/python/steps.py,sha256=
|
|
45
|
-
proj_flow/ext/python/version.py,sha256=
|
|
46
|
-
proj_flow/ext/sign/__init__.py,sha256=
|
|
43
|
+
proj_flow/ext/python/rtdocs.py,sha256=kNPlrnmFLXIbtWB-WuEAgwpymNnI-qXF0P1cHJXfgiM,7116
|
|
44
|
+
proj_flow/ext/python/steps.py,sha256=c2ZXaS6F0p1euQrsZMLuSjisUTmZd-CFKWhbk7RnOQI,1865
|
|
45
|
+
proj_flow/ext/python/version.py,sha256=wgrhWCYSnJsAg52rijvX7WxAyKQwgh-oSRIp5uRk5hs,3216
|
|
46
|
+
proj_flow/ext/sign/__init__.py,sha256=IMnFqRdl9e-EejXsIiifHs6dF4jkujQHbvbNXWjDP50,4298
|
|
47
47
|
proj_flow/ext/sign/api.py,sha256=l5SO5RHiHTwxg0aexkGOfApRdojWDcIBY_cfbKSKsC0,2286
|
|
48
48
|
proj_flow/ext/sign/win32.py,sha256=yMAmO-DdIWZdOi_NxycRym8XM9WIsrWKtFANdIwthJ4,4968
|
|
49
|
+
proj_flow/ext/test_runner/__init__.py,sha256=dgPOf6b4AnoHVtPvhHrfC46m_4I-CCXvhQUsI-rXD-E,163
|
|
50
|
+
proj_flow/ext/test_runner/cli.py,sha256=qxDx5GJwbxK7ULlbgWpNKY9m_bMrHlRe7JdIuabU0T4,11880
|
|
51
|
+
proj_flow/ext/test_runner/driver/__init__.py,sha256=VJs_ODnF7-8DE0MbYKX-Bs-JDNqHgGdMkk2w142bcYQ,101
|
|
52
|
+
proj_flow/ext/test_runner/driver/commands.py,sha256=TzG9aqdUZLNa7yI2DajK7M7Ehhi_t8D_nEY6m1uICLo,2217
|
|
53
|
+
proj_flow/ext/test_runner/driver/test.py,sha256=xcZcBLNMkIN-jIQjtd7ke6Ngs4laTTd0TtMG_x_GlvE,19213
|
|
54
|
+
proj_flow/ext/test_runner/driver/testbed.py,sha256=jhxRvOXT1iEFIut9LIgJbixk7mUta9nKrcBEicaGhZA,4256
|
|
55
|
+
proj_flow/ext/test_runner/utils/__init__.py,sha256=VJs_ODnF7-8DE0MbYKX-Bs-JDNqHgGdMkk2w142bcYQ,101
|
|
56
|
+
proj_flow/ext/test_runner/utils/archives.py,sha256=f7whwVUeh5YtRwXxGCDs7CCRLd38aWPjwfb4bHBXyvI,1325
|
|
49
57
|
proj_flow/ext/tools/__init__.py,sha256=m9iJeCkdmrqLjBWNx9hp4o1H2kgzIXpgypHiSf3SzKE,373
|
|
50
58
|
proj_flow/ext/tools/pragma_once.py,sha256=BiNvX5X5pX_bGPZwBaKISlL6KkxJJGWFeZGSO-UDAgo,1218
|
|
51
59
|
proj_flow/ext/tools/run_linter.py,sha256=_EdmTfITc_hwI5hgMc_mKFkbw4unnDGkWaFohs0RDr4,6145
|
|
@@ -86,19 +94,19 @@ proj_flow/log/release.py,sha256=tm25MACkcn7DpneR5z7vvnU24cGGvuH9tj-R7NXuRrE,4463
|
|
|
86
94
|
proj_flow/log/hosting/__init__.py,sha256=9Teyw8jJcxeWH2MegqYEgW0n5OmSAWC7FFJj2u_UcrM,278
|
|
87
95
|
proj_flow/log/hosting/github.py,sha256=O2BdB50vzVSKKIu3qNEYBiBdEUIPqj6C2xVvGAKjTZ4,9123
|
|
88
96
|
proj_flow/log/rich_text/__init__.py,sha256=D3Y2jy9xlGgnQZdNC_ekoLzQtwkF_NTgLqDTWPvSRUk,279
|
|
89
|
-
proj_flow/log/rich_text/api.py,sha256=
|
|
97
|
+
proj_flow/log/rich_text/api.py,sha256=dJq2QMPbO4XczK4qux7q2Sb3vkGD_khUdn_N1FI8fBY,3513
|
|
90
98
|
proj_flow/log/rich_text/markdown.py,sha256=jBnNxxhBHzyIZ3Y4HXDfqpl7zlRbbKbKdwdnZwkmNAI,1623
|
|
91
99
|
proj_flow/log/rich_text/re_structured_text.py,sha256=DEl9KjBUF6cxfNWpQ7GVnHi7wKeuFnPGJwxQxjbCsnM,1823
|
|
92
100
|
proj_flow/minimal/__init__.py,sha256=Yv32uwmS5a9SXSjaMVK0xKla9sWtcA8QkJHt15ffhiU,354
|
|
93
101
|
proj_flow/minimal/base.py,sha256=jFAiJICAD6izCBqsNgt7syZ_lynpC5goNuEsaQv1a44,1227
|
|
94
102
|
proj_flow/minimal/bootstrap.py,sha256=PcZfBsUmj8uDPGBC55iUgD5O7W4VSkpCQb6r9GEyAaQ,556
|
|
95
103
|
proj_flow/minimal/init.py,sha256=-ZNzhPFqAgZFAuN5hYOJFuFy_wHkPzjeSk90G2GUQfk,4365
|
|
96
|
-
proj_flow/minimal/list.py,sha256=
|
|
97
|
-
proj_flow/minimal/run.py,sha256=
|
|
104
|
+
proj_flow/minimal/list.py,sha256=FIp49D0BW2UcOggibP_-5Ar1Ao_UmERMqHMDxNO7fRQ,8338
|
|
105
|
+
proj_flow/minimal/run.py,sha256=ASYisLyhPGVuDcaRIiZ5K7dtuaHXVihDskRSuveLccM,4702
|
|
98
106
|
proj_flow/minimal/system.py,sha256=9FliH5TD103JYSAe2O5EU7hkOHDgVzTqu0Exxk-WrXE,1579
|
|
99
107
|
proj_flow/minimal/ext/bug_report.py,sha256=dKy2FzVanoF3LISN5fsoaj-0TatGvVnahKuhy9HE4os,2311
|
|
100
108
|
proj_flow/project/__init__.py,sha256=AROrwhbuMR5rJE-HC769eL4IXrMLQYpQb3HgpkOAYqg,293
|
|
101
|
-
proj_flow/project/api.py,sha256=
|
|
109
|
+
proj_flow/project/api.py,sha256=j0j3UBWi8vwGLIScSL7t2fWUr2-ezAilYkc1FM-EfYM,2103
|
|
102
110
|
proj_flow/project/data.py,sha256=TluhBDoJEYL4dnyTpInmhQ49Uvf8mkWmpU-YMLQPNhE,317
|
|
103
111
|
proj_flow/project/interact.py,sha256=t9brVfLC0HR3LUWs2RSBjMi7NgCBQc9_Ip1ut5oYVa4,9522
|
|
104
112
|
proj_flow/project/cplusplus/__init__.py,sha256=cBjTOL8unMiPBWx9QkY4-vahzlHXNVNAxdaUTtVBjZM,302
|
|
@@ -160,8 +168,8 @@ proj_flow/template/licenses/MIT.mustache,sha256=NncPoQaNsuy-WmRmboik3fyhJJ8m5pc2
|
|
|
160
168
|
proj_flow/template/licenses/Unlicense.mustache,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
|
|
161
169
|
proj_flow/template/licenses/WTFPL.mustache,sha256=lvF4V_PrKKfZPa2TC8CZo8tlqaKvs3Bpv9G6XsWWQ4k,483
|
|
162
170
|
proj_flow/template/licenses/Zlib.mustache,sha256=uIj-mhSjes2HJ3rRapyy2ALflKRz4xQgS4mVM9827C0,868
|
|
163
|
-
proj_flow-0.
|
|
164
|
-
proj_flow-0.
|
|
165
|
-
proj_flow-0.
|
|
166
|
-
proj_flow-0.
|
|
167
|
-
proj_flow-0.
|
|
171
|
+
proj_flow-0.22.0.dist-info/METADATA,sha256=PR4boGwINN-tDoh2CE4VgcX4tH-AjYVcVT_EHR_LYb8,3472
|
|
172
|
+
proj_flow-0.22.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
173
|
+
proj_flow-0.22.0.dist-info/entry_points.txt,sha256=d_OmGKZzpY7FCWz0sZ4wnBAPZC75oMEzTgJZWtpDELo,49
|
|
174
|
+
proj_flow-0.22.0.dist-info/licenses/LICENSE,sha256=vpOQJ5QlrTedF3coEWvA4wJzVJH304f66ZitR7Od4iU,1068
|
|
175
|
+
proj_flow-0.22.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|