---
name: appspec-bash
appspec: { version: 0.001 }
title: Command line framework generator for bash
abstract: Generate commandline parser, completion and man pages
class: App::Spec::Bash
markup: pod
description: |
This script can generate a commandline parser for bash from a specification
file written in YAML.
Writing a parser for commandline arguments isn't rocket science, but it's
something you don't want to do manually for all of your scripts, especially
in bash. Some tools exist, but they often don't support subcommands or
validating of option values.
C<appspec>/C<appspec-bash> can generate pretty much everything for you:
=over
=item Commandline parser for subcommands, options and parameters
=item Usage output
=item Shell completion files
=item man pages
=back
=head2 EXAMPLES
Here is an example of a very simple script.
The following files are needed:
share/mytool.yaml
bin/mytool
lib/mytool
lib/appspec # generated
share/completion/zsh/_mytool # generated
share/completion/bash/mytool.bash # generated
pod/mytool.pod # generated
lib/help # generated
The spec:
# share/mytool.yaml
---
name: mytool # commandname
appspec: { version: 0.001 }
plugins: [-Meta] # not supported in bash
title: My cool tool # Will be shown in help
class: MyTool # "Class name" (means function prefix here)
subcommands:
command1:
op: command1 # The function name (MyTool.command1)
summary: cmd one # Will be shown in help and completion
options:
- foo|f=s --Foo # --foo or -f; '=s' means string
- bar|b --Bar # --bar or -b; a flag
Your script C<mytool> would look like this:
# bin/mytool
#!/bin/bash
DIR="$( dirname $BASH_SOURCE )"
source "$DIR/../lib/appspec"
source "$DIR/../lib/mytool"
APPSPEC.run $@
The actual app:
# lib/mytool
#!/bin/bash
MyTool.command1() {
echo "=== OPTION foo: $OPT_FOO"
echo "=== OPTION bar: $OPT_BAR"
}
=head3 Generating the parser
Then generate the parser like this:
$ appspec-bash generate parser share/mytool.yaml lib/appspec
C<APPSPEC.run> will parse the arguments and then call the function
C<MyTool.command1>. In this function you can use the options via
C<$OPT_FOO> and C<$OPT_BAR>.
$ ./bin/mytool command1 --foo x --bar
# or
$ mytool command1 -f x -b
=== OPTION foo: x
=== OPTION bar: true
=head3 Generate completion
$ appspec completion share/mytool.yaml --zsh >share/completion/zsh/_mytool
$ appspec completion share/mytool.yaml --bash >share/completion/bash/mytool.bash
=head3 Generate pod
$ appspec pod share/mytool.yaml > pod/mytool.pod
$ perldoc pod/mytool.pod
=head3 Generate help
$ appspec-bash generate help share/mydemo.yaml lib/help
=head2 Generate a new app skeleton
appspec-bash new --class MyTool --name mytool
This will create your app C<mytool> in the directory C<MyTool> and output
some usage information like this:
To generate the parser and help, do:
% cd MyTool
% appspec-bash generate parser share/mytool.yaml lib/appspec
% appspec-bash generate help share/mytool.yaml lib/help
Try it out:
% bin/mytool cmd1 -ab --opt-x x -yfoo --opt-y bar
% bin/mytool cmd2 -vvv
% bin/mytool cmd2 -vvv foo
=head2 OPTION AND PARAMETER PARSING
appspec-bash supports various types of options.
=head3 Flags
# YAML
options:
- verbose|v -- Verbose output
% mytool --verbose
% mytool -v
You can also stack several flags:
% mytool -abc
=head3 Options with values
# YAML
options:
- color|c=s --Specify color
% mytool --color red
% mytool -c red
% mytool -cred
# Not yet supported
# mytool --color=red
You can stack flags together with options. If you have the flags C<-a> and
C<-b> and the option C<-c>, then you can use this syntax:
% mytool -abc23
=head3 Incremental flags
# YAML
options:
- verbose|v+ --Verbose output (incremental)
% mytool -vvv # like: declare -i OPT_VERBOSE=3
% mytool --verbose --verbose # like: declare -i OPT_VERBOSE=2
=head3 Options with multiple values
# YAML
options:
- server|s=s@ --List of servers
% mytool --server foo --server bar
% mytool -s foo -s bar
=head3 Parameters
# YAML
parameters:
- name: server
required: true
summary: Server name
=head3 Option types
By default, an option is a flag. To accept a value, add a C<=>. Then it will
be a string by default:
- foo=
# or
- foo=s
You can also create integer options:
- max=i --Specify maximum value
Then you can treat it as an integer and use C<OPT_MAX+=1> for example.
There are also the types C<file>, C<dir>, C<filename> and C<dirname>.
Currently they are only relevant for completion.
# YAML
- input= +file --Input filename
- source-dir= +dir --Source directory
- output= +filename --Output file
- out-dir= +dirname --Output directory
In the future, C<file> and C<dir> will check for an existing file or
directory. And C<filename> and C<dirname> can be used if the file
or directory doesn't exist yet, but the tab completion will still offer
file or directory names.
See the C<mydemo> app in the example directory for examples of options and
parameters.
options: []
subcommands:
generate:
summary: Generate parser, help
subcommands:
parser:
op: parser
summary: Generate main commandline parser script
parameters:
- +spec= +file --YAML Specification file
- +output= +filename --Output file, e.g. lib/appspec
help:
op: genhelp
summary: Generate help functions
parameters:
- +spec= +file --YAML Specification file
- +output= +filename --Output file, e.g. lib/help
new:
summary: Generate new app
op: cmd_new
description: |
This command creates a skeleton for a new app.
It will create a directory for your app and write a skeleton
spec file.
Example:
appspec-bash new --name mytool --class MyTool MyTool
parameters:
- path= +dirname --Path to the distribution directory (default is the classname in current directory)
options:
- +name|n=s --The (file) name of the app
- +class|c=s --The main "class" (function prefix) for your app implementation
- overwrite|o --Overwrite existing dist directory
# - with-subcommands|s --Not implememted yet, subcommands are default
# vim:et:sts=2:sws=2:sw=2:foldmethod=indent