#!/bin/bash # Authors: Dalibor Pospíšil # Author: Dalibor Pospisil # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Copyright (c) 2012 Red Hat, Inc. All rights reserved. # # This copyrighted material is made available to anyone wishing # to use, modify, copy, or redistribute it subject to the terms # and conditions of the GNU General Public License version 2. # # 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, write to the Free # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # library-prefix = Cleanup # library-version = 9 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ __INTERNAL_Cleanup_LIB_VERSION=9 : <<'=cut' =pod =head1 NAME BeakerLib library Cleanup =head1 DESCRIPTION This file contains functions which provides cleanup stack functionality. =head1 USAGE To use this functionality you need to import library distribution/Cleanup and add following line to Makefile. @echo "RhtsRequires: library(distribution/Cleanup)" >> $(METADATA) B rlJournalStart rlPhaseStartSetup rlImport 'distribution/Cleanup' tmp=$(mktemp) CleanupRegister " rlLog 'Removing data' rlRun \"rm -f ${tmp}\" " rlLog 'Creating some data' rlRun "echo 'asdfalkjh' > $tmp" CleanupRegister " rlLog 'just something to demonstrate unregistering' " ID1=$CleanupRegisterID CleanupUnregister $ID1 CleanupRegister " rlLog 'just something to demonstrate partial cleanup' " ID2=$CleanupRegisterID CleanupRegister "rlLog 'cleanup some more things'" # cleanup everything upto ID2 CleanupDo $ID2 CleanupRegister --mark " rlLog 'yet another something to demonstrate partial cleanup using internal ID saving' " CleanupRegister "rlLog 'cleanup some more things'" # cleanup everything upto last mark CleanupDo --mark rlPhaseEnd rlPhaseStartCleanup CleanupDo rlPhaseEnd rlJournalPrintText rlJournalEnd =head1 FUNCTIONS =cut echo -n "loading library Cleanup v$__INTERNAL_Cleanup_LIB_VERSION... " __INTERNAL_Cleanup_stack_file="$BEAKERLIB_DIR/Cleanup_stack" touch "$__INTERNAL_Cleanup_stack_file" chmod ug+rw "$__INTERNAL_Cleanup_stack_file" # CleanupRegister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ # CleanupRegister [--mark] CLEANUP_CODE # --mark - also mark this position CleanupRegister() { local mark=0 [[ "$1" == "--mark" ]] && { mark=1 shift } if ! CleanupGetStack; then rlLogError "cannot continue, could not get cleanup stack" return 1 fi CleanupRegisterID="${RANDOM}$(date +"%s%N")" echo -n "Registering cleanup ID=$CleanupRegisterID" >&2 if [[ $mark -eq 1 ]]; then __INTERNAL_CleanupMark=( "$CleanupRegisterID" "${__INTERNAL_CleanupMark[@]}" ) echo -n " with mark" >&2 fi echo " '$1'" >&2 rlLogDebug "prepending '$1'" local ID_tag="# ID='$CleanupRegisterID'" __INTERNAL_Cleanup_stack="$ID_tag $1 $ID_tag $__INTERNAL_Cleanup_stack" if ! CleanupSetStack "$__INTERNAL_Cleanup_stack"; then rlLogError "an error occured while registering the cleanup '$1'" return 1 fi return 0 }; # end of CleanupRegister }}} # __INTERNAL_Cleanup_get_stack_part ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ # 1: ID # -ID - everything upto the ID # 2: '' - return ID only # 'rest' - return exact oposit __INTERNAL_Cleanup_get_stack_part() { rlLogDebug "__INTERNAL_Cleanup_get_stack_part(): $* begin" local ID="$1" local n='1 0 1' local stack='' [[ "${ID:0:1}" == "-" ]] && { ID="${ID:1}" n='0 0 1' } [[ "$2" == "rest" ]] && { n="$(echo "${n//0/2}")" n="$(echo "${n//1/0}")" n="$(echo "${n//2/1}")" } n=($n) [[ -n "$DEBUG" ]] && rlLogDebug "$(set | grep ^n=)" local ID_tag="# ID='$ID'" while IFS= read -r line; do [[ "$line" == "$ID_tag" ]] && { n=( "${n[@]:1}" ) continue } if [[ $n -eq 0 ]]; then stack="$stack $line" fi done < <(echo "$__INTERNAL_Cleanup_stack") rlLogDebug "__INTERNAL_Cleanup_get_stack_part(): cleanup stack part is '${stack:1}'" echo "${stack:1}" rlLogDebug "__INTERNAL_Cleanup_get_stack_part(): $* end" }; # end of __INTERNAL_Cleanup_get_stack_part }}} # CleanupUnregister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ CleanupUnregister() { local ID="$1" rlLog "Unregistering cleanup ID='$ID'" if ! CleanupGetStack; then rlLogError "cannot continue, could not get cleanup stack" return 1 fi rlLogDebug "removing ID='$ID'" if ! CleanupSetStack "$(__INTERNAL_Cleanup_get_stack_part "$ID" 'rest')"; then rlLogError "an error occured while registering the cleanup '$1'" return 1 fi return 0 }; # end of CleanupUnregister }}} # CleanupMark ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ __INTERNAL_CleanupMark=() CleanupMark() { echo -n "Setting cleanup mark" >&2 CleanupRegister --mark '' 2>/dev/null local res=$? echo " ID='$CleanupRegisterID'" >&2 return $res }; # end of CleanupMark }}} # CleanupDo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ # 1: '' - cleanup all # ID - cleanup ID only # -ID - cleanup all upto ID, including # mark - cleanup all unto last mark, including CleanupDo() { local ID="$1" if ! CleanupGetStack; then rlLogError "cannot continue, could not get cleanup stack" return 1 fi local res tmp newstack='' tmp="$(mktemp)" if [[ "$ID" == "mark" || "$ID" == "--mark" ]]; then echo "execute cleanup upto mark='$__INTERNAL_CleanupMark'" >&2 __INTERNAL_Cleanup_get_stack_part "-$__INTERNAL_CleanupMark" | grep -v "^# ID='" > "$tmp" newstack="$(__INTERNAL_Cleanup_get_stack_part "-$__INTERNAL_CleanupMark" 'rest')" __INTERNAL_CleanupMark=("${__INTERNAL_CleanupMark[@]:1}") elif [[ -n "$ID" ]]; then echo "execute cleanup for ID='$ID'" >&2 __INTERNAL_Cleanup_get_stack_part "$ID" | grep -v "^# ID='" > "$tmp" newstack="$(__INTERNAL_Cleanup_get_stack_part "$ID" 'rest')" else CleanupTrapUnhook trap "echo 'temporarily blocking ctrl+c until cleanup is done' >&2" SIGINT cat "$__INTERNAL_Cleanup_stack_file" | grep -v "^# ID='" > "$tmp" echo "execute whole cleanup stack" >&2 fi . "$tmp" res=$? [[ $res -ne 0 ]] && { echo "cleanup code:" >&2 cat -n "$tmp" >&2 } rm -f "$tmp" echo "cleanup execution done" >&2 if [[ -z "$ID" ]]; then trap - SIGINT fi if ! CleanupSetStack "$newstack"; then rlLogError "an error occured while cleaning the stack" return 1 fi return $res }; # end of CleanupDo }}} # CleanupGetStack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ CleanupGetStack() { rlLogDebug "getting cleanup stack" if [[ -r "$__INTERNAL_Cleanup_stack_file" ]]; then if __INTERNAL_Cleanup_stack="$(cat "$__INTERNAL_Cleanup_stack_file")"; then rlLogDebug "cleanup stack is '$__INTERNAL_Cleanup_stack'" return 0 fi fi rlLogError "could not load cleanup stack" return 1 }; # end of CleanupGetStack }}} # CleanupSetStack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ CleanupSetStack() { rlLogDebug "setting cleanup stack to '$1'" __INTERNAL_Cleanup_stack="$1" if echo "$__INTERNAL_Cleanup_stack" > "$__INTERNAL_Cleanup_stack_file"; then rlLogDebug "cleanup stack is now '$__INTERNAL_Cleanup_stack'" return 0 fi rlLogError "could not set cleanup stack" return 1 }; # end of CleanupSetStack }}} __INTERNAL_Cleanup_signals='' __INTERNAL_Cleanup_trap_code='rlJournalStart; rlPhaseStartCleanup; CleanupDo; rlPhaseEnd; rlJournalPrintText; rlJournalEnd; exit' # CleanupTrapHook ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ CleanupTrapHook() { rlLog "register cleanup trap" __INTERNAL_Cleanup_signals="${1:-"SIGHUP SIGINT SIGTERM EXIT"}" eval "trap \"${__INTERNAL_Cleanup_trap_code}\" $__INTERNAL_Cleanup_signals" }; # end of CleanupTrapHook }}} # CleanupTrapUnhook ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ CleanupTrapUnhook() { if [[ -n "$__INTERNAL_Cleanup_signals" ]]; then rlLog "unregister cleanup trap" eval trap - $__INTERNAL_Cleanup_signals __INTERNAL_Cleanup_signals='' fi }; # end of CleanupTrapUnhook }}} # CleanupLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ CleanupLibraryLoaded() { CleanupTrapHook }; # end of CleanupLibraryLoaded }}} echo "done." : <<'=cut' =pod =head1 AUTHORS =over =item * Dalibor Pospisil =back =cut