Drivers¶
Drivers are resposible for executing, listing and providing help for tasks. The driver defines the format and filename for a task file. By default, the only driver included in Bash Task Master is the bash driver. Built-in tasks and modules use the bash driver.
See below on how to implement a driver to support different file formats.
Drivers are managed by the built-in driver module.
Note
Disabling a driver is non destructive. Driver files remain in place but the filename association is temporarily removed. This is so that if you want to re-enable a driver, it does not redownload the assets.
Bash Driver¶
The bash driver is used whenever a task file is named tasks.sh or .tasks.sh. As the name implies, it is implemented in bash and the task file is a bash script. Arguments and tasks are defined in bash functions which are loaded by the main task function.
Tasks¶
Tasks in a bash task file are created as functions with the task_ prefix in the tasks.sh file.
Anything after task_ is treated as the task name:
# Example tasks.sh file
# run with task clean
task_clean() {
...
}
# run with task check_all
task_check_all() {
...
}
Arguments¶
Each argument given to a task is loaded into the task as an ARG_ variable.
By default, any long argument, i.e. one that starts with a --, is loaded with the same name as it was given on the command line.
For example, running task hello --foo bar would run the task_hello function with ARG_FOO=bar.
Specifying Arguments¶
Arguments can be defined in an arguments_TASKNAME function.
This function should be loaded alongside the task definition, i.e. inside the same tasks.sh file.
The variables inside this function are used to parse and validate the arguments before the task function is run.
The following variables are supported in arguments functions:
| Variable Name | Description | Example |
|---|---|---|
SUBCOMMANDS |
a | delimited list of subcommands. |
SUBCOMMANDS="sign|clean|init" |
[COMMAND]_DESCRIPTION |
help string for a COMMAND or SUBCOMMAND | BUILD_DESCRIPTION="Build the project" |
[COMMAND]_REQUIREMENTS |
required arguments for a COMMAND or SUBCOMMAND. | INIT_REQUIREMENTS="out:o:str dir:d:str" |
[COMMAND]_OPTIONS |
arguments for a COMMAND or SUBCOMMAND | CLEAN_OPTIONS="f:force:bool" |
Note that DESCRIPTION, REQUIREMENTS and OPTIONS can be used with a command AND/OR a subcommand.
REQUIREMENTS and OPTIONS are written as lists of space delimited argument specifications that are of the form: long-arg:short-arg:arg-type.
The long-arg of the argument specifies the flag to be used with -- and also denotes the portion of the ARG_ variable in the tasks.
The short-arg is the flag to be used with - (single dash).
The arg-type specifies what type the argument is. See below for available types.
Example
┌─ these are optional arguments
│
COMPOSE_OPTIONS="name:n:int host:h:ip iterations:i:int"
│ │ │
Can be specified by --name ─┘ │ └─ Will fail if not an integer
│
Can be specified by -n ┘
The above specification specifies that the compose command has 3 optional arguments: --name or -n, --host or -h, --iterations or -i.
In the task we could access these values as ARG_NAME, ARG_HOST and ARG_ITERATIONS respectively.
Note
All dashes (-) in subcommands and arguments are converted to underscores (_).
i.e. task thing --my-way 100 would have ARG_MY_WAY=100.
Arguments Example¶
If the following arguments are defined for the build task:
arguments_build() {
SUBCOMMANDS="help|frontend|backend|all"
FRONTEND_REQUIREMENTS="out:o:str in:i:str"
FRONTEND_OPTIONS="VERBOSE:v:bool LINT:L:bool DIR:d:str"
BACKEND_REQUIREMENTS="PID:P:int"
BACKEND_OPTIONS="VERBOSE:v:bool BUILD-FIRST:B:bool"
}
Then all of the following calls would succeed:
task build frontend --out outdir --in infile
task build frontend --out outdir --in infile --lint --verbose
task build frontend -o outdir -i infile -L -v
task build all
task build backend --pid 123
task build backend -P 123
task build backend -vBP 123
task build frontend -Lo outdir -vi infile
But none of the following:
task build frontend # Missing required arguments
task build frontend --in infile --lint --verbose # Unknown argument --in
task build backend -P 12 -v garbage # Verbose is not a bool
Supported Argument Types¶
Available types are as follows:
| Type | Identifier | Description |
|---|---|---|
| String | str | A string of characters, can pretty much be anything. |
| Integer | int | An integer |
| Boolean | bool | An argument that is either T if present or an empty string if not* |
| Word | nowhite | A string with no whitespaces |
| Uppercase | upper | An uppercase string |
| Lowercase | lower | A lowercase string |
| Single Char | single | A single character* |
All types, except for bool, require that a value is given.
With bool arguments, the argument being present automatically sets the ARG_VAR.
Note that short arguments can be combined to one combined argument, e.g -vBP, but only the last can be a non bool.
Note
A single character may be confused as a boolean at validation time. If a value for a single character argument is left out, it will be set to "1"
Custom Drivers¶
Task drivers are determined by the filename of the task file. The tasks.sh and .task.sh filenames are associated with the bash_driver. A custom driver needs to have a unique name for it's task file.
The way that the task runner switches between drivers is by loading different sets of functions for executing, listing and providing help on tasks.
The following variables indicate what command or function to run when processing a task file.
| Variable Name | Arguments | Description |
|---|---|---|
| DRIVER_EXECUTE_TASK | $@ | Executes a task. Gets passed all of the arguments to the task function. |
| DRIVER_HELP_TASK | TASK_COMMAND | Shows the help for the given command. |
| DRIVER_LIST_TASKS | TASKS_FILE | Lists the available tasks in the given task file. Outputs a space or newline separated list of tasks. The list is used to verify that the task is defined. |
| DRIVER_VALIDATE_TASK_FILE | TASKS_FILE | Validates a that the given task file is readable by the driver. |
Different languages may be used to implement custom drivers but the driver must define these variables to interface with the execution environment.
The following driver file would define an alternative bash driver that doesn't do anything with arguments and just executes hello, world, foo and bar tasks:
DRIVER_EXECUTE_TASK=execute_task
DRIVER_HELP_TASK=not_helpful
DRIVER_LIST_TASKS=acceptable_tasks
DRIVER_VALIDATE_TASK_FILE=noop
noop() {
return 0
}
execute_task() {
task_$1
}
not_helpful() {
echo rtfd
}
acceptable_tasks() {
echo "hello world foo bar"
}
Installing a Custom Driver¶
Note
These steps only apply to drivers you develop locally. See repositories for information on how to do this automatically with a repository.
After the source for a driver is added to the $TASK_MASTER_HOME/lib/drivers/ directory, the $TASK_MASTER_HOME/lib/drivers/installed_drivers.sh file must be updated with the filename that should be associated with the driver.
For example, if I wanted to install a driver for a task file named .task-master.py I would need to add the following to the driver_defs.sh file:
TASK_FILE_NAME_DICT[.task-master.py]=my_driver
TASK_DRIVER_DICT[my_driver]=my_driver.sh
where my_driver.sh is the filename of the driver in the $TASK_MASTER_HOME/lib/drivers/ directory.