proj-flow 0.9.2__py3-none-any.whl → 0.9.4__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.
Files changed (53) hide show
  1. proj_flow/__init__.py +1 -1
  2. proj_flow/api/env.py +7 -2
  3. proj_flow/api/makefile.py +1 -1
  4. proj_flow/base/plugins.py +1 -36
  5. proj_flow/base/registry.py +2 -1
  6. proj_flow/cli/__init__.py +1 -3
  7. proj_flow/cli/argument.py +1 -1
  8. proj_flow/ext/cplusplus/__init__.py +10 -0
  9. proj_flow/ext/cplusplus/cmake/__init__.py +12 -0
  10. proj_flow/{plugins → ext/cplusplus}/cmake/context.py +2 -2
  11. proj_flow/{plugins → ext/cplusplus}/cmake/parser.py +6 -28
  12. proj_flow/ext/cplusplus/cmake/steps.py +142 -0
  13. proj_flow/ext/cplusplus/cmake/version.py +35 -0
  14. proj_flow/{plugins → ext/cplusplus}/conan/__init__.py +2 -1
  15. proj_flow/{plugins → ext/cplusplus}/conan/_conan.py +7 -2
  16. proj_flow/ext/github/__init__.py +2 -2
  17. proj_flow/ext/github/cli.py +11 -2
  18. proj_flow/{plugins/github.py → ext/github/switches.py} +1 -1
  19. proj_flow/ext/{markdown_changelist.py → markdown_changelog.py} +2 -1
  20. proj_flow/ext/python/rtdocs.py +1 -1
  21. proj_flow/ext/python/version.py +1 -2
  22. proj_flow/ext/{re_structured_changelist.py → re_structured_changelog.py} +3 -1
  23. proj_flow/{plugins → ext}/sign/__init__.py +64 -44
  24. proj_flow/ext/sign/api.py +83 -0
  25. proj_flow/ext/sign/win32.py +152 -0
  26. proj_flow/{plugins/store/store_packages.py → ext/store.py} +51 -9
  27. proj_flow/log/release.py +12 -0
  28. proj_flow/log/rich_text/markdown.py +1 -1
  29. proj_flow/log/rich_text/re_structured_text.py +1 -1
  30. proj_flow/minimal/__init__.py +2 -2
  31. proj_flow/{plugins → minimal}/base.py +2 -2
  32. proj_flow/{plugins/commands → minimal}/init.py +1 -1
  33. {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/METADATA +2 -1
  34. {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/RECORD +38 -47
  35. proj_flow/plugins/__init__.py +0 -8
  36. proj_flow/plugins/cmake/__init__.py +0 -11
  37. proj_flow/plugins/cmake/build.py +0 -29
  38. proj_flow/plugins/cmake/config.py +0 -59
  39. proj_flow/plugins/cmake/pack.py +0 -37
  40. proj_flow/plugins/cmake/test.py +0 -29
  41. proj_flow/plugins/commands/__init__.py +0 -12
  42. proj_flow/plugins/commands/ci/__init__.py +0 -17
  43. proj_flow/plugins/commands/ci/changelog.py +0 -47
  44. proj_flow/plugins/commands/ci/matrix.py +0 -46
  45. proj_flow/plugins/commands/ci/release.py +0 -116
  46. proj_flow/plugins/sign/win32.py +0 -191
  47. proj_flow/plugins/store/__init__.py +0 -11
  48. proj_flow/plugins/store/store_both.py +0 -22
  49. proj_flow/plugins/store/store_tests.py +0 -21
  50. /proj_flow/{plugins → ext/cplusplus}/cmake/__version__.py +0 -0
  51. {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/WHEEL +0 -0
  52. {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/entry_points.txt +0 -0
  53. {proj_flow-0.9.2.dist-info → proj_flow-0.9.4.dist-info}/licenses/LICENSE +0 -0
proj_flow/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # Copyright (c) 2025 Marcin Zdun
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
- __version__ = "0.9.2"
4
+ __version__ = "0.9.4"
proj_flow/api/env.py CHANGED
@@ -24,7 +24,6 @@ from enum import Enum
24
24
  from typing import Any, Callable, Dict, List, Optional, Union, cast
25
25
 
26
26
  from proj_flow.base import plugins, uname
27
- from proj_flow.base.plugins import load_module_plugins
28
27
 
29
28
  platform = uname.uname()[0]
30
29
 
@@ -152,7 +151,13 @@ class FlowConfig:
152
151
  sys.path.insert(0, local_extensions)
153
152
 
154
153
  for extension in extensions:
155
- importlib.import_module(extension)
154
+ try:
155
+ importlib.import_module(extension)
156
+ except ModuleNotFoundError:
157
+ print(
158
+ f"-- error: module `{extension}` was no found, ignoring",
159
+ file=sys.stderr,
160
+ )
156
161
 
157
162
  @property
158
163
  def entry(self) -> Dict[str, dict]:
proj_flow/api/makefile.py CHANGED
@@ -2,7 +2,7 @@
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
4
  """
5
- The **proj_flow.api.makefiles** exposes simple makefiles APIs, so extensions can
5
+ The **proj_flow.api.makefile** exposes simple makefile APIs, so extensions can
6
6
  easily provide run steps with multiple scripts being called.
7
7
  """
8
8
 
proj_flow/base/plugins.py CHANGED
@@ -5,11 +5,9 @@
5
5
  The **proj_flow.base.plugins** provide the plugin enumeration helpers.
6
6
  """
7
7
 
8
- import importlib
9
8
  import json
10
9
  import os
11
- from types import ModuleType
12
- from typing import Optional, cast
10
+ from typing import cast
13
11
 
14
12
  import yaml
15
13
 
@@ -48,36 +46,3 @@ def load_data(filename: str):
48
46
  pass
49
47
 
50
48
  return {}
51
-
52
-
53
- def _load_plugins(directory: str, package: Optional[str], can_fail=False):
54
- for _, dirnames, filenames in os.walk(directory):
55
- for dirname in dirnames:
56
- if dirname == "__pycache__":
57
- continue
58
-
59
- try:
60
- importlib.import_module(f".{dirname}", package=package)
61
- except ModuleNotFoundError as err:
62
- if not can_fail:
63
- raise err
64
- for filename in filenames:
65
- if filename == "__init__.py":
66
- continue
67
-
68
- try:
69
- importlib.import_module(
70
- f".{os.path.splitext(filename)[0]}", package=package
71
- )
72
- except ModuleNotFoundError as err:
73
- if not can_fail:
74
- raise err
75
- dirnames[:] = []
76
-
77
-
78
- def load_module_plugins(mod: ModuleType, can_fail=False):
79
- spec = mod.__spec__
80
- if not spec:
81
- return
82
- for location in spec.submodule_search_locations: # type: ignore
83
- _load_plugins(location, spec.name, can_fail)
@@ -2,7 +2,8 @@
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
4
  """
5
- The **proj_flow.base.registry**
5
+ The **proj_flow.base.registry** allows building extension points, with ability
6
+ to register the plugins with a decorator.
6
7
  """
7
8
 
8
9
  import typing
proj_flow/cli/__init__.py CHANGED
@@ -10,10 +10,8 @@ The **proj_flow.cli** provides command-line entry for the *Project Flow*.
10
10
  import argparse
11
11
  import os
12
12
  import sys
13
- from pprint import pprint
14
- from typing import Dict, Optional, Tuple
15
13
 
16
- from proj_flow.api import arg, env
14
+ from proj_flow.api import env
17
15
  from proj_flow.cli import argument, finder
18
16
  from proj_flow.flow import steps
19
17
 
proj_flow/cli/argument.py CHANGED
@@ -2,7 +2,7 @@
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
4
  """
5
- The **proj_flow.cli.arguments** provides command-line builders and runners,
5
+ The **proj_flow.cli.argument** provides command-line builders and runners,
6
6
  supporting the functions decorated with :func:`@arg.command()
7
7
  <proj_flow.api.arg.command>`.
8
8
  """
@@ -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.ext.cplusplus** defines steps and commands for C++ projects.
6
+ """
7
+
8
+ from . import cmake, conan
9
+
10
+ __all__ = ["cmake", "conan"]
@@ -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.cmake** provides ``"CMake"``, ``"Build"``,
6
+ ``"Pack"`` and ``"Test"`` steps, as well as CMake-specific initialization
7
+ context.
8
+ """
9
+
10
+ from . import context, parser, steps, version
11
+
12
+ __all__ = ["context", "parser", "steps", "version"]
@@ -2,8 +2,8 @@
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
4
  """
5
- The **proj_flow.plugins.cmake.context** provides CMake-specific initialization
6
- context.
5
+ The **proj_flow.ext.cplusplus.cmake.context** provides CMake-specific
6
+ initialization context.
7
7
  """
8
8
 
9
9
  import re
@@ -2,13 +2,15 @@
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
4
  """
5
- The **proj_flow.plugins.cmake.parser** contains simple CMake parser.
5
+ The **proj_flow.ext.cplusplus.cmake.parser** contains simple CMake parser.
6
6
  """
7
7
 
8
8
  import os
9
9
  import re
10
10
  from typing import Iterator, List, NamedTuple, Optional
11
11
 
12
+ from proj_flow.api.release import NO_ARG, Arg
13
+
12
14
  TOKENS = [
13
15
  ("COMMENT", r"#.*"),
14
16
  ("STR", r'"[^"]*"'),
@@ -25,39 +27,18 @@ class Token(NamedTuple):
25
27
  offset: int
26
28
 
27
29
 
28
- class Arg(NamedTuple):
29
- value: str
30
- offset: int
31
-
32
-
33
30
  class Command(NamedTuple):
34
31
  name: str
35
32
  args: List[Arg]
36
33
  offset: int
37
34
 
38
35
 
39
- class Project(NamedTuple):
36
+ class CMakeProject(NamedTuple):
40
37
  name: Arg
41
38
  version: Arg
42
39
  stability: Arg
43
40
  description: Arg
44
41
 
45
- def set_version(self, directory: str, next_version: str):
46
- _patch(directory, self.version, next_version)
47
- return ["proj_flow/__init__.py"]
48
-
49
- @property
50
- def ver(self):
51
- return f"{self.version.value}{self.stability.value}"
52
-
53
- @property
54
- def pkg(self):
55
- return f"{self.name.value}-{self.ver}"
56
-
57
- @property
58
- def tag(self):
59
- return f"v{self.ver}"
60
-
61
42
 
62
43
  def _token_stream(text: str) -> Iterator[Token]:
63
44
  tok_regex = "|".join("(?P<%s>%s)" % pair for pair in TOKENS)
@@ -121,10 +102,7 @@ def _patch(directory: str, arg: Arg, value: str):
121
102
  input.write(patched)
122
103
 
123
104
 
124
- NO_ARG = Arg("", -1)
125
-
126
-
127
- def get_project(dirname: str) -> Optional[Project]:
105
+ def get_project(dirname: str) -> Optional[CMakeProject]:
128
106
  try:
129
107
  commands = _cmake(os.path.join(dirname, "CMakeLists.txt"))
130
108
  except FileNotFoundError:
@@ -158,7 +136,7 @@ def get_project(dirname: str) -> Optional[Project]:
158
136
  if version_stability is None:
159
137
  version_stability = NO_ARG
160
138
 
161
- return Project(
139
+ return CMakeProject(
162
140
  name=project_name,
163
141
  version=version,
164
142
  stability=version_stability,
@@ -0,0 +1,142 @@
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.steps** defines steps for configuring,
6
+ building and archiving.
7
+ """
8
+
9
+ import os
10
+ from typing import Dict, List, cast
11
+
12
+ from proj_flow import api
13
+ from proj_flow.api import env, step
14
+
15
+ from .__version__ import CMAKE_VERSION
16
+
17
+
18
+ class CMakeBase(api.step.Step):
19
+ _name: str
20
+ _runs_after: List[str] = []
21
+ _runs_before: List[str] = []
22
+
23
+ @property
24
+ def name(self):
25
+ return self._name
26
+
27
+ @property
28
+ def runs_after(self):
29
+ return self._runs_after
30
+
31
+ @property
32
+ def runs_before(self):
33
+ return self._runs_before
34
+
35
+ def __init__(
36
+ self, name: str, runs_after: List[str] = [], runs_before: List[str] = []
37
+ ):
38
+ super().__init__()
39
+ self._name = name
40
+ self._runs_after = runs_after
41
+ self._runs_before = runs_before
42
+
43
+ def is_active(self, config: api.env.Config, rt: api.env.Runtime) -> int:
44
+ return os.path.isfile("CMakeLists.txt") and os.path.isfile("CMakePresets.json")
45
+
46
+ def platform_dependencies(self):
47
+ return [f"cmake>={CMAKE_VERSION}"]
48
+
49
+ def dep_with_tool(self, tool: str):
50
+ return [f"cmake>={CMAKE_VERSION}", f"{tool}>={CMAKE_VERSION}"]
51
+
52
+
53
+ @step.register
54
+ class CMakeConfig(CMakeBase):
55
+ """Configures the project using ``preset`` config."""
56
+
57
+ def __init__(self):
58
+ super().__init__(name="CMake")
59
+
60
+ def is_active(self, config: env.Config, rt: env.Runtime) -> int:
61
+ return os.path.isfile("CMakeLists.txt") and os.path.isfile("CMakePresets.json")
62
+
63
+ def directories_to_remove(self, config: env.Config) -> List[str]:
64
+ return [f"build/{config.build_type}"]
65
+
66
+ def run(self, config: env.Config, rt: env.Runtime) -> int:
67
+ cmake_vars = cast(Dict[str, str], rt._cfg.get("cmake", {}).get("vars", {}))
68
+ defines: List[str] = []
69
+ for var in cmake_vars:
70
+ value = cmake_vars[var]
71
+
72
+ is_flag = value.startswith("?")
73
+ if is_flag:
74
+ value = value[1:]
75
+
76
+ if value.startswith("config:"):
77
+ value = value[len("config:")]
78
+ value = config.get_path(value)
79
+ elif value.startswith("runtime:"):
80
+ value = value[len("runtime:")]
81
+ value = getattr(rt, value, None)
82
+
83
+ if is_flag:
84
+ value = "ON" if value else "OFF"
85
+
86
+ defines.append(f"-D{var}={value}")
87
+
88
+ return rt.cmd(
89
+ "cmake",
90
+ "--preset",
91
+ f"{config.preset}-{config.build_generator}",
92
+ *defines,
93
+ )
94
+
95
+
96
+ @step.register()
97
+ class CMakeBuild(CMakeBase):
98
+ """Builds the project using ``preset`` config."""
99
+
100
+ def __init__(self):
101
+ super().__init__(name="Build", runs_after=["CMake"])
102
+
103
+ def run(self, config: env.Config, rt: env.Runtime) -> int:
104
+ return rt.cmd("cmake", "--build", "--preset", config.preset, "--parallel")
105
+
106
+
107
+ @step.register
108
+ class CMakeTest(CMakeBase):
109
+ """Runs tests in the project using ``preset`` config."""
110
+
111
+ def __init__(self):
112
+ super().__init__(name="Test", runs_after=["Build"])
113
+
114
+ def platform_dependencies(self):
115
+ return self.dep_with_tool("ctest")
116
+
117
+ def run(self, config: env.Config, rt: env.Runtime) -> int:
118
+ return rt.cmd("ctest", "--preset", config.preset)
119
+
120
+
121
+ @step.register
122
+ class PackStep(CMakeBase):
123
+ """
124
+ Packs archives and installers from ``cpack_generator`` config, using
125
+ ``preset`` config.
126
+ """
127
+
128
+ def __init__(self):
129
+ super().__init__(name="Pack", runs_after=["Build"])
130
+
131
+ def platform_dependencies(self):
132
+ return self.dep_with_tool("cpack")
133
+
134
+ def is_active(self, config: env.Config, rt: env.Runtime) -> int:
135
+ return (
136
+ super().is_active(config, rt)
137
+ and len(config.items.get("cpack_generator", [])) > 0
138
+ )
139
+
140
+ def run(self, config: env.Config, rt: env.Runtime) -> int:
141
+ generators = ";".join(config.items.get("cpack_generator", []))
142
+ return rt.cmd("cpack", "--preset", config.preset, "-G", generators)
@@ -0,0 +1,35 @@
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.version** provides project suite plugin.
6
+ """
7
+
8
+ import os
9
+ import re
10
+ from typing import NamedTuple, Optional
11
+
12
+ import toml
13
+
14
+ from proj_flow.api import env, release
15
+ from proj_flow.ext.cplusplus.cmake.parser import get_project
16
+
17
+
18
+ class QuickProjectInfo(NamedTuple):
19
+ name: Optional[str] = None
20
+ path: Optional[str] = None
21
+ pattern: Optional[str] = None
22
+
23
+
24
+ @release.project_suites.add
25
+ class ProjectSuite(release.ProjectSuite):
26
+ def get_project(self, rt: env.Runtime) -> Optional[release.Project]:
27
+ project = get_project(rt.root)
28
+ if project is None:
29
+ return None
30
+ return release.Project(
31
+ project.name.value, release.Version(project.version, project.stability)
32
+ )
33
+
34
+ def get_version_file_path(self, rt: env.Runtime) -> Optional[str]:
35
+ return "CMakeLists.txt"
@@ -2,7 +2,7 @@
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
4
  """
5
- The **proj_flow.plugins.conan** provides the ``"Conan"`` step.
5
+ The **proj_flow.ext.cplusplus.conan** provides the ``"Conan"`` step.
6
6
  """
7
7
 
8
8
  import os
@@ -23,6 +23,7 @@ class ConanConfig:
23
23
  """Configures the project for ``preset`` config using ``build_type`` config."""
24
24
 
25
25
  name = "Conan"
26
+ runs_before = ["CMake"]
26
27
 
27
28
  def platform_dependencies(self):
28
29
  return ["conan"]
@@ -2,10 +2,12 @@
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
4
  """
5
- The **proj_flow.plugins.conan._conan** adds support for both Conan v1 and v2.
5
+ The **proj_flow.ext.cplusplus.conan._conan** adds support for both Conan v1
6
+ and v2.
6
7
  """
7
8
 
8
9
  import shutil
10
+ import subprocess
9
11
  from abc import ABC, abstractmethod
10
12
  from typing import Callable, List, cast
11
13
 
@@ -119,7 +121,10 @@ def _conan_version():
119
121
  if found is None:
120
122
  return 1
121
123
 
122
- proc = cmd.run(found, "--version", capture_output=True)
124
+ proc = cast(
125
+ subprocess.CompletedProcess[str],
126
+ cmd.run(found, "--version", capture_output=True),
127
+ )
123
128
  if proc.returncode != 0:
124
129
  return 1
125
130
  m = VER_REGEX.search(proc.stdout)
@@ -6,6 +6,6 @@ The **proj_flow.ext.github** provides GitHub support through CLI and GitHub
6
6
  hosting plugin.
7
7
  """
8
8
 
9
- from . import cli, hosting
9
+ from . import cli, hosting, switches
10
10
 
11
- __all__ = ["cli", "hosting"]
11
+ __all__ = ["cli", "hosting", "switches"]
@@ -107,9 +107,10 @@ def release(
107
107
  forced_level = commit.FORCED_LEVEL.get(force) if force else None
108
108
  git = commit.Git(rt)
109
109
  gh_links = hosting.github.GitHub.from_repo(git) or commit.NoHosting()
110
+ released = False
110
111
 
111
112
  try:
112
- log.release.add_release(
113
+ next_tag = log.release.add_release(
113
114
  rt=rt,
114
115
  forced_level=forced_level,
115
116
  take_all=all,
@@ -118,8 +119,16 @@ def release(
118
119
  git=git,
119
120
  hosting=gh_links,
120
121
  )
122
+ released = not not next_tag
121
123
  except log.release.VersionNotAdvancing as err:
122
124
  rt.message(err.message, level=env.Msg.STATUS)
123
- return 0
125
+ return
124
126
  except log.error.ReleaseError as err:
125
127
  rt.fatal(err.message)
128
+ finally:
129
+ if "GITHUB_ACTIONS" in os.environ:
130
+ GITHUB_OUTPUT = os.environ.get("GITHUB_OUTPUT")
131
+ if GITHUB_OUTPUT is not None:
132
+ with open(GITHUB_OUTPUT, "a", encoding="UTF-8") as github_output:
133
+ print(f"tag={next_tag}", file=github_output)
134
+ print(f"released={json.dumps(released)}", file=github_output)
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2025 Marcin Zdun
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
  """
4
- The **proj_flow.plugins.github** provides GitHub-related switches for new
4
+ The **proj_flow.ext.github.switches** provides GitHub-related switches for new
5
5
  projects.
6
6
  """
7
7
 
@@ -2,7 +2,8 @@
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
4
  """
5
- The **proj_flow.ext.markdown_changelist** .
5
+ The **proj_flow.ext.markdown_changelog** registers a
6
+ :class:`api.ChangelogGenerator` plugin implemented for markdown changelogs.
6
7
  """
7
8
 
8
9
  from proj_flow.log.rich_text.api import changelog_generators
@@ -2,7 +2,7 @@
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
4
  """
5
- The **proj_flow.ext.python.steps.rtdocs** defines RTDocs step, which uses
5
+ The **proj_flow.ext.python.rtdocs** defines RTDocs step (`"RTD"`), which uses
6
6
  .readthedocs.yaml to build the HTML documentation.
7
7
  """
8
8
 
@@ -2,8 +2,7 @@
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
4
  """
5
- The **proj_flow.ext.python.steps** defines steps for building, installing and
6
- documenting.
5
+ The **proj_flow.ext.python.version** provides project suite plugin.
7
6
  """
8
7
 
9
8
  import os
@@ -2,7 +2,9 @@
2
2
  # This code is licensed under MIT license (see LICENSE for details)
3
3
 
4
4
  """
5
- The **proj_flow.ext.re_structured_text** .
5
+ The **proj_flow.ext.re_structured_changelog** registers a
6
+ :class:`api.ChangelogGenerator` plugin implemented for reStructuredText
7
+ changelogs.
6
8
  """
7
9
 
8
10
  from proj_flow.log.rich_text.api import changelog_generators