proj-flow 0.9.2__py3-none-any.whl → 0.9.4__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/env.py +7 -2
- proj_flow/api/makefile.py +1 -1
- proj_flow/base/plugins.py +1 -36
- proj_flow/base/registry.py +2 -1
- proj_flow/cli/__init__.py +1 -3
- proj_flow/cli/argument.py +1 -1
- proj_flow/ext/cplusplus/__init__.py +10 -0
- proj_flow/ext/cplusplus/cmake/__init__.py +12 -0
- proj_flow/{plugins → ext/cplusplus}/cmake/context.py +2 -2
- proj_flow/{plugins → ext/cplusplus}/cmake/parser.py +6 -28
- proj_flow/ext/cplusplus/cmake/steps.py +142 -0
- proj_flow/ext/cplusplus/cmake/version.py +35 -0
- proj_flow/{plugins → ext/cplusplus}/conan/__init__.py +2 -1
- proj_flow/{plugins → ext/cplusplus}/conan/_conan.py +7 -2
- proj_flow/ext/github/__init__.py +2 -2
- proj_flow/ext/github/cli.py +11 -2
- proj_flow/{plugins/github.py → ext/github/switches.py} +1 -1
- proj_flow/ext/{markdown_changelist.py → markdown_changelog.py} +2 -1
- proj_flow/ext/python/rtdocs.py +1 -1
- proj_flow/ext/python/version.py +1 -2
- proj_flow/ext/{re_structured_changelist.py → re_structured_changelog.py} +3 -1
- proj_flow/{plugins → ext}/sign/__init__.py +64 -44
- proj_flow/ext/sign/api.py +83 -0
- proj_flow/ext/sign/win32.py +152 -0
- proj_flow/{plugins/store/store_packages.py → ext/store.py} +51 -9
- proj_flow/log/release.py +12 -0
- proj_flow/log/rich_text/markdown.py +1 -1
- proj_flow/log/rich_text/re_structured_text.py +1 -1
- proj_flow/minimal/__init__.py +2 -2
- proj_flow/{plugins → minimal}/base.py +2 -2
- proj_flow/{plugins/commands → minimal}/init.py +1 -1
- {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/METADATA +2 -1
- {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/RECORD +38 -47
- proj_flow/plugins/__init__.py +0 -8
- proj_flow/plugins/cmake/__init__.py +0 -11
- proj_flow/plugins/cmake/build.py +0 -29
- proj_flow/plugins/cmake/config.py +0 -59
- proj_flow/plugins/cmake/pack.py +0 -37
- proj_flow/plugins/cmake/test.py +0 -29
- proj_flow/plugins/commands/__init__.py +0 -12
- proj_flow/plugins/commands/ci/__init__.py +0 -17
- proj_flow/plugins/commands/ci/changelog.py +0 -47
- proj_flow/plugins/commands/ci/matrix.py +0 -46
- proj_flow/plugins/commands/ci/release.py +0 -116
- proj_flow/plugins/sign/win32.py +0 -191
- proj_flow/plugins/store/__init__.py +0 -11
- proj_flow/plugins/store/store_both.py +0 -22
- proj_flow/plugins/store/store_tests.py +0 -21
- /proj_flow/{plugins → ext/cplusplus}/cmake/__version__.py +0 -0
- {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/WHEEL +0 -0
- {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/entry_points.txt +0 -0
- {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/licenses/LICENSE +0 -0
proj_flow/plugins/sign/win32.py
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
-
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
The **proj_flow.plugins.sign.win32** provides code signing with SignTool
|
|
6
|
-
from Windows SDKs.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import base64
|
|
10
|
-
import json
|
|
11
|
-
import os
|
|
12
|
-
import platform
|
|
13
|
-
import struct
|
|
14
|
-
import subprocess
|
|
15
|
-
import sys
|
|
16
|
-
import winreg
|
|
17
|
-
from typing import Iterable, List, NamedTuple, Optional, Tuple
|
|
18
|
-
|
|
19
|
-
from proj_flow.api.env import Runtime
|
|
20
|
-
|
|
21
|
-
ENV_KEY = "SIGN_TOKEN"
|
|
22
|
-
|
|
23
|
-
Version = Tuple[int, int, int]
|
|
24
|
-
|
|
25
|
-
machine = {"ARM64": "arm64", "AMD64": "x64", "X86": "x86"}.get(
|
|
26
|
-
platform.machine(), "x86"
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def find_sign_tool(rt: Runtime) -> Optional[str]:
|
|
31
|
-
with winreg.OpenKeyEx(
|
|
32
|
-
winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"
|
|
33
|
-
) as kits:
|
|
34
|
-
try:
|
|
35
|
-
kits_root = winreg.QueryValueEx(kits, "KitsRoot10")[0]
|
|
36
|
-
except FileNotFoundError:
|
|
37
|
-
rt.message("sign/win32: No KitsRoot10 value")
|
|
38
|
-
return None
|
|
39
|
-
|
|
40
|
-
versions: List[Tuple[Version, str]] = []
|
|
41
|
-
try:
|
|
42
|
-
index = 0
|
|
43
|
-
while True:
|
|
44
|
-
ver_str = winreg.EnumKey(kits, index)
|
|
45
|
-
ver = tuple(int(chunk) for chunk in ver_str.split("."))
|
|
46
|
-
index += 1
|
|
47
|
-
versions.append((ver, ver_str))
|
|
48
|
-
except OSError:
|
|
49
|
-
pass
|
|
50
|
-
versions.sort()
|
|
51
|
-
versions.reverse()
|
|
52
|
-
rt.message(
|
|
53
|
-
"sign/win32: Regarding versions:", ", ".join(version[1] for version in versions)
|
|
54
|
-
)
|
|
55
|
-
for _, version in versions:
|
|
56
|
-
# C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe
|
|
57
|
-
sign_tool = os.path.join(kits_root, "bin", version, machine, "signtool.exe")
|
|
58
|
-
if os.path.isfile(sign_tool):
|
|
59
|
-
rt.message("sign/win32: using:", sign_tool)
|
|
60
|
-
return sign_tool
|
|
61
|
-
return None
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class Key(NamedTuple):
|
|
65
|
-
token: str
|
|
66
|
-
secret: bytes
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def _get_key_from_contents(key: str, rt: Runtime):
|
|
70
|
-
try:
|
|
71
|
-
obj = json.loads(key)
|
|
72
|
-
except json.decoder.JSONDecodeError:
|
|
73
|
-
rt.message("sign/win32: the signature is not a valid JSON document")
|
|
74
|
-
return None
|
|
75
|
-
|
|
76
|
-
if not isinstance(obj, dict):
|
|
77
|
-
rt.message("sign/win32: the signature is missing required fields")
|
|
78
|
-
return None
|
|
79
|
-
|
|
80
|
-
token = obj.get("token")
|
|
81
|
-
secret = obj.get("secret")
|
|
82
|
-
if not isinstance(token, str) or not isinstance(secret, str):
|
|
83
|
-
rt.message("sign/win32: the signature is missing required fields")
|
|
84
|
-
return None
|
|
85
|
-
|
|
86
|
-
return Key(
|
|
87
|
-
base64.b64decode(token).decode("UTF-8"),
|
|
88
|
-
base64.b64decode(secret),
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def get_key(rt: Runtime) -> Optional[Key]:
|
|
93
|
-
rt.message(f"sign/win32: trying ${ENV_KEY}")
|
|
94
|
-
env = os.environ.get(ENV_KEY)
|
|
95
|
-
if env:
|
|
96
|
-
key = _get_key_from_contents(env, rt)
|
|
97
|
-
if key is not None:
|
|
98
|
-
return key
|
|
99
|
-
local_signature = os.path.join(".", "signature.key")
|
|
100
|
-
home_signature = os.path.join(os.path.expanduser("~"), "signature.key")
|
|
101
|
-
for filename in [local_signature, home_signature]:
|
|
102
|
-
rt.message(f"sign/win32: trying {filename}")
|
|
103
|
-
if os.path.isfile(filename):
|
|
104
|
-
with open(filename, encoding="UTF-8") as file:
|
|
105
|
-
result = file.read().strip()
|
|
106
|
-
key = _get_key_from_contents(result, rt)
|
|
107
|
-
if key is not None:
|
|
108
|
-
return key
|
|
109
|
-
|
|
110
|
-
rt.message("sign/win32: no key set up")
|
|
111
|
-
|
|
112
|
-
return None
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def is_active(os_name: str, rt: Runtime):
|
|
116
|
-
if os_name != "windows":
|
|
117
|
-
return False
|
|
118
|
-
key = get_key(rt)
|
|
119
|
-
return (
|
|
120
|
-
key is not None
|
|
121
|
-
and key.token is not None
|
|
122
|
-
and key.secret is not None
|
|
123
|
-
and find_sign_tool(rt) is not None
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
_IMAGE_DOS_HEADER = "HHHHHHHHHHHHHH8sHH20sI"
|
|
128
|
-
_IMAGE_NT_HEADERS_Signature = "H"
|
|
129
|
-
_IMAGE_DOS_HEADER_size = struct.calcsize(_IMAGE_DOS_HEADER)
|
|
130
|
-
_IMAGE_NT_HEADERS_Signature_size = struct.calcsize(_IMAGE_NT_HEADERS_Signature)
|
|
131
|
-
_MZ = 23117
|
|
132
|
-
_PE = 17744
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def is_pe_exec(path: str):
|
|
136
|
-
with open(path, "rb") as exe:
|
|
137
|
-
mz_header = exe.read(_IMAGE_DOS_HEADER_size)
|
|
138
|
-
dos_header = struct.unpack(_IMAGE_DOS_HEADER, mz_header)
|
|
139
|
-
if dos_header[0] != _MZ:
|
|
140
|
-
return False
|
|
141
|
-
|
|
142
|
-
PE_offset = dos_header[-1]
|
|
143
|
-
if PE_offset < _IMAGE_DOS_HEADER_size:
|
|
144
|
-
return False
|
|
145
|
-
|
|
146
|
-
if PE_offset > _IMAGE_DOS_HEADER_size:
|
|
147
|
-
exe.read(PE_offset - _IMAGE_DOS_HEADER_size)
|
|
148
|
-
|
|
149
|
-
pe_header = exe.read(_IMAGE_NT_HEADERS_Signature_size)
|
|
150
|
-
signature = struct.unpack(_IMAGE_NT_HEADERS_Signature, pe_header)[0]
|
|
151
|
-
return signature == _PE
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
def sign(files: Iterable[str], rt: Runtime):
|
|
155
|
-
key = get_key(rt)
|
|
156
|
-
|
|
157
|
-
if key is None or key.token is None or key.secret is None:
|
|
158
|
-
print("proj-flow: sign: the key is missing", file=sys.stderr)
|
|
159
|
-
return 1
|
|
160
|
-
|
|
161
|
-
sign_tool = find_sign_tool(rt)
|
|
162
|
-
if sign_tool is None:
|
|
163
|
-
print("proj-flow: sign: signtool.exe not found", file=sys.stderr)
|
|
164
|
-
sys.exit(0)
|
|
165
|
-
|
|
166
|
-
with open("temp.pfx", "wb") as pfx:
|
|
167
|
-
pfx.write(key.secret)
|
|
168
|
-
|
|
169
|
-
args = [
|
|
170
|
-
sign_tool,
|
|
171
|
-
"sign",
|
|
172
|
-
"/f",
|
|
173
|
-
"temp.pfx",
|
|
174
|
-
"/p",
|
|
175
|
-
key.token,
|
|
176
|
-
"/tr",
|
|
177
|
-
"http://timestamp.digicert.com",
|
|
178
|
-
"/fd",
|
|
179
|
-
"sha256",
|
|
180
|
-
"/td",
|
|
181
|
-
"sha256",
|
|
182
|
-
*files,
|
|
183
|
-
]
|
|
184
|
-
|
|
185
|
-
result = 1
|
|
186
|
-
try:
|
|
187
|
-
result = subprocess.run(args, shell=False).returncode
|
|
188
|
-
finally:
|
|
189
|
-
os.remove("temp.pfx")
|
|
190
|
-
|
|
191
|
-
return result
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
-
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
The **proj_flow.plugins.store** provides ``"Store"``, ``"StoreTests"`` and
|
|
6
|
-
``"StorePackages"`` steps.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from . import store_both, store_packages, store_tests
|
|
10
|
-
|
|
11
|
-
__all__ = ["store_both", "store_tests", "store_packages"]
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
-
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
The **proj_flow.plugins.store** provides ``"Store"`` step.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from proj_flow.api import step
|
|
9
|
-
|
|
10
|
-
from .store_packages import StorePackages
|
|
11
|
-
from .store_tests import StoreTests
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@step.register
|
|
15
|
-
class StoreBoth(step.SerialStep):
|
|
16
|
-
"""Stores all artifacts created for ``preset`` config value."""
|
|
17
|
-
|
|
18
|
-
name = "Store"
|
|
19
|
-
|
|
20
|
-
def __init__(self):
|
|
21
|
-
super().__init__()
|
|
22
|
-
self.children = [StoreTests(), StorePackages()]
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
-
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
The **proj_flow.plugins.store** provides ``"StoreTests"`` step.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from proj_flow.api import env, step
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@step.register
|
|
12
|
-
class StoreTests(step.Step):
|
|
13
|
-
"""Stores test results gathered during tests for ``preset`` config value."""
|
|
14
|
-
|
|
15
|
-
name = "StoreTests"
|
|
16
|
-
runs_after = ["Test"]
|
|
17
|
-
|
|
18
|
-
def run(self, config: env.Config, rt: env.Runtime) -> int:
|
|
19
|
-
return rt.cp(
|
|
20
|
-
f"build/{config.preset}/test-results", "build/artifacts/test-results"
|
|
21
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|