proj-flow 0.14.1__py3-none-any.whl → 0.15.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.
Files changed (29) hide show
  1. proj_flow/__init__.py +1 -1
  2. proj_flow/api/arg.py +23 -3
  3. proj_flow/base/__init__.py +27 -0
  4. proj_flow/cli/argument.py +21 -4
  5. proj_flow/ext/github/cli.py +4 -2
  6. proj_flow/ext/github/switches.py +15 -2
  7. proj_flow/flow/layer.py +6 -5
  8. proj_flow/log/commit.py +1 -0
  9. proj_flow/minimal/init.py +48 -6
  10. proj_flow/project/api.py +2 -2
  11. proj_flow/project/cplusplus/cmake_context.py +3 -3
  12. proj_flow/project/cplusplus/conan_context.py +1 -1
  13. proj_flow/project/cplusplus/project.py +2 -1
  14. proj_flow/project/interact.py +90 -33
  15. proj_flow/template/layers/cmake/CMakeLists.txt.mustache +11 -11
  16. proj_flow/template/layers/cmake/src/main.cc.mustache +6 -6
  17. proj_flow/template/layers/cmake/tests/test.cc.mustache +4 -4
  18. proj_flow/template/layers/cmake.json +1 -1
  19. proj_flow/template/layers/conan.json +1 -1
  20. proj_flow/template/layers/github_actions/.github/workflows/build.yml.auto-release +285 -0
  21. proj_flow/template/layers/github_actions/.github/workflows/build.yml.basic +248 -0
  22. proj_flow/template/layers/github_actions.json +11 -1
  23. proj_flow/template/layers/github_social.json +1 -1
  24. {proj_flow-0.14.1.dist-info → proj_flow-0.15.1.dist-info}/METADATA +2 -2
  25. {proj_flow-0.14.1.dist-info → proj_flow-0.15.1.dist-info}/RECORD +28 -27
  26. proj_flow/template/layers/github_actions/.github/workflows/build.yml +0 -241
  27. {proj_flow-0.14.1.dist-info → proj_flow-0.15.1.dist-info}/WHEEL +0 -0
  28. {proj_flow-0.14.1.dist-info → proj_flow-0.15.1.dist-info}/entry_points.txt +0 -0
  29. {proj_flow-0.14.1.dist-info → proj_flow-0.15.1.dist-info}/licenses/LICENSE +0 -0
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.14.1"
9
+ __version__ = "0.15.1"
proj_flow/api/arg.py CHANGED
@@ -26,6 +26,15 @@ class _Completable(typing.Protocol):
26
26
  completer: _inspect.Function
27
27
 
28
28
 
29
+ @dataclass
30
+ class ExclusiveArgumentGroup:
31
+ opt: bool = False
32
+
33
+ def visit(self, parser: argparse._ActionsContainer) -> argparse._ActionsContainer:
34
+ self.opt
35
+ return parser.add_mutually_exclusive_group(required=not self.opt)
36
+
37
+
29
38
  @dataclass
30
39
  class Argument:
31
40
  help: LazyArgument[str] = ""
@@ -38,8 +47,9 @@ class Argument:
38
47
  default: LazyArgument[typing.Optional[typing.Any]] = None
39
48
  choices: LazyArgument[typing.Optional[typing.List[str]]] = None
40
49
  completer: typing.Optional[_inspect.Function] = None
50
+ group: typing.Optional[ExclusiveArgumentGroup] = None
41
51
 
42
- def visit(self, parser: argparse.ArgumentParser, name: str):
52
+ def visit(self, parser: argparse._ActionsContainer, name: str):
43
53
  kwargs = {}
44
54
 
45
55
  self_help = _eval(self.help)
@@ -82,9 +92,19 @@ class Argument:
82
92
 
83
93
 
84
94
  class FlagArgument(Argument):
85
- def __init__(self, help: str = "", names: typing.List[str] = []):
95
+ def __init__(
96
+ self,
97
+ help: str = "",
98
+ names: typing.List[str] = [],
99
+ group: typing.Optional[ExclusiveArgumentGroup] = None,
100
+ ):
86
101
  super().__init__(
87
- help=help, names=names, opt=True, action="store_true", default=False
102
+ help=help,
103
+ names=names,
104
+ group=group,
105
+ opt=True,
106
+ action="store_true",
107
+ default=False,
88
108
  )
89
109
 
90
110
 
@@ -6,6 +6,33 @@ The **proj_flow.base** contains low-level tools for higher-level parts of the
6
6
  library.
7
7
  """
8
8
 
9
+ import typing
10
+
9
11
  from . import cmd, matrix, plugins, registry, uname
10
12
 
11
13
  __all__ = ["cmd", "matrix", "plugins", "registry", "uname"]
14
+
15
+
16
+ def path_get(
17
+ structure: typing.Union[dict, list], dotted_path: str, default: typing.Any = None
18
+ ):
19
+ ctx: typing.Any = structure
20
+ for name in dotted_path.split("."):
21
+ if isinstance(ctx, dict):
22
+ try:
23
+ ctx = ctx[name]
24
+ continue
25
+ except KeyError:
26
+ return default
27
+
28
+ if isinstance(ctx, (list, tuple)):
29
+ try:
30
+ index = int(name)
31
+ except ValueError:
32
+ return default
33
+ except IndexError:
34
+ return default
35
+
36
+ return default
37
+
38
+ return ctx
proj_flow/cli/argument.py CHANGED
@@ -135,7 +135,11 @@ class AnnotatedArgument:
135
135
  name: str
136
136
  argument: arg.Argument
137
137
 
138
- def argparse_visit(self, parser: argparse.ArgumentParser):
138
+ @property
139
+ def group(self):
140
+ return self.argument.group
141
+
142
+ def argparse_visit(self, parser: argparse._ActionsContainer):
139
143
  return self.argument.visit(parser, self.name)
140
144
 
141
145
 
@@ -186,8 +190,21 @@ class Command:
186
190
  if has_config:
187
191
  _argparse_config_visit(parser)
188
192
 
189
- for arg in self.annotated:
190
- arg.argparse_visit(parser)
193
+ groups: typing.Set[int] = set()
194
+ for arg_index in range(len(self.annotated)):
195
+ annotated = self.annotated[arg_index]
196
+ group = annotated.group
197
+ if group is not None:
198
+ if id(group) in groups:
199
+ continue
200
+ groups.add(id(group))
201
+ group_container = group.visit(parser)
202
+ for sub_index in range(arg_index, len(self.annotated)):
203
+ sub = self.annotated[sub_index]
204
+ if sub.group is group:
205
+ sub.argparse_visit(group_container)
206
+ continue
207
+ annotated.argparse_visit(parser)
191
208
 
192
209
  if len(self.children):
193
210
  subparsers = parser.add_subparsers(
@@ -257,7 +274,7 @@ def _argparse_visit_all(
257
274
  dest="command", metavar="command", help="Known command name, see below"
258
275
  )
259
276
 
260
- subparsers.parent = parser # type: ignore
277
+ subparsers.parent = parser
261
278
 
262
279
  run: typing.Optional[Command] = None
263
280
  for entry in menu:
@@ -88,7 +88,9 @@ def release_cmd(
88
88
  ],
89
89
  changelog: typing.Annotated[
90
90
  bool,
91
- arg.FlagArgument(help="Even with --dry-run, write changes in project files, changelog, etc."),
91
+ arg.FlagArgument(
92
+ help="Even with --dry-run, write changes in project files, changelog, etc."
93
+ ),
92
94
  ],
93
95
  ):
94
96
  """
@@ -107,7 +109,7 @@ def release_cmd(
107
109
  released = False
108
110
 
109
111
  released = False
110
- next_tag = ''
112
+ next_tag = ""
111
113
  try:
112
114
  next_tag = log.release.add_release(
113
115
  rt=rt,
@@ -7,7 +7,20 @@ projects.
7
7
 
8
8
  from proj_flow.api import ctx
9
9
 
10
- ctx.register_common_switch("with_github_actions", "Use Github Actions", True)
10
+ ctx.register_common_switch("with.github.actions", "Use Github Actions", True)
11
11
  ctx.register_common_switch(
12
- "with_github_social", "Use Github ISSUE_TEMPLATE, CONTRIBUTING.md, etc.", True
12
+ "with.github.auto-release",
13
+ "Make a GitHub release automatically on each closed PR",
14
+ False,
15
+ )
16
+ ctx.register_common_switch(
17
+ "with.github.social", "Use Github ISSUE_TEMPLATE, CONTRIBUTING.md, etc.", True
18
+ )
19
+
20
+ ctx.register_common_init_setting(
21
+ ctx.Setting(
22
+ "with.github.no-auto-release",
23
+ value=lambda settings: not settings.get("with.github.auto-release"),
24
+ ),
25
+ is_hidden=True,
13
26
  )
proj_flow/flow/layer.py CHANGED
@@ -14,6 +14,7 @@ from typing import List, Optional, cast
14
14
  import chevron
15
15
 
16
16
  from proj_flow.api import ctx, env
17
+ from proj_flow.base import path_get
17
18
 
18
19
 
19
20
  @dataclass
@@ -42,8 +43,8 @@ class FileInfo:
42
43
  open_mstch = "{{"
43
44
  close_mstch = "}}"
44
45
  if self.when:
45
- return f"{open_mstch}#{self.when}{close_mstch}\n{self.dst}\n{open_mstch}/{self.when}{close_mstch}\n"
46
- return f"{self.dst}\n"
46
+ return f"{open_mstch}#{self.when}{close_mstch}\n{self.src}\n{open_mstch}/{self.when}{close_mstch}\n"
47
+ return f"{self.src}\n"
47
48
 
48
49
  def run(self, root: str, rt: env.Runtime, context: ctx.SettingsType):
49
50
  if not rt.silent:
@@ -81,7 +82,7 @@ class LayerInfo:
81
82
  def from_fs(cls, layer_dir: str, context: ctx.SettingsType):
82
83
  with open(f"{layer_dir}.json", encoding="UTF-8") as f:
83
84
  layer_info: dict = json.load(f)
84
- when = cast(Optional[bool], layer_info.get("when"))
85
+ when = cast(Optional[str], layer_info.get("when"))
85
86
  filelist = cast(dict, layer_info.get("filelist", {}))
86
87
 
87
88
  sources: List[str] = []
@@ -110,7 +111,7 @@ class LayerInfo:
110
111
  chevron.render(result.template(), context).split("\n"),
111
112
  )
112
113
  )
113
- result.files = list(filter(lambda file: file.dst in allowed_files, files))
114
+ result.files = list(filter(lambda file: file.src in allowed_files, files))
114
115
 
115
116
  return result
116
117
 
@@ -150,7 +151,7 @@ class LayerInfo:
150
151
 
151
152
 
152
153
  def copy_license(rt: env.Runtime, context: ctx.SettingsType):
153
- license = context.get("COPY", {}).get("LICENSE")
154
+ license = path_get(context, "COPY.LICENSE")
154
155
  if not license:
155
156
  return
156
157
 
proj_flow/log/commit.py CHANGED
@@ -144,6 +144,7 @@ def _get_commit(hash: str, short_hash: str, message: str) -> Optional[Commit]:
144
144
  breaking_change = [
145
145
  re.sub(r"\s+", " ", para.strip()) for para in body.split("\n\n")
146
146
  ]
147
+ is_breaking = True
147
148
 
148
149
  return Commit(
149
150
  type_scope[0].strip(),
proj_flow/minimal/init.py CHANGED
@@ -29,6 +29,9 @@ def _project_help():
29
29
  )
30
30
 
31
31
 
32
+ _output_group = arg.ExclusiveArgumentGroup(opt=True)
33
+
34
+
32
35
  @arg.command("init")
33
36
  def main(
34
37
  project: Annotated[
@@ -52,25 +55,58 @@ def main(
52
55
  ],
53
56
  non_interactive: Annotated[
54
57
  bool,
55
- arg.FlagArgument(help="Selects all the default answers", names=["-y", "--yes"]),
58
+ arg.FlagArgument(
59
+ help="Selects all the default answers.",
60
+ names=["-y", "--yes"],
61
+ group=_output_group,
62
+ ),
63
+ ],
64
+ store: Annotated[
65
+ Optional[str],
66
+ arg.Argument(
67
+ help="Do not create project, store the context in given file.",
68
+ meta="context-file",
69
+ group=_output_group,
70
+ ),
71
+ ],
72
+ answers: Annotated[
73
+ Optional[str],
74
+ arg.Argument(
75
+ help="Take all the answers from the answer sheet.",
76
+ meta="context-file",
77
+ group=_output_group,
78
+ ),
56
79
  ],
57
80
  save_context: Annotated[
58
81
  bool,
59
- arg.FlagArgument(help="Save the mustache context as JSON", names=["--ctx"]),
82
+ arg.FlagArgument(help="Save the mustache context as YAML.", names=["--ctx"]),
60
83
  ],
61
84
  rt: env.Runtime,
62
85
  ):
63
86
  """Initialize new project"""
64
87
 
88
+ setup = interact.ContextSetup(
89
+ dest_path=path,
90
+ interactive=not non_interactive and answers is None,
91
+ simple=store is not None,
92
+ load=answers,
93
+ )
94
+
95
+ context_file = store or ".context.yaml"
96
+ save_context = save_context or store is not None
97
+ if path is not None and os.path.basename(path) == "":
98
+ setup.dest_path = os.path.dirname(path)
99
+
65
100
  try:
66
101
  current_project = api.get_project_type(project)
67
102
  except api.ProjectNotFound:
68
103
  print(f"proj-flow init: error: project type `{project}` is not known")
69
104
  return 1
70
105
 
71
- if path is not None:
106
+ if path is not None and store is None:
72
107
  os.makedirs(path, exist_ok=True)
73
108
  os.chdir(path)
109
+ setup.dest_path = None
74
110
 
75
111
  errors = dependency.verify(dependency.gather(init.__steps))
76
112
  if len(errors) > 0:
@@ -79,7 +115,7 @@ def main(
79
115
  print(f"proj-flow: {error}", file=sys.stderr)
80
116
  return 1
81
117
 
82
- context = current_project.get_context(not non_interactive, rt)
118
+ context = current_project.get_context(setup, rt)
83
119
  if not non_interactive and not rt.silent:
84
120
  print()
85
121
 
@@ -89,8 +125,14 @@ def main(
89
125
  rt.message("[CONTEXT]", line)
90
126
 
91
127
  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)
128
+ with open(context_file, "w", encoding="UTF-8") as jsonf:
129
+ if os.path.splitext(context_file)[1] == ".json":
130
+ json.dump(context, jsonf, indent=4)
131
+ else:
132
+ yaml.dump(context, jsonf, indent=4)
133
+
134
+ if store is not None:
135
+ return 0
94
136
 
95
137
  flow.layer.copy_license(rt, context)
96
138
  if not rt.silent:
proj_flow/project/api.py CHANGED
@@ -30,8 +30,8 @@ class ProjectType(ABC):
30
30
  def register_init_setting(self, *settings: ctx.Setting, is_hidden=False):
31
31
  ctx.register_init_setting(*settings, is_hidden=is_hidden, project=self.id)
32
32
 
33
- def get_context(self, interactive: bool, rt: env.Runtime):
34
- return interact.get_context(interactive, self.id, rt)
33
+ def get_context(self, setup: interact.ContextSetup, rt: env.Runtime):
34
+ return interact.get_context(setup, self.id, rt)
35
35
 
36
36
  def append_extensions(self, context: dict):
37
37
  extensions = self.get_extension_list(context)
@@ -17,13 +17,13 @@ from proj_flow.project import data
17
17
  from proj_flow.project.cplusplus import project
18
18
 
19
19
  config_json_mustache = """
20
- {{#with_cmake}}
20
+ {{#with.cmake}}
21
21
  cmake:
22
22
  vars:
23
23
  {{NAME_PREFIX}}_COVERAGE: "?config:coverage"
24
24
  {{NAME_PREFIX}}_SANITIZE: "?config:sanitizer"
25
25
  {{NAME_PREFIX}}_CUTDOWN_OS: "?runtime:cutdown_os"
26
- {{/with_cmake}}
26
+ {{/with.cmake}}
27
27
  """
28
28
 
29
29
 
@@ -64,7 +64,7 @@ project.cxx.register_init_setting(
64
64
  api.ctx.Setting("PROJECT.WIX.UPGRADE_GUID", value=lambda: str(uuid.uuid4())),
65
65
  is_hidden=True,
66
66
  )
67
- project.cxx.register_switch("with_cmake", "Use CMake", True)
67
+ project.cxx.register_switch("with.cmake", "Use CMake", True)
68
68
  project.cxx.register_internal(
69
69
  "cmake",
70
70
  {
@@ -7,4 +7,4 @@ The **proj_flow.ext.cplusplus.conan** provides the ``"Conan"`` step.
7
7
 
8
8
  from proj_flow.project.cplusplus import project
9
9
 
10
- project.cxx.register_switch("with_conan", "Use Conan for dependency manager", True)
10
+ project.cxx.register_switch("with.conan", "Use Conan for dependency manager", True)
@@ -5,6 +5,7 @@
5
5
  The **proj_flow.project.cplusplus** registers a ``"C++"`` projects support.
6
6
  """
7
7
 
8
+ from proj_flow.base import path_get
8
9
  from proj_flow.project import api
9
10
 
10
11
  CPP_EXTENSIONS = [
@@ -20,7 +21,7 @@ class CPlusPlus(api.ProjectType):
20
21
  super().__init__("C++ plus CMake plus Conan", "cxx")
21
22
 
22
23
  def get_extension_list(self, context: dict):
23
- with_github_actions = not not context.get("with_github_actions")
24
+ with_github_actions = not not path_get(context, "with.github.actions")
24
25
  if with_github_actions:
25
26
  return [*CPP_EXTENSIONS, "proj_flow.ext.github"]
26
27
  return CPP_EXTENSIONS
@@ -6,8 +6,9 @@ The **proj_flow.project.interact** provides initialization context through
6
6
  user prompts.
7
7
  """
8
8
 
9
+ import os
9
10
  from dataclasses import dataclass
10
- from typing import Callable, List, Optional, Union
11
+ from typing import Any, Callable, List, Optional, Union, cast
11
12
 
12
13
  from prompt_toolkit import prompt as tk_prompt
13
14
  from prompt_toolkit.completion import WordCompleter
@@ -16,6 +17,7 @@ from prompt_toolkit.shortcuts import CompleteStyle
16
17
  from prompt_toolkit.validation import Validator
17
18
 
18
19
  from proj_flow.api import ctx, env
20
+ from proj_flow.base import plugins
19
21
 
20
22
 
21
23
  @dataclass
@@ -51,31 +53,31 @@ class _Question:
51
53
  return self.prompt or f'"{self.key}"'
52
54
 
53
55
  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
- ]
56
+ if isinstance(default, str):
57
+ if default == "":
58
+ return f"[{counter}/{size}] {self.ps}: "
73
59
  return [
74
60
  ("", f"[{counter}/{size}] {self.ps} ["),
75
- ("bold", default[0]),
76
- ("", f"{''.join(f' / {x}' for x in default[1:])}]: "),
61
+ ("bold", default),
62
+ ("", f"]: "),
77
63
  ]
78
- return f"[{counter}/{size}] {self.ps}: "
64
+ if isinstance(default, bool):
65
+ b = "bold"
66
+ n = ""
67
+ on_true = (b if default else n, "yes")
68
+ on_false = (b if not default else n, "no")
69
+ return [
70
+ ("", f"[{counter}/{size}] {self.ps} ["),
71
+ on_true,
72
+ ("", " / "),
73
+ on_false,
74
+ ("", f"]: "),
75
+ ]
76
+ return [
77
+ ("", f"[{counter}/{size}] {self.ps} ["),
78
+ ("bold", default[0]),
79
+ ("", f"{''.join(f' / {x}' for x in default[1:])}]: "),
80
+ ]
79
81
 
80
82
  def _get_str(self, default: str, counter: int, size: int):
81
83
  value = tk_prompt(self._ps(default, counter, size))
@@ -214,6 +216,10 @@ def _fixup_context(settings: ctx.SettingsType, wanted: Callable[[ctx.Setting], b
214
216
  except KeyError:
215
217
  pass
216
218
 
219
+ return _split_keys(settings)
220
+
221
+
222
+ def _split_keys(settings: dict):
217
223
  result = {}
218
224
  for key in settings:
219
225
  path = key.split(".")
@@ -226,14 +232,54 @@ def _fixup_context(settings: ctx.SettingsType, wanted: Callable[[ctx.Setting], b
226
232
  return result
227
233
 
228
234
 
229
- def get_context(interactive: bool, project: Optional[str], rt: env.Runtime):
235
+ def _flatten_keys(settings: Any, prefix=""):
236
+ if not isinstance(settings, dict):
237
+ yield (prefix, settings)
238
+ return
239
+
240
+ for key in settings:
241
+ next = f"{prefix}{key}."
242
+ for name, value in _flatten_keys(settings[key], next):
243
+ yield (cast(str, name), cast(Any, value))
244
+
245
+
246
+ def _flatten_dict(settings: dict):
247
+ result = {}
248
+ for name, value in _flatten_keys(settings):
249
+ result[name[:-1]] = value
250
+ return result
251
+
252
+
253
+ @dataclass
254
+ class ContextSetup:
255
+ """
256
+ Holds the setup for current context gathering.
257
+ """
258
+
259
+ #: Provides path name for project, in case it should differ from current
260
+ #: directory.
261
+ dest_path: Optional[str]
262
+
263
+ #: Selects, if the initialization process is done through prompts, or not.
264
+ interactive: bool
265
+
266
+ #: Do no post-processing and key expanding of the resulting context
267
+ simple: bool
268
+
269
+ #: If this setup is non-interactive, use contents of this file for
270
+ #: answers. If any given answer is missing, the default answer would be
271
+ #: taken.
272
+ load: Optional[str]
273
+
274
+
275
+ def get_context(setup: ContextSetup, project: Optional[str], rt: env.Runtime):
230
276
  """
231
277
  Prompts user to provide details of newly-crated project. If `interactive`
232
278
  is true, however, this functions skips the prompts and chooses all the
233
279
  default answers.
234
280
 
235
- :param interactive: Selects, if the initialization process is done through
236
- prompts, or not.
281
+ :param setup: Selects, if the initialization process is done through
282
+ prompts, or not and how to answer any given question.
237
283
 
238
284
  :param project: Alows to select questions for any given language.
239
285
 
@@ -243,13 +289,24 @@ def get_context(interactive: bool, project: Optional[str], rt: env.Runtime):
243
289
  """
244
290
 
245
291
  overrides = rt._cfg.get("defaults", {})
292
+ if setup.dest_path is not None:
293
+ overrides["PROJECT.NAME"] = os.path.basename(setup.dest_path)
294
+
295
+ if setup.load is not None:
296
+ data = plugins.load_data(setup.load)
297
+ data = _flatten_dict(_split_keys(data))
298
+ for key, value in data.items():
299
+ overrides[key] = value
246
300
 
247
301
  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,
302
+ result = (
303
+ _all_default(wanted, overrides)
304
+ if not setup.interactive
305
+ else _prompt(wanted, overrides)
255
306
  )
307
+ if "COPY.YEAR" in result:
308
+ fast = cast(dict, result)
309
+ fast["COPY.YEAR"] = int(fast["COPY.YEAR"])
310
+ if setup.simple:
311
+ return _split_keys(result)
312
+ return _fixup_context(result, wanted)
@@ -24,16 +24,16 @@ set(CMAKE_CXX_EXTENSIONS OFF)
24
24
 
25
25
  set_property(GLOBAL PROPERTY USE_FOLDERS ON)
26
26
 
27
- {{#with_conan}}
27
+ {{#with.conan}}
28
28
  list(APPEND CMAKE_MODULE_PATH "${PROJECT_BINARY_DIR}/conan" "${PROJECT_SOURCE_DIR}/.flow/cmake")
29
29
  list(APPEND CMAKE_PREFIX_PATH "${PROJECT_BINARY_DIR}/conan")
30
- {{/with_conan}}
31
- {{^with_conan}}
30
+ {{/with.conan}}
31
+ {{^with.conan}}
32
32
  list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/.flow/cmake")
33
- {{/with_conan}}
33
+ {{/with.conan}}
34
34
 
35
35
  include(common)
36
- {{#with_conan}}
36
+ {{#with.conan}}
37
37
  include(output_dirs_setup)
38
38
 
39
39
  set(CONAN_CMAKE_SILENT_OUTPUT ON)
@@ -41,14 +41,14 @@ find_package(Python3 COMPONENTS Interpreter REQUIRED)
41
41
  find_package(fmt REQUIRED)
42
42
  find_package(GTest REQUIRED)
43
43
  find_package(mbits-args REQUIRED)
44
- {{/with_conan}}
44
+ {{/with.conan}}
45
45
 
46
46
  if ({{NAME_PREFIX}}_TESTING)
47
47
  enable_testing()
48
48
 
49
- {{#with_conan}}
49
+ {{#with.conan}}
50
50
  find_package(GTest REQUIRED)
51
- {{/with_conan}}
51
+ {{/with.conan}}
52
52
 
53
53
  set(TEST_REPORT_DIR "${PROJECT_BINARY_DIR}/test-results")
54
54
  set(TEST_SANITIZER_TAG "")
@@ -58,10 +58,10 @@ if ({{NAME_PREFIX}}_TESTING)
58
58
  set(TEST_REPORT_FILE "${CMAKE_SYSTEM_NAME}-${CMAKE_CXX_COMPILER_ID}-${CMAKE_BUILD_TYPE}${TEST_SANITIZER_TAG}.xml")
59
59
  endif()
60
60
 
61
- {{#with_conan}}
61
+ {{#with.conan}}
62
62
  include(output_dirs_setup)
63
63
  old_conan_output_dirs_setup()
64
- {{/with_conan}}
64
+ {{/with.conan}}
65
65
 
66
66
  # See <https://github.com/lefticus/cppbestpractices/blob/v1.0.0/02-Use_the_Tools_Available.md#compilers>
67
67
 
@@ -177,7 +177,7 @@ target_include_directories(${PROJECT_NAME}
177
177
  ${CMAKE_CURRENT_SOURCE_DIR}/src
178
178
  ${CMAKE_CURRENT_BINARY_DIR}/src
179
179
  )
180
- target_link_libraries(${PROJECT_NAME}{{#with_conan}} fmt::fmt mbits::args{{/with_conan}})
180
+ target_link_libraries(${PROJECT_NAME}{{#with.conan}} fmt::fmt mbits::args{{/with.conan}})
181
181
  set_target_properties(${PROJECT_NAME} PROPERTIES
182
182
  VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
183
183
  {{#cmake.dynamic-library}}
@@ -1,10 +1,10 @@
1
1
  // Copyright (c) {{COPY.YEAR}} {{COPY.HOLDER}}
2
2
  // This code is licensed under {{COPY.LICENSE}} license (see LICENSE for details)
3
3
 
4
- {{#with_conan}}
4
+ {{#with.conan}}
5
5
  #include <fmt/format.h>
6
6
  #include <args/parser.hpp>
7
- {{/with_conan}}
7
+ {{/with.conan}}
8
8
  #include <{{INCLUDE_PREFIX}}/version{{EXT.hxx}}>
9
9
 
10
10
  int main(int argc, char* argv[]) {
@@ -23,15 +23,15 @@ int main(int argc, char* argv[]) {
23
23
  "sets the argument for the plural string");
24
24
  parser.parse();
25
25
 
26
- {{#with_conan}}
26
+ {{#with.conan}}
27
27
  auto msg = std::string_view{counter == 1 ? "you have one foobar"
28
28
  : "you have {0} foobars"};
29
29
  fmt::print(fmt::runtime(msg), counter);
30
- {{/with_conan}}
31
- {{^with_conan}}
30
+ {{/with.conan}}
31
+ {{^with.conan}}
32
32
  auto msg = std::string_view{counter == 1 ? "you have one foobar"
33
33
  : "you have %ld foobars"};
34
34
  printf(msg.data(), counter);
35
- {{/with_conan}}
35
+ {{/with.conan}}
36
36
  fputc('\n', stdout);
37
37
  }