Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ So this could be useful for any project which wants to ship a single entrypoint
## Docs

[Read the CLI docs for more information on how commands works.](docs/CLI.md)

[Read the Tests docs for more information on how to write tests.](docs/Tests.md)

## Using this template in your project
Expand Down
28 changes: 18 additions & 10 deletions cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@ set -u

# Simple CLI wrapper that discovers scripts in the commands/ directory

# Cd to the directory of this script, so it can be run from anywhere
# Get the directory of this script, so it can be run from anywhere
realpath="$(realpath "$0")" || { echo "Failed to get realpath"; exit 1; }
cd "${realpath%/*}" || { echo "Failed to cd to script directory"; exit 1; }

# `CLIROOT` is the directory of the cli script.
# Commands are run from the directory the user is in,
# use `$CLIROOT` to cd to the directory of the cli script.
CLIROOT="${realpath%/*}"

# `CMDROOT` absolute path to commands directory.
CMDROOT="$CLIROOT/commands"

####################
# Helper functions #
Expand Down Expand Up @@ -58,8 +65,8 @@ BLUE="\e[34m"

# Build commands list from commands/*.sh (lowercased, without .sh)
commands=()
if [ -d "commands" ]; then
for f in commands/*.sh; do
if [ -d "$CMDROOT" ]; then
for f in "$CMDROOT"/*.sh; do
[ -f "$f" ] || continue
name=$(basename "$f" .sh)
name_lc=${name,,}
Expand Down Expand Up @@ -90,7 +97,7 @@ if [ "$CMD" = "list" ]; then

for c in "${commands[@]}"; do
desc=""
helpfile="commands/${c}.help.txt"
helpfile="$CMDROOT/${c}.help.txt"
if [ -f "$helpfile" ]; then
IFS= read -r desc < "$helpfile" || true
fi
Expand All @@ -100,14 +107,15 @@ if [ "$CMD" = "list" ]; then
fi

if [ "$CMD" = "help" ] || [ "$CMD" = "--help" ]; then
if [ -z "$1" ]; then
if [ "$#" -eq 0 ]; then
echo "Display help for a command."
echo "Usage: help [command]"
exit 0
fi
target=${1,,}
if command_exists "$target" && [ -f "commands/${target}.help.txt" ]; then
cat "commands/${target}.help.txt"
helpfile="$CMDROOT/${target}.help.txt"
if command_exists "$target" && [ -f "$helpfile" ]; then
cat "$helpfile"
exit 0
fi
echo "No help available for $target"
Expand All @@ -121,5 +129,5 @@ if ! command_exists "$CMD"; then
fi

# Source the script matching CMD
# shellcheck source=/dev/null
. "commands/${CMD}.sh"
# shellcheck disable=SC1090
source "$CMDROOT/$CMD.sh"
6 changes: 6 additions & 0 deletions commands/hello-world.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ echo "Hello world!"

# Examples of using the helper functions to print messages.

# You can cd to the directory of the cli script using `$CLIROOT`
cd "$CLIROOT" || error "Failed to cd to CLIROOT: $CLIROOT"
# You can also cd to the commands directory using `$CMDROOT`
cd "$CMDROOT" || error "Failed to cd to CMDROOT: $CMDROOT"
# However, these are optional, commands (and helper functions) will work without needing to change directory.

# You can check if a command exists and do something
command_exists "hello-world" && echo "hello world exists!"

Expand Down
3 changes: 3 additions & 0 deletions docs/CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ Running `cli.sh` or `cli.sh list` will then show the newly created command.

When running `cli.sh` followed by the name of the command, the shell script for the command will be sourced as is. This means that commands do not need to use any specific functions to run.

Note that `cli.sh` does not change the directory, running `pwd` from a command script will show the directory the user is in. Variables are provided to get the directory of the CLI script and commands.

## Writing the command script

The command script in the `commands` directory will be sourced by the top-level `cli.sh` script when the command is run, this means that the script should be written procedurally.

Scripts should be written following these best practices:
* Start with `#!/usr/bin/env bash`
* Do not write any usage or help functions within the script, instead use a `.help.txt` file, see the next section for more details.
* Commands are ran from the user's current directory, use `$CLIROOT` to get the directory of the cli script, and `$CMDROOT` to get the directory containing the command script. For example, use `cd "$CLIROOT"` to change to the directory of the cli script.
* Use `$CMD` to get the name of the command being run. All positional arguments have been shifted, so `$1` is not the name of the command, instead it is the first argument passed after the name of the command. Checking if `$#` is `0` is a quick way to know if the user provided any additional arguments.
* To check if a command exists, use the `command_exists` function, for example `command_exists "hello-world"` will return `0` if `hello-world` is a command, otherwise `1`.
* To print error, warning and success messages, use the functions `error`, `warning` and `success`, all arguments passed to these will be printed.
Expand Down
Loading