diff --git a/docs/examples/Makefile b/docs/examples/Makefile index 425a1d7..3c0f669 100644 --- a/docs/examples/Makefile +++ b/docs/examples/Makefile @@ -1,7 +1,7 @@ MAKEFLAGS += --no-print-directory COLS ?= 60 ROWS ?= 20 -EXAMPLES := check embedded +EXAMPLES := check embedded recipe-help CASTS := $(addsuffix /demo.cast, $(EXAMPLES)) all: $(CASTS) diff --git a/docs/examples/index.md b/docs/examples/index.md index d1baa82..c7939cb 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -1,10 +1,14 @@ # Examples -[`Check`](./check) +[Confirm](./check) : Perform a basic confirmation test with the user and exit with error code 1 if input is N/n. -[`Embedded`](./embedded) +[Embedded Scripts](./embedded) : Use the builtin functions to write multi-line python/bash scripts directly in your `Makefile` + +[Recipe Help](./recipe-help) + +: Display the target, docstring and recipe for a given target then exit. diff --git a/docs/examples/recipe-help/demo.cast b/docs/examples/recipe-help/demo.cast new file mode 100644 index 0000000..fa12542 --- /dev/null +++ b/docs/examples/recipe-help/demo.cast @@ -0,0 +1,139 @@ +{"version": 2, "width": 60, "height": 20, "timestamp": 1664059901, "env": {"SHELL": "/usr/bin/zsh", "TERM": "xterm-256color"}} +[0.008451, "o", "\u001b[H\u001b[2J\u001b[3J"] +[0.008952, "o", "bash >> "] +[0.009359, "o", "ma"] +[0.189924, "o", "ke"] +[0.280056, "o", " -"] +[0.370134, "o", "f "] +[0.460177, "o", "re"] +[0.550458, "o", "ci"] +[0.640486, "o", "pe"] +[0.730615, "o", "-h"] +[0.820777, "o", "el"] +[0.910842, "o", "p/"] +[1.091156, "o", "re"] +[1.181306, "o", "ci"] +[1.271522, "o", "pe"] +[1.361548, "o", "-h"] +[1.451772, "o", "el"] +[1.542044, "o", "p."] +[1.631969, "o", "mk"] +[1.722108, "o", " h"] +[1.812243, "o", "el"] +[1.992584, "o", "p\r\n"] +[3.024383, "o", "\u001b[1;36musage:\u001b[0m\r\n\tmake \r\n\tmake help \r\n\r\n\u001b[1;33m deps-only\u001b[0m │ \u001b[2ma task/target with dependencies\u001b[0m\r\n\u001b[1;33m foo\u001b[0m │ \u001b[2ma dummy rule that depends on the local files\u001b[0m\r\n\u001b[1;33m h, help\u001b[0m │ \u001b[2mshow this help\u001b[0m\r\n\r\n"] +[5.031848, "o", "\u001b[H\u001b[2J\u001b[3Jbash >> "] +[5.033617, "o", "ma"] +[5.214025, "o", "ke"] +[5.304303, "o", " -"] +[5.394401, "o", "f "] +[5.484589, "o", "re"] +[5.574811, "o", "ci"] +[5.66483, "o", "pe"] +[5.755019, "o", "-h"] +[5.84516, "o", "el"] +[5.93541, "o", "p/"] +[6.115387, "o", "re"] +[6.205505, "o", "ci"] +[6.295713, "o", "pe"] +[6.385951, "o", "-h"] +[6.476085, "o", "el"] +[6.566208, "o", "p."] +[6.656285, "o", "mk"] +[6.746562, "o", " h"] +[6.836615, "o", "el"] +[7.016942, "o", "p "] +[7.106926, "o", "he"] +[7.19701, "o", "lp"] +[7.287225, "o", "\r\n"] +[8.317848, "o", "\u001b[1;36mtask.mk recipe help\u001b[0m\r\n\r\n"] +[8.324713, "o", " \u001b[1;33mh help\u001b[0m\r\n\u001b[38m ────────────────────────────────────────────────────────\u001b[0m\r\n $(call py,help_py) || { echo \"exiting early!\"; exit 1; }\r\n\r\n"] +[8.328735, "o", "exiting early!\r\n"] +[8.328871, "o", "make[1]: *** [/home/daylin/dev/github/mine/task.mk/task.mk:30: help] Error 1\r\n"] +[10.331577, "o", "\u001b[H\u001b[2J\u001b[3J"] +[10.331816, "o", "bash >> "] +[10.333573, "o", "ma"] +[10.514271, "o", "ke"] +[10.604555, "o", " -"] +[10.694653, "o", "f "] +[10.784848, "o", "re"] +[10.87526, "o", "ci"] +[10.965322, "o", "pe"] +[11.055364, "o", "-h"] +[11.145456, "o", "el"] +[11.23557, "o", "p/"] +[11.415828, "o", "re"] +[11.505942, "o", "ci"] +[11.596096, "o", "pe"] +[11.68623, "o", "-h"] +[11.776544, "o", "el"] +[11.866685, "o", "p."] +[11.95676, "o", "mk"] +[12.046838, "o", " h"] +[12.136847, "o", "el"] +[12.317252, "o", "p "] +[12.407456, "o", "de"] +[12.497528, "o", "ps"] +[12.587592, "o", "-o"] +[12.677666, "o", "nl"] +[12.767817, "o", "y\r\n"] +[13.818205, "o", "\u001b[1;36mtask.mk recipe help\u001b[0m\r\n\r\n"] +[13.827472, "o", "\u001b[1;33m deps-only\u001b[0m │ \u001b[2ma task/target with dependencies\u001b[0m\r\n \u001b[38mdeps\u001b[0m: \u001b[2mfoo\u001b[0m\r\n\r\n"] +[13.832182, "o", "exiting early!\r\n"] +[13.83243, "o", "make[1]: *** [/home/daylin/dev/github/mine/task.mk/task.mk:30: help] Error 1\r\n"] +[15.835429, "o", "\u001b[H\u001b[2J\u001b[3J"] +[15.83575, "o", "bash >> "] +[15.837618, "o", "ma"] +[16.018125, "o", "ke"] +[16.108476, "o", " -"] +[16.198731, "o", "f "] +[16.289003, "o", "re"] +[16.379138, "o", "ci"] +[16.469105, "o", "pe"] +[16.559388, "o", "-h"] +[16.649374, "o", "el"] +[16.739538, "o", "p/"] +[16.919813, "o", "re"] +[17.009951, "o", "ci"] +[17.100097, "o", "pe"] +[17.19021, "o", "-h"] +[17.280433, "o", "el"] +[17.370612, "o", "p."] +[17.460651, "o", "mk"] +[17.550888, "o", " h"] +[17.641021, "o", "el"] +[17.821304, "o", "p "] +[17.911452, "o", "fo"] +[18.001558, "o", "o\r\n"] +[19.029965, "o", "\u001b[1;36mtask.mk recipe help\u001b[0m\r\n\r\n"] +[19.039573, "o", "\u001b[1;33m foo\u001b[0m │ \u001b[2ma dummy rule that depends on the local files\u001b[0m\r\n \u001b[38mdeps\u001b[0m: \u001b[2mcheck embedded functions.sh index.md Makefile recipe-help\u001b[0m\r\n\u001b[38m ────────────────────────────\u001b[0m\r\n @echo 'this is a dummy rule'\r\n\r\n"] +[19.044473, "o", "exiting early!\r\n"] +[19.044637, "o", "make[1]: *** [/home/daylin/dev/github/mine/task.mk/task.mk:30: help] Error 1\r\n"] +[21.047851, "o", "\u001b[H\u001b[2J\u001b[3J"] +[21.048155, "o", "bash >> "] +[21.050062, "o", "ma"] +[21.230577, "o", "ke"] +[21.320832, "o", " -"] +[21.410896, "o", "f "] +[21.501092, "o", "re"] +[21.591208, "o", "ci"] +[21.681347, "o", "pe"] +[21.77147, "o", "-h"] +[21.861573, "o", "el"] +[21.951884, "o", "p/"] +[22.13224, "o", "re"] +[22.222235, "o", "ci"] +[22.312372, "o", "pe"] +[22.40265, "o", "-h"] +[22.49285, "o", "el"] +[22.582874, "o", "p."] +[22.672961, "o", "mk"] +[22.763162, "o", " h"] +[22.853371, "o", "el"] +[23.033526, "o", "p "] +[23.123576, "o", "ba"] +[23.214792, "o", "r\r\n"] +[24.264812, "o", "\u001b[1;36mtask.mk recipe help\u001b[0m\r\n\r\n"] +[24.271227, "o", " \u001b[1;33mbar\u001b[0m\r\n\u001b[38m ─────────────────────────────────────\u001b[0m\r\n @echo 'some rule with no help string'\r\n\r\n"] +[24.275046, "o", "exiting early!\r\n"] +[24.275205, "o", "make[1]: *** [/home/daylin/dev/github/mine/task.mk/task.mk:30: help] Error 1\r\n"] diff --git a/docs/examples/recipe-help/index.md b/docs/examples/recipe-help/index.md new file mode 100644 index 0000000..1a93e93 --- /dev/null +++ b/docs/examples/recipe-help/index.md @@ -0,0 +1,12 @@ +--- +asciinema: true +--- + +# Recipe Help + +
+ +```make title="recipe-help.mk" +--8<-- "docs/examples/recipe-help/recipe-help.mk" +``` + diff --git a/docs/examples/recipe-help/recipe-help.mk b/docs/examples/recipe-help/recipe-help.mk new file mode 100644 index 0000000..1f50dbf --- /dev/null +++ b/docs/examples/recipe-help/recipe-help.mk @@ -0,0 +1,24 @@ +## deps-only | a task/target with dependencies +.PHONY: deps-only +deps-only: foo + +## foo | a dummy rule that depends on the local files +.PHONY: foo +foo: $(wildcard *) + @echo 'this is a dummy rule' + +# bar but no docstring +.PHONY: bar +bar: + @echo 'some rule with no help string' + +define USAGE +{a.header}usage:{a.end} + make + make help + +endef + +.DEFAULT_GOAL = help +include $(shell git rev-parse --show-toplevel)/task.mk + diff --git a/docs/examples/recipe-help/record.sh b/docs/examples/recipe-help/record.sh new file mode 100755 index 0000000..0ce5a85 --- /dev/null +++ b/docs/examples/recipe-help/record.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +source "$(dirname "${BASH_SOURCE[0]}")/../functions.sh" + +cmd 'make -f recipe-help/recipe-help.mk help' +cmd 'make -f recipe-help/recipe-help.mk help help' +cmd 'make -f recipe-help/recipe-help.mk help deps-only' +cmd 'make -f recipe-help/recipe-help.mk help foo' +cmd 'make -f recipe-help/recipe-help.mk help bar' + +sleep 1 diff --git a/task.mk b/task.mk index 796f637..0d44d2a 100644 --- a/task.mk +++ b/task.mk @@ -1,7 +1,7 @@ # }> [github.com/daylinmorgan/task.mk] <{ # # Copyright (c) 2022 Daylin Morgan # MIT License -# version: v22.9.19-13-g63eb8ac-dev +# version: v22.9.19-17-gd6bd8a0-dev # # task.mk should be included at the bottom of your Makefile with `-include .task.mk` # See below for the standard configuration options that should be set prior to including this file. @@ -15,6 +15,7 @@ MSG_STYLE ?= faint DIVIDER ?= ─ DIVIDER_STYLE ?= default HELP_SEP ?= │ +WRAP ?= 100 # python f-string literals EPILOG ?= USAGE ?={ansi.header}usage{ansi.end}:\n make \n @@ -50,7 +51,8 @@ tconfirm = $(call py,confirm_py,$(1)) _update-task.mk: $(call tprint,{a.b_cyan}Updating task.mk{a.end}) curl https://raw.githubusercontent.com/daylinmorgan/task.mk/main/task.mk -o .task.mk -export MAKEFILE_LIST MAKE +TASK_MAKEFILE_LIST := $(filter-out $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)),$(MAKEFILE_LIST)) +export MAKEFILE_LIST MAKE TASK_MAKEFILE_LIST ifndef INHERIT_SHELL SHELL := $(shell which bash) endif @@ -138,13 +140,17 @@ def recipe_help_header(goal): return f" {ansi.style(goal,'goal')}" def get_goal_deps(goal="task.mk"): make = os.getenv("MAKE", "make") - database = subprocess.check_output([make, "-p", "-n"], universal_newlines=True) + cmd = [make, "-p", "-n", "-i"] + for file in os.getenv("TASK_MAKEFILE_LIST", "").split(): + cmd.extend(["-f", file]) + database = subprocess.check_output(cmd, universal_newlines=True) dep_pattern = re.compile(r"^" + goal + ":(.*)?") for line in database.splitlines(): match = dep_pattern.search(line) if match and match.groups()[0]: return wrap( f"{ansi.style('deps','default')}: {ansi.style(match.groups()[0].strip(),'msg')}", + width=cfg.wrap, initial_indent=" ", subsequent_indent=" ", ) @@ -224,11 +230,11 @@ def print_arg_help(help_args): print(f"{ansi.style('task.mk recipe help','header')}\n") for arg in help_args.split(): print("\n".join(parse_goal(gen_makefile(), arg))) + print() def main(): help_args = os.getenv("HELP_ARGS") if help_args: print_arg_help(help_args) - print(ansi.faint) sys.exit(1) else: print_help() @@ -284,6 +290,7 @@ class Config: sep: str epilog: str usage: str + wrap: int color2byte = dict( black=0, red=1, @@ -364,5 +371,6 @@ class Ansi: else: return f"{self.__dict__[style]}{text}{self.__dict__['end']}" a = ansi = Ansi() -cfg = Config("$(DIVIDER)", "$(HELP_SEP)", f"""$(EPILOG)""", f"""$(USAGE)""") +cfg = Config( + "$(DIVIDER)", "$(HELP_SEP)", f"""$(EPILOG)""", f"""$(USAGE)""",int('$(WRAP)')) endef