π Bask in the convenience of a task runner for bash
Bask is a task runner for Bash. It's like Make with a bunch of shell targets,
but without the .PHONY
's everywhere, and nicer because there's no more Make
syntax. The main difference is that tasks are always run in Bask, but only run
if targets are out of date in Make.
If you're writing a Makefile with all .PHONY
targets, chances are that Bask is
really what you want.
Bask was initially forked from bash-task-runner. It was forked for a couple reasons:
- I needed to vendor it for an unrelated project.
- I wanted to drop the dependency on GNU coreutils.
- I wanted to improve the name π
I actively follow upstream changes. If I'm missing a compatible feature that was added upstream, feel free to notify me via an issue, pull request, or message on Gitter.
Bask's first commit is a squashed version of bash-task-runner
at the time it
was forked. For a complete list of changes, just use the commit log.
Each of the below installation methods is differentiated along two properties:
- Local to project
- Whether Bask will be installed locally to your project or globally on a system.
- This is good for CI builds and spinning up multiple people on your project
- CLI-enabled
- Whether you will be able to use the
bask
command from your prompt. - Useful for local development, tab completion, and convenience.
- Whether you will be able to use the
You may want to combine multiple installation methods in order to satisfy both of these requirements. In particular, we recommend Simple (vendored) with a method that gives you a CLI and is compatible with your system.
Local to Project | CLI-enabled | |
---|---|---|
Simple (vendored) | β | π« |
Submodule (vendored) | β | β |
Homebrew | π« | β |
NPM | β | β |
Git + PATH | π« | β |
Currently Bask requires Bash 4.2+.
Just drop src/bask.sh
anywhere in your project folder:
wget https://raw.githubusercontent.com/jez/bask/master/src/bask.sh
Then skip to Usage for how to use a vendored Bask installation.
If you'd like a slightly better story around updating Bask when vendored, you can use a Git submodule, if you're familiar with submodules:
git submodule add https://github.com/jez/bask
Note that if submodules are too heavy-handed, you can get the same effect (without the ease of updating) by just unzip'ing Bask's source into your project.
You should now be able to access bask.sh
within the submodule. Additionally,
you can access the CLI with ./bask/bin/bask
. You can make this more ergonomic
by altering your PATH:
export PATH="$PATH:./bask/bin"
Then skip to Usage to learn more.
On OS X, installing Bask globally is simple if you have Homebrew:
brew install jez/formulae/bask
Then skip to Usage to learn more.
If you don't mind the additional dependency on the NPM ecosystem, you can install Bask with NPM:
# --- Local to Project --- #
npm install --save bask
# to enable CLI:
export PATH="PATH:./node_modules/.bin"
# --- Global --- #
npm install -g bask
Then skip to Usage to learn more.
If Bask is not available in a package manager for your system, you can clone Bask to your computer, and adjust your PATH to contain the installation location:
git clone https://github.com/jez/bask
export PATH="$PATH:$(pwd)/bask/bin"
Then skip to Usage for how to use the CLI.
You use Bask in conjunction with a Baskfile
. A basic Baskfile
looks like
this:
task_foo() {
## Do something...
}
task_bar() {
## Do something...
}
Optional: if you want your Baskfile
to be a standalone script, add this
to the beginning (works best in conjunction with a vendored installation):
#!/usr/bin/env bash
cd "$(dirname "$0")" || exit
source ./path/to/bask.sh
You invoke Bask using bask [task ...]
:
$ bask foo bar
[21:37:43.754] Starting 'foo'
[21:37:43.755] Finished 'foo' after 1 ms
[21:37:43.756] Starting 'bar'
[21:37:43.757] Finished 'bar' after 1 ms
Or, if your Baskfile
sources bash.sh
:
bash Baskfile foo bar
NOTE: Please see bask -h
for complete, up-to-date CLI usage information.
Usage: bask [options] [task] [task_options] ...
Options:
-C <dir>, --directory=<dir> Change to <dir> before doing anything.
--completion=<shell> Output code to activate task completions.
Supported shells: 'bash'.
-f <file>, --file=<file> Use <file> as a Baskfile.
-l, --list-tasks List available tasks.
-h, --help Print this message and exit.
All flags you pass after the task names are passed to your tasks.
task_foo() {
echo ${@}
}
$ bask foo --production
--production
To pass options to the bask
CLI specifically, you must provide them
before any task names:
$ bask -f scripts/tasks.sh foo
The bask
CLI supports autocompletion for task names (bash only). Simply add
the following line your ~/.bashrc
:
eval $(bask --completion=bash)
This section covers all the features of Bask.
Your Baskfile can be named any of the following. Using a .sh
suffix helps with
things like editor syntax highlighting.
Baskfile
Baskfile.sh
baskfile
baskfile.sh
You can specify a default task in your Baskfile. It will run when no arguments are provided. There are two ways to do this:
task_default() {
# do something ...
}
bask_default_task="foo"
task_foo() {
# do something ...
}
Bask exposes a number of functions for manipulating dependencies among tasks, for logging, and for a few utilities.
Alias:
bask_sequence
This function is for declaring dependencies of a task. It should be invoked within another task.
Usage: bask_depends [task ...]
task_default() {
bask_depends foo bar
# Output:
# [21:50:33.194] Starting 'foo'
# [21:50:33.195] Finished 'foo' after 1 ms
# [21:50:33.196] Starting 'bar'
# [21:50:33.198] Finished 'bar' after 2 ms
}
If any task return non-zero, the entire sequence of tasks is aborted with an error.
Note that return codes can be bubbled up using ... || return
, so you can
conveniently abort tasks prematurely like this:
maybe_error() {
return $(($RANDOM % 2))
}
task_try() {
echo "Bad"
maybe_error || return # <-- bubbles error up if error
# code for when no error
}
task_finally() {
echo "Good"
}
task_foo() {
bask_depends try finally
}
Alias:
bask_parallel
Bask also allows for spawning independent work in parallel, and resuming the task when all tasks have completed:
Usage: bask_fork_join [task ...]
task_default() {
bask_fork_join sleep3 sleep5
bask_log "after"
# [21:50:33.194] Starting 'sleep3'
# [21:50:33.194] Starting 'sleep5'
# [21:50:36.396] Finished 'sleep3' after 3.20 s
# [21:50:38.421] Finished 'sleep5' after 5.23 s
# [21:50:38.422] after
}
Note that all tasks always run to completion, unlike with bask_depends
.
This will log a timestamp plus the command with its arguments, then run it.
Usage: bask_run <command --with args>
Note that the command must be a simple command--things like pipes, &&
, ||
,
{ ... }
, etc. will not work.
You can log information inside Bask tasks using one of the five bask_log
helpers:
Function | Description |
---|---|
bask_log |
Adds a log line (with time), in the foreground color |
bask_log_success |
Same as above, but in green |
bask_log_error |
Same as above, but in red |
bask_log_warning |
Same as above, but in yellow |
bask_log_info |
Same as above, but in cyan |
bask_log_debug |
Same as above, but in gray |
Usage: bask_log message
All logging functions have the same usage.
While the dedicated logging functions are helpful, sometimes you want finer control over your colors.
Usage: bask_colorize <colorname> message
Where colorname
is one of
black | gray | light_gray | white | ||
red | green | yellow | blue | purple | cyan |
light_red | light_green | light_yellow | light_blue | light_purple | light_cyan |
# Simple example
bask_colorize purple This will all be purple
# Use with `bask_log` to get a timestamp:
bask_log "$(bask_colorize purple This will all be purple)"
Note that your message will be wrapped with the appropriate color and reset codes. You don't need to worry about manually turning the color back to normal.
The default behavior if no tasks are specified at the command line and no default tasks are registered is to list all available tasks. You can manually invoke that with this function.
Usage: bask_list_tasks
task_list() {
bask_list_tasks
}
Utility function for checking whether a list of tasks are defined. Used internally, but exposed externally.
Usage: bask_is_task_defined [task ...]
Note that you can pass in more than one task for checking.
Alternatively, you can use bask_is_task_defined_verbose
, which will do the
same checks, but log an error if any task is not defined.
Bask was forked from bash-task-runner. Chances are that if you have an issue or pull request it can be made against that upstream repo.
If your issue pertains to functionality specifically only provided here, then feel free to voice your concerns here. If you're confused where to make the request, feel free to ask in Gitter first.
GNU Lesser General Public License v3 (LGPL-3.0). See License.md
Copyright (c) | Commits |
---|---|
Aleksej Komarov | 8a28f72 |
Jake Zimmerman | 5e92344+ |