proj-flow 0.9.3__py3-none-any.whl → 0.10.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 +6 -1
- proj_flow/api/arg.py +47 -24
- proj_flow/api/ctx.py +43 -23
- proj_flow/api/env.py +7 -2
- proj_flow/api/makefile.py +1 -1
- proj_flow/api/step.py +3 -5
- proj_flow/base/name_list.py +19 -0
- proj_flow/base/plugins.py +1 -36
- proj_flow/base/registry.py +19 -4
- proj_flow/cli/__init__.py +2 -4
- proj_flow/cli/argument.py +3 -3
- proj_flow/{flow/dependency.py → dependency.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/__version__.py +5 -0
- proj_flow/{plugins → ext/cplusplus}/cmake/context.py +10 -8
- 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 +7 -3
- proj_flow/{plugins → ext/cplusplus}/conan/_conan.py +8 -3
- proj_flow/ext/github/__init__.py +2 -2
- proj_flow/ext/github/cli.py +2 -11
- proj_flow/{plugins/github.py → ext/github/switches.py} +3 -3
- 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/flow/__init__.py +2 -2
- proj_flow/log/release.py +1 -1
- 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 +3 -2
- proj_flow/{plugins/commands → minimal}/init.py +44 -11
- proj_flow/minimal/run.py +1 -2
- proj_flow/project/__init__.py +11 -0
- proj_flow/project/api.py +51 -0
- proj_flow/project/cplusplus.py +17 -0
- proj_flow/project/data.py +14 -0
- proj_flow/{flow → project}/interact.py +114 -13
- {proj_flow-0.9.3.dist-info → proj_flow-0.10.0.dist-info}/METADATA +3 -2
- {proj_flow-0.9.3.dist-info → proj_flow-0.10.0.dist-info}/RECORD +50 -55
- proj_flow/flow/init.py +0 -65
- 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-0.9.3.dist-info → proj_flow-0.10.0.dist-info}/WHEEL +0 -0
- {proj_flow-0.9.3.dist-info → proj_flow-0.10.0.dist-info}/entry_points.txt +0 -0
- {proj_flow-0.9.3.dist-info → proj_flow-0.10.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
+
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
The **proj_flow.ext.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
|
+
from typing import Iterable, List, Optional, Tuple
|
|
17
|
+
|
|
18
|
+
from proj_flow.api.env import Config, Msg, Runtime
|
|
19
|
+
|
|
20
|
+
from .api import ENV_KEY, SigningTool, get_key, signing_tool
|
|
21
|
+
|
|
22
|
+
if sys.platform == "win32":
|
|
23
|
+
import winreg
|
|
24
|
+
|
|
25
|
+
@signing_tool.add
|
|
26
|
+
class Win32SigningTool(SigningTool):
|
|
27
|
+
def is_active(self, config: Config, rt: Runtime):
|
|
28
|
+
return _is_active(config.os, rt)
|
|
29
|
+
|
|
30
|
+
def sign(self, config: Config, rt: Runtime, files: List[str]):
|
|
31
|
+
rt.print("signtool", *(os.path.basename(file) for file in files))
|
|
32
|
+
return _sign(files, rt)
|
|
33
|
+
|
|
34
|
+
def is_signable(self, filename: str, as_package: bool):
|
|
35
|
+
if as_package:
|
|
36
|
+
_, ext = os.path.splitext(filename)
|
|
37
|
+
return ext.lower() == ".msi"
|
|
38
|
+
return _is_pe_exec(filename)
|
|
39
|
+
|
|
40
|
+
Version = Tuple[int, int, int]
|
|
41
|
+
|
|
42
|
+
machine = {"ARM64": "arm64", "AMD64": "x64", "X86": "x86"}.get(
|
|
43
|
+
platform.machine(), "x86"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def _find_sign_tool(rt: Runtime) -> Optional[str]:
|
|
47
|
+
with winreg.OpenKeyEx( # type: ignore
|
|
48
|
+
winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows Kits\Installed Roots" # type: ignore
|
|
49
|
+
) as kits:
|
|
50
|
+
try:
|
|
51
|
+
kits_root = winreg.QueryValueEx(kits, "KitsRoot10")[0] # type: ignore
|
|
52
|
+
except FileNotFoundError:
|
|
53
|
+
rt.message("sign/win32: No KitsRoot10 value")
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
versions: List[Tuple[Version, str]] = []
|
|
57
|
+
try:
|
|
58
|
+
index = 0
|
|
59
|
+
while True:
|
|
60
|
+
ver_str = winreg.EnumKey(kits, index) # type: ignore
|
|
61
|
+
ver = tuple(int(chunk) for chunk in ver_str.split("."))
|
|
62
|
+
index += 1
|
|
63
|
+
versions.append((ver, ver_str)) # type: ignore
|
|
64
|
+
except OSError:
|
|
65
|
+
pass
|
|
66
|
+
versions.sort()
|
|
67
|
+
versions.reverse()
|
|
68
|
+
rt.message(
|
|
69
|
+
"sign/win32: Regarding versions:",
|
|
70
|
+
", ".join(version[1] for version in versions),
|
|
71
|
+
)
|
|
72
|
+
for _, version in versions:
|
|
73
|
+
# C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe
|
|
74
|
+
sign_tool = os.path.join(kits_root, "bin", version, machine, "signtool.exe")
|
|
75
|
+
if os.path.isfile(sign_tool):
|
|
76
|
+
rt.message("sign/win32: using:", sign_tool)
|
|
77
|
+
return sign_tool
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
def _is_active(os_name: str, rt: Runtime):
|
|
81
|
+
if os_name != "windows":
|
|
82
|
+
return False
|
|
83
|
+
key = get_key(rt)
|
|
84
|
+
return (
|
|
85
|
+
key is not None
|
|
86
|
+
and key.token is not None
|
|
87
|
+
and key.secret is not None
|
|
88
|
+
and _find_sign_tool(rt) is not None
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
_IMAGE_DOS_HEADER = "HHHHHHHHHHHHHH8sHH20sI"
|
|
92
|
+
_IMAGE_NT_HEADERS_Signature = "H"
|
|
93
|
+
_IMAGE_DOS_HEADER_size = struct.calcsize(_IMAGE_DOS_HEADER)
|
|
94
|
+
_IMAGE_NT_HEADERS_Signature_size = struct.calcsize(_IMAGE_NT_HEADERS_Signature)
|
|
95
|
+
_MZ = 23117
|
|
96
|
+
_PE = 17744
|
|
97
|
+
|
|
98
|
+
def _is_pe_exec(path: str):
|
|
99
|
+
with open(path, "rb") as exe:
|
|
100
|
+
mz_header = exe.read(_IMAGE_DOS_HEADER_size)
|
|
101
|
+
dos_header = struct.unpack(_IMAGE_DOS_HEADER, mz_header)
|
|
102
|
+
if dos_header[0] != _MZ:
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
PE_offset = dos_header[-1]
|
|
106
|
+
if PE_offset < _IMAGE_DOS_HEADER_size:
|
|
107
|
+
return False
|
|
108
|
+
|
|
109
|
+
if PE_offset > _IMAGE_DOS_HEADER_size:
|
|
110
|
+
exe.read(PE_offset - _IMAGE_DOS_HEADER_size)
|
|
111
|
+
|
|
112
|
+
pe_header = exe.read(_IMAGE_NT_HEADERS_Signature_size)
|
|
113
|
+
signature = struct.unpack(_IMAGE_NT_HEADERS_Signature, pe_header)[0]
|
|
114
|
+
return signature == _PE
|
|
115
|
+
|
|
116
|
+
def _sign(files: Iterable[str], rt: Runtime):
|
|
117
|
+
key = get_key(rt)
|
|
118
|
+
|
|
119
|
+
if key is None or key.token is None or key.secret is None:
|
|
120
|
+
rt.fatal("sign: the key is missing")
|
|
121
|
+
|
|
122
|
+
sign_tool = _find_sign_tool(rt)
|
|
123
|
+
if sign_tool is None:
|
|
124
|
+
rt.message("proj-flow: sign: signtool.exe not found", level=Msg.ALWAYS)
|
|
125
|
+
return 0
|
|
126
|
+
|
|
127
|
+
with open("temp.pfx", "wb") as pfx:
|
|
128
|
+
pfx.write(key.secret)
|
|
129
|
+
|
|
130
|
+
args = [
|
|
131
|
+
sign_tool,
|
|
132
|
+
"sign",
|
|
133
|
+
"/f",
|
|
134
|
+
"temp.pfx",
|
|
135
|
+
"/p",
|
|
136
|
+
key.token,
|
|
137
|
+
"/tr",
|
|
138
|
+
"http://timestamp.digicert.com",
|
|
139
|
+
"/fd",
|
|
140
|
+
"sha256",
|
|
141
|
+
"/td",
|
|
142
|
+
"sha256",
|
|
143
|
+
*files,
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
result = 1
|
|
147
|
+
try:
|
|
148
|
+
result = subprocess.run(args, shell=False).returncode
|
|
149
|
+
finally:
|
|
150
|
+
os.remove("temp.pfx")
|
|
151
|
+
|
|
152
|
+
return result
|
|
@@ -2,18 +2,17 @@
|
|
|
2
2
|
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
3
|
|
|
4
4
|
"""
|
|
5
|
-
The **proj_flow.
|
|
5
|
+
The **proj_flow.ext.store** provides ``"Store"``, ``"StoreTests"`` and
|
|
6
|
+
``"StorePackages"`` steps.
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
9
|
import os
|
|
9
10
|
import shutil
|
|
10
11
|
from typing import List, cast
|
|
11
12
|
|
|
12
|
-
from proj_flow.api import env, step
|
|
13
|
+
from proj_flow.api import env, release, step
|
|
13
14
|
from proj_flow.base.uname import uname
|
|
14
15
|
|
|
15
|
-
from ..cmake.parser import get_project
|
|
16
|
-
|
|
17
16
|
_system, _version, _arch = uname()
|
|
18
17
|
_version = "" if _version is None else f"-{_version}"
|
|
19
18
|
_project_pkg = None
|
|
@@ -26,12 +25,24 @@ def _package_name(config: env.Config, pkg: str, group: str):
|
|
|
26
25
|
return f"{pkg}-{_system}{_version}-{_arch}{debug}{suffix}"
|
|
27
26
|
|
|
28
27
|
|
|
28
|
+
def _get_project(rt: env.Runtime):
|
|
29
|
+
def wrap(suite: release.ProjectSuite):
|
|
30
|
+
return suite.get_project(rt)
|
|
31
|
+
|
|
32
|
+
return wrap
|
|
33
|
+
|
|
34
|
+
|
|
29
35
|
@step.register
|
|
30
|
-
class StorePackages:
|
|
36
|
+
class StorePackages(step.Step):
|
|
31
37
|
"""Stores archives and installers build for ``preset`` config value."""
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
@property
|
|
40
|
+
def name(self):
|
|
41
|
+
return "StorePackages"
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def runs_after(self):
|
|
45
|
+
return ["Pack"]
|
|
35
46
|
|
|
36
47
|
def run(self, config: env.Config, rt: env.Runtime) -> int:
|
|
37
48
|
if not rt.dry_run:
|
|
@@ -41,10 +52,10 @@ class StorePackages:
|
|
|
41
52
|
|
|
42
53
|
global _project_pkg
|
|
43
54
|
if _project_pkg is None:
|
|
44
|
-
project =
|
|
55
|
+
_, project = release.project_suites.find(_get_project(rt))
|
|
45
56
|
if project is None:
|
|
46
57
|
rt.fatal(f"Cannot get project information from {rt.root}")
|
|
47
|
-
_project_pkg = project.
|
|
58
|
+
_project_pkg = project.archive_name
|
|
48
59
|
|
|
49
60
|
main_group = cast(str, rt._cfg.get("package", {}).get("main-group"))
|
|
50
61
|
if main_group is not None and not rt.dry_run:
|
|
@@ -77,3 +88,34 @@ class StorePackages:
|
|
|
77
88
|
"build/artifacts/packages",
|
|
78
89
|
f"^{_project_pkg}-.*$",
|
|
79
90
|
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@step.register
|
|
94
|
+
class StoreTests(step.Step):
|
|
95
|
+
"""Stores test results gathered during tests for ``preset`` config value."""
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def name(self):
|
|
99
|
+
return "StoreTests"
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def runs_after(self):
|
|
103
|
+
return ["Test"]
|
|
104
|
+
|
|
105
|
+
def run(self, config: env.Config, rt: env.Runtime) -> int:
|
|
106
|
+
return rt.cp(
|
|
107
|
+
f"build/{config.preset}/test-results", "build/artifacts/test-results"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@step.register
|
|
112
|
+
class StoreBoth(step.SerialStep):
|
|
113
|
+
"""Stores all artifacts created for ``preset`` config value."""
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def name(self):
|
|
117
|
+
return "Store"
|
|
118
|
+
|
|
119
|
+
def __init__(self):
|
|
120
|
+
super().__init__()
|
|
121
|
+
self.children = [StoreTests(), StorePackages()]
|
proj_flow/flow/__init__.py
CHANGED
|
@@ -6,6 +6,6 @@ The **proj_flow.flow** contains the inner workings of various *Project Flow*
|
|
|
6
6
|
components.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
from . import configs,
|
|
9
|
+
from . import configs, layer, steps
|
|
10
10
|
|
|
11
|
-
__all__ = ["configs", "
|
|
11
|
+
__all__ = ["configs", "layer", "steps"]
|
proj_flow/log/release.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
3
|
|
|
4
4
|
"""
|
|
5
|
-
The **proj_flow.log.
|
|
5
|
+
The **proj_flow.log.rich_text.re_structured_text** provides details of making
|
|
6
6
|
reStructuredText changelogs.
|
|
7
7
|
"""
|
|
8
8
|
|
proj_flow/minimal/__init__.py
CHANGED
|
@@ -6,6 +6,6 @@ The **proj_flow.minimal** defines minimal extension package: ``bootstrap``
|
|
|
6
6
|
and ``run`` commands, with basic set of steps.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
from . import bootstrap, list, run, system
|
|
9
|
+
from . import bootstrap, init, list, run, system
|
|
10
10
|
|
|
11
|
-
__all__ = ["bootstrap", "list", "run", "system"]
|
|
11
|
+
__all__ = ["bootstrap", "init", "list", "run", "system"]
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
3
|
|
|
4
4
|
"""
|
|
5
|
-
The **proj_flow.
|
|
6
|
-
projects.
|
|
5
|
+
The **proj_flow.minimal.base** provides basic initialization setup for all
|
|
6
|
+
new projects.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from proj_flow import __version__, api
|
|
@@ -26,5 +26,6 @@ api.init.register_init_step(GitInit())
|
|
|
26
26
|
api.ctx.register_init_setting(
|
|
27
27
|
api.ctx.Setting("__flow_version__", value=__version__),
|
|
28
28
|
api.ctx.Setting("${", value="${"),
|
|
29
|
+
project=None,
|
|
29
30
|
is_hidden=True,
|
|
30
31
|
)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
3
|
|
|
4
4
|
"""
|
|
5
|
-
The **proj_flow.
|
|
5
|
+
The **proj_flow.minimal.init** implements ``proj-flow init`` command.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import json
|
|
@@ -10,12 +10,36 @@ import os
|
|
|
10
10
|
import sys
|
|
11
11
|
from typing import Annotated, Optional
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
import yaml
|
|
14
|
+
|
|
15
|
+
from proj_flow import dependency, flow
|
|
14
16
|
from proj_flow.api import arg, ctx, env, init
|
|
17
|
+
from proj_flow.base.name_list import name_list
|
|
18
|
+
from proj_flow.project import api, interact
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _project_types():
|
|
22
|
+
return list(map(lambda proj: proj.id, api.project_type.get()))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _project_help():
|
|
26
|
+
return (
|
|
27
|
+
"Type of project to create. "
|
|
28
|
+
f"Allowed values are: {name_list(_project_types())}"
|
|
29
|
+
)
|
|
15
30
|
|
|
16
31
|
|
|
17
32
|
@arg.command("init")
|
|
18
33
|
def main(
|
|
34
|
+
project: Annotated[
|
|
35
|
+
str,
|
|
36
|
+
arg.Argument(
|
|
37
|
+
help=_project_help,
|
|
38
|
+
meta="project",
|
|
39
|
+
pos=True,
|
|
40
|
+
choices=_project_types,
|
|
41
|
+
),
|
|
42
|
+
],
|
|
19
43
|
path: Annotated[
|
|
20
44
|
Optional[str],
|
|
21
45
|
arg.Argument(
|
|
@@ -38,26 +62,35 @@ def main(
|
|
|
38
62
|
):
|
|
39
63
|
"""Initialize new project"""
|
|
40
64
|
|
|
65
|
+
try:
|
|
66
|
+
current_project = api.get_project_type(project)
|
|
67
|
+
except api.ProjectNotFound:
|
|
68
|
+
print(f"proj-flow init: error: project type `{project}` is not known")
|
|
69
|
+
return 1
|
|
70
|
+
|
|
41
71
|
if path is not None:
|
|
42
72
|
os.makedirs(path, exist_ok=True)
|
|
43
73
|
os.chdir(path)
|
|
44
74
|
|
|
45
|
-
errors =
|
|
75
|
+
errors = dependency.verify(dependency.gather(init.__steps))
|
|
46
76
|
if len(errors) > 0:
|
|
47
77
|
if not rt.silent:
|
|
48
78
|
for error in errors:
|
|
49
79
|
print(f"proj-flow: {error}", file=sys.stderr)
|
|
50
80
|
return 1
|
|
51
81
|
|
|
52
|
-
context =
|
|
53
|
-
flow.init.all_default() if non_interactive else flow.interact.prompt()
|
|
54
|
-
)
|
|
82
|
+
context = current_project.get_context(not non_interactive)
|
|
55
83
|
if not non_interactive and not rt.silent:
|
|
56
84
|
print()
|
|
57
85
|
|
|
58
|
-
if save_context:
|
|
59
|
-
|
|
60
|
-
|
|
86
|
+
if save_context and rt.verbose:
|
|
87
|
+
lines = yaml.dump(context, indent=4).rstrip().split("\n")
|
|
88
|
+
for line in lines:
|
|
89
|
+
rt.message("[CONTEXT]", line)
|
|
90
|
+
|
|
91
|
+
if save_context and not rt.dry_run:
|
|
92
|
+
with open(".context.yaml", "w", encoding="UTF-8") as jsonf:
|
|
93
|
+
yaml.dump(context, jsonf, indent=4)
|
|
61
94
|
|
|
62
95
|
flow.layer.copy_license(rt, context)
|
|
63
96
|
if not rt.silent:
|
|
@@ -67,9 +100,9 @@ def main(
|
|
|
67
100
|
for fs_layer in layers:
|
|
68
101
|
fs_layer.run(rt, context)
|
|
69
102
|
|
|
70
|
-
if save_context:
|
|
103
|
+
if save_context and not rt.dry_run:
|
|
71
104
|
with open(".gitignore", "ab") as ignoref:
|
|
72
|
-
ignoref.write("\n/.context.
|
|
105
|
+
ignoref.write("\n/.context.yaml\n".encode("UTF-8"))
|
|
73
106
|
|
|
74
107
|
for step in init.__steps:
|
|
75
108
|
step.postprocess(rt, context)
|
proj_flow/minimal/run.py
CHANGED
|
@@ -11,9 +11,8 @@ import sys
|
|
|
11
11
|
from contextlib import contextmanager
|
|
12
12
|
from typing import Annotated, List, Optional, Set, cast
|
|
13
13
|
|
|
14
|
-
from proj_flow import api
|
|
14
|
+
from proj_flow import api, dependency
|
|
15
15
|
from proj_flow.base import matrix
|
|
16
|
-
from proj_flow.flow import dependency
|
|
17
16
|
from proj_flow.flow.configs import Configs
|
|
18
17
|
|
|
19
18
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
+
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
The **proj_flow.project** contains the inner workings of ``proj-flow init``
|
|
6
|
+
command.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from . import api, cplusplus, data, interact
|
|
10
|
+
|
|
11
|
+
__all__ = ["api", "cplusplus", "data", "interact"]
|
proj_flow/project/api.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
+
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
The **proj_flow.project.api** defines an extension point for project suites.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from abc import ABC, abstractmethod
|
|
9
|
+
from typing import Any, List, NamedTuple, Optional
|
|
10
|
+
|
|
11
|
+
from proj_flow import base
|
|
12
|
+
from proj_flow.api import ctx
|
|
13
|
+
from proj_flow.project import interact
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ProjectType(ABC):
|
|
17
|
+
name: str
|
|
18
|
+
id: str
|
|
19
|
+
|
|
20
|
+
def __init__(self, name: str, id: str):
|
|
21
|
+
self.name = name
|
|
22
|
+
self.id = id
|
|
23
|
+
|
|
24
|
+
def register_switch(self, key: str, prompt: str, enabled: bool):
|
|
25
|
+
ctx.register_switch(key, prompt, enabled, self.id)
|
|
26
|
+
|
|
27
|
+
def register_internal(self, key: str, value: Any):
|
|
28
|
+
ctx.register_internal(key, value)
|
|
29
|
+
|
|
30
|
+
def register_init_setting(self, *settings: ctx.Setting, is_hidden=False):
|
|
31
|
+
ctx.register_init_setting(*settings, is_hidden=is_hidden, project=self.id)
|
|
32
|
+
|
|
33
|
+
def get_context(self, interactive: bool):
|
|
34
|
+
return interact.get_context(interactive, self.id)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
project_type = base.registry.Registry[ProjectType]("ProjectType")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ProjectNotFound(Exception):
|
|
41
|
+
name: str
|
|
42
|
+
|
|
43
|
+
def __init__(self, name: str):
|
|
44
|
+
self.name = name
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_project_type(id: str):
|
|
48
|
+
result, _ = project_type.find(lambda proj: proj.id == id)
|
|
49
|
+
if result is None:
|
|
50
|
+
raise ProjectNotFound(id)
|
|
51
|
+
return result
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
+
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
The **proj_flow.project.cplusplus** registers a ``"C++"`` projects support.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from proj_flow.project import api
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@api.project_type.add
|
|
12
|
+
class CPlusPlus(api.ProjectType):
|
|
13
|
+
def __init__(self):
|
|
14
|
+
super().__init__("C++ + CMake + Conan", "cxx")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
project = api.get_project_type("cxx")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
+
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
The **proj_flow.project.data** supports the ``init`` command.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from proj_flow.api import ctx
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_internal(key: str, value: Any = None):
|
|
14
|
+
return ctx.internals.get(key, value)
|