proj-flow 0.9.4__py3-none-any.whl → 0.11.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 +65 -2
- proj_flow/api/step.py +3 -5
- proj_flow/{ext/cplusplus/cmake/__version__.py → base/__cmake_version__.py} +5 -0
- proj_flow/base/name_list.py +19 -0
- proj_flow/base/registry.py +23 -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/__init__.py +2 -2
- proj_flow/ext/cplusplus/cmake/steps.py +1 -1
- proj_flow/ext/cplusplus/conan/__init__.py +2 -4
- 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/__init__.py +10 -0
- proj_flow/{ext/cplusplus/cmake/context.py → project/cplusplus/cmake_context.py} +10 -7
- proj_flow/project/cplusplus/conan_context.py +12 -0
- proj_flow/project/cplusplus/project.py +16 -0
- proj_flow/project/data.py +14 -0
- proj_flow/project/interact.py +255 -0
- {proj_flow-0.9.4.dist-info → proj_flow-0.11.0.dist-info}/METADATA +2 -2
- {proj_flow-0.9.4.dist-info → proj_flow-0.11.0.dist-info}/RECORD +34 -28
- proj_flow/flow/init.py +0 -65
- proj_flow/flow/interact.py +0 -134
- {proj_flow-0.9.4.dist-info → proj_flow-0.11.0.dist-info}/WHEEL +0 -0
- {proj_flow-0.9.4.dist-info → proj_flow-0.11.0.dist-info}/entry_points.txt +0 -0
- {proj_flow-0.9.4.dist-info → proj_flow-0.11.0.dist-info}/licenses/LICENSE +0 -0
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, rt)
|
|
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, env
|
|
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, rt: env.Runtime):
|
|
34
|
+
return interact.get_context(interactive, self.id, rt)
|
|
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,10 @@
|
|
|
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.cplusplus import cmake_context, conan_context
|
|
9
|
+
|
|
10
|
+
__all__ = ["cmake_context", "conan_context"]
|
|
@@ -11,9 +11,11 @@ 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 data
|
|
16
|
+
from proj_flow.project.cplusplus import project
|
|
15
17
|
|
|
16
|
-
from .
|
|
18
|
+
from proj_flow.base.__cmake_version__ import CMAKE_VERSION
|
|
17
19
|
|
|
18
20
|
config_json_mustache = """
|
|
19
21
|
{{#with_cmake}}
|
|
@@ -49,22 +51,23 @@ class CMakeInit(api.init.InitStep):
|
|
|
49
51
|
def _list_cmake_types():
|
|
50
52
|
return api.ctx.move_to_front(
|
|
51
53
|
"console-application",
|
|
52
|
-
sorted(key for key in
|
|
54
|
+
sorted(key for key in data.get_internal("cmake").keys() if key),
|
|
53
55
|
)
|
|
54
56
|
|
|
55
57
|
|
|
56
58
|
api.init.register_init_step(CMakeInit())
|
|
57
|
-
|
|
59
|
+
|
|
60
|
+
project.cxx.register_init_setting(
|
|
58
61
|
api.ctx.Setting("PROJECT.TYPE", "CMake project type", _list_cmake_types)
|
|
59
62
|
)
|
|
60
|
-
|
|
63
|
+
project.cxx.register_init_setting(
|
|
61
64
|
api.ctx.Setting("cmake", fix="{PROJECT.TYPE$map:cmake}"),
|
|
62
65
|
api.ctx.Setting("CMAKE_VERSION", value=CMAKE_VERSION),
|
|
63
66
|
api.ctx.Setting("PROJECT.WIX.UPGRADE_GUID", value=lambda: str(uuid.uuid4())),
|
|
64
67
|
is_hidden=True,
|
|
65
68
|
)
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
project.cxx.register_switch("with_cmake", "Use CMake", True)
|
|
70
|
+
project.cxx.register_internal(
|
|
68
71
|
"cmake",
|
|
69
72
|
{
|
|
70
73
|
"": {"cmd": "add_executable", "type": ""},
|
|
@@ -0,0 +1,12 @@
|
|
|
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.cplusplus.conan** provides the ``"Conan"`` step.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from proj_flow.project.cplusplus import project
|
|
9
|
+
|
|
10
|
+
project.cxx.register_switch(
|
|
11
|
+
"with_conan", "Use Conan for dependency manager", True
|
|
12
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
@api.project_type.add
|
|
11
|
+
class CPlusPlus(api.ProjectType):
|
|
12
|
+
def __init__(self):
|
|
13
|
+
super().__init__("C++ plus CMake plus Conan", "cxx")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
cxx = 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)
|
|
@@ -0,0 +1,255 @@
|
|
|
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.interact** provides initialization context through
|
|
6
|
+
user prompts.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import Callable, List, Optional, Union
|
|
11
|
+
|
|
12
|
+
from prompt_toolkit import prompt as tk_prompt
|
|
13
|
+
from prompt_toolkit.completion import WordCompleter
|
|
14
|
+
from prompt_toolkit.formatted_text.base import AnyFormattedText
|
|
15
|
+
from prompt_toolkit.shortcuts import CompleteStyle
|
|
16
|
+
from prompt_toolkit.validation import Validator
|
|
17
|
+
|
|
18
|
+
from proj_flow.api import ctx, env
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class _Question:
|
|
23
|
+
key: str
|
|
24
|
+
prompt: str
|
|
25
|
+
value: ctx.Values
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def load_default(
|
|
29
|
+
cls,
|
|
30
|
+
default: ctx.Setting,
|
|
31
|
+
previous: ctx.SettingsType,
|
|
32
|
+
override: Optional[ctx.StrOrBool],
|
|
33
|
+
):
|
|
34
|
+
value = default.calc_value(previous)
|
|
35
|
+
if override is not None:
|
|
36
|
+
if isinstance(value, (str, bool)) and type(value) == type(override):
|
|
37
|
+
value = override
|
|
38
|
+
elif isinstance(value, list) and isinstance(override, str):
|
|
39
|
+
value = ctx.move_to_front(override, value)
|
|
40
|
+
return cls(default.json_key, default.prompt, value)
|
|
41
|
+
|
|
42
|
+
def interact(self, counter: int, size: int) -> ctx.StrOrBool:
|
|
43
|
+
if isinstance(self.value, str):
|
|
44
|
+
return self._get_str(self.value, counter, size)
|
|
45
|
+
if isinstance(self.value, bool):
|
|
46
|
+
return self._get_flag(self.value, counter, size)
|
|
47
|
+
return self._get_list(self.value, counter, size)
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def ps(self):
|
|
51
|
+
return self.prompt or f'"{self.key}"'
|
|
52
|
+
|
|
53
|
+
def _ps(self, default: ctx.Values, counter: int, size: int) -> AnyFormattedText:
|
|
54
|
+
if default:
|
|
55
|
+
if isinstance(default, str):
|
|
56
|
+
return [
|
|
57
|
+
("", f"[{counter}/{size}] {self.ps} ["),
|
|
58
|
+
("bold", default),
|
|
59
|
+
("", f"]: "),
|
|
60
|
+
]
|
|
61
|
+
if isinstance(default, bool):
|
|
62
|
+
b = "bold"
|
|
63
|
+
n = ""
|
|
64
|
+
on_true = (b if default else n, "yes")
|
|
65
|
+
on_false = (b if not default else n, "no")
|
|
66
|
+
return [
|
|
67
|
+
("", f"[{counter}/{size}] {self.ps} ["),
|
|
68
|
+
on_true,
|
|
69
|
+
("", " / "),
|
|
70
|
+
on_false,
|
|
71
|
+
("", f"]: "),
|
|
72
|
+
]
|
|
73
|
+
return [
|
|
74
|
+
("", f"[{counter}/{size}] {self.ps} ["),
|
|
75
|
+
("bold", default[0]),
|
|
76
|
+
("", f"{''.join(f' / {x}' for x in default[1:])}]: "),
|
|
77
|
+
]
|
|
78
|
+
return f"[{counter}/{size}] {self.ps}: "
|
|
79
|
+
|
|
80
|
+
def _get_str(self, default: str, counter: int, size: int):
|
|
81
|
+
value = tk_prompt(self._ps(default, counter, size))
|
|
82
|
+
if not value:
|
|
83
|
+
value = default
|
|
84
|
+
return value
|
|
85
|
+
|
|
86
|
+
def _get_flag(self, default: bool, counter: int, size: int):
|
|
87
|
+
value = self._tk_prompt(
|
|
88
|
+
default, ["yes", "no", "on", "off", "1", "0"], counter, size
|
|
89
|
+
)
|
|
90
|
+
result = default
|
|
91
|
+
if value:
|
|
92
|
+
result = value.lower() in ["1", "on", "y", "yes"]
|
|
93
|
+
return result
|
|
94
|
+
|
|
95
|
+
def _get_list(self, defaults: List[str], counter: int, size: int):
|
|
96
|
+
value = self._tk_prompt(defaults, defaults, counter, size)
|
|
97
|
+
if not value:
|
|
98
|
+
value = defaults[0]
|
|
99
|
+
return value
|
|
100
|
+
|
|
101
|
+
def _tk_prompt(
|
|
102
|
+
self,
|
|
103
|
+
defaults: Union[bool, List[str]],
|
|
104
|
+
words: List[str],
|
|
105
|
+
counter: int,
|
|
106
|
+
size: int,
|
|
107
|
+
):
|
|
108
|
+
def valid(word: str):
|
|
109
|
+
return word == "" or word in words
|
|
110
|
+
|
|
111
|
+
validator = Validator.from_callable(valid)
|
|
112
|
+
completer = WordCompleter(words)
|
|
113
|
+
return tk_prompt(
|
|
114
|
+
self._ps(defaults, counter, size),
|
|
115
|
+
validator=validator,
|
|
116
|
+
completer=completer,
|
|
117
|
+
complete_while_typing=True,
|
|
118
|
+
complete_style=CompleteStyle.READLINE_LIKE,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _project_filter(project: Optional[str]):
|
|
123
|
+
if project is None:
|
|
124
|
+
|
|
125
|
+
def impl(setting: ctx.Setting):
|
|
126
|
+
return setting.project is None
|
|
127
|
+
|
|
128
|
+
return impl
|
|
129
|
+
|
|
130
|
+
def impl(setting: ctx.Setting):
|
|
131
|
+
return setting.project is None or setting.project == project
|
|
132
|
+
|
|
133
|
+
return impl
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _prompt(
|
|
137
|
+
wanted: Callable[[ctx.Setting], bool], overrides: ctx.SettingsType
|
|
138
|
+
) -> ctx.SettingsType:
|
|
139
|
+
settings: ctx.SettingsType = {}
|
|
140
|
+
|
|
141
|
+
defaults = [setting for setting in ctx.defaults if wanted(setting)]
|
|
142
|
+
switches = [setting for setting in ctx.switches if wanted(setting)]
|
|
143
|
+
|
|
144
|
+
size = len(defaults) + len(switches)
|
|
145
|
+
counter = 1
|
|
146
|
+
|
|
147
|
+
for coll in [defaults, switches]:
|
|
148
|
+
for setting in coll:
|
|
149
|
+
loaded = _Question.load_default(
|
|
150
|
+
setting, settings, overrides.get(setting.json_key)
|
|
151
|
+
)
|
|
152
|
+
value = loaded.interact(counter, size)
|
|
153
|
+
settings[loaded.key] = value
|
|
154
|
+
counter += 1
|
|
155
|
+
|
|
156
|
+
return settings
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _all_default(wanted: Callable[[ctx.Setting], bool], overrides: ctx.SettingsType):
|
|
160
|
+
"""
|
|
161
|
+
Chooses default answers for all details of newly-crated project.
|
|
162
|
+
|
|
163
|
+
:returns: Dictionary with default values of all interactive settings
|
|
164
|
+
and switches.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
settings: ctx.SettingsType = {}
|
|
168
|
+
|
|
169
|
+
defaults = [setting for setting in ctx.defaults if wanted(setting)]
|
|
170
|
+
switches = [setting for setting in ctx.switches if wanted(setting)]
|
|
171
|
+
|
|
172
|
+
for coll in [defaults, switches]:
|
|
173
|
+
for setting in coll:
|
|
174
|
+
if setting.json_key in overrides:
|
|
175
|
+
settings[setting.json_key] = overrides[setting.json_key]
|
|
176
|
+
else:
|
|
177
|
+
value = _get_default(setting, settings)
|
|
178
|
+
settings[setting.json_key] = value
|
|
179
|
+
|
|
180
|
+
return settings
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _fixup(settings: ctx.SettingsType, key: str, fixup: str, force=False):
|
|
184
|
+
value = settings.get(key, "")
|
|
185
|
+
if value != "" and not force:
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
value = ctx._build_fixup(settings, fixup)
|
|
189
|
+
settings[key] = value
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _get_default(setting: ctx.Setting, settings: ctx.SettingsType):
|
|
193
|
+
value = setting.calc_value(settings)
|
|
194
|
+
if isinstance(value, list):
|
|
195
|
+
return value[0]
|
|
196
|
+
return value
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _fixup_context(settings: ctx.SettingsType, wanted: Callable[[ctx.Setting], bool]):
|
|
200
|
+
defaults = [setting for setting in ctx.defaults if wanted(setting)]
|
|
201
|
+
hidden = [setting for setting in ctx.hidden if wanted(setting)]
|
|
202
|
+
|
|
203
|
+
for setting in hidden:
|
|
204
|
+
value = _get_default(setting, settings)
|
|
205
|
+
if isinstance(value, bool) or value != "":
|
|
206
|
+
settings[setting.json_key] = value
|
|
207
|
+
|
|
208
|
+
for coll in [defaults, hidden]:
|
|
209
|
+
for setting in coll:
|
|
210
|
+
_fixup(settings, setting.json_key, setting.fix or "", setting.force_fix)
|
|
211
|
+
|
|
212
|
+
try:
|
|
213
|
+
del settings["EXT"]
|
|
214
|
+
except KeyError:
|
|
215
|
+
pass
|
|
216
|
+
|
|
217
|
+
result = {}
|
|
218
|
+
for key in settings:
|
|
219
|
+
path = key.split(".")
|
|
220
|
+
path_ctx = result
|
|
221
|
+
for step in path[:-1]:
|
|
222
|
+
if step not in path_ctx or not isinstance(path_ctx[step], dict):
|
|
223
|
+
path_ctx[step] = {}
|
|
224
|
+
path_ctx = path_ctx[step]
|
|
225
|
+
path_ctx[path[-1]] = settings[key]
|
|
226
|
+
return result
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def get_context(interactive: bool, project: Optional[str], rt: env.Runtime):
|
|
230
|
+
"""
|
|
231
|
+
Prompts user to provide details of newly-crated project. If `interactive`
|
|
232
|
+
is true, however, this functions skips the prompts and chooses all the
|
|
233
|
+
default answers.
|
|
234
|
+
|
|
235
|
+
:param interactive: Selects, if the initialization process is done through
|
|
236
|
+
prompts, or not.
|
|
237
|
+
|
|
238
|
+
:param project: Alows to select questions for any given language.
|
|
239
|
+
|
|
240
|
+
:param rt: Runtime with config loaded in.
|
|
241
|
+
|
|
242
|
+
:returns: Dictionary with answers to all interactive settings and switches.
|
|
243
|
+
"""
|
|
244
|
+
|
|
245
|
+
overrides = rt._cfg.get("defaults", {})
|
|
246
|
+
|
|
247
|
+
wanted = _project_filter(project)
|
|
248
|
+
return _fixup_context(
|
|
249
|
+
(
|
|
250
|
+
_all_default(wanted, overrides)
|
|
251
|
+
if not interactive
|
|
252
|
+
else _prompt(wanted, overrides)
|
|
253
|
+
),
|
|
254
|
+
wanted,
|
|
255
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: proj-flow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.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,41 +1,42 @@
|
|
|
1
|
-
proj_flow/__init__.py,sha256=
|
|
1
|
+
proj_flow/__init__.py,sha256=rJnUcfKn1M3oCrkLIpU66A5IZYuXAN9puzWG3l2KM7s,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/env.py,sha256=
|
|
7
|
+
proj_flow/api/ctx.py,sha256=IJu0q0Chivo6b2M4MKkAlV09oi7Cn9VxtDFeAeL_tnc,6646
|
|
8
|
+
proj_flow/api/env.py,sha256=VOJbyyMQydPLV4-xQ9ylxwhkvJ8EhZro1GOYPfUSnCU,12629
|
|
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
|
|
13
|
+
proj_flow/base/__cmake_version__.py,sha256=imja0GnhpBvS8Crz-64eOUKhc4i6FeRrjBGRB68x_p0,239
|
|
12
14
|
proj_flow/base/__init__.py,sha256=RRmqiYjdVlC4i8QijXHNiRh9yzNH8305WXezrSaPjKk,311
|
|
13
15
|
proj_flow/base/cmd.py,sha256=Vo3e8kd4CHRzbsUkO-MnbhQxjLXTczv7YQRUkFlcBQE,1560
|
|
14
16
|
proj_flow/base/inspect.py,sha256=lt5P19rvSZ-wMCTrCYAaQFCt2S9fUjEQXlrKK-Tmvwc,2786
|
|
15
17
|
proj_flow/base/matrix.py,sha256=8XBFGYOwW6Myt_4h3WNk36V2bJ5xeqUv6DvzF4B3q_g,7767
|
|
18
|
+
proj_flow/base/name_list.py,sha256=KiHSnbDgYplJc25O3EehYhFAhD7Z3mHVAK6UYOdg5PQ,416
|
|
16
19
|
proj_flow/base/plugins.py,sha256=evn2Dym_NeoBaIZAu2YUtRd--15PCFpHD0h5zSsWkQE,978
|
|
17
|
-
proj_flow/base/registry.py,sha256=
|
|
20
|
+
proj_flow/base/registry.py,sha256=JJJONiBwpPvOvwh-Omrsc0OfhDC_88wC9HUJTN9udww,3743
|
|
18
21
|
proj_flow/base/uname.py,sha256=7Awb3Es0jTAKMpyRawdrC16xc5X9M97BlPqEfQibqIk,2295
|
|
19
|
-
proj_flow/cli/__init__.py,sha256=
|
|
20
|
-
proj_flow/cli/argument.py,sha256=
|
|
22
|
+
proj_flow/cli/__init__.py,sha256=cMsZpECkXeSzY4Hv_ela3Ou-FhwE5w1A3ypMSnZZikM,1196
|
|
23
|
+
proj_flow/cli/argument.py,sha256=OCx_Z0NVm4bmHI30WFdtPdqVMdDnvkqqluhAgP7Ya0w,13686
|
|
21
24
|
proj_flow/cli/finder.py,sha256=5x7H1nH0k63DetDauhB_wABel_f0RQpsZ5YnhPfbkRc,1402
|
|
22
25
|
proj_flow/ext/__init__.py,sha256=XD52rUFTPz3GnyRq6KZUNeWdMce7e0bB19iTx-zU6DE,169
|
|
23
26
|
proj_flow/ext/markdown_changelog.py,sha256=fRGL09jojnv2B-8vAX2prvgNp8e7uyq5NxboSZjFCJ8,436
|
|
24
27
|
proj_flow/ext/re_structured_changelog.py,sha256=UF23W9eu_YgPO42MiaoDbEKu8In_48mQg6rH9--mI30,459
|
|
25
28
|
proj_flow/ext/store.py,sha256=yfyIb2G7UhoIkPmVDnp1RPx2fwFZK8FyLZzrMvPlEUM,3681
|
|
26
29
|
proj_flow/ext/cplusplus/__init__.py,sha256=dAmLMyGVQq586jJM_jiAuo5Ecw9U8agpvSRbzzPgh3g,245
|
|
27
|
-
proj_flow/ext/cplusplus/cmake/__init__.py,sha256=
|
|
28
|
-
proj_flow/ext/cplusplus/cmake/__version__.py,sha256=tmRnT4aUpx4_h-vyWsGyVEeahW49VlLqlsd-o7irmKY,126
|
|
29
|
-
proj_flow/ext/cplusplus/cmake/context.py,sha256=5RPpc0tquh7xDO1_ifgnIdxCbabuZeW-Yw7QjpeazUo,3085
|
|
30
|
+
proj_flow/ext/cplusplus/cmake/__init__.py,sha256=QRD9qEzIhOuzwyjOFdOWUFiwwGTctss5y6Eam3RzeVc,346
|
|
30
31
|
proj_flow/ext/cplusplus/cmake/parser.py,sha256=ZqQRZqS_VU5VtC8uwax-dknh7sfuLEvtazG8ChSqHDQ,3814
|
|
31
|
-
proj_flow/ext/cplusplus/cmake/steps.py,sha256=
|
|
32
|
+
proj_flow/ext/cplusplus/cmake/steps.py,sha256=sYrx7R96HFxo7wzX1n53pthwWMdQFOBSb3tkL9JHneY,4120
|
|
32
33
|
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=
|
|
34
|
+
proj_flow/ext/cplusplus/conan/__init__.py,sha256=Fv839SWsKPWMZs9ox9T-bofZ4xDJXOI5UfWKQkm0Vtg,1924
|
|
35
|
+
proj_flow/ext/cplusplus/conan/_conan.py,sha256=9xnji-f8uN7huXLqavVBUDC33CgnjBIyZX6wVcGm2RA,3352
|
|
35
36
|
proj_flow/ext/github/__init__.py,sha256=Mgx19YS6SYBXYB66_pOgIgwuB2WKRxqp5UGutq0B9Xk,282
|
|
36
|
-
proj_flow/ext/github/cli.py,sha256=
|
|
37
|
+
proj_flow/ext/github/cli.py,sha256=zQS2TB7fDeY0VwR1bOw065Trz2NPe07JKcFQaJbwKGg,3934
|
|
37
38
|
proj_flow/ext/github/hosting.py,sha256=3iW8QjeJk7MyqKNbv92nB-5a_Yn_B5_eEIlw_cdgUT0,519
|
|
38
|
-
proj_flow/ext/github/switches.py,sha256=
|
|
39
|
+
proj_flow/ext/github/switches.py,sha256=g7O2hvrg4mHm3WSHYsRBhEDU0bIkEJgp4Qclhqxk0uI,421
|
|
39
40
|
proj_flow/ext/python/__init__.py,sha256=GbEKEJJZ3PJ4sRHEykAWjGIR6yyyrYdlUFulldvsAGI,252
|
|
40
41
|
proj_flow/ext/python/rtdocs.py,sha256=idm6DTUnbA18L-EpxQiFVXCz9x8AIRSb52ZPqIXzrf8,6354
|
|
41
42
|
proj_flow/ext/python/steps.py,sha256=pDHGAe_CDzzdRFAzM1AIBvkbc14KB3SNUunusKZAaaY,1815
|
|
@@ -43,11 +44,8 @@ proj_flow/ext/python/version.py,sha256=pnyuKATyZwBh1p0gf9KmqbRSZx8hJ5285CiFK_tHE
|
|
|
43
44
|
proj_flow/ext/sign/__init__.py,sha256=yvXpqLdvBwkB0GDBl4yWw--iZ2tFxhx-97EP9OAzx2g,4345
|
|
44
45
|
proj_flow/ext/sign/api.py,sha256=dlnXYYoBDYXx_WWGBQ8ThKmEMYmw2kt6NNZA8j-MXuM,2288
|
|
45
46
|
proj_flow/ext/sign/win32.py,sha256=fV8_Z42KaeDBEf3_5qCzlALb0dy1zN0Pqy8Hr-ZMAQ4,4874
|
|
46
|
-
proj_flow/flow/__init__.py,sha256=
|
|
47
|
+
proj_flow/flow/__init__.py,sha256=5Zo97zJsR7HMbl64jeMB9PbUuxCxpOlNuLmo3apWSVU,277
|
|
47
48
|
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
49
|
proj_flow/flow/layer.py,sha256=6mvbhiOy9KcMP69Q9zew_7jGhf5Wqr7v-veS3YPGnmc,5720
|
|
52
50
|
proj_flow/flow/steps.py,sha256=PN_C_B6vNvqOsjpDpa5ESvH30Sc6RM1fSSqWqXgqg-4,2804
|
|
53
51
|
proj_flow/log/__init__.py,sha256=02EIgasE-K7mmbbNiIdX0IebWQMp2Co_D6H4ZBhJgcs,365
|
|
@@ -64,12 +62,20 @@ proj_flow/log/rich_text/api.py,sha256=PCSAGwkmDUMoVlpN7BDsgIA1AiMZEC0H6TUZXpr_Mg
|
|
|
64
62
|
proj_flow/log/rich_text/markdown.py,sha256=jBnNxxhBHzyIZ3Y4HXDfqpl7zlRbbKbKdwdnZwkmNAI,1623
|
|
65
63
|
proj_flow/log/rich_text/re_structured_text.py,sha256=DEl9KjBUF6cxfNWpQ7GVnHi7wKeuFnPGJwxQxjbCsnM,1823
|
|
66
64
|
proj_flow/minimal/__init__.py,sha256=NglaSdKiMebrOqfsqF9ctqi0ZwiiBHOQcUnp3DS8lP0,340
|
|
67
|
-
proj_flow/minimal/base.py,sha256
|
|
65
|
+
proj_flow/minimal/base.py,sha256=yJR3FAigR_x8krTQ1UeifBb4AnLUZAk6LfVVqB_RFO4,758
|
|
68
66
|
proj_flow/minimal/bootstrap.py,sha256=PcZfBsUmj8uDPGBC55iUgD5O7W4VSkpCQb6r9GEyAaQ,556
|
|
69
|
-
proj_flow/minimal/init.py,sha256=
|
|
67
|
+
proj_flow/minimal/init.py,sha256=kJ4flv_W6ZHMVOEDwDbeURlOXS3O2AjGobGzKIbHxZE,2949
|
|
70
68
|
proj_flow/minimal/list.py,sha256=RlOqammE8olNKXsnbv1enF5uriu0MZ2wFbht37Z2ETw,4810
|
|
71
|
-
proj_flow/minimal/run.py,sha256=
|
|
69
|
+
proj_flow/minimal/run.py,sha256=4qvGLqz2ayCZDvVBrq4tG094fjfcmDPon-xcGPQkM_U,4665
|
|
72
70
|
proj_flow/minimal/system.py,sha256=9FliH5TD103JYSAe2O5EU7hkOHDgVzTqu0Exxk-WrXE,1579
|
|
71
|
+
proj_flow/project/__init__.py,sha256=AROrwhbuMR5rJE-HC769eL4IXrMLQYpQb3HgpkOAYqg,293
|
|
72
|
+
proj_flow/project/api.py,sha256=-B9Oj_7Z8hQvfgs32XU-S0nw9y8hFSkO71hx-JUHs7Q,1384
|
|
73
|
+
proj_flow/project/data.py,sha256=TluhBDoJEYL4dnyTpInmhQ49Uvf8mkWmpU-YMLQPNhE,317
|
|
74
|
+
proj_flow/project/interact.py,sha256=Abb6Jt88pCebJMkKLGCF3RQLM-Q9D8Yk92GarZ27e9E,7909
|
|
75
|
+
proj_flow/project/cplusplus/__init__.py,sha256=rEKuxAVMpkTTM01Upv3VUtkSiVIpXDAux-7FreWsF2k,301
|
|
76
|
+
proj_flow/project/cplusplus/cmake_context.py,sha256=HZTJ4D_EYHCZGfrSXUHtX2fPzbPp2jON5OCHRSyLPgk,3203
|
|
77
|
+
proj_flow/project/cplusplus/conan_context.py,sha256=iXKATfS56R8AgO3g02M15CqcAkvNeO4gBahWSLHo8Dg,319
|
|
78
|
+
proj_flow/project/cplusplus/project.py,sha256=gLvymc5bhXsjgBRm0u-oddXjbVHmwf6aIpHnqVAd9nc,399
|
|
73
79
|
proj_flow/template/layers/base.json,sha256=jrlby8FUUwkx4V_EGMix_pkQlWcUCVUgmeoapZaZnt4,3
|
|
74
80
|
proj_flow/template/layers/cmake.json,sha256=KJe9uqTDoGm0ppdNOtniKEv30iNV2K4Yk8hZQetEZ7Y,385
|
|
75
81
|
proj_flow/template/layers/conan.json,sha256=mAhDrxCtDjI_7Rbtr2hlNW5_jZkLdWLiwgfuhRsRuuw,29
|
|
@@ -124,8 +130,8 @@ proj_flow/template/licenses/MIT.mustache,sha256=NncPoQaNsuy-WmRmboik3fyhJJ8m5pc2
|
|
|
124
130
|
proj_flow/template/licenses/Unlicense.mustache,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
|
|
125
131
|
proj_flow/template/licenses/WTFPL.mustache,sha256=lvF4V_PrKKfZPa2TC8CZo8tlqaKvs3Bpv9G6XsWWQ4k,483
|
|
126
132
|
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.
|
|
133
|
+
proj_flow-0.11.0.dist-info/METADATA,sha256=x-Enl_zQtntZR9HXEwP7m-jaR86E6orA5ofhbaWXudc,2868
|
|
134
|
+
proj_flow-0.11.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
135
|
+
proj_flow-0.11.0.dist-info/entry_points.txt,sha256=d_OmGKZzpY7FCWz0sZ4wnBAPZC75oMEzTgJZWtpDELo,49
|
|
136
|
+
proj_flow-0.11.0.dist-info/licenses/LICENSE,sha256=vpOQJ5QlrTedF3coEWvA4wJzVJH304f66ZitR7Od4iU,1068
|
|
137
|
+
proj_flow-0.11.0.dist-info/RECORD,,
|