API / CLI Documentation


Tip

A major advantage of make is that the programmatic interface is the command-line interface, and vice versa, so the documentation here is often relevant for tool mode or library mode.

Note that the autogenerated section of the API (i.e. scaffolded targets created by compose.import) is not presented here.. see instead the docs for the Make/Compose Bridge.

This is the complete list of public targets available from compose.mk, along with their documentation. Things are organized into a few namespaces, so hopefully if you're using this stuff programmatically that helps to avoid collisions with your project targets. See the module layout overview for more details. Most documentation is pulled automatically from the latest source.

Some important notes about how these targets work:

  • Target names are reserved names after declaration.
  • Targets are usable interactively from your shell as make <target> or ./compose.mk <target>
  • Targets are usable as an API, either as prereq-targets or as part of the body in your project automation.
  • Most targets are pure shell, and have no exotic dependencies. That means that they generally run fine on host or as dispatched targets inside containers.

API: io


The io.* namespace has misc helpers for working with input/output, including utilities for working with temp files and showing output to users. User-facing output leverages charmbracelet utilities like gum[2] and glow[3]. Generally we use tools directly if they are available, falling back to utilities in containers.


DOCS:

This documentation is pulled automatically from source.

io.awk/arg

 Treats the given define-block name as an awk script, 
 always running it on stdin. Used internally.  
 Must remain silent, does not support args.  
 Also available as a macro.

 USAGE:
   io.awk/<def_name>
io.bash/arg

 Treats the given define-block name as a bash script.
 Also available as a macro.

 USAGE:
   io.bash/<def_name>,<optional_args>
io.browser

 Tries to open the given URL in a browser.
 NB: This requires python on the host and can not run from docker.

 USAGE: 
  url="..." ./compose.mk io.browser
io.browser/arg

 Like `io.browser`, but accepts a variable-name as an argument.
 Variable will be dereferenced and stored as 'url' before chaining.
 NB: This requires python on the host and can not run from docker.
io.draw.banner

 Helper for formatting text and banners using `gum style` and `gum format`.
 Expects label text under the `label variable, plus supporting optional `width`.
 Also available as a macro.  See instead `io.print.banner` for something simpler.

 REFS:
 [1] [gum documentation](https://github.com/charmbracelet/gum)

 EXAMPLE:
   label="..." ./compose.mk io.draw.banner 
   width=30 label='...' ./compose.mk io.draw.banner 
io.draw.banner/arg

Alias for io.gum.style/

io.echo

 Echos data from input stream. Alias for the `stream.stdin` macro.
io.env

 Dumps a relevant subset of environment variables for the current context.
 No arguments.  Pipe-safe since this is just filtered output from 'env'.

 USAGE: ./compose.mk io.env
io.env.filter.prefix/arg

Alias for io.env/

io.env.pretty

 Pretty version of io.env, this includes some syntax highlighting.
 No arguments.  See 'io.envp/<arg>' for a version that supports filtering.

 USAGE: ./compose.mk io.envp
io.env.pretty/arg

Alias for io.envp/

io.env/arg

 Filters environment variables by the given prefix or (comma-delimited) prefixes.
 Also available as a macro.

 USAGE:
   ./compose.mk io.env/<prefix1>,<prefix2>
io.envp

 Pretty version of io.env, this includes some syntax highlighting.
 No arguments.  See 'io.envp/<arg>' for a version that supports filtering.

 USAGE: ./compose.mk io.envp
io.envp/arg

 Pretty version of 'io.env/<arg>', this includes syntax highlighting and also filters the output.

 USAGE:
  ./compose.mk io.envp/<prefix_to_filter_for>

 USAGE: (only vars matching 'TUI*')
  ./compose.mk io.envp/TUI
io.figlet

 Pulls `label` from the environment and renders it with `figlet`. 
 Also available as a macro. NB: This requires the embedded tui is built.
io.figlet/arg

 Treats the argument as a label, and renders it with `figlet`. 
 NB: This requires the embedded tui is built.  
io.gum.choice/arg

 Interface to `gum choose`.
 This uses gum if it is available, falling back to docker if necessary.

 USAGE:
  ./compose.mk io.gum.choose/choice-one,choice-two
io.gum.choose/arg

Alias for io.gum.choice/

io.gum.div

 Draw a horizontal divider with gum.
 If `label` is not provided, this defaults to using a timestamp.

 USAGE:
  label=".." ./compose.mk io.gum.div 
io.gum.spin

 Runs `gum spin` with the given command/label.

 EXAMPLE:
   cmd="sleep 2" label=title ./compose.mk io.gum.spin

 REFS:
 [1] [gum documentation](https://github.com/charmbracelet/gum)
io.gum.style

 Helper for formatting text and banners using `gum style` and `gum format`.
 Expects label text under the `label variable, plus supporting optional `width`.
 Also available as a macro.  See instead `io.print.banner` for something simpler.

 REFS:
 [1] [gum documentation](https://github.com/charmbracelet/gum)

 EXAMPLE:
   label="..." ./compose.mk io.draw.banner 
   width=30 label='...' ./compose.mk io.draw.banner 
io.gum.style/arg

 Prints a divider with the given label. 
 Invocation must be a legal target (Do not use spaces, etc!)
 See also `io.draw.banner` and `io.print.banner` for something simpler.

 USAGE: ./compose.mk io.draw.banner/<label>
io.help

 Lists only the targets available under the 'io' namespace.
io.mkdir/arg

 Runs `mkdir -p` for the named directory
io.preview.file/arg

 Outputs syntax-highlighting + line-numbers for the given filename to stderr.

 USAGE:
  ./compose.mk io.preview.file/<fname>
io.preview.img/arg

 Console-friendly image preview for the given file. See also: `stream.img`

 USAGE: 
   ./compose.mk io.preview.img/<path_to_img>
io.preview.markdown/arg

 Console-friendly markdown preview for the given file. See also `stream.markdown`
io.preview.pygmentize/arg

 Syntax highlighting for the given file.
 Lexer will autodetected unless override is provided.
 Style defaults to 'trac', which works best with dark backgrounds.

 USAGE:
   ./compose.mk io.preview.pygmentize/<fname>
   lexer=.. ./compose.mk io.preview.pygmentize/<fname>
   lexer=.. style=.. ./compose.mk io.preview.pygmentize/<fname>

 REFS:
 [1]: https://pygments.org/
 [2]: https://pygments.org/styles/
io.print.banner

 Prints a divider on stdout, defaulting to the full 
 term-width, with optional label. If label is not set, 
 a timestamp will be used.  Also available as a macro.

 USAGE:
  label=".." filler=".." width="..." ./compose.mk io.print.banner 
io.print.banner/arg

 Like `io.print.banner` but accepts a label directly.
io.quiet.stderr.sh

 Runs the given target, surpressing stderr output, except in case of error.

 USAGE:
  ./compose.mk io.quiet/<target_name>
io.quiet.stderr/arg

 Runs the given target, surpressing stderr output, except in case of error.

 USAGE:
  ./compose.mk io.quiet/<target_name>
io.selector/arg

 Uses the given targets to generate and then handle choices.
 The 1st argument should be a nullary target; the 2nd must be unary.

 USAGE: 
   ./compose.mk io.selector/<choice_generator>,<choice_handler>
io.shell

 Starts an interactive shell with all the environment variables set
 by the parent environment, plus those set by this Makefile context.
io.stack.pop/arg

 Pops first item off the given stack file.  
 Not strict: popping an empty stack is allowed.

 USAGE:
  ./compose.mk io.stack.pop/<fname>
  {.. data ..}
io.stack.push/arg

 Pushes new JSON data onto the named stack-file

 USAGE:
   echo '<json>' | ./compose.mk io.stack.push/<fname>
io.stack/arg

 Returns all the data in the named stack-file 

 USAGE:
  ./compose.mk io.stack/<fname>
  [ {.. data ..}, .. ]
io.tail/arg

 Tails the named file.  Blocking.  Creates file first if necessary.

 USAGE: ./compose.mk io.tail/<fname>
io.time.wait

 Pauses for 1 second.
io.time.wait/arg

Alias for io.wait/

io.user_exit

 Wait for user-input, then exit cleanly.
 This explicitly uses `mk.supervisor.exit`, 
 thus honoring `CMK_AT_EXIT_TARGETS`.
io.wait

 Pauses for 1 second.
io.wait/arg

 Pauses for the given amount of seconds.

 USAGE: ./compose.mk io.time.wait/<int>
io.with.color/arg

 A context manager that paints the given targets output as the given color.
 This outputs to stderr, and only assumes the original target-output was also on stderr.

 USAGE: ( colors the banner red )
  ./compose.mk io.with.color/red,io.figlet/banner
io.with.file/arg

 Context manager.
 Creates a temp-file for the given define-block, then runs the 
 given (unary) target using the temp-file for an argument

 USAGE:
   ./compose.mk io.with.file/<def_name>/<downstream_target>

API: compose



Targets for working with docker compose, without using the compose.import macro.

These targets support basic operations on compose files like 'build' and 'clean', so in some cases scaffolded targets will chain here.


DOCS:

This documentation is pulled automatically from source.

compose.build/arg

 Builds all services for the given compose file.
 This optionally runs for just the given service, otherwise on all services.

 USAGE:
   ./compose.mk compose.build/<compose_file>
   svc=<svc_name> ./compose.mk compose.build/<compose_file>
compose.clean/arg

 Runs `docker compose down` for the given compose file, 
 including reasonable cleanup like --rmi and --remove-orphans, etc.
 This optionally runs on a given service, otherwise on all services.

 USAGE:
   ./compose.mk compose.clean/<compose_file>
   svc=<svc_name> ./compose.mk compose.clean/<compose_file> 
compose.dispatch.sh/arg

 Similar interface to the scaffolded '<compose_stem>.dispatch' target,
 except that this is a backup plan for when 'compose.import' has not
 imported services more directly.

 USAGE: 
   cmd=<shell_cmd> svc=<svc_name> compose.dispatch.sh/<fname>
compose.get.stem/arg

 Returns a normalized version of the stem for the given compose-file.
 (A "stem" is just the basename without a suffix.)

 USAGE:
  ./compose.mk compose.get.stem/<fname>
compose.images/arg

 Returns all images used with the given compose file.
compose.loadf

 Loads the given file,
 then curries the rest of the CLI arguments to the resulting environment
 FIXME: this is linux-only due to usage of MAKE_CLI?

 USAGE:
  ./compose.mk loadf <compose_file> ...
compose.require

 Asserts that docker compose is available.
compose.select/arg

 Interactively selects a container from the given docker compose file,
 then drops into an interactive shell for that container.  

 The container must already have sh or bash.

 USAGE:
  ./compose.mk compose.select/demos/data/docker-compose.yml
compose.services/arg

 Returns space-delimited names for each non-abstract service defined by the given composefile.
 Also available as a macro.

 USAGE:
   ./compose.mk compose.services/demos/data/docker-compose.yml
compose.size/arg

 Returns image sizes for all services in the given compose file,
  i.e. JSON like `{ "repo:tag" : "human friendly size" }`
compose.validate.quiet/arg

 Like `compose.validate`, but silent.
compose.validate/arg

 Validates the given compose file (i.e. asks docker compose to parse it)

 USAGE:
   ./compose.mk compose.validate/<compose_file>
compose.versions/arg

 Attempts to extract version-defaults from the given compose file.
compose.versions_table/arg

 Like `.versions` but returns a markdown table of results 

API: docker


The docker.* targets cover a few helpers for working with docker.

This interface is deliberately minimal, focusing on verbs like 'stop' and 'stat' more than verbs like 'build' and 'run'. That's because containers that re managed by docker compose are preferred, but some ability to work with nlined Dockerfiles for simple use-cases is supported. For an example see the implementation of stream.pygmentize.


DOCS:

This documentation is pulled automatically from source.

docker.build.def/arg

Alias for docker.from.def/

docker.build/arg

 Standard noisy docker build for the given filename.

 For embedded Dockerfiles see instead `Dockerfile.build/<def_name>`
 For remote Dockerfiles, see instead`docker.from.url`

 USAGE:
   tag=<tag_to_use> ./compose.mk docker.build/<name>
docker.clean

 This refers to "local" images.  Cleans all images from 'compose.mk' repository,
 i.e. affiliated containers that are related to the embedded TUI, and certain things
 created by the 'docker.*' targets. No arguments.
docker.commander

 TUI layout providing an overview for docker.
 This has 3 panes by default, where the main pane is lazydocker, 
 plus two utility panes. Automation also ensures that lazydocker 
 always starts with the "statistics" tab open.
docker.context

 Returns all of the available docker context. 
 JSON output, pipe-friendly.
docker.context/arg

 Returns docker-context details for the given context-name.
 Pipe-friendly; outputs JSON from 'docker context inspect'

 USAGE: (shortcut for the current context name)
  ./compose.mk docker.context/current

 USAGE: (using named context)
  ./compose.mk docker.context/<context_name>
docker.def.is.cached/arg

 Answers whether the named define has a cached docker image

 This never fails and exits with "yes" if the image has been
 built at least once, and "no" otherwise, but it also respects
 whether 'force=1' has been set.
docker.def.run/arg

 Builds, then runs the docker-container for the given define-block
docker.def.start/arg

 Starts a container represented by named define-block.
 (This is like docker.run.def but assumes default entrypoint)
docker.dispatch/arg

 Runs the named target inside the named docker container.
 This works for any image as given; See instead 'mk.docker.run' 
 for a version that implicitly uses internally generated containers.
 Also available as a macro.

 USAGE:
  img=<img> make docker.dispatch/<target>

 EXAMPLE:
  img=debian/buildd:bookworm ./compose.mk docker.dispatch/flux.ok
docker.from.def/arg

 Builds a container, treating the given 'define' block as a Dockerfile.
 This implicitly prefixes the named define with 'Dockerfile.' to enforce 
 naming conventions, and make for easier cleanup.  Container tags are 
 determined by 'tag' var if provided, falling back to the name used 
 for the define-block.  Tags are implicitly prefixed with 'compose.mk:',
 for the same reason as the other prefixes.

 USAGE: ( explicit tag )
   tag=<my_tag> make docker.from.def/<my_def_name>

 USAGE: ( implicit tag, same name as the define-block )
   make docker.from.def/<my_def_name>

 REFS:
  [1]: https://robot-wranglers.github.io/compose.mk/#demos
docker.from.file/arg

Alias for docker.build/

docker.from.github

 Helper that constructs an appropriate url, then chains to `docker.from.url`.

 Note that the output tag will not be the same as the input tag here!  See 
 `docker.from.url` for more details.

 USAGE:
  user=alpine-docker repo=git tag="1.0.38" ./compose.mk docker.from.github
docker.from.url

 Builds a container, treating the given 'url' as a Dockerfile.  
 The 'tag' and 'url' env-vars are required.  Note that incoming 
 tags will get the standard repo prefix, i.e. end up as `compose.mk:<tag>`

 See also the docs about supported URL syntax:
  https://docs.docker.com/build/concepts/context/#git-repositories

 FIXME: this currently does not respect 'force'

 USAGE:
   url="<repo_url>#<branch_or_tag>:<sub_dir>" tag="<my_tag>" make docker.from.url
docker.help

 Lists only the targets available under the 'docker' namespace.
docker.host_ip

 Attempts to return the address for the docker host.  
 This is the IP that *containers* can use to contact the host machine from, 
 if the network bridge is setup as usual.  This can be useful for things 
 like testing kind/k3d cluster services from the outside.

 This must run on the host and the details can be *passed* to containers; 
 it will not run inside containers. This  probably does not work outside of linux.
docker.image.dispatch/arg

 Similar to `docker.dispatch/<arg>`, but accepts both the image
 and the target as arguments instead of using environment variables.
 Also available as a macro.

 USAGE:
  ./compose.mk docker.image.dispatch/<img>/<target>
docker.image.entrypoint

 Returns the current entrypoint for the given image.
docker.image.run/arg

 Runs the named image, using the (optional) named entrypoint.
 Also available as a macro.

 USAGE:
   ./compose.mk docker.image.run/<img>,<entrypoint>
docker.image.sizes

 Shows disk-size summaries for all images. 
 Returns JSON like `{ "repo:tag" : "human friendly size" }`
 See `docker.size.summary` for similar column-oriented output
docker.image.stop

 Stops one or more running instances launched from given image.
docker.images

 Returns only affiliated images from 'compose.mk' repository, 
 i.e. containers that are related to the embedded TUI, and/or 
 things created by compose.mk inside the 'docker.*' targets, etc.
 These are "local" images.

 Extensions (like 'k8s.mk') may optionally export a value for 
 'CMK_EXTRA_REPO', which appends to the default list described above.
docker.images.all

 Like plain 'docker images' CLI, but always returns JSON
 This target is also available as a function.
docker.init

 Checks if docker is available, then displays version/context (no real setup)
docker.init.compose

 Ensures compose is available.  Note that
 build/run/etc cannot happen without a file,
 for that, see instead targets like '<compose_file_stem>.build'
docker.lambda/arg

 Similar to `docker.def.run`, but eschews usage of tags 
 and rebuilds implicitly on every single invocation. 

 Note that technically, this is still caching and 
 still actually  involves tags, but the tags are naked SHAs.
docker.logs.follow/arg

 Tails logs for the given container ID.
 This is blocking, and never exits.
docker.logs.timeout/arg

 Like docker.logs.follow, but times out after the given number of seconds.
 USAGE: docker.logs.timeout/<timeout_in_seconds>,<id>
docker.logs/arg

 Tails logs for the given container ID.
 This is non-blocking.
docker.network.panic

 Runs 'docker network prune' for the entire system.
docker.panic

 Debugging only!  This is good for ensuring a clean environment,
 but running this from automation will nix your cache of downloaded
 images, and then you will probably quickly hit rate-limiting at dockerhub.
 It tears down volumes and networks also, so you do not want to run this in prod.
docker.prune

 Debugging only! Runs 'docker system prune' for the entire system.
docker.prune.old

 Debugging only! Runs 'docker system prune --all --force --filter "until=168h"'
docker.ps

 Like 'docker ps', but always returns JSON.
docker.run.def

 Treats the named define-block as a script, then runs it inside the given container.

 USAGE:
  entrypoint=<entry> def=<def_name> img=<image> ./compose.mk docker.run.def
docker.run.sh

 Runs the given command inside the named container.

 This automatically detects whether it is used as a pipe & proxies stdin as appropriate.
 This always shares the working directory as a volume & uses that as a workspace.
 If 'env' is provided, it should be a comma-delimited list of variable names; 
 those variables will be dereferenced and passed into docker's "-e" arguments.

 USAGE:
   img=... entrypoint=... cmd=... env=var1,var2 docker_args=.. ./compose.mk docker.run.sh
docker.run/arg

 Starts the named docker image with the default entrypoint
 USAGE: 
   ./compose.mk docker.start/<img>
docker.size.summary

 Shows disk-size summaries for all images. 
 Returns nl-delimited output like `repo:tag human_friendly_size`
 See `docker.image.sizes` for similar JSON output.
docker.socket

 Returns the docker socket in use for the current docker context.
 No arguments & pipe-friendly.
docker.start

 Like 'docker.run', but uses the default entrypoint.
 USAGE: 
   img=.. ./compose.mk docker.start
docker.start.def/arg

Alias for docker.def.start/

docker.start.tty

 Like `docker.start`, but sets tty=1
docker.start.tty/arg

 Like `docker.start/..`, but sets tty=1
docker.start/arg

Alias for docker.run/

docker.stat

 Show information about docker-status.  No arguments.

 This is pipe-friendly, although it also displays additional
 information on stderr for humans, specifically an abbreviated
 table for 'docker ps'.  Machine-friendly JSON is also output
 with the following schema:

   { "version": .., "container_count": ..,
     "socket": .., "context_name": .. }
docker.stop

 Stops one or more containers, with optional timeout,
 filtering by the given id, name, or image.

 USAGE:
   id=8f350cdf2867 ./compose.mk docker.stop 
   name=my-container ./compose.mk docker.stop 
   name=my-container timeout=99 ./compose.mk docker.stop
   img=debian:latest ./compose.mk docker.stop
docker.stop.all

 Non-graceful stop for all running containers.

 USAGE:
   ./compose.mk docker.stop name=my-container timeout=99
docker.system.prune

 Debugging only! Runs 'docker system prune' for the entire system.
docker.tags.by.repo/arg

 Filters all docker images by the given repository.
 This helps to separate system images from compose.mk images.
 Also available as a function.
 See 'docker.images' for more details.
docker.volume.prune

 Runs 'docker volume prune' for the entire system.

API: Dockerfile


This documentation is pulled automatically from source.

Dockerfile.build/arg

Alias for docker.from.def/

Dockerfile.from.fs/arg

Alias for docker.build/


API: flux


The flux.* targets describe a miniature workflow library. Combining flux with container dispatch is similar in spirit to things like declarative pipelines in Jenkins, but simpler, more portable, and significantly easier to use.


What's a workflow in this context? Shell by itself is fine for what you might call "process algebra", and using operators like &&, ||, | in the grand unix tradition goes a long way. And adding make to the mix already provides DAGs.

What flux.* targets add is flow-control constructs and higher-level join/loop/map instructions over other make targets, taking inspiration from functional programming and threading libraries. Alternatively, one may think of flux as a programming language where all primitives are the objects that make understands, like targets, defines, and variables. Since every target in make is a DAG, you might say that task-DAGs are also primitives. Since compose.import maps containers onto targets, containers are primitives too. Since tux targets map targets onto TUI panes, UI elements are also effectively primitives.

In most cases flux targets are used programmatically for scripting, but in stand-alone mode it can sometimes be useful for cleaning up (external) bash scripts, or porting from bash to makefiles, or ad-hoc interactive scripting.

For parts that are more specific to shell code, see flux.*.sh, and for working with scripts see flux.*.script.


DOCS:

See especially the Platform Setup Example for a more complete walk-through of motivation, starting from an example use-case.

This documentation is pulled automatically from source.

flux.all/arg

 Performs an 'and' operation with the named comma-delimited targets.
 This is equivalent to the default behaviour of `make t1 t2 .. tN`.
 This is mostly used as a wrapper in case arguments are unary, but 
 also has different semantics than default `make`, which ignores 
 duplicate targets as already satisfied.

 USAGE:
   ./compose.mk flux.and/<t1>,<t2>

 See also 'flux.or'.
flux.always/arg

Alias for flux.finally/

flux.and/arg

Alias for flux.all/

flux.any/arg

Alias for flux.or/

flux.apply.later.sh/arg

 Applies the given command at some point in the future.  This is non-blocking.
 Not pipe-safe since targets run in the background, this can garble your display!

 USAGE:
   cmd="..." ./compose.mk flux.apply.later.sh/<seconds>
flux.apply.later/arg

 Applies the given (unary) target at some point in the future.  This is non-blocking.
 Not pipe-safe, because since targets run in the background, this can garble your display!

 USAGE:
   ./compose.mk flux.apply.later/<seconds>/<target>
flux.apply/arg

 Applies the given target to the given argument, comma-delimited.
 In case no argument is given, we assume target is nullary.

 USAGE: ( generic )
   ./compose.mk flux.apply/<target>,<arg>

 USAGE: ( generic )
   ./compose.mk flux.apply/<target>

 USAGE: ( concrete )
   ./compose.mk make flux.apply/flux.echo,THUNK
flux.column/arg

 Exactly flux.pipeline, but splits targets on colons.
flux.context_manager/arg

Alias for flux.with.ctx/

flux.delay/arg

Alias for flux.apply.later/

flux.do.unless/arg

 Runs the 1st target iff the 2nd target fails.
 This is a version of 'flux.if.then', see those docs for more details.

  USAGE: ( generic )
    ./compose.mk flux.do.unless/<umbrella>,<dry>

  USAGE: ( concrete ) 
    ./compose.mk flux.do.unless/flux.ok,flux.fail
flux.do.when/arg

 Runs the 1st given target iff the 2nd target is successful.

 This is a version of 'flux.if.then', see those docs for more details.
 This version is nicer when your "then" target has multiple commas.

  USAGE: ( generic )
    ./compose.mk flux.do.when/<umbrella>,<raining>
flux.each/arg

 Similar to `flux.for.each`, but accepts input on a pipe. 
 This maps the newline/space separated input on to the named (unary) target.
 This works via xargs, runs sequentially, and fails fast.  Also 
 available as a macro.  The named target MUST be parametric so it
 can accept the argument that is passed through!

 USAGE:

  printf 'one\ntwo' | ./compose.mk flux.each/flux.echo
flux.echo/arg

 Simply echoes the given argument.
 Mostly used in testing, but also provided for completeness.. 
 you can think of this as the "identity function" for flux algebra.
flux.fail

 Alias for 'exit 1', which is POSIX failure.
 This is mostly for used for testing other pipelines.

 See also the `flux.ok` target.
flux.finally/arg

 Always run the given target, even if the rest of the pipeline fails.
 See also 'flux.try.except.finally'.

 NB: For this to work, the `always` target needs to be declared at the
 beginning.  See the example below where "<target>" always runs, even
 though the pipeline fails in the middle.

 USAGE:
   ./compose.mk flux.always/<target_name> flux.ok flux.fail flux.ok
flux.for.each/arg

Alias for flux.map/

flux.help

 Lists only the targets available under the 'flux' namespace.
flux.if.then.else/arg

 Standard if/then/else control flow, for make targets.

 USAGE: ( generic )
   ./compose.mk flux.if.then.else/<test_target>,<then_target>,<else_target>
flux.if.then/arg

 Runs the 2nd given target iff the 1st one is successful.

 Failure (non-zero exit) for the "if" check is not distinguished
 from a crash, & it will not propagate.  Only the 2nd argument may contain 
 commas.  For a reversed version of this construct, see 'flux.do.when'

 USAGE: ( generic )
   ./compose.mk flux.if.then/<name_of_test_target>,<name_of_then_target>

 USAGE: ( concrete )
   ./compose.mk flux.if.then/flux.fail,flux.ok
flux.indent.sh

 Similar to flux.indent, but this works with any shell command.

 USAGE:
  cmd="echo foo; echo bar >/dev/stderr" ./compose.mk flux.indent.sh
flux.indent/arg

 Given a target, this runs it and indents both the resulting output for both stdout/stderr.
 See also the 'stream.indent' target.

 USAGE:
   ./compose.mk flux.indent/<target>
flux.joinarg

Alias for flux.mux/

flux.loop.until/arg

 Loop the given target until it succeeds.

 By default to reduce logging noise, this sends stderr to null, but preserves stdout.
 This makes debugging hard, so only use this with well tested/understood sub-targets,
 or set "verbose=1" to allow stderr.  When "quiet=1" is set, even more logging is trimmed.

 USAGE:
flux.loop.watch/arg

 Loops the given target forever, using `watch` instead of the while-loop default.
 This requires `watch` is actually available.
flux.loop/arg

 Helper for repeatedly running the named target a given number of times.
 This requires the 'pv' tool for progress visualization, which is available
 by default in k8s-tools containers.   By default, stdout for targets is
 supressed because it messes up the progress bar, but stderr is left alone.

 USAGE:
   ./compose.mk flux.loop/<times>/<target_name>

 NB: This requires "flat" targets with no '/' !
flux.loopf.quiet.quiet/arg

 Like flux.loopf, but even more quiet.
flux.loopf.quiet/arg

 Loops the given target forever.

 By default to reduce logging noise, this sends stderr to null, but preserves stdout.
 This makes debugging hard, so only use this with well tested/understood sub-targets,
 or set "verbose=1" to allow stderr.  When "quiet=1" is set, even more logging is trimmed.

 USAGE:
   ./compose.mk flux.loopf/
flux.loopf/arg

 Loops the given target forever.
flux.map/arg

 Like `flux.each`, but accepts input as an argument.

 USAGE:
   flux.for.each/flux.echo,hello,world 
   flux.map/flux.echo,hello,world 
flux.match/arg

Alias for flux.star/

flux.mux

 Similar to `flux.parallel`, but actually uses processes directly.  
 See instead that implementation for finer-grained control.

 Runs the given comma-delimited targets in parallel, then waits for all of them to finish.
 For stdout and stderr, this is a many-to-one mashup of whatever writes first, and nothing
 about output ordering is guaranteed.  This works by creating a small script, displaying it,
 and then running it.  It is not very sophisticated!  The script just tracks pids of
 launched processes, then waits on all pids.

 If the named targets are all well-behaved, this *might* be pipe-safe, but in
 general it is possible for the subprocess output to be out of order.  If you do
 want *legible, structured output* that *prints* in ways that are concurrency-safe,
 here is a hint: emit nothing, or emit minified JSON output with printf and 'jq -c',
 and there is a good chance you can consume it.  Printf should be atomic on most
 platforms with JSON of practical size? And crucially, 'jq .' handles object input,
 empty input, and streamed objects with no wrapper (i.e. '{}<newline>{}').

 EXAMPLE: (runs 2 commands in parallel)
   targets="io.time.wait/1,io.time.wait/3" ./compose.mk flux.mux | jq .
flux.mux/arg

 Like `flux.join` but accepts arguments directly.
flux.negate/arg

 Negates the status for the given target.

 USAGE: 
   `./compose.mk flux.negate/flux.fail`
flux.noop

 NO-OP mostly used for testing.  
 Similar to 'flux.ok', but this does not include logging.

 USAGE: 
  ./compose.mk flux.noop
flux.ok

 Alias for 'exit 0', which is success.
 This is mostly for used for testing other pipelines.  

 See also `flux.fail`
flux.or/arg

 Performs an 'or' operation with the named comma-delimited targets.
 This is equivalent to 'make target1 || .. || make targetN'.  See also 'flux.and'.

 USAGE: (generic)
   ./compose.mk flux.or/<t1>,<t2>,..

 USAGE: (example)
   ./compose.mk flux.or/flux.fail,flux.ok
flux.parallel/arg

 Runs the named targets in parallel, using  builtin support for concurrency.

 Similar to `flux.join` but using `make --jobs`, this is fundamentally much more
 tricky to handle than `flux.join`, but also in some ways will allow for 
 finer-grained control.  It probably does not work the way you think, because
 concurrency may affect *more* than the top level targets that are named as 
 arguments.  See [1] for more documentation about that.

 See the `flux.join` docs for some hints about running concurrently but safely 
 producing structured output.  Major caveat: input streams [2] probably cannot be 
 easily or safely used with `flux.parallel`. 

 REFS: 
  [1] https://www.gnu.org/software/make/manual/html_node/Parallel-Disable.html
  [2] https://www.gnu.org/software/make/manual/html_node/Parallel-Input.html
flux.pipe.fork

 Demultiplex / fan-out operator that sends stdin to each of the named targets in parallel.
 This is like `flux.sh.tee` but works with make-target names instead of shell commands.
 Also available as a macro.

 USAGE: (pipes the same input to target1 and target2)
   echo {} | targets="jq,jq" ./compose.mk flux.pipe.fork 
flux.pipe.fork/arg

 Same as flux.pipe.fork, but accepts arguments directly (no variable)
 Stream-usage is required (this blocks waiting on stdin).

 USAGE: ( pipes the same input to yq and jq )
   echo hello-world | ./compose.mk flux.pipe.fork/stream.echo,stream.echo
flux.pipeline.quiet/arg


flux.pipeline.verbose/arg


flux.pipeline/arg

 Runs the given comma-delimited targets in a bash-style command pipeline.
 Besides working with targets and allowing for DAG composition, this has 
 the advantage of giving visibility to the intermediate results.

 There are several caveats though: all targets *must* be pipe safe on stdout, 
 and downstream targets must consume stdin.  Note also that this does not use
 pure streams, and tmp files are created as part of an attempt to debuffer and 
 avoid reordering stderr output.  Error handling is also probably not great!

 USAGE: (example)
   ./compose.mk flux.pipeline/extract,transform,load
    => roughly equivalent to `make extract | make transform | make load`
flux.post/arg

 Dispatch post-hook if one is available
flux.pre/arg

 Dispatch pre-hook if one is available
flux.retry/arg

 Retries the given target a certain number of times.

 USAGE: (using default interval of FLUX_POLL_DELTA)
   ./compose.mk flux.retry/<times>/<target>

 USAGE: (explicit interval in seconds)
   interval=3 ./compose.mk flux.retry/<times>/<target>
flux.select.and.dispatch

 USAGE: 
   pattern='*.mk' dir=demos/ ./compose.mk flux.select.and.dispatch
flux.select.file/arg

 Opens an interactive file-selector using the given dir, 
 then treats user-choice as a parameter to be passed into
 the given target.  

 You can use this to build layered interactions, getting new 
 input at each stage.  See example usage below which first
 chooses a file from `demos/` folder, then uses `mk.select` 
 to choose a target

 USAGE: 
   pattern='*.mk' dir=demos/ ./compose.mk flux.select.file/mk.select
flux.sh.tee

 Helper for constructing a parallel process pipeline with `tee` and command substitution.
 Pipe-friendly, this works directly with stdin.  This exists mostly to enable `flux.pipe.fork`
 but it can be used directly.

 Using this is easier than the alternative pure-shell version for simple commands, but it is
 also pretty naive, and splits commands on commas; probably better to avoid loading other
 pipelines as individual commands with this approach.

 USAGE: ( pipes the same input to 'jq' and 'yq' commands )
   echo {} | cmds="jq,yq" ./compose.mk flux.sh.tee 
flux.split

 Demultiplex / fan-out operator that sends stdin to each of the named targets in parallel.
 This is like `flux.sh.tee` but works with make-target names instead of shell commands.
 Also available as a macro.

 USAGE: (pipes the same input to target1 and target2)
   echo {} | targets="jq,jq" ./compose.mk flux.pipe.fork 
flux.split/arg

 Alias for flux.split, but accepts arguments directly
flux.stage

 Returns the name of the current stage. No Arguments.
flux.stage.clean

 Cleans all stage-files from all runs, including ones that do not belong to this pid!
 No arguments.

 USAGE: ( generic )
  ./compose.mk flux.stage./
flux.stage.clean/arg

 Cleans only stage files that belong to the given stage.

 USAGE: 
   ./compose.mk flux.stage.clean/<stage_name>
flux.stage.enter/arg

 Declares entry for the given stage.
 Stage names are generally target names or similar, no spaces allowed.

 Calling this target prints a pretty divider that makes output easier 
 to parse, but stages also add an idea of persistence to our otherwise 
 pretty stateless workflows, via a file-backed JSON stack object that 
 cooperating tasks can *push/pop* from.

 By default we draw a banner with `io.draw.banner`, but you can override 
 with e.g. `target_banner=io.figlet`, etc.

 USAGE:
  ./compose.mk flux.stage.enter/<stage_name>
flux.stage.exit/arg

 Declares exit for the given stage.
 Calling this is optional but if you do not, stack-files will not be deleted!

 USAGE: ( generic )
  ./compose.mk flux.stage.exit/<stage_name>
flux.stage.file/arg

 Returns the name of the current stage file.

 USAGE: ( generic )
  ./compose.mk flux.stage.file/<stage_name>
flux.stage.pop/arg

 Pops the stack for the named stage.  
 Caller should handle empty value, this will not throw an error.

 USAGE:
   ./compose.mk flux.stage.pop/<stage_name>
   {"key":"val"}
flux.stage.push

 Push the JSON data on stdin into the stack for the implied stage 

 USAGE: ( generic )
  ./compose.mk flux.stage.push
flux.stage.push/arg

 Push the JSON data on stdin into the stack for the named stage.

 USAGE:
   echo '<json_data>' | ./compose.mk flux.stage.push/<stage_name>
flux.stage.stack

 Dumps JSON for all the data on the current stack-file.

 USAGE: ( generic )
  ./compose.mk flux.stage.stack/
flux.stage.stack/arg

 Returns the entire stack given a stack name

 USAGE: ( generic )
  ./compose.mk flux.stage./
flux.stage.wrap

 Like `flux.stage.wrap/<stage>/<target>`, but taking args from env
flux.stage.wrap/arg

 Context-manager that wraps the given target with stage-enter 
 and stage-exit.  It only accepts one stage at a time, but can
 easily be combined with `flux.wrap` for multiplem targets.

 USAGE: ( generic )
  ./compose.mk flux.stage.wrap/<stage>/<target>

 USAGE: ( concrete )
  ./compose.mk flux.stage.wrap/MAIN/flux.ok
flux.stage/arg

Alias for flux.stage.enter/

flux.star/arg

 Runs all targets in the local namespace matching given pattern

 USAGE: (run all the test targets)
   make -f project.mk flux.star/test.
flux.starmap/arg

 Based on itertools.starmap from python, 
 this accepts 2 targets called the "function" and the "iterable".
 The iterable is nullary, and the function is unary.  The "function"
 target will be called once for each result of the "iterable" target.
 Iterable *must* return newline-separated data, usually one word per line!

 USAGE: ( generic )
  ./compose.mk flux.starmap/<fn>,<iterable>
flux.stream.obliviate/arg

 Runs the given target, consigning all output to oblivion
flux.timeout.sh

 Runs the given command for the given amount of seconds, then stops it with TERM.
 Exit status is ignored

 USAGE: (tails docker logs for up to 10s, then stops)
   ./compose.mk flux.timeout.sh cmd='docker logs -f xxxx' timeout=10

 FIXME: use timeout(1) ?
flux.timeout/arg

 Runs the given target for the given number of seconds, then stops it with TERM.

 USAGE:
   ./compose.mk flux.timeout/<seconds>/<target>
flux.timer/arg

 Emits run time for the given make-target in seconds.

 USAGE:
   ./compose.mk flux.timer/<target_to_run>
flux.try.except.finally/arg

 Performs a try/except/finally operation with the named targets.
 See also 'flux.finally'.

 USAGE: (generic)
  ./compose.mk flux.try.except.finally/<try_target>,<except_target>,<finally_target>

 USAGE: (concrete)
  ./compose.mk flux.try.except.finally/flux.fail,flux.ok,flux.ok
flux.try.except/arg

 Performs a try/except operation with the named targets.
 This is just `flux.try.except.finally` where `finally` is `flux.noop`.

 USAGE: (generic)
  ./compose.mk flux.try.except/<try_target>,<except_target>
flux.try.finally/arg

 Performs a try/finally operation with the named targets.
 This is just `flux.try.except.finally` where `except` is `flux.noop`.

 USAGE: (generic)
  ./compose.mk flux.try.finally/<try_target>,<finally_target>
flux.with.ctx/arg

 Runs the given target, using the given namespace as a context-manager

 USAGE: 
  ./compose.mk flux.ctx/<target>,<ctx_name>

 Roughly equivalent to `compose.mk <ctx_name>.enter <target> <ctx_name>.exit`
flux.wrap/arg

 Same as `flux.and` except that it accepts commas or colon-delimited args.
 You can use this to disambiguate targets that need to have "," reserved.

 This performs an 'and' operation with the named targets, equivalent to the
 default behaviour of `make t1 t2 .. tN`.  Mostly used as a wrapper in case
 targets are unary

API: mk


The 'mk.*' targets are meta-tooling that include various extensions to make itself, including some support for reflection and runtime changes.

A rough guide to stuff you can find here:

  • mk.supervisor.* for signals and supervisors

  • mk.def.* for tools related to reading 'define' blocks

  • mk.parse.* for makefile parsing (used as part of generating help)

  • mk.help.* for help-generation


DOCS:

This documentation is pulled automatically from source.

mk.__main__

 Runs the default goal, whatever it is.
 We need this for use with the supervisor because 
 usage of `mk.supervisor.enter/<pid>` is ALWAYS present,
 and that overrides default that would run with an empty CLI.
mk.assert.env/arg

 Asserts that the (comma-delimited) environment variables are set and non-empty.
 Also available as a macro.
mk.compile

 This is a transpiler for the CMK language -> Makefile.
 Accepts streaming CMK source on stdin, result on stdout.
 Quiet by default, pass quiet=0 to preview results from intermediate stages.

 USAGE:
  echo "<source_code>" | ./compose.mk mk.compiler
mk.compile/arg

 Like `mk.compile`, but accepts file as argument instead of using stdin.
mk.compiler

 This is a transpiler for the CMK language -> Makefile.
 Accepts streaming CMK source on stdin, result on stdout.
 Quiet by default, pass quiet=0 to preview results from intermediate stages.

 USAGE:
  echo "<source_code>" | ./compose.mk mk.compiler
mk.compiler/arg

Alias for mk.compile/

mk.def.dispatch/arg

 Reads the given <def_name>, writes to a tmp-file,
 then runs the given interpreter on the tmp file.

 This requires that the interpreter is actually available..
 for dockerized access to similar functionality, see `docker.run.def`

 USAGE:
   ./compose.mk mk.def.dispatch/<interpreter>,<def_name>

 HINT: for testing, use 'make mk.def.dispatch/cat,<def_name>'
mk.def.read/arg

 Reads the named define/endef block from this makefile,
 emitting it to stdout. This works around normal behaviour 
 of completely wrecking indention/newlines and requiring 
 escaped dollar-signs present inside the block.  
 Also available as a macro.

 USAGE:
   ./compose.mk mk.read_def/<name_of_define>
mk.def.to.file/arg

 Reads the given define/endef block from this makefile context, 
 writing it to the given output file. Also available as a macro.

 USAGE: ( explicit filename for output )
   ./compose.mk mk.def.to.file/<def_name>/<fname>

 USAGE: ( use <def_name> as filename )
   ./compose.mk mk.def.to.file/<def_name>
mk.docker

 Like `mk.docker/..` but expects `img` argument is available from environment.
mk.docker.dispatch/arg

 Like `docker.run` but insists that image is "local" or internally 
 managed by compose.mk, i.e. using the  "compose.mk:" prefix.
 Also available as a macro.
mk.docker.image/arg

Alias for mk.docker/

mk.docker.prune

 Like `docker.prune` but only covers "local" images internally 
 managed by compose.mk, i.e. using the  "compose.mk:" prefix.
mk.docker.run.sh

 Like docker.run.sh, but implicitly assumes the 'compose.mk:' prefix.
mk.docker/arg

 Like `docker.image.run`, but automatically adds the `compose.mk:` prefix.
 This is used with "local" images that are managed by compose.mk itself, 
 e.g. embedded images that are built with `Dockerfile.build/..`, etc.
mk.fork.guest

 Like `mk.fork.guest`, but with streaming input.
mk.fork.guest/arg

 Forks this source code, returning modified version on stdout.
 This rewrites the contents of the current "guest" section.
mk.fork.payload

 Like `mk.fork.payload`, but with streaming input.
mk.fork.payload/arg

 Forks this source code, returning modified version on stdout.
 This rewrites the contents of the current "guest" section.
mk.fork.services

 Like `mk.fork.services`, but with streaming input.
mk.fork.services/arg

 Forks this source code, returning modified version on stdout.
 This rewrites the contents of the default services section.
mk.fork/arg

 USAGE: ./compose.mk mk.fork/<Makefile>,<composefile>
 Like `mk.fork.guest/1st` followed by `mk.fork.services/2nd`
mk.get/arg

 Returns the value of the given make-variable
mk.help

 Lists only the targets available under the 'mk' namespace.
mk.help.block/arg

 Shows the help-block matching the given pattern.
 Similar to module-docs, but this need not match a target namespace.

 USAGE: ./compose.mk mk.help.block/<pattern>
mk.help.module/arg

 Shows help for the named module.
 USAGE: ./compose.mk mk.help.module/<mod_name>
mk.help.search/arg

 Shows all targets matching the given prefix.

 USAGE:
   ./compose.mk mk.help.search/<pattern>
mk.help.target/arg

 Shows rendered help for the named target.

 USAGE: ./compose.mk mk.help.target/<target_name>
mk.ifdef/arg

 Answers whether the given variable is defined.
 This is silent, and only communicates via the exit code.
mk.ifndef/arg

 Flips the assertion for 'mk.ifdef'.
mk.include/arg

 Dynamic includes. Experimental stuff for reflection support.

 This works by using code-generation and turning over the execution, 
 so it requires the supervisor/signals hack to short-circuit the 
 original execution!

 USAGE: ( generic )
   ./compose.mk mk.include/<makefile>

 USAGE: ( concrete )
   ./compose.mk mk.include/demos/no-include.mk foo:flux.ok mk.let/bar:foo bar
mk.interpret

 This is similar to `mk.include`, and (simulates) changes to the `make` runtime.
 It is mostly intended to be used as shebang, and essentially sets up `compose.mk` 
 as an alternative to using `make` as an interpreter.  By opting in to this, 
 extensions can inherit not only `compose.mk` code, but also the signals / supervisors. 

 See `mk.interpret!` for a version of this that does preprocessing.
 See https://robot-wranglers.github.io/compose.mk/signals/ for more information.

 USAGE:
  ./compose.mk mk.interpret path/to/Makefile <target> .. <target> 
mk.interpret!

 Like `mk.interpret`, but runs CMK preprocessing/transpilation step first. 

 USAGE: 
   ./compose.mk mk.interpret! <fname>
mk.interpret/arg

 A version of `mk.interpret` that accepts file-args.

 USAGE: ./compose.mk mk.interpret/<fname>
mk.interrupt

 The default interrupt.  This is shorthand for mk.interrupt/SIGINT
mk.interrupt/arg

Alias for mk.supervisor.interrupt/

mk.kernel

 Executes the input data on stdin as a kind of "script" that 
 runs inside the current make-context.  This basically allows
 you to treat targets as an instruction-set without any kind 
 of 'make ... ' preamble.

 USAGE: ( concrete )
  echo flux.ok | ./compose.mk kernel
  echo flux.and/flux.ok,flux.ok | ./compose.mk kernel
mk.let/arg

 Dynamic target assignment.
 This is experimental stuff for reflection support.

 This is basically a hack to work around the dreaded error 
 that "recipes may not define targets".  It should probably 
 be regarded as black magic that is best avoided!  

 This works by using code-generation and turning over the execution, 
 so it requires the supervisor/signals hack to short-circuit the 
 original execution!

 USAGE: ( generic )
   ./compose.mk mk.let/<newtarget>:<oldtarget>

 USAGE: ( concrete )
   ./compose.mk mk.let/foo:flux.ok mk.let/bar:foo bar
mk.namespace.filter/arg

 Lists all targets in the given namespace, filtering them by the given pattern.
 Simple, pipe-friendly output.  
 WARNING:  Callers must anticipate parametric targets with percent-signs, i.e. "foo.bar/%"

 USAGE: ./compose.mk mk.namespace.filter/<namespace>
mk.namespace.list

 Returns only the top-level target namespaces
 Pipe-friendly; stdout is newline-delimited target prefixes.
mk.parse.block/arg

 Pulls out documentation blocks that match the given pattern.

 USAGE:
  pattern=.. ./compose.mk mk.parse.block/<makefile>

 EXAMPLE:
   pattern='*Keybindings*' make mk.parse.block/compose.mk
mk.parse.local

 Returns only local targets for the current Makefile, ignoring includes
 Output of `mk.parse.shallow/` for the current val of MAKEFILE.
mk.parse.module.docs/arg

 Parses the given Makefile, returning module-level documentation.

 USAGE:
  pattern=.. ./compose.mk mk.parse.module.docs/<makefile>
mk.parse.shallow/arg

Alias for mk.targets/

mk.parse.targets

 Returns only local targets for the current Makefile, ignoring includes
 Output of `mk.parse.shallow/` for the current val of MAKEFILE.
mk.parse.targets/arg

 Parses the given Makefile, returning target-names only. Simple, pipe-friendly output. 
 Also available as a macro.  
 WARNING: Callers must anticipate parametric targets with percent-signs, i.e. "foo.bar/%"

 USAGE: 
   ./compose.mk mk.parse.targets/<file>
mk.parse/arg

 Parses the given Makefile, returning JSON output that describes the targets, docs, etc.
 This parsing is "deep", i.e. it returns docs & metadata for *included* targets as well.
 This uses a dockerized version of the pynchon[1] tool.

 REFS:
   * `[1]`: https://github.com/elo-enterprises/pynchon/
mk.pkg

 Like `mk.self`, but includes `compose.mk` source also.
mk.pkg.root

 Packages the application root, or the given command if provided.
mk.pkg/arg

 Packages the given make target as a single-file executable.

 This works by using to `makeself` to bundle/freeze/release 
 a self-extracting archive where we include the current Makefile, 
 and try to automatically include any related dependencies.

 To add other explicit deps to the archive, set `archive` 
 as a space-separated list of files or directories.

 USAGE:
  archive="file1 file2 dir1" make -f ... mk.pkg/<target_name>
mk.preprocess

 Runs the CMK input preprocessor on stdin.
mk.preprocess.decorators

 Runs the decorator-preprocessor on stdin.
 NB: This must come before sugar/dialects.
mk.preprocess.dialect

 Runs dialect preprocessor on stdin.
 Part of the CMK->Makefile transpilation process.
mk.preprocess.minify

 Assuming stdin is makefile source, minifies it and outputs to stdout
mk.preprocess.sugar

 Runs sugar-preprocessor on stdin.
 Part of the CMK->Makefile transpilation process.
mk.preprocess/arg

 A version of `mk.preprocess` that accepts a file-arg.

 USAGE: ./compose.mk mk.preprocess/<fname>
mk.reconn/arg

 Runs makefile in dry-run / reconn mode 
mk.require.tool/arg

 Asserts that the given tool is available in the environment.
 Output is only on stderr, but this shows whereabouts if it is in PATH.
 If not found, this exits with an error.  Also available as a macro.
mk.run/arg

 A target that runs the given makefile.
 This uses `make` directly and naively, NOT using the current context.
mk.select

 Interactive target selection / runner for the local Makefile
mk.select.local

 Interactive target selection / runner for the local Makefile
mk.select/arg

 Interactive target-selector for the given Makefile.
 This uses `gum choose` for user-input.
mk.self

 An interface to a dockerized version of the `makeself` tool.[1]

 You can use this to create self-extracting executables.  
 Required arguments are only accepted as environment variables.

 Set `archive` as a space-separated list of files or directories. 
 Set `script` as the script that will run inside the archive.
 Set `bin` as the name of the executable you want to create. 

 Optionally set `label`.  This is displayed at runtime, 
 after rehydrating the archive but before the script runs.

 USAGE:
  archive=<dirname> label=<label> bin=<bin_name> script="pwd; ls" ./compose.mk mk.self

 [1]: https://makeself.io/
mk.set/arg

 Setter for make variables, available as a target. 
 This is experimental stuff for reflection support.

 USAGE: ./compose.mk mk.set/<key>/<val>
mk.src

 Returns source-code for this make-context (excluding compose.mk).
 This effectively flattens includes, basically concatenating 
 MAKEFILE_LIST in reverse order, and is used internally as part 
 of mk.compile.  This has a different meaning if called from extensions
mk.stat

 Shows version-information for make itself  & compose.mk

 USAGE: ./compose.mk mk.stat
mk.supervisor.enter/arg

 Unconditionally executed by the supervisor program, prior to main pipeline. 
 Argument is always supervisors PPID.  Not to be confused with 
 the supervisors pid; See instead 'mk.supervisor.pid'
mk.supervisor.exit/arg

 Unconditionally executed by the supervisor program after main pipeline, 
 regardless of whether that  pipeline was successful. Argument is always 
 the exit-status of the main pipeline.
mk.supervisor.interrupt

 The default interrupt.  This is shorthand for mk.interrupt/SIGINT
mk.supervisor.interrupt/arg

 Sends the given signal to the process-tree supervisor, then kills this process with SIGKILL.

 This is mostly used to short-circuit  default command-line processing
 so that targets can be greedy about consuming the *whole* CLI, rather than 
 having make try to interpret everything as additional targets.

 This can be used without a supervisor process wrapping 'make', 
 but in that case the exit status is *always* failure, and there 
 is *always* an error that the user has to know they should ignore.

 To correct for exit status/error output, you will have to have a supervisor. 
 See the polyglot-wrapper at the top of this file for more info, and see 
 the 'mk.supervisor.*' namespace for handlers invoked by that supervisor.
mk.supervisor.pid

 Returns the pid for the supervisor process which is responsible for trapping signals.
 See 'mk.interrupt' docs for more details.
mk.supervisor.trap/arg

 Executed by the supervisor program when the given signal is trapped.
mk.targets

 Returns only local targets for the current Makefile, ignoring includes
 Output of `mk.parse.shallow/` for the current val of MAKEFILE.
mk.targets.filter.parametric/arg

 Filters all parametric targets by the given pattern.
mk.targets.filter/arg

 Lists all targets in the given namespace, filtering them by the given pattern.
 Simple, pipe-friendly output.  
 WARNING:  Callers must anticipate parametric targets with percent-signs, i.e. "foo.bar/%"

 USAGE: ./compose.mk mk.targets.filter/<namespace>
mk.targets.local

 Returns only local targets for the current Makefile, ignoring includes
 Output of `mk.parse.shallow/` for the current val of MAKEFILE.
mk.targets.parametric

 This finds only the parametric targets in the current namespace.

 Note that targets like 'foo/%:' are automatically converted to simply 'foo', 
 which makes this friendly for use with stuff like `flux.starmap`, etc.
mk.targets.simple/arg

 Returns only local targets from the given file, 
 excluding parametric targets, and ignoring included targets.
mk.targets/arg

 Returns only local targets from the given file, ignoring includes.
 Returns a newline-delimited list of targets inside the given Makefile.
 Unlike `mk.parse`, this is "flat" and too naive to parse targets that come 
 via includes.  Targets starting with "." are considered private, and 
 ommitted from the return value.
mk.validate

 Validates whether the input stream is legal Makefile
mk.validate/arg

 Validate the given Makefile (using `make -n`)
mk.vars

 Lists all the variables known to Make, including local or 
 inherited env-vars, make-vars, make-defines etc. 
 This target is also available as a macro.
mk.vars.filter/arg

 Filter output of `mk.vars` with the given pattern.
 Non-strict; no error in case of no-match.

API: stream


The stream.* targets support IO streams, including basic stuff with JSON, newline-delimited, and space-delimited formats.

General purpose tools:

  • For conversion, see stream.nl.to.comma, stream.comma.to.nl, etc.

  • For JSON ops, see stream.jb[2] and stream.json.append.*, etc

  • For formatting and printing, see stream.dim.*, etc.


Macro Equivalents:

Most targets here are also available as macros, which can be used

as an optimization since it saves a process.

# For example, from a makefile, these are equivalent commands:

echo "one,two,three" | ${stream.comma.to.nl}

echo "one,two,three" | make stream.comma.to.nl

DOCS:

This documentation is pulled automatically from source.

stream.as.log

 A dimmed, indented version of the input stream sent to stderr.
 See `stream.indent` for a version that works with stdout.
 Note that this consumes the input stream.. see instead 
 `stream.peek` for a version with pass-through.
stream.chafa

 Given an image file on stdin, this shows a preview on the console. 
 Under the hood, this works using a dockerized version of `chafa`.

 USAGE: ( generic )
   > cat docs/img/docker.png | ./compose.mk stream.img.preview
stream.code

 A version of `io.preview.file` that works with streaming input.
 Uses pygments on the backend; pass style=.. lexer=.. to override.
stream.comma.to.json

 Converts comma-delimited input into minimized JSON array

 USAGE:
   > echo 1,2,3 | ./compose.mk stream.comma.to.json
   ["1","2","3"]
stream.comma.to.nl

 Converts comma-delimited input stream to newline-delimited output.
 Also available as a macro.

 USAGE: 
   > echo 'foo,bar' | ./compose.mk stream.comma.to.nl
   foo
   bar
stream.comma.to.space

 Converts comma-delimited input stream to space-delimited output
stream.csv.pygmentize

 Highlights the input stream as if it were a CSV.  Pygments actually
 does not have a CSV lexer, so we have to fake it with an awk script.  

 USAGE: ( concrete )
   echo one,two | ./compose.mk stream.csv.pygmentize
stream.dim

 Pipe-friendly helper for dimming the input text.  

 USAGE:
   $ echo "logging info" | ./compose.mk stream.dim
stream.dim.indent

 Like 'io.print.indent' except it also dims the text.
stream.echo

 Just echoes the input stream.  Mostly used for testing.  See also `flux.echo`.

 EXAMPLE:
   echo hello-world | ./compose.mk stream.echo
stream.fold

 Uses fold(1) to wrap the input stream to the given width, 
 defaulting to current terminal width if nothing is provided.
 Also available as a macro.
stream.glow

 Renders markdown from stdin to stdout.
stream.help

 Lists only the targets available under the 'stream' namespace.
stream.img

 Given an image file on stdin, this shows a preview on the console. 
 Under the hood, this works using a dockerized version of `chafa`.

 USAGE: ( generic )
   > cat docs/img/docker.png | ./compose.mk stream.img.preview
stream.img.preview

 Given an image file on stdin, this shows a preview on the console. 
 Under the hood, this works using a dockerized version of `chafa`.

 USAGE: ( generic )
   > cat docs/img/docker.png | ./compose.mk stream.img.preview
stream.indent

 Indents the input stream to stdout.  Also available as a macro.
 For a version that works with stderr, see `stream.as.log`
stream.indent.to.stderr

 Shortcut for ' .. | stream.indent | stream.to.stderr'
stream.ini.pygmentize

 Highlights input stream using the 'ini' lexer.
stream.jb

 Interface to jb[1].  You can use this to build JSON on the fly.
 Also available as macro.

 USAGE:
   $ echo foo=bar | ./compose.mk stream.jb
   {"foo":"bar"}

 REFS:
   `[1]:` https://github.com/h4l/json.bash
stream.json.append

 Appends the given key/val to the input object.
 This is usually used to build JSON objects from scratch.

 USAGE:
     > echo {} | key=foo val=bar ./compose.mk stream.json.object.append
   {"foo":"bar"}
stream.json.array.append

 Appends <val> to input array

 USAGE:
   > echo "[]" | val=1 ./compose.mk stream.json.array.append | val=2 make stream.json.array.append
   [1,2]
stream.json.object.append

 Appends the given key/val to the input object.
 This is usually used to build JSON objects from scratch.

 USAGE:
     > echo {} | key=foo val=bar ./compose.mk stream.json.object.append
   {"foo":"bar"}
stream.json.pygmentize

 Syntax highlighting for the JSON on stdin.
stream.lstrip

 Left-strips the input stream.  Also available as a macro.
stream.markdown

 Renders markdown from stdin to stdout.
stream.nl.enum

 Enumerates the newline-delimited input stream, zipping index with values

 USAGE:
   > printf "one\ntwo" | ./compose.mk stream.nl.enum
        0   one
        1   two
stream.nl.to.comma


stream.nl.to.json.array

  Converts newline-delimited input stream into a JSON array
stream.nl.to.space

 Converts newline-delimited input stream to space-delimited output.
 Also available as a macro.

 USAGE: 
   $ echo '\nfoo\nbar' | ./compose.mk stream.nl.to.space
   > foo bar
stream.peek

 Prints the entire input stream as indented/dimmed text on stderr,
 Then passes-through the entire stream to stdout.  Note that this uses
 a tmpfile because proc-substition seems to disorder output.

 USAGE:
   echo hello-world | ./compose.mk stream.peek | cat
stream.preview

 Sends input stream to stderr.
 Unlike 'stream.peek', this does not pass on the input stream.
stream.pygmentize

 Syntax highlighting for the input stream.
 Lexer will be autodetected unless override is provided.
 Style defaults to 'monokai', which works best with dark backgrounds.
 Also available as a macro.

 USAGE: (using JSON lexer)
   > echo {} | lexer=json ./compose.mk stream.pygmentize

 REFS:
 [1]: https://pygments.org/
 [2]: https://pygments.org/styles/
stream.space.enum

 Enumerates the space-delimited input list, 
 zipping indexes with values in newline delimited output.

 USAGE: 
   printf one two | ./compose.mk stream.space.enum
      0 one
      1 two
stream.space.to.nl

 Converts a space-separated stream to a newline-separated one
stream.strip

 Pipe-friendly helper for stripping whitespace.
stream.to.docker/arg

 This is a work-around because some interpreters require files and can not work with streams.

 USAGE: ( generic )
   echo ..code.. | ./compose.mk stream.to.docker/<img>,<optional_entrypoint>

 USAGE: ( generic, as macro )
   ${mk.def.read}/<def_name> | ${stream.to.docker}/<img>,<optional_entrypoint>
stream.to.stderr

 Sends input stream to stderr.
 Unlike 'stream.peek', this does not pass on the input stream.
stream.yaml.to.json

 Converts yaml to JSON

The stream.* targets support IO streams, including basic stuff with JSON, newline-delimited, and space-delimited formats.

General purpose tools:

  • For conversion, see stream.nl.to.comma, stream.comma.to.nl, etc.

  • For JSON ops, see stream.jb[2] and stream.json.append.*, etc

  • For formatting and printing, see stream.dim.*, etc.


Macro Equivalents:

Most targets here are also available as macros, which can be used

as an optimization since it saves a process.

# For example, from a makefile, these are equivalent commands:

echo "one,two,three" | ${stream.comma.to.nl}

echo "one,two,three" | make stream.comma.to.nl

DOCS: