diff --git a/README.md b/README.md index 229ef15..ba86a55 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/cli.sh b/cli.sh index 26cbe15..a0f3754 100755 --- a/cli.sh +++ b/cli.sh @@ -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 # @@ -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,,} @@ -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 @@ -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" @@ -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" diff --git a/commands/hello-world.sh b/commands/hello-world.sh index 26e55d9..6228527 100644 --- a/commands/hello-world.sh +++ b/commands/hello-world.sh @@ -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!" diff --git a/docs/CLI.md b/docs/CLI.md index 31aaf6a..d830411 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -10,6 +10,8 @@ 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. @@ -17,6 +19,7 @@ The command script in the `commands` directory will be sourced by the top-level 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.