#!/bin/bash APP_SVNID='$HeadURL$ $LastChangedRevision$' . $(ade-config ade_share_prefix)/include/ade.sh || { echo "${0##*/}: INTERNAL ERROR: failed to load ade.sh" >&2; exit 3; } ADEINST_DEFINED_ERRORS=( "KEY=ADEINST_ERR_MISC; FMT=\"%s\"" ) adeinst() { local OPTVAL LISTPATHS RC TEMP ERRSTACK_REF ERRSTACK_REF="$1" shift # Register application-specific errors ade_err_registerdefderrs ADEINST_DEFINED_ERRORS # Defaults for options OPT_MODE=unset OPT_SIMULATE=false OPT_PERMS=unset #OPT_GROUP=unset #OPT_OWNER=unset # Register adeinst's options ade_opt_register "$ERRSTACK_REF" -o nm:D --longoptions=simulate,perms: --callback-template="adeinst_opt_handler_%s" || return $? ade_msg_register "$ERRSTACK_REF" adeinst_usage adeinst_version adeinst_listpaths || return $? # Process options ade_opt_process "$ERRSTACK_REF" NEW_DOLLAR_AT "$@" || return $? set -- "${NEW_DOLLAR_AT[@]}" # Argument processing # (delegated) # Sanity checks and derivations if [ "X$OPT_PERMS" = Xunset ]; then MKDIR_PERMS= elif ! [[ $OPT_PERMS =~ ^([0-7])([0-7])([0-7])$ ]]; then ade_err_error "$ERRSTACK_REF" ADEINST_ERR_MISC "$OPT_PERMS: invalid permissions" return $ADE_ERR_FAIL else # Convert 644 to 755, etc (int-divide by 2 to make 6 and 7 both map to 3, multiply by 2 and add 1). MKDIR_PERMS="$(( 2 * (${BASH_REMATCH[1]} / 2) + 1 ))$(( 2 * (${BASH_REMATCH[2]} / 2) + 1 ))$(( 2 * (${BASH_REMATCH[3]} / 2) + 1 ))" ade_err_debug "$ERRSTACK_REF" 10 "adeinst: OPT_PERMS=$OPT_PERMS, MKDIR_PERMS=$MKDIR_PERMS" fi # Guts # Mode needs at least one argument. if [ $OPT_MODE = 3 ] && [ $# -lt 1 ]; then ade_msg_usage "$ERRSTACK_REF" # Mode 3 is equivalent to 'mkdir ...'. The choice to use mode 3 is # made by command line option '-D'. elif [ $OPT_MODE = 3 ]; then mode_3 "$ERRSTACK_REF" "$@" RC=$? # Mode 1 is equivalent to 'cp '. The choice to use mode 1 is # made by having two args and the second is either an existing file or doesn't # exist. elif [ $# = 2 ] && [ -h "$1" -o -f "$1" ] && [ -f "$2" -o ! -e "$2" ]; then mode_1 "$ERRSTACK_REF" "$@" RC=$? # Then remaining mode (mode 2) needs at least two arguments. elif [ $# -lt 2 ]; then ade_msg_usage "$ERRSTACK_REF" # Mode 3 is equivalent to 'cp ... '. The choice is made # by not being either of the other two modes. else mode_2 "$ERRSTACK_REF" "$@" RC=$? fi if [ $RC != $ADE_ERR_OK ]; then return $RC fi return $ADE_ERR_OK } mode_1() { local ERRSTACK_REF SRCFILES DSTDIR # Process arguments ERRSTACK_REF="$1"; shift SRCFILE=$1 DSTFILE=$2 ade_err_debug "$ERRSTACK_REF" 10 "mode_1: SRCFILE=$SRCFILE, DSTFILE=$DSTFILE" # Sanity checks if [ ! -h "$SRCFILE" -a ! -f "$SRCFILE" ]; then ade_err_error "$ERRSTACK_REF" ADEINST_ERR_MISC "$SRCFILE: not found or not a file/symlink" return $ADE_ERR_FAIL fi if [ -e "$DSTFILE" ] && [ ! -h "$DSTFILE" -a ! -f "$DSTFILE" ]; then ade_err_error "$ERRSTACK_REF" ADEINST_ERR_MISC "$DSTFILE: exists but is not a file/sylink" return $ADE_ERR_FAIL fi # Make leading directory components mode_3 "$ERRSTACK_REF" "${DSTFILE%/*}" # copy file in adeinst_evaler "$ERRSTACK_REF" "cp --no-dereference --remove-destination \"$SRCFILE\" \"$DSTFILE\"" # symlinks really are nod chmod-able on Linux; but their permissions are never read so it doesn't matter. [ $OPT_PERMS = unset ] || [ -h "$DSTFILE" ] || adeinst_evaler "$ERRSTACK_REF" "chmod \"$OPT_PERMS\" \"$DSTFILE\"" return $ADE_ERR_OK } mode_2() { local ERRSTACK_REF SRCFILES DSTDIR # Process arguments ERRSTACK_REF="$1"; shift SRCFILES=( "${@:1:$#-1}" ) DSTDIR=${@:$#} ade_err_debug "$ERRSTACK_REF" 10 "mode_2: DSTDIR=$DSTDIR, SRCFILES=( ${SRCFILES[*]} )" # Sanity checks for SRCFILE in "${SRCFILES[@]}"; do if [ ! -h "$SRCFILE" -a ! -f "$SRCFILE" ]; then ade_err_error "$ERRSTACK_REF" ADEINST_ERR_MISC "$SRCFILE: not found or not a file/symlink" return $ADE_ERR_FAIL fi done if [ ! -d "$DSTDIR" ]; then ade_err_error "$ERRSTACK_REF" ADEINST_ERR_MISC "$DSTDIR: not found or not a directory" return $ADE_ERR_FAIL fi # Guts for SRCFILE in "${SRCFILES[@]}"; do mode_1 "$ERRSTACK_REF" "$SRCFILE" "$DSTDIR/${SRCFILE##*/}" RC=$? if [ $RC != $ADE_ERR_OK ]; then return $RC fi done return $ADE_ERR_OK } mode_3() { local ERRSTACK_REF DIR ERRSTACK_REF="$1"; shift ade_err_debug "$ERRSTACK_REF" 10 "mode_3: DIRS=( $* )" for DIR in "$@"; do adeinst_evaler "$ERRSTACK_REF" "mkdir --parents ${MKDIR_PERMS:+--mode=$MKDIR_PERMS} \"$DIR\"" done return $ADE_ERR_OK } # There is no technical need for this function to have a module prefix (this file # is not sourced by any others). However, I grep for this function but written # without the prefix (which I'm trying in this comment not to explicitly write) # in order to find scripts that should be using miniade but aren't. ADE itself # doesn't provide its functionality (unlike miniade). Hence defining it here. adeinst_evaler() { local ERRSTACK_REF CMD ERRSTACK_REF="$1"; shift CMD="$1" if $OPT_SIMULATE; then echo "$CMD" else eval "$CMD" fi } adeinst_usage() { local ERRSTACK_REF="$1"; shift local USAGETEXT_REF="$1"; shift local PASSNO=$1; shift if [ $PASSNO = 1 ]; then eval "$USAGETEXT_REF=\"...\"" elif [ $PASSNO = 2 ]; then eval "$USAGETEXT_REF=\"\ -n | --simulate simulate -D create directories -m | --perms= install with mode \"" fi return $ADE_ERR_OK } adeinst_listpaths() { local ERRSTACK_REF="$1"; shift local PATHLIST_REF=$1; shift eval "$PATHLIST_REF=\"\ \"" return $ADE_ERR_OK } adeinst_version() { local ERRSTACK_REF="$1"; shift local VERSION_REF=$1; shift ade_smf_extractversionfromsvnstring "$ERRSTACK_REF" "$APP_SVNID" "$VERSION_REF" return $ADE_ERR_OK } adeinst_opt_handler_m() { adeinst_opt_handler_perms "$@" } adeinst_opt_handler_D() { local ERRSTACK_REF="$1"; shift OPT_MODE=3 return $ADE_ERR_OK } adeinst_opt_handler_perms() { local ERRSTACK_REF="$1"; shift OPT_PERMS="$1" return $ADE_ERR_OK } adeinst_opt_handler_n() { adeinst_opt_handler_simulate "$@" } adeinst_opt_handler_simulate() { local ERRSTACK_REF="$1"; shift OPT_SIMULATE="$1" return $ADE_ERR_OK } ade_gep_main adeinst "$@"