Skip to content

Commit 27dd8b1

Browse files
authored
Merge pull request #44 from mxstack/feat-help
first basic impl of a help system
2 parents 5f7ebcc + 849182f commit 27dd8b1

File tree

7 files changed

+204
-46
lines changed

7 files changed

+204
-46
lines changed

Makefile

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# DOMAINS:
55
#: applications.zest-releaser
66
#: core.base
7+
#: core.help
78
#: core.mxenv
89
#: core.mxfiles
910
#: core.packages
@@ -50,7 +51,7 @@ EXTRA_PATH?=
5051
PRIMARY_PYTHON?=python3
5152

5253
# Minimum required Python version.
53-
# Default: 3.7
54+
# Default: 3.9
5455
PYTHON_MIN_VERSION?=3.9
5556

5657
# Install packages using the given package installer method.
@@ -166,6 +167,12 @@ MYPY_SRC?=src
166167
# Default: types-setuptools
167168
MYPY_REQUIREMENTS?=types-setuptools types-docutils types-PyYAML
168169

170+
## core.help
171+
172+
# Request to show all targets, descriptions and arguments for a given domain.
173+
# No default value.
174+
HELP_DOMAIN?=
175+
169176
## applications.zest-releaser
170177

171178
# Options to pass to zest.releaser prerelease command.
@@ -594,6 +601,14 @@ TYPECHECK_TARGETS+=mypy
594601
CLEAN_TARGETS+=mypy-clean
595602
DIRTY_TARGETS+=mypy-dirty
596603

604+
##############################################################################
605+
# help
606+
##############################################################################
607+
608+
.PHONY: help
609+
help: $(MXENV_TARGET)
610+
@mxmake help-generator
611+
597612
##############################################################################
598613
# zest-releaser
599614
##############################################################################
@@ -636,6 +651,10 @@ INSTALL_TARGETS+=$(ZEST_RELEASER_TARGET)
636651
DIRTY_TARGETS+=zest-releaser-dirty
637652
CLEAN_TARGETS+=zest-releaser-clean
638653

654+
##############################################################################
655+
# Custom includes
656+
##############################################################################
657+
639658
-include $(INCLUDE_MAKEFILE)
640659

641660
##############################################################################

src/mxmake/helpgen.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
from .parser import MakefileParser
2+
from .topics import get_domain
3+
from .topics import get_topic
4+
from .topics import resolve_domain_dependencies
5+
from .topics import set_domain_runtime_depends
6+
7+
import os
8+
import pathlib
9+
import sys
10+
import textwrap
11+
12+
13+
def print_help(makefile: pathlib.Path):
14+
"""Parse the Makefile and print the help."""
15+
16+
parser = MakefileParser(makefile)
17+
18+
sys.stdout.write("\nUsage: make <target> [ARGUMENT1=value1] [ARGUMENT2=value2]\n\n")
19+
help_domain = os.environ.get("HELP_DOMAIN")
20+
if help_domain:
21+
sys.stdout.write(f"Help for domain '{help_domain}'\n\n")
22+
else:
23+
sys.stdout.write("Available targets:\n\n")
24+
25+
domains = [get_domain(fqn) for fqn in parser.fqns]
26+
set_domain_runtime_depends(domains)
27+
idnt = " "
28+
lvl = 1
29+
found = False
30+
for domain in resolve_domain_dependencies(domains):
31+
if help_domain and domain.name != help_domain:
32+
continue
33+
topic = get_topic(domain.topic)
34+
sys.stdout.write(f"DOMAIN '{domain.name}' (topic {topic.title})\n")
35+
sys.stdout.write(
36+
"\n".join(
37+
textwrap.wrap(
38+
domain.description,
39+
width=79,
40+
initial_indent=idnt * lvl,
41+
subsequent_indent=idnt * lvl,
42+
)
43+
)
44+
)
45+
sys.stdout.write("\n\nTARGETS\n\n")
46+
for target in domain.targets:
47+
sys.stdout.write(f"{idnt*lvl}{target.name}\n")
48+
if help_domain:
49+
lvl += 1
50+
found = True
51+
sys.stdout.write(
52+
"\n".join(
53+
textwrap.wrap(
54+
target.description,
55+
width=79,
56+
initial_indent=idnt * (lvl),
57+
subsequent_indent=idnt * (lvl),
58+
)
59+
)
60+
)
61+
sys.stdout.write("\n\n")
62+
lvl -= 1
63+
if help_domain:
64+
sys.stdout.write("ARGUMENTS\n\n")
65+
for setting in domain.settings:
66+
fqn_setting = f"{domain.fqn}.{setting.name}"
67+
sys.stdout.write(
68+
f"{idnt*lvl}{setting.name}={parser.settings.get(fqn_setting) or '<not set>'}\n"
69+
)
70+
sys.stdout.write(
71+
"\n".join(
72+
textwrap.wrap(
73+
setting.description,
74+
width=79,
75+
initial_indent=idnt * (lvl + 1),
76+
subsequent_indent=idnt * (lvl + 1),
77+
)
78+
)
79+
)
80+
sys.stdout.write("\n\n")
81+
else:
82+
sys.stdout.write("\n\n")
83+
84+
if not help_domain:
85+
sys.stdout.write("")
86+
sys.stdout.write(
87+
"Need detailed help by domain containing all information?\nRun:\n\n make help HELP_DOMAIN=<domain>\n"
88+
)
89+
elif not found:
90+
sys.stdout.write("No help found for requested domain st\n")
91+
sys.exit(1)

src/mxmake/main.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
from mxmake.parser import MakefileParser
2-
from mxmake.templates import ci_template
3-
from mxmake.templates import get_template_environment
4-
from mxmake.templates import template
5-
from mxmake.topics import collect_missing_dependencies
6-
from mxmake.topics import Domain
7-
from mxmake.topics import get_domain
8-
from mxmake.topics import get_topic
9-
from mxmake.topics import load_topics
10-
from mxmake.topics import resolve_domain_dependencies
11-
from mxmake.topics import set_domain_runtime_depends
1+
from .helpgen import print_help
2+
from .parser import MakefileParser
3+
from .templates import ci_template
4+
from .templates import get_template_environment
5+
from .templates import template
6+
from .topics import collect_missing_dependencies
7+
from .topics import Domain
8+
from .topics import get_domain
9+
from .topics import get_topic
10+
from .topics import load_topics
11+
from .topics import resolve_domain_dependencies
12+
from .topics import set_domain_runtime_depends
1213
from operator import attrgetter
1314
from pathlib import Path
1415
from textwrap import indent
@@ -301,16 +302,31 @@ def update_command(args: argparse.Namespace):
301302
sys.stdout.write("###############\n\n")
302303

303304
if not Path("Makefile").exists():
304-
sys.stdout.write("Makefile not exists, abort\n")
305+
sys.stdout.write("Makefile does not exist, abort\n")
305306
sys.exit(1)
306307

307308
create_config(prompt=False, preseeds=None)
308309

309310

310-
update_parser = command_parsers.add_parser("update", help="Update makefile")
311+
update_parser = command_parsers.add_parser("update", help="Update Makefile")
311312
update_parser.set_defaults(func=update_command)
312313

313314

315+
def help_generator_command(args: argparse.Namespace):
316+
sys.stdout.write("Help for Makefile\n")
317+
makefile = Path("Makefile")
318+
if not makefile.exists():
319+
sys.stdout.write("Makefile does not exist, abort\n")
320+
sys.exit(1)
321+
322+
print_help(makefile)
323+
324+
325+
help_generator_parser = command_parsers.add_parser(
326+
"help-generator", help="Help for Makefile"
327+
)
328+
help_generator_parser.set_defaults(func=help_generator_command)
329+
314330
##############################################################################
315331
# main
316332
##############################################################################

src/mxmake/templates.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -546,21 +546,18 @@ def target_folder(self) -> Path:
546546
def template_variables(self):
547547
targets = []
548548
for folder, proxy in self.settings.items():
549-
for item in [item.strip() for item in proxy.split('\n') if item.strip()]:
550-
topic_name, domain_names = item.split(':')
549+
for item in [item.strip() for item in proxy.split("\n") if item.strip()]:
550+
topic_name, domain_names = item.split(":")
551551
topic = get_topic(topic_name.strip())
552-
domain_names = domain_names.split(',')
552+
domain_names = domain_names.split(",")
553553
domains = []
554554
for domain_name in domain_names:
555-
if domain_name == '*':
555+
if domain_name == "*":
556556
domains = topic.domains
557557
break
558558
else:
559559
domains.append(topic.domain(domain_name.strip()))
560560
for domain in domains:
561561
for target in domain.targets:
562-
targets.append(dict(
563-
name=target.name,
564-
folder=folder
565-
))
562+
targets.append(dict(name=target.name, folder=folder))
566563
return dict(targets=targets)

src/mxmake/tests/test_templates.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -965,28 +965,33 @@ def test_ProxyMk(self, tempdir):
965965
factory = templates.template.lookup("proxy")
966966
template = factory(configuration, templates.get_template_environment())
967967

968-
self.assertEqual(template.description, "Contains proxy targets for Makefiles of source folders")
968+
self.assertEqual(
969+
template.description,
970+
"Contains proxy targets for Makefiles of source folders",
971+
)
969972
self.assertEqual(template.target_folder, utils.mxmake_files())
970973
self.assertEqual(template.target_name, "proxy.mk")
971974
self.assertEqual(template.template_name, "proxy.mk")
972975
self.assertEqual(
973976
template.template_variables,
974-
{'targets': [
975-
{'name': 'plone-site-create', 'folder': 'folder'},
976-
{'name': 'plone-site-purge', 'folder': 'folder'},
977-
{'name': 'plone-site-recreate', 'folder': 'folder'},
978-
{'name': 'gettext-create', 'folder': 'folder'},
979-
{'name': 'gettext-update', 'folder': 'folder'},
980-
{'name': 'gettext-compile', 'folder': 'folder'},
981-
{'name': 'lingua-extract', 'folder': 'folder'},
982-
{'name': 'lingua', 'folder': 'folder'}
983-
]}
977+
{
978+
"targets": [
979+
{"name": "plone-site-create", "folder": "folder"},
980+
{"name": "plone-site-purge", "folder": "folder"},
981+
{"name": "plone-site-recreate", "folder": "folder"},
982+
{"name": "gettext-create", "folder": "folder"},
983+
{"name": "gettext-update", "folder": "folder"},
984+
{"name": "gettext-compile", "folder": "folder"},
985+
{"name": "lingua-extract", "folder": "folder"},
986+
{"name": "lingua", "folder": "folder"},
987+
]
988+
},
984989
)
985990

986991
template.write()
987992
with (tempdir / "proxy.mk").open() as f:
988993
self.checkOutput(
989-
'''
994+
"""
990995
##############################################################################
991996
# proxy targets
992997
##############################################################################
@@ -1023,6 +1028,6 @@ def test_ProxyMk(self, tempdir):
10231028
folder-lingua:
10241029
$(MAKE) -C "./folder/" lingua
10251030
1026-
''',
1031+
""",
10271032
f.read(),
10281033
)

src/mxmake/topics/core/base.mk

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,17 @@
1010
#:description = Deploy project. Supposed to setup a production version of
1111
#: the project.
1212
#:
13+
#:[setting.DEPLOY_TARGETS]
14+
#:description = `deploy` target dependencies.
15+
#:default =
16+
#:
1317
#:[target.run]
1418
#:description = Run project. Depending on target defined in `RUN_TARGET`
1519
#:
20+
#:[setting.RUN_TARGET]
21+
#:description = target to be executed when calling `make run`
22+
#:default =
23+
#:
1624
#:[target.dirty]
1725
#:description = Force make to rebuild targets on next make run.
1826
#:
@@ -27,21 +35,21 @@
2735
#:[target.runtime-clean]
2836
#:description = Remove runtime artifacts, like byte-code and caches.
2937
#:
38+
#:[setting.CLEAN_FS]
39+
#:description = Additional files and folders to remove when running clean target
40+
#:default =
41+
#:
3042
#:[target.check]
31-
#:description = Run all QA related targets, e.g. code style or type checks.
43+
#:description = Run all QA checkers related targets, e.g. code style
3244
#: Only gets included if any qa topic related domain is used.
3345
#:
34-
#:[setting.DEPLOY_TARGETS]
35-
#:description = `deploy` target dependencies.
36-
#:default =
37-
#:
38-
#:[setting.RUN_TARGET]
39-
#:description = target to be executed when calling `make run`
40-
#:default =
46+
#:[target.type-check]
47+
#:description = Run all QA type-checkers related targets, e.g. type checks.
48+
#: Only gets included if any qa topic related domain is used.
4149
#:
42-
#:[setting.CLEAN_FS]
43-
#:description = Additional files and folders to remove when running clean target
44-
#:default =
50+
#:[target.format]
51+
#:description = Run all QA code formatters related targets, e.g. code style
52+
#: Only gets included if any qa topic related domain is used.
4553
#:
4654
#:[setting.INCLUDE_MAKEFILE]
4755
#:description = Optional makefile to include before default targets. This can

src/mxmake/topics/core/help.mk

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#:[help]
2+
#:title = Help System
3+
#:description = A system to provide the user of the Makefile an overview of the targets
4+
#: and all environment variable based arguments.
5+
#:
6+
#:depends = core.mxenv
7+
#:
8+
#:[target.help]
9+
#:description = Print help for the Makefile.
10+
#:
11+
#:[setting.HELP_DOMAIN]
12+
#:description = Request to show all targets, descriptions and arguments for a given domain.
13+
#:default =
14+
#:
15+
16+
##############################################################################
17+
# help
18+
##############################################################################
19+
20+
.PHONY: help
21+
help: $(MXENV_TARGET)
22+
@mxmake help-generator

0 commit comments

Comments
 (0)