diff --git a/objects.tar.gz b/objects.tar.gz index 2aa4b6425..e1f167c97 100644 Binary files a/objects.tar.gz and b/objects.tar.gz differ diff --git a/sherpa-manager.tar.gz b/sherpa-manager.tar.gz index db8869e49..2905106f7 100644 Binary files a/sherpa-manager.tar.gz and b/sherpa-manager.tar.gz differ diff --git a/support/sherpa-manager.source b/support/sherpa-manager.source index 34c9537b0..240156c89 100755 --- a/support/sherpa-manager.source +++ b/support/sherpa-manager.source @@ -116,10 +116,10 @@ ShowResults() ;; *) if QPKGs.AClist.IS${a}.IsSet; then - QPKGs.IS${a}:Show + ShowQPKGsIS${a} break elif QPKGs.AClist.ISNT${a}.IsSet; then - QPKGs.ISNT${a}:Show + ShowQPKGsISNT${a} break fi esac @@ -128,41 +128,41 @@ ShowResults() fi if [[ $useropt_paste_log_last = true ]]; then - Log.Last:Paste + PasteLogLast elif [[ $useropt_paste_log_tail = true ]]; then - Log.Tail:Paste + PasteLogTail fi if [[ $useropt_help_basic = true ]]; then - Help.Basic:Show - Help.Basic.Examples:Show + ShowHelpBasic + ShowHelpBasicExamples fi if [[ $generate_help_report = true ]]; then ReleaseLockfile if [[ $useropt_help_tips = true ]]; then - Help.Tips:Show + ShowHelpTips elif [[ $useropt_help_abbreviations = true ]]; then - Help.Abbreviations:Show + HelpAbbreviations elif [[ $useropt_help_actions = true ]]; then - Help.Actions:Show + ShowHelpActions elif [[ $useropt_help_actions_all = true ]]; then - Help.ActionsAll:Show + ShowHelpActionsAll elif [[ $useropt_help_lists = true ]]; then - Help.Lists:Show + ShowHelpLists elif [[ $useropt_help_options = true ]]; then - Help.Options:Show + ShowHelpOptions elif [[ $useropt_help_packages = true ]]; then - Help.Packages:Show + ShowHelpPackages elif [[ $useropt_help_show = true ]]; then - Help.Show:Show + ShowHelpShow elif [[ $useropt_help_problems = true ]]; then - Help.Problems:Show + ShowHelpProblems elif [[ $useropt_help_upgrades = true ]]; then - Help.Upgrades:Show + ShowHelpUpgrades elif [[ $useropt_help_groups = true ]]; then - Help.Groups:Show + ShowHelpGroups fi fi @@ -170,8 +170,8 @@ ShowResults() ShowReportAllActionResults fi - [[ $show_backuploc = true ]] && Help.BackupLocation:Show - [[ $show_suggest_raise_issue = true ]] && Help.Issue:Show + [[ $show_backuploc = true ]] && ShowHelpBackupLocation + [[ $show_suggest_raise_issue = true ]] && ShowHelpIssue DebugInfoMinSepr DebugScript finished "$(ConvertNowToFullDate)" @@ -314,6 +314,7 @@ LoadVars() pips_install=false proc_counts_path='' qpkg_timeouts_increased=false + report_footer_default=true run_package_actions=false show_backuploc=false show_action_results_failed=false @@ -322,13 +323,15 @@ LoadVars() show_suggest_raise_issue=false show_title=true show_action_results_zero=false - switch_colour=false switch_branch=false + switch_colour=false + switch_report_footer=false switch_terse=false terse_default=true title_shown=false user_branch_value='' user_colourful_value='' + user_report_footer_value='' user_terse_value='' # User-selectable options. @@ -358,6 +361,7 @@ LoadVars() useropt_help_upgrades=false useropt_paste_log_last=false useropt_paste_log_tail=false + useropt_report_footer=$(LoadSetting ReportFooter "$report_footer_default") useropt_show_backups=false useropt_show_dependencies=false useropt_show_features=false @@ -493,12 +497,12 @@ LocateSQLiteBinary() # HybridBackup = `Hybrid Backup Sync` if [[ -z $sqlite_cmd ]] && QpkgIsInstalled HybridBackup; then - sqlite_pathfile=$(QpkgGetInstallationPath HybridBackup)/CloudConnector3/bin/sqlite3 + sqlite_pathfile=$(QpkgGetInstalledPath HybridBackup)/CloudConnector3/bin/sqlite3 [[ -e $sqlite_pathfile ]] && sqlite_cmd=$sqlite_pathfile fi if [[ -z $sqlite_cmd ]] && QpkgIsInstalled ArchiwareP5; then # untested - sqlite_pathfile=$(QpkgGetInstallationPath ArchiwareP5)/binaries/Linux/unknown/64/sqlite3 + sqlite_pathfile=$(QpkgGetInstalledPath ArchiwareP5)/binaries/Linux/unknown/64/sqlite3 [[ -e $sqlite_pathfile ]] && sqlite_cmd=$sqlite_pathfile fi @@ -508,7 +512,7 @@ LocateSQLiteBinary() if [[ -z $sqlite_cmd ]]; then for a in container-station HD_Station; do # 'HD_Station' is untested if QpkgIsInstalled "$a"; then - sqlite_pathfile=$(QpkgGetInstallationPath "$a")/usr/bin/sqlite3 + sqlite_pathfile=$(QpkgGetInstalledPath "$a")/usr/bin/sqlite3 [[ -e $sqlite_pathfile ]] || continue sqlite_cmd=$sqlite_pathfile break @@ -522,7 +526,7 @@ LocateSQLiteBinary() if [[ -z $sqlite_cmd ]]; then for a in CacheMount qmiixagent QPython312 QPython311 QPython39; do if QpkgIsInstalled "$a"; then - sqlite_pathfile=$(QpkgGetInstallationPath "$a")/bin/sqlite3 + sqlite_pathfile=$(QpkgGetInstalledPath "$a")/bin/sqlite3 [[ -e $sqlite_pathfile ]] || continue sqlite_cmd=$sqlite_pathfile break @@ -537,9 +541,9 @@ LocateSQLiteBinary() if [[ -z $sqlite_cmd ]]; then for a in img2pdf Qsirch OCR_Converter; do if QpkgIsInstalled "$a"; then - sqlite_pathfile=$(QpkgGetInstallationPath "$a")/bin/sqlite3 + sqlite_pathfile=$(QpkgGetInstalledPath "$a")/bin/sqlite3 [[ -e $sqlite_pathfile ]] || continue - sqlite_cmd="LD_LIBRARY_PATH=$(QpkgGetInstallationPath "$a")/lib $sqlite_pathfile" + sqlite_cmd="LD_LIBRARY_PATH=$(QpkgGetInstalledPath "$a")/lib $sqlite_pathfile" break fi done @@ -583,7 +587,7 @@ LoadEnv() readonly OBJECTS_ARCHIVE_URL=''/$useropt_branch/objects.tar.gz readonly PACKAGES_ARCHIVE_URL=''/$useropt_branch/packages.tar.gz readonly QPKG_BU_PATH=$(UserGetDefVol)/.qpkg_config_backup - readonly THIS_PACKAGE_PATH=$(QpkgGetInstallationPath) + readonly THIS_PACKAGE_PATH=$(QpkgGetInstalledPath) if [[ -z $THIS_PACKAGE_PATH || $THIS_PACKAGE_PATH = undefined || ! -d $THIS_PACKAGE_PATH ]]; then ShowAsError "$(ShowAsTitleName) installation path not found. Please reinstall the $(ShowAsTitleName) QPKG" @@ -767,9 +771,9 @@ DebugLogEnv() DebugFirmware ok 'kernel version' "$(OsGetKernelVersion)" if OsIsStdKernelPageSize; then - DebugFirmware ok 'kernel page size' "$KERNEL_PAGE_SIZE" + DebugFirmware ok 'kernel page size' "${KERNEL_PAGE_SIZE}B" else - DebugFirmware warning 'kernel page size' "$KERNEL_PAGE_SIZE" + DebugFirmware warning 'kernel page size' "${KERNEL_PAGE_SIZE}B" fi DebugFirmware ok platform "$NAS_PLATFORM" @@ -799,7 +803,7 @@ DebugLogEnv() if OsIsSupportSudo; then DebugUserspace ok '$SUDO_UID' "$(UserGetSudoUID)" else - DebugUserspace ok '$SUDO_UID' 'N/A' + DebugUserspace ok '$SUDO_UID' N/A fi DebugUserspace ok '$EUID' "$EUID" @@ -831,7 +835,7 @@ DebugLogEnv() DebugQpkg warning 'allow unofficial' no fi else - DebugQpkg detect 'allow unofficial' 'N/A' + DebugQpkg detect 'allow unofficial' N/A fi if OsIsSupportSignedPackages; then @@ -841,12 +845,12 @@ DebugLogEnv() DebugQpkg detect 'allow unsigned' no fi else - DebugQpkg detect 'allow unsigned' 'N/A' + DebugQpkg detect 'allow unsigned' N/A fi DebugQpkg detect architecture "$NAS_QPKG_ARCH" DebugQpkg detect "$(ShowAsPackageName Entware) type" "$ENTWARE_VER" - DebugQpkg detect "$(ShowAsPackageName Entware) install date" "$(QpkgGetInstallDate Entware)" + DebugQpkg detect "$(ShowAsPackageName Entware) install date" "$(QpkgGetInstalledDate Entware)" if QpkgIsInstalled SortMyQPKGs; then DebugQpkg detect "$(ShowAsPackageName SortMyQPKGs)" installed @@ -865,7 +869,7 @@ DebugLogEnv() DebugQpkg warning "$(ShowAsPackageName IncreaseTimeouts)" 'not installed' fi else - DebugQpkg detect "$(ShowAsPackageName IncreaseTimeouts)" 'N/A' + DebugQpkg detect "$(ShowAsPackageName IncreaseTimeouts)" N/A fi DebugInfoMinSepr @@ -952,7 +956,7 @@ CheckTasks() fi if [[ $build_states = true ]]; then - QPKGs.States:Build + BuildQPKGsStates else get_qpkg_states=false run_package_actions=false @@ -1018,7 +1022,7 @@ CheckEnv() if [[ ${installed_version//.} -gt 238 ]]; then ipks_downgrade=true - ShowAsNote "various IPKs will be downgraded to suit $KERNEL_PAGE_SIZE kernel page size" + ShowAsNote "various IPKs will be downgraded to suit ${KERNEL_PAGE_SIZE}B kernel page size" IPKs-ACdowngrade-to:Add "$target_packages" else IPKs-ACdowngrade-sk:Add "$target_packages" @@ -1044,9 +1048,9 @@ CheckEnv() esac fi - QPKGs.IsCanBackup:Build - QPKGs.IsCanRestartToUpdate:Build - QPKGs.IsCanClean:Build + BuildQPKGsIsCanBackup + BuildQPKGsIsCanRestartToUpdate + BuildQPKGsIsCanClean AllocPackGroupsToAcs AllocPackStatesToAcs @@ -1079,7 +1083,7 @@ QPKGsAssignToActions() # KLUDGE: ensure Entware is reinstalled when IPKs are upgraded. if QpkgIsInstalled Entware; then - local entware_install_date=$(QpkgGetInstallDate Entware) + local entware_install_date=$(QpkgGetInstalledDate Entware) if [[ $entware_install_date = undefined || ${entware_install_date//[!0-9]/} -le 20240809 ]] && [[ $NAS_ARCH != armv5tel ]]; then ShowAsNote "the $(TextBrightOrange Entware) QPKG will be auto-reinstalled (Entware packages were updated early in August 2024)" @@ -1105,7 +1109,7 @@ QPKGsAssignToActions() for qpkg_name in $(QPKGs-ACinstall-to:Array) $(QPKGs-ACreinstall-to:Array); do QpkgSetIndex - for prospect in $(QpkgGetDependencies); do + for prospect in $(QpkgGetDatabaseDependencies); do QPKGs-ISNTinstalled.Exist "$prospect" && QPKGs-ACinstall-to:Add "$prospect" done done @@ -1116,7 +1120,7 @@ QPKGsAssignToActions() if [[ $useropt_check = true ]] || QPKGs-ACactivate-to.Exist "$qpkg_name"; then QpkgSetIndex - for prospect in $(QpkgGetDependencies); do + for prospect in $(QpkgGetDatabaseDependencies); do QPKGs-ISNTinstalled.Exist "$prospect" && QPKGs-ACinstall-to:Add "$prospect" done fi @@ -1129,7 +1133,7 @@ QPKGsAssignToActions() if QPKGs-GRindependent.Exist "$qpkg_name" && QPKGs-ISinstalled.Exist "$qpkg_name"; then QpkgSetIndex - for prospect in $(QpkgGetDependents); do + for prospect in $(QpkgGetDatabaseDependents); do if QPKGs-ISenabled.Exist "$prospect"; then QPKGs-ACdeactivate-to:Add "$prospect" ! QPKGs-ACuninstall-to.Exist "$prospect" && ! QPKGs-ACinstall-to.Exist "$prospect" && QPKGs-ACactivate-to:Add "$prospect" @@ -1146,7 +1150,7 @@ QPKGsAssignToActions() if QPKGs-GRindependent.Exist "$qpkg_name" && QPKGs-ISinstalled.Exist "$qpkg_name"; then QpkgSetIndex - for prospect in $(QpkgGetDependents); do + for prospect in $(QpkgGetDatabaseDependents); do QPKGs-ISinstalled.Exist "$prospect" && QPKGs-ACdeactivate-to:Add "$prospect" done fi @@ -1167,7 +1171,7 @@ QPKGsAssignToActions() if QPKGs-GRindependent.Exist "$qpkg_name" && QPKGs-ISinstalled.Exist "$qpkg_name" && QPKGs-ACinstall-to.Exist "$qpkg_name"; then QpkgSetIndex - for prospect in $(QpkgGetDependents); do + for prospect in $(QpkgGetDatabaseDependents); do if QPKGs-ISenabled.Exist "$prospect"; then QPKGs-ACdeactivate-to:Add "$prospect" ! QPKGs-ACuninstall-to.Exist "$prospect" && ! QPKGs-ACinstall-to.Exist "$prospect" && QPKGs-ACactivate-to:Add "$prospect" @@ -1193,7 +1197,7 @@ QPKGsAssignToActions() for qpkg_name in $(QPKGs-AC${action}-to:Array); do QpkgSetIndex - for prospect in $(QpkgGetDependencies); do + for prospect in $(QpkgGetDatabaseDependencies); do QPKGs-ISinstalled.Exist "$prospect" && QPKGs-ACactivate-to:Add "$prospect" done done @@ -1222,7 +1226,7 @@ QPKGsAssignToActions() if QPKGs-ISinstalled.Exist "$qpkg_name" && QPKGs-ACinstall-to.Exist "$qpkg_name"; then QPKGs_were_installed_name+=("$qpkg_name") QpkgSetIndex - QPKGs_were_installed_path+=("$($DIRNAME_CMD "$(QpkgGetInstallationPath)")") + QPKGs_were_installed_path+=("$($DIRNAME_CMD "$(QpkgGetInstalledPath)")") fi QPKGs-ACdeactivate-to:Add "$qpkg_name" @@ -1262,7 +1266,7 @@ QPKGsAssignToActions() } -# QPKG action processing shall be conducted in this order: +# QPKG action processing shall-be conducted in this order: # # 1. status all # 2. rebuild all (meta-action: `download`, `install` & `restore` QPKG, but only if package has an existing backup file) @@ -1415,9 +1419,9 @@ ProcActions() fi if [[ $useropt_debug = true ]]; then - QPKGs.Actions:List - IPKs.Actions:List - PIPs.Actions:List + ListQPKGsActions + ListIPKsActions + ListPIPsActions fi if [[ $title_shown = true ]]; then @@ -1539,11 +1543,12 @@ ProcAction() pidfile=$($MKTEMP_CMD "$ASYNC_PROCS_PATH"/bgproc_XXXXXX) # Set $pidfile here, before launching async process so it's inherited by that process. - _LaunchOneActionWithManyForks_ "_${PACKAGE_TYPE}:${TARGET_ACTION}_" "${target_packages[@]}" & + _ExecOneActionWithManyForks_ "_${PACKAGE_TYPE}:${TARGET_ACTION}_" "${target_packages[@]}" & echo "$!" > "$pidfile" # Read message pipe and process QPKGs and actions as-per requests contained within. + while [[ ${#target_packages[@]} -gt 0 && ! -e $ACTION_ABORT_PATHFILE ]]; do ReadFromActionMsgPipe msg1_key msg1_value msg2_key msg2_value @@ -1598,7 +1603,7 @@ ProcAction() status) # Update the status of a single action fork in the parent shell. case $msg1_value in ok) # Completed OK (wonderful!). - [[ $TARGET_ACTION != status ]] && ((ok_count++)) # Don't need to count the result of `status` checks. + [[ $TARGET_ACTION != status ]] && ((ok_count++)) # No-need to count result of `status` checks. ;; so) # Action was skipped, but this is normal (no-big-deal). ((skip_ok_count++)) @@ -1820,9 +1825,11 @@ ParseManagementArgs() # $run_package_actions # $switch_branch # $switch_colour + # $switch_report_footer # $switch_terse # $user_branch_value # $user_colourful_value + # $user_report_footer_value # $user_terse_value # $useropt_check # $useropt_paste_log_last @@ -1860,7 +1867,7 @@ ParseManagementArgs() user_action=$arg useropt_check=true ;; - colo?(u)r?(ful)|follow|paste|terse) + colo?(u)r?(ful)|follow|paste|report-footer|terse) requires_group=true user_action=$arg ;; @@ -1941,6 +1948,19 @@ ParseManagementArgs() args_remaining+=("$action") esac ;; + report-footer) + case $group in + true|false) + action='' + awaiting_group=false + switch_report_footer=true + user_report_footer_value=$group + UpdateReportFooter + ;; + *) + args_remaining+=("$action") + esac + ;; terse) case $group in true|false) @@ -2658,7 +2678,7 @@ MatchVerb() add|install) printf install ;; - backup|clean|colo?(u)r?(ful)|@(dis|en)able|follow|help|list|paste|reassign|rebuild|reinstall|reset|restore|sign|terse) + backup|clean|colo?(u)r?(ful)|@(dis|en)able|follow|help|list|paste|reassign|rebuild|reinstall|report-footer|reset|restore|sign|terse) printf '%s' "$a" ;; c|check) @@ -3169,7 +3189,7 @@ PatchEntwareService() local -r TAB=$'\t' local -r PREFIX='# the following line was inserted by sherpa: https://git.io/sherpa' - local -r PACKAGE_INIT_PATHFILE=$(QpkgGetServicePathFile Entware) + local -r PACKAGE_INIT_PATHFILE=$(QpkgGetInstalledServicePathFile Entware) local find='' local insert='' @@ -3521,7 +3541,7 @@ IPKs:install() for qpkg_name in "${QPKG_NAME[@]}"; do [[ $previous = "$qpkg_name" ]] && continue || previous=$qpkg_name QpkgSetIndex - IPKs-ACinstall-to:Add "$(QpkgGetIPKs)" + IPKs-ACinstall-to:Add "$(QpkgGetDatabaseIPKs)" done else for qpkg_name in "${QPKG_NAME[@]}"; do @@ -3529,7 +3549,7 @@ IPKs:install() if QPKGs-ACinstall-to.Exist "$qpkg_name" || QPKGs-ISinstalled.Exist "$qpkg_name" || (QPKGs-ACreinstall-to.Exist "$qpkg_name" && QPKGs-ISinstalled.Exist "$qpkg_name"); then QpkgSetIndex - IPKs-ACinstall-to:Add "$(QpkgGetIPKs)" + IPKs-ACinstall-to:Add "$(QpkgGetDatabaseIPKs)" fi done fi @@ -3789,7 +3809,7 @@ CloseIpkArchive() } -_LaunchOneActionWithManyForks_() +_ExecOneActionWithManyForks_() { # Execute actions concurrently, but only as many as $max_forks will allow given the circumstances. @@ -4081,6 +4101,50 @@ UpdateBranch() } +UpdateReportFooter() + { + + # Inputs: (local) + # $1 = 'silent' (optional): don't announce setting was saved. + + # Inputs: (global) + # $switch_terse + # $user_report_footer_value + # $useropt_report_footer + + # Outputs: (global) + # $run_package_actions + # $switch_report_footer + # $useropt_report_footer + + local a='' + + if [[ $switch_report_footer = true && -n $user_report_footer_value ]]; then + # Validate before saving. + + for a in true false; do + [[ $a != "$user_report_footer_value" ]] && continue + useropt_report_footer=$user_report_footer_value + + if [[ ${1:-} = silent ]]; then + SaveSetting ReportFooter "$useropt_report_footer" + else + SaveSetting ReportFooter "$useropt_report_footer" announce + fi + + switch_report_footer=false + + return + done + + ShowAsAbort "user setting '$user_report_footer_value' is not 'true' or 'false'" + run_package_actions=false + + return 1 + fi + + } + UpdateTerse() { @@ -4342,7 +4406,7 @@ DisplayAsProjSynIndentExam() # Display as project syntax indented example. - # Inputs: + # Inputs: (local) # $1 = description (optional) # $2 = example syntax @@ -4361,7 +4425,7 @@ DisplayAsSynExam() # Display as syntax example. - # Inputs: + # Inputs: (local) # $1 = description # $2 = example syntax @@ -4374,7 +4438,7 @@ DisplayAsIndentItem() # Display as indented single field, bulleted. - # Inputs: + # Inputs: (local) # $1 = item printf "%${HELP_DESC_INDENT}s${CHARS_BULLET}%s\n" '' "$(Capitalise "${1:-}")" @@ -4385,14 +4449,15 @@ DisplayAsIndentQuotedInfoItem() { # Display as indented two fields, first field quoted, second field hyphenated. + # Example: - # " 'inactive' • application is dead or not-started. Try starting/activating it." + # " 'inactive' - application is dead or not-started. Try starting/activating it." - # Inputs: + # Inputs: (local) # $1 = word # $2 = description - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf "%${HELP_DESC_INDENT}s%s|%s\n" '' "'${1:-}'" "- $(AddPeriod "${2:-}")" else printf "%${HELP_DESC_INDENT}s%-$((FOOTER_NAME_COL_WIDTH+2+$(LenANSIDiff "${1:-}")))s%s\n" '' "'${1:-}'" "- $(AddPeriod "${2:-}")" @@ -4405,7 +4470,7 @@ GeneratePacksReportTitleLine() local a='' - # column 1: package name + # column 1: package name. a='QPKG name:' printf "%-$((PACKAGE_NAME_COL_WIDTH+2+$(LenANSIDiff "$a")))s" "$a" @@ -4424,37 +4489,37 @@ GeneratePacksReportTitleLine() GeneratePacksReportDataLine() { - # Inputs: (global) - # $qpkg_name - # Input (local): # $1 = QPKG name (optional). + # Inputs: (global) + # $qpkg_name + local app_ver='' local app_ver_msg=$CHARS_BLANK -# local author=$(QpkgGetAuthor) +# local author=$(QpkgGetDatabaseAuthor) # local author_msg=$CHARS_BLANK local description_msg=$CHARS_BLANK local mode='' local name=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} - local description=$(QpkgGetDesc "$name") - local notes=$(QpkgGetNote "$name") + local description=$(QpkgGetDatabaseDesc "$name") + local notes=$(QpkgGetDatabaseNote "$name") [[ $notes = none ]] && notes='' local name_msg=$CHARS_NORMAL local notes_msg="${notes}." - if QpkgIsMissing; then - mode=highlighted + if QpkgIsInstalledMissing; then + mode=highlight /bin/touch "$REPORT_FLAGS_PATH"/status-missing elif QpkgIsNtInstalled; then - mode=muted + mode=mute /bin/touch "$REPORT_FLAGS_PATH"/state-notinstalled else mode=normal /bin/touch "$REPORT_FLAGS_PATH"/state-installed fi - app_ver=$(QpkgGetApplVer) + app_ver=$(QpkgGetDatabaseApplVer) case $app_ver in dynamic|final|static) @@ -4467,25 +4532,25 @@ GeneratePacksReportDataLine() name_msg+=$qpkg_name case $mode in - muted) + mute) app_ver_msg=$(TextDarkGrey "$app_ver_msg") # author_msg=$(TextDarkGrey "$author_msg") description_msg=$(TextDarkGrey "$description_msg") name_msg=$(TextDarkGrey "$name_msg") ;; - highlighted) + highlight) # [[ $author = missing ]] && author_msg=$(TextBrightRedBlink "${CHARS_ALERT}${author}") name_msg=$(TextBrightRed "$name_msg") esac - if [[ -e $GNU_AWK_CMD ]]; then - printf '%s|%s|%s\n' "$name_msg" "$app_ver_msg" "$description_msg" + if OsIsSupportAutowidthTableColumns; then + echo "$name_msg|$app_ver_msg|$description_msg" if [[ -n $notes ]]; then printf "%s|%s|%$((${#CHARS_BLANK}))s%s\n" '' '' '' "$(TextBrightOrange "${CHARS_DROPEND}${CHARS_NOTE}") $notes_msg" fi else - # column 1: package name + # column 1: package name. printf "%-$((PACKAGE_NAME_COL_WIDTH+$(LenANSIDiff "$name_msg")))s" "$name_msg" # column 2: application version @@ -4510,7 +4575,7 @@ GenerateStatusReportTitleLine() local a='' - # column 1: package name + # column 1: package name. a='QPKG name' printf "%-${PACKAGE_NAME_COL_WIDTH}s" "$a:" @@ -4549,167 +4614,207 @@ GenerateStatusReportDataLine() # * This function runs asynchronously * - # Inputs: + # Inputs: (global) + # $qpkg_name local action='' local action_msg=$CHARS_BLANK - local app_ver='' + local app_ver=$(QpkgGetDatabaseApplVer) local app_ver_msg=$CHARS_BLANK local mode='' local -i n=0 local name_msg=$CHARS_BLANK + local path=$(QpkgGetInstalledPath) local path_msg=$CHARS_BLANK local result='' local status='' local status_msg=$CHARS_NORMAL + local ver=$(QpkgGetInstalledVer) local ver_msg=$CHARS_BLANK - if QpkgIsMissing; then - mode=highlighted - /bin/touch "$REPORT_FLAGS_PATH"/status-missing - elif QpkgIsNtInstalled; then - mode=muted - /bin/touch "$REPORT_FLAGS_PATH"/state-notinstalled - else + if QpkgIsInstalledMissing; then + mode=missing + elif QpkgIsInstalled; then mode=normal - /bin/touch "$REPORT_FLAGS_PATH"/state-installed + else + mode=mute + QpkgIsReallyInstalled && QpkgIsNtInstalledAuthorOk && mode=author fi - app_ver=$(QpkgGetApplVer) - case $app_ver in dynamic|final|static) /bin/touch "$REPORT_FLAGS_PATH"/app-$app_ver esac case $mode in - normal) - app_ver_msg+=$app_ver - name_msg+=$qpkg_name - path_msg+=$(QpkgGetInstallationPath) - - if QPKGs-ISenabled.Exist "$qpkg_name"; then - status+=" $(TextBrightGreen enabled)" - /bin/touch "$REPORT_FLAGS_PATH"/state-enabled - else - status+=" $(TextBrightRed disabled)" - /bin/touch "$REPORT_FLAGS_PATH"/state-disabled - fi - - if QPKGs-ISactive.Exist "$qpkg_name"; then - status+=" $(TextBrightGreen active)" - /bin/touch "$REPORT_FLAGS_PATH"/status-active - elif QPKGs-ISslow.Exist "$qpkg_name"; then - status+=" $(TextBrightOrange slow)" - /bin/touch "$REPORT_FLAGS_PATH"/status-slow - elif QPKGs-ISNTactive.Exist "$qpkg_name"; then - status+=" $(TextBrightRed inactive)" - /bin/touch "$REPORT_FLAGS_PATH"/status-inactive - else - status+=" $(TextBrightOrange unknown)" - /bin/touch "$REPORT_FLAGS_PATH"/status-unknown - fi - - if QpkgIsSherpaCompatible; then - action=$(QpkgGetServiceAction) + missing|normal) + if QpkgIsDatabaseSherpaCompatible; then + action=$(QpkgGetInstalledServiceAction) /bin/touch "$REPORT_FLAGS_PATH"/action-$action if [[ $action = not-found ]]; then - if OsIsStarting && [[ -e $REPORT_FLAGS_PATH/state-enabled && -e $REPORT_FLAGS_PATH/status-inactive ]]; then + if OsIsStarting && QpkgIsInstalledEnabled; then action_msg+=$(TextBrightOrange pending) /bin/touch "$REPORT_FLAGS_PATH"/action-pending else action_msg+=$(TextDarkGrey not-found) fi else - action_msg+="$action" + action_msg+=$action fi - result=$(QpkgGetServiceResult) + result=$(QpkgGetInstalledServiceResult) /bin/touch "$REPORT_FLAGS_PATH"/result-$result case $result in - ok) - action_msg+=" ($(TextBrightGreen OK))" + aborted|failed) + action_msg+=" ($(TextBrightRed "$result"))" ;; in-progress) - action_msg+=" ($(TextBrightOrange $result))" + action_msg+=" ($(TextBrightOrange "$result"))" ;; - aborted|failed) - action_msg+=" ($(TextBrightRed $result))" + ok) + action_msg+=" ($(TextBrightGreen "$(Uppercase "$result")"))" esac else - action_msg+=$(TextDarkGrey unsupported) + action=unsupported /bin/touch "$REPORT_FLAGS_PATH"/action-unsupported + + action_msg+=$(TextDarkGrey "$action") fi + ;; + *) + action=N/A + /bin/touch "$REPORT_FLAGS_PATH"/na + esac - status_msg+=$(AddSeparators "$status") - ver_msg+=$(QpkgGetInstalledVer) + case $mode in + author) + /bin/touch "$REPORT_FLAGS_PATH"/status-wrongauthor + /bin/touch "$REPORT_FLAGS_PATH"/na + + # Set field values. + app_ver=N/A + status='incompatible author' + ver=N/A + + # Assign field messages. + action_msg+=$action + app_ver_msg+=$app_ver + name_msg+=$qpkg_name + path_msg+=$path + status_msg=${CHARS_ATTENTION}${status} + ver_msg+=$ver + + # Highlight field messages. + action_msg=$(TextBrightOrange "$action_msg") + app_ver_msg=$(TextBrightOrange "$app_ver_msg") + name_msg=$(TextBrightOrange "$name_msg") + path_msg=$(TextBrightOrange "$path_msg") + status_msg=$(TextBrightOrange "$status_msg") + ver_msg=$(TextBrightOrange "$ver_msg") ;; - muted) - if QpkgIsSherpaCompatible; then - action=$(QpkgGetServiceAction) - - if [[ $action != not-found ]]; then - /bin/touch "$REPORT_FLAGS_PATH"/action-$action - action_msg+="$action" - result=$(QpkgGetServiceResult) - /bin/touch "$REPORT_FLAGS_PATH"/result-$result - - case $result in - ok) - action_msg+=" ($(TextBrightGreen OK))" - ;; - in-progress) - action_msg+=" ($(TextBrightOrange $result))" - ;; - aborted|failed) - action_msg+=" ($(TextBrightRed $result))" - esac - else - action_msg+=$(TextDarkGrey 'N/A') - /bin/touch "$REPORT_FLAGS_PATH"/na - fi - else - action_msg+=$(TextDarkGrey 'N/A') - /bin/touch "$REPORT_FLAGS_PATH"/na - fi + missing) + /bin/touch "$REPORT_FLAGS_PATH"/status-missing - app_ver_msg+=$(TextDarkGrey "$app_ver") - name_msg+=$(TextDarkGrey "$qpkg_name") - path_msg+=$(TextDarkGrey 'N/A') + # Set field values. + status=missing + + # Assign field messages. + app_ver_msg+=$app_ver + name_msg+=$qpkg_name + path_msg+=$path + status_msg=${CHARS_ALERT}${status} + ver_msg+=$ver + + # Highlight field messages. + app_ver_msg=$(TextBrightRed "$app_ver_msg") + name_msg=$(TextBrightRed "$name_msg") + path_msg=$(TextBrightRedBlink "$path_msg") + status_msg=$(TextBrightRedBlink "$status_msg") + ver_msg=$(TextBrightRed "$ver_msg") + ;; + mute) + /bin/touch "$REPORT_FLAGS_PATH"/state-notinstalled /bin/touch "$REPORT_FLAGS_PATH"/na - if ! QpkgIsArchOK; then - status='incompatible arch' - elif ! QpkgIsMinOSVerOk; then - status="incompatible $(OsGetQnapOS)" - elif ! QpkgIsMinRAMOk; then - status='insufficient RAM' + # Set field values. + path=N/A + + if ! QpkgIsDatabaseArchOK; then + status+='incompatible NAS arch' + elif ! QpkgIsDatabaseMinOSVerOk || ! QpkgIsDatabaseMaxOSVerOk; then + status+="incompatible $(OsGetQnapOS)" + elif ! QpkgIsDatabaseMinRAMOk; then + status+='insufficient NAS RAM' else - status='not installed' + status+='not installed' fi - status_msg=$(TextDarkGrey "${CHARS_NORMAL}${status}") - ver_msg+=$(TextDarkGrey "$(QpkgGetAvailVer "$qpkg_name")") + ver=$(QpkgGetDatabaseVer "$qpkg_name") + + # Assign field messages. + action_msg+=$action + app_ver_msg+=$app_ver + name_msg+=$qpkg_name + path_msg+=$path + status_msg+=$status + ver_msg+=$ver + + # Highlight field messages. + action_msg=$(TextDarkGrey "$action_msg") + app_ver_msg=$(TextDarkGrey "$app_ver_msg") + name_msg=$(TextDarkGrey "$name_msg") + path_msg=$(TextDarkGrey "$path_msg") + status_msg=$(TextDarkGrey "$status_msg") + ver_msg=$(TextDarkGrey "$ver_msg") ;; - highlighted) - app_ver_msg+=$(TextBrightRed "$app_ver") - name_msg+=$(TextBrightRed "$qpkg_name") - path_msg=$(TextBrightRedBlink "${CHARS_ALERT}$(QpkgGetInstallationPath)") - status_msg=$(TextBrightRedBlink "${CHARS_ALERT}missing") - ver_msg+=$(TextBrightRed "$(QpkgGetInstalledVer)") + normal) + /bin/touch "$REPORT_FLAGS_PATH"/state-installed + + # Set field values. + + # Assign highlighting earlier than-usual as each status can have a different highlight. + + if QPKGs-ISenabled.Exist "$qpkg_name"; then + status+=" $(TextBrightGreen enabled)" + /bin/touch "$REPORT_FLAGS_PATH"/state-enabled + else + status+=" $(TextBrightRed disabled)" + /bin/touch "$REPORT_FLAGS_PATH"/state-disabled + fi + + if QPKGs-ISactive.Exist "$qpkg_name"; then + status+=" $(TextBrightGreen active)" + /bin/touch "$REPORT_FLAGS_PATH"/status-active + elif QPKGs-ISslow.Exist "$qpkg_name"; then + status+=" $(TextBrightOrange slow)" + /bin/touch "$REPORT_FLAGS_PATH"/status-slow + elif QPKGs-ISNTactive.Exist "$qpkg_name"; then + status+=" $(TextBrightRed inactive)" + /bin/touch "$REPORT_FLAGS_PATH"/status-inactive + else + status+=" $(TextBrightOrange unknown)" + /bin/touch "$REPORT_FLAGS_PATH"/status-unknown + fi + + # Assign field messages. + app_ver_msg+=$app_ver + name_msg+=$qpkg_name + path_msg+=$path + status_msg+=$(AddSeparators "$status") + ver_msg+=$ver esac if QPKGs-ISupgradable.Exist "$qpkg_name"; then - ver_msg+=" ($(TextBrightOrange "$(QpkgGetAvailVer)"))" + ver_msg+=" ($(TextBrightOrange "$(QpkgGetDatabaseVer)"))" /bin/touch "$REPORT_FLAGS_PATH"/status-upgradable fi - if [[ -e $GNU_AWK_CMD ]]; then - printf '%s|%s|%s|%s|%s|%s\n' "$name_msg" "$status_msg" "$action_msg" "$ver_msg" "$app_ver_msg" "$path_msg" + if OsIsSupportAutowidthTableColumns; then + echo "$name_msg|$status_msg|$action_msg|$ver_msg|$app_ver_msg|$path_msg" else - # column 1: package qpkg_name + # column 1: package name. printf "%-$((PACKAGE_NAME_COL_WIDTH+$(LenANSIDiff "$name_msg")))s" "$name_msg" # column 2: package statuses @@ -4742,7 +4847,7 @@ GenerateReposReportTitleLine() local a='' - # column 1: package name + # column 1: package name. a="QPKG name:" printf "%-$((PACKAGE_NAME_COL_WIDTH+2+$(LenANSIDiff "$a")))s" "$a" @@ -4769,32 +4874,50 @@ GenerateReposReportDataLine() local assigned_repo='' local assigned_repo_msg=$CHARS_NORMAL - local install_date=$(QpkgGetInstallDate) + local install_date=$(QpkgGetInstalledDate) local install_date_msg=$CHARS_BLANK local mode='' local name_msg=$CHARS_BLANK - local store_id=$(QpkgGetStoreID) + local store_id=$(QpkgGetInstalledStoreID) + [[ $store_id = undefined ]] && store_id=sherpa - if [[ $store_id = undefined || $store_id = sherpa ]]; then - store_id=sherpa - assigned_repo=sherpa - /bin/touch "$REPORT_FLAGS_PATH"/repo-sherpa + if QpkgIsInstalledMissing; then + mode=highlight + /bin/touch "$REPORT_FLAGS_PATH"/status-missing + elif QpkgIsInstalled; then + mode=normal + /bin/touch "$REPORT_FLAGS_PATH"/state-installed else - assigned_repo=$(GetRepoURLFromStoreID "$store_id") + mode=mute + /bin/touch "$REPORT_FLAGS_PATH"/state-notinstalled fi - if QpkgIsMissing; then - mode=highlighted - /bin/touch "$REPORT_FLAGS_PATH"/status-missing - elif QpkgIsNtInstalled; then - mode=muted - /bin/touch "$REPORT_FLAGS_PATH"/state-notinstalled + if [[ $store_id = sherpa ]]; then + assigned_repo=sherpa + /bin/touch "$REPORT_FLAGS_PATH"/repo-sherpa else - mode=normal - /bin/touch "$REPORT_FLAGS_PATH"/state-installed + assigned_repo=$(GetRepoURLFromStoreID "$store_id") fi case $mode in + highlight) + install_date=missing + + case $assigned_repo in + sherpa) + assigned_repo_msg+=$(TextBrightGreen "$assigned_repo") + ;; + unassigned) + assigned_repo_msg+=$(TextBrightOrange "$assigned_repo") + ;; + *) + assigned_repo_msg+=$assigned_repo + /bin/touch "$REPORT_FLAGS_PATH"/repo-other + esac + + install_date_msg=$(TextBrightRedBlink "${CHARS_ALERT}${install_date}") + name_msg=$(TextBrightRed "${name_msg}${qpkg_name}") + ;; normal) case $assigned_repo in sherpa) @@ -4802,56 +4925,41 @@ GenerateReposReportDataLine() name_msg+=$qpkg_name ;; undefined) - assigned_repo_msg+='N/A' + assigned_repo_msg+=N/A name_msg+=$qpkg_name /bin/touch "$REPORT_FLAGS_PATH"/na ;; *) - assigned_repo_msg=$(TextBrightOrange "${CHARS_ATTENTION}$assigned_repo") - name_msg+=$(TextBrightOrange "$qpkg_name") + assigned_repo_msg=$(TextBrightOrange "${CHARS_ATTENTION}${assigned_repo}") + name_msg=$(TextBrightOrange "${name_msg}${qpkg_name}") /bin/touch "$REPORT_FLAGS_PATH"/repo-other esac install_date_msg+=$install_date ;; - muted) - assigned_repo_msg=$(TextDarkGrey "${CHARS_NORMAL}N/A") + mute) + assigned_repo=N/A /bin/touch "$REPORT_FLAGS_PATH"/na - if ! QpkgIsArchOK; then + if ! QpkgIsDatabaseArchOK; then install_date='incompatible arch' - elif ! QpkgIsMinOSVerOk; then + elif ! QpkgIsDatabaseMinOSVerOk; then install_date="incompatible $(OsGetQnapOS)" - elif ! QpkgIsMinRAMOk; then + elif ! QpkgIsDatabaseMinRAMOk; then install_date='insufficient RAM' else install_date='not installed' fi - install_date_msg+=$(TextDarkGrey "$install_date") - name_msg+=$(TextDarkGrey "$qpkg_name") - ;; - highlighted) - case $assigned_repo in - sherpa) - assigned_repo_msg+=$(TextBrightGreen "$assigned_repo") - ;; - unassigned) - assigned_repo_msg+=$(TextBrightOrange "$assigned_repo") - ;; - *) - assigned_repo_msg+=$assigned_repo - /bin/touch "$REPORT_FLAGS_PATH"/repo-other - esac - - install_date_msg=$(TextBrightRedBlink "${CHARS_ALERT}missing") - name_msg+=$(TextBrightRed "$qpkg_name") + assigned_repo_msg=$(TextDarkGrey "${assigned_repo_msg}${assigned_repo}") + install_date_msg=$(TextDarkGrey "${install_date_msg}${install_date}") + name_msg=$(TextDarkGrey "${name_msg}${qpkg_name}") esac - if [[ -e $GNU_AWK_CMD ]]; then - printf '%s|%s|%s\n' "$name_msg" "$assigned_repo_msg" "$install_date_msg" + if OsIsSupportAutowidthTableColumns; then + echo "$name_msg|$assigned_repo_msg|$install_date_msg" else - # column 1: package qpkg_name + # column 1: package name. printf "%-$((PACKAGE_NAME_COL_WIDTH+$(LenANSIDiff "$name_msg")))s" "$name_msg" # column 2: package repository @@ -4872,7 +4980,7 @@ GenerateAbsReportTitleLine() local a='' - # column 1: package name + # column 1: package name. a='QPKG name:' printf "%-$((PACKAGE_NAME_COL_WIDTH+2+$(LenANSIDiff "$a")))s" "$a" @@ -4901,11 +5009,11 @@ GenerateAbsReportDataLine() local mode='' local name_msg=$CHARS_BLANK - if QpkgIsMissing; then - mode=highlighted + if QpkgIsInstalledMissing; then + mode=highlight /bin/touch "$REPORT_FLAGS_PATH"/status-missing elif QpkgIsNtInstalled; then - mode=muted + mode=mute /bin/touch "$REPORT_FLAGS_PATH"/state-notinstalled else mode=normal @@ -4914,35 +5022,35 @@ GenerateAbsReportDataLine() case $mode in normal) - abs_msg=${CHARS_NORMAL}$(AddSeparators "$(QpkgGetAbbrvs)") + abs_msg=${CHARS_NORMAL}$(AddSeparators "$(QpkgGetDatabaseAbbrvs)") installed_msg+=true name_msg+=$qpkg_name ;; - muted) - if ! QpkgIsArchOK "$qpkg_name"; then + mute) + if ! QpkgIsDatabaseArchOK "$qpkg_name"; then abs_msg="${CHARS_ALERT}incompatible architecture" - elif ! QpkgIsMinOSVerOk "$qpkg_name"; then + elif ! QpkgIsDatabaseMinOSVerOk "$qpkg_name"; then abs_msg="${CHARS_ALERT}incompatible $(OsGetQnapOS) version" - elif ! QpkgIsMinRAMOk "$qpkg_name"; then + elif ! QpkgIsDatabaseMinRAMOk "$qpkg_name"; then abs_msg="${CHARS_ALERT}insufficient RAM installed" else - abs_msg=${CHARS_NORMAL}$(AddSeparators "$(QpkgGetAbbrvs "$qpkg_name")") + abs_msg=${CHARS_NORMAL}$(AddSeparators "$(QpkgGetDatabaseAbbrvs "$qpkg_name")") fi abs_msg=$(TextDarkGrey "$abs_msg") installed_msg+=$(TextDarkGrey false) name_msg+=$(TextDarkGrey "$qpkg_name") ;; - highlighted) - abs_msg=$(TextBrightRed "${CHARS_ALERT}$(AddSeparators "$(QpkgGetAbbrvs)")") + highlight) + abs_msg=$(TextBrightRed "${CHARS_ALERT}$(AddSeparators "$(QpkgGetDatabaseAbbrvs)")") installed_msg=$(TextBrightRedBlink "${CHARS_ALERT}missing") name_msg+=$(TextBrightRed "$qpkg_name") esac - if [[ -e $GNU_AWK_CMD ]]; then - printf '%s|%s|%s\n' "$name_msg" "$installed_msg" "$abs_msg" + if OsIsSupportAutowidthTableColumns; then + echo "$name_msg|$installed_msg|$abs_msg" else - # column 1: package name + # column 1: package name. printf "%-$((PACKAGE_NAME_COL_WIDTH+$(LenANSIDiff "$name_msg")))s" "$name_msg" # column 2: package is installed? @@ -4999,6 +5107,10 @@ GenerateDepsReportTitleLine() a='Supported arch?' printf "%-$((PACKAGE_ARCH_COL_WIDTH+2+$(LenANSIDiff "$a")))s" "$a" + # column 10: installed QPKG author + a='Installed QPKG author:' + printf "%-$((STD_COL_WIDTH+2+$(LenANSIDiff "$a")))s" "$a" + printf '\n' } @@ -5008,252 +5120,433 @@ GenerateDepsReportDataLine() # * This function runs asynchronously * - # Inputs: (local) - # $1 = QPKG name (optional). - # Inputs: (global) # $qpkg_name + local author=$(QpkgGetInstalledAuthor) + local author_ok=false + local author_msg=$CHARS_BLANK + local arch=false local arch_msg=$CHARS_BLANK local dep_name='' local deps='' local deps_msg=$CHARS_NORMAL - local deps_raw=$(QpkgGetDependencies "$qpkg_name") + local deps_raw=$(QpkgGetDatabaseDependencies "$qpkg_name") + local enabled=false local enabled_msg=$CHARS_BLANK + local installed=false local installed_msg=$CHARS_BLANK - local managed='N/A' + local managed=false local managed_msg=$CHARS_BLANK - local max_os=$(QpkgGetMaxOSVer "$qpkg_name") + local max_os=$(QpkgGetDatabaseMaxOSVer "$qpkg_name") local max_os_msg=$CHARS_BLANK - local min_os=$(QpkgGetMinOSVer "$qpkg_name") + local max_os_ok=false + local min_os=$(QpkgGetDatabaseMinOSVer "$qpkg_name") local min_os_msg=$CHARS_BLANK - local min_ram=$(QpkgGetMinRAM "$qpkg_name") + local min_os_ok=false + local min_ram=$(QpkgGetDatabaseMinRAM "$qpkg_name") local min_ram_msg=$CHARS_BLANK + local min_ram_ok=false local mode='' local name_msg=$CHARS_BLANK + local req_alert=false + local req_attention=false - [[ -z $deps_raw ]] && deps_raw=none - [[ -n $max_os && $max_os != none && ${#max_os} -eq 3 ]] && max_os=${max_os:0:1}.${max_os:1:1}.${max_os:2:1} - [[ -n $min_os && $min_os != none && ${#min_os} -eq 3 ]] && min_os=${min_os:0:1}.${min_os:1:1}.${min_os:2:1} - [[ $min_ram != none ]] && min_ram=$(FormatAsThous "$min_ram")kB /bin/touch "$REPORT_FLAGS_PATH"/deps - if QpkgIsMissing; then - mode=highlighted - elif QpkgIsNtInstalled; then - mode=muted - /bin/touch "$REPORT_FLAGS_PATH"/state-notinstalled - else + if QpkgIsInstalledMissing; then + mode=missing + elif QpkgIsInstalled; then mode=normal - - if QpkgIsRepoSelfManaged; then - managed_msg+=$(TextBrightGreen true) - else - managed_msg+=$(TextBrightOrange false) - fi + else + mode=mute + QpkgIsReallyInstalled && QpkgIsNtInstalledAuthorOk && mode=author fi - case $mode in - normal) - name_msg+=$qpkg_name + [[ -z $deps_raw ]] && deps_raw=none + [[ -n $max_os && $max_os != none && ${#max_os} -eq 3 ]] && max_os=${max_os:0:1}.${max_os:1:1}.${max_os:2:1} + [[ -n $min_os && $min_os != none && ${#min_os} -eq 3 ]] && min_os=${min_os:0:1}.${min_os:1:1}.${min_os:2:1} + [[ $min_ram != none ]] && min_ram=$(FormatAsThous "$min_ram")kB - if QpkgIsArchOK; then - arch_msg+=$(TextBrightGreen true) - else - arch_msg=$(TextBrightRed "$CHARS_ALERT") - arch_msg+=$(TextBrightRed false) - name_msg=${CHARS_BLANK}$(TextBrightRed "$qpkg_name") - /bin/touch "$REPORT_FLAGS_PATH"/req-alert - fi + case $mode in + author) + /bin/touch "$REPORT_FLAGS_PATH"/status-wrongauthor + + # Set field values. + arch=N/A + deps='incompatible author' + enabled=N/A + installed=true + managed=N/A + max_os=N/A + min_os=N/A + min_ram=N/A + req_attention=true + + # Assign field messages. + arch_msg+=$arch + author_msg=${CHARS_ATTENTION}${author} + deps_msg=${CHARS_ATTENTION}${deps} + enabled_msg+=$enabled + installed_msg+=$installed + managed_msg+=$managed + max_os_msg+=$max_os + min_os_msg+=$min_os + min_ram_msg+=$min_ram + + # Highlight field messages. + arch_msg=$(TextBrightOrange "$arch_msg") + author_msg=$(TextBrightOrange "$author_msg") + deps_msg=$(TextBrightOrange "$deps_msg") + enabled_msg=$(TextBrightOrange "$enabled_msg") + installed_msg=$(TextBrightGreen "$installed_msg") + managed_msg=$(TextBrightOrange "$managed_msg") + max_os_msg=$(TextBrightOrange "$max_os_msg") + min_os_msg=$(TextBrightOrange "$min_os_msg") + min_ram_msg=$(TextBrightOrange "$min_ram_msg") + ;; + missing) + # Set field values. + QpkgIsDatabaseArchOK && arch=true if [[ $deps_raw != none ]]; then for dep_name in $deps_raw; do [[ -n $deps ]] && deps+=' ' - if QpkgIsInstalled "$dep_name" && QpkgIsEnabled "$dep_name"; then + # Assign highlighting earlier than-usual as each QPKG name can have a different highlight. + + if QpkgIsInstalled "$dep_name" && QpkgIsInstalledEnabled "$dep_name"; then deps+=$(TextBrightGreen "$dep_name") else deps+=$(TextBrightRed "$dep_name") - deps_msg=$(TextBrightRed "$CHARS_ALERT") - name_msg=${CHARS_BLANK}$(TextBrightRed "$qpkg_name") - /bin/touch "$REPORT_FLAGS_PATH"/req-alert fi done else - deps+=$deps_raw + deps+=$(TextBrightGreen "$deps_raw") fi + QpkgIsInstalledEnabled && enabled=true + installed=missing + QpkgIsInstalledRepoSelfManaged && managed=true + QpkgIsDatabaseMaxOSVerOk && max_os_ok=true + QpkgIsDatabaseMinOSVerOk && min_os_ok=true + QpkgIsDatabaseMinRAMOk && min_ram_ok=true + req_alert=true + + # Assign field messages. + + if [[ $arch = true ]]; then + arch_msg+=$arch + else + arch_msg=${CHARS_ALERT}${arch} + fi + + author_msg+=$author deps_msg+=${deps// /, } - if QpkgIsEnabled; then - enabled_msg+=$(TextBrightGreen true) + if [[ $enabled = true ]]; then + enabled_msg+=$enabled else - enabled_msg=$(TextBrightRed "$CHARS_ALERT") - enabled_msg+=$(TextBrightRed false) - name_msg=${CHARS_BLANK}$(TextBrightRed "$qpkg_name") - /bin/touch "$REPORT_FLAGS_PATH"/req-alert + enabled_msg=${CHARS_ALERT}${enabled} fi - installed_msg+=$(TextBrightGreen true) + installed_msg=${CHARS_ALERT}${installed} + managed_msg+=$managed - if QpkgIsMaxOSVerOk; then - if [[ $max_os != none ]]; then - max_os_msg+=$(TextBrightGreen "$max_os") - else - max_os_msg+=$max_os - fi + if [[ $max_os_ok = true ]]; then + max_os_msg+=$max_os else - max_os_msg=$(TextBrightRed "$CHARS_ALERT") - max_os_msg+=$(TextBrightRed "$max_os") - name_msg=${CHARS_BLANK}$(TextBrightRed "$qpkg_name") - /bin/touch "$REPORT_FLAGS_PATH"/req-alert + max_os_msg=${CHARS_ALERT}${max_os} fi - if QpkgIsMinOSVerOk; then - min_os_msg+=$(TextBrightGreen "$min_os") + if [[ $min_os_ok = true ]]; then + min_os_msg+=$min_os else - min_os_msg=$(TextBrightRed "$CHARS_ALERT") - min_os_msg+=$(TextBrightRed "$min_os") - name_msg=${CHARS_BLANK}$(TextBrightRed "$qpkg_name") - /bin/touch "$REPORT_FLAGS_PATH"/req-alert + min_os_msg=${CHARS_ALERT}${min_os} fi - if QpkgIsMinRAMOk; then - if [[ $min_ram != none ]]; then - min_ram_msg+=$(TextBrightGreen "$min_ram") - else - min_ram_msg+=$min_ram + if [[ $min_ram_ok = true ]]; then + min_ram_msg+=$min_ram + else + min_ram_msg=${CHARS_ALERT}${min_ram} + fi + + # Highlight field messages. + + if [[ $arch = true ]]; then + arch_msg=$(TextBrightGreen "$arch_msg") + else + arch_msg=$(TextBrightRed "$arch_msg") + fi + + author_msg=$(TextBrightGreen "$author_msg") + + if [[ $enabled = true ]]; then + enabled_msg=$(TextBrightGreen "$enabled_msg") + else + enabled_msg=$(TextBrightRedBlink "$enabled_msg") + fi + + installed_msg=$(TextBrightRedBlink "$installed_msg") + + if [[ $managed = true ]]; then + managed_msg=$(TextBrightGreen "$managed_msg") + else + managed_msg=$(TextBrightOrange "$managed_msg") + fi + + if [[ $max_os_ok = true ]]; then + if [[ $max_os != none ]]; then + max_os_msg=$(TextBrightGreen "$max_os_msg") fi else - min_ram_msg=$(TextBrightRed "$CHARS_ALERT") - min_ram_msg+=$(TextBrightRed "$min_ram") - name_msg=${CHARS_BLANK}$(TextBrightRed "$qpkg_name") - /bin/touch "$REPORT_FLAGS_PATH"/req-alert + max_os_msg=$(TextBrightRed "$max_os_msg") fi - ;; - muted) - managed_msg+=$(TextDarkGrey 'N/A') - name_msg+=$(TextDarkGrey "$qpkg_name") - /bin/touch "$REPORT_FLAGS_PATH"/na + if [[ $min_os_ok = true ]]; then + if [[ $min_os != none ]]; then + min_os_msg=$(TextBrightGreen "$min_os_msg") + fi + else + min_os_msg=$(TextBrightRed "$min_os_msg") + fi - if QpkgIsArchOK "$qpkg_name"; then - arch_msg+=$(TextDarkGrey true) + if [[ $min_ram_ok = true ]]; then + if [[ $min_ram != none ]]; then + min_ram_msg=$(TextBrightGreen "$min_ram_msg") + fi else - arch_msg=$(TextBrightOrange "$CHARS_ATTENTION") - arch_msg+=$(TextBrightOrange false) - /bin/touch "$REPORT_FLAGS_PATH"/req-attention + min_ram_msg=$(TextBrightRed "$min_ram_msg") fi + ;; + mute) + /bin/touch "$REPORT_FLAGS_PATH"/state-notinstalled - deps_msg=$(TextDarkGrey "$CHARS_NORMAL") + # Set field values. + QpkgIsDatabaseArchOK "$qpkg_name" && arch=true + author=N/A if [[ $deps_raw != none ]]; then for dep_name in $deps_raw; do [[ -n $deps ]] && deps+=' ' - deps+=$(TextDarkGrey "$dep_name") + deps+=$dep_name done else - deps+=$(TextDarkGrey "$deps_raw") + deps+=$deps_raw fi - deps_msg+=${deps// /$(TextDarkGrey ', ')} - enabled_msg+=$(TextDarkGrey 'N/A') - installed_msg+=$(TextDarkGrey false) + enabled=N/A + managed=N/A + QpkgIsDatabaseMaxOSVerOk "$qpkg_name" && max_os_ok=true + QpkgIsDatabaseMinOSVerOk "$qpkg_name" && min_os_ok=true + QpkgIsDatabaseMinRAMOk "$qpkg_name" && min_ram_ok=true + /bin/touch "$REPORT_FLAGS_PATH"/na - if QpkgIsMaxOSVerOk "$qpkg_name"; then - max_os_msg+=$(TextDarkGrey "$max_os") + # Assign field messages. + + if [[ $arch = true ]]; then + arch_msg+=$arch + else + arch_msg=${CHARS_ATTENTION}${arch} + req_attention=true + fi + + author_msg+=$author + deps_msg+=${deps// /, } + enabled_msg+=$enabled + installed_msg+=$installed + managed_msg+=$managed + + if [[ $max_os_ok = true ]]; then + max_os_msg+=$max_os + else + max_os_msg=${CHARS_ATTENTION}${max_os} + req_attention=true + fi + + if [[ $min_os_ok = true ]]; then + min_os_msg+=$min_os + else + min_os_msg=${CHARS_ATTENTION}${min_os} + req_attention=true + fi + + if [[ $min_ram_ok = true ]]; then + min_ram_msg+=$min_ram + else + min_ram_msg=${CHARS_ATTENTION}${min_ram} + req_attention=true + fi + + # Highlight field messages. + + if [[ $arch = true ]]; then + arch_msg=$(TextDarkGrey "$arch_msg") else - max_os_msg=$(TextBrightOrange "$CHARS_ATTENTION") - max_os_msg+=$(TextBrightOrange "$max_os") - /bin/touch "$REPORT_FLAGS_PATH"/req-attention + arch_msg=$(TextBrightOrange "$arch_msg") fi - if QpkgIsMinOSVerOk "$qpkg_name"; then - min_os_msg+=$(TextDarkGrey "$min_os") + author_msg=$(TextDarkGrey "$author_msg") + deps_msg=$(TextDarkGrey "$deps_msg") + enabled_msg=$(TextDarkGrey "$enabled_msg") + installed_msg=$(TextDarkGrey "$installed_msg") + managed_msg=$(TextDarkGrey "$managed_msg") + + if [[ $max_os_ok = true ]]; then + max_os_msg=$(TextDarkGrey "$max_os_msg") else - min_os_msg=$(TextBrightOrange "$CHARS_ATTENTION") - min_os_msg+=$(TextBrightOrange "$min_os") - /bin/touch "$REPORT_FLAGS_PATH"/req-attention + max_os_msg=$(TextBrightOrange "$max_os_msg") fi - if QpkgIsMinRAMOk "$qpkg_name"; then - min_ram_msg+=$(TextDarkGrey "$min_ram") + if [[ $min_os_ok = true ]]; then + min_os_msg=$(TextDarkGrey "$min_os_msg") else - min_ram_msg=$(TextBrightOrange "$CHARS_ATTENTION") - min_ram_msg+=$(TextBrightOrange "$min_ram") - /bin/touch "$REPORT_FLAGS_PATH"/req-attention + min_os_msg=$(TextBrightOrange "$min_os_msg") fi + if [[ $min_ram_ok = true ]]; then + min_ram_msg=$(TextDarkGrey "$min_ram_msg") + else + min_ram_msg=$(TextBrightOrange "$min_ram_msg") + fi ;; - highlighted) - if QpkgIsArchOK; then - arch_msg+=$(TextBrightGreen true) + normal) + # Set field values. + + QpkgIsDatabaseArchOK && arch=true + author_ok=true + QpkgIsInstalledEnabled && enabled=true + installed=true + QpkgIsInstalledRepoSelfManaged && managed=true + QpkgIsDatabaseMaxOSVerOk && max_os_ok=true + QpkgIsDatabaseMinOSVerOk && min_os_ok=true + QpkgIsDatabaseMinRAMOk && min_ram_ok=true + + # Assign field messages. + + if [[ $arch = true ]]; then + arch_msg+=$arch else - arch_msg=$(TextBrightRed "$CHARS_ALERT") - arch_msg+=$(TextBrightRed false) - /bin/touch "$REPORT_FLAGS_PATH"/req-alert + arch_msg=${CHARS_ALERT}${arch} + req_alert=true fi + author_msg+=$author + if [[ $deps_raw != none ]]; then for dep_name in $deps_raw; do [[ -n $deps ]] && deps+=' ' - if QpkgIsInstalled "$dep_name" && QpkgIsEnabled "$dep_name"; then + if QpkgIsInstalled "$dep_name" && QpkgIsInstalledEnabled "$dep_name"; then deps+=$(TextBrightGreen "$dep_name") else deps+=$(TextBrightRed "$dep_name") + deps_msg=$(TextBrightRed "$CHARS_ALERT") + req_alert=true fi done else - deps+=$(TextBrightGreen "$deps_raw") + deps+=$deps_raw + fi + + if [[ $enabled = true ]]; then + enabled_msg+=$enabled + else + enabled_msg=${CHARS_ALERT}${enabled} + req_alert=true + fi + + installed_msg+=$installed + managed_msg+=$managed + + if [[ $max_os_ok = true ]]; then + max_os_msg+=$max_os + else + max_os_msg=${CHARS_ALERT}${max_os} + req_alert=true fi + if [[ $min_os_ok = true ]]; then + min_os_msg+=$min_os + else + min_os_msg=${CHARS_ALERT}${min_os} + req_alert=true + fi + + if [[ $min_ram_ok = true ]]; then + min_ram_msg+=$min_ram + else + min_ram_msg=${CHARS_ALERT}${min_ram} + req_alert=true + fi + + # Highlight field messages. + + if [[ $arch = true ]]; then + arch_msg=$(TextBrightGreen "$arch_msg") + else + arch_msg=$(TextBrightRed "$arch_msg") + fi + + author_msg=$(TextBrightGreen "$author_msg") deps_msg+=${deps// /, } - if QpkgIsEnabled; then - enabled_msg+=$(TextBrightGreen true) + if [[ $enabled = true ]]; then + enabled_msg=$(TextBrightGreen "$enabled_msg") else - enabled_msg=$(TextBrightRedBlink "$CHARS_ALERT") - enabled_msg+=$(TextBrightRed 'false') - /bin/touch "$REPORT_FLAGS_PATH"/req-alert + enabled_msg=$(TextBrightRed "$enabled_msg") fi - installed_msg=$(TextBrightRedBlink "$CHARS_ALERT") - installed_msg+=$(TextBrightRedBlink 'missing') - /bin/touch "$REPORT_FLAGS_PATH"/req-alert + installed_msg=$(TextBrightGreen "$installed_msg") - if QpkgIsMaxOSVerOk; then - max_os_msg+=$(TextBrightGreen "$max_os") + if [[ $managed = true ]]; then + managed_msg=$(TextBrightGreen "$managed_msg") else - max_os_msg=$(TextBrightRed "$CHARS_ALERT") - max_os_msg+=$(TextBrightRed "$max_os") - /bin/touch "$REPORT_FLAGS_PATH"/req-alert + managed_msg=$(TextBrightOrange "$managed_msg") fi - if QpkgIsMinOSVerOk; then - min_os_msg+=$(TextBrightGreen "$min_os") + if [[ $max_os_ok = true ]]; then + if [[ $max_os != none ]]; then + max_os_msg=$(TextBrightGreen "$max_os_msg") + fi else - min_os_msg=$(TextBrightRed "$CHARS_ALERT") - min_os_msg+=$(TextBrightRed "$min_os") - /bin/touch "$REPORT_FLAGS_PATH"/req-alert + max_os_msg=$(TextBrightRed "$max_os_msg") fi - if QpkgIsMinRAMOk; then - min_ram_msg+=$(TextBrightGreen "$min_ram") + if [[ $min_os_ok = true ]]; then + if [[ $min_os != none ]]; then + min_os_msg=$(TextBrightGreen "$min_os_msg") + fi else - min_ram_msg=$(TextBrightRed "$CHARS_ALERT") - min_ram_msg+=$(TextBrightRed "$min_ram") - /bin/touch "$REPORT_FLAGS_PATH"/req-alert + min_os_msg=$(TextBrightRed "$min_os_msg") fi - name_msg+=$(TextBrightRed "$qpkg_name") + if [[ $min_ram_ok = true ]]; then + if [[ $min_ram != none ]]; then + min_ram_msg=$(TextBrightGreen "$min_ram_msg") + fi + else + min_ram_msg=$(TextBrightRed "$min_ram_msg") + fi esac - if [[ -e $GNU_AWK_CMD ]]; then - printf '%s|%s|%s|%s|%s|%s|%s|%s|%s\n' "$name_msg" "$deps_msg" "$installed_msg" "$enabled_msg" "$managed_msg" "$min_ram_msg" "$min_os_msg" "$max_os_msg" "$arch_msg" + if [[ $req_alert = true ]]; then + /bin/touch "$REPORT_FLAGS_PATH"/req-alert + name_msg=${CHARS_BLANK}$(TextBrightRed "$qpkg_name") + elif [[ $req_attention = true ]]; then + /bin/touch "$REPORT_FLAGS_PATH"/req-attention + name_msg=${CHARS_BLANK}$(TextBrightOrange "$qpkg_name") + elif [[ $mode = mute ]]; then + name_msg+=$(TextDarkGrey "$qpkg_name") + else + name_msg+=$qpkg_name + fi + + if OsIsSupportAutowidthTableColumns; then + echo "$name_msg|$deps_msg|$installed_msg|$enabled_msg|$managed_msg|$min_ram_msg|$min_os_msg|$max_os_msg|$arch_msg|$author_msg" else - # column 1: package qpkg_name + # column 1: package name. printf "%-$((PACKAGE_NAME_COL_WIDTH+$(LenANSIDiff "$name_msg")))s" "$name_msg" # column 2: package dependencies. @@ -5288,6 +5581,10 @@ GenerateDepsReportDataLine() printf "%$((COLUMN_SPACING))s" printf "%-$((PACKAGE_ARCH_COL_WIDTH+$(LenANSIDiff "$arch_msg")))s" "$arch_msg" + # column 10: installed QPKG author. + printf "%$((COLUMN_SPACING))s" + printf "%-$((STD_COL_WIDTH+$(LenANSIDiff "$author_msg")))s" "$author_msg" + printf '\n' fi @@ -5346,187 +5643,174 @@ GenerateFeaturesReportDataLine() # Inputs: (global) # $qpkg_name + local active_test=false local active_test_msg=$CHARS_BLANK + local autoupdate=false local autoupdate_msg=$CHARS_BLANK + local backup=false local backup_msg=$CHARS_BLANK + local clean=false local clean_msg=$CHARS_BLANK + local compatible=false local compatible_msg=$CHARS_BLANK local mode='' local name_msg=$CHARS_BLANK + local req_alert=false + local req_attention=false + local restart_to_update=false local restart_to_update_msg=$CHARS_BLANK + local sherpa_compatible=false local sherpa_compatible_msg=$CHARS_BLANK + local tier=false local tier_msg=$CHARS_BLANK - if QpkgIsMissing; then - mode=highlighted - elif QpkgIsNtInstalled; then - mode=muted - else + if QpkgIsInstalledMissing; then + mode=missing + elif QpkgIsInstalled; then mode=normal - fi - - if [[ $(QpkgGetActiveTest) = builtin ]]; then - active_test_msg+=true - else - active_test_msg+=false - fi - - if QpkgIsCanBackup; then - backup_msg+=true - else - backup_msg+=false - fi - - if QpkgIsCanClean; then - clean_msg+=true - else - clean_msg+=false - fi - - if QpkgIsCanRestartToUpdate; then - restart_to_update_msg+=true - elif [[ $qpkg_name = sherpa ]]; then - restart_to_update_msg+=true # sherpa always auto-updates and this can't be disabled. - else - restart_to_update_msg+=false - fi - - if QpkgIsInstalled && QpkgIsCanRestartToUpdate; then - if QpkgIsAutoUpdate; then - autoupdate_msg+=true - else - autoupdate_msg+=false - fi - elif [[ $qpkg_name = sherpa ]]; then - autoupdate_msg+=true # sherpa always auto-updates and this can't be disabled. - else - autoupdate_msg+='N/A' - /bin/touch "$REPORT_FLAGS_PATH"/na - fi - - if QpkgIsIndependent; then - tier_msg+=true - else - tier_msg+=false - fi - - if QpkgIsArchOK; then - compatible_msg+=true - else - compatible_msg+=false - fi - - if QpkgIsSherpaCompatible; then - sherpa_compatible_msg+=true else - sherpa_compatible_msg+=false + mode=mute + QpkgIsReallyInstalled && QpkgIsNtInstalledAuthorOk && mode=author fi case $mode in - normal) - if [[ $active_test_msg =~ true ]]; then - active_test_msg=$(TextBrightGreen "$active_test_msg") - else - active_test_msg=$(TextBrightOrange "$active_test_msg") - fi - - if [[ $compatible_msg =~ true ]]; then - compatible_msg=$(TextBrightGreen "$compatible_msg") - else - compatible_msg=$(TextBrightRed "$compatible_msg") - fi - - if [[ $autoupdate_msg =~ true ]]; then - autoupdate_msg=$(TextBrightGreen "$autoupdate_msg") - elif [[ $autoupdate_msg =~ false ]]; then - autoupdate_msg=$(TextBrightOrange "$autoupdate_msg") - fi - - if [[ $backup_msg =~ true ]]; then - backup_msg=$(TextBrightGreen "$backup_msg") -# else -# backup_msg=$(TextBrightOrange "$backup_msg") - fi + author) + # Set field values. + backup='incompatible author' + req_attention=true - if [[ $clean_msg =~ true ]]; then - clean_msg=$(TextBrightGreen "$clean_msg") -# else -# clean_msg=$(TextBrightOrange "$clean_msg") - fi + # Assign field messages. + backup_msg=${CHARS_ATTENTION}${backup} - name_msg+=$qpkg_name + # Highlight field messages. + backup_msg=$(TextBrightOrange "$backup_msg") + ;; + missing) + # Set field values. + backup=missing + req_alert=true - if [[ $restart_to_update_msg =~ true ]]; then - restart_to_update_msg=$(TextBrightGreen "$restart_to_update_msg") -# else -# restart_to_update_msg=$(TextBrightOrange "$restart_to_update_msg") - fi + # Assign field messages. + backup_msg=${CHARS_ALERT}${backup} - if [[ $sherpa_compatible_msg =~ true ]]; then - sherpa_compatible_msg=$(TextBrightGreen "$sherpa_compatible_msg") - else - sherpa_compatible_msg=$(TextBrightOrange "$sherpa_compatible_msg") - fi + # Highlight field messages. + backup_msg=$(TextBrightRedBlink "$backup_msg") ;; - muted) + mute) + # Set field values. + active_test=N/A + autoupdate=N/A + backup=N/A + clean=N/A + compatible=N/A + restart_to_update=N/A + sherpa_compatible=N/A + tier=N/A + + # Assign field messages. + active_test_msg+=$active_test + autoupdate_msg+=$autoupdate + backup_msg+=$backup + clean_msg+=$clean + compatible_msg+=$compatible + restart_to_update_msg+=$restart_to_update + sherpa_compatible_msg+=$sherpa_compatible + tier_msg+=$tier + + # Highlight field messages. active_test_msg=$(TextDarkGrey "$active_test_msg") - compatible_msg=$(TextDarkGrey "$compatible_msg") autoupdate_msg=$(TextDarkGrey "$autoupdate_msg") backup_msg=$(TextDarkGrey "$backup_msg") clean_msg=$(TextDarkGrey "$clean_msg") - name_msg+=$(TextDarkGrey "$qpkg_name") + compatible_msg=$(TextDarkGrey "$compatible_msg") restart_to_update_msg=$(TextDarkGrey "$restart_to_update_msg") sherpa_compatible_msg=$(TextDarkGrey "$sherpa_compatible_msg") tier_msg=$(TextDarkGrey "$tier_msg") ;; - highlighted) - if [[ $active_test_msg =~ true ]]; then - active_test_msg=$(TextBrightGreen "$active_test_msg") - else - active_test_msg=$(TextBrightOrange "$active_test_msg") - fi + normal) + # Set field values. + [[ $(QpkgGetDatabaseActiveTest) = builtin ]] && active_test=true - if [[ $compatible_msg =~ true ]]; then - compatible_msg=$(TextBrightGreen "$compatible_msg") + if QpkgIsInstalled && QpkgIsDatabaseCanRestartToUpdate; then + if QpkgIsInstalledAutoUpdate; then + autoupdate=true + fi + elif [[ $qpkg_name = sherpa ]]; then + autoupdate=true # sherpa always auto-updates and this can't be disabled. else - compatible_msg=$(TextBrightOrange "$compatible_msg") + autoupdate=N/A + /bin/touch "$REPORT_FLAGS_PATH"/na fi - if [[ $autoupdate_msg =~ true ]]; then - autoupdate_msg=$(TextBrightGreen "$autoupdate_msg") - else - autoupdate_msg=$(TextBrightOrange "$autoupdate_msg") + QpkgIsDatabaseCanBackup && backup=true + QpkgIsDatabaseCanClean && clean=true + QpkgIsDatabaseArchOK && compatible=true + + if QpkgIsDatabaseCanRestartToUpdate; then + restart_to_update=true + elif [[ $qpkg_name = sherpa ]]; then + restart_to_update=true # sherpa always auto-updates and this can't be disabled. fi - if [[ $backup_msg =~ true ]]; then - backup_msg=$(TextBrightGreen "$backup_msg") + QpkgIsDatabaseSherpaCompatible && sherpa_compatible=true + QpkgIsDatabaseIndependent && tier=true + + # Assign field messages. + active_test_msg+=$active_test + autoupdate_msg+=$autoupdate + backup_msg+=$backup + clean_msg+=$clean + compatible_msg+=$compatible + restart_to_update_msg+=$restart_to_update + sherpa_compatible_msg+=$sherpa_compatible + tier_msg+=$tier + + # Highlight field messages. + + if [[ $active_test = true ]]; then + active_test_msg=$(TextBrightGreen "$active_test_msg") else - backup_msg=$(TextBrightOrange "$backup_msg") + active_test_msg=$(TextBrightOrange "$active_test_msg") fi - if [[ $clean_msg =~ true ]]; then - clean_msg=$(TextBrightGreen "$clean_msg") - else - clean_msg=$(TextBrightOrange "$clean_msg") + if [[ $autoupdate = true ]]; then + autoupdate_msg=$(TextBrightGreen "$autoupdate_msg") + elif [[ $autoupdate = false ]]; then + autoupdate_msg=$(TextBrightOrange "$autoupdate_msg") fi - name_msg+=$(TextBrightRed "$qpkg_name") + [[ $backup = true ]] && backup_msg=$(TextBrightGreen "$backup_msg") + [[ $clean = true ]] && clean_msg=$(TextBrightGreen "$clean_msg") - if [[ $restart_to_update_msg =~ true ]]; then - restart_to_update_msg=$(TextBrightGreen "$restart_to_update_msg") + if [[ $compatible = true ]]; then + compatible_msg=$(TextBrightGreen "$compatible_msg") else - restart_to_update_msg=$(TextBrightOrange "$restart_to_update_msg") + compatible_msg=$(TextBrightRed "$compatible_msg") fi - if [[ $sherpa_compatible_msg =~ true ]]; then + [[ $restart_to_update = true ]] && restart_to_update_msg=$(TextBrightGreen "$restart_to_update_msg") + + if [[ $sherpa_compatible = true ]]; then sherpa_compatible_msg=$(TextBrightGreen "$sherpa_compatible_msg") else sherpa_compatible_msg=$(TextBrightOrange "$sherpa_compatible_msg") fi esac - if [[ -e $GNU_AWK_CMD ]]; then - printf '%s|%s|%s|%s|%s|%s|%s|%s|%s\n' "$name_msg" "$backup_msg" "$clean_msg" "$restart_to_update_msg" "$autoupdate_msg" "$active_test_msg" "$tier_msg" "$compatible_msg" "$sherpa_compatible_msg" + if [[ $req_alert = true ]]; then + /bin/touch "$REPORT_FLAGS_PATH"/req-alert + name_msg=${CHARS_BLANK}$(TextBrightRed "$qpkg_name") + elif [[ $req_attention = true ]]; then + /bin/touch "$REPORT_FLAGS_PATH"/req-attention + name_msg=${CHARS_BLANK}$(TextBrightOrange "$qpkg_name") + elif [[ $mode = mute ]]; then + name_msg+=$(TextDarkGrey "$qpkg_name") + else + name_msg+=$qpkg_name + fi + + if OsIsSupportAutowidthTableColumns; then + echo "$name_msg|$backup_msg|$clean_msg|$restart_to_update_msg|$autoupdate_msg|$active_test_msg|$tier_msg|$compatible_msg|$sherpa_compatible_msg" else # column 1: package name. printf "%-$((PACKAGE_NAME_COL_WIDTH+$(LenANSIDiff "$name_msg")))s" "$name_msg" @@ -5612,7 +5896,7 @@ DisplayAsBacksReportItemLine() local mode='' if [[ ${epoch_time%.*} -lt $(/bin/date --date="$local_highlight_backups_older_than" +%s) ]]; then - mode=highlighted + mode=highlight else mode=normal fi @@ -5626,7 +5910,7 @@ DisplayAsBacksReportItemLine() file_name_msg+=$file_name /bin/touch "$REPORT_FLAGS_PATH"/backup-file-ok ;; - highlighted) + highlight) epoch_time_msg=$(TextBrightRed "${CHARS_ALERT}$(ConvertSecondsToFullDate "$epoch_time")") file_bytes_msg+=$(TextBrightRed "$file_bytes") file_name_msg+=$(TextBrightRed "$file_name") @@ -5735,7 +6019,7 @@ DisplayWait() } -Help.Actions:Show() +ShowHelpActions() { DisableDebugToArchiveAndFile @@ -5743,7 +6027,7 @@ Help.Actions:Show() { - Help.Basic:Show + ShowHelpBasic DisplayAsHelpTitle "$(ShowAsAction) usage examples:" DisplayAsProjSynIndentExam 'activate these packages (this will upgrade internal applications where-supported)' "activate $(ShowAsPackages)" DisplayAsProjSynIndentExam '' "start $(ShowAsPackages)" @@ -5799,7 +6083,7 @@ Help.Actions:Show() } -Help.ActionsAll:Show() +ShowHelpActionsAll() { DisableDebugToArchiveAndFile @@ -5807,7 +6091,7 @@ Help.ActionsAll:Show() { - Help.Basic:Show + ShowHelpBasic DisplayAsHelpTitle "the 'all' group applies to all QPKGs. If $(ShowAsAction) is 'install all' then all available QPKGs will be installed." DisplayAsHelpTitle "$(ShowAsAction) $(ShowAsPackageGroup) usage examples:" DisplayAsProjSynIndentExam 'activate all QPKGs (this will upgrade internal applications where-supported)' 'activate all' @@ -5846,7 +6130,7 @@ Help.ActionsAll:Show() } -Help.BackupLocation:Show() +ShowHelpBackupLocation() { DisplayAsSynExam 'the backup location can be accessed by running' "cd $QPKG_BU_PATH" @@ -5855,7 +6139,7 @@ Help.BackupLocation:Show() } -Help.Basic:Show() +ShowHelpBasic() { DisplayAsHelpTitle "usage: sherpa $(ShowAsAction) $(ShowAsPackages) $(ShowAsPackageGroup) $(ShowAsOptions)" @@ -5864,7 +6148,7 @@ Help.Basic:Show() } -Help.Basic.Examples:Show() +ShowHelpBasicExamples() { DisplayAsProjSynIndentExam "to see available $(ShowAsAction)s" 'help actions' @@ -5878,7 +6162,7 @@ Help.Basic.Examples:Show() } -Help.Groups:Show() +ShowHelpGroups() { DisableDebugToArchiveAndFile @@ -5886,7 +6170,7 @@ Help.Groups:Show() { - Help.Basic:Show + ShowHelpBasic DisplayAsHelpTitle "$(ShowAsPackageGroup) usage examples:" DisplayAsProjSynIndentExam 'select every package' "$(ShowAsAction) all" DisplayAsProjSynIndentExam 'select only independent QPKGs (these do not depend on other QPKGs)' "$(ShowAsAction) independent" @@ -5919,7 +6203,7 @@ Help.Groups:Show() } -Help.Issue:Show() +ShowHelpIssue() { DisplayAsHelpTitle "please consider creating a new issue for this on GitHub: $(ShowAsURL 'https://github.com/OneCDOnly/sherpa/issues')" @@ -5935,7 +6219,7 @@ Help.Issue:Show() } -Help.Lists:Show() +ShowHelpLists() { DisableDebugToArchiveAndFile @@ -5943,7 +6227,7 @@ Help.Lists:Show() { - Help.Basic:Show + ShowHelpBasic DisplayAsHelpTitle "'list' usage examples:" DisplayAsProjSynIndentExam 'list all available QPKGs' 'list all' # DisplayAsProjSynIndentExam 'list package backup files' 'list backups' @@ -5972,195 +6256,54 @@ Help.Lists:Show() } -ShowReportAllActionResults() +ShowHelpShow() { - local -i a=0 - local -i b=0 - local -i c=0 - local -i d=0 - local -i e=0 - local action='' - local -i datetime=0 - local -i duration=0 - local package_name='' - local package_type='' - local -i quantity=0 - local reason='' - local result='' - - if [[ $useropt_show_all_results = true ]]; then - show_action_results_failed=true - show_action_results_ok=true - show_action_results_skipped=true - fi - - if [[ -e $SESS_ACTION_RESULTS_PATHFILE ]]; then - while IFS='|' read -r datetime action quantity package_name package_type result duration reason; do - if [[ $datetime -gt 0 && $duration -gt 0 ]]; then - [[ $a -eq 0 ]] && a=$datetime # Only use first entry as start time. - b=$datetime - c=$duration - ((d++)) - fi - done < "$SESS_ACTION_RESULTS_PATHFILE" - - a=$(ConvertMillisecondsToSeconds "$a") - b=$(ConvertMillisecondsToSeconds "$b") - c=$(ConvertMillisecondsToSeconds "$c") - - [[ $b -gt 0 ]] && e=$((b+c+1)) # Use last non-zero iteration of $datetime as beginning of last action, then add duration to it. + DisableDebugToArchiveAndFile + DisplayProcReport show - if [[ $show_action_results_ok = true || $show_action_results_skipped = true || $show_action_results_failed = true || $show_action_results_zero = true ]]; then - { + { - DisplayAsHelpTitle "package action$(Pluralise "$d") started @ $(ConvertSecondsToTime "$a"), ended @ $(ConvertSecondsToTime "$e"), elapsed = $(ConvertSecondsToDuration "$(CalcAmountDiff "$a" "$e")")" + ShowHelpBasic + DisplayAsHelpTitle "'show' usage examples:" + DisplayAsProjSynIndentExam 'show QPKG abbreviations' 'show abbreviations' + DisplayAsProjSynIndentExam '' 'show abs' + DisplayAsProjSynIndentExam '' a + DisplayAsProjSynIndentExam 'show application backup files' 'show backups' + DisplayAsProjSynIndentExam '' b + DisplayAsProjSynIndentExam 'show QPKG dependency report' 'show dependencies' + DisplayAsProjSynIndentExam '' 'show deps' + DisplayAsProjSynIndentExam '' d + DisplayAsProjSynIndentExam 'show QPKG repository assignments report' 'show repositories' + DisplayAsProjSynIndentExam '' 'show repos' + DisplayAsProjSynIndentExam '' r + DisplayAsProjSynIndentExam 'show last session action results' 'show results' + DisplayAsProjSynIndentExam '' results + DisplayAsProjSynIndentExam 'find the live status of each application in all QPKGs' 'show status' - [[ $show_action_results_ok = true ]] && ShowReportActionResults ok - [[ $show_action_results_skipped = true ]] && ShowReportActionResults skipped - [[ $show_action_results_failed = true ]] && ShowReportActionResults failed - [[ $show_action_results_zero = true ]] && ShowZeroQpkgs + } > "$REPORT_OUTPUT_PATHFILE" - } > "$REPORT_OUTPUT_PATHFILE" + EraseThisLine - if [[ -e $REPORT_OUTPUT_PATHFILE ]]; then - DisplayFileInViewport "$REPORT_OUTPUT_PATHFILE" - else - ShowAsError 'no information to display' - fi - fi + if [[ -e $REPORT_OUTPUT_PATHFILE ]]; then + DisplayFileInViewport "$REPORT_OUTPUT_PATHFILE" + else + ShowAsError 'no information to display' fi + return 0 + } -ShowReportActionResults() +ShowHelpOptions() { - # Inputs: - # $1 = `ok`, `skipped`, `failed` - - local action='' - local -i count=0 - local -i datetime=0 - local -i duration=0 - local package_name='' - local package_type='' - local -i quantity=0 - local reason='' - local result='' - - if [[ -e $SESS_ACTION_RESULTS_PATHFILE ]]; then - # Obtain count of same results. Need to know if action applied to one QPKG or many. - - while IFS='|' read -r datetime action quantity package_name package_type result duration reason; do - if [[ $result = "$1" ]] || [[ $1 = skipped && ($result = 'skipped-ok' || $result = 'skipped-error' || $result = 'skipped-abort') ]]; then - [[ $action = status && $useropt_show_all_results = false ]] && continue # Don't need to see the result of `status` checks unless a 'results' report has been requested. - ((count++)) - [[ $count -gt 1 ]] && break # Two-or-more of the same action means must pluralise messages. - fi - done < "$SESS_ACTION_RESULTS_PATHFILE" - - # Display action titles and QPKGs. - - if [[ $count -eq 1 ]]; then - case $1 in - ok) - DisplayAsHelpTitle "this package action completed $(TextBrightGreen OK):" - ;; - skipped) - DisplayAsHelpTitle "this package action was $(TextBrightOrange skipped) (and why):" - ;; - failed) - DisplayAsHelpTitle "this package action $(TextBrightRed failed) (and why):" - esac - elif [[ $count -gt 1 ]]; then - case $1 in - ok) - DisplayAsHelpTitle "these package actions completed $(TextBrightGreen OK):" - ;; - skipped) - DisplayAsHelpTitle "these package actions were $(TextBrightOrange skipped) (and why):" - ;; - failed) - DisplayAsHelpTitle "these package actions $(TextBrightRed failed) (and why):" - esac - fi - - if [[ $count -ge 1 ]]; then - while IFS='|' read -r datetime action quantity package_name package_type result duration reason; do - if [[ $result = "$1" ]] || [[ $1 = skipped && ($result = 'skipped-ok' || $result = 'skipped-error' || $result = 'skipped-abort') ]]; then - [[ $action = status && $useropt_show_all_results = false ]] && continue # Don't need to see the result of `status` checks unless a 'results' report has been requested. - ShowAsActionLogDetail "$datetime" "$package_name" "$action" "$result" "$duration" "$reason" "$package_type" "$quantity" - fi - done < "$SESS_ACTION_RESULTS_PATHFILE" - fi - fi - - if [[ $count -eq 0 ]]; then - case $1 in - ok) - DisplayAsHelpTitle "no package actions completed $(TextBrightGreen OK)." - ;; - skipped) - DisplayAsHelpTitle "no package actions were $(TextBrightOrange skipped)." - ;; - failed) - DisplayAsHelpTitle "no package actions $(TextBrightRed failed)." - esac - fi - - return 0 - - } - -Help.Show:Show() - { - - DisableDebugToArchiveAndFile - DisplayProcReport show - - { - - Help.Basic:Show - DisplayAsHelpTitle "'show' usage examples:" - DisplayAsProjSynIndentExam 'show QPKG abbreviations' 'show abbreviations' - DisplayAsProjSynIndentExam '' 'show abs' - DisplayAsProjSynIndentExam '' a - DisplayAsProjSynIndentExam 'show application backup files' 'show backups' - DisplayAsProjSynIndentExam '' b - DisplayAsProjSynIndentExam 'show QPKG dependency report' 'show dependencies' - DisplayAsProjSynIndentExam '' 'show deps' - DisplayAsProjSynIndentExam '' d - DisplayAsProjSynIndentExam 'show QPKG repository assignments report' 'show repositories' - DisplayAsProjSynIndentExam '' 'show repos' - DisplayAsProjSynIndentExam '' r - DisplayAsProjSynIndentExam 'show last session action results' 'show results' - DisplayAsProjSynIndentExam '' results - DisplayAsProjSynIndentExam 'find the live status of each application in all QPKGs' 'show status' - - } > "$REPORT_OUTPUT_PATHFILE" - - EraseThisLine - - if [[ -e $REPORT_OUTPUT_PATHFILE ]]; then - DisplayFileInViewport "$REPORT_OUTPUT_PATHFILE" - else - ShowAsError 'no information to display' - fi - - return 0 - - } - -Help.Options:Show() - { - - DisableDebugToArchiveAndFile - DisplayProcReport options + DisableDebugToArchiveAndFile + DisplayProcReport options { - Help.Basic:Show + ShowHelpBasic DisplayAsHelpTitle "$(ShowAsOptions) usage examples:" DisplayAsProjSynIndentExam 'show debugging information, and record it to file' "$(ShowAsAction) $(ShowAsPackages) debug" DisplayAsProjSynIndentExam '' "$(ShowAsAction) $(ShowAsPackages) verbose" @@ -6180,7 +6323,7 @@ Help.Options:Show() } -Help.Packages:Show() +ShowHelpPackages() { DisableDebugToArchiveAndFile @@ -6188,7 +6331,7 @@ Help.Packages:Show() { - Help.Basic:Show + ShowHelpBasic DisplayAsHelpTitle 'usage examples for QPKGs will go here:' } > "$REPORT_OUTPUT_PATHFILE" @@ -6205,7 +6348,7 @@ Help.Packages:Show() } -Help.Problems:Show() +ShowHelpProblems() { DisableDebugToArchiveAndFile @@ -6213,7 +6356,7 @@ Help.Problems:Show() { - Help.Basic:Show + ShowHelpBasic DisplayAsHelpTitle 'usage examples for dealing with problems:' DisplayAsProjSynIndentExam 'activate these QPKGs' "activate $(ShowAsPackages)" DisplayAsProjSynIndentExam 'ensure all dependencies exist for installed QPKGs' check @@ -6249,7 +6392,7 @@ Help.Problems:Show() } -Help.Upgrades:Show() +ShowHelpUpgrades() { DisableDebugToArchiveAndFile @@ -6257,7 +6400,7 @@ Help.Upgrades:Show() { - Help.Basic:Show + ShowHelpBasic DisplayAsHelpTitle 'usage examples for upgrading your QPKGs:' DisplayAsProjSynIndentExam 'upgrade only the upgradable QPKGs' 'upgrade upgradable' DisplayAsProjSynIndentExam '' 'upgrade new' @@ -6281,7 +6424,7 @@ Help.Upgrades:Show() } -Help.Tips:Show() +ShowHelpTips() { DisableDebugToArchiveAndFile @@ -6289,7 +6432,7 @@ Help.Tips:Show() { - Help.Basic:Show + ShowHelpBasic DisplayAsHelpTitle 'helpful tips and shortcuts:' DisplayAsProjSynIndentExam "install all available $(ShowAsTitleName) QPKGs" 'install all' DisplayAsProjSynIndentExam 'package abbreviations and aliases also work. To see these' 'help abs' @@ -6300,7 +6443,7 @@ Help.Tips:Show() DisplayAsProjSynIndentExam '' l DisplayAsProjSynIndentExam 'activate all inactive QPKGs' 'activate inactive' DisplayAsProjSynIndentExam 'upgrade the internal applications only' "reactivate $(ShowAsPackages)" - Help.BackupLocation:Show + ShowHelpBackupLocation } > "$REPORT_OUTPUT_PATHFILE" @@ -6444,7 +6587,7 @@ DisplayFileInViewport() } -Log.Last:Paste() +PasteLogLast() { local link='' @@ -6479,7 +6622,7 @@ Log.Last:Paste() } -Log.Tail:Paste() +PasteLogTail() { local link='' @@ -6611,22 +6754,6 @@ ExtractTailFromLog() } -ShowReportVersions() - { - - DisableDebugToArchiveAndFile - EraseThisLine - - Display "QPKG: ${THIS_PACKAGE_VER:-undefined}" - Display "manager: ${THIS_SCRIPT_VER:-undefined}" - Display "loader: ${LOADER_SCRIPT_VER:-undefined}" - Display "objects: ${OBJECTS_VER:-undefined}" - Display "packages: ${PACKAGES_EPOCH}$([[ $PACKAGES_EPOCH != undefined ]] && printf '%s' " ($(ConvertSecondsToFullDate "$PACKAGES_EPOCH"))")" - - return 0 - - } - InitForkCounts() { @@ -6747,7 +6874,7 @@ UpdateForkProgress() } >&2 -QPKGs.Missing:Show() +ShowQPKGsMissing() { # Check installed QPKGs and check if they're missing. If so, advise on-screen. @@ -6800,7 +6927,7 @@ QPKGs.Missing:Show() } -QPKGs.NewVers:Show() +ShowQPKGsNewVers() { # Check installed QPKGs and compare versions against upgradable array. If new versions are available, advise on-screen. @@ -6862,7 +6989,7 @@ CheckQPKGsConflicts() if [[ -n ${BASE_QPKG_CONFLICTS_WITH:-} ]]; then # shellcheck disable=2068 for a in "${BASE_QPKG_CONFLICTS_WITH[@]}"; do - if QpkgIsEnabled "$a"; then + if QpkgIsInstalledEnabled "$a"; then ShowAsError "the '$a' QPKG is enabled. $(ShowAsTitleName) is incompatible with this package. Please consider stopping this QPKG in your App Center" run_package_actions=false @@ -6883,7 +7010,7 @@ CheckQPKGsWarnings() if [[ -n ${BASE_QPKG_WARNINGS:-} ]]; then # shellcheck disable=2068 for a in "${BASE_QPKG_WARNINGS[@]}"; do - if QpkgIsEnabled "$a"; then + if QpkgIsInstalledEnabled "$a"; then ShowAsWarn "the '$a' QPKG is enabled. This may cause problems with $(ShowAsTitleName) applications. Please consider stopping this QPKG in your App Center" return 1 @@ -6895,7 +7022,7 @@ CheckQPKGsWarnings() } -QPKGs.Actions:List() +ListQPKGsActions() { [[ $useropt_debug = true ]] || return @@ -6934,7 +7061,32 @@ QPKGs.Actions:List() } -IPKs.Actions:List() +ListQPKGsActionsAll() #devdebug + { #devdebug + + # Only used when debugging. #devdebug + + FuncInit #devdebug + + local a='' #devdebug + local b='' #devdebug + DebugInfoMinSepr #devdebug + + for a in "${QPKG_ACTIONS[@]}"; do #devdebug + for b in to ok er sk so se sa; do #devdebug + if QPKGs-AC${a}-${b}.IsAny; then #devdebug + DebugQpkg info "AC${a}-${b}" "($(QPKGs-AC${a}-${b}:Count)) $(QPKGs-AC${a}-${b}:ListCSV) " #devdebug + fi #devdebug + done #devdebug + done #devdebug + + DebugInfoMinSepr #devdebug + + FuncExit #devdebug + + } #devdebug + +ListIPKsActions() { [[ $useropt_debug = true ]] || return @@ -6968,7 +7120,7 @@ IPKs.Actions:List() } -PIPs.Actions:List() +ListPIPsActions() { [[ $useropt_debug = true ]] || return @@ -6989,32 +7141,7 @@ PIPs.Actions:List() } -QPKGs.Actions:ListAll() #devdebug - { #devdebug - - # Only used when debugging. #devdebug - - FuncInit #devdebug - - local a='' #devdebug - local b='' #devdebug - DebugInfoMinSepr #devdebug - - for a in "${QPKG_ACTIONS[@]}"; do #devdebug - for b in to ok er sk so se sa; do #devdebug - if QPKGs-AC${a}-${b}.IsAny; then #devdebug - DebugQpkg info "AC${a}-${b}" "($(QPKGs-AC${a}-${b}:Count)) $(QPKGs-AC${a}-${b}:ListCSV) " #devdebug - fi #devdebug - done #devdebug - done #devdebug - - DebugInfoMinSepr #devdebug - - FuncExit #devdebug - - } #devdebug - -QPKGs.States:List() +ListQPKGsStates() { [[ $useropt_debug = true ]] || return @@ -7023,7 +7150,7 @@ QPKGs.States:List() local a='' - QPKGs.States:Build + BuildQPKGsStates DebugInfoMinSepr for a in "${QPKG_IS_STATES[@]}" "${QPKG_SERVICE_RESULTS[@]}"; do @@ -7059,7 +7186,7 @@ QPKGs.States:List() } -QPKGs.Tiers:Build() +BuildQPKGsTiers() { FuncInit @@ -7086,7 +7213,7 @@ QPKGs.Tiers:Build() [[ $previous = "$qpkg_name" ]] && continue || previous=$qpkg_name QpkgSetIndex - if QpkgIsDependent; then + if QpkgIsDatabaseDependent; then echo "$qpkg_name" >> "$DEPENDENT_QPKGS_LIST_PATHFILE" else echo "$qpkg_name" >> "$INDEPENDENT_QPKGS_LIST_PATHFILE" @@ -7103,7 +7230,7 @@ QPKGs.Tiers:Build() } -QPKGs.Tiers:Init() +InitQPKGsTiers() { rm -f "$DEPENDENT_QPKGS_LIST_PATHFILE" "$INDEPENDENT_QPKGS_LIST_PATHFILE" 2> /dev/null @@ -7111,7 +7238,7 @@ QPKGs.Tiers:Init() } -QPKGs.States:Build() +BuildQPKGsStates() { # Build several lists of QPKGs: @@ -7135,7 +7262,7 @@ QPKGs.States:Build() fi LoadPackages - QPKGs.States:Init + InitQPKGsStates OsIsStarting && ShowAsWarn "$(OsGetQnapOS) is starting all enabled QPKGs $CHARS_ELLIPSIS check again in a few minutes" OsIsStopping && ShowAsWarn "$(OsGetQnapOS) is shutting-down and all QPKGs are stopping" @@ -7172,7 +7299,7 @@ QPKGs.States:Build() for qpkg_name in $(QPKGs-GRall:Array); do QpkgSetIndex - if QpkgIsMissing; then + if QpkgIsInstalledMissing; then echo missing else echo notmissing @@ -7197,7 +7324,7 @@ QPKGs.States:Build() QpkgSetIndex if QpkgIsInstalled; then - if QpkgIsEnabled; then + if QpkgIsInstalledEnabled; then echo enabled else echo notenabled @@ -7212,7 +7339,7 @@ QPKGs.States:Build() if QpkgIsInstalled; then echo installed - else + elif QpkgIsNtReallyInstalled; then echo notinstalled fi >> "$QPKG_STATES_PATH/$qpkg_name" # done #& @@ -7317,14 +7444,14 @@ QPKGs.States:Build() done qpkgs_states_built=true - QPKGs.Missing:Show - QPKGs.NewVers:Show + ShowQPKGsMissing + ShowQPKGsNewVers FuncExit } -QPKGs.States:Init() +InitQPKGsStates() { # Clears in-memory state list objects @@ -7356,7 +7483,7 @@ QPKGs.States:Init() } -QPKGs.IsCanBackup:Build() +BuildQPKGsIsCanBackup() { # Build a list of QPKGs that support `backup` and `restore` actions. @@ -7366,14 +7493,14 @@ QPKGs.IsCanBackup:Build() local qpkg_name='' for qpkg_name in $(QPKGs-GRall:Array); do - QpkgIsCanBackup "$qpkg_name" && QPKGs-GRcanbackup:Add "$qpkg_name" + QpkgIsDatabaseCanBackup "$qpkg_name" && QPKGs-GRcanbackup:Add "$qpkg_name" done FuncExit } -QPKGs.IsCanRestartToUpdate:Build() +BuildQPKGsIsCanRestartToUpdate() { # Build a list of QPKGs that support application update on QPKG restart. @@ -7383,14 +7510,14 @@ QPKGs.IsCanRestartToUpdate:Build() local qpkg_name='' for qpkg_name in $(QPKGs-GRall:Array); do - QpkgIsCanRestartToUpdate "$qpkg_name" && QPKGs-GRcanrestarttoupdate:Add "$qpkg_name" + QpkgIsDatabaseCanRestartToUpdate "$qpkg_name" && QPKGs-GRcanrestarttoupdate:Add "$qpkg_name" done FuncExit } -QPKGs.IsCanClean:Build() +BuildQPKGsIsCanClean() { # Build a list of QPKGs that support `clean` actions. @@ -7400,7 +7527,7 @@ QPKGs.IsCanClean:Build() local qpkg_name='' for qpkg_name in $(QPKGs-GRall:Array); do - QpkgIsCanClean "$qpkg_name" && QPKGs-GRcanclean:Add "$qpkg_name" + QpkgIsDatabaseCanClean "$qpkg_name" && QPKGs-GRcanclean:Add "$qpkg_name" done FuncExit @@ -7414,7 +7541,7 @@ QPKGs.IsTimeoutsIncreased() } -Help.Abbreviations:Show() +HelpAbbreviations() { FuncInit @@ -7431,13 +7558,13 @@ Help.Abbreviations:Show() { - Help.Basic:Show + ShowHelpBasic DisplayAsHelpTitle "$(ShowAsTitleName) can recognise various abbreviations and aliases as $(ShowAsPackages)." printf '\n' } > "$REPORT_OUTPUT_PATHFILE" - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf -v a '%s\n' 'QPKG name:|Installed?|Acceptable QPKG name abbreviations and aliases:' else printf -v a '%s\n' "$(GenerateAbsReportTitleLine)" @@ -7460,7 +7587,7 @@ Help.Abbreviations:Show() done if [[ -n $a ]]; then - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf '%s' "$a" | Tableise else printf '%s' "$a" @@ -7479,7 +7606,7 @@ Help.Abbreviations:Show() ShowAsError 'no information to display' fi - QPKGs.States:List + ListQPKGsStates FuncExit @@ -7547,8 +7674,8 @@ ShowReportDependencies() DisplayProcReport dependency ResetReportsPath &> /dev/null - if [[ -e $GNU_AWK_CMD ]]; then - printf -v a '%s\n' 'QPKG name:|Dependencies:|Installed?|Enabled?|Managed?|Min. RAM:|Min. OS:|Max. OS:|Supported arch?' + if OsIsSupportAutowidthTableColumns; then + printf -v a '%s\n' 'QPKG name:|Dependencies:|Installed?|Enabled?|Managed?|Min. RAM:|Min. OS:|Max. OS:|Supported arch?|Installed QPKG author:' else printf -v a '%s\n' "$(GenerateDepsReportTitleLine)" fi @@ -7570,7 +7697,7 @@ ShowReportDependencies() done if [[ -n $a ]]; then - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf '%s' "$a" | Tableise else printf '%s' "$a" @@ -7588,7 +7715,7 @@ ShowReportDependencies() ShowAsError 'no information to display' fi - QPKGs.States:List + ListQPKGsStates FuncExit @@ -7607,7 +7734,7 @@ ShowReportFeatures() DisplayProcReport features ResetReportsPath &> /dev/null - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf -v a '%s\n' 'QPKG name:|CanBack?|CanClean?|StartUpd?|AutoUpd?|LiveTest?|Indep?|Compat?|Enhanced?' else printf -v a '%s\n' "$(GenerateFeaturesReportTitleLine)" @@ -7630,7 +7757,7 @@ ShowReportFeatures() done if [[ -n $a ]]; then - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf '%s' "$a" | Tableise else printf '%s' "$a" @@ -7648,7 +7775,7 @@ ShowReportFeatures() ShowAsError 'no information to display' fi - QPKGs.States:List + ListQPKGsStates FuncExit @@ -7668,13 +7795,13 @@ ShowReportPackages() { - Help.Basic:Show + ShowHelpBasic DisplayAsHelpTitle "one-or-more $(ShowAsPackages) may be specified at-once." printf '\n' } > "$REPORT_OUTPUT_PATHFILE" - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf -v a '%s\n' 'QPKG name:|Appl. version:|Description:' else printf -v a '%s\n' "$(GeneratePacksReportTitleLine)" @@ -7696,7 +7823,7 @@ ShowReportPackages() done if [[ -n $a ]]; then - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf '%s' "$a" | Tableise else printf '%s' "$a" @@ -7738,7 +7865,7 @@ ShowReportRepos() DisplayProcReport repository ResetReportsPath &> /dev/null - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf -v a '%s\n' 'QPKG name:|Repository:|Install date:' else printf -v a '%s\n' "$(GenerateReposReportTitleLine)" @@ -7761,7 +7888,7 @@ ShowReportRepos() done if [[ -n $a ]]; then - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf '%s' "$a" | Tableise else printf '%s' "$a" @@ -7779,7 +7906,7 @@ ShowReportRepos() ShowAsError 'no information to display' fi - QPKGs.States:List + ListQPKGsStates FuncExit @@ -7809,7 +7936,7 @@ ShowReportStatuses() GenerateStatusReportDataLine > "$REPORTS_PATH/$n" & done - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then [[ $a = true ]] && b=" ($(TextBrightOrange new))" printf -v c '%s\n' "QPKG name:|Status:|Previous action (result):|QPKG version${b}:|Appl. version:|Location:" else @@ -7828,7 +7955,7 @@ ShowReportStatuses() done if [[ -n $c ]]; then - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf '%s' "$c" | Tableise else printf '%s' "$c" @@ -7846,7 +7973,7 @@ ShowReportStatuses() ShowAsError 'no information to display' fi - QPKGs.States:List + ListQPKGsStates show_action_results_ok=false show_action_results_skipped=false @@ -7856,56 +7983,219 @@ ShowReportStatuses() } -GenerateReportFooter() +ShowReportVersions() { - DisplayAsHelpTitle 'report information:' + DisableDebugToArchiveAndFile + EraseThisLine - local a='' + Display "QPKG: ${THIS_PACKAGE_VER:-undefined}" + Display "manager: ${THIS_SCRIPT_VER:-undefined}" + Display "loader: ${LOADER_SCRIPT_VER:-undefined}" + Display "objects: ${OBJECTS_VER:-undefined}" + Display "packages: ${PACKAGES_EPOCH}$([[ $PACKAGES_EPOCH != undefined ]] && printf '%s' " ($(ConvertSecondsToFullDate "$PACKAGES_EPOCH"))")" - a=$({ - if [[ -e "$REPORT_FLAGS_PATH"/status-missing ]]; then - DisplayAsIndentQuotedInfoItem "$(TextBrightRed '! missing')" 'QPKG is missing from its installation path. Please reinstall it' - fi + return 0 - if [[ -e "$REPORT_FLAGS_PATH"/req-alert ]]; then - DisplayAsIndentQuotedInfoItem "$(TextBrightRed '!')" 'prevents QPKG working correctly' - fi + } - if [[ -e "$REPORT_FLAGS_PATH"/state-disabled ]]; then - DisplayAsIndentQuotedInfoItem "$(TextBrightRed disabled)" "QPKG won't start at bootup. Enable it first, then start it" - fi +ShowReportAllActionResults() + { - if [[ -e "$REPORT_FLAGS_PATH"/result-aborted ]]; then - DisplayAsIndentQuotedInfoItem "($(TextBrightRed aborted))" 'previous action was aborted' - fi + local -i a=0 + local -i b=0 + local -i c=0 + local -i d=0 + local -i e=0 + local action='' + local -i datetime=0 + local -i duration=0 + local package_name='' + local package_type='' + local -i quantity=0 + local reason='' + local result='' - if [[ -e "$REPORT_FLAGS_PATH"/result-failed ]]; then - DisplayAsIndentQuotedInfoItem "($(TextBrightRed failed))" 'previous action failed' - fi + if [[ $useropt_show_all_results = true ]]; then + show_action_results_failed=true + show_action_results_ok=true + show_action_results_skipped=true + fi - if [[ -e "$REPORT_FLAGS_PATH"/status-inactive ]]; then - DisplayAsIndentQuotedInfoItem "$(TextBrightRed inactive)" 'application process is dead or not-started. Try starting it' - fi + if [[ -e $SESS_ACTION_RESULTS_PATHFILE ]]; then + while IFS='|' read -r datetime action quantity package_name package_type result duration reason; do + if [[ $datetime -gt 0 && $duration -gt 0 ]]; then + [[ $a -eq 0 ]] && a=$datetime # Only use first entry as start time. + b=$datetime + c=$duration + ((d++)) + fi + done < "$SESS_ACTION_RESULTS_PATHFILE" - if [[ -e "$REPORT_FLAGS_PATH"/backup-file-old ]]; then - DisplayAsIndentQuotedInfoItem "$(TextBrightRed '!')" "QPKG backup file was updated more-than $highlight_backups_older_than." - fi + a=$(ConvertMillisecondsToSeconds "$a") + b=$(ConvertMillisecondsToSeconds "$b") + c=$(ConvertMillisecondsToSeconds "$c") - if [[ -e "$REPORT_FLAGS_PATH"/status-upgradable ]]; then - DisplayAsIndentQuotedInfoItem "($(TextBrightOrange new))" 'an upgraded QPKG version is available' - fi + [[ $b -gt 0 ]] && e=$((b+c+1)) # Use last non-zero iteration of $datetime as beginning of last action, then add duration to it. - if [[ -e "$REPORT_FLAGS_PATH"/req-attention ]]; then - DisplayAsIndentQuotedInfoItem "$(TextBrightOrange '*')" 'QPKG cannot be installed' - fi + if [[ $show_action_results_ok = true || $show_action_results_skipped = true || $show_action_results_failed = true || $show_action_results_zero = true ]]; then + { - if [[ -e "$REPORT_FLAGS_PATH"/action-pending ]]; then - DisplayAsIndentQuotedInfoItem "$(TextBrightOrange pending)" 'QPKG is waiting to run an action. Check again shortly' - fi + DisplayAsHelpTitle "package action$(Pluralise "$d") started @ $(ConvertSecondsToTime "$a"), ended @ $(ConvertSecondsToTime "$e"), elapsed = $(ConvertSecondsToDuration "$(CalcAmountDiff "$a" "$e")")" - if [[ -e "$REPORT_FLAGS_PATH"/status-stopping ]]; then - DisplayAsIndentQuotedInfoItem "$(TextBrightOrange stopping)" 'QPKG is stopping. Check again shortly' + [[ $show_action_results_ok = true ]] && ShowReportActionResults ok + [[ $show_action_results_skipped = true ]] && ShowReportActionResults skipped + [[ $show_action_results_failed = true ]] && ShowReportActionResults failed + [[ $show_action_results_zero = true ]] && ShowZeroQpkgs + + } > "$REPORT_OUTPUT_PATHFILE" + + if [[ -e $REPORT_OUTPUT_PATHFILE ]]; then + DisplayFileInViewport "$REPORT_OUTPUT_PATHFILE" + else + ShowAsError 'no information to display' + fi + fi + fi + + } + +ShowReportActionResults() + { + + # Inputs: + # $1 = `ok`, `skipped`, `failed` + + local action='' + local -i count=0 + local -i datetime=0 + local -i duration=0 + local package_name='' + local package_type='' + local -i quantity=0 + local reason='' + local result='' + + if [[ -e $SESS_ACTION_RESULTS_PATHFILE ]]; then + # Obtain count of same results. Need to know if action applied to one QPKG or many. + + while IFS='|' read -r datetime action quantity package_name package_type result duration reason; do + if [[ $result = "$1" ]] || [[ $1 = skipped && ($result = 'skipped-ok' || $result = 'skipped-error' || $result = 'skipped-abort') ]]; then + [[ $action = status && $useropt_show_all_results = false ]] && continue # Don't need to see the result of `status` checks unless a 'results' report has been requested. + ((count++)) + [[ $count -gt 1 ]] && break # Two-or-more of the same action means must pluralise messages. + fi + done < "$SESS_ACTION_RESULTS_PATHFILE" + + # Display action titles and QPKGs. + + if [[ $count -eq 1 ]]; then + case $1 in + ok) + DisplayAsHelpTitle "this package action completed $(TextBrightGreen OK):" + ;; + skipped) + DisplayAsHelpTitle "this package action was $(TextBrightOrange skipped) (and why):" + ;; + failed) + DisplayAsHelpTitle "this package action $(TextBrightRed failed) (and why):" + esac + elif [[ $count -gt 1 ]]; then + case $1 in + ok) + DisplayAsHelpTitle "these package actions completed $(TextBrightGreen OK):" + ;; + skipped) + DisplayAsHelpTitle "these package actions were $(TextBrightOrange skipped) (and why):" + ;; + failed) + DisplayAsHelpTitle "these package actions $(TextBrightRed failed) (and why):" + esac + fi + + if [[ $count -ge 1 ]]; then + while IFS='|' read -r datetime action quantity package_name package_type result duration reason; do + if [[ $result = "$1" ]] || [[ $1 = skipped && ($result = 'skipped-ok' || $result = 'skipped-error' || $result = 'skipped-abort') ]]; then + [[ $action = status && $useropt_show_all_results = false ]] && continue # Don't need to see the result of `status` checks unless a 'results' report has been requested. + ShowAsActionLogDetail "$datetime" "$package_name" "$action" "$result" "$duration" "$reason" "$package_type" "$quantity" + fi + done < "$SESS_ACTION_RESULTS_PATHFILE" + fi + fi + + if [[ $count -eq 0 ]]; then + case $1 in + ok) + DisplayAsHelpTitle "no package actions completed $(TextBrightGreen OK)." + ;; + skipped) + DisplayAsHelpTitle "no package actions were $(TextBrightOrange skipped)." + ;; + failed) + DisplayAsHelpTitle "no package actions $(TextBrightRed failed)." + esac + fi + + return 0 + + } + +GenerateReportFooter() + { + + [[ $useropt_report_footer = true ]] || return + + DisplayAsHelpTitle 'report information:' + + local a='' + + a=$({ + if [[ -e "$REPORT_FLAGS_PATH"/status-missing ]]; then + DisplayAsIndentQuotedInfoItem "$(TextBrightRed missing)" 'QPKG is missing from its installation path. Please reinstall it' + fi + + if [[ -e "$REPORT_FLAGS_PATH"/req-alert ]]; then + DisplayAsIndentQuotedInfoItem "$(TextBrightRed '!')" 'QPKG is prevented from working correctly' + fi + + if [[ -e "$REPORT_FLAGS_PATH"/state-disabled ]]; then + DisplayAsIndentQuotedInfoItem "$(TextBrightRed disabled)" "QPKG won't start at bootup. Enable it first, then start it" + fi + + if [[ -e "$REPORT_FLAGS_PATH"/result-aborted ]]; then + DisplayAsIndentQuotedInfoItem "($(TextBrightRed aborted))" 'previous action was aborted' + fi + + if [[ -e "$REPORT_FLAGS_PATH"/result-failed ]]; then + DisplayAsIndentQuotedInfoItem "($(TextBrightRed failed))" 'previous action failed' + fi + + if [[ -e "$REPORT_FLAGS_PATH"/status-inactive ]]; then + DisplayAsIndentQuotedInfoItem "$(TextBrightRed inactive)" 'application process is dead or not-started. Try starting it' + fi + + if [[ -e "$REPORT_FLAGS_PATH"/backup-file-old ]]; then + DisplayAsIndentQuotedInfoItem "$(TextBrightRed '!')" "QPKG backup file was updated more-than $highlight_backups_older_than." + fi + + if [[ -e "$REPORT_FLAGS_PATH"/status-upgradable ]]; then + DisplayAsIndentQuotedInfoItem "($(TextBrightOrange new))" 'an upgraded QPKG version is available' + fi + + if [[ -e "$REPORT_FLAGS_PATH"/status-wrongauthor ]]; then + DisplayAsIndentQuotedInfoItem "$(TextBrightOrange 'incompatible author')" "QPKG is a non-compatible, identically-named duplicate of a $(ShowAsTitleName) QPKG" + fi + + if [[ -e "$REPORT_FLAGS_PATH"/req-attention ]]; then + DisplayAsIndentQuotedInfoItem "$(TextBrightOrange '*')" "QPKG cannot be managed with $(ShowAsTitleName)" + fi + + if [[ -e "$REPORT_FLAGS_PATH"/action-pending ]]; then + DisplayAsIndentQuotedInfoItem "$(TextBrightOrange pending)" 'QPKG is waiting to run an action. Check again shortly' + fi + + if [[ -e "$REPORT_FLAGS_PATH"/status-stopping ]]; then + DisplayAsIndentQuotedInfoItem "$(TextBrightOrange stopping)" 'QPKG is stopping. Check again shortly' fi if [[ -e "$REPORT_FLAGS_PATH"/status-slow ]]; then @@ -7956,6 +8246,10 @@ GenerateReportFooter() DisplayAsIndentQuotedInfoItem final 'application version is the last available' fi + if [[ -e "$REPORT_FLAGS_PATH"/na ]]; then + DisplayAsIndentQuotedInfoItem N/A 'not applicable' + fi + if [[ -e "$REPORT_FLAGS_PATH"/action-not-found ]]; then DisplayAsIndentQuotedInfoItem "$(TextDarkGrey not-found)" 'action tracking files were not found' fi @@ -7963,14 +8257,10 @@ GenerateReportFooter() if [[ -e "$REPORT_FLAGS_PATH"/action-unsupported ]]; then DisplayAsIndentQuotedInfoItem "$(TextDarkGrey unsupported)" 'action tracking is unsupported by this QPKG' fi - - if [[ -e "$REPORT_FLAGS_PATH"/na ]]; then - DisplayAsIndentQuotedInfoItem "$(TextDarkGrey 'N/A')" 'not applicable' - fi }) if [[ -n $a ]]; then - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf '%s' "$a" | Tableise else printf '%s\n' "$a" @@ -7994,6 +8284,8 @@ GenerateReportFooter() GenerateReportHeadingsFooter() { + [[ $useropt_report_footer = true ]] || return + DisplayAsHelpTitle 'column headings:' local a='' @@ -8010,7 +8302,7 @@ GenerateReportHeadingsFooter() }) if [[ -n $a ]]; then - if [[ -e $GNU_AWK_CMD ]]; then + if OsIsSupportAutowidthTableColumns; then printf '%s' "$a" | Tableise else printf '%s\n' "$a" @@ -8019,7 +8311,7 @@ GenerateReportHeadingsFooter() } -QPKGs.ISbackedup:Show() +ShowQPKGsISbackedup() { DisableDebugToArchiveAndFile @@ -8037,7 +8329,7 @@ QPKGs.ISbackedup:Show() } -QPKGs.ISNTbackedup:Show() +ShowQPKGsISNTbackedup() { DisableDebugToArchiveAndFile @@ -8055,7 +8347,7 @@ QPKGs.ISNTbackedup:Show() } -QPKGs.ISenabled:Show() +ShowQPKGsISenabled() { DisableDebugToArchiveAndFile @@ -8073,7 +8365,7 @@ QPKGs.ISenabled:Show() } -QPKGs.ISNTenabled:Show() +ShowQPKGsISNTenabled() { DisableDebugToArchiveAndFile @@ -8091,7 +8383,7 @@ QPKGs.ISNTenabled:Show() } -QPKGs.ISinstalled:Show() +ShowQPKGsISinstalled() { DisableDebugToArchiveAndFile @@ -8109,7 +8401,7 @@ QPKGs.ISinstalled:Show() } -QPKGs.ISNTinstalled:Show() +ShowQPKGsISNTinstalled() { DisableDebugToArchiveAndFile @@ -8127,7 +8419,7 @@ QPKGs.ISNTinstalled:Show() } -#QPKGs.GRall:Show() +#ShowQPKGsGRall() # { # # DisableDebugToArchiveAndFile @@ -8145,7 +8437,7 @@ QPKGs.ISNTinstalled:Show() # # } -QPKGs.ISinstallable:Show() +ShowQPKGsISinstallable() { DisableDebugToArchiveAndFile @@ -8163,7 +8455,7 @@ QPKGs.ISinstallable:Show() } -QPKGs.ISNTinstallable:Show() +ShowQPKGsISNTinstallable() { DisableDebugToArchiveAndFile @@ -8181,7 +8473,7 @@ QPKGs.ISNTinstallable:Show() } -QPKGs.ISmissing:Show() +ShowQPKGsISmissing() { DisableDebugToArchiveAndFile @@ -8199,7 +8491,7 @@ QPKGs.ISmissing:Show() } -QPKGs.ISNTmissing:Show() +ShowQPKGsISNTmissing() { DisableDebugToArchiveAndFile @@ -8217,7 +8509,7 @@ QPKGs.ISNTmissing:Show() } -QPKGs.ISactive:Show() +ShowQPKGsISactive() { DisableDebugToArchiveAndFile @@ -8235,7 +8527,7 @@ QPKGs.ISactive:Show() } -QPKGs.ISNTactive:Show() +ShowQPKGsISNTactive() { DisableDebugToArchiveAndFile @@ -8253,7 +8545,7 @@ QPKGs.ISNTactive:Show() } -QPKGs.ISupgradable:Show() +ShowQPKGsISupgradable() { DisableDebugToArchiveAndFile @@ -8271,7 +8563,7 @@ QPKGs.ISupgradable:Show() } -QPKGs.ISNTupgradable:Show() +ShowQPKGsISNTupgradable() { DisableDebugToArchiveAndFile @@ -8289,7 +8581,7 @@ QPKGs.ISNTupgradable:Show() } -QPKGs.GRindependent:Show() +ShowQPKGsGRindependent() { DisableDebugToArchiveAndFile @@ -8307,7 +8599,7 @@ QPKGs.GRindependent:Show() } -QPKGs.GRdependent:Show() +ShowQPKGsGRdependent() { DisableDebugToArchiveAndFile @@ -8564,11 +8856,11 @@ OsGetKernelVersion() OsGetKernelPageSize() { - # Accuracy of this method is uncertain. - - $GREP_CMD KernelPageSize /proc/1/smaps | head -n1 | cut -f2 -d':' | tr -d ' ' - - # There's also: /sbin/hal_app --get_pagesize + if [[ -e /sbin/hal_app ]]; then + /sbin/hal_app --get_pagesize + else + $GREP_CMD KernelPageSize /proc/1/smaps | head -n1 | cut -f2 -d':' | tr -d ' ' + fi } @@ -8925,7 +9217,7 @@ OsIsSupportUnofficialPackages() # Must check for "official QPKGs" on QTS 4.3.3 to QTS 4.3.6: - [[ ${NAS_FIRMWARE_VER//.} -gt 426 && ${NAS_FIRMWARE_VER//.} -lt 440 ]] + [[ ${NAS_FIRMWARE_VER//.} -gt 426 && ${NAS_FIRMWARE_VER//.} -le 436 ]] } @@ -8954,6 +9246,13 @@ OsIsSupportDecimalSleepSeconds() } +OsIsSupportAutowidthTableColumns() + { + + [[ -e $GNU_AWK_CMD ]] + + } + OsIsAllowUnsignedPackages() { @@ -8985,10 +9284,10 @@ OsIsStopping() OsIsStdKernelPageSize() { - # Standard kernel page size for most QNAP NAS is 4kB. Non-standard size is 32kB (confirmed on the TS-431XeU, TS-431X3 & TS-1635). + # Standard kernel page size for most QNAP NAS is 4kiB. Non-standard size is 32kiB (confirmed on the TS-431XeU, TS-431X3 & TS-1635). # https://www.qnap.com/en-us/how-to/faq/article/why-do-the-installed-third-party-containers-not-run-successfully-on-specific-32-bit-arm-devices - [[ ${KERNEL_PAGE_SIZE:=$(OsGetKernelPageSize)} = 4kB ]] + [[ ${KERNEL_PAGE_SIZE:=$(OsGetKernelPageSize)} = 4096 || $KERNEL_PAGE_SIZE = 4kB ]] } @@ -9137,7 +9436,7 @@ SaveActionResultToLog() # Write package type, package name, datetime in seconds, action, result, reason to actions logfile, and into actions durations file. - # Inputs: Example: + # Inputs: (local) Example: # $1 = package type `QPKG`, `IPK`, `PIP` # $2 = package or group name `SABnzbd`, `essential` # $3 = action `download`, `activate` @@ -9207,10 +9506,13 @@ _QPKG:reassign_() # * This function runs asynchronously * # Remove the `storeid` assignment for the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $LOGS_PATH + # $qpkg_name + # $REASSIGN_LOG_FILE + # $useropt_verbose - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -9219,11 +9521,15 @@ _QPKG:reassign_() local -i z=0 - if ! QPKGs-ISinstalled.Exist "$qpkg_name"; then + if QPKGs-ISNTinstalled.Exist "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" reassign '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 - elif [[ $(QpkgGetStoreID) = sherpa || $(QpkgGetStoreID) = undefined ]]; then + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" reassign '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 + elif [[ $(QpkgGetInstalledStoreID) = sherpa || $(QpkgGetInstalledStoreID) = undefined ]]; then SaveActionResultToLog QPKG "$qpkg_name" reassign '' skipped 'already assigned to sherpa' MarkThisAcForkAsSkipped z=1 @@ -9254,18 +9560,23 @@ _QPKG:download_() # * This function runs asynchronously * # Download the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $DOWNLOAD_LOG_FILE + # $LOGS_PATH + # $QPKG_DL_PATH + # $qpkg_name + # $REMOTE_FILENAME + # $useropt_verbose - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null FuncForkInit - local -r REMOTE_HASH=$(QpkgGetHash) - local -r REMOTE_URL=$(QpkgGetURL) + local -r REMOTE_HASH=$(QpkgGetDatabaseHash) + local -r REMOTE_URL=$(QpkgGetDatabaseURL) local -r REMOTE_FILENAME=$($BASENAME_CMD "$REMOTE_URL") local -r LOCAL_PATHFILE=$QPKG_DL_PATH/$REMOTE_FILENAME local -r LOCAL_FILENAME=$($BASENAME_CMD "$LOCAL_PATHFILE") @@ -9326,10 +9637,15 @@ _QPKG:install_() # * This function runs asynchronously * # Install the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $INSTALL_LOG_FILE + # $LOGS_PATH + # $qpkg_name + # $QPKGs_were_installed_name[] + # $useropt_debug + # $useropt_verbose - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -9344,15 +9660,19 @@ _QPKG:install_() SaveActionResultToLog QPKG "$qpkg_name" install '' skipped 'already installed' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsArchOK "$qpkg_name"; then + elif QpkgIsReallyInstalled && QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" install '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 + elif ! QpkgIsDatabaseArchOK "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" install '' skipped 'NAS arch is incompatible' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsMinOSVerOk "$qpkg_name"; then + elif ! QpkgIsDatabaseMinOSVerOk "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" install '' skipped "$(OsGetQnapOS) version is incompatible" MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsMinRAMOk "$qpkg_name"; then + elif ! QpkgIsDatabaseMinRAMOk "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" install '' skipped 'NAS has insufficient RAM' MarkThisAcForkAsSkipped z=1 @@ -9360,7 +9680,7 @@ _QPKG:install_() [[ $z -eq 0 ]] || FuncForkExit $z - local local_pathfile=$(QpkgGetPathFilename) + local local_pathfile=$(QpkgGetDatabasePathFilename) if [[ -z $local_pathfile || ! -e $local_pathfile ]]; then SaveActionResultToLog QPKG "$qpkg_name" install '' skipped-error 'no local file found for processing: please report this issue' @@ -9382,20 +9702,20 @@ _QPKG:install_() fi DebugAsProc "installing $(ShowAsPackageName)" - [[ ${QPKGs_were_installed_name[*]:-} = *"$qpkg_name"* ]] && a+="QINSTALL_PATH=$(QpkgGetOriginalPath "$qpkg_name") " + [[ ${QPKGs_were_installed_name[*]:-} = *"$qpkg_name"* ]] && a+="QINSTALL_PATH=$(QpkgGetInstalledOriginalPath "$qpkg_name") " RunAndLog "${a}${SH_CMD} $local_pathfile" "$LOGS_PATH/$($BASENAME_CMD "$local_pathfile").$INSTALL_LOG_FILE" log:failure-only 10 z=$? LogQpkgServiceResult - QpkgIsCanLog && ! QpkgServiceResultWasOk && z=1 + QpkgIsDatabaseCanLog && ! QpkgInstalledServiceResultWasOk && z=1 [[ $qpkg_name = Entware ]] && IsNtSysFileExist $OPKG_CMD && z=1 # Entware installation has failed. if [[ $z -eq 0 || $z -eq 10 ]]; then # '0' or '10' from a QPKG install/reinstall/upgrade is OK, but also includes user-aborts. SendPackageStateChange ISinstalled - if QpkgIsEnabled "$qpkg_name"; then + if QpkgIsInstalledEnabled "$qpkg_name"; then SendPackageStateChange ISenabled else SendPackageStateChange ISNTenabled @@ -9426,7 +9746,7 @@ _QPKG:install_() z=1 # Remap to 1. fi - ClearQpkgAppCenterNotifier + ClearQpkgInstalledAppCenterNotifier FuncForkExit $z @@ -9438,10 +9758,10 @@ _QPKG:reinstall_() # * This function runs asynchronously * # Reinstall the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -9452,11 +9772,15 @@ _QPKG:reinstall_() [[ $useropt_debug = true ]] && a+='DEBUG_QPKG=true ' local -i z=0 - if ! QPKGs-ISinstalled.Exist "$qpkg_name"; then + if QPKGs-ISNTinstalled.Exist "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" reinstall '' skipped "not installed, please use 'install' instead." MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" reinstall '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" reinstall '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -9464,7 +9788,7 @@ _QPKG:reinstall_() [[ $z -eq 0 ]] || FuncForkExit $z - local local_pathfile=$(QpkgGetPathFilename) + local local_pathfile=$(QpkgGetDatabasePathFilename) if [[ -z $local_pathfile || ! -e $local_pathfile ]]; then SaveActionResultToLog QPKG "$qpkg_name" reinstall '' skipped-error 'no local file found for processing, please report this issue.' @@ -9475,18 +9799,18 @@ _QPKG:reinstall_() [[ $z -eq 0 ]] || FuncForkExit $z DebugAsProc "reinstalling $(ShowAsPackageName)" - QpkgIsInstalled && a+="QINSTALL_PATH=$($DIRNAME_CMD "$(QpkgGetInstallationPath)") " + QpkgIsInstalled && a+="QINSTALL_PATH=$($DIRNAME_CMD "$(QpkgGetInstalledPath)") " RunAndLog "${a}${SH_CMD} $local_pathfile" "$LOGS_PATH/$($BASENAME_CMD "$local_pathfile").$REINSTALL_LOG_FILE" log:failure-only 10 z=$? LogQpkgServiceResult - QpkgIsCanLog && ! QpkgServiceResultWasOk && z=1 + QpkgIsDatabaseCanLog && ! QpkgInstalledServiceResultWasOk && z=1 [[ $qpkg_name = Entware ]] && IsNtSysFileExist $OPKG_CMD && z=1 if [[ $z -eq 0 || $z -eq 10 ]]; then # '0' or '10' from a QPKG install/reinstall/upgrade is OK, but also includes aborts. - if QpkgIsEnabled "$qpkg_name"; then + if QpkgIsInstalledEnabled "$qpkg_name"; then SendPackageStateChange ISenabled else SendPackageStateChange ISNTenabled @@ -9501,7 +9825,7 @@ _QPKG:reinstall_() z=1 # Remap to 1. fi - ClearQpkgAppCenterNotifier + ClearQpkgInstalledAppCenterNotifier FuncForkExit $z @@ -9513,10 +9837,10 @@ _QPKG:rebuild_() # * This function runs asynchronously * # Meta-action: rebuild the QPKG named in $qpkg_name. This is a `download`, `install` and `restore`, but only if a backup file exists for this QPKG. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -9525,10 +9849,14 @@ _QPKG:rebuild_() local -i z=0 - if ! QpkgIsCanBackup; then + if ! QpkgIsDatabaseCanBackup; then SaveActionResultToLog QPKG "$qpkg_name" meta-rebuild '' skipped 'does not support rebuild' MarkThisAcForkAsSkipped z=1 + elif QpkgIsReallyInstalled && QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" meta-rebuild '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 elif QPKGs-ISinstalled.Exist "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" meta-rebuild '' skipped "already installed, please use 'restore' instead" MarkThisAcForkAsSkipped @@ -9537,7 +9865,7 @@ _QPKG:rebuild_() SaveActionResultToLog QPKG "$qpkg_name" meta-rebuild '' skipped 'backup file does not exist' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" meta-rebuild '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -9550,7 +9878,7 @@ _QPKG:rebuild_() SaveActionResultToLog QPKG "$qpkg_name" meta-rebuild '' ok MarkThisAcForkAsOk - ClearQpkgAppCenterNotifier + ClearQpkgInstalledAppCenterNotifier FuncForkExit $z @@ -9562,10 +9890,10 @@ _QPKG:upgrade_() # * This function runs asynchronously * # Upgrade the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -9576,15 +9904,19 @@ _QPKG:upgrade_() [[ $useropt_debug = true ]] && a+='DEBUG_QPKG=true ' local -i z=0 - if ! QPKGs-ISinstalled.Exist "$qpkg_name"; then + if QPKGs-ISNTinstalled.Exist "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" upgrade '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" upgrade '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 elif ! QPKGs-ISupgradable.Exist "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" upgrade '' skipped 'no new QPKG is available' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" upgrade '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -9592,7 +9924,7 @@ _QPKG:upgrade_() [[ $z -eq 0 ]] || FuncForkExit $z - local local_pathfile=$(QpkgGetPathFilename) + local local_pathfile=$(QpkgGetDatabasePathFilename) if [[ -z $local_pathfile || ! -e $local_pathfile ]]; then SaveActionResultToLog QPKG "$qpkg_name" upgrade '' skipped-error 'no local file found for processing, please report this issue' @@ -9605,20 +9937,20 @@ _QPKG:upgrade_() local prev_ver=$(QpkgGetInstalledVer) DebugAsProc "upgrading $(ShowAsPackageName)" - QpkgIsInstalled && a+="QINSTALL_PATH=$($DIRNAME_CMD "$(QpkgGetInstallationPath "$qpkg_name")") " + QpkgIsInstalled && a+="QINSTALL_PATH=$($DIRNAME_CMD "$(QpkgGetInstalledPath "$qpkg_name")") " RunAndLog "${a}${SH_CMD} $local_pathfile" "$LOGS_PATH/$($BASENAME_CMD "$local_pathfile").$UPGRADE_LOG_FILE" log:failure-only 10 z=$? LogQpkgServiceResult - QpkgIsCanLog && ! QpkgServiceResultWasOk && z=1 + QpkgIsDatabaseCanLog && ! QpkgInstalledServiceResultWasOk && z=1 [[ $qpkg_name = Entware ]] && IsNtSysFileExist $OPKG_CMD && z=1 if [[ $z -eq 0 || $z -eq 10 ]]; then # '0' or '10' from a QPKG install/reinstall/upgrade is OK, but also includes aborts. SendPackageStateChange ISNTupgradable - if QpkgIsEnabled "$qpkg_name"; then + if QpkgIsInstalledEnabled "$qpkg_name"; then SendPackageStateChange ISenabled else SendPackageStateChange ISNTenabled @@ -9640,7 +9972,7 @@ _QPKG:upgrade_() z=1 # Remap to 1. fi - ClearQpkgAppCenterNotifier + ClearQpkgInstalledAppCenterNotifier FuncForkExit $z @@ -9652,10 +9984,10 @@ _QPKG:uninstall_() # * This function runs asynchronously * # Uninstall the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -9670,11 +10002,15 @@ _QPKG:uninstall_() SaveActionResultToLog QPKG "$qpkg_name" uninstall '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" uninstall '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 elif [[ $qpkg_name = sherpa ]]; then SaveActionResultToLog QPKG "$qpkg_name" uninstall '' skipped "it's needed here! 😉" MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" uninstall '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -9682,7 +10018,7 @@ _QPKG:uninstall_() [[ $z -eq 0 ]] || FuncForkExit $z - local -r QPKG_UNINSTALLER_PATHFILE=$(QpkgGetInstallationPath)/.uninstall.sh + local -r QPKG_UNINSTALLER_PATHFILE=$(QpkgGetInstalledPath)/.uninstall.sh [[ $qpkg_name = Entware ]] && SaveIpkAndPipList @@ -9730,10 +10066,10 @@ _QPKG:activate_() # * This function runs asynchronously * # Activate/start the service-script for the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -9748,11 +10084,15 @@ _QPKG:activate_() SaveActionResultToLog QPKG "$qpkg_name" activate '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" activate '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 elif QPKGs-ISNTenabled.Exist "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" activate '' skipped "not enabled, please 'enable' it first" MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" activate '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -9763,7 +10103,7 @@ _QPKG:activate_() local -r LOG_PATHFILE=$LOGS_PATH/$qpkg_name.$ACTIVATE_LOG_FILE local timeout='' OsIsSupportQpkgTimeout && timeout=" -t $QPKG_START_TIMEOUT_SECONDS" - local service_pathfile=$(QpkgGetServicePathFile) + local service_pathfile=$(QpkgGetInstalledServicePathFile) DebugAsProc "activating $(ShowAsPackageName)" @@ -9775,9 +10115,9 @@ _QPKG:activate_() elif [[ $useropt_debug = true ]]; then RunAndLog "${a}${service_pathfile} start" "$LOG_PATHFILE" log:failure-only z=$? - elif QpkgIsCanLog; then # Use `qpkg_service` if-possible, so package icon in App Center will dynamically update. + elif QpkgIsDatabaseCanLog; then # Use `qpkg_service` if-possible, so package icon in App Center will dynamically update. RunAndLog "/sbin/qpkg_service${timeout} start $qpkg_name" "$LOG_PATHFILE" log:failure-only - QpkgServiceResultWasOk && z=0 || z=1 + QpkgInstalledServiceResultWasOk && z=0 || z=1 else RunAndLog "$service_pathfile start" "$LOG_PATHFILE" log:failure-only z=$? @@ -9802,7 +10142,7 @@ _QPKG:activate_() z=1 # Remap to 1. fi - ClearQpkgAppCenterNotifier + ClearQpkgInstalledAppCenterNotifier FuncForkExit $z @@ -9814,10 +10154,10 @@ _QPKG:reactivate_() # * This function runs asynchronously * # Reactivate/restart the service-script for the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -9832,11 +10172,15 @@ _QPKG:reactivate_() SaveActionResultToLog QPKG "$qpkg_name" reactivate '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" reactivate '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 elif QPKGs-ISNTenabled.Exist "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" reactivate '' skipped "not enabled, please 'enable' it first" MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" reactivate '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -9847,7 +10191,7 @@ _QPKG:reactivate_() local -r LOG_PATHFILE=$LOGS_PATH/$qpkg_name.$REACTIVATE_LOG_FILE local timeout='' OsIsSupportQpkgTimeout && timeout=" -t $QPKG_RESTART_TIMEOUT_SECONDS" - local service_pathfile=$(QpkgGetServicePathFile) + local service_pathfile=$(QpkgGetInstalledServicePathFile) DebugAsProc "reactivating $(ShowAsPackageName)" @@ -9859,9 +10203,9 @@ _QPKG:reactivate_() elif [[ $useropt_debug = true ]]; then RunAndLog "${a}${service_pathfile} restart" "$LOG_PATHFILE" log:failure-only z=$? - elif QpkgIsCanLog; then # Use `qpkg_service` if-possible, so package icon in App Center will dynamically update. + elif QpkgIsDatabaseCanLog; then # Use `qpkg_service` if-possible, so package icon in App Center will dynamically update. RunAndLog "/sbin/qpkg_service${timeout} restart $qpkg_name" "$LOG_PATHFILE" log:failure-only - QpkgServiceResultWasOk && z=0 || z=1 + QpkgInstalledServiceResultWasOk && z=0 || z=1 else RunAndLog "$service_pathfile restart" "$LOG_PATHFILE" log:failure-only z=$? @@ -9877,7 +10221,7 @@ _QPKG:reactivate_() z=1 # Remap to 1. fi - ClearQpkgAppCenterNotifier + ClearQpkgInstalledAppCenterNotifier FuncForkExit $z @@ -9889,10 +10233,10 @@ _QPKG:deactivate_() # * This function runs asynchronously * # Deactivate/stop the service-script for the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -9907,11 +10251,15 @@ _QPKG:deactivate_() SaveActionResultToLog QPKG "$qpkg_name" deactivate '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" deactivate '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 # elif [[ $qpkg_name = sherpa ]]; then # SaveActionResultToLog QPKG "$qpkg_name" deactivate '' skipped "it's needed here! 😉" # MarkThisAcForkAsSkipped # z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" deactivate '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -9922,7 +10270,7 @@ _QPKG:deactivate_() local -r LOG_PATHFILE=$LOGS_PATH/$qpkg_name.$DEACTIVATE_LOG_FILE local timeout='' OsIsSupportQpkgTimeout && timeout=" -t $QPKG_STOP_TIMEOUT_SECONDS" - local service_pathfile=$(QpkgGetServicePathFile) + local service_pathfile=$(QpkgGetInstalledServicePathFile) DebugAsProc "deactivating $(ShowAsPackageName)" @@ -9934,9 +10282,9 @@ _QPKG:deactivate_() elif [[ $useropt_debug = true ]]; then RunAndLog "${a}${service_pathfile} stop" "$LOG_PATHFILE" log:failure-only z=$? - elif QpkgIsCanLog; then # Use `qpkg_service` if-possible, so package icon in App Center will dynamically update. + elif QpkgIsDatabaseCanLog; then # Use `qpkg_service` if-possible, so package icon in App Center will dynamically update. RunAndLog "/sbin/qpkg_service${timeout} stop $qpkg_name" "$LOG_PATHFILE" log:failure-only - QpkgServiceResultWasOk && z=0 || z=1 + QpkgInstalledServiceResultWasOk && z=0 || z=1 else RunAndLog "$service_pathfile stop" "$LOG_PATHFILE" log:failure-only z=$? @@ -9960,7 +10308,7 @@ _QPKG:deactivate_() z=1 # Remap to 1. fi - ClearQpkgAppCenterNotifier + ClearQpkgInstalledAppCenterNotifier FuncForkExit $z @@ -9972,10 +10320,10 @@ _QPKG:enable_() # * This function runs asynchronously * # Enable the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -9988,11 +10336,15 @@ _QPKG:enable_() SaveActionResultToLog QPKG "$qpkg_name" enable '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" enable '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 elif QPKGs-ISenabled.Exist "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" enable '' skipped 'already enabled' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" enable '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -10007,8 +10359,8 @@ _QPKG:enable_() DebugAsProc "enabling $(ShowAsPackageName)" RunAndLog "/sbin/qpkg_service${timeout} enable $qpkg_name" "$LOG_PATHFILE" log:failure-only - QpkgIsEnabled "$qpkg_name" && SendPackageStateChange ISenabled - ClearQpkgAppCenterNotifier + QpkgIsInstalledEnabled "$qpkg_name" && SendPackageStateChange ISenabled + ClearQpkgInstalledAppCenterNotifier SaveActionResultToLog QPKG "$qpkg_name" enable '' ok MarkThisAcForkAsOk @@ -10022,10 +10374,10 @@ _QPKG:disable_() # * This function runs asynchronously * # Disable the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -10038,6 +10390,10 @@ _QPKG:disable_() SaveActionResultToLog QPKG "$qpkg_name" disable '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" disable '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 elif QPKGs-ISNTenabled.Exist "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" disable '' skipped 'already disabled' MarkThisAcForkAsSkipped @@ -10046,7 +10402,7 @@ _QPKG:disable_() # SaveActionResultToLog QPKG "$qpkg_name" disable '' skipped "it's needed here! 😉" # MarkThisAcForkAsSkipped # z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" disable '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -10061,9 +10417,9 @@ _QPKG:disable_() DebugAsProc "disabling $(ShowAsPackageName)" RunAndLog "/sbin/qpkg_service${timeout} disable $qpkg_name" "$LOG_PATHFILE" log:failure-only - ! QpkgIsEnabled "$qpkg_name" && SendPackageStateChange ISNTenabled + ! QpkgIsInstalledEnabled "$qpkg_name" && SendPackageStateChange ISNTenabled - ClearQpkgAppCenterNotifier + ClearQpkgInstalledAppCenterNotifier SaveActionResultToLog QPKG "$qpkg_name" disable '' ok MarkThisAcForkAsOk @@ -10077,10 +10433,10 @@ _QPKG:enableau_() # * This function runs asynchronously * # Enable auto-updating of the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -10095,15 +10451,19 @@ _QPKG:enableau_() SaveActionResultToLog QPKG "$qpkg_name" enableau '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" enableau '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 elif [[ $qpkg_name = sherpa ]]; then SaveActionResultToLog QPKG "$qpkg_name" enableau '' skipped 'auto-update is always enabled' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsCanRestartToUpdate "$qpkg_name"; then + elif ! QpkgIsDatabaseCanRestartToUpdate "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" enableau '' skipped 'auto-update is unsupported' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" enableau '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -10113,7 +10473,7 @@ _QPKG:enableau_() DebugAsProc "enabling auto-update $(ShowAsPackageName)" - RunAndLog "${a}$(QpkgGetServicePathFile) enable-auto-update" "$LOGS_PATH/$qpkg_name.$ENABLEAU_LOG_FILE" log:failure-only + RunAndLog "${a}$(QpkgGetInstalledServicePathFile) enable-auto-update" "$LOGS_PATH/$qpkg_name.$ENABLEAU_LOG_FILE" log:failure-only z=$? if [[ $z -eq 0 ]]; then @@ -10136,10 +10496,10 @@ _QPKG:disableau_() # * This function runs asynchronously * # Disable auto-updating of the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -10154,15 +10514,19 @@ _QPKG:disableau_() SaveActionResultToLog QPKG "$qpkg_name" disableau '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" disableau '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 elif [[ $qpkg_name = sherpa ]]; then SaveActionResultToLog QPKG "$qpkg_name" disableau '' skipped 'auto-update cannot be disabled' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsCanRestartToUpdate "$qpkg_name"; then + elif ! QpkgIsDatabaseCanRestartToUpdate "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" disableau '' skipped 'auto-update is unsupported' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" disableau '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -10172,7 +10536,7 @@ _QPKG:disableau_() DebugAsProc "disabling auto-update $(ShowAsPackageName)" - RunAndLog "${a}$(QpkgGetServicePathFile) disable-auto-update" "$LOGS_PATH/$qpkg_name.$DISABLEAU_LOG_FILE" log:failure-only + RunAndLog "${a}$(QpkgGetInstalledServicePathFile) disable-auto-update" "$LOGS_PATH/$qpkg_name.$DISABLEAU_LOG_FILE" log:failure-only z=$? if [[ $z -eq 0 ]]; then @@ -10195,10 +10559,10 @@ _QPKG:backup_() # * This function runs asynchronously * # Run a `backup` action for the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -10213,11 +10577,15 @@ _QPKG:backup_() SaveActionResultToLog QPKG "$qpkg_name" backup '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsCanBackup; then + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" backup '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 + elif ! QpkgIsDatabaseCanBackup; then SaveActionResultToLog QPKG "$qpkg_name" backup '' skipped 'backup is unsupported' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" backup '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -10227,7 +10595,7 @@ _QPKG:backup_() DebugAsProc "backing-up $(ShowAsPackageName) configuration" - RunAndLog "${a}$(QpkgGetServicePathFile) backup" "$LOGS_PATH/$qpkg_name.$BACKUP_LOG_FILE" log:failure-only + RunAndLog "${a}$(QpkgGetInstalledServicePathFile) backup" "$LOGS_PATH/$qpkg_name.$BACKUP_LOG_FILE" log:failure-only z=$? if [[ $z -eq 0 ]]; then @@ -10251,10 +10619,10 @@ _QPKG:restore_() # * This function runs asynchronously * # Run a `restore` action for the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -10269,7 +10637,11 @@ _QPKG:restore_() SaveActionResultToLog QPKG "$qpkg_name" restore '' skipped "not installed, try 'rebuild' instead" MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsCanBackup; then + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" restore '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 + elif ! QpkgIsDatabaseCanBackup; then SaveActionResultToLog QPKG "$qpkg_name" restore '' skipped 'restore is unsupported' MarkThisAcForkAsSkipped z=1 @@ -10277,7 +10649,7 @@ _QPKG:restore_() SaveActionResultToLog QPKG "$qpkg_name" restore '' skipped 'backup file does not exist' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" restore '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -10287,7 +10659,7 @@ _QPKG:restore_() DebugAsProc "restoring $(ShowAsPackageName) configuration" - RunAndLog "${a}$(QpkgGetServicePathFile) restore" "$LOGS_PATH/$qpkg_name.$RESTORE_LOG_FILE" log:failure-only + RunAndLog "${a}$(QpkgGetInstalledServicePathFile) restore" "$LOGS_PATH/$qpkg_name.$RESTORE_LOG_FILE" log:failure-only z=$? if [[ $z -eq 0 ]]; then @@ -10311,10 +10683,10 @@ _QPKG:clean_() # * This function runs asynchronously * # Run a `clean` action for the QPKG named in $qpkg_name. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -10329,11 +10701,15 @@ _QPKG:clean_() SaveActionResultToLog QPKG "$qpkg_name" clean '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsCanClean; then + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" clean '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 + elif ! QpkgIsDatabaseCanClean; then SaveActionResultToLog QPKG "$qpkg_name" clean '' skipped 'clean is unsupported' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" clean '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -10343,7 +10719,7 @@ _QPKG:clean_() DebugAsProc "cleaning $(ShowAsPackageName)" - RunAndLog "${a}$(QpkgGetServicePathFile) clean" "$LOGS_PATH/$qpkg_name.$CLEAN_LOG_FILE" log:failure-only + RunAndLog "${a}$(QpkgGetInstalledServicePathFile) clean" "$LOGS_PATH/$qpkg_name.$CLEAN_LOG_FILE" log:failure-only z=$? if [[ $z -eq 0 ]]; then @@ -10370,10 +10746,10 @@ _QPKG:sign_() # Should only be required for QTS 4.3.5-and-later firmwares. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name - # Outputs: + # Outputs: (local) # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. [[ $useropt_verbose != true ]] && exec &> /dev/null @@ -10394,15 +10770,19 @@ _QPKG:sign_() DebugVar sqlite_cmd - if ! QPKGs-ISinstalled.Exist "$qpkg_name"; then + if QPKGs-ISNTinstalled.Exist "$qpkg_name"; then SaveActionResultToLog QPKG "$qpkg_name" '"sign"' '' skipped 'not installed' MarkThisAcForkAsSkipped z=1 + elif QpkgIsNtInstalledAuthorOk; then + SaveActionResultToLog QPKG "$qpkg_name" '"sign"' '' skipped 'incompatible author' + MarkThisAcForkAsSkipped + z=1 elif ! OsIsSupportSignedPackages; then SaveActionResultToLog QPKG "$qpkg_name" '"sign"' '' skipped 'not required: firmware < 4.3.5' MarkThisAcForkAsSkipped z=1 - elif ! QpkgIsRepoSelfManaged; then + elif QpkgIsNtInstalledRepoSelfManaged; then SaveActionResultToLog QPKG "$qpkg_name" '"sign"' '' skipped "assigned to another repository, please 'reassign' it first" MarkThisAcForkAsSkipped z=1 @@ -10477,8 +10857,8 @@ _QPKG:status_() # * This function runs asynchronously * # Query a QPKG for its 'status'. Each compatible QPKG will return 0 if application process is active or ready-to-run, 0 if not. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name # Outputs: # $? = none, this function executes asynchronously. But an exitcode is recorded in the debug log. @@ -10502,16 +10882,16 @@ _QPKG:status_() DebugAsProc "status $(ShowAsPackageName)" - a=$(QpkgGetActiveTest) + a=$(QpkgGetDatabaseActiveTest) if [[ $a = builtin ]]; then # Run status query with GNU `timeout` if-possible. if [[ -e $GNU_TIMEOUT_CMD ]]; then - $GNU_TIMEOUT_CMD "$QPKG_STATUS_CHECK_TIMEOUT_SECONDS" /bin/bash -c "${b}$(QpkgGetServicePathFile) status" + $GNU_TIMEOUT_CMD "$QPKG_STATUS_CHECK_TIMEOUT_SECONDS" /bin/bash -c "${b}$(QpkgGetInstalledServicePathFile) status" z=$? else - RunAndLog "${b}$(QpkgGetServicePathFile) status" "$LOGS_PATH/$qpkg_name.$STATUS_LOG_FILE" log:failure-only + RunAndLog "${b}$(QpkgGetInstalledServicePathFile) status" "$LOGS_PATH/$qpkg_name.$STATUS_LOG_FILE" log:failure-only z=$? fi elif [[ $a != none ]]; then @@ -10543,45 +10923,33 @@ _QPKG:status_() } -ClearQpkgAppCenterNotifier() +ClearQpkgInstalledAppCenterNotifier() { - # Inputs: - # $qpkg_name (global) = QPKG name to clear from notifier list. + # Clear QPKG name from notifier list. + + # Inputs: (global) + # $qpkg_name - # KLUDGE: `clean` QTS 4.5.1+ App Center notifier status + # KLUDGE: `clean` QTS 4.5.1+ App Center notifier status. [[ -e /sbin/qpkg_cli ]] && /sbin/qpkg_cli --cancel "$qpkg_name" QpkgIsNtInstalled && return - # Need to do this when installing QPKGs at the CLI. + # Must also do this when installing QPKGs at the CLI. /sbin/setcfg "$qpkg_name" Status complete -f /etc/config/qpkg.conf return 0 } &> /dev/null -QpkgServiceResultWasOk() - { - - # Returns true if previous action for this package is `ok`. - - # Inputs: - # $qpkg_name (global) = QPKG name - - [[ -n $qpkg_name ]] || return - - [[ $(QpkgGetServiceResult) = ok ]] - - } - LogQpkgServiceResult() { # Inputs: (global) # $qpkg_name - if ! local a=$(QpkgGetServiceResult); then + if ! local a=$(QpkgGetInstalledServiceResult); then DebugAsWarn "unable to get status of $(ShowAsPackageName) service. It may be a non-sherpa package, or a sherpa package earlier than 200816c that doesn't support service results." return 1 @@ -10610,14 +10978,14 @@ LogQpkgServiceResult() } -QpkgGetInstallationPath() +QpkgGetInstalledPath() { - # Inputs: (global) - # $qpkg_name + # Inputs: (local) + # $1 (optional) = QPKG name. - # Input (local): - # $1 (optional) = source QPKG name. + # Inputs: (global) + # $qpkg_name (default) # Outputs: # stdout = package installation date. @@ -10627,16 +10995,16 @@ QpkgGetInstallationPath() } -QpkgGetServicePathFile() +QpkgGetInstalledServicePathFile() { - # Inputs: (global) - # $qpkg_name + # Inputs: (local) + # $1 (optional) = QPKG name. - # Input (local): - # $1 (optional) = source QPKG name. + # Inputs: (global) + # $qpkg_name (default) - # Outputs: + # Outputs: (local) # stdout = service-script pathfile # $? = 0 if found, 250 if not. @@ -10644,7 +11012,7 @@ QpkgGetServicePathFile() } -QpkgGetApplVer() +QpkgGetDatabaseApplVer() { # Returns the version number of the application contained within a QPKG. @@ -10657,7 +11025,7 @@ QpkgGetApplVer() # $QPKG_NAME # $QPKG_VERSION - # Outputs: + # Outputs: (local) # stdout = application version # $? = 0 if found, !0 if not @@ -10681,7 +11049,7 @@ QpkgGetApplVer() fi [[ -n $a ]] || return - [[ $a = dynamic ]] && QpkgIsInstalled && ! QpkgIsAutoUpdate && a=static + [[ $a = dynamic ]] && QpkgIsInstalled && ! QpkgIsInstalledAutoUpdate && a=static printf '%s' "$a" @@ -10689,7 +11057,7 @@ QpkgGetApplVer() } -QpkgGetAvailVer() +QpkgGetDatabaseVer() { # Returns the version number of an available (not-installed) QPKG. @@ -10699,7 +11067,7 @@ QpkgGetAvailVer() # $qpkg_index # $qpkg_name - # Outputs: + # Outputs: (local) # stdout = package version # $? = 0 if found, !0 if not @@ -10733,9 +11101,11 @@ QpkgGetInstalledVer() # Returns the version number of an installed QPKG. - # Inputs: + # Inputs: (local) # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. + + # Inputs: (global) + # $qpkg_name (default) # Outputs: # stdout = package version @@ -10745,16 +11115,18 @@ QpkgGetInstalledVer() } -QpkgGetStoreID() +QpkgGetInstalledStoreID() { # Returns the presently assigned repository store ID of an installed QPKG. - # Inputs: - # $qpkg_name (global) = QPKG name (default). - # $1 = if specified, use this as QPKG name instead. + # Inputs: (local) + # $1 (optional) = QPKG name. - # Outputs: + # Inputs: (global) + # $qpkg_name (default) + + # Outputs: (local) # stdout = package store ID # $? = 0 if found, 250 if not. @@ -10762,16 +11134,18 @@ QpkgGetStoreID() } -QpkgGetInstallDate() +QpkgGetInstalledDate() { # Returns the date specified QPKG was installed. - # Inputs: - # $qpkg_name (global) = QPKG name (default). - # $1 = if specified, use this as QPKG name instead. + # Inputs: (local) + # $1 (optional) = QPKG name. - # Outputs: + # Inputs: (global) + # $qpkg_name (default) + + # Outputs: (local) # stdout = package installation date # $? = 0 if found, 1 if QPKG name unspecified, 250 if not found @@ -10779,21 +11153,25 @@ QpkgGetInstallDate() } -QpkgGetOriginalPath() +QpkgGetInstalledOriginalPath() { - # Inputs: - # $1 = QPKG name + # Inputs: (local) + # $1 (optional) = QPKG name. - # Outputs: + # Inputs: (global) + # $qpkg_name (default) + + # Outputs: (local) # stdout = the original installation path of this QPKG (even if it was migrated to another volume). # $? = 0 if successful, 1 if failed + local a=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} local -i i=0 if [[ ${#QPKGs_were_installed_name[@]} -gt 0 ]]; then for i in "${!QPKGs_were_installed_name[@]}"; do - [[ ${QPKGs_were_installed_name[$i]} = "${1:?${FUNCNAME[0]}'()': undefined package name}" ]] || continue + [[ ${QPKGs_were_installed_name[$i]} = "$a" ]] || continue printf '%s' "${QPKGs_were_installed_path[$i]}" return 0 @@ -10804,24 +11182,19 @@ QpkgGetOriginalPath() } -QpkgGetPathFilename() +QpkgGetDatabasePathFilename() { - # Inputs: - # $qpkg_default_index (global, optional) - # $qpkg_index (global, optional) - # $qpkg_name (global) - - # Outputs: - # stdout = QPKG local filename. - # $? = 0 (found), !0 (not-found) + # Outputs: (local) + # stdout = pathfilename. + # $? = 0 if found, !0 if not local a='' - a=$(QpkgGetURL) + a=$(QpkgGetDatabaseURL) [[ -n $a ]] || return - [[ $(Lowercase "${a##*.}") != qpkg ]] && a=${a%.*}.qpkg # Swap `zip` for `qpkg` here (only for compatibilty with `QDK.zip`). + [[ $(Lowercase "${a##*.}") != qpkg ]] && a=${a%.*}.qpkg # Swap 'zip' for 'qpkg' here (only for compatibilty with 'QDK.zip'). printf '%s' "$QPKG_DL_PATH/$($BASENAME_CMD "$a")" @@ -10829,15 +11202,15 @@ QpkgGetPathFilename() } -QpkgGetHash() +QpkgGetDatabaseHash() { - # Inputs: - # $qpkg_default_index (global) - # $qpkg_index (global) - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_default_index + # $qpkg_index + # $qpkg_name - # Outputs: + # Outputs: (local) # stdout = QPKG MD5 # $? = 0 if found, !0 if not @@ -10855,18 +11228,20 @@ QpkgGetHash() } -QpkgGetURL() +QpkgGetDatabaseURL() { # Returns the URL of $qpkg_index. - # Inputs: + # Inputs: (local) # $1 = QPKG name (optional): if QPKG name is explicitly stated, then lookup QPKG name in package lists, ignoring current $qpkg_name and $qpkg_index. - # $qpkg_default_index (global) - # $qpkg_index (global) - # $qpkg_name (global) - # Outputs: + # Inputs: (global) + # $qpkg_default_index + # $qpkg_index + # $qpkg_name + + # Outputs: (local) # stdout = QPKG remote URL. # $? = 0 if found, !0 if not @@ -10894,16 +11269,18 @@ QpkgGetURL() } -QpkgGetMinRAM() +QpkgGetDatabaseMinRAM() { - # Inputs: + # Inputs: (local) # $1 = QPKG name (optional): if QPKG name is explicitly stated, then lookup QPKG name in package lists, ignoring current $qpkg_name and $qpkg_index. - # $qpkg_default_index (global) - # $qpkg_index (global) - # $qpkg_name (global) - # Outputs: + # Inputs: (global) + # $qpkg_default_index + # $qpkg_index + # $qpkg_name + + # Outputs: (local) # stdout = minimum installed RAM required. # $? = 0 if found, !0 if not @@ -10928,16 +11305,18 @@ QpkgGetMinRAM() } -QpkgGetMinOSVer() +QpkgGetDatabaseMinOSVer() { - # Inputs: + # Inputs: (local) # $1 = QPKG name (optional): if QPKG name is explicitly stated, then lookup QPKG name in package lists, ignoring current $qpkg_name and $qpkg_index. - # $qpkg_default_index (global) - # $qpkg_index (global) - # $qpkg_name (global) - # Outputs: + # Inputs: (global) + # $qpkg_default_index + # $qpkg_index + # $qpkg_name + + # Outputs: (local) # stdout = minimum QTS/QuTS version required by this QPKG. # $? = 0 if found, !0 if not @@ -10962,16 +11341,18 @@ QpkgGetMinOSVer() } -QpkgGetMaxOSVer() +QpkgGetDatabaseMaxOSVer() { - # Inputs: + # Inputs: (local) # $1 = QPKG name (optional): if QPKG name is explicitly stated, then lookup QPKG name in package lists, ignoring current $qpkg_name and $qpkg_index. - # $qpkg_default_index (global) - # $qpkg_index (global) - # $qpkg_name (global) - # Outputs: + # Inputs: (global) + # $qpkg_default_index + # $qpkg_index + # $qpkg_name + + # Outputs: (local) # stdout = maximum QTS/QuTS version required by this QPKG. # $? = 0 if found, !0 if not @@ -10996,30 +11377,52 @@ QpkgGetMaxOSVer() } -# QpkgGetAuthor() -# { -# -# # Return the maintainer of the specified QPKG. -# -# # Inputs: -# # $1 = QPKG name -# -# # Outputs: -# # stdout = QPKG author (first package found). -# # $? = 0 (found), !0 (not-found) -# -# local -i i=0 -# -# for i in "${!QPKG_NAME[@]}"; do -# [[ ${QPKG_NAME[$i]} = "${1:?${FUNCNAME[0]}'()': undefined package name}" ]] || continue -# printf '%s' "${QPKG_AUTHOR[$i]}" -# -# return 0 -# done -# -# return 1 -# -# } +QpkgGetDatabaseAuthor() + { + + # Return the maintainer of the specified QPKG. + + # Inputs: (local) + # $1 (optional) = QPKG name. + + # Inputs: (global) + # $qpkg_name (default) + + # Outputs: (local) + # stdout = QPKG author (first package found). + # $? = 0 (found), !0 (not-found) + + local a=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} + local -i i=0 + + for i in "${!QPKG_NAME[@]}"; do + [[ ${QPKG_NAME[$i]} = "$a" ]] || continue + printf '%s' "${QPKG_AUTHOR[$i]}" + + return 0 + done + + return 1 + + } + +QpkgGetInstalledAuthor() + { + + # Return the maintainer of the specified installed QPKG. + + # Inputs: (local) + # $1 (optional) = QPKG name. + + # Inputs: (global) + # $qpkg_name (default) + + # Outputs: (local) + # stdout = installed QPKG author. + + /sbin/getcfg "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}" Author -f /etc/config/qpkg.conf + + } #QpkgGetAuthorEmail() # { @@ -11096,7 +11499,7 @@ QpkgGetMaxOSVer() # # } -QpkgGetDesc() +QpkgGetDatabaseDesc() { # Inputs: @@ -11130,7 +11533,7 @@ QpkgGetDesc() } -QpkgGetNote() +QpkgGetDatabaseNote() { # Return any additional notes to be prominently displayed. @@ -11165,7 +11568,7 @@ QpkgGetNote() } -QpkgGetAbbrvs() +QpkgGetDatabaseAbbrvs() { # Inputs: @@ -11199,7 +11602,7 @@ QpkgGetAbbrvs() } -QpkgGetDependencies() +QpkgGetDatabaseDependencies() { # Inputs: @@ -11252,7 +11655,7 @@ QpkgGetDependencies() # Test alternative for compatibility - if QpkgIsArchOK "$alt"; then + if QpkgIsDatabaseArchOK "$alt"; then out+=" $alt" found=true break @@ -11273,7 +11676,7 @@ QpkgGetDependencies() } -QpkgGetDependents() +QpkgGetDatabaseDependents() { # Inputs: @@ -11309,7 +11712,7 @@ QpkgGetDependents() } -QpkgGetIPKs() +QpkgGetDatabaseIPKs() { # Inputs: @@ -11335,7 +11738,7 @@ QpkgGetIPKs() } -QpkgGetActiveTest() +QpkgGetDatabaseActiveTest() { # Return any custom commands required to determine if specified QPKG is active or not. @@ -11361,14 +11764,16 @@ QpkgGetActiveTest() } -QpkgGetServiceAction() +QpkgGetInstalledServiceAction() { - # Inputs: + # Inputs: (local) # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. - # Outputs: + # Inputs: (global) + # $qpkg_name (default) + + # Outputs: (local) # $stdout = previous action requested. # $? = 0 (found), !0 (not-found) @@ -11384,14 +11789,16 @@ QpkgGetServiceAction() } -QpkgGetServiceResult() +QpkgGetInstalledServiceResult() { - # Inputs: + # Inputs: (local) # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. - # Outputs: + # Inputs: (global) + # $qpkg_name (default) + + # Outputs: (local) # $stdout = last known package service status. # $? = 0 (found), !0 (not-found) @@ -11407,20 +11814,41 @@ QpkgGetServiceResult() } +QpkgInstalledServiceResultWasOk() + { + + # Returns true if previous action for this package is 'ok'. + + # Inputs: (global) + # $qpkg_name + + # Outputs: (local) + # $? = true/false + + [[ -n $qpkg_name ]] || return + + [[ $(QpkgGetInstalledServiceResult) = ok ]] + + } + QpkgMatchAbbrv() { - # Inputs: - # $1 = a potential package abbreviation supplied by user. + # Inputs: (local) + # $1 (string) = a potential package abbreviation supplied by user. - # Outputs: + # Inputs: (global) + # $QPKG_ABBRVS[] + # $QPKG_NAME[] + + # Outputs: (local) # stdout = matched installable package name (empty if unmatched). - # $? = 0 (matched), !0 (unmatched) + # $? = 0 (matched) / !0 (unmatched) local -a ar=() local -i i=0 local -i j=0 - local -i z=1 # default to unmatched + local -i z=1 # Default to 'unmatched'. for i in "${!QPKG_NAME[@]}"; do ar=(${QPKG_ABBRVS[$i]}) @@ -11440,14 +11868,19 @@ QpkgMatchAbbrv() QpkgSetIndex() { - # Find and set the 1-based indexed reference of the named arch-specific QPKG in 'packages' file. + # Find and set the 1-based indexed reference of the named arch-specific QPKG in `packages` file. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $NAS_QPKG_ARCH + # $QPKG_ARCH[] + # $qpkg_name + # $QPKG_NAME[] - # Outputs: - # $qpkg_index (global) = QPKG element index in packages list arrays. '0' if a compatible arch could not be found. - # $? = 0 (successful), !0 (failed) + # Outputs: (local) + # $? = 0 (successful) / !0 (failed) + + # Outputs: (global) + # $qpkg_index ('0' if QPKG a compatible arch could not be found). [[ -n ${qpkg_name:-} ]] || return @@ -11469,14 +11902,17 @@ QpkgSetIndex() QpkgSetDefaultIndex() { - # Find and set the 1-based indexed reference of the named QPKG in 'packages' file. + # Find and set the 1-based indexed reference of the named QPKG in `packages` file. - # Inputs: - # $qpkg_name (global) + # Inputs: (global) + # $qpkg_name + # $QPKG_NAME[] - # Outputs: - # $qpkg_default_index (global) = QPKG element index in packages list arrays. '0' if QPKG could not be found. - # $? = 0 (successful), !0 (failed) + # Outputs: (local) + # $? = 0 (successful) / !0 (failed) + + # Outputs: (global) + # $qpkg_default_index ('0' if QPKG could not be found). [[ -n ${qpkg_name:-} ]] || return @@ -11492,127 +11928,239 @@ QpkgSetDefaultIndex() } -QpkgIsRepoSelfManaged() +QpkgIsInstalledRepoSelfManaged() + { + + # Is this QPKG managable by sherpa? + + # Inputs: (local) + # $1 (optional) = QPKG name. + + # Inputs: (global) + # $qpkg_name (default) + + # Outputs: (local) + # $? = true/false + + local a=$(QpkgGetInstalledStoreID "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") + + [[ -z $a || $a = undefined || $a = sherpa ]] + + } + +QpkgIsNtInstalledRepoSelfManaged() + { + + # Is this QPKG not managable by sherpa? + + # Inputs: (local) + # $1 (optional) = QPKG name. + + # Inputs: (global) + # $qpkg_name (default) + + # Outputs: (local) + # $? = true/false + + ! QpkgIsInstalledRepoSelfManaged "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}" + + } + +QpkgIsBackupExist() + { + + # Does this QPKG have an existing `backup` file? + + # Inputs: (local) + # $1 (optional) = QPKG name. + + # Inputs: (global) + # $QPKG_BU_PATH + # $qpkg_name (default) + + # Outputs: (local) + # $? = true/false + + [[ -e $QPKG_BU_PATH/${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}.config.tar.gz ]] + + } + +QpkgIsUpgradable() + { + + # Does an upgraded QPKG exist? + + # Inputs: (local) + # $1 (optional) = QPKG name. + + # Inputs: (global) + # $qpkg_name (default) + + # Outputs: (local) + # $? = true/false + + local a=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} + + QpkgIsInstalled "$a" && QpkgIsInstalledAuthorOk "$a" && QpkgIsInstalledRepoSelfManaged "$a" && [[ $(QpkgGetInstalledVer "$a") != "$(QpkgGetDatabaseVer "$a")" ]] && QpkgIsDatabaseArchOK "$a" && QpkgIsDatabaseMinOSVerOk "$a" && QpkgIsDatabaseMaxOSVerOk "$a" && QpkgIsDatabaseMinRAMOk "$a" + + } + +QpkgIsInstallable() { - # Is this QPKG managable by sherpa? + # Can this QPKG be installed? + + # Inputs: (global) + # $qpkg_default_index + # $qpkg_index + + # Outputs: (local) + # $? = true/false + + [[ $qpkg_index -gt 0 && $qpkg_default_index -gt 0 ]] || return + + QpkgIsNtReallyInstalled && QpkgIsDatabaseArchOK && QpkgIsDatabaseMinOSVerOk && QpkgIsDatabaseMaxOSVerOk && QpkgIsDatabaseMinRAMOk + + } + +QpkgIsDatabaseDependent() + { + + # Does this QPKG depend on any other QPKGs? + + # Inputs: (global) + # $qpkg_default_index + # $qpkg_index - # Inputs: - # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. + # Outputs: (local) + # $? = true/false - # Outputs: - # $? = 0 (true), !0 (false) + [[ $qpkg_index -gt 0 && $qpkg_default_index -gt 0 ]] || return - local a=$(QpkgGetStoreID "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") + local a='' - [[ -z $a || $a = undefined || $a = sherpa ]] + a=${QPKG_DEPENDS_ON[$qpkg_index]} + [[ $a = default ]] && a=${QPKG_DEPENDS_ON[$qpkg_default_index]} + [[ $a != none ]] } -QpkgIsBackupExist() +QpkgIsDatabaseIndependent() { - # Does this QPKG have an existing `backup` file? + # Will this package run independent of other QPKGs? - # Inputs: - # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. + # Inputs: (global) + # $qpkg_default_index + # $qpkg_index - # Outputs: - # $? = 0 (true), !0 (false) + # Outputs: (local) + # $? = true/false - [[ -e $QPKG_BU_PATH/${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}.config.tar.gz ]] + ! QpkgIsDatabaseDependent } -QpkgIsDependent() +QpkgIsDatabaseArchOK() { - # Does this QPKG depend on any other QPKGs? + # Does an arch-compatible QPKG exist to suit this NAS? - # Inputs: - # $qpkg_default_index (global) - # $qpkg_index (global) + # Inputs: (local) + # $1 (optional) = QPKG name. - # Outputs: - # $? = 0 (true), !0 (false) + # Inputs: (global) + # $qpkg_name (default) - [[ $qpkg_index -gt 0 && $qpkg_default_index -gt 0 ]] || return + # Outputs: (local) + # $? = true/false - local a='' + local a=$(QpkgGetDatabaseURL "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") - a=${QPKG_DEPENDS_ON[$qpkg_index]} - [[ $a = default ]] && a=${QPKG_DEPENDS_ON[$qpkg_default_index]} - [[ $a != none ]] + [[ -n $a && $a != none ]] } -QpkgIsIndependent() +QpkgIsDatabaseMinRAMOk() { - # Will this package run independent of other QPKGs? + # Does this NAS meets the minimum RAM requirements for QPKG name? - # Inputs: - # $qpkg_default_index (global) - # $qpkg_index (global) + # Inputs: (local) + # $1 (optional) = QPKG name. - # Outputs: - # $? = 0 (true), !0 (false) + # Inputs: (global) + # $NAS_RAM_KB + # $qpkg_name (default) + + # Outputs: (local) + # $? = true/false - ! QpkgIsDependent + local a=$(QpkgGetDatabaseMinRAM "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") + + [[ -n $a ]] && [[ $a = none || $NAS_RAM_KB -ge $a ]] } -QpkgIsUpgradable() +QpkgIsDatabaseMinOSVerOk() { - # Does an upgraded QPKG exist? + # Does this NAS meets the minimum OS firmware version requirements for QPKG name? - # Inputs: - # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. + # Inputs: (local) + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. - # Outputs: - # $? = 0 (true), !0 (false) + # Inputs: (global) + # $NAS_FIRMWARE_VER + # $qpkg_name (default for $1) - local a=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} + # Outputs: (local) + # $? = true/false - QpkgIsInstalled "$a" && QpkgIsRepoSelfManaged "$a" && [[ $(QpkgGetInstalledVer "$a") != "$(QpkgGetAvailVer "$a")" ]] && QpkgIsArchOK "$a" && QpkgIsMinOSVerOk "$a" && QpkgIsMaxOSVerOk "$a" && QpkgIsMinRAMOk "$a" + local a=$(QpkgGetDatabaseMinOSVer "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") + + [[ -n $a ]] && [[ $a = none || ${NAS_FIRMWARE_VER//.} -ge $a ]] } -QpkgIsInstallable() +QpkgIsDatabaseMaxOSVerOk() { - # Can this QPKG be installed? + # Does this NAS meets the maximum OS firmware version requirements for QPKG name? - # Inputs: - # $qpkg_default_index (global) - # $qpkg_index (global) + # Inputs: (local) + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. - # Outputs: - # $? = 0 (true), !0 (false) + # Inputs: (global) + # $NAS_FIRMWARE_VER + # $qpkg_name (default for $1) - [[ $qpkg_index -gt 0 && $qpkg_default_index -gt 0 ]] || return + # Outputs: (local) + # $? = true/false + + local a=$(QpkgGetDatabaseMaxOSVer "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") - ! QpkgIsInstalled && QpkgIsRepoSelfManaged && QpkgIsArchOK && QpkgIsMinOSVerOk && QpkgIsMaxOSVerOk && QpkgIsMinRAMOk + [[ -n $a ]] && [[ $a = none || ${NAS_FIRMWARE_VER//.} -le $a ]] } -QpkgIsCanBackup() +QpkgIsDatabaseCanBackup() { # Does this QPKG service-script support `backup` and `restore` actions? - # Inputs: - # $1 = QPKG name (optional): if QPKG name is explicitly stated, then lookup QPKG name in package lists, ignoring current $qpkg_name and $qpkg_index. - # $qpkg_default_index (global) - # $qpkg_index (global) - # $qpkg_name (global) + # Inputs: (local) + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. - # Outputs: - # $? = 0 (true), !0 (false) + # Inputs: (global) + # $QPKG_CAN_BACKUP[] + # $qpkg_default_index + # $qpkg_index + # $qpkg_name (default for $1) + # $QPKG_NAME[] + + # Outputs: (local) + # $? = true/false local a='' local -i i=0 @@ -11633,22 +12181,27 @@ QpkgIsCanBackup() } -QpkgIsCanRestartToUpdate() +QpkgIsDatabaseCanRestartToUpdate() { # Does this QPKG service-script support updating the internal application when the QPKG is restarted? - # Inputs: - # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. + # Inputs: (local) + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. - # Outputs: + # Inputs: (global) + # $qpkg_name (default for $1) + # $QPKG_NAME[] + # $QPKG_CAN_RESTART_TO_UPDATE[] + + # Outputs: (local) # $? = 0 (true), !0 (false) (first package found). + local a=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} local -i i=0 for i in "${!QPKG_NAME[@]}"; do - [[ ${QPKG_NAME[$i]} = "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}" ]] || continue + [[ ${QPKG_NAME[$i]} = "$a" ]] || continue ${QPKG_CAN_RESTART_TO_UPDATE[$i]} && return 0 || break done @@ -11656,22 +12209,25 @@ QpkgIsCanRestartToUpdate() } -QpkgIsCanClean() +QpkgIsDatabaseCanClean() { # Does this QPKG service-script support cleaning of the internal application? - # Inputs: - # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. + # Inputs: (local) + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. - # Outputs: - # $? = 0 (true), !0 (false) (first package found). + # Inputs: (global) + # $qpkg_name (default for $1) + + # Outputs: (local) + # $? = 0 (true), 1 (false) (first package found). + local a=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} local -i i=0 for i in "${!QPKG_NAME[@]}"; do - [[ ${QPKG_NAME[$i]} = "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}" ]] || continue + [[ ${QPKG_NAME[$i]} = "$a" ]] || continue ${QPKG_CAN_CLEAN[$i]} && return 0 || break done @@ -11679,19 +12235,21 @@ QpkgIsCanClean() } -QpkgIsSherpaCompatible() +QpkgIsDatabaseSherpaCompatible() { # Is this QPKG service-script compatible with enhanced actions supplied by sherpa? - # Inputs: - # $1 = QPKG name (optional): if QPKG name is explicitly stated, then lookup QPKG name in package lists, ignoring current $qpkg_name and $qpkg_index. - # $qpkg_default_index (global) - # $qpkg_index (global) - # $qpkg_name (global) + # Inputs: (local) + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. - # Outputs: - # $? = 0 (true), !0 (false) + # Inputs: (global) + # $qpkg_default_index + # $qpkg_index + # $qpkg_name (default for $1) + + # Outputs: (local) + # $? = true/false local a='' local -i i=0 @@ -11712,17 +12270,19 @@ QpkgIsSherpaCompatible() } -QpkgIsCanLog() +QpkgIsDatabaseCanLog() { # Does this QPKG service-script support logging of actions? When an action fails, this means user can be directed to check the service-script log. - # Inputs: - # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. + # Inputs: (local) + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. - # Outputs: - # $? = 0 (true), !0 (false) (first package found). + # Inputs: (global) + # $qpkg_name (default for $1) + + # Outputs: (local) + # $? = 0 (true) / !0 (false) (first package found). local -i i=0 @@ -11735,171 +12295,166 @@ QpkgIsCanLog() } -QpkgIsInstalled() +QpkgIsInstalledAutoUpdate() { - # Inputs: - # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. + # Is the installed QPKG set to auto-update on restart? - # Outputs: - # $? = 0 (true), !0 (false) + # Inputs: (local) + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. + + # Inputs: (global) + # $qpkg_name (default for $1) + + # Outputs: (local) + # $? = true/false + + local a=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} - $GREP_CMD -q "^\[${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}\]" /etc/config/qpkg.conf + [[ $(/sbin/getcfg "$a" Auto_Update -u -f /etc/config/qpkg.conf) = TRUE ]] } -QpkgIsNtInstalled() +QpkgIsInstalledAuthorOk() { - # Inputs: - # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. + # Inputs: (local) + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. - # Outputs: - # $? = 0 (true), !0 (false) + # Inputs: (global) + # $qpkg_name (default for $1) - ! QpkgIsInstalled "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}" + # Outputs: (local) + # $? = true/false + + local a=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} + + [[ $(QpkgGetDatabaseAuthor "$a") = "$(QpkgGetInstalledAuthor "$a")" ]] } -QpkgIsMissing() +QpkgIsNtInstalledAuthorOk() { - # Inputs: - # $1 (optional) = QPKG name. - # $qpkg_name (global, default) = target QPKG name. + # Inputs: (local) + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. - # Outputs: - # stdout = package installation date. - # $? = 0 (found), !0 (not-found). + # Inputs: (global) + # $qpkg_name (default for $1) - local a=$(QpkgGetInstallationPath "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") + # Outputs: (local) + # $? = true/false - [[ $a != undefined && ! -d $a ]] + ! QpkgIsInstalledAuthorOk "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}" } -QpkgIsEnabled() +QpkgIsInstalled() { + # Check if specified QPKG is installed, and that QPKG author is valid. + # Inputs: (local) - # $1 (optional) = QPKG name. + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. # Inputs: (global) - # $qpkg_name (default) = target QPKG name. + # $qpkg_name (default for $1) # Outputs: (local) - # $? = 0 : true - # $? = !0 : false + # $? = true/false - [[ $(/sbin/getcfg "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}" Enable -u -f /etc/config/qpkg.conf) = TRUE ]] + local a=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} + + $GREP_CMD -q "^\[$a\]" /etc/config/qpkg.conf && QpkgIsInstalledAuthorOk "$a" } -QpkgIsArchOK() +QpkgIsNtInstalled() { - # Does an arch-compatible QPKG exist to suit this NAS? - # Inputs: (local) - # $1 (optional) = QPKG name. + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. # Inputs: (global) - # $qpkg_name (default) = target QPKG name. + # $qpkg_name (default for $1) # Outputs: (local) - # $? = 0 : true - # $? = !0 : false - - local a=$(QpkgGetURL "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") + # $? = true/false - [[ -n $a && $a != none ]] + ! QpkgIsInstalled "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}" } -QpkgIsMinRAMOk() +QpkgIsReallyInstalled() { - # Does this NAS meets the minimum RAM requirements for QPKG name? + # Check if specified QPKG is installed, and don't check anything else. # Inputs: (local) - # $1 (optional) = QPKG name. + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. # Inputs: (global) - # $NAS_RAM_KB - # $qpkg_name (default) = target QPKG name. + # $qpkg_name (default for $1) # Outputs: (local) - # $? = 0 : true - # $? = !0 : false + # $? = true/false - local a=$(QpkgGetMinRAM "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") + local a=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} - [[ -n $a ]] && [[ $a = none || $NAS_RAM_KB -ge $a ]] + $GREP_CMD -q "^\[$a\]" /etc/config/qpkg.conf } -QpkgIsMinOSVerOk() +QpkgIsNtReallyInstalled() { - # Does this NAS meets the minimum OS firmware version requirements for QPKG name? - # Inputs: (local) - # $1 (optional) = QPKG name. + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. # Inputs: (global) - # $NAS_FIRMWARE_VER - # $qpkg_name (default) = target QPKG name. + # $qpkg_name (default for $1) # Outputs: (local) - # $? = 0 : true - # $? = !0 : false - - local a=$(QpkgGetMinOSVer "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") + # $? = true/false - [[ -n $a ]] && [[ $a = none || ${NAS_FIRMWARE_VER//.} -ge $a ]] + ! QpkgIsReallyInstalled "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}" } -QpkgIsMaxOSVerOk() +QpkgIsInstalledMissing() { - # Does this NAS meets the maximum OS firmware version requirements for QPKG name? - # Inputs: (local) - # $1 (optional) = QPKG name. + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. # Inputs: (global) - # $NAS_FIRMWARE_VER - # $qpkg_name (default) = target QPKG name. + # $qpkg_name (default for $1) # Outputs: (local) - # $? = 0 : true - # $? = !0 : false + # stdout = package installation date. + # $? = true (found) / false (not-found). - local a=$(QpkgGetMaxOSVer "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") + local a=$(QpkgGetInstalledPath "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}") - [[ -n $a ]] && [[ $a = none || ${NAS_FIRMWARE_VER//.} -le $a ]] + [[ $a != undefined && ! -d $a ]] } -QpkgIsAutoUpdate() +QpkgIsInstalledEnabled() { - # Is the installed QPKG set to auto-update on restart? - # Inputs: (local) - # $1 (optional) = QPKG name. + # $1 (string, optional override for $qpkg_name) = QPKG name: if $1 is explicitly stated, lookup $1 in package lists, ignoring current $qpkg_name and $qpkg_index. # Inputs: (global) - # $qpkg_name (default) = target QPKG name. + # $qpkg_name (default for $1) # Outputs: (local) - # $? = 0 : true - # $? = !0 : false + # $? = true/false + + local a=${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}} - [[ $(/sbin/getcfg "${1:-${qpkg_name:?${FUNCNAME[0]}'()': undefined package name}}" Auto_Update -u -f /etc/config/qpkg.conf) = TRUE ]] + [[ $(/sbin/getcfg "$a" Enable -u -f /etc/config/qpkg.conf) = TRUE ]] } @@ -12047,6 +12602,11 @@ RunAndLog() # $3 = 'log:failure-only' (optional) - if specified, stdout & stderr are only recorded in the specified log if the command failed. Default is to always record stdout & stderr. # $4 = e.g. '10' (optional) - an additional acceptable result code. Any other non-zero result from command will be considered a failure. + # Inputs: (global) + # $RUN_LOGS_PATH + # $useropt_debug + # $useropt_verbose + # Outputs: (local) # stdout = commandstring stdout and stderr if script is in 'debug' mode. # pathfile (specified as $2) = stdout and stderr from commandstring (specified as $1). @@ -12157,7 +12717,7 @@ LTrim() [[ -n ${1:-} ]] || return - (shopt -s extglob; printf '%s' "${1##+(' ')}") + printf '%s' "${1##+(' ')}" } @@ -12168,7 +12728,7 @@ RTrim() [[ -n ${1:-} ]] || return - (shopt -s extglob; printf '%s' "${1%%+(' ')}") + printf '%s' "${1%%+(' ')}" } @@ -12230,6 +12790,14 @@ FormatAsIsoBytes() ShowTitle() { + # Inputs: (global) + # $show_title + # $title_shown + # $useropt_verbose + + # Outputs: (global) + # $title_shown + [[ $show_title = true && $title_shown = false && $useropt_verbose = false ]] || return EraseThisLine @@ -12383,8 +12951,17 @@ ShowAsResultAndStdout() DisplayProcReport() { - # Inputs: - # $1 = report type (optional) + # Inputs: (local) + # $1 = report type string (optional) + + # Inputs: (global) + # $report_title_shown + + # Outputs: (local) + # stdout = formatted string + + # Outputs: (global) + # $report_title_shown [[ ${report_title_shown:=false} = false ]] || return @@ -12574,10 +13151,10 @@ DebugErrorTabld() DebugVar() { - # Inputs: + # Inputs: (local) # $1 = variable name - # Outputs: + # Outputs: (global) # to debug log if [[ -n ${!1:-} ]]; then @@ -12591,11 +13168,11 @@ DebugVar() DebugArray() { - # Inputs: + # Inputs: (local) # $1 = array name # $2 = array contents: i.e. "${myarray[*]}" - # Outputs: + # Outputs: (global) # to debug log [[ -n ${1:-} ]] || return @@ -12703,11 +13280,11 @@ FuncForkExit() CalcAmountDiff() { - # Inputs: + # Inputs: (local) # $1 = e.g. start time in seconds/milliseconds. # $2 = e.g. end time in seconds/milliseconds. - # Outputs: + # Outputs: (local) # stdout = difference. if [[ $2 -gt $1 ]]; then @@ -12721,11 +13298,11 @@ CalcAmountDiff() CalcMillisecondsDiffFromNanoseconds() { - # Inputs: + # Inputs: (local) # $1 = start time in nanoseconds. # $2 = end time in nanoseconds. - # Outputs: + # Outputs: (local) # stdout = difference in milliseconds. printf '%s' "$((($2-$1)/(10**6)))" @@ -12735,10 +13312,10 @@ CalcMillisecondsDiffFromNanoseconds() ConvertSecondsToFullDate() { - # Inputs: + # Inputs: (local) # $1 = Epoch seconds. - # Outputs: + # Outputs: (local) # stdout = real date. /bin/date -d @"$1" +%c | tr -s ' ' @@ -12748,10 +13325,10 @@ ConvertSecondsToFullDate() ConvertSecondsToTime() { - # Inputs: + # Inputs: (local) # $1 = Epoch seconds. - # Outputs: + # Outputs: (local) # stdout = time component only. /bin/date -d @"$1" '+%-l:%M:%S %p' | tr -s ' ' @@ -13318,8 +13895,8 @@ ShowAsActionLogDetail() DisplayAsIndentActionResultDurationReason "$3" "$2 $package_type" "$5" "$6" ;; *) - if QpkgIsCanLog "$2"; then - DisplayAsIndentActionResultDurationReason "$3" "$2 $package_type" "$5" "For more information: /etc/init.d/$($BASENAME_CMD "$(QpkgGetServicePathFile "$2")") log" + if QpkgIsDatabaseCanLog "$2"; then + DisplayAsIndentActionResultDurationReason "$3" "$2 $package_type" "$5" "For more information: /etc/init.d/$($BASENAME_CMD "$(QpkgGetInstalledServicePathFile "$2")") log" else DisplayAsIndentActionResultDurationReason "$3" "$2 $package_type" "$5" "$6" fi @@ -13760,7 +14337,7 @@ LoadPackages() $TAR_CMD --extract --gzip --no-same-owner --file="$PACKAGES_ARCHIVE_PATHFILE" --directory="$CACHE_PATH" fi - QPKGs.Tiers:Init + InitQPKGsTiers fi fi @@ -13879,7 +14456,7 @@ LoadPackages() QPKGs-GRall:Add "$qpkg_name" done - QPKGs.Tiers:Build + BuildQPKGsTiers FuncExit diff --git a/workshop/issues.txt b/workshop/issues.txt index 12cb978d8..6d3dd8673 100644 --- a/workshop/issues.txt +++ b/workshop/issues.txt @@ -2,9 +2,6 @@ Observed issues: * Will need a new method to detect if QTS 5.2.0 is still starting QPKGs due to async starts. - * Need sherpa to determine the diff between sherpa ClamAV QPKG and the new QNAP ClamAV QPKG so it knows when to ignore the new one. - - Maybe compare installed QPKG authors (in qpkg.conf) against packages file? - * 'sherpa enable-auto-update active' is not running 'enable-auto-update' action. * Near the end of installing IPKs, monitored download path can remain at non-zero size while packages complete installation.