proj-flow 0.8.1__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 +4 -0
- proj_flow/__main__.py +10 -0
- proj_flow/api/__init__.py +10 -0
- proj_flow/api/arg.py +134 -0
- proj_flow/api/completers.py +93 -0
- proj_flow/api/ctx.py +238 -0
- proj_flow/api/env.py +416 -0
- proj_flow/api/init.py +26 -0
- proj_flow/api/makefile.py +140 -0
- proj_flow/api/step.py +173 -0
- proj_flow/base/__init__.py +11 -0
- proj_flow/base/cmd.py +50 -0
- proj_flow/base/inspect.py +133 -0
- proj_flow/base/matrix.py +240 -0
- proj_flow/base/plugins.py +44 -0
- proj_flow/base/uname.py +71 -0
- proj_flow/flow/__init__.py +11 -0
- proj_flow/flow/cli/__init__.py +66 -0
- proj_flow/flow/cli/cmds.py +385 -0
- proj_flow/flow/cli/finder.py +59 -0
- proj_flow/flow/configs.py +162 -0
- proj_flow/flow/dependency.py +153 -0
- proj_flow/flow/init.py +65 -0
- proj_flow/flow/interact.py +134 -0
- proj_flow/flow/layer.py +176 -0
- proj_flow/flow/steps.py +104 -0
- proj_flow/log/__init__.py +10 -0
- proj_flow/log/commit.py +463 -0
- proj_flow/log/fmt.py +12 -0
- proj_flow/log/format.py +13 -0
- proj_flow/log/hosting/__init__.py +11 -0
- proj_flow/log/hosting/github.py +248 -0
- proj_flow/log/msg.py +201 -0
- proj_flow/log/release.py +34 -0
- proj_flow/log/rich_text/__init__.py +22 -0
- proj_flow/log/rich_text/api.py +126 -0
- proj_flow/log/rich_text/markdown.py +61 -0
- proj_flow/log/rich_text/re_structured_text.py +68 -0
- proj_flow/plugins/__init__.py +8 -0
- proj_flow/plugins/base.py +30 -0
- proj_flow/plugins/cmake/__init__.py +11 -0
- proj_flow/plugins/cmake/__version__.py +5 -0
- proj_flow/plugins/cmake/build.py +29 -0
- proj_flow/plugins/cmake/config.py +59 -0
- proj_flow/plugins/cmake/context.py +112 -0
- proj_flow/plugins/cmake/pack.py +37 -0
- proj_flow/plugins/cmake/parser.py +166 -0
- proj_flow/plugins/cmake/test.py +29 -0
- proj_flow/plugins/commands/__init__.py +12 -0
- proj_flow/plugins/commands/bootstrap.py +21 -0
- proj_flow/plugins/commands/ci/__init__.py +17 -0
- proj_flow/plugins/commands/ci/changelog.py +47 -0
- proj_flow/plugins/commands/ci/matrix.py +46 -0
- proj_flow/plugins/commands/ci/release.py +116 -0
- proj_flow/plugins/commands/init.py +75 -0
- proj_flow/plugins/commands/list.py +167 -0
- proj_flow/plugins/commands/run.py +147 -0
- proj_flow/plugins/commands/system.py +60 -0
- proj_flow/plugins/conan/__init__.py +66 -0
- proj_flow/plugins/conan/_conan.py +146 -0
- proj_flow/plugins/github.py +13 -0
- proj_flow/plugins/sign/__init__.py +130 -0
- proj_flow/plugins/sign/win32.py +191 -0
- proj_flow/plugins/store/__init__.py +11 -0
- proj_flow/plugins/store/store_both.py +22 -0
- proj_flow/plugins/store/store_packages.py +79 -0
- proj_flow/plugins/store/store_tests.py +21 -0
- proj_flow/template/layers/base/.clang-format +27 -0
- proj_flow/template/layers/base/.flow/config.yml +38 -0
- proj_flow/template/layers/base/.flow/flow.py.mustache +172 -0
- proj_flow/template/layers/base/.flow/matrix.yml +63 -0
- proj_flow/template/layers/base/.flow/official.yml +4 -0
- proj_flow/template/layers/base/.gitignore +39 -0
- proj_flow/template/layers/base/README.md.mustache +2 -0
- proj_flow/template/layers/base/flow +7 -0
- proj_flow/template/layers/base/flow.cmd +9 -0
- proj_flow/template/layers/base.json +2 -0
- proj_flow/template/layers/cmake/.flow/cmake/common.cmake.mustache +27 -0
- proj_flow/template/layers/cmake/.flow/extensions/wall/__init__.py.mustache +2 -0
- proj_flow/template/layers/cmake/.flow/extensions/wall/icons/__init__.py.mustache +54 -0
- proj_flow/template/layers/cmake/.flow/extensions/wall/icons/magick.py.mustache +97 -0
- proj_flow/template/layers/cmake/.flow/packages/base.cmake.mustache +33 -0
- proj_flow/template/layers/cmake/.flow/packages/config.cmake +12 -0
- proj_flow/template/layers/cmake/.flow/packages/cpack.cmake +3 -0
- proj_flow/template/layers/cmake/.flow/packages/wix/cpack.cmake.mustache +1 -0
- proj_flow/template/layers/cmake/.flow/packages/wix/patches.in.wix +10 -0
- proj_flow/template/layers/cmake/.flow/packages/wix.cmake.mustache +13 -0
- proj_flow/template/layers/cmake/CMakeGraphVizOptions.cmake +8 -0
- proj_flow/template/layers/cmake/CMakeLists.txt.mustache +213 -0
- proj_flow/template/layers/cmake/CMakePresets.json +196 -0
- proj_flow/template/layers/cmake/data/assets/appicon.ico +0 -0
- proj_flow/template/layers/cmake/data/assets/appicon.png +0 -0
- proj_flow/template/layers/cmake/data/assets/wix_banner.bmp +0 -0
- proj_flow/template/layers/cmake/data/assets/wix_dialog.bmp +0 -0
- proj_flow/template/layers/cmake/data/icons/.gitignore +3 -0
- proj_flow/template/layers/cmake/data/icons/appicon-mask.svg +6 -0
- proj_flow/template/layers/cmake/data/icons/appicon.svg +27 -0
- proj_flow/template/layers/cmake/src/main.cc.mustache +38 -0
- proj_flow/template/layers/cmake/src/version.hpp.in.mustache +36 -0
- proj_flow/template/layers/cmake/tests/test.cc.mustache +17 -0
- proj_flow/template/layers/cmake.json +15 -0
- proj_flow/template/layers/conan/.flow/cmake/libcxx_toolchain.cmake +4 -0
- proj_flow/template/layers/conan/.flow/cmake/output_dirs_setup.cmake +19 -0
- proj_flow/template/layers/conan/conanfile.txt +9 -0
- proj_flow/template/layers/conan.json +3 -0
- proj_flow/template/layers/github_actions/.github/linters/.isort.cfg +4 -0
- proj_flow/template/layers/github_actions/.github/linters/.mypy.ini +2 -0
- proj_flow/template/layers/github_actions/.github/workflows/build.yml +241 -0
- proj_flow/template/layers/github_actions/.github/workflows/linter.yml +59 -0
- proj_flow/template/layers/github_actions/CPPLINT.cfg +16 -0
- proj_flow/template/layers/github_actions.json +3 -0
- proj_flow/template/layers/github_social/.github/ISSUE_TEMPLATE/bug_report.md.mustache +42 -0
- proj_flow/template/layers/github_social/.github/ISSUE_TEMPLATE/feature_request.md.mustache +28 -0
- proj_flow/template/layers/github_social/CODE_OF_CONDUCT.md.mustache +76 -0
- proj_flow/template/layers/github_social/CONTRIBUTING.md +10 -0
- proj_flow/template/layers/github_social.json +3 -0
- proj_flow/template/licenses/0BSD.mustache +12 -0
- proj_flow/template/licenses/MIT.mustache +21 -0
- proj_flow/template/licenses/Unlicense.mustache +24 -0
- proj_flow/template/licenses/WTFPL.mustache +13 -0
- proj_flow/template/licenses/Zlib.mustache +19 -0
- proj_flow-0.8.1.dist-info/METADATA +81 -0
- proj_flow-0.8.1.dist-info/RECORD +126 -0
- proj_flow-0.8.1.dist-info/WHEEL +4 -0
- proj_flow-0.8.1.dist-info/entry_points.txt +2 -0
- proj_flow-0.8.1.dist-info/licenses/LICENSE +21 -0
proj_flow/__init__.py
ADDED
proj_flow/__main__.py
ADDED
|
@@ -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.api** contains public APIs, usable in third-party plugins.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from . import arg, completers, ctx, env, init, makefile, step
|
|
9
|
+
|
|
10
|
+
__all__ = ["arg", "completers", "ctx", "env", "init", "makefile", "step"]
|
proj_flow/api/arg.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
+
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
The **proj_flow.api.arg** is used by various commands to declare CLI arguments.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import inspect
|
|
10
|
+
import typing
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
|
|
13
|
+
from proj_flow.base import inspect as _inspect
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class Argument:
|
|
18
|
+
help: str = ""
|
|
19
|
+
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
|
|
27
|
+
completer: typing.Optional[callable] = None # type: ignore
|
|
28
|
+
|
|
29
|
+
def visit(self, parser: argparse.ArgumentParser, name: str):
|
|
30
|
+
kwargs = {}
|
|
31
|
+
if self.help is not None:
|
|
32
|
+
kwargs["help"] = self.help
|
|
33
|
+
if self.nargs is not None:
|
|
34
|
+
kwargs["nargs"] = self.nargs
|
|
35
|
+
if self.meta is not None:
|
|
36
|
+
kwargs["metavar"] = self.meta
|
|
37
|
+
if self.default is not None:
|
|
38
|
+
kwargs["default"] = self.default
|
|
39
|
+
if self.action is not None:
|
|
40
|
+
kwargs["action"] = self.action
|
|
41
|
+
if self.choices is not None:
|
|
42
|
+
kwargs["choices"] = self.choices
|
|
43
|
+
|
|
44
|
+
names = (
|
|
45
|
+
[name] if self.pos else self.names if len(self.names) > 0 else [f"--{name}"]
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if self.pos:
|
|
49
|
+
kwargs["nargs"] = "?" if self.opt else 1
|
|
50
|
+
else:
|
|
51
|
+
kwargs["dest"] = name
|
|
52
|
+
kwargs["required"] = not self.opt
|
|
53
|
+
|
|
54
|
+
action = parser.add_argument(*names, **kwargs)
|
|
55
|
+
if self.completer:
|
|
56
|
+
action.completer = self.completer # type: ignore
|
|
57
|
+
|
|
58
|
+
return action
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class FlagArgument(Argument):
|
|
62
|
+
def __init__(self, help: str = "", names: typing.List[str] = []):
|
|
63
|
+
super().__init__(
|
|
64
|
+
help=help, names=names, opt=True, action="store_true", default=False
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class _Command:
|
|
70
|
+
name: str
|
|
71
|
+
entry: typing.Optional[callable] # type: ignore
|
|
72
|
+
doc: typing.Optional[str]
|
|
73
|
+
subs: typing.Dict[str, "_Command"]
|
|
74
|
+
|
|
75
|
+
def add(self, names: typing.List[str], entry: callable, doc: typing.Optional[str]): # type: ignore
|
|
76
|
+
name = names[0]
|
|
77
|
+
rest = names[1:]
|
|
78
|
+
if len(rest):
|
|
79
|
+
try:
|
|
80
|
+
child = self.subs[name]
|
|
81
|
+
except KeyError:
|
|
82
|
+
child = _Command(name, None, None, {})
|
|
83
|
+
self.subs[name] = child
|
|
84
|
+
|
|
85
|
+
child.add(rest, entry, doc)
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
child = self.subs[name]
|
|
90
|
+
child.entry = entry
|
|
91
|
+
child.doc = doc
|
|
92
|
+
except KeyError:
|
|
93
|
+
self.subs[name] = _Command(name, entry, doc, {})
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
_known_commands = _Command("", None, None, {})
|
|
97
|
+
_autodoc = {
|
|
98
|
+
"proj_flow.flow.configs.Configs": "Current configuration list.",
|
|
99
|
+
"proj_flow.api.env.Runtime": "Tools and print messages, while respecting ``--dry-run``, ``--silent`` and ``--verbose``.",
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def command(*name: str):
|
|
104
|
+
def wrap(entry: callable): # type: ignore
|
|
105
|
+
global _known_commands
|
|
106
|
+
_known_commands.add(list(name), entry, entry.__doc__)
|
|
107
|
+
|
|
108
|
+
doc = inspect.getdoc(entry) or ""
|
|
109
|
+
if doc:
|
|
110
|
+
doc += "\n\n"
|
|
111
|
+
|
|
112
|
+
for arg in _inspect.signature(entry):
|
|
113
|
+
help = ""
|
|
114
|
+
for meta in arg.metadata:
|
|
115
|
+
if isinstance(meta, Argument):
|
|
116
|
+
help = meta.help
|
|
117
|
+
if help:
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
if not help:
|
|
121
|
+
full_name = f"{arg.type.__module__}.{arg.type.__name__}"
|
|
122
|
+
help = _autodoc.get(full_name, "")
|
|
123
|
+
|
|
124
|
+
doc += f":param {_inspect.type_name(arg.type)} {arg.name}: {help}\n"
|
|
125
|
+
|
|
126
|
+
entry.__doc__ = doc
|
|
127
|
+
|
|
128
|
+
return entry
|
|
129
|
+
|
|
130
|
+
return wrap
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def get_commands():
|
|
134
|
+
return _known_commands
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
+
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
The **proj_flow.api.completers** defines :py:mod:`argcomplete` functions for
|
|
6
|
+
``-C``, ``--step`` and ``-D``.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
from typing import Any, Dict, List, Union, cast
|
|
11
|
+
|
|
12
|
+
import yaml
|
|
13
|
+
|
|
14
|
+
from proj_flow import api
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def cd_completer(prefix, **kwargs):
|
|
18
|
+
target_dir = os.path.dirname(prefix)
|
|
19
|
+
incomplete_part = os.path.basename(prefix)
|
|
20
|
+
try:
|
|
21
|
+
names = os.listdir(target_dir or ".")
|
|
22
|
+
except Exception:
|
|
23
|
+
return # empty iterator
|
|
24
|
+
|
|
25
|
+
for name in names:
|
|
26
|
+
if not name.startswith(incomplete_part):
|
|
27
|
+
continue
|
|
28
|
+
full = os.path.join(target_dir, name)
|
|
29
|
+
if not os.path.isdir(full):
|
|
30
|
+
continue
|
|
31
|
+
|
|
32
|
+
yield f"{full}{os.sep}"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def step_completer(prefix: str, parser, **kwargs):
|
|
36
|
+
flow_cfg = cast(api.env.FlowConfig, parser.flow)
|
|
37
|
+
|
|
38
|
+
comma_sep = prefix.split(",")
|
|
39
|
+
start = ",".join(comma_sep[:-1])
|
|
40
|
+
if len(comma_sep) > 1:
|
|
41
|
+
start += ","
|
|
42
|
+
|
|
43
|
+
current = comma_sep[-1].lower()
|
|
44
|
+
for step in flow_cfg.steps:
|
|
45
|
+
name = cast(str, step.name)
|
|
46
|
+
if name.lower().startswith(current):
|
|
47
|
+
candidate = current + name[len(current) :]
|
|
48
|
+
yield start + candidate
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _str_arg(arg: Union[bool, str]):
|
|
52
|
+
if isinstance(arg, bool):
|
|
53
|
+
return "ON" if arg else "OFF"
|
|
54
|
+
return str(arg)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def matrix_completer(prefix: str, parser, **kwargs):
|
|
58
|
+
flow_cfg = cast(api.env.FlowConfig, parser.flow)
|
|
59
|
+
|
|
60
|
+
matrix_yml = os.path.join(flow_cfg.root, ".flow", "matrix.yml")
|
|
61
|
+
with open(matrix_yml, "r", encoding="UTF-8") as contents:
|
|
62
|
+
data: Dict[str, List[Any]] = yaml.load(contents, Loader=yaml.Loader).get(
|
|
63
|
+
"matrix", {}
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
comma_sep = prefix.split(",")
|
|
67
|
+
start = ",".join(comma_sep[:-1])
|
|
68
|
+
if len(comma_sep) > 1:
|
|
69
|
+
start += ","
|
|
70
|
+
|
|
71
|
+
current = comma_sep[-1].split("=", 1)
|
|
72
|
+
|
|
73
|
+
if len(current) == 1:
|
|
74
|
+
completions: List[str] = []
|
|
75
|
+
for key in data:
|
|
76
|
+
if key.startswith(current[0]):
|
|
77
|
+
completions.append(f"{start}{key}=")
|
|
78
|
+
if len(completions) != 1:
|
|
79
|
+
return completions
|
|
80
|
+
|
|
81
|
+
current = completions[0].split("=", 1)
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
args = data[current[0]]
|
|
85
|
+
except KeyError:
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
completions: List[str] = []
|
|
89
|
+
for arg in map(_str_arg, args):
|
|
90
|
+
if arg.startswith(current[1]):
|
|
91
|
+
completions.append(f"{start}{current[0]}={arg}")
|
|
92
|
+
|
|
93
|
+
return completions
|
proj_flow/api/ctx.py
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# Copyright (c) 2025 Marcin Zdun
|
|
2
|
+
# This code is licensed under MIT license (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
The **proj_flow.api.ctx** provides tools for preparing the project template.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import datetime
|
|
9
|
+
import inspect
|
|
10
|
+
import os
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Callable, Dict, Iterable, List, Optional, Union
|
|
13
|
+
|
|
14
|
+
from proj_flow.base import cmd
|
|
15
|
+
|
|
16
|
+
package_root = os.path.dirname(os.path.dirname(__file__))
|
|
17
|
+
template_dir = "template"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
StrOrBool = Union[str, bool]
|
|
21
|
+
Values = Union[StrOrBool, List[str]]
|
|
22
|
+
SettingsType = Dict[str, StrOrBool]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class Setting:
|
|
27
|
+
json_key: str
|
|
28
|
+
prompt: str = ""
|
|
29
|
+
value: Union[Values, Callable[[], Values]] = ""
|
|
30
|
+
fix: Optional[str] = None
|
|
31
|
+
force_fix: bool = False
|
|
32
|
+
|
|
33
|
+
def calc_value(self, previous: SettingsType):
|
|
34
|
+
if isinstance(self.value, Callable):
|
|
35
|
+
kwargs = {}
|
|
36
|
+
|
|
37
|
+
params = inspect.signature(self.value).parameters
|
|
38
|
+
if "settings" in params:
|
|
39
|
+
kwargs["settings"] = previous
|
|
40
|
+
|
|
41
|
+
return self.value(**kwargs)
|
|
42
|
+
|
|
43
|
+
return self.value
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def register_init_setting(*setting: Setting, is_hidden=False):
|
|
47
|
+
(hidden if is_hidden else defaults).extend(setting)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def register_switch(key: str, prompt: str, enabled: bool):
|
|
51
|
+
switches.append(Setting(key, prompt, value=enabled))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def register_internal(key: str, value: any):
|
|
55
|
+
internals[key] = value
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _git_config(name: str):
|
|
59
|
+
def wrap():
|
|
60
|
+
proc = cmd.run("git", "config", name, capture_output=True)
|
|
61
|
+
if proc is None or proc.returncode != 0:
|
|
62
|
+
return None
|
|
63
|
+
return proc.stdout.strip()
|
|
64
|
+
|
|
65
|
+
return wrap
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def move_to_front(preferred: str, values: Iterable[str]):
|
|
69
|
+
result: List[str] = []
|
|
70
|
+
|
|
71
|
+
has_preferred = False
|
|
72
|
+
for value in values:
|
|
73
|
+
if value == preferred:
|
|
74
|
+
has_preferred = True
|
|
75
|
+
else:
|
|
76
|
+
result.append(value)
|
|
77
|
+
|
|
78
|
+
if has_preferred:
|
|
79
|
+
result.insert(0, preferred)
|
|
80
|
+
|
|
81
|
+
return result
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _list_ext():
|
|
85
|
+
return move_to_front(".cpp", sorted(_fileext.keys()))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _as_mustache(basename: str):
|
|
89
|
+
name, ext = os.path.splitext(basename)
|
|
90
|
+
return ext == ".mustache" and name or None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _enum_licenses():
|
|
94
|
+
root = os.path.abspath(os.path.join(package_root, template_dir, "licenses"))
|
|
95
|
+
for _, dirnames, filenames in os.walk(root):
|
|
96
|
+
dirnames[:] = []
|
|
97
|
+
iter = filter(lambda x: x is not None, map(_as_mustache, filenames))
|
|
98
|
+
return move_to_front("MIT", iter)
|
|
99
|
+
return []
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _filter(
|
|
103
|
+
src: Callable[[SettingsType], StrOrBool],
|
|
104
|
+
flt: Callable[[StrOrBool], StrOrBool],
|
|
105
|
+
):
|
|
106
|
+
def impl(settings: SettingsType):
|
|
107
|
+
return flt(src(settings))
|
|
108
|
+
|
|
109
|
+
return impl
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _get_nothing(_: SettingsType) -> StrOrBool:
|
|
113
|
+
return ""
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _map(internal_key: str):
|
|
117
|
+
def impl(key: str):
|
|
118
|
+
mapped = internals.get(internal_key)
|
|
119
|
+
if not isinstance(mapped, dict):
|
|
120
|
+
return None
|
|
121
|
+
return mapped.get(key)
|
|
122
|
+
|
|
123
|
+
return impl
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _get_key(key: str):
|
|
127
|
+
def impl(settings: SettingsType):
|
|
128
|
+
return settings.get(key, "")
|
|
129
|
+
|
|
130
|
+
return impl
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _build_fixup(settings: SettingsType, fixup: str):
|
|
134
|
+
fixup_refs = fixup.split("{")
|
|
135
|
+
result = fixup_refs.pop(0)
|
|
136
|
+
for ref_expr in fixup_refs:
|
|
137
|
+
ref_text, verbose = ref_expr.split("}")
|
|
138
|
+
filter_path = ref_text.split("$")
|
|
139
|
+
|
|
140
|
+
ref = filter_path.pop(0)
|
|
141
|
+
code = _get_nothing if ref == "" else _get_key(ref)
|
|
142
|
+
|
|
143
|
+
for filter_name in filter_path:
|
|
144
|
+
flt = _filters.get(filter_name)
|
|
145
|
+
if flt is None:
|
|
146
|
+
if filter_name.startswith("map:"):
|
|
147
|
+
internal_key = filter_name[4:]
|
|
148
|
+
code = _filter(code, _map(internal_key))
|
|
149
|
+
continue
|
|
150
|
+
code = _filter(code, flt)
|
|
151
|
+
|
|
152
|
+
value = code(settings)
|
|
153
|
+
|
|
154
|
+
if result:
|
|
155
|
+
result += value
|
|
156
|
+
else:
|
|
157
|
+
result = value
|
|
158
|
+
|
|
159
|
+
if verbose:
|
|
160
|
+
result += verbose
|
|
161
|
+
|
|
162
|
+
return result
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _fixed(fixup: str):
|
|
166
|
+
def wrap(settings: SettingsType):
|
|
167
|
+
return _build_fixup(settings, fixup)
|
|
168
|
+
|
|
169
|
+
return wrap
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
internals = {}
|
|
173
|
+
|
|
174
|
+
switches: List[Setting] = []
|
|
175
|
+
|
|
176
|
+
defaults: List[Setting] = [
|
|
177
|
+
Setting(
|
|
178
|
+
"PROJECT.NAME",
|
|
179
|
+
"Project name",
|
|
180
|
+
lambda: os.path.basename(os.path.abspath("")) or "?project-name?",
|
|
181
|
+
),
|
|
182
|
+
Setting("PROJECT.DESCRIPTION", "Project description"),
|
|
183
|
+
Setting(
|
|
184
|
+
"PROJECT.EMAIL",
|
|
185
|
+
"Valid email, e.g. for CODE_OF_CONDUCT",
|
|
186
|
+
_git_config("user.email"),
|
|
187
|
+
),
|
|
188
|
+
Setting(
|
|
189
|
+
"COPY.YEAR",
|
|
190
|
+
"Year for copyright notices",
|
|
191
|
+
str(datetime.date.today().year),
|
|
192
|
+
),
|
|
193
|
+
Setting(
|
|
194
|
+
"COPY.HOLDER",
|
|
195
|
+
"Holder of the copyright",
|
|
196
|
+
_git_config("user.name"),
|
|
197
|
+
),
|
|
198
|
+
Setting("COPY.LICENSE", "License", _enum_licenses),
|
|
199
|
+
Setting(
|
|
200
|
+
"INCLUDE_PREFIX",
|
|
201
|
+
'Prefix for includes (as in #include "{PREFIX}/version.hpp")',
|
|
202
|
+
_fixed("{PROJECT.NAME}"),
|
|
203
|
+
),
|
|
204
|
+
Setting(
|
|
205
|
+
"NAME_PREFIX",
|
|
206
|
+
"CMake variable name prefix",
|
|
207
|
+
_fixed("{PROJECT.NAME$safe$upper}"),
|
|
208
|
+
),
|
|
209
|
+
Setting(
|
|
210
|
+
"NAMESPACE",
|
|
211
|
+
"C++ namespace for the project",
|
|
212
|
+
_fixed("{PROJECT.NAME$safe}"),
|
|
213
|
+
),
|
|
214
|
+
Setting("EXT", "Extension for code files", _list_ext),
|
|
215
|
+
Setting("SRCDIR", "Directory for code files", "src"),
|
|
216
|
+
Setting(
|
|
217
|
+
"INCLUDEDIR",
|
|
218
|
+
"Directory for include files",
|
|
219
|
+
"include",
|
|
220
|
+
"{INCLUDEDIR}/{INCLUDE_PREFIX}",
|
|
221
|
+
force_fix=True,
|
|
222
|
+
),
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
hidden: List[Setting] = [
|
|
226
|
+
Setting("EXT.cxx", fix="{EXT}"),
|
|
227
|
+
Setting("EXT.hxx", fix="{EXT.cxx$header}"),
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
_fileext = {".cc": ".hh", ".cxx": ".hxx", ".cpp": ".hpp"}
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
_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"),
|
|
238
|
+
}
|