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.
Files changed (53) hide show
  1. proj_flow/__init__.py +1 -1
  2. proj_flow/api/env.py +7 -2
  3. proj_flow/api/makefile.py +1 -1
  4. proj_flow/base/plugins.py +1 -36
  5. proj_flow/base/registry.py +2 -1
  6. proj_flow/cli/__init__.py +1 -3
  7. proj_flow/cli/argument.py +1 -1
  8. proj_flow/ext/cplusplus/__init__.py +10 -0
  9. proj_flow/ext/cplusplus/cmake/__init__.py +12 -0
  10. proj_flow/{plugins → ext/cplusplus}/cmake/context.py +2 -2
  11. proj_flow/{plugins → ext/cplusplus}/cmake/parser.py +6 -28
  12. proj_flow/ext/cplusplus/cmake/steps.py +142 -0
  13. proj_flow/ext/cplusplus/cmake/version.py +35 -0
  14. proj_flow/{plugins → ext/cplusplus}/conan/__init__.py +2 -1
  15. proj_flow/{plugins → ext/cplusplus}/conan/_conan.py +7 -2
  16. proj_flow/ext/github/__init__.py +2 -2
  17. proj_flow/ext/github/cli.py +11 -2
  18. proj_flow/{plugins/github.py → ext/github/switches.py} +1 -1
  19. proj_flow/ext/{markdown_changelist.py → markdown_changelog.py} +2 -1
  20. proj_flow/ext/python/rtdocs.py +1 -1
  21. proj_flow/ext/python/version.py +1 -2
  22. proj_flow/ext/{re_structured_changelist.py → re_structured_changelog.py} +3 -1
  23. proj_flow/{plugins → ext}/sign/__init__.py +64 -44
  24. proj_flow/ext/sign/api.py +83 -0
  25. proj_flow/ext/sign/win32.py +152 -0
  26. proj_flow/{plugins/store/store_packages.py → ext/store.py} +51 -9
  27. proj_flow/log/release.py +12 -0
  28. proj_flow/log/rich_text/markdown.py +1 -1
  29. proj_flow/log/rich_text/re_structured_text.py +1 -1
  30. proj_flow/minimal/__init__.py +2 -2
  31. proj_flow/{plugins → minimal}/base.py +2 -2
  32. proj_flow/{plugins/commands → minimal}/init.py +1 -1
  33. {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/METADATA +2 -1
  34. {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/RECORD +38 -47
  35. proj_flow/plugins/__init__.py +0 -8
  36. proj_flow/plugins/cmake/__init__.py +0 -11
  37. proj_flow/plugins/cmake/build.py +0 -29
  38. proj_flow/plugins/cmake/config.py +0 -59
  39. proj_flow/plugins/cmake/pack.py +0 -37
  40. proj_flow/plugins/cmake/test.py +0 -29
  41. proj_flow/plugins/commands/__init__.py +0 -12
  42. proj_flow/plugins/commands/ci/__init__.py +0 -17
  43. proj_flow/plugins/commands/ci/changelog.py +0 -47
  44. proj_flow/plugins/commands/ci/matrix.py +0 -46
  45. proj_flow/plugins/commands/ci/release.py +0 -116
  46. proj_flow/plugins/sign/win32.py +0 -191
  47. proj_flow/plugins/store/__init__.py +0 -11
  48. proj_flow/plugins/store/store_both.py +0 -22
  49. proj_flow/plugins/store/store_tests.py +0 -21
  50. /proj_flow/{plugins → ext/cplusplus}/cmake/__version__.py +0 -0
  51. {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/WHEEL +0 -0
  52. {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/entry_points.txt +0 -0
  53. {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/licenses/LICENSE +0 -0
@@ -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
- )