The groan framework is a basis for building complex hierarchical CLI interfaces with bash and other languages, and aspires to achieve this with some degree of elegance, through hierarchical composition.
/ɡrəʊn/
noun
- the noise that emits from programmers forced to code in bash.
Groan is a simple extensible bash framework (similar to sub)
for creating a suite of scripts that have similar command, sub-command usage style to git/bzr/hg/docker etc.
Clone this repository, and rename 'groan' to be the top level name of YOUR command.
Add your scripts (in any language) and help topics, to the commands folder.
Your command can be nested within other commands, or you can compose your command from others.
Pick and choose modules from the commands/, setup-tool/, and
tests/ folders that you wish to include in your command.
Roll your own gitlike command suites, complete with help-documentation help-topics. Support for standard options like --debug, --quiet is also included.
Groan is recursively merge-able/compose-able. Assemble a named suite of sub-command scripts in a folder, that folder may be made available alongside, or nested as sub-commands within another suite.
Sub-commands in one folder can act as dispatchers into another folder's command suite, following the
<name>.sub.<target>.cmd.<entry>.sh naming convention.
Fork keithy/groan to yourrepo/yourcommand then create your working branch with the name of your new command. To contibute your command back submit a pull-request.
This incarnation of groan was conceived in about 2009, in 2017 I used 'sub' extensively and then fed that experience back into groan (in 2018), rather than port existing groan based projects.
- Is recursively composeable and mergeable
- Is simpler than sub
- Sub-commands provide usage and documentation
- Support for additional documentation topics/reporting
- Demonstrates simple implementation conventions and patterns (e.g. options handling)
- Adopts the informal bash "strict" mode which considerably aids debugging.
- Supports dynamic Bash autocompletion (via
---completionorsetup self-install).
- supports default option flags (--verbose --quiet --help +debug --dry-run --confirm +groan-debug)
- default means for platform determination
- finds sub-commands via a configurable search path (allows local overides)
- finds config files via a configurable search path
- reads a config file (to set environment vars) before running sub-commands
- sub-commands may be written in any shell or language
- sub-commands may have metadata for help
- sub-commands can run as source, exec, or eval
- help included provides:
--list— list sub-commands of the current level--all— recursively list every sub-command in every reachable sub-command suite, with descriptions
The framework has debug levels prefixed with + to separate internal developer diagnostics from command options. They can be combined.
+D/+debug— user-level debug. SetsDEBUG=trueandVERBOSE=true. Most sub-commands check this to print extra detail.+DD/+ddebug/+deep-debug— developer deep debug. For sub-command code that distinguishes user vs developer traces.+GD/+groan-debug— groan's own trace. SetsGDEBUG=trueand turns on verbose mode. Logs the dispatcher scanning (Scanning for test*.cmd.* in: ...), the result of each match (Found #1 : ... : ...), and the path taken when sourcing sub-commands. Useful when a sub-command isn't being found.+CD/+config-debug— config-file trace. SetsCDEBUG=trueand turns on verbose mode. Logs the config-file search path (Custom1? $PWD/groan.conf,Config < $PWD/config/other.conf, etc.) so you can see which.conffiles are considered and which one is sourced. Combine with+GDto see both at once.+XD/+bash-debug—set -xtrace. Prints every command as bash executes it. Very noisy; use only when you need the full command trace.
Groan (sub)commands are called after having:
- processed and filtered out the standard set of flags.
- --verbose -V
- +debug +D
- --quiet
- --dry-run # enabled by default
- --confirm # disables --dry-run flag for destructive operations
- +ddebug +DD # developer debug
- found and 'sourced' a config-file.
- found and 'sourced' metadata (if separate).
Setup, environment discovery, and lifecycle management have moved into the setup sub-suite:
groan setup environment --origin: inspect repository remote origin URLgroan setup update: pull latest code and submodules or update data librariesgroan setup self-install: configure shell aliases, autocompletions, or PATH symlinks
Groan includes built-in dynamic tab completion for Bash.
To output the completion script for your shell configuration:
eval "$(groan ---completion)"Or append it to your ~/.bashrc / ~/.bash_profile:
groan ---completion >> ~/.bashrcRunning groan setup self-install --completion --confirm automatically registers autocompletion bindings in ~/.bash_profile.
When <TAB> is pressed, Bash delegates completion to groan via an internal ---AUTOCOMPLETE hook:
- Dynamically resolves nested sub-commands and dispatcher suites (e.g.
groan setup <TAB>). - Completes flag options (e.g.
--config=,--theme=,--debug). - Generates completions for available config names when typing
--config=<TAB>.
Groan looks for config files in a number of places. The set of
locations is set in the <exe>.conf file (or by overriding
g_config_file_locations directly).
"$g_home/$c_file.conf" # --local
"$HOME/.config/<context_name>/default.conf" # --user
Sub-commands are files in commands/ whose names encode how the
framework should invoke them. The extension after the last . selects
the dispatch mode:
<name>.cmd.sh—sourcethe file in the current shell<name>.cmd.conf—sourcethe file as a metadata-only conf (no body run)<name>.cmd.exec—execthe file as a new process<name>.cmd.su—sudothen run the file<name>.cmd.ps1— run the file under PowerShell<name>.cmd.<ext>— any other extension iseval'd; the file is resolved viarealpathand must live underg_subcmd_locations[]for safety
Non-shell scripts can supply their help metadata via <name>.cmd.conf
without the file being executable.
A sub-command in one folder can alias to a sub-command suite in another folder. The naming convention is:
<X>.sub.<Y>.cmd.<Z>.<ext>
Where <X> is the alias name, <Y> is the destination command suite,
and <Z> is the entry sub-command to pass to that suite. The framework
recognises *.sub.*.cmd.* as a dispatcher pattern and follows the
alias when --all recurses.
For example, commands/nested.sub.nested.cmd.sh in the parent suite
makes groan nested invoke ./nested/nested with no argument.
Help topics are user-facing documentation files that you can place anywhere
on g_locations[]. They are text files with the extension .topic.txt or
.topic.md; the basename (without .topic.<ext>) is the topic name.
Commands are implemented expecting that they may be run with the METADATAONLY flag, in which case they populate variables and exit prior to doing anything:
$s_description$s_usage
-EXIT=env
prints out the environment variables (or evaluates a given expression) in the context of where scripts ran
A number of template conf files can be provided, the user can choose a file and a place to install it. Out of the box, local, user and global config options are provided
./groan setup configure --options
Available options:
1) local config : /Users/coding/wip/groan.conf
2) user config : /Users/bob/.groan.conf
3) global config : /Users/bob/.local/bin/groan/groan.conf
Available templates:
default.conf (preset)
Install configuration with:
./groan setup configure --install=local default.conf
groan setup self-install --link /usr/local/bin --confirm
A dispatcher script named <X>.sub.<Y>.cmd.<Z>.<ext> aliases sub-command <X> to
the <Y> command suite, passing <Z> as the entry sub-command. Place such a
script in the parent's commands/ folder; the framework recognises the
*.sub.*.cmd.* pattern and follows the dispatcher when recursing.
The comprehensive test suite is here https://gitlab.com/keithy/groan-dev using the bash-spec framework.