From 7724c3effd7d2b3459b0a3379977d9e84cab654e Mon Sep 17 00:00:00 2001 From: steadfasterX Date: Fri, 14 Apr 2023 08:24:46 +0000 Subject: [PATCH 1/3] make divest functions error aware this commit adds (the currently non-existing) error handling when using divest's functions and scripts. all the magic here gets activated when `source ../../Scripts/init.sh` gets executed which is already a mandatory step before starting any of the divest functions. when something fails during patching, resetting or building each error will be catched + printed including an error code now. last but not least the executed file and the line number causing that failure will be shown, too. as all divest functions get source'd and so not a single build script gets executed all ERR's needs to be trapped to catch issues. I am not aware of another way to handle that properly as sourcing means we cannot track a script or smth while this approach here just works. Example for an error thrown in a function call: > ERROR: $DOS_WORKSPACE_ROOT/Scripts/Common/Functions.sh -> verifyAllPlatformTags() ended with status >1< at line >49< Final SUCCESS result message after using `patchWorkspace`: > [FINAL RESULT] No error detected (please check the above output nevertheless!) Final ERROR result message after using `patchWorkspace`: > [FINAL RESULT] Serious error(s) found!!! > Summary error code was: 126. Check & fix all error lines above Some notes: - when an error occurs the process continues until the end (like it is now) i.e. an error will not stop the current and following tasks - when multiple errors occur the exit codes will be summed - buildDevice: a (summed) end result gets printed (SUCCESS or ERROR) at the very end - the trap used to catch any error will also be active for any command executed on the cli. that means: type "false" -> ENTER and you will get an error, too same for any script exectued after source init.sh - when all goes well the trap will be resetted at the end but there are cases where this might not happen -> that is why `resetEnv` can be executed to reset the trap, i.e. all becomes as it was before sourcing init.sh - `resetEnv` gets called automatically: - after a successful `patchWorkspace` run - whenever CTRL+C is used (during a running task or just on the cli) - a process get killed (SIGHUP, TERM) - the whole implementation might not catch all errors though - it highly depends on how the function or the script/program called actually handles errors or better said: if they return a proper exit code on failures. For example some tools (like some git cmds) might print an error but don't return a non-zero exit code. This cannot be tracked other then with your eyes or these must be replaced by other methods returning a non-zero exit code on failures. Signed-off-by: steadfasterX --- Scripts/Common/Functions.sh | 13 +++++++++++++ Scripts/Common/Post.sh | 2 ++ Scripts/init.sh | 36 ++++++++++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/Scripts/Common/Functions.sh b/Scripts/Common/Functions.sh index b9cd35ff..ed85e641 100644 --- a/Scripts/Common/Functions.sh +++ b/Scripts/Common/Functions.sh @@ -16,6 +16,19 @@ #along with this program. If not, see . umask 0022; +_fetchError(){ + local last_status="$1"; + local error_line_number="$2"; + local last_func="$3"; + local file=$(echo "$4" | sed "s#$DOS_WORKSPACE_ROOT#\$DOS_WORKSPACE_ROOT#g"); + if [ ! -z "$last_func" ] && [ ! -z "$file" ];then + echo -e "\e[0;31mERROR: $file -> ${last_func}() ended with status >${last_status}< at line >$((error_line_number -1))<\e[0m"; + else + echo -e "\e[0;31mERROR: last command ended with status >${last_status}< at line >$((error_line_number -1))<\e[0m"; + fi +} +export -f _fetchError; + startPatcher() { java -jar "$DOS_BINARY_PATCHER" patch workspace "$DOS_BUILD_BASE" "$DOS_WORKSPACE_ROOT""Patches/Linux/" "$DOS_SCRIPTS_CVES" $1; } diff --git a/Scripts/Common/Post.sh b/Scripts/Common/Post.sh index a3c91472..ca257417 100644 --- a/Scripts/Common/Post.sh +++ b/Scripts/Common/Post.sh @@ -58,3 +58,5 @@ sed -i '/android.software.managed_users/s/notLowRam="true"//' frameworks/native/ cd "$DOS_BUILD_BASE"; echo -e "\e[0;32m[SCRIPT COMPLETE] Post tweaks complete\e[0m"; + +kill -USR2 $TR_PID diff --git a/Scripts/init.sh b/Scripts/init.sh index 1d06d163..e089293c 100644 --- a/Scripts/init.sh +++ b/Scripts/init.sh @@ -117,6 +117,38 @@ export DOS_THEME_700="E64A19"; #Deep Orange 700 umask 0022; +export TR_ERR=0 +export TR_PID=$$ + +set -E; #required for resetEnv() +resetEnv(){ + trap - ERR EXIT USR2 SIGINT SIGHUP TERM + echo -e "\n\e[0;32mThe environment has been reset.\e[0m\nRemember to always '\e[0;31msource ../../Scripts/init.sh\e[0m' before building.\n" + set +E +f +} +export -f resetEnv + +# print result +# will also ensure the corresponding status code gets returned properly +_errorReport(){ + if [ "$TR_ERR" -ne 0 ];then + echo -e "\n\e[0;31m[FINAL RESULT] Serious error(s) found!!!\nSummary error code was: $TR_ERR. Check & fix all error lines above\e[0m" + else + echo -e "\n\e[0;32m[FINAL RESULT] No error detected (please check the above output nevertheless!)\e[0m" + fi + return $TR_ERR +} +export -f _errorReport + +# trap and print errors +# ERR: needed to fetch aborts when set -e is set +trap 'E=$?; \ + [ $E -ne 0 ] && _fetchError $E $LINENO $FUNCNAME $BASH_SOURCE \ + && export TR_ERR=$((TR_ERR + $E))' EXIT ERR + +trap _errorReport USR2 +trap resetEnv SIGINT SIGHUP TERM + gpgVerifyGitHead() { if [ -r "$DOS_TMP_GNUPG/pubring.kbx" ]; then if git -C "$1" verify-commit HEAD &>/dev/null; then @@ -203,5 +235,5 @@ source "$DOS_SCRIPTS_COMMON/Functions.sh"; source "$DOS_SCRIPTS_COMMON/Tag_Verifier.sh"; source "$DOS_SCRIPTS/Functions.sh"; -[[ -f "$DOS_BUILD_BASE/.repo/local_manifests/roomservice.xml" ]] && echo "roomservice manifest found! Please fix your manifests before continuing!"; -[[ -f "$DOS_BUILD_BASE/DOS_PATCHED_FLAG" ]] && echo "NOTE: THIS WORKSPACE IS ALREADY PATCHED, PLEASE RESET BEFORE PATCHING AGAIN!"; +[[ -f "$DOS_BUILD_BASE/.repo/local_manifests/roomservice.xml" ]] && echo "roomservice manifest found! Please fix your manifests before continuing!" || true; +[[ -f "$DOS_BUILD_BASE/DOS_PATCHED_FLAG" ]] && echo "NOTE: THIS WORKSPACE IS ALREADY PATCHED, PLEASE RESET BEFORE PATCHING AGAIN!" || true; From fcec1c8887183d91b31e9a3b8e61c504c98b68f8 Mon Sep 17 00:00:00 2001 From: steadfasterX Date: Tue, 26 Sep 2023 14:54:04 +0200 Subject: [PATCH 2/3] common: do not abort when recovery-in-boot when using strict (i.e set -e added by this PR) a build will fail on release when there is no recovery.img. this makes that non-fatal allowing to proceed Signed-off-by: steadfasterX --- Scripts/Common/Functions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/Common/Functions.sh b/Scripts/Common/Functions.sh index ed85e641..c1806b83 100644 --- a/Scripts/Common/Functions.sh +++ b/Scripts/Common/Functions.sh @@ -393,7 +393,7 @@ processRelease() { echo "$INCREMENTAL_ID" > "$OUT_DIR/$PREFIX-target_files.zip.id"; #Image - unzip -l $OUT_DIR/$PREFIX-target_files.zip | grep -q recovery.img; + unzip -l $OUT_DIR/$PREFIX-target_files.zip | grep -q recovery.img || true; local hasRecoveryImg="$?"; unzip -l $OUT_DIR/$PREFIX-target_files.zip | grep -q dtbo.img; local hasDtboImg="$?"; From 30859d2c086517e0b73786abc96204ece1e4254f Mon Sep 17 00:00:00 2001 From: steadfasterX Date: Thu, 11 Apr 2024 16:53:25 +0000 Subject: [PATCH 3/3] fix-up & enhance advanced error handling new (internal used) functions: - _exit - _exit_report - _exit_sigint these are used to fix several (wrong) error handlings. new environment variable: - UNATTENDED_PATCHING by default we assume unattended patching, i.e. if an error occurs during the patch, reset or any other process we will report the error and auto close the shell. this is needed as we source functions and code and so cannot simply terminate a master process. instead the whole shell will be terminated so if an error occurs nothing else will be executed (and you should notice easily that something is wrong). without that a (serious) error can still continue the rest of a function and you likely not even noticing the error itself. you can use: export UNATTENDED_PATCHING=0 before or after sourcing init.sh and it will *NOT* auto-close the shell. that way you can check the output and fix any issues. Signed-off-by: steadfasterX --- Scripts/Common/Functions.sh | 23 ++++++++++++++-- Scripts/init.sh | 52 ++++++++++++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/Scripts/Common/Functions.sh b/Scripts/Common/Functions.sh index c1806b83..0f7c0588 100644 --- a/Scripts/Common/Functions.sh +++ b/Scripts/Common/Functions.sh @@ -21,11 +21,22 @@ _fetchError(){ local error_line_number="$2"; local last_func="$3"; local file=$(echo "$4" | sed "s#$DOS_WORKSPACE_ROOT#\$DOS_WORKSPACE_ROOT#g"); + + # ignore when pressing TAB or sim. + if [[ "$file" =~ .*bash_completion ]];then return; fi + case $last_func in + command_not_found_handle|_filedir) return;; + esac + if [ ! -z "$last_func" ] && [ ! -z "$file" ];then echo -e "\e[0;31mERROR: $file -> ${last_func}() ended with status >${last_status}< at line >$((error_line_number -1))<\e[0m"; + elif [ ! -z "$last_func" ];then + echo -e "\e[0;31mERROR: ${last_func}() ended with status >${last_status}< at line >$((error_line_number -1))<\e[0m"; else echo -e "\e[0;31mERROR: last command ended with status >${last_status}< at line >$((error_line_number -1))<\e[0m"; fi + export TR_ERR=$last_status + _exit_report } export -f _fetchError; @@ -74,7 +85,7 @@ enterAndClear() { export -f enterAndClear; gitReset() { - git add -A && git reset --hard; + (git add -A && git reset --hard) || true; } export -f gitReset; @@ -88,16 +99,22 @@ applyPatchReal() { git format-patch -1 HEAD --zero-commit --no-signature --output="$currentWorkingPatch"; fi; fi; + else + echo "Applying (git am): $currentWorkingPatch - FAILED" + git am --abort || true + echo "Applying (patch fallback): $currentWorkingPatch" + patch -r - --no-backup-if-mismatch --forward --ignore-whitespace --verbose -p1 < $currentWorkingPatch fi; else - git apply "$@"; echo "Applying (as diff): $currentWorkingPatch"; + git apply "$@"; fi; } export -f applyPatchReal; applyPatch() { currentWorkingPatch=$1; + set -E if [ -f "$currentWorkingPatch" ]; then if git apply --check "$@" &> /dev/null; then applyPatchReal "$@"; @@ -110,11 +127,13 @@ applyPatch() { echo "Applied (as 3way): $currentWorkingPatch"; else echo -e "\e[0;31mERROR: Cannot apply: $currentWorkingPatch\e[0m"; + false fi; fi; fi; else echo -e "\e[0;31mERROR: Patch doesn't exist: $currentWorkingPatch\e[0m"; + false fi; } export -f applyPatch; diff --git a/Scripts/init.sh b/Scripts/init.sh index e089293c..a0167bf3 100644 --- a/Scripts/init.sh +++ b/Scripts/init.sh @@ -119,14 +119,15 @@ umask 0022; export TR_ERR=0 export TR_PID=$$ +unset nokill +if [ -z "$UNATTENDED_PATCHING" ];then export UNATTENDED_PATCHING=1;fi set -E; #required for resetEnv() resetEnv(){ trap - ERR EXIT USR2 SIGINT SIGHUP TERM echo -e "\n\e[0;32mThe environment has been reset.\e[0m\nRemember to always '\e[0;31msource ../../Scripts/init.sh\e[0m' before building.\n" set +E +f -} -export -f resetEnv +}; export -f resetEnv # print result # will also ensure the corresponding status code gets returned properly @@ -137,8 +138,47 @@ _errorReport(){ echo -e "\n\e[0;32m[FINAL RESULT] No error detected (please check the above output nevertheless!)\e[0m" fi return $TR_ERR -} -export -f _errorReport +}; export -f _errorReport + +# exit +_exit(){ + if [ "$1" == "noreset" ] || [ $TR_ERR -eq 0 ] ;then + echo -e "Ended with $TR_ERR.\nThe shell env has NOT been reset, type: resetEnv if needed.\n" + else + if [ -z "$nokill" ];then nokill=0;fi + resetEnv + echo -e "\nExecution has been STOPPED (TR_ERR=$TR_ERR)." + if [ "$UNATTENDED_PATCHING" -eq 1 ];then + echo -e "\n\e[0;31mPressing any key or waiting 10s will close this shell (set UNATTENDED_PATCHING=0 to disable auto-close)!\e[0m" + read -t 10 -p "- press any key to exit the shell NOW (auto closes after 10s) -" DUMMY || true + else + read -p "- press any key to exit the shell NOW -" DUMMY || true + fi + _SPIDS=$(ps -s $TR_PID -o pid= | tr '\n' ' ') + if [ -z "$_SPIDS" ];then + echo -e "... ok, no childs running (I am: $TR_PID)" + else + echo -e "... killing childs: $_SPIDS" + kill -9 $_SPIDS + fi + if [ $nokill -eq 0 ];then + echo "... killing shell: $TR_PID" + kill -9 $TR_PID + fi + fi +}; export -f _exit + +# exit & reset & report +_exit_report(){ + _errorReport + _exit +}; export -f _exit_report + +# exit without reset/kill +_exit_sigint(){ + echo -e "\n\nCTRL+C pressed or process has been terminated.." + _exit noreset +}; export _exit_sigint # trap and print errors # ERR: needed to fetch aborts when set -e is set @@ -146,8 +186,8 @@ trap 'E=$?; \ [ $E -ne 0 ] && _fetchError $E $LINENO $FUNCNAME $BASH_SOURCE \ && export TR_ERR=$((TR_ERR + $E))' EXIT ERR -trap _errorReport USR2 -trap resetEnv SIGINT SIGHUP TERM +trap _exit_report SIGUSR2 USR2 +trap _exit_sigint SIGINT SIGHUP TERM gpgVerifyGitHead() { if [ -r "$DOS_TMP_GNUPG/pubring.kbx" ]; then