Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
notheotherben committed Dec 6, 2016
1 parent d3b0863 commit 49df702
Show file tree
Hide file tree
Showing 23 changed files with 372 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Bash CLI
**A command line framework built using nothing but Bash and compatible with anything**

Bash CLI was borne of the need to provide a common entrypoint into a range of scripts
and tools for a project. Rather than port the scripts to something like Go or Python,
or merge them into a single bash script, we opted to build a framework which allows
and executable to be presented as a sub-command.

## Example

```sh
bash-cli install my-app
bash-cli command create start
my-app start
```
1 change: 1 addition & 0 deletions app/.author
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Benjamin Pannell
1 change: 1 addition & 0 deletions app/.bash_cli
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v1
9 changes: 9 additions & 0 deletions app/.help
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
This is a demonstration application which makes use of Bash CLI
to present its interface.

You can place any scripts here and Bash CLI will automatically make
them available, you can also add <command>.help files to provide contextual
help information for individual commands.

Directories allow you to create tree based command hierarchies and you
can add a .help file to each directory to describe what that tree does.
1 change: 1 addition & 0 deletions app/.name
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bash CLI
1 change: 1 addition & 0 deletions app/.version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.0
4 changes: 4 additions & 0 deletions app/command/.help
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Tools to manage commands in a Bash CLI project.

This includes things like creating new commands, removing existing
commands and opening their various files for editing.
50 changes: 50 additions & 0 deletions app/command/create
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash

if [ $# == 0 ]; then
exit 3
fi

APP_DIR=`pwd`
if [[ -d "$APP_DIR/app" && -f "$APP_DIR/app/.bash_cli" ]]; then
APP_DIR="$APP_DIR/app"
fi

if [[ ! -f "$APP_DIR/.bash_cli" ]]; then
>&2 echo -e "\e[31mYou are not within a Bash CLI project\e[39m"
>&2 echo "Please change your directory to a valid project or run the init command to set one up."
exit 1
fi

CMD_DIR="$APP_DIR"

if [[ $# -gt 1 ]]; then
for i in $(($#-1)); do
DIR=${!i}
CMD_DIR="$CMD_DIR/$DIR"
if [[ ! -d "$CMD_DIR" ]]; then
mkdir "$CMD_DIR"
echo "TODO: Add help for this directory" > "$CMD_DIR/.help"
fi
done
fi

CMD_NAME="${!#}"
if [[ -f "$CMD_DIR/$CMD_NAME" ]]; then
>&2 echo -e "\e[31mThat command already exists\e[39m"
>&2 echo "We'd rather not overwrite commands you've already created."
exit 1
fi

cat > "$CMD_DIR/$CMD_NAME" <<EOT
#!/usr/bin/env bash
echo -e "\e[36mTODO\e[39m: Implement this command"
EOT

echo "ARGS..." > "$CMD_DIR/$CMD_NAME.usage"
cat > "$CMD_DIR/$CMD_NAME.help" <<EOT
ARGS - The arguments you wish to provide to this command
TODO: Fill out the help information for this command.
EOT

echo -e "\e[32mCommand \e[36m$@\e[32m created successfully\e[39m"
8 changes: 8 additions & 0 deletions app/command/create.help
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
COMMAND - The full name of the command you wish to create.
Example: new command

This will create the files required to fully describe a command
to Bash CLI, specifically the <command>, <command>.usage and
<command>.help files. The correct directory structure to host
the command will be created, and .help files will be created
at each directory level.
1 change: 1 addition & 0 deletions app/command/create.usage
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
COMMAND
42 changes: 42 additions & 0 deletions app/command/rm
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env bash

if [ $# == 0 ]; then
exit 3
fi

APP_DIR=`pwd`
if [[ -d "$APP_DIR/app" && -f "$APP_DIR/app/.bash_cli" ]]; then
APP_DIR="$APP_DIR/app"
fi

if [[ ! -f "$APP_DIR/.bash_cli" ]]; then
>&2 echo -e "\e[31mYou are not within a Bash CLI project\e[39m"
>&2 echo "Please change your directory to a valid project or run the init command to set one up."
exit 1
fi

CMD_DIR="$APP_DIR"

if [[ $# -gt 1 ]]; then
for i in $(($#-1)); do
DIR=${!i}
CMD_DIR="$CMD_DIR/$DIR"
if [[ ! -d "$CMD_DIR" ]]; then
exit 0
fi
done
fi

CMD_NAME="${!#}"
if [[ -f "$CMD_DIR/$CMD_NAME" ]]; then
rm -f "$CMD_DIR/$CMD_NAME"
rm -f "$CMD_DIR/$CMD_NAME.help"
rm -f "$CMD_DIR/$CMD_NAME.usage"
elif [[ -d "$CMD_DIR/$CMD_NAME" ]]; then
rm -Rf "$CMD_DIR/$CMD_NAME"
else
echo -e "\e[31mCommand \e[36m$@\e[31m did not exist\e[39m"
exit 1
fi

echo -e "\e[32mCommand \e[36m$@\e[32m successfully removed\e[39m"
5 changes: 5 additions & 0 deletions app/command/rm.help
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
COMMAND - The full name of the command you wish to remove.

This will remove the specified command and all its related
files. It will clobber directories if you provide one instead
of a specific command, so be careful!
1 change: 1 addition & 0 deletions app/command/rm.usage
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
COMMAND
22 changes: 22 additions & 0 deletions app/install
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash

if [ $# == 0 ]; then
exit 3
fi

APP_DIR=`pwd`

if [[ -f "$APP_DIR/.bash_cli" ]]; then
APP_DIR=`dirname "$APP_DIR"`
fi

if [[ ! -f "$APP_DIR/app/.bash_cli" ]]; then
>&2 echo -e "\e[31mYou are not within a Bash CLI project\e[39m"
>&2 echo "Please change your directory to a valid project or run the init command to set one up."
exit 1
fi

NAME="$1"
FOLDER="${2-"/usr/bin"}"

ln -s "$APP_DIR/cli" "$FOLDER/$NAME"
8 changes: 8 additions & 0 deletions app/install.help
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
NAME - The name you would like to use for your commands
Example: my-app
FOLDER - (Optional) The directory you would like the command line installed to
Default: /usr/bin
Example: /usr/sbin

Installs your command line app under the given name by creating a symlink
to the Bash CLI proxy.
1 change: 1 addition & 0 deletions app/install.usage
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NAME [FOLDER]
36 changes: 36 additions & 0 deletions app/uninstall
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash

if [ $# == 0 ]; then
exit 3
fi

APP_DIR=`pwd`

if [[ -f "$APP_DIR/.bash_cli" ]]; then
APP_DIR=`dirname "$APP_DIR"`
fi

if [[ ! -f "$APP_DIR/app/.bash_cli" ]]; then
>&2 echo -e "\e[31mYou are not within a Bash CLI project\e[39m"
>&2 echo "Please change your directory to a valid project or run the init command to set one up."
exit 1
fi

NAME="$1"
FOLDER="${2-"/usr/bin"}"

if [[ ! -f "$FOLDER/$NAME" ]]; then
>&2 echo -e "\e[31mCommand \e[36m$1\e[31m did not exist in \e[36m$2\e[39m"
exit 1
fi

LN_PATH=`perl -e 'use Cwd "abs_path"; print abs_path(shift)' "$FOLDER/$NAME"`

if [[ "$LN_PATH" != "$APP_DIR/cli" ]]; then
>&2 echo -e "\e[31mCommand \e[36m$1\e[31m doesn't resolve to this project\e[39m"
>&2 echo "Expected: $APP_DIR/cli"
>&2 echo "Got: $LN_PATH"
exit 1
fi

rm "$FOLDER/$NAME"
10 changes: 10 additions & 0 deletions app/uninstall.help
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
NAME - The name you would like to use for your commands
Example: my-app
FOLDER - (Optional) The directory you would like the command line installed to
Default: /usr/bin
Example: /usr/sbin

Removes an installed Bash CLI command line app by removing the symlink to it.
This command will only work within the directory of the project which created
the symlink originally, and only if the same arguments provided to install
are provided again.
1 change: 1 addition & 0 deletions app/uninstall.usage
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NAME [FOLDER]
53 changes: 53 additions & 0 deletions cli
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env bash

ROOT_DIR=`dirname "$(perl -e 'use Cwd "abs_path"; print abs_path(shift)' $0)"`
CLI_ENTRYPOINT=`basename $0`

. "$ROOT_DIR/utils"

# Locate the correct command to execute by looking through the app directory
# for folders and files which match the arguments provided on the command line.
CMD_FILE="$ROOT_DIR/app/"
CMD_ARG_START=1
while [[ -d "$CMD_FILE" && $CMD_ARG_START -le $# ]]; do

# If the user provides help as the last argument on a directory, then
# show them the help for that directory rather than continuing
if [[ "${!CMD_ARG_START}" == "help" ]]; then
"$ROOT_DIR/help" $0 ${@:1:$(($CMD_ARG_START-1))}
exit 3
fi

CMD_FILE="$CMD_FILE/${!CMD_ARG_START}"
CMD_ARG_START=$(($CMD_ARG_START+1))
done

# If we hit a directory by the time we run out of arguments, then our user
# hasn't completed their command, so we'll show them the help for that directory
# to help them along.
if [ -d "$CMD_FILE" ]; then
"$ROOT_DIR/help" $0 $@
exit 3
fi

# If we didn't couldn't find the exact command the user entered then warn them
# about it, and try to be helpful by displaying help for that directory.
if [[ ! -f "$CMD_FILE" ]]; then
"$ROOT_DIR/help" $0 ${@:1:$(($CMD_ARG_START-1))}
>&2 echo -e "\e[31mWe could not find the command \e[36m$CLI_ENTRYPOINT ${@:1:$CMD_ARG_START}\e[39m"
>&2 echo -e "To help out, we've shown you the help docs for \e[36m$CLI_ENTRYPOINT ${@:1:$(($CMD_ARG_START-1))}\e[39m"
exit 3
fi

# Run the command and capture its exit code for introspection
"$CMD_FILE" ${@:$CMD_ARG_START}
EXIT_CODE=$?

# If the command exited with an exit code of 3 (our "show help" code)
# then show the help documentation for the command.
if [[ $EXIT_CODE == 3 ]]; then
"$ROOT_DIR/help" $0 $@
fi

# Exit with the same code as the command
exit $EXIT_CODE
71 changes: 71 additions & 0 deletions help
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env bash

ROOT_DIR=`dirname "$(perl -e 'use Cwd "abs_path"; print abs_path(shift)' $0)"`
CLI_ENTRYPOINT=`basename "$1"`

. "$ROOT_DIR/utils"

# If we don't have any additional help arguments, then show the app's
# header as well.
if [ $# == 0 ]; then
bcli_show_header "$ROOT_DIR/app"
fi

# Locate the correct level to display the helpfile for, either a directory
# with no further arguments, or a command file.
HELP_FILE="$ROOT_DIR/app/"
HELP_ARG_START=2
while [[ -d "$HELP_FILE" && $HELP_ARG_START -le $# ]]; do
HELP_FILE="$HELP_FILE/${!HELP_ARG_START}"
HELP_ARG_START=$(($HELP_ARG_START+1))
done

# If we've got a directory's helpfile to show, then print out the list of
# commands in that directory along with its help content.
if [[ -d "$HELP_FILE" ]]; then
echo -e "${COLOR_GREEN}$CLI_ENTRYPOINT ${COLOR_CYAN}${@:2:$(($HELP_ARG_START-1))} ${COLOR_NORMAL}"

# If there's a help file available for this directory, then show it.
if [[ -f "$HELP_FILE/.help" ]]; then
cat "$HELP_FILE/.help"
echo ""
fi

echo ""
echo -e "${COLOR_MAGENTA}Commands${COLOR_NORMAL}"
echo ""

for file in $HELP_FILE/*; do
cmd=`basename "$file"`

# Don't show hidden files as available commands
if [[ "$cmd" != .* && "$cmd" != *.usage && "$cmd" != *.help ]]; then
echo -en "${COLOR_GREEN}$CLI_ENTRYPOINT ${COLOR_CYAN}${@:2:$(($HELP_ARG_START-1))} $cmd ${COLOR_NORMAL}"

if [[ -f "$file.usage" ]]; then
bcli_trim_whitespace "$(cat "$file.usage")"
echo ""
elif [[ -d "$file" ]]; then
echo -e "${COLOR_MAGENTA}...${COLOR_NORMAL}"
else
echo ""
fi
fi
done

exit 0
fi

echo -en "${COLOR_GREEN}$CLI_ENTRYPOINT ${COLOR_CYAN}${@:2:$(($HELP_ARG_START-1))} ${COLOR_NORMAL}"
if [[ -f "$HELP_FILE.usage" ]]; then
bcli_trim_whitespace "$(cat "$HELP_FILE.usage")"
echo ""
else
echo ""
fi


if [[ -f "$HELP_FILE.help" ]]; then
cat "$HELP_FILE.help"
echo ""
fi
Loading

0 comments on commit 49df702

Please sign in to comment.