diff --git a/README.md b/README.md index e19851f..67b6123 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,191 @@ -# task.mk +
+

task.mk

+ help +

+ the task runner for GNU Make you've been missing +

+
+
-GNU make is the task runner we love to hate, but can't escape. So let's improve the UX for users. +GNU make is an excellent build tool and the task runner we love to hate, but can't escape. +So let's improve the UX to make it the best task runner it can be. -So I give you `task.mk`, a standalone makefile you can deploy alongside your own -`Makefile`'s to add some QOL improvements for your users and fellow maintainers. +`Task.mk`, is a standalone `Makefile` you can deploy alongside your own +to add some QOL improvements for your users and fellow maintainers. Current Features: - - ANSI Color Support - - Formatted Help Screen - - Custom print function + - ANSI escape code support (including NO_COLOR) + - formatted help output + - custom print function Depends on `GNU Make`, obviously and `Python >=3.7`. -Wait python?!, I'm not `pip` installing some package just to parse my makefile. +Wait python?!?!, I'm not `pip` installing some package just to parse my makefile. I agree, so I've hacked together a file containing the bits of python we need with some tricks to run it. -## Usage +## Setup -You can include this as an optional dependency on your project by adding the below lines the end of your make file. -When your users first your `make help` it will download `task.mk`. -If you intend to use any of the other features like `tprint` (see below), -I'd recommend committing `.task.mk` into version control so behavior is consistent. +You can include this as an optional dependency on your project by adding the below lines to the end of your `Makefile`. +If someone tries to invoke `make help` it will download `.task.mk` for them. ```make -include .task.mk $(if $(filter help,$(MAKECMDGOALS)),.task.mk: ; curl -fsSL https://raw.githubusercontent.com/daylinmorgan/task.mk/22.9.5/task.mk -o .task.mk) ``` + +If you intend to use any of the other features like `tprint` (see below), +I'd recommend committing `.task.mk` into version control so behavior is consistent. + +```bash +curl -fsSL https://raw.githubusercontent.com/daylinmorgan/task.mk/22.9.5/task.mk -o .task.mk +``` + +## Usage + +`Task.mk` will add access to a recipe `help` (also aliased to `h`). +In order to use `make help` to you will need to add some custom comments to your `Makefile`. + +Deliberately, I don't get names from recipes themselves. +This not only greatly simplifies the parsing but add's some opportunity to customize the output. +Such as to document wildcard or redundant recipes. + +You can place these anywhere, but I recommend adding these notes directly above their relevant recipes. +The format is `## | ` + +```make +## build | build the project +.PHONY: build +build: + ... +``` + +Now when you invoke `task.mk` it will parse these and generate your help output. + +In addition to a generic help output you can expose some configuration settings with `make vars`. +To do so define the variables you'd like to print with `PRINT_VARS := VAR1 VAR2 VAR3`. + +In addition to the `help` and `vars` recipes you can use a custom make function to format your text for fancier output. +For this there are two options depending on your needs `tprint` or `tprint-sh`. (`tprint-sh` is for use within a multiline sub-shell that has already been silenced, see the version-check rule of this project's `Makefile` for an example.) + + +To use `tprint` you call it with the builtin `make` call function. +It accepts only one argument: an unquoted f-string literal. +All strings passed to `tprint` have access to an object `ansi` or `a` for simplicity. +This stores ANSI escape codes which can be used to style your text. + +```make +## build | compile the source +.PHONY: build +build: + $(call tprint,{a.cyan}Build Starting{a.end}) + ... + $(call tprint,{a.green}Build Finished{a.end}) +``` +See this projects `make info` for more examples of `tprint`. + +To see the available colors and formatting(bold,italic,etc.) use the hidden recipe `make _print-ansi`. + +**Note**: Any help commands starting with an underscore will be ignored. +To view hidden `tasks` (or recipes in GNU Make land) you can use `make _help`. + +## Configuration + +You can quickly customize some of the default behavior of `task.mk` by overriding the below variables prior to the `-include .task.mk`. + +```make +# ---- CONFIG ---- # +HEADER_COLOR ?= b_cyan +PARAMS_COLOR ?= b_magenta +ACCENT_COLOR ?= b_yellow +GOAL_COLOR ?= $(ACCENT_COLOR) +MSG_COLOR ?= faint +HELP_SEP ?= | +HELP_SORT ?= # sort goals alphabetically + +# python f-string literals +EPILOG ?= +define USAGE ?= +{ansi.$(HEADER_COLOR)}usage{ansi.end}: + make + +endef +``` + +**NOTE**: `HELP_SEP` does not change the argument definitions syntax only the format of `make help`. + +## Advanced Usage: Embedded Python Scripts + +You can take advantage of the builtin python script runner and write multi-line python scripts of your own. +This is a simple example but a few lines of python in your `Makefile` +may be easier than balancing sub-shells and strung together awk commands. + +When `make` expands the function it will take the parameters passed to `py` and expand them `$(1)` is the variable name. +`$(2)` in this case is the implicit pattern from the rule. Pay attention to quotes. +If you need to debug your python script, use `DEBUG=1` when you run `make` and it will first print the script that will be piped to `python`. + +```make +define list_files_py +from pathlib import Path +print("files in $(2)") +print([f.name for f in (Path("$(2)").iterdir())]) +endef + +## list-% | use pathlib.Path to list files +list-%: + $(call py,list_files_py,$*) +``` + +For what it's worth there is also a predefined function for `bash` (named `tbash`) as well should you need to accomplish something similar of more easily embedding your bash script rather than having to escape every line with '\'. + +```make +define bash_script +echo "This is from bash" +cat /etc/hostname +printf "%s\n" "$(2)" +endef +.PHONY: test-bash +test-bash: + $(call tbash,bash_script,test bash multiline) +``` + + + +## Zsh Completions for GNU Make + +If you use `GNU Make` with zsh you may want to add the following +line to your rc file to allow `make` to handle the autocomplete. + +```zsh +zstyle ':completion::complete:make:*:targets' call-command true +``` + +## Why Make? + +There are lot of `GNU Make` alternatives but none have near the same level of ubiquity. +This project attaches to `make` some of native features of [`just`](https://github.com/casey/just), a command runner. + +Just is a great task runner, but it suffers two problems, users probably don't have it installed already, and there is no way to define file specific recipes. +Most of my `Makefile`'s are comprised primarily of handy `.PHONY` recipes, but I always end up with a few file specific recipes. + +Another interesting project I've evaluated for these purposes is [`go-task/task`](https://github.com/go-task/task). +`Task` has many of the features of `GNU Make` and some novel features of it's own. +But like `just` it's a tool people don't usually already have and it's configured using a `yaml` file. +`Yaml` files can be finicky to work with and and it uses a golang based shell runtime not your native shell, which might lead to unexpected behavior. + + +## Simpler Alternative + +But I just want a basic help output, surely I don't need python for this... you would be right. +`Task.mk` replaces my old `make help` recipe boilerplate which may better serve you. + + +```make +## h, help | show this help +.PHONY: help h +help h: Makefile params + @awk -v fill=$(shell sed -n 's/^## \(.*\) | .*/\1/p' $< | wc -L)\ + 'match($$0,/^## (.*) \|/,name) && match($$0,/\| (.*)$$/,help)\ + {printf "\033[1;93m%*s\033[0m | \033[30m%s\033[0m\n",\ + fill,name[1],help[1];} match($$0,/^### (.*)/,str) \ + {printf "%*s \033[30m%s\033[0m\n",fill," ",str[1];}' $< +``` \ No newline at end of file diff --git a/assets/help.svg b/assets/help.svg new file mode 100644 index 0000000..596e1d8 --- /dev/null +++ b/assets/help.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + make help + + + + + + + + + + usage: +make <recipe> + +  Turn your `Makefile` into +  the task runner you always needed. +  See the example output below. + +bootstrap | generate local dev environment +     lint | lint the python +   assets | generate assets +   list-% | use pathlib.Path to list files +  release | release new version of task.mk + c, clean | remove the generated files +     info | demonsrtate usage of tprint +  h, help | show this help + +for more info: see github.com/daylinmorgan/task.mk + + + +