"""
GNU Make support.
"""
import medikit
from medikit.events import subscribe
from medikit.feature import HIGH_PRIORITY, Feature
from medikit.feature.make.config import MakeConfig
from medikit.feature.make.events import MakefileEvent
from medikit.feature.make.resources import CleanScript, InstallScript, Makefile, MakefileTarget
from medikit.feature.make.utils import which
from medikit.globals import PIP_VERSION
from medikit.structs import Script
__all__ = [
"CleanScript",
"InstallScript",
"MakeConfig",
"MakeFeature",
"Makefile",
"MakefileEvent",
"MakefileTarget",
"which",
]
[docs]class MakeFeature(Feature):
Config = MakeConfig
[docs] @subscribe(medikit.on_start, priority=HIGH_PRIORITY)
def on_start(self, event):
"""
:param ProjectEvent event:
"""
for k in event.variables:
self.makefile[k.upper()] = event.variables[k]
self.makefile.updateleft(("QUICK", ""))
self.makefile.add_install_target()
for extra in event.config["make"].extras:
self.makefile.add_install_target(extra)
self.makefile.add_target("quick", Script('@printf ""'), phony=True, hidden=True)
self.dispatcher.dispatch(
MakeConfig.on_generate, MakefileEvent(event.config.package_name, self.makefile, event.config)
)
if event.config["make"].include_medikit_targets:
self.add_medikit_targets(event.config["make"])
if event.config["make"].includes:
self.add_includes(event.config["make"].includes)
# Recipe courtesy of https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
self.makefile.add_target(
"help",
r"""
@echo "Available commands:"
@echo
@grep -E '^[a-zA-Z_-]+:.*?##[\s]?.*$$' --no-filename $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?##"}; {printf " make \033[36m%-30s\033[0m %s\n", $$1, $$2}'
@echo
""",
phony=True,
doc="Shows available commands.",
)
# Actual rendering of the Makefile
self.render_file_inline("Makefile", self.makefile.__str__(), override=True)
[docs] def add_medikit_targets(self, config):
if not "PYTHON" in self.makefile:
self.makefile["PYTHON"] = which("python")
self.makefile["MEDIKIT"] = "$(PYTHON) -m medikit"
self.makefile["MEDIKIT_UPDATE_OPTIONS"] = ""
self.makefile["MEDIKIT_VERSION"] = medikit.__version__
source = [
"import medikit, pip, sys",
"from packaging.version import Version",
'sys.exit(0 if (Version(medikit.__version__) >= Version("$(MEDIKIT_VERSION)")) and (Version(pip.__version__) < Version("10")) else 1)',
]
self.makefile.add_target(
"medikit",
'@$(PYTHON) -c {!r} || $(PYTHON) -m pip install -U "pip {PIP_VERSION}" "medikit>=$(MEDIKIT_VERSION)"'.format(
"; ".join(source), PIP_VERSION=PIP_VERSION
),
phony=True,
hidden=True,
doc="Checks installed medikit version and updates it if it is outdated.",
)
self.makefile.add_target(
"update",
"$(MEDIKIT) update $(MEDIKIT_UPDATE_OPTIONS)",
deps=("medikit",),
phony=True,
doc="""Update project artifacts using medikit.""",
)
# TODO this should adapt to langauges included, and be removed if no language
# For example, requirements*.txt are specific to python, using classic setuptools.
self.makefile.add_target(
"update-requirements",
'MEDIKIT_UPDATE_OPTIONS="--override-requirements" $(MAKE) update',
phony=True,
doc="""Update project artifacts using medikit, including requirements files.""",
)
[docs] def add_includes(self, includes):
for include in includes:
self.makefile.header.append("include " + include)