#!/bin/bash # $HeadURL$ $LastChangedRevision$ set -e { [[ $0 =~ ^/ ]] && PROGNAME_FULL=$0; } || PROGNAME_FULL=$(cd $PWD/$(dirname $0) && pwd)/$(basename $0) PROGNAME=$(basename $0) #PROGNAME=${PROGNAME_FULL//\//_} # MODROOT MODROOT=${MDI_MODROOT:-$(while [ ! -d lib/helpers -a $PWD != / ]; do cd ..; done; echo $PWD)} [ -d $MODROOT/lib/helpers ] || { echo "$PROGNAME: ERROR: can't find components (do you need to set 'MDI_MODROOT'?)" >&2; exit 1; } # Load config and support functions . $MODROOT/include/mdi.sh . $MODROOT/etc/mdi.sh # Globals main() { # Defaults for options VERBOSELEVEL=2 HELPER_HOOKS_FILE=$PROGNAME_FULL-hooks DISPLAY_PROGNAME=$(basename $(dirname $PROGNAME_FULL)) RECURSE_FLAG=true # Process options while [ "X$1" != X ]; do case $1 in # Application-specific options --helper-hooks=*) HELPER_HOOKS_FILE=${1#*=} ;; --progname=*) DISPLAY_PROGNAME=${1#*=} ;; --recurse=*) RECURSE_FLAG=${1#*=} ;; # General options -v|--verbose) VERBOSELEVEL=3 ;; -d) VERBOSELEVEL=$2; shift ;; --debug=*) VERBOSELEVEL=${1#*=} ;; -h|--help) usage 0 ;; --) shift; break ;; -*) usage ;; *) break ;; esac shift done # Process arguments [ $# -ge 1 ] || usage MODE=$1; shift debug 10 "main: MODE=$MODE" case $MODE in edit|create|delete|list|purge|init) : ;; *) usage ;; esac # Sanity checks and derivations debug 10 "main: sanity checks ..." [ $RECURSE_FLAG = true -o $RECURSE_FLAG = false ] || usage debug 10 "main: calling [. $HELPER_HOOKS_FILE] ..." . $HELPER_HOOKS_FILE debug 10 "main: after call" inherit MY_ID MY_ATTRIBUTES PARENT_ID # Delegate debug 10 "main: delegating ..." $MODE "$@" return 0 } init() { local HELPER CMDLINE inherit MY_HELPER_IDS MY_ID MY_PRIVATE_ATTRIBUTES MY_PUBLIC_ATTRIBUTES PARENT_ID # Process arguments [ $# = 0 ] || usage # Sanity checks and derivations # Guts info "initialising ..." debug 10 "init: calling init_prologue() ..." init_prologue || return $? debug 10 "init: registering helper ..." $SQLITE_CMD $DB_FILE "insert into helpers (helper, parent_helper) values ('$MY_ID', '$PARENT_ID');" debug 10 "init: registering attributes ..." for ATTRIBUTE in $MY_PRIVATE_ATTRIBUTES; do $SQLITE_CMD $DB_FILE "insert into attributes (helper, attribute, public) values ('$MY_ID', '$ATTRIBUTE', 0);" done for ATTRIBUTE in $MY_PUBLIC_ATTRIBUTES; do $SQLITE_CMD $DB_FILE "insert into attributes (helper, attribute, public) values ('$MY_ID', '$ATTRIBUTE', 1);" done if [ $RECURSE_FLAG = true ]; then for HELPER in $MY_HELPER_IDS; do ( cd $HELPER && ./helper --progname=$DISPLAY_PROGNAME/$HELPER --debug=$VERBOSELEVEL init ) || return $? done fi debug 10 "init: calling init_epilogue() ..." init_epilogue || return $? return 0 } init_prologue() { return 0 } init_epilogue() { return 0 } list() { local HELPER inherit RECURSE_FLAG MY_HELPER_IDS # Process arguments [ $# = 0 ] || usage debug 10 "list: " # Sanity checks and derivations # Guts debug 10 "list: calling list_prologue() ..." list_prologue || return $? if [ $RECURSE_FLAG = true ]; then for HELPER in $MY_HELPER_IDS; do debug 10 "list: calling $HELPER helper ..." ( cd $HELPER && ./helper --progname=$DISPLAY_PROGNAME/$HELPER --debug=$VERBOSELEVEL list ) || return $? done fi return 0 } # Stupid hook to dump the table. list_prologue() { inherit SQLITE_CMD DB_FILE MY_ID MY_ATTRIBUTES printf "%${#MY_ID}.${#MY_ID}s\n" "$MY_ID" printf "%${#MY_ID}.${#MY_ID}s\n" "===================================" echo $SQLITE_CMD $DB_FILE "select uname from attribute_values where helper == '$MY_ID' and attribute == 'status' and value == 'installing';" echo return 0 } edit() { # arguments local UNAME # my properties inherit MY_ID MY_HELPER_IDS MY_ATTRIBUTES # globals inherit RECURSE_FLAG # real locals local HELPER # Process arguments [ $# = 1 ] || usage UNAME=$1; shift debug 10 "edit: UNAME=$UNAME" # Sanity checks and derivations # Guts info "editing settings ..." debug 10 "edit: loading local (public and private) attribute values ..." load_local_attributes $MY_ID $UNAME "$MY_ATTRIBUTES" debug 10 "edit: loading inherited attribute names ..." MY_INHERITED_ATTRIBUTES=$(list_inherited_attributes $MY_ID) debug 10 "edit: MY_INHERITED_ATTRIBUTES=\"$MY_INHERITED_ATTRIBUTES\"" if [ "X$MY_INHERITED_ATTRIBUTES" != X ]; then local ${MY_INHERITED_ATTRIBUTES^^} debug 10 "edit: loading inherited attribute values ..." load_inherited_attributes $MY_ID $UNAME "$MY_INHERITED_ATTRIBUTES" fi debug 10 "edit: setting any of my attributes that are blank to a default ..." for ATTRIBUTE in $MY_ATTRIBUTES; do eval "[ \"X\$${ATTRIBUTE^^}\" != X ] || ${ATTRIBUTE^^}=\"\$DFLT_${ATTRIBUTE^^}\"" done # Guts debug 10 "edit: calling edit_prologue() ..." edit_prologue || return $? STATUS="not installing" debug 10 "edit: saving new values ..." debug 10 "edit: UNAME=$UNAME" save_local_attributes $MY_ID $UNAME "$MY_ATTRIBUTES" if [ $RECURSE_FLAG = true ]; then for HELPER in $MY_HELPER_IDS; do debug 10 "edit: calling $HELPER helper ..." ( cd $HELPER && ./helper --progname=$DISPLAY_PROGNAME/$HELPER --debug=$VERBOSELEVEL edit $UNAME ) || return $? done fi return 0 } edit_prologue() { return 0 } create() { # locals for parameters local UNAME # my properties inherit MY_HELPER_IDS MY_ID MY_ATTRIBUTES # globals inherit RECURSE_FLAG # locals local HELPER COUNT MY_INHERITED_ATTRIBUTES # Process arguments [ $# = 1 ] || usage UNAME=$1; shift debug 10 "create: UNAME=$UNAME, MY_ID=$MY_ID" # Sanity checks and derivations debug 10 "create: loading local (public and private) attribute values ..." load_local_attributes $MY_ID $UNAME "$MY_ATTRIBUTES" debug 10 "create: loading inherited attribute values ..." MY_INHERITED_ATTRIBUTES=$(list_inherited_attributes $MY_ID) if [ "X$MY_INHERITED_ATTRIBUTES" != X ]; then local ${MY_INHERITED_ATTRIBUTES^^} debug 10 "edit: loading inherited attribute values ..." load_inherited_attributes $MY_ID $UNAME "$MY_INHERITED_ATTRIBUTES" fi if [ "X$STATUS" = X ]; then error "$UNAME: no config found (do you need to run 'mdi edit $UNAME'?)" return 1 elif [ "X$STATUS" = Xinstalling ]; then error "$UNAME: appears to be being installed already" return 1 elif [ "X$STATUS" = "Xnot installing" ]; then : else internal "create: $STATUS: invalid status" fi # Guts debug 10 "create: marking installing ..." $SQLITE_CMD $DB_FILE "update attribute_values set value = 'installing' where helper == '$MY_ID' and attribute == 'status' and uname == '$UNAME';" # From here on, if anything goes wrong then we call the delete() function to handler it. debug 10 "create: calling create_prologue() ..." create_prologue || { RC=$? delete $UNAME || internal "create: create_prologue() failed, we tried to rollback by calling delete() but that failed too!" return $RC } # create_prologue() may change MY_HELPER_IDS debug 10 "create: after calling create_prologue(), MY_HELPER_IDS=\"$MY_HELPER_IDS\"" if [ $RECURSE_FLAG = true ]; then RC=0 SUCCESSFULLY_COMPLETED_HELPERS=() for HELPER in $MY_HELPER_IDS; do debug 10 "create: calling sub-helper $HELPER ..." ( cd $HELPER && ./helper --progname=$DISPLAY_PROGNAME/$HELPER --debug=$VERBOSELEVEL create $UNAME ) || { RC=$? delete $UNAME || internal "create: sub-helper $HELPER failed, we tried to rollback by calling delete() but that failed too!" return $RC } done fi debug 10 "create: calling create_epilogue() ..." create_epilogue || { RC=$? delete $UNAME || internal "create: create_epilogue() failed, we tried to rollback by calling delete() but that failed too!" return $RC } # No counterpart to lock code above. return 0 } create_prologue() { return 0 } create_epilogue() { return 0 } delete() { # arguments local UNAME # my properties inherit MY_HELPER_IDS MY_ID # globals inherit RECURSE_FLAG # real locals local HELPER # Process arguments [ $# = 1 ] || usage UNAME=$1; shift debug 10 "delete: UNAME=$UNAME, MY_ID=$MY_ID" delete_or_purge delete $UNAME } purge() { # arguments local UNAME # my properties inherit MY_HELPER_IDS MY_ID # globals inherit RECURSE_FLAG # real locals local HELPER # Process arguments [ $# = 1 ] || usage UNAME=$1; shift debug 10 "purge: UNAME=$UNAME, MY_ID=$MY_ID" delete_or_purge purge $UNAME } delete_or_purge() { # arguments local UNAME # my properties inherit MY_HELPER_IDS MY_ID # globals inherit RECURSE_FLAG # real locals local MODE HELPER # Process arguments [ $# = 2 ] || usage MODE=$1; shift UNAME=$1; shift debug 10 "delete_or_purge: MODE=$MODE, UNAME=$UNAME, MY_ID=$MY_ID" # Sanity checks and derivations debug 10 "delete_or_purge: loading local (public and private) attribute values ..." load_local_attributes $MY_ID $UNAME "$MY_ATTRIBUTES" debug 10 "delete_or_purge: loading inherited attribute values ..." MY_INHERITED_ATTRIBUTES=$(list_inherited_attributes $MY_ID) if [ "X$MY_INHERITED_ATTRIBUTES" != X ]; then local ${MY_INHERITED_ATTRIBUTES^^} debug 10 "edit: loading inherited attribute values ..." load_inherited_attributes $MY_ID $UNAME "$MY_INHERITED_ATTRIBUTES" fi if [ $MODE = delete ];then if [ "X$STATUS" = X ]; then return 0 elif [ "X$STATUS" = Xinstalling ]; then : elif [ "X$STATUS" = "Xnot installing" ]; then return 0 else internal "delete_or_purge: $STATUS: invalid status" fi fi # Guts debug 10 "delete_or_purge: calling delete_prologue() ..." delete_prologue || internal "delete_or_purge: delete_prologue() failed; it is illegal for any delete operation to fail!" debug 10 "delete_or_purge: after calling delete_prologue(), MY_HELPER_IDS=\"$MY_HELPER_IDS\"" if [ $RECURSE_FLAG = true ]; then for HELPER in $(echo $MY_HELPER_IDS | xargs -n 1 echo | tac | xargs echo); do debug 10 "delete_or_purge: calling $HELPER helper ..." ( cd $HELPER && ./helper --progname=$DISPLAY_PROGNAME/$HELPER --debug=$VERBOSELEVEL $MODE $UNAME ) || { internal "delete_or_purge: sub-helper $HELPER failed; it is illegal for any delete operation to fail!" } done fi debug 10 "delete_or_purge: calling delete_epilogue() ..." delete_epilogue || internal "delete_or_purge: delete_epilogue() failed; it is illegal for any delete operation to fail!" debug 10 "delete_or_purge: marking not installing ..." $SQLITE_CMD $DB_FILE "update attribute_values set value = 'not installing' where helper == '$MY_ID' and attribute == 'status' and uname == '$UNAME';" return 0 } delete_prologue() { return 0 } delete_epilogue() { return 0 } usage() { local RC RC=${1:-1} { echo "Usage: $DISPLAY_PROGNAME [ ] { edit | create | delete | purge | init | list }" echo } | if [ $RC = 0 ]; then cat else cat >&2 fi exit $RC } main "$@"