=head1 NAME

ots-build - bash library to build OTS packages

=head1 SYNTAX


  # load library
  if ots_build=$(pkg-config --libs ots-build); then
    . "$ots_build"
  else
    echo >&2 "unable to load ots-build library"
    exit 1
  fi

  # override some default variables
  otsb_set var1 val1
  otsb_set var2 val2

  # initialize the library
  otsb_init

  # parse the command line
  otsb_options "$@"

  # create build variables
  otsb_set_build_variables

  otsb_run_cmds

=head1 DESCRIPTION

Sometimes the Off-The-Shelf (OTS) software you need has a complicated
build workflow.  If you want to manage that in a scripted
(patch)-config-build-test-install environment, that usually means
building a script to perform all of the work.  If you are working with
dozens of OTS package, that can be a lot of redundant work.

B<ots-build> is a B<bash> library which provides support for common
tasks in building OTS software. You'll still have to write a driver
script to perform the build, but it should be much simpler.

It provides a framework for

=over

=item *

parsing command line arguments

=item *

running partial or complete builds and installation

=item *

unarchiving packages and patching the source prior to configuration.

=item *

a rudimentary logging mechanism to keep things tidy.

=back

B<ots-build> tries to figure out some things about the package to be
built, such as name and version, which is useful when installing into
staging areas (such as used by the B<graft> or B<stow> commands).  It
does this using the name of the source directory (see the B<--srcdir>
option).

=head1 USING THE LIBRARY

B<ots-build> consists of a single file containing B<bash> functions.

I<driver> scripts use those functions to implement the build process.

Typically a site would create a wrapper around B<ots-build> to
customize defaults or add extra functionality required for the site.

B<ots-build> requires B<bash> 4.3 or newer.

=head2 Assumptions

B<ots-build> makes a few assumptions about where package archives and
patches are located.  These can be overridden with command line
arguments or hooks.  Two directories are special:

=over

=item The directory containing the build script

By default B<ots-build> assumes that the build script, the package
archive, and an optional patch are located in the same directory.
These can be overridden with the C<--archive> and C<--patchfile>
options

=item The directory containing the unarchive package source.

B<ots-build> deduces the package name and version from the name of the
directory containing the unarchived source (which is usually something
like F<package-x.y.z>).  It uses this to create the default patch file
name.

This information can be fairly useful to the driver scripts, for
instance in specifying version specific compiler or installation
flags.

The example autoconf driver script uses it to offer support for
installing packages into staged areas for use by the B<graft> or
B<stow> commands.

B<Note:> By default B<ots-build> assumes that the I<current directory>
contains the source.  If this is not the case, the B<--srcdir> option
must be specified.

=back

=head2 Sharing information with the library

In order to simplify the interface, much of the information needed and
provided by B<ots-build> is shared via B<bash> variables.  Variables
associated with particular tasks (for instance parsing the command
line) are described in the documentation for those tasks.

B<ots-build> is designed so that it does not override variables which
have already been set.  This is accomplished by using the B<otsb_set>
and B<otsb_setarr> functions to modify variable values.  These
functions will only set a value if the variable has not yet been set;
variables with values will not be changed.  If you need to discard an
existing value so that a default can be recomputed, use
B<otsb_reset> or B<otsbv_reset> first.

The only deviation from this behavior is when parsing command line
options;  these always override preset variables.

Variables which are special to B<ots-build> use the B<otsbv_set>
command.

=head2 Driver Scripts

Driver scripts are B<bash> scripts which use B<ots-build> to perform
build operations.  They must be invoked with at least one argument
specifying which command to perform.  See L</Commands> for the commands
provided by B<ots-build>.  The driver script specifies which commands
are legal and the code to perform them.

The typical sequence of invocation of B<ots-build> functions is

=over

=item 1

Load the library. This should be doneI<at the very start> of the build
script.  B<ots-build> provides a B<pkg-config> metadata file:

  if ots_build=$(pkg-config --libs ots-build); then
    . $ots_build
  else
    echo >&2 "unable to load ots-build library"
    exit 1
  fi

=item 2

Initialize the library via

  otsb_init

This sets up the internal globals, hook queues, and built-in option
metadata.

=item 3

Indicate the available required commands and their order via the
C<otsb_commands> and C<otsb_opt_commands> arrays.

=item 4

Define actions for commands by creating functinos for them, e.g. C<otsb_cmd_build>.

=item 5

Add command line options to be recognized with L</otsb_add_option>.

=item 6

Parse the command line with L</otsb_options>

=item 7

Set up the variables which control the build by running

  otsb_set_build_variables

=item 8

Perform requested actions using B<otsb_run_cmds>

=back

=head2 Workflow Customization

Customization is done by providing code which will be run by
B<ots-build> functions at particular points (hooks) in their execution
sequences.  The code can be used to specify default values for
parameters, add command line options, create new build variables, or
whatever might be needed to support local build requirements.

B<ots-build> maintains an execution queue for each hook location.  The
B<otsb_hook_push_fn_front> and B<otsb_hook_push_fn_back> functions add
function callbacks to the front or back of the queue, while
B<otsb_hook_push_front> and B<otsb_hook_push_back> add shell snippets.
Function callbacks are invoked directly; shell snippets are evaluated
as code when the hook runs.  The latter approach is deprecated.  For
C<*_before> hooks, function callbacks are passed the arguments given to
the function which invoked the hook.
Workflow command hooks are created automatically when commands are
registered.

Hooks for the administrative commands are:

=over

=item init_before

The code is run at the start of B<otsb_init>.

=item init_after

The code is run at the end of B<otsb_init>.

=item options_before

The code is run at the start of B<otsb_options>.

=item options_after

The code is run at the end of B<otsb_options>.

=item build_variables_before

The code is run at the start of B<otsb_set_build_variables>.

=item build_variables_after

The code is run at the end of B<otsb_set_build_variables>.

=back

C<*_before> and C<*_after> hooks for each workflow command
(e.g. C<patch>, C<build>, etc) are automatically generated.

=head2 Wrapping B<ots-build>

Rather than encode site-specific options or defaults into driver
scripts, it's easier to centralize the information in a wrapper around
B<ots-build>.  The driver scripts should load the wrapper library
instead of B<ots-build>.

For example, let's say that a site wants to specify a default value
for the B<--prefix> option, add an additional command line option, and
set some site-specific build variables.  Here's one way of doing this:

  #!/bin/bash
  
  # don't load this multiple times
  [[ ${_mst_otsb_loaded:=0} ]] && return 0
  _mst_otsb_loaded=1
  
  # load ots-build
  if ots_build=$(pkg-config --libs ots-build); then
    . $ots_build
  else
    echo >&2 "unable to load ots-build library"
    exit 1
  fi
  
  create_new_options() {
  
      # On Solaris, prefer GNU patch & tar
      # create defaults here so that help information can show the
      # default values
  
      case `uname -s` in
    
        SunOS )
            otsb_set make $(command -v gmake)
            otsb_set tar $(command -v gtar)
            otsbv_set patch-cmd /usr/local/bin/patch
            ;;
  
        * )
            otsb_set make $(command -v make)
            otsb_set tar  $(command -v tar)
            ;;
  
      esac
  
      otsb_set ots_root /soft/ots
  
      otsb_add_option scalar ots-root \
      "top-level directory containing installed OTS [$ots_root]"
  
      otsb_add_option scalar ots-pkgs \
         "directory into which OTS packages will be installed [$ots-root/pkgs]"
  
      otsb_add_option scalar make     "name of the make command [$make]"
      otsb_add_option scalar tar      "name of the tar  command [$tar]"
  
      otsb_add_option array  config-opts 'extra options for configure; may be specified multiple times'
  }
  
  default_option_values () {
      # can't set this until after otsb_options is run,
      # as it depends upon the value of the ots-root option
      otsb_set ots_pkgs ${ots_root}/pkgs
  }
  
  otsb_hook_push_fn_back options_before create_new_options
  otsb_hook_push_fn_back options_after  default_option_values


=head2 Command Line Options

C<ots-build> provides an extensible parser for command line options,
with an initial set of options, such as L</--help>. The driver script
can create additional options using L</otsb_add_option> prior to
the call to L</otsb_options>.

The L</otsb_options> function is parses command line options and
arguments and sets up bash variables with their values.
It takes a list of tokens to parse, which is typeically
just those passed on the command line to the script:

  otsb_options "$@"

=head3 Option format

Only long options (preceded by C<-->) are recognized.  Options which
take values may be separated from their values by a C<=> character or
white space.  For example:

  --exec-prefix=a --prefix b  --flag

Hyphens in option names may be specified as underscores.

Command line options are either boolean (presence signifies true or
false), scalars (take a single value) or arrays (may be specified
multiple times, appending each value to an array).  Boolean options
may be specified either in the affirmative ( C<--flag> ) or in the
negative (C<--no-flag>).

=head3 Provided options

The following options are provided out-of-the-box:

=over

=item --prefix I<string>

=item --exec-prefix I<string>

These are the standard prefixes used by most software installers

=item --debug

=item --log

=item --logconsole

=item --logpfx I<string>

=item --logsingle

See L</Logging>

=item --help

Outputs help information and exits

=item --version

Outputs the version of B<ots-build> and exits.

=item --srcdir I<srcdir>

This specifies the directory containing the source.  B<ots-build> will
change to this directory before performing any actions.  It defaults
to the current directory.

=item --archive F<filename>

The file name of the archive containing the source.  If the B<unpack>
command is specified the archive is unpacked and B<ots-build> will
change into the archive directory.  Currently only compressed tar
files are handled.  B<ots-build> can handle archives which don't
unpack into a single top-level directory.  See L</Commands> for more
information on what happens after an unpack operation.

If the filename is specified with a directory, it is assumed to be in
the directory containing the driver script.

=item --patch-cmd I<string>

The patch command to use.  It defaults to the B<patch> command in the
users path.

=item --patch-opts I<string>

Options to pass to the patch command in addition to the patch file.
This is an array option, and it may be repeated.
It defaults to C<-p0 -N -s>.

=back

=head3 Default values

Default values for options created via L</otsb_add_option> may be set
with C<otsb_set> before calling C<otsb_options>.  Option parsing is
the only context where values specified via C<otsb_set> are
overridden.

=head3 Retrieving option values

After parsing, the values of the options are stored in bash variables
with the same name as the option (with any hyphens converted to
underscores).  Boolean values are represented as the string C<true> for
true and C<false> for false.  Options which are not specified on
the command line are not set to any default value.

In addition to the options that you provide, B<ots-build> provides
some of its own.  These are stored in variables with a special prefix,
C<otsbv_> to prevent confusion.  To specify defaults, use the
C<otsbv_set> command prior to calling C<otsb_init>.  For example, the
C<--logsingle> option value will be stored in C<otsbv_logsingle>.  To
set its default value:

  otsbv_set logsingle true

=head3 Option help

B<ots-build> supports a C<--help> option.

Options added via calls to L</otsb_add_option> will use the help string
provided in those calls.

Options provided by B<ots-build> have pre-defined help strings which
can be overridden by calling the C<otsb_help> function after
calling C<otsb_init> and before calling C<otsb_options>.


=head2 Arguments

The only arguments accepted on the command line are the names of
commands.  B<ots-build> provides some built-in commands (see
L</Commands> for more information).

The names of commands that the driver script provides should be
placed in one of two arrays:

=over

=item C<otsb_commands>

This array should contain all of the commands which are part of the
normal build workflow.  B<ots-build> provides an C<all> command which
will run all of these in the order specified in C<otsb_commands>.

This array defaults to

  otsb_commands=( patch configure build test install )

=item C<otsb_opt_commands>

This array should contain any commands which are not part of the
normal build workflow.  They are I<not> run by the C<all> command.

=back

The actual requested commands are made available in the
C<otsb_req_cmds> array after the command line is parsed. See
L</Commands> for more information on how to interface build
commands to the auto-invocation code.

=head2 Setting build variables

After invoking C<otsb_options> and before running commands, build
variables must be set by calling C<otsb_set_build_variables>.
B<otsb_set_build_variables> assumes that the current directory is the
source directory.  This is automatically performed by B<otsb_options>
if the B<--srcdir> options is specified on the command line.

The C<prefix> variable must already be defined, which is typically set
via the C<--prefix> command line option.

The following variables are set; they may be overridden prior
to invoking C<otsb_set_build_variables> using C<otsb_set>.

=over

=item otsbv_import_root

This is a directory which may contain things associated with the
package, such as a patch file.  By default this is extracted from the
name of the build script (under the assumption that all package
related things are in the same directory as the build script).  It may
also be set with the B<--import-root> option.

=item package

This is the name of the package (including version information).  This
is by default extracted from the name of the I<current directory>
using the C<otsb_pkg> function (use the B<--srcdir> to specify an
alternative directory).

=item package_name

The name of the package (without any version information).  This is by
default derived from the C<package> variable using the
C<otsb_pkg_name> function.  An alternative to overriding the variable
is to redefine the C<otsb_pkg_name> function.

=item package_version

The version of the package.  This is by default derived from the
C<package> variable using the C<otsb_pkg_version> function.  An
alternative to overriding the variable is to redefine the
C<otsb_pkg_name> function.

=item patchfile

The name of the patch file (if any).  This is by default set to

  ${package}.patch

=item exec_prefix

This will default to the value of C<prefix> if it not already set.

=item bindir

Defaults to C<< ${exec_prefix}/bin >>

=item libdir

Defaults to C<< ${exec_prefix}/lib >>

=item incdir

Defaults to C<< ${prefix}/include/${package} >>

=item mandir

Defaults to C<< ${prefix}/man >>

=item docdir

Defaults to C<< ${prefix}/share/doc/$package >>

=back

=head2 Commands

The main purpose of B<ots-build> is to run commands.  The commands
to run are specified on the command line (see L</Arguments>).
The commands which will always be available are:

=over

=item all

Run all of the commands in the C<otsb_commands> array, in order specified.

=item dump

Output the command line arguments.

=item unpack

Unpack the source archive and change into the containing directory.
The B<--archive> option must have been specified.

Because the unpacking is done after the B<otsb_set_build_variables>
function has executed, the values of variables which depend
upon the current directory being the build directory will be incorrect.

Therefore, after unpacking the driver script is automatically executed
again with the B<--srcdir> option set to the directory containing the
unpacked source.

=item show-cmds

Output a list of the non-administrative (i.e. actual build workflow)
commands to stdout.

=back

B<ots-build> provides the C<otsb_run_cmds> function which will execute
the commands specified on the command line.  A command is implemented
as a bash function of the same name, prefixed with I<otsb_cmd_>.  For
example, the I<install> command might be written as:

  otsb_cmd_install () {
    ... commands to perform the actual install ...
  }

It is important that these functions either exit or return with
non-zero values if an error occurred (see L</Errors> for other means of
signalling an error).  These functions are invoked in subshells, to
isolate them from the rest of B<ots-build>.

Stub functions are provided for the C<configure>, C<build>, C<test>, and
C<install> commands.  These will print an error message and exit with
a non-zero status (to remind you that you haven't implemented them
properly).  You must provide replacement versions of these.

The C<patch> command is more fully implemented.  See L</Patching> for
more information.

=head2 Patching

B<ots-build> provides a default B<patch> command for patching a source
distribution before it is configured.  This can be changed by
redefining the C<otsb_cmd_patch> function.  Patching is dependent upon
the existence of the patch file specified via the C<patchfile> global
variable.

A working version of B<patch> is required (Solaris' version is by
definition broken).  By default the version of B<patch> in the user's
path is used; an alternative may be specified with the B<--patch-cmd>
option.

The B<patch> command is passed the options specified via the
B<--patch-opts> option.

If the B<applypatch> command is available it is used to drive
B<patch>, e.g.

  applypatch -patch "patch -p0 -N -s" $patchfile

=head2 Logging

If logging is turned on via the C<--log> or C<--logsingle> options,
the output of each command is logged.

C<--log> logs each command to a separate file, I<pfx>F<cmd>.log, where
I<pfx> is the prefix specified by C<--logpfx>.  This defaults to
C<otsb_>, so that it does not interfere with any log files created by
the package (such as F<config.log>, etc.).

C<--logsingle> sends the output from all commands to a single file,
I<pfx>.log, where I<pfx> is the value of the C<--logpfx> option, with
any trailing underscore removed.

When logging is turned on, by default no output is sent to the terminal.
To log to the terminal as well as to files, specify C<--logconsole>.

The C<--debug>, C<--log>, C<--logconsole>, C<--logsingle>, and
C<--logpfx> options may also be set via the environment variables
C<OTS_BUILD_DEBUG>, C<OTS_BUILD_LOG>, C<OTS_BUILD_LOGCONSOLE>,
C<OTS_BUILD_LOGSINGLE>, and C<OTS_BUILD_LOGPFX>.  Command line settings
override the environment.

Defaults for the variables associated with these options may set via the
C<otsbv_set> function I<before> calling C<otsb_init>.

=head2 Errors

If a command function returns a non-zero value B<ots-build> will exit
with an error.  Typically it is up to the writer of that function to
ensure that an error will cause a non-zero return.  That can be a
pain.  B<ots-build> provides a simple interface to the B<bash> error
trapping system which will ensure that if any command executed within
a command function exits with an error it will be caught and
B<ots-build> will be notified.

The C<otsb_trap_err> command is used to manage the trap.

=over

=item To engage or disengage the error trap for all command functions, use

  otsb_trap_err functions on
  otsb_trap_err functions off

This sets the default state when a command function is invoked. If
this is invoked within a command function it will change the state
immediately.

=item To engage or disengage the error trap immediately

  otsb_trap_err on
  otsb_trap_err off

These turn the system on and off immediately.  If invoked within
a command function, the trap state will return to I<off> after the
function returns.

=item To reset the state to that specified for command functions

  otsb_trap_err functions reset

This is only valid within a command function and resets the state to
the default state specified by the last C<otsb_trap_err functions>
setting.

=back

=head1 FUNCTIONS

=over

=item otsb_add_option

  otsb_add_option $type $name "$help"

Add an option of the given type (C<scalar>, C<bool>, C<array>),
name, and help string.

=item otsb_add_dumpvar

  otsb_add_dumpvar $var_name

Add the I<named> variable to the list of variables output by the
C<dump> command.  Option variables are automatically added to the
list.

=item otsb_append_path

  otsb_append_path $path_var_name $path1 $path2 ...

Append the specified path(s) to the path variable with the given
name. A path variable's value is a colon separated list of paths. For
example,

  foo=a:b:c:d
  otsb_append_path foo e f g h

results in

  foo=a:b:c:d:e:f:g:h

=item otsb_assert_has_command

  otsb_assert_has_command $cmd1 $cmd2

Checks if the passed commands are in the user's path.  If not it
exits with an error message via B<otsb_die>.

=item otsb_has_command

  otsb_has_command $cmd

Returns true if the named command is available in the user's path.

=item otsb_check_logfile

  otsb_check_logfile logfile

Ensures that the named logfile can be written.  If the file does not
exist it is created and removed again; if it already exists, write
permission is checked.

=item otsb_cleanup

This function is called when the script exits and performs any
necessary cleanup.  By default it does nothing.  You should redefine
it if you need it.

=item otsb_die

  otsb_die $message

Print the message to the standard error stream using a standard format
and exit with a non-zero status code.

=item otsb_warn

  otsb_warn $message

Print the message to the standard error stream using the standard
library message format and continue.

=item otsb_error

  otsb_error $message

Output the message to the standard error stream using a standard
format.

=item otsb_source

  otsb_source file1 [file2 ...]

Source the named files once and remember that they have been loaded.
Repeated calls for the same file are ignored.

=item otsb_help

  otsb_help cmd    cmd_name "cmd help string"
  otsb_help option option_name "option helpstring"

Change the help string of an existing option or command.

The second argument is either C<cmd> or C<option> indicating what
element the help string is for.  For example, here's how the default
help string for the C<--exec-prefix> option is specified:

  otsb_help option exec-prefix  \
     "install architecture-dependent files here"

=item otsb_hook_push_back

  otsb_hook_push_back hook_name code

Push a shell snippet onto the back of the execution queue of the named
hook.  The snippet is evaluated when the hook runs.

=item otsb_hook_push_front

  otsb_hook_push_front hook_name code

Push a shell snippet onto the front of the execution queue of the named
hook.  The snippet is evaluated when the hook runs.

=item otsb_hook_push_fn_back

  otsb_hook_push_fn_back hook_name function_name

Push a function callback onto the back of the execution queue of the
named hook.  The named function is invoked directly when the hook runs.

=item otsb_hook_push_fn_front

  otsb_hook_push_fn_front hook_name function_name

Push a function callback onto the front of the execution queue of the
named hook.  The named function is invoked directly when the hook runs.

=item otsb_init

  otsb_init

Initializes the B<ots-build> library.

=item otsb_is_absolute

  otsb_is_absolute path

Returns true if the supplied path is absolute.

=item otsb_is_boolean

  otsb_is_boolean $value

Returns true if the value is a boolean recognized by either C<otsb_is_true>
or C<otsb_is_false>.

=item otsb_is_set

  otsb_is_set variable_name

Returns true if the variable has been set.

=item otsb_join

  otsb_join delimiter value1 value2 ...

Join the supplied values using the delimiter and print the result.

=item otsb_mesh

  otsb_mesh left_array right_array start_index pair_format sequence_format

Join corresponding elements from the two named arrays, starting at the
given index.  Each pair is formatted with the first C<printf>-style
format using the corresponding left and right elements as its two
arguments.  Pairs are then joined with the second C<printf>-style
format, which receives the accumulated result and the next pair as its
two arguments.  The two arrays must have the same number of elements.

=item otsb_argv

  otsb_argv array_name

Set the named array variable to the original arguments most recently
passed to C<otsb_options>.

=item otsb_make_path_absolute

  otsb_make_path_absolute path [base_dir]

Print an absolute path.  Relative paths are resolved against the
optional base directory, which defaults to the current directory.

=item otsb_is_true

=item otsb_is_false

  otsb_is_true $value
  otsb_is_false $value

These return true if the passed value matches what B<ots-build>
understands as true or false:

  true:  the strings 'true' or 'on', or a non-zero number
  false: the strings 'false' or 'off', or zero

Any other values will return false.

=item otsb_options

  otsb_options "$@"
  otsb_options "$my_options_from_somewhere_else"

C<otsb_options> parses the passed tokens for options and commands.  It
places values for passed options in variables of the same name and
queues the requested commands internally.  See
L</Parsing the Command Line> for more information.

Default values for options may be specified by setting the appropriate
option variables before or after calling C<otsb_options>.

=item otsb_internal_options

  otsb_internal_options "$@"

Parse only the built-in "internal" options, such as C<--help>,
C<--version>, C<--srcdir>, C<--import-root>, and the logging and patch
options.  The results are stored in variables with the C<otsbi_>
prefix, such as C<otsbi_help> and C<otsbi_srcdir>.

This parser ignores public options and commands.  It is useful when a
driver needs to inspect built-in options before calling
C<otsb_options>.  Calling C<otsb_options> after C<otsb_internal_options>
has the same effect as if C<otsb_internal_options> had never been
called.

=item otsb_split

  otsb_split string delimiter

Split the string on a single delimiter character and print the
non-empty fields one per line.

=item otsb_pkg

This function returns the package name and version (as a single
string).  It defaults to

  otsb_pkg () { echo $(basename $(pwd)); }

=item otsb_pkg_name

This function determines the name of the package and prints it to
the standard output stream.  It is used to generate the value of the
C<package_name> variable.  The default definition is

  otsb_pkg_name () { echo ${package%%-*} ; }

It may be overridden (before calling C<otsb_set_build_variables>).  When
called, the C<package> variable will have been set.

=item otsb_pkg_version

This function determines the version of the package and prints it to
the standard output stream.  It is used to generate the value of the
C<package_version> variable.  The default definition is

  otsb_pkg_version () { echo ${package##*-} ; }

It may be overridden (before calling C<otsb_set_build_variables>).  When
called, the C<package> variable will have been set.

=item otsb_prepend_path

  otsb_prepend_path $path_var_name $path1 $path2 ...

Prepend the specified path(s) to the path variable with the given
name. A path variable's value is a colon separated list of paths. For
example,

  foo=a:b:c:d
  otsb_prepend_path foo e f g h

results in

  foo=e:f:g:h:a:b:c:d

=item otsb_default_value

  otsb_default_value variable [prefix]

Print the default value of the named variable.  For array defaults,
the value is printed as a space-separated string.  If a prefix is
supplied, it is used when looking up the underlying option variable.

=item otsb_run_cmds

This executes the build commands listed in the C<otsb_req_cmds>
variable, which is filled in by C<otsb_options>.  The commands are run
in the order in which they were specified, I<not> the order listed in
C<otsb_commands>.  Do I<not> invoke this command more than once.

If a command does not return a successful exit status code, the
subsequent commands are not run and C<otsb_run_cmds> returns the exit
status code of the failing command.

=item otsb_set

  otsb_set variable value

If the named (scalar!) variable has not been set, assign it the
specified value:

  otsb_set prefix "a prefix is here"

In most cases this is the preferred way of setting a variable's value,
as it allows using environment variables to specify default values.

For example, if the build script is run in an environment with the
environment variable prefix set:

  prefix=/my/prefix /imports/package/build all

then setting the default value of prefix via

  [...]
  prefix=/a/default/value
  otsb_options "$@"

will ignore the environment, while

  [...]
  otsb_set prefix /a/default/value
  otsb_options "$@"

will not.

=item otsb_setarr

  otsb_setarr variable value1 value2 ...

If the named (array!) variable has not been set, assign it the
specified list of values:

  otsb_setarr config_opts --do-this --do-that

will do the equivalent of

  config_opts=( --do-this --do-that )

if C<config_opts> is empty.

=item otsb_set-default-value

  otsb_set-default-value variable1 variable2 ...

Set the named variable or variables to their defaults if they are not
already set.  Array defaults are assigned with C<otsb_setarr>; scalar
defaults are assigned with C<otsb_set>.

=item otsb_reset

  otsb_reset variable1 variable2 ...

Unset the named variable or variables.  This returns the variables to
an unset state so that later calls to C<otsb_set>,
C<otsb_setarr>, or the default-value helpers can repopulate them.


=item otsbv_set

  otsbv_set variable value

Similar to C<otsb_set>, but used only for option variables provided by
B<ots-build>.

  otsbv_set log true

=item otsbv_set-default-value

  otsbv_set-default-value variable1 variable2 ...

Set the named B<ots-build> variable or variables to their defaults if
they are not already set.  Array defaults are assigned with
C<otsb_setarr>; scalar defaults are assigned with C<otsbv_set>.

=item otsbv_reset

  otsbv_reset variable1 variable2 ...

Unset the named I<ots-build> variable or variables.  This returns the
variables to an unset state so that later calls to C<otsbv_set> or the
default-value helpers can repopulate them.

=item otsb_set_build_variables

This function is called after all invocations of C<otsb_options>. It
generates important build variables; see L</Setting build variables>.

=item otsb_trap_err

See the L</Errors> section.

=back

=head1 VARIABLES

The following variables are important to B<ots-build>.  Be careful that
you do not inadvertently use them in a different context.

=over

=item otsb_commands

An array containing the available commands, in the order that they
should be invoked.

=item otsb_req_cmds

An array containing the commands requested on the command line.

=item otsb_version

The version of the B<ots-build> library.

=item otsbv_import_root

See L</Setting build variables>

=item package

The name of the package, including the version number, derived from
the directory that the build script is run in.

=item patchfile

The (optional) file containing the patch to apply to the source
directory, derived from the package name and the directory containing
the build script.

=item version

The package version, determined from the package name.

=item log

A boolean indicating whether or not logging is enabled.

=item logpfx

The prefix appended to the command name to create a name for
the log file.

=item logsingle

A boolean indicating that all logs should go to a single file.

=item logconsole

A boolean indicating that logging should be sent to the
console as well as to the log files.

=back

=head2 EXAMPLES

=over

=item * Drivers

Two example drivers are installed: C<ots-build-autoconf> and
C<ots-build-cmake>.

=item * plugins

Drivers may want to allow per-package modifications to a more generic
workflow, including changing the available commands and options.

This must be done prior to calling L</otsb_options>, but also requires
information that may be available only after parsing the command line,
e.g. the value of L</otsbv_import_root>.  This can be accomplished
using the L</otsb_internal_options> command inside of a
L</otsb_options_before> hook, e.g.

  load_plugins () {
      otsb_internal_options
      local plugind="$otsbi_import_root/plugins"
      if [ -d "$plugind" ]; then
          local -a plugins=()
          mapfile -d '' -t plugins < <( find "$plugind" -name '*.sh' -print0 | sort )
          otsb_source "${plugins[@]}"
      fi
  }                         

=back

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2010 Smithsonian Astrophysical Observatory

This file is part of ots-build.

ots-build is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see L<http://www.gnu.org/licenses/>.


=head1 AUTHOR

Diab Jerius E<lt>djerius@cfa.harvard.eduE<gt>
