proj-flow 0.9.4__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/step.py +3 -5
- proj_flow/base/name_list.py +19 -0
- proj_flow/base/registry.py +17 -3
- proj_flow/cli/__init__.py +1 -1
- proj_flow/cli/argument.py +2 -2
- proj_flow/{flow/dependency.py → dependency.py} +1 -1
- proj_flow/ext/cplusplus/cmake/__version__.py +5 -0
- proj_flow/ext/cplusplus/cmake/context.py +8 -6
- proj_flow/ext/cplusplus/conan/__init__.py +5 -2
- proj_flow/ext/cplusplus/conan/_conan.py +1 -1
- proj_flow/ext/github/cli.py +2 -11
- proj_flow/ext/github/switches.py +2 -2
- proj_flow/flow/__init__.py +2 -2
- proj_flow/minimal/base.py +1 -0
- proj_flow/minimal/init.py +43 -10
- 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.4.dist-info → proj_flow-0.10.0.dist-info}/METADATA +2 -2
- {proj_flow-0.9.4.dist-info → proj_flow-0.10.0.dist-info}/RECORD +29 -25
- proj_flow/flow/init.py +0 -65
- {proj_flow-0.9.4.dist-info → proj_flow-0.10.0.dist-info}/WHEEL +0 -0
- {proj_flow-0.9.4.dist-info → proj_flow-0.10.0.dist-info}/entry_points.txt +0 -0
- {proj_flow-0.9.4.dist-info → proj_flow-0.10.0.dist-info}/licenses/LICENSE +0 -0
proj_flow/__init__.py
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
# Copyright (c) 2025 Marcin Zdun
|
|
2
2
|
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
"""
|
|
5
|
+
The **proj_flow** contains only ``__version__`` to be updated, nothing more.
|
|
6
|
+
This is in an attempt to make this module easy to load initially.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "0.10.0"
|
proj_flow/api/arg.py
CHANGED
|
@@ -12,48 +12,71 @@ from dataclasses import dataclass, field
|
|
|
12
12
|
|
|
13
13
|
from proj_flow.base import inspect as _inspect
|
|
14
14
|
|
|
15
|
+
T = typing.TypeVar("T")
|
|
16
|
+
LazyArgument = typing.Union[T, typing.Callable[[], T]]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _eval(arg: LazyArgument[T]) -> T:
|
|
20
|
+
if callable(arg):
|
|
21
|
+
return typing.cast(T, arg())
|
|
22
|
+
return arg
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class _Completable(typing.Protocol):
|
|
26
|
+
completer: _inspect.Function
|
|
27
|
+
|
|
15
28
|
|
|
16
29
|
@dataclass
|
|
17
30
|
class Argument:
|
|
18
|
-
help: str = ""
|
|
31
|
+
help: LazyArgument[str] = ""
|
|
19
32
|
pos: bool = False
|
|
20
|
-
names: typing.List[str] = field(default_factory=list)
|
|
21
|
-
nargs: typing.Union[str, int, None] = None
|
|
22
|
-
opt: typing.Optional[bool] = None
|
|
23
|
-
meta: typing.Optional[str] = None
|
|
24
|
-
action: typing.Union[str, argparse.Action, None] = None
|
|
25
|
-
default: typing.Optional[typing.Any] = None
|
|
26
|
-
choices: typing.Optional[typing.List[str]] = None
|
|
33
|
+
names: LazyArgument[typing.List[str]] = field(default_factory=list)
|
|
34
|
+
nargs: LazyArgument[typing.Union[str, int, None]] = None
|
|
35
|
+
opt: LazyArgument[typing.Optional[bool]] = None
|
|
36
|
+
meta: LazyArgument[typing.Optional[str]] = None
|
|
37
|
+
action: LazyArgument[typing.Union[str, argparse.Action, None]] = None
|
|
38
|
+
default: LazyArgument[typing.Optional[typing.Any]] = None
|
|
39
|
+
choices: LazyArgument[typing.Optional[typing.List[str]]] = None
|
|
27
40
|
completer: typing.Optional[_inspect.Function] = None
|
|
28
41
|
|
|
29
42
|
def visit(self, parser: argparse.ArgumentParser, name: str):
|
|
30
43
|
kwargs = {}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if
|
|
42
|
-
kwargs["
|
|
44
|
+
|
|
45
|
+
self_help = _eval(self.help)
|
|
46
|
+
self_names = _eval(self.names)
|
|
47
|
+
self_nargs = _eval(self.nargs)
|
|
48
|
+
self_opt = _eval(self.opt)
|
|
49
|
+
self_meta = _eval(self.meta)
|
|
50
|
+
self_action = _eval(self.action)
|
|
51
|
+
self_default = _eval(self.default)
|
|
52
|
+
self_choices = _eval(self.choices)
|
|
53
|
+
|
|
54
|
+
if self_help is not None:
|
|
55
|
+
kwargs["help"] = self_help
|
|
56
|
+
if self_nargs is not None:
|
|
57
|
+
kwargs["nargs"] = self_nargs
|
|
58
|
+
if self_meta is not None:
|
|
59
|
+
kwargs["metavar"] = self_meta
|
|
60
|
+
if self_default is not None:
|
|
61
|
+
kwargs["default"] = self_default
|
|
62
|
+
if self_action is not None:
|
|
63
|
+
kwargs["action"] = self_action
|
|
64
|
+
if self_choices is not None:
|
|
65
|
+
kwargs["choices"] = self_choices
|
|
43
66
|
|
|
44
67
|
names = (
|
|
45
|
-
[name] if self.pos else
|
|
68
|
+
[name] if self.pos else self_names if len(self_names) > 0 else [f"--{name}"]
|
|
46
69
|
)
|
|
47
70
|
|
|
48
71
|
if self.pos:
|
|
49
|
-
kwargs["nargs"] = "?" if
|
|
72
|
+
kwargs["nargs"] = "?" if self_opt else 1
|
|
50
73
|
else:
|
|
51
74
|
kwargs["dest"] = name
|
|
52
|
-
kwargs["required"] = not
|
|
75
|
+
kwargs["required"] = not self_opt
|
|
53
76
|
|
|
54
77
|
action = parser.add_argument(*names, **kwargs)
|
|
55
78
|
if self.completer:
|
|
56
|
-
action.completer = self.completer
|
|
79
|
+
typing.cast(_Completable, action).completer = self.completer
|
|
57
80
|
|
|
58
81
|
return action
|
|
59
82
|
|
proj_flow/api/ctx.py
CHANGED
|
@@ -9,9 +9,10 @@ import datetime
|
|
|
9
9
|
import inspect
|
|
10
10
|
import os
|
|
11
11
|
from dataclasses import dataclass
|
|
12
|
-
from typing import Callable, Dict, Iterable, List, Optional, Union
|
|
12
|
+
from typing import Any, Callable, Dict, Iterable, List, Optional, Union, cast
|
|
13
13
|
|
|
14
14
|
from proj_flow.base import cmd
|
|
15
|
+
from proj_flow.base import inspect as _inspect
|
|
15
16
|
|
|
16
17
|
package_root = os.path.dirname(os.path.dirname(__file__))
|
|
17
18
|
template_dir = "template"
|
|
@@ -26,32 +27,44 @@ SettingsType = Dict[str, StrOrBool]
|
|
|
26
27
|
class Setting:
|
|
27
28
|
json_key: str
|
|
28
29
|
prompt: str = ""
|
|
29
|
-
value: Union[Values, Callable[[], Values]] = ""
|
|
30
|
+
value: Union[Values, Callable[[], Values], Callable[[SettingsType], Values]] = ""
|
|
30
31
|
fix: Optional[str] = None
|
|
31
32
|
force_fix: bool = False
|
|
33
|
+
project: Optional[str] = None
|
|
32
34
|
|
|
33
35
|
def calc_value(self, previous: SettingsType):
|
|
34
|
-
if
|
|
36
|
+
if callable(self.value):
|
|
35
37
|
kwargs = {}
|
|
36
38
|
|
|
37
39
|
params = inspect.signature(self.value).parameters
|
|
38
40
|
if "settings" in params:
|
|
39
41
|
kwargs["settings"] = previous
|
|
40
42
|
|
|
41
|
-
return self.value(**kwargs)
|
|
43
|
+
return cast(_inspect.Function, self.value)(**kwargs)
|
|
42
44
|
|
|
43
45
|
return self.value
|
|
44
46
|
|
|
45
47
|
|
|
46
|
-
def register_init_setting(*
|
|
48
|
+
def register_init_setting(*settings: Setting, is_hidden=False, project: Optional[str]):
|
|
49
|
+
if project is not None:
|
|
50
|
+
for setting in settings:
|
|
51
|
+
setting.project = project
|
|
52
|
+
(hidden if is_hidden else defaults).extend(settings)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def register_common_init_setting(*setting: Setting, is_hidden=False):
|
|
47
56
|
(hidden if is_hidden else defaults).extend(setting)
|
|
48
57
|
|
|
49
58
|
|
|
50
|
-
def register_switch(key: str, prompt: str, enabled: bool):
|
|
59
|
+
def register_switch(key: str, prompt: str, enabled: bool, project: Optional[str]):
|
|
60
|
+
switches.append(Setting(key, prompt, value=enabled, project=project))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def register_common_switch(key: str, prompt: str, enabled: bool):
|
|
51
64
|
switches.append(Setting(key, prompt, value=enabled))
|
|
52
65
|
|
|
53
66
|
|
|
54
|
-
def register_internal(key: str, value:
|
|
67
|
+
def register_internal(key: str, value: Any):
|
|
55
68
|
internals[key] = value
|
|
56
69
|
|
|
57
70
|
|
|
@@ -59,17 +72,20 @@ def _git_config(name: str):
|
|
|
59
72
|
def wrap():
|
|
60
73
|
proc = cmd.run("git", "config", name, capture_output=True)
|
|
61
74
|
if proc is None or proc.returncode != 0:
|
|
62
|
-
return
|
|
75
|
+
return ""
|
|
63
76
|
return proc.stdout.strip()
|
|
64
77
|
|
|
65
78
|
return wrap
|
|
66
79
|
|
|
67
80
|
|
|
68
|
-
def move_to_front(preferred: str, values: Iterable[str]):
|
|
81
|
+
def move_to_front(preferred: str, values: Iterable[Optional[str]]):
|
|
69
82
|
result: List[str] = []
|
|
70
83
|
|
|
71
84
|
has_preferred = False
|
|
72
85
|
for value in values:
|
|
86
|
+
if value is None:
|
|
87
|
+
continue
|
|
88
|
+
|
|
73
89
|
if value == preferred:
|
|
74
90
|
has_preferred = True
|
|
75
91
|
else:
|
|
@@ -94,7 +110,7 @@ def _enum_licenses():
|
|
|
94
110
|
root = os.path.abspath(os.path.join(package_root, template_dir, "licenses"))
|
|
95
111
|
for _, dirnames, filenames in os.walk(root):
|
|
96
112
|
dirnames[:] = []
|
|
97
|
-
iter =
|
|
113
|
+
iter = map(_as_mustache, filenames)
|
|
98
114
|
return move_to_front("MIT", iter)
|
|
99
115
|
return []
|
|
100
116
|
|
|
@@ -114,11 +130,11 @@ def _get_nothing(_: SettingsType) -> StrOrBool:
|
|
|
114
130
|
|
|
115
131
|
|
|
116
132
|
def _map(internal_key: str):
|
|
117
|
-
def impl(key:
|
|
133
|
+
def impl(key: StrOrBool) -> StrOrBool:
|
|
118
134
|
mapped = internals.get(internal_key)
|
|
119
135
|
if not isinstance(mapped, dict):
|
|
120
|
-
return
|
|
121
|
-
return mapped.get(key)
|
|
136
|
+
return ""
|
|
137
|
+
return mapped.get(key, "")
|
|
122
138
|
|
|
123
139
|
return impl
|
|
124
140
|
|
|
@@ -152,12 +168,12 @@ def _build_fixup(settings: SettingsType, fixup: str):
|
|
|
152
168
|
value = code(settings)
|
|
153
169
|
|
|
154
170
|
if result:
|
|
155
|
-
result
|
|
171
|
+
result = f"{result}{value}"
|
|
156
172
|
else:
|
|
157
173
|
result = value
|
|
158
174
|
|
|
159
175
|
if verbose:
|
|
160
|
-
result
|
|
176
|
+
result = f"{result}{verbose}"
|
|
161
177
|
|
|
162
178
|
return result
|
|
163
179
|
|
|
@@ -169,7 +185,7 @@ def _fixed(fixup: str):
|
|
|
169
185
|
return wrap
|
|
170
186
|
|
|
171
187
|
|
|
172
|
-
internals = {}
|
|
188
|
+
internals: Dict[str, Any] = {}
|
|
173
189
|
|
|
174
190
|
switches: List[Setting] = []
|
|
175
191
|
|
|
@@ -200,18 +216,21 @@ defaults: List[Setting] = [
|
|
|
200
216
|
"INCLUDE_PREFIX",
|
|
201
217
|
'Prefix for includes (as in #include "{PREFIX}/version.hpp")',
|
|
202
218
|
_fixed("{PROJECT.NAME}"),
|
|
219
|
+
project="cxx",
|
|
203
220
|
),
|
|
204
221
|
Setting(
|
|
205
222
|
"NAME_PREFIX",
|
|
206
223
|
"CMake variable name prefix",
|
|
207
224
|
_fixed("{PROJECT.NAME$safe$upper}"),
|
|
225
|
+
project="cxx",
|
|
208
226
|
),
|
|
209
227
|
Setting(
|
|
210
228
|
"NAMESPACE",
|
|
211
229
|
"C++ namespace for the project",
|
|
212
230
|
_fixed("{PROJECT.NAME$safe}"),
|
|
231
|
+
project="cxx",
|
|
213
232
|
),
|
|
214
|
-
Setting("EXT", "Extension for code files", _list_ext),
|
|
233
|
+
Setting("EXT", "Extension for code files", _list_ext, project="cxx"),
|
|
215
234
|
Setting("SRCDIR", "Directory for code files", "src"),
|
|
216
235
|
Setting(
|
|
217
236
|
"INCLUDEDIR",
|
|
@@ -219,20 +238,21 @@ defaults: List[Setting] = [
|
|
|
219
238
|
"include",
|
|
220
239
|
"{INCLUDEDIR}/{INCLUDE_PREFIX}",
|
|
221
240
|
force_fix=True,
|
|
241
|
+
project="cxx",
|
|
222
242
|
),
|
|
223
243
|
]
|
|
224
244
|
|
|
225
245
|
hidden: List[Setting] = [
|
|
226
|
-
Setting("EXT.cxx", fix="{EXT}"),
|
|
227
|
-
Setting("EXT.hxx", fix="{EXT.cxx$header}"),
|
|
246
|
+
Setting("EXT.cxx", fix="{EXT}", project="cxx"),
|
|
247
|
+
Setting("EXT.hxx", fix="{EXT.cxx$header}", project="cxx"),
|
|
228
248
|
]
|
|
229
249
|
|
|
230
250
|
_fileext = {".cc": ".hh", ".cxx": ".hxx", ".cpp": ".hpp"}
|
|
231
251
|
|
|
232
252
|
|
|
233
253
|
_filters: Dict[str, Callable[[StrOrBool], StrOrBool]] = {
|
|
234
|
-
"safe": lambda value: value.replace("-", "_"),
|
|
235
|
-
"upper": lambda value: value.upper(),
|
|
236
|
-
"lower": lambda value: value.lower(),
|
|
237
|
-
"header": lambda cxx_ext: _fileext.get(cxx_ext, ".hpp"),
|
|
254
|
+
"safe": lambda value: str(value).replace("-", "_"),
|
|
255
|
+
"upper": lambda value: str(value).upper(),
|
|
256
|
+
"lower": lambda value: str(value).lower(),
|
|
257
|
+
"header": lambda cxx_ext: _fileext.get(str(cxx_ext), ".hpp"),
|
|
238
258
|
}
|
proj_flow/api/step.py
CHANGED
|
@@ -12,6 +12,7 @@ from typing import List, cast
|
|
|
12
12
|
from proj_flow.api.env import Config, Runtime
|
|
13
13
|
from proj_flow.base import inspect as _inspect
|
|
14
14
|
from proj_flow.base import matrix
|
|
15
|
+
from proj_flow.base.name_list import name_list
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class Step(ABC):
|
|
@@ -111,11 +112,8 @@ def _name_list(label: str, names: List[str], template="`{}`") -> str:
|
|
|
111
112
|
if len(names) == 0:
|
|
112
113
|
return ""
|
|
113
114
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if prefix:
|
|
117
|
-
prefix += " and "
|
|
118
|
-
return f"\n:{label}: {prefix}{em[-1]}"
|
|
115
|
+
joined = name_list([template.format(name) for name in names])
|
|
116
|
+
return f"\n:{label}: {joined}"
|
|
119
117
|
|
|
120
118
|
|
|
121
119
|
def _make_private(f: _inspect.Function):
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
+
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
The **proj_flow.base.name_list** provides name list helper for arguments with
|
|
6
|
+
choices
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import List
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def name_list(names: List[str]) -> str:
|
|
13
|
+
if len(names) == 0:
|
|
14
|
+
return ""
|
|
15
|
+
|
|
16
|
+
prefix = ", ".join(names[:-1])
|
|
17
|
+
if prefix:
|
|
18
|
+
prefix += " and "
|
|
19
|
+
return f"{prefix}{names[-1]}"
|
proj_flow/base/registry.py
CHANGED
|
@@ -7,6 +7,7 @@ to register the plugins with a decorator.
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import typing
|
|
10
|
+
from collections import OrderedDict
|
|
10
11
|
|
|
11
12
|
T = typing.TypeVar("T")
|
|
12
13
|
K = typing.TypeVar("K")
|
|
@@ -101,6 +102,19 @@ _debug_copies: typing.List[Registry] = []
|
|
|
101
102
|
def verbose_info():
|
|
102
103
|
for registry in _debug_copies:
|
|
103
104
|
for item in registry.container:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
)
|
|
105
|
+
full_name = f"{item.__module__}.{item.__class__.__name__}"
|
|
106
|
+
|
|
107
|
+
kw = OrderedDict()
|
|
108
|
+
|
|
109
|
+
if hasattr(item, "name"):
|
|
110
|
+
kw["name"] = getattr(item, "name")
|
|
111
|
+
elif hasattr(item, "__name__"):
|
|
112
|
+
kw["name"] = getattr(item, "__name__")
|
|
113
|
+
|
|
114
|
+
if hasattr(item, "id"):
|
|
115
|
+
kw["id"] = getattr(item, "id")
|
|
116
|
+
|
|
117
|
+
items = ", ".join([f"{key}={value}" for key, value in kw.items()])
|
|
118
|
+
if len(items) > 0:
|
|
119
|
+
items = f" ({items})"
|
|
120
|
+
print(f"-- {registry.name}: adding `{full_name}`{items}")
|
proj_flow/cli/__init__.py
CHANGED
|
@@ -29,7 +29,7 @@ def main():
|
|
|
29
29
|
def _change_dir():
|
|
30
30
|
root = argparse.ArgumentParser(
|
|
31
31
|
prog="proj-flow",
|
|
32
|
-
usage="proj-flow [-h] [--version] [-C [dir]]
|
|
32
|
+
usage="proj-flow [-h] [--version] [-C [dir]] command ...",
|
|
33
33
|
add_help=False,
|
|
34
34
|
)
|
|
35
35
|
root.add_argument("-C", dest="cd", nargs="?")
|
proj_flow/cli/argument.py
CHANGED
|
@@ -192,7 +192,7 @@ class Command:
|
|
|
192
192
|
if len(self.children):
|
|
193
193
|
subparsers = parser.add_subparsers(
|
|
194
194
|
dest=f"command_{level}",
|
|
195
|
-
metavar="
|
|
195
|
+
metavar="command",
|
|
196
196
|
help="Known command name, see below",
|
|
197
197
|
)
|
|
198
198
|
subparsers.parent = parser # type: ignore
|
|
@@ -254,7 +254,7 @@ def _argparse_visit_all(
|
|
|
254
254
|
parser.shortcuts = shortcut_configs
|
|
255
255
|
|
|
256
256
|
subparsers = parser.add_subparsers(
|
|
257
|
-
dest="command", metavar="
|
|
257
|
+
dest="command", metavar="command", help="Known command name, see below"
|
|
258
258
|
)
|
|
259
259
|
|
|
260
260
|
subparsers.parent = parser # type: ignore
|
|
@@ -11,7 +11,8 @@ import uuid
|
|
|
11
11
|
|
|
12
12
|
import chevron
|
|
13
13
|
|
|
14
|
-
from proj_flow import api,
|
|
14
|
+
from proj_flow import api, project
|
|
15
|
+
from proj_flow.project import cplusplus
|
|
15
16
|
|
|
16
17
|
from .__version__ import CMAKE_VERSION
|
|
17
18
|
|
|
@@ -49,22 +50,23 @@ class CMakeInit(api.init.InitStep):
|
|
|
49
50
|
def _list_cmake_types():
|
|
50
51
|
return api.ctx.move_to_front(
|
|
51
52
|
"console-application",
|
|
52
|
-
sorted(key for key in
|
|
53
|
+
sorted(key for key in project.data.get_internal("cmake").keys() if key),
|
|
53
54
|
)
|
|
54
55
|
|
|
55
56
|
|
|
56
57
|
api.init.register_init_step(CMakeInit())
|
|
57
|
-
|
|
58
|
+
|
|
59
|
+
cplusplus.project.register_init_setting(
|
|
58
60
|
api.ctx.Setting("PROJECT.TYPE", "CMake project type", _list_cmake_types)
|
|
59
61
|
)
|
|
60
|
-
|
|
62
|
+
cplusplus.project.register_init_setting(
|
|
61
63
|
api.ctx.Setting("cmake", fix="{PROJECT.TYPE$map:cmake}"),
|
|
62
64
|
api.ctx.Setting("CMAKE_VERSION", value=CMAKE_VERSION),
|
|
63
65
|
api.ctx.Setting("PROJECT.WIX.UPGRADE_GUID", value=lambda: str(uuid.uuid4())),
|
|
64
66
|
is_hidden=True,
|
|
65
67
|
)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
cplusplus.project.register_switch("with_cmake", "Use CMake", True)
|
|
69
|
+
cplusplus.project.register_internal(
|
|
68
70
|
"cmake",
|
|
69
71
|
{
|
|
70
72
|
"": {"cmd": "add_executable", "type": ""},
|
|
@@ -9,7 +9,8 @@ import os
|
|
|
9
9
|
import textwrap
|
|
10
10
|
from typing import List
|
|
11
11
|
|
|
12
|
-
from proj_flow.api import
|
|
12
|
+
from proj_flow.api import env, step
|
|
13
|
+
from proj_flow.project import cplusplus
|
|
13
14
|
|
|
14
15
|
from ._conan import conan_api
|
|
15
16
|
|
|
@@ -64,4 +65,6 @@ class ConanConfig:
|
|
|
64
65
|
return 0
|
|
65
66
|
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
cplusplus.project.register_switch(
|
|
69
|
+
"with_conan", "Use Conan for dependency manager", True
|
|
70
|
+
)
|
proj_flow/ext/github/cli.py
CHANGED
|
@@ -16,22 +16,13 @@ import typing
|
|
|
16
16
|
|
|
17
17
|
from proj_flow import log
|
|
18
18
|
from proj_flow.api import arg, env
|
|
19
|
+
from proj_flow.base.name_list import name_list
|
|
19
20
|
from proj_flow.flow.configs import Configs
|
|
20
21
|
from proj_flow.log import commit, hosting, rich_text
|
|
21
22
|
|
|
22
23
|
FORCED_LEVEL_CHOICES = list(commit.FORCED_LEVEL.keys())
|
|
23
24
|
|
|
24
25
|
|
|
25
|
-
def _name_list(names: typing.List[str]) -> str:
|
|
26
|
-
if len(names) == 0:
|
|
27
|
-
return ""
|
|
28
|
-
|
|
29
|
-
prefix = ", ".join(names[:-1])
|
|
30
|
-
if prefix:
|
|
31
|
-
prefix += " and "
|
|
32
|
-
return f"{prefix}{names[-1]}"
|
|
33
|
-
|
|
34
|
-
|
|
35
26
|
@arg.command("github")
|
|
36
27
|
def github():
|
|
37
28
|
"""Interact with GitHub workflows and releases"""
|
|
@@ -81,7 +72,7 @@ def release(
|
|
|
81
72
|
typing.Optional[str],
|
|
82
73
|
arg.Argument(
|
|
83
74
|
help="Ignore the version change from changelog and instead use this value. "
|
|
84
|
-
f"Allowed values are: {
|
|
75
|
+
f"Allowed values are: {name_list(FORCED_LEVEL_CHOICES)}",
|
|
85
76
|
meta="level",
|
|
86
77
|
choices=FORCED_LEVEL_CHOICES,
|
|
87
78
|
),
|
proj_flow/ext/github/switches.py
CHANGED
|
@@ -7,7 +7,7 @@ projects.
|
|
|
7
7
|
|
|
8
8
|
from proj_flow.api import ctx
|
|
9
9
|
|
|
10
|
-
ctx.
|
|
11
|
-
ctx.
|
|
10
|
+
ctx.register_common_switch("with_github_actions", "Use Github Actions", True)
|
|
11
|
+
ctx.register_common_switch(
|
|
12
12
|
"with_github_social", "Use Github ISSUE_TEMPLATE, CONTRIBUTING.md, etc.", True
|
|
13
13
|
)
|
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/minimal/base.py
CHANGED
proj_flow/minimal/init.py
CHANGED
|
@@ -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)
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
3
|
|
|
4
4
|
"""
|
|
5
|
-
The **proj_flow.
|
|
6
|
-
prompts.
|
|
5
|
+
The **proj_flow.project.interact** provides initialization context through
|
|
6
|
+
user prompts.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from dataclasses import dataclass
|
|
10
|
-
from typing import List, Union
|
|
10
|
+
from typing import Callable, List, Optional, Union
|
|
11
11
|
|
|
12
12
|
from prompt_toolkit import prompt as tk_prompt
|
|
13
13
|
from prompt_toolkit.completion import WordCompleter
|
|
14
|
+
from prompt_toolkit.formatted_text.base import AnyFormattedText
|
|
14
15
|
from prompt_toolkit.shortcuts import CompleteStyle
|
|
15
16
|
from prompt_toolkit.validation import Validator
|
|
16
17
|
|
|
@@ -39,7 +40,7 @@ class _Question:
|
|
|
39
40
|
def ps(self):
|
|
40
41
|
return self.prompt or f'"{self.key}"'
|
|
41
42
|
|
|
42
|
-
def _ps(self, default: ctx.Values, counter: int, size: int):
|
|
43
|
+
def _ps(self, default: ctx.Values, counter: int, size: int) -> AnyFormattedText:
|
|
43
44
|
if default:
|
|
44
45
|
if isinstance(default, str):
|
|
45
46
|
return [
|
|
@@ -89,7 +90,7 @@ class _Question:
|
|
|
89
90
|
|
|
90
91
|
def _tk_prompt(
|
|
91
92
|
self,
|
|
92
|
-
defaults: Union[bool
|
|
93
|
+
defaults: Union[bool, List[str]],
|
|
93
94
|
words: List[str],
|
|
94
95
|
counter: int,
|
|
95
96
|
size: int,
|
|
@@ -108,27 +109,127 @@ class _Question:
|
|
|
108
109
|
)
|
|
109
110
|
|
|
110
111
|
|
|
111
|
-
def
|
|
112
|
-
|
|
113
|
-
Prompts user to provide details of newly-crated project.
|
|
112
|
+
def _project_filter(project: Optional[str]):
|
|
113
|
+
if project is None:
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
def impl(setting: ctx.Setting):
|
|
116
|
+
return setting.project is None
|
|
117
|
+
|
|
118
|
+
return impl
|
|
119
|
+
|
|
120
|
+
def impl(setting: ctx.Setting):
|
|
121
|
+
return setting.project is None or setting.project == project
|
|
122
|
+
|
|
123
|
+
return impl
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _prompt(wanted: Callable[[ctx.Setting], bool]) -> ctx.SettingsType:
|
|
117
127
|
settings: ctx.SettingsType = {}
|
|
118
128
|
|
|
119
|
-
|
|
129
|
+
defaults = [setting for setting in ctx.defaults if wanted(setting)]
|
|
130
|
+
switches = [setting for setting in ctx.switches if wanted(setting)]
|
|
131
|
+
|
|
132
|
+
size = len(defaults) + len(switches)
|
|
120
133
|
counter = 1
|
|
121
134
|
|
|
122
|
-
for setting in
|
|
135
|
+
for setting in defaults:
|
|
123
136
|
loaded = _Question.load_default(setting, settings)
|
|
124
137
|
value = loaded.interact(counter, size)
|
|
125
138
|
settings[loaded.key] = value
|
|
126
139
|
counter += 1
|
|
127
140
|
|
|
128
|
-
for setting in
|
|
141
|
+
for setting in switches:
|
|
129
142
|
loaded = _Question.load_default(setting, settings)
|
|
130
143
|
value = loaded.interact(counter, size)
|
|
131
144
|
settings[loaded.key] = value
|
|
132
145
|
counter += 1
|
|
133
146
|
|
|
134
147
|
return settings
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _all_default(wanted: Callable[[ctx.Setting], bool]):
|
|
151
|
+
"""
|
|
152
|
+
Chooses default answers for all details of newly-crated project.
|
|
153
|
+
|
|
154
|
+
:returns: Dictionary with default values of all interactive settings
|
|
155
|
+
and switches.
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
settings: ctx.SettingsType = {}
|
|
159
|
+
|
|
160
|
+
defaults = [setting for setting in ctx.defaults if wanted(setting)]
|
|
161
|
+
switches = [setting for setting in ctx.switches if wanted(setting)]
|
|
162
|
+
|
|
163
|
+
for setting in defaults:
|
|
164
|
+
value = _get_default(setting, settings)
|
|
165
|
+
settings[setting.json_key] = value
|
|
166
|
+
|
|
167
|
+
for setting in switches:
|
|
168
|
+
value = _get_default(setting, settings)
|
|
169
|
+
settings[setting.json_key] = value
|
|
170
|
+
|
|
171
|
+
return settings
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _fixup(settings: ctx.SettingsType, key: str, fixup: str, force=False):
|
|
175
|
+
value = settings.get(key, "")
|
|
176
|
+
if value != "" and not force:
|
|
177
|
+
return
|
|
178
|
+
|
|
179
|
+
value = ctx._build_fixup(settings, fixup)
|
|
180
|
+
settings[key] = value
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _get_default(setting: ctx.Setting, settings: ctx.SettingsType):
|
|
184
|
+
value = setting.calc_value(settings)
|
|
185
|
+
if isinstance(value, list):
|
|
186
|
+
return value[0]
|
|
187
|
+
return value
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _fixup_context(settings: ctx.SettingsType, wanted: Callable[[ctx.Setting], bool]):
|
|
191
|
+
defaults = [setting for setting in ctx.defaults if wanted(setting)]
|
|
192
|
+
hidden = [setting for setting in ctx.hidden if wanted(setting)]
|
|
193
|
+
|
|
194
|
+
for setting in hidden:
|
|
195
|
+
value = _get_default(setting, settings)
|
|
196
|
+
if isinstance(value, bool) or value != "":
|
|
197
|
+
settings[setting.json_key] = value
|
|
198
|
+
|
|
199
|
+
for coll in [defaults, hidden]:
|
|
200
|
+
for setting in coll:
|
|
201
|
+
_fixup(settings, setting.json_key, setting.fix or "", setting.force_fix)
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
del settings["EXT"]
|
|
205
|
+
except KeyError:
|
|
206
|
+
pass
|
|
207
|
+
|
|
208
|
+
result = {}
|
|
209
|
+
for key in settings:
|
|
210
|
+
path = key.split(".")
|
|
211
|
+
path_ctx = result
|
|
212
|
+
for step in path[:-1]:
|
|
213
|
+
if step not in path_ctx or not isinstance(path_ctx[step], dict):
|
|
214
|
+
path_ctx[step] = {}
|
|
215
|
+
path_ctx = path_ctx[step]
|
|
216
|
+
path_ctx[path[-1]] = settings[key]
|
|
217
|
+
return result
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def get_context(interactive: bool, project: Optional[str]):
|
|
221
|
+
"""
|
|
222
|
+
Prompts user to provide details of newly-crated project. If `interactive`
|
|
223
|
+
is true, however, this functions skips the prompts and chooses all the
|
|
224
|
+
default answers.
|
|
225
|
+
|
|
226
|
+
:param interactive: Selects, if the initialization process is done through
|
|
227
|
+
prompts, or not
|
|
228
|
+
|
|
229
|
+
:returns: Dictionary with answers to all interactive settings and switches.
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
wanted = _project_filter(project)
|
|
233
|
+
return _fixup_context(
|
|
234
|
+
_all_default(wanted) if not interactive else _prompt(wanted), wanted
|
|
235
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: proj-flow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.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/
|
|
@@ -76,7 +76,7 @@ From PowerShell with:
|
|
|
76
76
|
A fresh C++ project can be created with a
|
|
77
77
|
|
|
78
78
|
```sh
|
|
79
|
-
proj-flow init
|
|
79
|
+
proj-flow init cxx
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
This command will ask multiple questions to build Mustache context for the
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
proj_flow/__init__.py,sha256=
|
|
1
|
+
proj_flow/__init__.py,sha256=cd3hxTcDnlv9Qd6qQYRRa3g7bs5iuMrPJtfF_ENzMTY,277
|
|
2
2
|
proj_flow/__main__.py,sha256=HUar_qQ9Ndmchmryegtzu__5wukwCLrFN_SGRl5Ol_M,233
|
|
3
|
+
proj_flow/dependency.py,sha256=CpcnR6El8AO9hlLc9lQtYQADYlkx3GMHlkLYbEAtdMI,4639
|
|
3
4
|
proj_flow/api/__init__.py,sha256=gV2f6kll_5JXtvkGASvnx7CbOWr34PHOdck-4ce-qEk,378
|
|
4
|
-
proj_flow/api/arg.py,sha256=
|
|
5
|
+
proj_flow/api/arg.py,sha256=id08mLFVDWIvsrhEaPuJfng27f92Vf8pIA5VajyjGVo,4802
|
|
5
6
|
proj_flow/api/completers.py,sha256=NapNVu6QAQ_iF6dqcAzOV5kDHKD9MAMVX209Bklq-Mw,2464
|
|
6
|
-
proj_flow/api/ctx.py,sha256=
|
|
7
|
+
proj_flow/api/ctx.py,sha256=IJu0q0Chivo6b2M4MKkAlV09oi7Cn9VxtDFeAeL_tnc,6646
|
|
7
8
|
proj_flow/api/env.py,sha256=4VvSkfA2k6OPrtvkPtEPhb24dDyaqbUoqSznIgvAXNg,11082
|
|
8
9
|
proj_flow/api/init.py,sha256=an0czDiPCDqW4Bp0I8sGQgaAlDAozLO0ZYnP149lWqk,521
|
|
9
10
|
proj_flow/api/makefile.py,sha256=AxtGOvmypBtSvoyMEDJq1bGoaVD5yW9YYRZSdunUEeg,3856
|
|
10
11
|
proj_flow/api/release.py,sha256=A-t4qcjeaptEgfBCZs2Q9cOjsGACrNM0CzmCorms0U4,2401
|
|
11
|
-
proj_flow/api/step.py,sha256=
|
|
12
|
+
proj_flow/api/step.py,sha256=AOqe1wXYnU_O3pD5KlzfyyOm_D9fcF_4vyhhr1w-NrI,4561
|
|
12
13
|
proj_flow/base/__init__.py,sha256=RRmqiYjdVlC4i8QijXHNiRh9yzNH8305WXezrSaPjKk,311
|
|
13
14
|
proj_flow/base/cmd.py,sha256=Vo3e8kd4CHRzbsUkO-MnbhQxjLXTczv7YQRUkFlcBQE,1560
|
|
14
15
|
proj_flow/base/inspect.py,sha256=lt5P19rvSZ-wMCTrCYAaQFCt2S9fUjEQXlrKK-Tmvwc,2786
|
|
15
16
|
proj_flow/base/matrix.py,sha256=8XBFGYOwW6Myt_4h3WNk36V2bJ5xeqUv6DvzF4B3q_g,7767
|
|
17
|
+
proj_flow/base/name_list.py,sha256=KiHSnbDgYplJc25O3EehYhFAhD7Z3mHVAK6UYOdg5PQ,416
|
|
16
18
|
proj_flow/base/plugins.py,sha256=evn2Dym_NeoBaIZAu2YUtRd--15PCFpHD0h5zSsWkQE,978
|
|
17
|
-
proj_flow/base/registry.py,sha256=
|
|
19
|
+
proj_flow/base/registry.py,sha256=C04Imxux_BO7DffZZth28iFLPnM4Yw9K7IGt06VokE0,3528
|
|
18
20
|
proj_flow/base/uname.py,sha256=7Awb3Es0jTAKMpyRawdrC16xc5X9M97BlPqEfQibqIk,2295
|
|
19
|
-
proj_flow/cli/__init__.py,sha256=
|
|
20
|
-
proj_flow/cli/argument.py,sha256=
|
|
21
|
+
proj_flow/cli/__init__.py,sha256=cMsZpECkXeSzY4Hv_ela3Ou-FhwE5w1A3ypMSnZZikM,1196
|
|
22
|
+
proj_flow/cli/argument.py,sha256=OCx_Z0NVm4bmHI30WFdtPdqVMdDnvkqqluhAgP7Ya0w,13686
|
|
21
23
|
proj_flow/cli/finder.py,sha256=5x7H1nH0k63DetDauhB_wABel_f0RQpsZ5YnhPfbkRc,1402
|
|
22
24
|
proj_flow/ext/__init__.py,sha256=XD52rUFTPz3GnyRq6KZUNeWdMce7e0bB19iTx-zU6DE,169
|
|
23
25
|
proj_flow/ext/markdown_changelog.py,sha256=fRGL09jojnv2B-8vAX2prvgNp8e7uyq5NxboSZjFCJ8,436
|
|
@@ -25,17 +27,17 @@ proj_flow/ext/re_structured_changelog.py,sha256=UF23W9eu_YgPO42MiaoDbEKu8In_48mQ
|
|
|
25
27
|
proj_flow/ext/store.py,sha256=yfyIb2G7UhoIkPmVDnp1RPx2fwFZK8FyLZzrMvPlEUM,3681
|
|
26
28
|
proj_flow/ext/cplusplus/__init__.py,sha256=dAmLMyGVQq586jJM_jiAuo5Ecw9U8agpvSRbzzPgh3g,245
|
|
27
29
|
proj_flow/ext/cplusplus/cmake/__init__.py,sha256=f-_gTY_XpIfcKrAj0jhT57DBGeifkW2s7NlSxjpHTMg,366
|
|
28
|
-
proj_flow/ext/cplusplus/cmake/__version__.py,sha256=
|
|
29
|
-
proj_flow/ext/cplusplus/cmake/context.py,sha256=
|
|
30
|
+
proj_flow/ext/cplusplus/cmake/__version__.py,sha256=imja0GnhpBvS8Crz-64eOUKhc4i6FeRrjBGRB68x_p0,239
|
|
31
|
+
proj_flow/ext/cplusplus/cmake/context.py,sha256=BJDMRuIvCEXR577yWuYSw-wzQ9PQudpXjnIxo1gKHBU,3172
|
|
30
32
|
proj_flow/ext/cplusplus/cmake/parser.py,sha256=ZqQRZqS_VU5VtC8uwax-dknh7sfuLEvtazG8ChSqHDQ,3814
|
|
31
33
|
proj_flow/ext/cplusplus/cmake/steps.py,sha256=Q7HcVlMbKOwrRj-Sms0W7FS027M_shM7s2FJx6rX4KQ,4100
|
|
32
34
|
proj_flow/ext/cplusplus/cmake/version.py,sha256=E0PAUdO9Wg02pxtU4LWYTNoTB-9Oer3Y9zr1lR2zvgw,962
|
|
33
|
-
proj_flow/ext/cplusplus/conan/__init__.py,sha256=
|
|
34
|
-
proj_flow/ext/cplusplus/conan/_conan.py,sha256=
|
|
35
|
+
proj_flow/ext/cplusplus/conan/__init__.py,sha256=1WmGMY1hhvJdHsXfHg5MjA8g6qL3H2FABsK0TLBigCI,2022
|
|
36
|
+
proj_flow/ext/cplusplus/conan/_conan.py,sha256=9xnji-f8uN7huXLqavVBUDC33CgnjBIyZX6wVcGm2RA,3352
|
|
35
37
|
proj_flow/ext/github/__init__.py,sha256=Mgx19YS6SYBXYB66_pOgIgwuB2WKRxqp5UGutq0B9Xk,282
|
|
36
|
-
proj_flow/ext/github/cli.py,sha256=
|
|
38
|
+
proj_flow/ext/github/cli.py,sha256=zQS2TB7fDeY0VwR1bOw065Trz2NPe07JKcFQaJbwKGg,3934
|
|
37
39
|
proj_flow/ext/github/hosting.py,sha256=3iW8QjeJk7MyqKNbv92nB-5a_Yn_B5_eEIlw_cdgUT0,519
|
|
38
|
-
proj_flow/ext/github/switches.py,sha256=
|
|
40
|
+
proj_flow/ext/github/switches.py,sha256=g7O2hvrg4mHm3WSHYsRBhEDU0bIkEJgp4Qclhqxk0uI,421
|
|
39
41
|
proj_flow/ext/python/__init__.py,sha256=GbEKEJJZ3PJ4sRHEykAWjGIR6yyyrYdlUFulldvsAGI,252
|
|
40
42
|
proj_flow/ext/python/rtdocs.py,sha256=idm6DTUnbA18L-EpxQiFVXCz9x8AIRSb52ZPqIXzrf8,6354
|
|
41
43
|
proj_flow/ext/python/steps.py,sha256=pDHGAe_CDzzdRFAzM1AIBvkbc14KB3SNUunusKZAaaY,1815
|
|
@@ -43,11 +45,8 @@ proj_flow/ext/python/version.py,sha256=pnyuKATyZwBh1p0gf9KmqbRSZx8hJ5285CiFK_tHE
|
|
|
43
45
|
proj_flow/ext/sign/__init__.py,sha256=yvXpqLdvBwkB0GDBl4yWw--iZ2tFxhx-97EP9OAzx2g,4345
|
|
44
46
|
proj_flow/ext/sign/api.py,sha256=dlnXYYoBDYXx_WWGBQ8ThKmEMYmw2kt6NNZA8j-MXuM,2288
|
|
45
47
|
proj_flow/ext/sign/win32.py,sha256=fV8_Z42KaeDBEf3_5qCzlALb0dy1zN0Pqy8Hr-ZMAQ4,4874
|
|
46
|
-
proj_flow/flow/__init__.py,sha256=
|
|
48
|
+
proj_flow/flow/__init__.py,sha256=5Zo97zJsR7HMbl64jeMB9PbUuxCxpOlNuLmo3apWSVU,277
|
|
47
49
|
proj_flow/flow/configs.py,sha256=l-pIotrXFm4oMqqpuvKP-RdtlTmDDnK_izhTJfsWbhk,5260
|
|
48
|
-
proj_flow/flow/dependency.py,sha256=5o_-5Soc2e1tOu5mwvkXa6jqDFplZi_chN8edkR6vVY,4644
|
|
49
|
-
proj_flow/flow/init.py,sha256=9k3cgVmmeOKtH6mJ0nc4IOmI48oXvtYXFYWx2rj60-M,1777
|
|
50
|
-
proj_flow/flow/interact.py,sha256=AJknpCxk3C39GhsR6BjH5QDk33KouWCZbHEUFLjvfGc,4166
|
|
51
50
|
proj_flow/flow/layer.py,sha256=6mvbhiOy9KcMP69Q9zew_7jGhf5Wqr7v-veS3YPGnmc,5720
|
|
52
51
|
proj_flow/flow/steps.py,sha256=PN_C_B6vNvqOsjpDpa5ESvH30Sc6RM1fSSqWqXgqg-4,2804
|
|
53
52
|
proj_flow/log/__init__.py,sha256=02EIgasE-K7mmbbNiIdX0IebWQMp2Co_D6H4ZBhJgcs,365
|
|
@@ -64,12 +63,17 @@ proj_flow/log/rich_text/api.py,sha256=PCSAGwkmDUMoVlpN7BDsgIA1AiMZEC0H6TUZXpr_Mg
|
|
|
64
63
|
proj_flow/log/rich_text/markdown.py,sha256=jBnNxxhBHzyIZ3Y4HXDfqpl7zlRbbKbKdwdnZwkmNAI,1623
|
|
65
64
|
proj_flow/log/rich_text/re_structured_text.py,sha256=DEl9KjBUF6cxfNWpQ7GVnHi7wKeuFnPGJwxQxjbCsnM,1823
|
|
66
65
|
proj_flow/minimal/__init__.py,sha256=NglaSdKiMebrOqfsqF9ctqi0ZwiiBHOQcUnp3DS8lP0,340
|
|
67
|
-
proj_flow/minimal/base.py,sha256
|
|
66
|
+
proj_flow/minimal/base.py,sha256=yJR3FAigR_x8krTQ1UeifBb4AnLUZAk6LfVVqB_RFO4,758
|
|
68
67
|
proj_flow/minimal/bootstrap.py,sha256=PcZfBsUmj8uDPGBC55iUgD5O7W4VSkpCQb6r9GEyAaQ,556
|
|
69
|
-
proj_flow/minimal/init.py,sha256=
|
|
68
|
+
proj_flow/minimal/init.py,sha256=YFAsD_wGypGxweEFrbAbCdGptV1jQ2OdxUseUPi-3C8,2945
|
|
70
69
|
proj_flow/minimal/list.py,sha256=RlOqammE8olNKXsnbv1enF5uriu0MZ2wFbht37Z2ETw,4810
|
|
71
|
-
proj_flow/minimal/run.py,sha256=
|
|
70
|
+
proj_flow/minimal/run.py,sha256=4qvGLqz2ayCZDvVBrq4tG094fjfcmDPon-xcGPQkM_U,4665
|
|
72
71
|
proj_flow/minimal/system.py,sha256=9FliH5TD103JYSAe2O5EU7hkOHDgVzTqu0Exxk-WrXE,1579
|
|
72
|
+
proj_flow/project/__init__.py,sha256=AROrwhbuMR5rJE-HC769eL4IXrMLQYpQb3HgpkOAYqg,293
|
|
73
|
+
proj_flow/project/api.py,sha256=xQ3eFcxgLfi6ZAGs2q_1V0uHTpM7v9gsb7Ie2o2z-v8,1358
|
|
74
|
+
proj_flow/project/cplusplus.py,sha256=GXHXI4cdrSm0jWTr2g9dCBgeFS1G4g2fC9WCv6ILn0c,398
|
|
75
|
+
proj_flow/project/data.py,sha256=TluhBDoJEYL4dnyTpInmhQ49Uvf8mkWmpU-YMLQPNhE,317
|
|
76
|
+
proj_flow/project/interact.py,sha256=DgclUNeY6K146QQe510tdHcYnZmWmQZ0xH9w4HifLTU,7235
|
|
73
77
|
proj_flow/template/layers/base.json,sha256=jrlby8FUUwkx4V_EGMix_pkQlWcUCVUgmeoapZaZnt4,3
|
|
74
78
|
proj_flow/template/layers/cmake.json,sha256=KJe9uqTDoGm0ppdNOtniKEv30iNV2K4Yk8hZQetEZ7Y,385
|
|
75
79
|
proj_flow/template/layers/conan.json,sha256=mAhDrxCtDjI_7Rbtr2hlNW5_jZkLdWLiwgfuhRsRuuw,29
|
|
@@ -124,8 +128,8 @@ proj_flow/template/licenses/MIT.mustache,sha256=NncPoQaNsuy-WmRmboik3fyhJJ8m5pc2
|
|
|
124
128
|
proj_flow/template/licenses/Unlicense.mustache,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
|
|
125
129
|
proj_flow/template/licenses/WTFPL.mustache,sha256=lvF4V_PrKKfZPa2TC8CZo8tlqaKvs3Bpv9G6XsWWQ4k,483
|
|
126
130
|
proj_flow/template/licenses/Zlib.mustache,sha256=uIj-mhSjes2HJ3rRapyy2ALflKRz4xQgS4mVM9827C0,868
|
|
127
|
-
proj_flow-0.
|
|
128
|
-
proj_flow-0.
|
|
129
|
-
proj_flow-0.
|
|
130
|
-
proj_flow-0.
|
|
131
|
-
proj_flow-0.
|
|
131
|
+
proj_flow-0.10.0.dist-info/METADATA,sha256=bQUtOSHQevlBQB43X1xui_BfX4KBey_TwIYx_tUNx1Q,2868
|
|
132
|
+
proj_flow-0.10.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
133
|
+
proj_flow-0.10.0.dist-info/entry_points.txt,sha256=d_OmGKZzpY7FCWz0sZ4wnBAPZC75oMEzTgJZWtpDELo,49
|
|
134
|
+
proj_flow-0.10.0.dist-info/licenses/LICENSE,sha256=vpOQJ5QlrTedF3coEWvA4wJzVJH304f66ZitR7Od4iU,1068
|
|
135
|
+
proj_flow-0.10.0.dist-info/RECORD,,
|
proj_flow/flow/init.py
DELETED
|
@@ -1,65 +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.flow.init** supports the ``init`` command.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from proj_flow.api import ctx
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def _fixup(settings: ctx.SettingsType, key: str, fixup: str, force=False):
|
|
12
|
-
value = settings.get(key, "")
|
|
13
|
-
if value != "" and not force:
|
|
14
|
-
return
|
|
15
|
-
|
|
16
|
-
value = ctx._build_fixup(settings, fixup)
|
|
17
|
-
settings[key] = value
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _get_default(setting: ctx.Setting, settings: ctx.SettingsType):
|
|
21
|
-
value = setting.calc_value(settings)
|
|
22
|
-
if isinstance(value, list):
|
|
23
|
-
return value[0]
|
|
24
|
-
return value
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def all_default():
|
|
28
|
-
settings: ctx.SettingsType = {}
|
|
29
|
-
|
|
30
|
-
for setting in ctx.defaults:
|
|
31
|
-
value = _get_default(setting, settings)
|
|
32
|
-
settings[setting.json_key] = value
|
|
33
|
-
|
|
34
|
-
for setting in ctx.switches:
|
|
35
|
-
value = _get_default(setting, settings)
|
|
36
|
-
settings[setting.json_key] = value
|
|
37
|
-
|
|
38
|
-
return settings
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def fixup(settings: ctx.SettingsType):
|
|
42
|
-
for setting in ctx.hidden:
|
|
43
|
-
value = _get_default(setting, settings)
|
|
44
|
-
if isinstance(value, bool) or value != "":
|
|
45
|
-
settings[setting.json_key] = value
|
|
46
|
-
|
|
47
|
-
for coll in [ctx.defaults, ctx.hidden]:
|
|
48
|
-
for setting in coll:
|
|
49
|
-
_fixup(settings, setting.json_key, setting.fix or "", setting.force_fix)
|
|
50
|
-
del settings["EXT"]
|
|
51
|
-
|
|
52
|
-
result = {}
|
|
53
|
-
for key in settings:
|
|
54
|
-
path = key.split(".")
|
|
55
|
-
path_ctx = result
|
|
56
|
-
for step in path[:-1]:
|
|
57
|
-
if step not in path_ctx or not isinstance(path_ctx[step], dict):
|
|
58
|
-
path_ctx[step] = {}
|
|
59
|
-
path_ctx = path_ctx[step]
|
|
60
|
-
path_ctx[path[-1]] = settings[key]
|
|
61
|
-
return result
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def get_internal(key: str, value: any = None):
|
|
65
|
-
return ctx.internals.get(key, value)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|