#!/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_register_error_types ADEINST_DEFINED_ERRORS # Defaults for options OPT_MODE=unset OPT_PERMS=unset #OPT_GROUP=unset #OPT_OWNER=unset # Register adeinst's options ade_register_options "$ERRSTACK_REF" -o m:D --longoptions=perms: --callback-template="handle_option_%s" || return $? ade_set_callbacks "$ERRSTACK_REF" adeinst_usage_help adeinst_version adeinst_paths || return $? # Process options ade_process_options "$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_error "$ERRSTACK_REF" ADEINST_ERR_MISC "$OPT_PERMS: invalid permissions" return $ADE_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_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_show_bad_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_show_bad_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_OK ]; then return $RC fi return $ADE_OK } mode_1() { local ERRSTACK_REF SRCFILES DSTDIR # Process arguments ERRSTACK_REF="$1"; shift SRCFILE=$1 DSTFILE=$2 ade_debug "$ERRSTACK_REF" 10 "mode_1: SRCFILE=$SRCFILE, DSTFILE=$DSTFILE" # Sanity checks if [ ! -h "$SRCFILE" -a ! -f "$SRCFILE" ]; then ade_error "$ERRSTACK_REF" ADEINST_ERR_MISC "$SRCFILE: not found or not a file/symlink" return $ADE_FAIL fi if [ -e "$DSTFILE" ] && [ ! -h "$DSTFILE" -a ! -f "$DSTFILE" ]; then ade_error "$ERRSTACK_REF" ADEINST_ERR_MISC "$DSTFILE: exists but is not a file/sylink" return $ADE_FAIL fi # Make leading directory components mode_3 "$ERRSTACK_REF" "${DSTFILE%/*}" # copy file in ade_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" ] || ade_evaler "$ERRSTACK_REF" "chmod \"$OPT_PERMS\" \"$DSTFILE\"" return $ADE_OK } mode_2() { local ERRSTACK_REF SRCFILES DSTDIR # Process arguments ERRSTACK_REF="$1"; shift SRCFILES=( "${@:1:$#-1}" ) DSTDIR=${@:$#} ade_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_error "$ERRSTACK_REF" ADEINST_ERR_MISC "$SRCFILE: not found or not a file/symlink" return $ADE_FAIL fi done if [ ! -d "$DSTDIR" ]; then ade_error "$ERRSTACK_REF" ADEINST_ERR_MISC "$DSTDIR: not found or not a directory" return $ADE_FAIL fi # Guts for SRCFILE in "${SRCFILES[@]}"; do mode_1 "$ERRSTACK_REF" "$SRCFILE" "$DSTDIR/${SRCFILE##*/}" RC=$? if [ $RC != $ADE_OK ]; then return $RC fi done return $ADE_OK } mode_3() { local ERRSTACK_REF DIR ERRSTACK_REF="$1"; shift ade_debug "$ERRSTACK_REF" 10 "mode_3: DIRS=( $* )" for DIR in "$@"; do ade_evaler "$ERRSTACK_REF" "mkdir --parents ${MKDIR_PERMS:+--mode=$MKDIR_PERMS} \"$DIR\"" done return $ADE_OK } adeinst_usage_help() { local ERRSTACK_REF="$1"; shift local USAGE_TEXT_SHORT_REF="$1"; shift local USAGE_TEXT_LONG_REF="$1"; shift eval "$USAGE_TEXT_SHORT_REF=\"...\"" eval "$USAGE_TEXT_LONG_REF=\"\ -n | --simulate simulate -D create directories -m | --perms= install with mode \"" return $ADE_OK } adeinst_paths() { local ERRSTACK_REF="$1"; shift local PATHLIST_REF=$1; shift eval "$PATHLIST_REF=\"\ \"" return $ADE_OK } adeinst_version() { local ERRSTACK_REF="$1"; shift local VERSION_REF=$1; shift ade_extract_version "$ERRSTACK_REF" "$APP_SVNID" "$VERSION_REF" return $ADE_OK } handle_option_m() { handle_option_perms "$@" } handle_option_D() { local ERRSTACK_REF="$1"; shift OPT_MODE=3 return $ADE_OK } handle_option_perms() { local ERRSTACK_REF="$1"; shift OPT_PERMS="$1" return $ADE_OK } ade_main adeinst "$@"