basf is a minimalist framework to write command line applications under the umbrella of the basf command, organized in modules and with a simple and unique interface.
The typical invocation of basf on the command prompt is:
$ basf <module> <action> [options...]The simplest way to bootstrap the application is to simply source the basf main file basf
#!/bin/bash
source /path/to/basf/basfA module is a container that organizes a set of related commands - the actions.
From the user perspective, the call of a module and it's action is similar to call a command on the command line. But instead of grouping several related commands loosely by a similar name, a module groups this commands into the same namespace.
In addition to the actions a module provides typically other common information, such a description and a help.
Bash and therefore modules supports inheritance and each module automatically
inherits from default.bsl module (it is located in the libs/ directory).
Actions are functions that can be called by the user. Or if you think OOP, then you can also say that these are the public methods of your modules.
Within a module a normal bash function is an action if it starts with
the prefix do_. A action can request any parameter like every other function
within the $@ variable and that works as expected. I.e. every value after
<action> is passed as a parameter to the action.
There are also some predefined actions. These are:
- usage
- version
- help
These actions do what they obviously should do. You can overwrite this actions but usually there is no good reason to do it.
The default implementation of these functions can be found in
libs/default.bsl.
There are several ways to control the behavior when the module was called without specifying an action.
First, there is the default behavior. If nothing else works, then the function
do_help is called. This function is already defined in the base file and
therefore pretty sure available.
The first way to change this behavior is to set another default action
using DEFAULT_ACTION as described above.
The second, not recommended, way is the most obvious - overwrite the do_help function.
A third possibility is to implement the __module function.
By default, an error is thrown when the requested action was not found.
However, if a function __action exists, then this function is called instead.
Notice that this function is called for all unknown actions, but not if no action is specified at all. For that case look at the default action section.
The following variables are optional.
-
DESCRIPTIONDescription of this module. Defaults empty
-
DEFAULT_ACTIONThe default action of the module if none is given. Defaults to
help -
VERSIONThe version of this module. Defaults to
0.1.0 -
HIDDENMODULEHide this module in the module overview if set to 1. Defaults to 0
Parameters to an action are defined in the describe_<action>_parameters
function.
describe_has_parameters() {
echo "<module>"
}Parameters are accessed via the ${@} variables.
Parameters are displayed in the help.
Extra actions:
has <module> Return true if the module or alias is installed, otherwise false.
Options of an action are defined in the describe_<action>_options function
using the make_option function.
describe_list_options() {
make_option --name "only_names" --long "only-names" --short "n" --desc "Output names of modules only"
make_option --name "all" --long "all" --short "a" --desc "Do not omit hidden modules"
}Options are displayed in the help.
Extra actions:
list List all available modules
-n --only-names Output names of modules only
-a --all Do not omit hidden modules
Options are accessed within the the action with has_option
if has_option "only_names" $@; then
# optional code here...
fiCurrently only flag options are supported. Options with parameters are covered in #16
Sometimes it can be useful to hide actions from the help page. To hide an action
define a hide_<action> function that returns a zero exit code.
Aliases are lightweight modules that are used without actions. Aliases make use
of the __module function defined in the alias.bsl library.
Aliases are defined by declaring the variables ALIAS_MODULE and ALIAS.
By inheriting the alias library the __module function and the help action
are defined.
-
ALIAS_MODULEDefines the module the alias is a shortcut for. This is only used for the help.
-
ALIASThe module, action, parameters and options of the alias. Will be invoked in the __modules function.
Other module configurations like DESCRIPTION, VERSION and HIDDENMODULE are
available. However, DEFAULT_ACTION cannot be used as the __module function
is used.
Libraries are used to group reusable functions. Libraries are devined in .bsl files in the library directories.
To use a library in a module load it using the inherit function.
inherit config tests output
There are several predefined libraries as described below
aliasconfigcoredefaultenvironmentgitoutputtests
The alias library is used for aliases that are defined using the ALIAS_MODULE
and ALIAS variables.
Library functions for working with configuration files.
-
read_config_valueLoad the value for key
keyfrom a configuration filefile.Parameters:
- file The file to read from
- key The key
Note:
The configuration file must be a valid bash script, that is, the file must be loadable with
source $file.
Core contains functions used by the basf core. The core library is not intended to be used in modules.
The default library is the 'base class' for modules. Here default actions and default module behavior is defined.
The environment library provides functions to query the application's environment.
-
environment_platformEchoes the platform provided by
uname. Examples are 'linux' or 'mingw64'. -
environment_is_rootReturns zero if the application is called with root privileges, non-zero otherwise.
Provides helpful functions related to git.
environment_platformgit_current_branchgit_tracking_branchgit_changesgit_has_empty_indexgit_has_clean_stagegit_has_untracked_filesgit_has_unstagedgit_wc_rootgit_editorgit_pager
The output library provides functions for colored and structured output
Colored and highlighted lines:
write_boldwrite_bold_redwrite_norm_redwrite_bold_greenwrite_norm_greenwrite_bold_yellowwrite_norm_yellowwrite_bold_bluewrite_norm_bluewrite_bold_magentawrite_norm_magentawrite_bold_cyanwrite_norm_cyanwrite_bold_whitewrite_norm_whitewrite_norm_highlightwrite_bold_highlight
Centered blocks with a fixed width containing a fixed word. Call with any argument to add brackets:
write_block_donewrite_block_okwrite_block_skipwrite_block_fail
Prefixed messages:
write_error_msgwrite_warning_msgwrite_info_msgwrite_info_msg
Lists:
write_list_start- Write a list headline. If -p is passed, the output is forced to plain.write_kv_list_entry- Write a key/value list entry with $1 on the left and $2 on the right.write_numbered_list_entry
Padding:
Echo the $text with at least $count characters. If width of $text is shorter
than $count characters, then the missing characters are padded by spaces.
lfill $text $count- pads leftrfill $text $count- pads right
The tests library provides simple tests:
-
is_number -
is_function -
has_no_option $@Returns zero if the current action was called with no options, non-zero otherwise.
-
has_option <name of the option> $@Returns zero if the current action was called with the give option, non-zero otherwise.
Global scope code is forbidden in modules, aliases and libraries.
Your module will be sourced for tasks other than running your actions. For example, your module will be sourced to obtain the description. Any code being run here would be a very bad thing!
BASF_BINARY_FILEPATH
Specifies the filepath to the application's main file as entry points for subscripts. Defaults to ${0}. Should not be changed.
BASF_PROGRAM_VERSION
The Application's version. Defaults to basf's version.
BASF_PROGRAM_NAME
The name of the application. Defaults to basename ${BASF_BINARY_FILEPATH}
BASF_CUSTOM_LIB_PATH
Additional path for libs. See libs for details
BASF_CUSTOM_MODULE_PATH
Additional path for modules. See modules for details
BASF_CUSTOM_ALIASES_PATH
Additional path for aliases. See aliases for details
There are three types of directories:
libs- The library directoriesmodules- The module directoriesaliases- The alias directories
All types of directories will be looked up as subdirectories of these directories in this order:
"${HOME}/.${BASF_PROGRAM_NAME}""${HOME}/.basf""${BASF_PROGRAM_ROOT}""${BASF_ROOT}""/usr/share/${BASF_PROGRAM_ROOT}""/usr/share/basf""/usr/local/share/${BASF_PROGRAM_ROOT}""/usr/local/share/basf""/opt/${BASF_PROGRAM_ROOT}""/opt/basf"
The modules/libs/aliases found in directories higher in the list take precedence.
BASF comes with dynamic completion (currently for bash only).
This command will create a completion script for bash:
<basf program name> completion bashTo use completion in the shell add this to .bashrc:
source <( <basf program name> completion bash)