proj-flow 0.16.0__py3-none-any.whl → 0.17.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 CHANGED
@@ -6,4 +6,4 @@ The **proj_flow** contains only ``__version__`` to be updated, nothing more.
6
6
  This is in an attempt to make this module easy to load initially.
7
7
  """
8
8
 
9
- __version__ = "0.16.0"
9
+ __version__ = "0.17.0"
@@ -7,6 +7,6 @@ The **proj_flow.ext.cplusplus.cmake** provides ``"CMake"``, ``"Build"``,
7
7
  context.
8
8
  """
9
9
 
10
- from . import parser, project, steps
10
+ from . import parser, presets, project, steps
11
11
 
12
- __all__ = ["parser", "project", "steps"]
12
+ __all__ = ["parser", "presets", "project", "steps"]
@@ -0,0 +1,160 @@
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.cmake.presets** check build directories for CMake step.
6
+ """
7
+
8
+ import json
9
+ import os
10
+ import platform
11
+ from dataclasses import dataclass
12
+ from enum import Enum
13
+ from pathlib import Path
14
+ from typing import cast
15
+
16
+
17
+ class MacroType(Enum):
18
+ PRESET_NAME = 1
19
+ GENERATOR = 2
20
+ FILE_DIR = 3
21
+
22
+
23
+ CMAKE_SOURCE_DIR = Path(".").resolve()
24
+ CMAKE_HOST_SYSTEM_NAME = platform.uname().system
25
+
26
+ MACROS: dict[str, Path | str | MacroType] = {
27
+ "${sourceDir}": CMAKE_SOURCE_DIR,
28
+ "${sourceParentDir}": CMAKE_SOURCE_DIR.parent,
29
+ "${sourceDirName}": CMAKE_SOURCE_DIR.name,
30
+ "${presetName}": MacroType.PRESET_NAME,
31
+ "${generator}": MacroType.GENERATOR,
32
+ "${hostSystemName}": CMAKE_HOST_SYSTEM_NAME,
33
+ "${fileDir}": MacroType.FILE_DIR,
34
+ "${dollar}": "$",
35
+ "${pathListSep}": os.pathsep,
36
+ }
37
+
38
+
39
+ @dataclass
40
+ class Preset:
41
+ name: str
42
+ binary_dir: str | None
43
+ generator: str | None
44
+ inherits: list[str]
45
+ file_dir: Path
46
+
47
+ def expand(self):
48
+ if not self.binary_dir:
49
+ return None
50
+ chunks = self.binary_dir.split("${")
51
+ parts: list[str | Path | MacroType] = [chunks[0]]
52
+ for chunk in chunks[1:]:
53
+ var_suffix = chunk.split("}", 1)
54
+ if len(var_suffix) != 2:
55
+ return None
56
+ key = f"${{{var_suffix[0]}}}"
57
+ value = MACROS.get(key, "")
58
+ if isinstance(value, MacroType):
59
+ if value == MacroType.PRESET_NAME:
60
+ value = self.name
61
+ elif value == MacroType.GENERATOR:
62
+ value = self.generator or ""
63
+ elif value == MacroType.FILE_DIR:
64
+ value = self.file_dir
65
+ elif isinstance(value, Path):
66
+ if value.is_absolute():
67
+ parts = []
68
+ value = str(value)
69
+ parts.append(value)
70
+ parts.append(var_suffix[1])
71
+
72
+ return Path("".join(str(part) for part in parts))
73
+
74
+
75
+ class Presets:
76
+ def __init__(self):
77
+ self.seen = cast(set[Path], set())
78
+ self.result = cast(dict[str, Preset], {})
79
+
80
+ def visit_file(self, filename: Path):
81
+ dirname = self.__parent_from_file(filename)
82
+ if dirname is None:
83
+ return self.result
84
+
85
+ includes, presets = Presets.__load_file(filename)
86
+ self.__visit_includes(dirname, includes)
87
+ for preset in presets:
88
+ self.__visit_preset(dirname, preset)
89
+ for preset in self.result.values():
90
+ self.__merge_preset(preset)
91
+
92
+ return self.result
93
+
94
+ def __parent_from_file(self, filename: Path):
95
+ key = filename.resolve()
96
+ if key in self.seen:
97
+ return None
98
+ self.seen.add(key)
99
+ return key.parent
100
+
101
+ def __visit_includes(self, dirname: Path, includes: list[str]):
102
+ for include in includes:
103
+ self.visit_file(dirname / include)
104
+
105
+ def __visit_preset(self, dirname: Path, preset: dict):
106
+ name = cast(str | None, preset.get("name"))
107
+ if name is None:
108
+ return
109
+ binary_dir = cast(str | None, preset.get("binaryDir"))
110
+ generator = cast(str | None, preset.get("generator"))
111
+ inherits = cast(list[str], preset.get("inherits", []))
112
+ self.result[name] = Preset(
113
+ name=name,
114
+ binary_dir=binary_dir,
115
+ generator=generator,
116
+ inherits=inherits,
117
+ file_dir=dirname,
118
+ )
119
+
120
+ def __merge_preset(self, preset: Preset):
121
+ inherits: list[str] = []
122
+ inherits.extend(preset.inherits)
123
+ while inherits:
124
+ parent = inherits[0]
125
+ inherits = inherits[1:]
126
+ if parent not in self.result:
127
+ continue
128
+ parent_preset = self.result[parent]
129
+ inherits.extend(parent_preset.inherits)
130
+
131
+ if parent_preset.binary_dir and not preset.binary_dir:
132
+ preset.binary_dir = parent_preset.binary_dir
133
+ if parent_preset.generator and not preset.generator:
134
+ preset.generator = parent_preset.generator
135
+
136
+ @staticmethod
137
+ def __load_file(filename: Path):
138
+ with open(filename, encoding="UTF-8") as f:
139
+ data = json.load(f)
140
+ includes = cast(list[str], data.get("include", []))
141
+ presets = cast(list[dict], data.get("configurePresets", []))
142
+
143
+ return (includes, presets)
144
+
145
+
146
+ def get_binary_dirs():
147
+ presets = Presets().visit_file(Path("CMakePresets.json"))
148
+
149
+ cwd = str(Path.cwd().as_posix()) + "/"
150
+ result: dict[str, str] = {}
151
+ for preset in presets.values():
152
+ dirname = preset.expand()
153
+ if dirname is None:
154
+ continue
155
+ rel = str(dirname.as_posix())
156
+ if rel[: len(cwd)] == cwd:
157
+ rel = rel[len(cwd) :]
158
+ result[preset.name] = rel
159
+
160
+ return result
@@ -12,6 +12,7 @@ from typing import Dict, List, cast
12
12
  from proj_flow import api
13
13
  from proj_flow.api import env, step
14
14
  from proj_flow.base.__cmake_version__ import CMAKE_VERSION
15
+ from proj_flow.ext.cplusplus.cmake.presets import get_binary_dirs
15
16
 
16
17
 
17
18
  class CMakeBase(api.step.Step):
@@ -39,7 +40,7 @@ class CMakeBase(api.step.Step):
39
40
  self._runs_after = runs_after
40
41
  self._runs_before = runs_before
41
42
 
42
- def is_active(self, config: api.env.Config, rt: api.env.Runtime) -> int:
43
+ def is_active(self, config: api.env.Config, rt: api.env.Runtime) -> bool:
43
44
  return os.path.isfile("CMakeLists.txt") and os.path.isfile("CMakePresets.json")
44
45
 
45
46
  def platform_dependencies(self):
@@ -55,12 +56,16 @@ class CMakeConfig(CMakeBase):
55
56
 
56
57
  def __init__(self):
57
58
  super().__init__(name="CMake")
59
+ self.binary_dirs = get_binary_dirs()
58
60
 
59
- def is_active(self, config: env.Config, rt: env.Runtime) -> int:
61
+ def is_active(self, config: env.Config, rt: env.Runtime) -> bool:
60
62
  return os.path.isfile("CMakeLists.txt") and os.path.isfile("CMakePresets.json")
61
63
 
62
64
  def directories_to_remove(self, config: env.Config) -> List[str]:
63
- return [f"build/{config.build_type}"]
65
+ binary_dir = self.binary_dirs.get(f"{config.preset}-{config.build_generator}")
66
+ if not binary_dir:
67
+ return []
68
+ return [binary_dir]
64
69
 
65
70
  def run(self, config: env.Config, rt: env.Runtime) -> int:
66
71
  cmake_vars = cast(Dict[str, str], rt._cfg.get("cmake", {}).get("vars", {}))
@@ -130,7 +135,7 @@ class PackStep(CMakeBase):
130
135
  def platform_dependencies(self):
131
136
  return self.dep_with_tool("cpack")
132
137
 
133
- def is_active(self, config: env.Config, rt: env.Runtime) -> int:
138
+ def is_active(self, config: env.Config, rt: env.Runtime) -> bool:
134
139
  return (
135
140
  super().is_active(config, rt)
136
141
  and len(config.items.get("cpack_generator", [])) > 0
@@ -25,6 +25,7 @@ def _version(ver: str) -> Tuple[int, int, int, str]:
25
25
  raise SystemExit(1)
26
26
  return (int(m.group(1)), int(m.group(2)), int(m.group(3)), ver)
27
27
 
28
+
28
29
  def _prev_version(new_version: str, tags: List[str]):
29
30
  current = _version(new_version)
30
31
  versions = [_version(tag) for tag in reversed(tags)]
@@ -40,6 +41,7 @@ def _prev_version(new_version: str, tags: List[str]):
40
41
 
41
42
  return None if index > len(versions) else versions[index][-1]
42
43
 
44
+
43
45
  @release.version_updaters.add
44
46
  class VersionUpdater(release.VersionUpdater):
45
47
  def on_version_change_tags(self, new_version: str, tags: List[str]):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: proj-flow
3
- Version: 0.16.0
3
+ Version: 0.17.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/
@@ -1,4 +1,4 @@
1
- proj_flow/__init__.py,sha256=hY1PrbNzkQICKLsEPUvODy7alsHfFSz0LoiO7CDwm84,277
1
+ proj_flow/__init__.py,sha256=8ysEUwuBhRMglNTkf4IxkACkbKNu6vsWbx4CnMt7JT4,277
2
2
  proj_flow/__main__.py,sha256=HUar_qQ9Ndmchmryegtzu__5wukwCLrFN_SGRl5Ol_M,233
3
3
  proj_flow/dependency.py,sha256=CpcnR6El8AO9hlLc9lQtYQADYlkx3GMHlkLYbEAtdMI,4639
4
4
  proj_flow/api/__init__.py,sha256=gV2f6kll_5JXtvkGASvnx7CbOWr34PHOdck-4ce-qEk,378
@@ -27,10 +27,11 @@ proj_flow/ext/markdown_changelog.py,sha256=fRGL09jojnv2B-8vAX2prvgNp8e7uyq5NxboS
27
27
  proj_flow/ext/re_structured_changelog.py,sha256=UF23W9eu_YgPO42MiaoDbEKu8In_48mQg6rH9--mI30,459
28
28
  proj_flow/ext/store.py,sha256=zc9yh9M042V5OSLUZjWe9KazhdZ35h1JJsWvKughM0Y,3385
29
29
  proj_flow/ext/cplusplus/__init__.py,sha256=dAmLMyGVQq586jJM_jiAuo5Ecw9U8agpvSRbzzPgh3g,245
30
- proj_flow/ext/cplusplus/cmake/__init__.py,sha256=XQ8l1WsEZAgcNX_A0KgY535VhF6s7glS0TW2L0EmdVc,346
30
+ proj_flow/ext/cplusplus/cmake/__init__.py,sha256=uQPclC2Bs5qVR_VnoYYPGUbzkzR2gU4RLThcTumYXUE,366
31
31
  proj_flow/ext/cplusplus/cmake/parser.py,sha256=ZqQRZqS_VU5VtC8uwax-dknh7sfuLEvtazG8ChSqHDQ,3814
32
+ proj_flow/ext/cplusplus/cmake/presets.py,sha256=iYtSlkIoY3fEa6GL95zJugJbmleV5NPPB9UhME8RbSA,4922
32
33
  proj_flow/ext/cplusplus/cmake/project.py,sha256=Cp-5HwEsrQW4RjDThjMBQmaVJiRHo9QvYbw7IvjHKNQ,929
33
- proj_flow/ext/cplusplus/cmake/steps.py,sha256=IBxATzcJfDI5XibaKgXDnKDKPIaJM1fAJKfjOBpufzo,4119
34
+ proj_flow/ext/cplusplus/cmake/steps.py,sha256=PQiDByCwz_AApxGRrEx_LnjCIgMh06nU8Pb2_z321Dk,4351
34
35
  proj_flow/ext/cplusplus/conan/__init__.py,sha256=Fv839SWsKPWMZs9ox9T-bofZ4xDJXOI5UfWKQkm0Vtg,1924
35
36
  proj_flow/ext/cplusplus/conan/_conan.py,sha256=9xnji-f8uN7huXLqavVBUDC33CgnjBIyZX6wVcGm2RA,3352
36
37
  proj_flow/ext/github/__init__.py,sha256=Mgx19YS6SYBXYB66_pOgIgwuB2WKRxqp5UGutq0B9Xk,282
@@ -69,7 +70,7 @@ proj_flow/minimal/init.py,sha256=Rx3wu2xDZQpaiU0vmNmsj1eS48DopvL023lB7eTf85A,431
69
70
  proj_flow/minimal/list.py,sha256=RlOqammE8olNKXsnbv1enF5uriu0MZ2wFbht37Z2ETw,4810
70
71
  proj_flow/minimal/run.py,sha256=4qvGLqz2ayCZDvVBrq4tG094fjfcmDPon-xcGPQkM_U,4665
71
72
  proj_flow/minimal/system.py,sha256=9FliH5TD103JYSAe2O5EU7hkOHDgVzTqu0Exxk-WrXE,1579
72
- proj_flow/minimal/ext/bug_report.py,sha256=aKTxjHBF5lZIU9Hmsq1Mc3Ou19GkSh_Q137I81fLsZY,2309
73
+ proj_flow/minimal/ext/bug_report.py,sha256=dKy2FzVanoF3LISN5fsoaj-0TatGvVnahKuhy9HE4os,2311
73
74
  proj_flow/project/__init__.py,sha256=AROrwhbuMR5rJE-HC769eL4IXrMLQYpQb3HgpkOAYqg,293
74
75
  proj_flow/project/api.py,sha256=fu7gW0JuC7brwdsR4TadXYRqeMdt-lBUCEV4Sf0kMfY,1999
75
76
  proj_flow/project/data.py,sha256=TluhBDoJEYL4dnyTpInmhQ49Uvf8mkWmpU-YMLQPNhE,317
@@ -133,8 +134,8 @@ proj_flow/template/licenses/MIT.mustache,sha256=NncPoQaNsuy-WmRmboik3fyhJJ8m5pc2
133
134
  proj_flow/template/licenses/Unlicense.mustache,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
134
135
  proj_flow/template/licenses/WTFPL.mustache,sha256=lvF4V_PrKKfZPa2TC8CZo8tlqaKvs3Bpv9G6XsWWQ4k,483
135
136
  proj_flow/template/licenses/Zlib.mustache,sha256=uIj-mhSjes2HJ3rRapyy2ALflKRz4xQgS4mVM9827C0,868
136
- proj_flow-0.16.0.dist-info/METADATA,sha256=o1kssBOMWGcv1Zh7K4iFpVvad3O_3PvZyiWlQ3A7Vu8,2980
137
- proj_flow-0.16.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
138
- proj_flow-0.16.0.dist-info/entry_points.txt,sha256=d_OmGKZzpY7FCWz0sZ4wnBAPZC75oMEzTgJZWtpDELo,49
139
- proj_flow-0.16.0.dist-info/licenses/LICENSE,sha256=vpOQJ5QlrTedF3coEWvA4wJzVJH304f66ZitR7Od4iU,1068
140
- proj_flow-0.16.0.dist-info/RECORD,,
137
+ proj_flow-0.17.0.dist-info/METADATA,sha256=9WNbInHfvYfv8k7LLWI51yyMfds-2Cvn4UfURnmoWcI,2980
138
+ proj_flow-0.17.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
139
+ proj_flow-0.17.0.dist-info/entry_points.txt,sha256=d_OmGKZzpY7FCWz0sZ4wnBAPZC75oMEzTgJZWtpDELo,49
140
+ proj_flow-0.17.0.dist-info/licenses/LICENSE,sha256=vpOQJ5QlrTedF3coEWvA4wJzVJH304f66ZitR7Od4iU,1068
141
+ proj_flow-0.17.0.dist-info/RECORD,,