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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,191 @@ get their own file. Once you edit, run `bashly generate` again to merge the
content from your functions back into the script.


Examples
--------------------------------------------------

The `bashly.yml` file can be set up to generate two types of scripts:

1. Script with subcommands (for example, like `docker` or `git`).
2. Script without subcommands (for example, like `ls`)

This is detected automatically by the contents of the configuration: If it
contains a `commands` definition, it will generate a script with subcommands.


### Sample configuraiton for a script without subcommands

You can get this script by running `bashly generate --minimal`.

```yaml
name: download
help: Sample minimal application without subcommands
version: 0.1.0

args:
- name: source
required: true
help: URL to download from
- name: target
help: "Target filename (default: same as source)"

flags:
- long: --force
short: -f
help: Overwrite existing files
```


### Sample configuraiton for a script with subcommands

You can get this script by running `bashly generate`.

```yaml
name: cli
help: Sample application
version: 0.1.0

commands:
- name: download
short: d
help: Download a file

args:
- name: source
required: true
help: URL to download from
- name: target
help: "Target filename (default: same as source)"

flags:
- long: --force
short: -f
help: Overwrite existing files

- name: upload
short: u
help: Upload a file
args:
- name: source
required: true
help: File to upload

flags:
- long: --user
short: -u
arg: user
help: Username to use for logging in
required: true
- long: --password
short: -p
arg: password
help: Password to use for logging in
```


Configuration Reference
--------------------------------------------------

### Command options

With the exception of `version` and `commands` (shich define subcommands),
everything else in this section is suitable both for the main script, and for
any subcommand you define using `commands`.

```yaml
# The name of the script or subcommand
name: myscript

# The header text to display when using --help
# This can have multiple lines. In this case, the first line will be used as
# summary wherever appropriate.
help: a sample script generated with bashly

# The string to display when using --version
version: 0.1.0

# Specify the array of subcommands to generate.
# Each subcommand will have its own args and flags.
# If this is provided, then you cannot provide flags or args for the main
# script.
commands:
- ...

# Specify the array of positional arguments this script needs.
# If this is provided, then you cannot provide commands for the main script.
args:
- ...

# Specify the array of option flags this script needs.
# If this is provided, then you cannot provide commands for the main script.
flags:
- ...
```


### Argument options

The below configuration generates this argument:

```
Usage:
myscript USER

Arguments:
USER
Username to use for logging in
```

The argument's value will be available to you as `${args[user]}` in your
bash function.

```yaml
# The name of the argument.
name: user

# The message to display when using --help.
# This can have multiple lines, but it is recommended to keep lines shorter
# than ~70 characters, to avoid text wrapping in narrower terminals.
help: Username to use for logging in

# Specify if this argument is required.
# Note that once you define an optional argument (without required: true)
# then you cannot define required arguments after it.
required: true
```

### Flag options

The below configuration generates this flag:

```
-o, --output DIRECTORY (required)
Specify the output directory
```

The flags's value will be available to you as `${args[--output]}` in your
bash function (regardless of whether the user provided ut with the long or
short form).

```yaml
# The long form of the flag.
long: --output

# The short form of the flag.
short: -o

# The text to display when using --help
# This can have multiple lines, but it is recommended to keep lines shorter
# than ~70 characters, to avoid text wrapping in narrower terminals.
help: Specify the output directory

# If the flag requires an argument, specify its name here.
arg: directory

# Specify if this flag is required.
required: true
```

Contributing / Support
--------------------------------------------------

Expand Down
152 changes: 152 additions & 0 deletions examples/minimal/download
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#!/usr/bin/env bash
# This script was generated by bashly (https://github.com/DannyBen/bashly)
# Modifying it manually is not recommended

# :command.root_command
root_command() {
# :src/root_command.sh
echo "# this file is located in 'src/root_command.sh'"
echo "# you can edit it freely and regenerate (it will not be overwritten)"
inspect_args
}

# :command.version_command
version_command() {
echo $version
}

# :command.usage
download_usage() {
echo "download - Sample minimal application without subcommands"
echo
echo "Usage:"
echo " download SOURCE [TARGET] [options]"
echo


if [[ -n $long_usage ]]; then
echo "Options:"
# :command.usage_fixed_flags
echo " --help, -h"
echo " Show this help"
echo
echo " --version"
echo " Show version number"
echo
# :command.usage_flags
# :flag.usage
echo " --force, -f"
echo " Overwrite existing files"
echo
# :command.usage_args
echo "Arguments:"

# :argument.usage
echo " SOURCE"
echo " URL to download from"
echo

# :argument.usage
echo " TARGET"
echo " Target filename (default: same as source)"
echo

fi
}


# :command.inspect_args
inspect_args() {
echo args:
for k in "${!args[@]}"; do echo "- \${args[$k]}" = ${args[$k]}; done
}

# :command.command_functions

# :command.parse_args
parse_args() {
# :command.fixed_flag_filter
case "$1" in
--version | -v )
version_command
exit 1
;;

--help | -h )
long_usage=yes
download_usage
exit 1
;;

esac
# :command.command_filter
action=root
# :command.required_args_filter
if [[ $1 && $1 != -* ]]; then
args[source]=$1
shift
else
echo missing required argument: SOURCE
echo Usage: download SOURCE [TARGET] [options]
exit 1
fi
# :command.required_flags_filter
# :command.parse_args_while
while [[ $# -gt 0 ]]; do
key="$1"
case "$key" in
# :flag.case
--force | -f )
args[--force]=1
shift
;;


-* )
echo invalid option: $key
exit 1
;;

* )
# :command.parse_args_case
if [[ ! ${args[source]} ]]; then
args[source]=$1
shift
elif [[ ! ${args[target]} ]]; then
args[target]=$1
shift
else
echo invalid argument: $key
exit 1
fi
;;

esac
done
}


# :command.initialize
initialize() {
version="0.1.0"
long_usage=''
set -e
}

# :command.run
run() {
declare -A args
parse_args "$@"

if [[ ${args[--version]} ]]; then
version_command
elif [[ ${args[--help]} ]]; then
long_usage=yes
download_usage
elif [[ $action == "root" ]]; then
root_command
fi
}

initialize
run "$@"
16 changes: 16 additions & 0 deletions examples/minimal/src/bashly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: download
help: Sample minimal application without subcommands
version: 0.1.0

args:
- name: source
required: true
help: URL to download from
- name: target
help: "Target filename (default: same as source)"

flags:
- long: --force
short: -f
help: Overwrite existing files

3 changes: 3 additions & 0 deletions examples/minimal/src/root_command.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
echo "# this file is located in 'src/root_command.sh'"
echo "# you can edit it freely and regenerate (it will not be overwritten)"
inspect_args
12 changes: 12 additions & 0 deletions examples/minimal/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash

set -x

rm -f ./src/*.sh

bashly generate

./download
./download -h
./download --version
./download somesource -f
Loading