#!@l_prefix@/lib/openpkg/bash
##
##  openpkg -- OpenPKG Tool Chain
##  Copyright (c) 2000-2007 OpenPKG Foundation e.V. <http://openpkg.net/>
##  Copyright (c) 2000-2007 Ralf S. Engelschall <http://engelschall.com/>
##
##  Permission to use, copy, modify, and distribute this software for
##  any purpose with or without fee is hereby granted, provided that
##  the above copyright notice and this permission notice appear in all
##  copies.
##
##  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
##  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
##  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
##  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
##  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
##  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
##  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
##  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
##  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
##  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
##  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
##  SUCH DAMAGE.
##
##  openpkg.sh: Execution Frontend (Language: Bourne-Shell)
##

##
##  command line parsing
##

#   command line options defaults
opt_prefix=""
opt_tools=""
opt_version=no
opt_help=no

#   process command line options by iterating over arguments
for opt
do
    case "${opt}" in
        -*=*) arg=`echo "${opt}" | sed 's/^[-_a-zA-Z0-9]*=//'` ;;
           *) arg='' ;;
    esac
    case "${opt}" in
        -v|--version ) opt_version=yes;     shift ;;
        -h|--help    ) opt_help=yes;        shift ;;
        --prefix=*   ) opt_prefix="${arg}"; shift ;;
        --tools=*    ) opt_tools="${arg}";  shift ;;
        -* ) echo "openpkg:ERROR: Invalid command-line option \"${opt}\"." 1>&2
             echo "openpkg:ERROR: Run \"${0} --help\" for list of valid options" 1>&2; exit 1 ;;
        *  ) break ;;
    esac
done

##
##  determine OpenPKG locations
##

#   determine path to OpenPKG instance
openpkg_prefix="@l_prefix@"
if [ ".${OPENPKG_PREFIX}" != . ]; then
    openpkg_prefix="${OPENPKG_PREFIX}"
fi
if [ ".${opt_prefix}" != . ]; then
    openpkg_prefix="${opt_prefix}"
fi
if [ -x "${openpkg_prefix}/bin/openpkg" -a -x "${openpkg_prefix}/libexec/openpkg/rpm" ]; then
    #   OpenPKG 2.0 and higher
    true
elif [ -f "${openpkg_prefix}/bin/rpm" -a -x "${openpkg_prefix}/lib/openpkg/rpm" ]; then
    #   OpenPKG 1.x
    echo "openpkg:ERROR: OpenPKG 1.x instance found under \"${openpkg_prefix}\" (not supported)" 1>&2
    exit 1
else
    echo "openpkg:ERROR: no OpenPKG instance found under \"${openpkg_prefix}\"" 1>&2
    exit 1
fi

#   allow convenient all-in-one specification of OpenPKG Tool Chain locations
#   (assuming the filesystem layout of an uninstalled OpenPKG Tool Chain)
openpkg_tools="${OPENPKG_TOOLS}"
openpkg_tools_cmdpath="${OPENPKG_TOOLS_CMDPATH}"
openpkg_tools_apipath="${OPENPKG_TOOLS_APIPATH}"
if [ ".${opt_tool}" != . ]; then
    openpkg_tools="${opt_tools}"
fi
if [ ".${openpkg_tools}" != . -a ".${openpkg_tools_cmdpath}" = . ]; then
    openpkg_tools_cmdpath="${openpkg_tools}/cmd:@"
fi
if [ ".${openpkg_tools}" != . -a ".${openpkg_tools_apipath}" = . ]; then
    openpkg_tools_apipath="${openpkg_tools}/api:@"
fi

#   determine path to OpenPKG Tool Chain commands
cmdpath="${openpkg_prefix}/libexec/openpkg"
if [ -d "${openpkg_prefix}/libexec/openpkg-tools" ]; then
    #   openpkg-tools package overrides
    cmdpath="${openpkg_prefix}/libexec/openpkg-tools:${cmdpath}"
fi
if [ -d "${openpkg_prefix}/libexec/openpkg-audit" ]; then
    #   openpkg-audit package overrides
    cmdpath="${openpkg_prefix}/libexec/openpkg-audit:${cmdpath}"
fi
if [ ".${openpkg_tools_cmdpath}" != . ]; then
    #   user supplied path overrides
    cmdpath=`echo "${openpkg_tools_cmdpath}" | sed -e "s;@;${cmdpath};"`
fi
openpkg_tools_cmdpath=`echo "${cmdpath}" | sed -e 's/::/:/g' -e 's/^://' -e 's/:$//'`

#   determine path to OpenPKG Tool Chain API
apipath=""
if [ -d "${openpkg_prefix}/lib/openpkg-tools" ]; then
    #   openpkg-tools package overrides
    apipath="${openpkg_prefix}/lib/openpkg-tools:${apipath}"
fi
if [ ".${openpkg_tools_apipath}" != . ]; then
    #   user supplied path overrides
    apipath=`echo "${openpkg_tools_apipath}" | sed -e "s;@;${apipath};"`
fi
openpkg_tools_apipath=`echo "${apipath}" | sed -e 's/::/:/g' -e 's/^://' -e 's/:$//'`

##
##  execute stand-alone option commands in advance
##

#   implement stand-alone "--help" option
if [ ".${opt_help}" = .yes ]; then
    release=`${openpkg_prefix}/libexec/openpkg/rpm --eval '%{l_openpkg_release}'`
    echo ""
    echo "This is ${release} <http://www.openpkg.org/>"
    echo "Cross-Platform Unix Software Packaging Facility"
    echo ""
    echo "Copyright (c) 2000-2007 OpenPKG Foundation e.V. <http://openpkg.net/>"
    echo "Copyright (c) 2000-2007 Ralf S. Engelschall <http://engelschall.com/>"
    echo ""
    echo "The command \"${openpkg_prefix}/bin/openpkg\" is the official command-line"
    echo "execution frontend of the OpenPKG tool chain. Its usage is:"
    echo ""
    echo "  \$ ${openpkg_prefix}/bin/openpkg [<option> ...] \\"
    echo "     <command> [<command-option> ...] [<command-argument> ...]"
    echo ""
    echo "where <option> is one of the following global options:"
    echo "  -p, --prefix    sets the OpenPKG instance prefix   (also: \${OPENPKG_PREFIX})"
    echo "  -t, --tools     sets the OpenPKG tool chain prefix (also: \${OPENPKG_TOOLS})"
    echo "  -v, --version   display OpenPKG version/release"
    echo "  -h, --help      display this usage help message"
    echo ""
    echo "where <command> is one of the following commands:"
    echo "  rpm             (provided by bootstrap package)"
    echo "  rpmbuild        (provided by bootstrap package)"
    echo "  rpm2cpio        (provided by bootstrap package)"
    echo "  rpm-config      (provided by bootstrap package)"
    echo "  uuid            (provided by bootstrap package)"
    echo "  rc              (provided by bootstrap package)"
    echo "  lsync           (provided by bootstrap package)"
    echo "  man             (provided by bootstrap package)"
    #   install command intentionally left out in above display!

    #   dynamically figure out add-on commands
    for cmd in rpm rpmbuild rpm2cpio rpm-config uuid rc lsync man install; do
        id=`echo "${cmd}" | sed -e 's/-/_/g'`
        eval "__cmd_seen_${id}=yes"
    done
    OIFS="${IFS}"; IFS=":"
    for dir in ${openpkg_tools_cmdpath}; do
        IFS="${OIFS}"
        if [ ! -d ${dir} ]; then
            continue
        fi
        for cmd in `cd ${dir} 2>/dev/null && echo *`; do
            name=`echo "${cmd}" | sed -e 's/\.sh$//' -e 's/\.pl$//' \
                 -e 's/^/X/' -e 's/^X\([a-z][a-zA-Z0-9_-]*\)$/\1/' -e 's/^X.*$//'`
            if [ ".${name}" != . ]; then
                if [ -f ${dir}/${cmd} ]; then
                    id=`echo "${name}" | sed -e 's/-/_/g'`
                    eval "seen=\$__cmd_seen_${id}"
                    if [ ".${seen}" != .yes ]; then
                        echo "${name}" | awk '{ printf("  %-15s (provided by add-on package)\n", $0); }'
                        eval "__cmd_seen_${id}=yes"
                    fi
                fi
            fi
        done
    done
    IFS="${OIFS}"
    echo ""
    echo "where <command-option> and <command-argument> are <command> specific"
    echo "options and arguments. Run \"${openpkg_prefix}/bin/openpkg <command> --help\""
    echo "and \"${openpkg_prefix}/bin/openpkg man <command>\" for more details."
    echo ""
    exit 0
fi

#   implement stand-alone "--version" option
if [ ".${opt_version}" = .yes ]; then
    release=`${openpkg_prefix}/libexec/openpkg/rpm --eval '%{l_openpkg_release}'`
    version=`${openpkg_prefix}/libexec/openpkg/rpm -q --qf '%{version}' openpkg`
    echo "${release} (${version})"
    exit 0
fi

##
##  determine command details and execute command appropriately
##

#   command line sanity check
if [ ${#} -eq 0 ]; then
    echo "openpkg:ERROR: Invalid command-line arguments." 1>&2
    echo "openpkg:ERROR: Run \"${openpkg_prefix}/bin/openpkg --help\" for list of valid arguments." 1>&2
    exit 1
fi

#   search command by iterating over all command directories
cmd="${1}"
shift
cmd_path=""
cmd_shell=""
cmd_stack="${OPENPKG_TOOLS_CMDSTACK}"
OIFS="${IFS}"; IFS=":"
for dir in ${openpkg_tools_cmdpath}; do
    IFS="${OIFS}"

    #   skip (currently) not existing directory
    if [ ! -d ${dir} ]; then
        continue
    fi

    #   check for various command implementations
    if [ -x ${dir}/${cmd} ]; then
        #   found executable stand-alone binary
        cmd_path="${dir}/${cmd}"
        cmd_shell=""
    elif [ -f ${dir}/${cmd}.sh ]; then
        #   found non-executable Bourne-Shell script
        cmd_path="${dir}/${cmd}.sh"
        cmd_shell="${openpkg_prefix}/lib/openpkg/bash"
    elif [ -f ${dir}/${cmd}.pl ]; then
        #   found non-executable Perl script
        cmd_path="${dir}/${cmd}.pl"
        if [ -x ${openpkg_prefix}/bin/perl ]; then
            cmd_shell="${openpkg_prefix}/bin/perl"
        else
            cmd_shell=`${openpkg_prefix}/lib/openpkg/shtool path -p "$PATH:$openpkg_prefix/lib/openpkg" -m perl 2>&1`
            if [ ".${cmd_shell}" = . ]; then
                echo "openpkg:ERROR: No Perl interpreter found in \${PATH}" 1>&2
                exit 1
            fi
        fi
        #   provide Perl module include path(s) to API
        OIFS="${IFS}"; IFS=":"
        for dir2 in ${openpkg_tools_apipath}; do
            IFS="${OIFS}"
            if [ ! -d ${dir2} ]; then
                continue
            fi
            cmd_shell="${cmd_shell} -I${dir2}"
        done
        IFS="${OIFS}"
    else
        #   command not found, continue searching
        continue
    fi

    #   check whether to use this found command or to continue searching
    #   for next command implementation in sequence (in order to support
    #   flexible nested command wrapping)
    cmd_last=`echo "${cmd_stack}" | sed -e 's;:.*$;;'`
    if [ ".${cmd_last}" = ".${cmd}" ]; then
        #   we were last command on stack, so pop us from call
        #   stack and continue searching for next implementation
        cmd_stack=`echo "${cmd_stack}" | sed -e 's;^[^:][^:]*:*;;'`
        continue
    else
        #   last command on stack was different, so stop
        #   searching because we found the implementation
        break
    fi
done
IFS="${OIFS}"

#   sanity check search result
if [ ".${cmd_path}" = . ]; then
    echo "openpkg:ERROR: No such command \"${cmd}\" found in command path" 1>&2
    echo "openpkg:ERROR: (${openpkg_tools_cmdpath})." 1>&2
    echo "openpkg:ERROR: Set \${OPENPKG_TOOLS_CMDPATH} appropriately." 1>&2
    echo "openpkg:ERROR: Run \"${openpkg_prefix}/bin/openpkg --help\" for list of valid commands." 1>&2
    exit 1
fi

#   export essential run-time information to command
export OPENPKG_PREFIX="$openpkg_prefix"
export OPENPKG_TOOLS_CMDPROG="${0}"
export OPENPKG_TOOLS_CMDNAME="${cmd}"
export OPENPKG_TOOLS_CMDSTACK=`echo "${OPENPKG_TOOLS_CMDSTACK}" | sed -e 's;^\(.\);:\1;' -e "s;^;${cmd};"`

#   execute command
eval "exec ${cmd_shell} ${cmd_path} \${1+\"\$@\"}"

