diff --git a/scripts/bin/update-packages b/scripts/bin/update-packages
index 6f0e203d6..21d74fda9 100755
--- a/scripts/bin/update-packages
+++ b/scripts/bin/update-packages
@@ -19,7 +19,10 @@ export TERMUX_REPOLOGY_DATA_FILE
TERMUX_REPOLOGY_DATA_FILE="$(mktemp -t termux-repology.XXXXXX)" # File to store repology data.
export TERMUX_SCRIPTDIR
-TERMUX_SCRIPTDIR="$(realpath "$(dirname "$0")/../..")" # Script directory.
+TERMUX_SCRIPTDIR=$(realpath "$(dirname "$0")/../..") # Root of repository.
+
+export TERMUX_PACKAGES_DIRECTORIES
+TERMUX_PACKAGES_DIRECTORIES=$(jq --raw-output 'keys | .[]' "${TERMUX_SCRIPTDIR}"/repo.json)
# Define few more variables used by scripts.
# shellcheck source=scripts/properties.sh
@@ -76,15 +79,6 @@ _update() {
TERMUX_PKG_NAME="$(basename "$1")"
export TERMUX_PKG_BUILDER_DIR
TERMUX_PKG_BUILDER_DIR="$(realpath "$1")" # Directory containing build.sh.
- # Avoid:
- # - ending on errors such as $(which prog), where prog is not installed.
- # - error on unbound variable.
- #
- # Variables used by auto update script should be covered by above variables and properties.sh.
- set +e +u
- # shellcheck source=/dev/null
- . "${pkg_dir}"/build.sh 2>/dev/null
- set -e -u
IFS="," read -r -a BLACKLISTED_ARCH <<<"${TERMUX_PKG_BLACKLISTED_ARCHES:-}"
export TERMUX_ARCH="" # Arch to test updates.
@@ -95,46 +89,24 @@ _update() {
break
fi
done
+ # Set +e +u to avoid:
+ # - ending on errors such as $(which prog), where prog is not installed.
+ # - error on unbound variable. (All global variables used should be covered by properties.sh and above.)
+ set +e +u
+ # shellcheck source=/dev/null
+ . "${TERMUX_PKG_BUILDER_DIR}"/build.sh 2>/dev/null
+ set -e -u
- # Only update if auto update is enabled.
- if [[ "${TERMUX_PKG_AUTO_UPDATE}" == "true" ]]; then
- echo # Newline.
- echo "INFO: Updating ${TERMUX_PKG_NAME} [Current version: ${TERMUX_PKG_VERSION}]..."
- termux_pkg_auto_update
- fi
-}
-
-# Check if an issue with same title already exists and is open.
-_gh_check_issue_exists() {
- local pkg_name="$1"
- while read -r title; do
- # Check for exact title match.
- if [[ "${title}" == "Auto update failing for ${pkg_name}" ]]; then
- return 0
- fi
- done <<<"$(
- gh issue list \
- --label "auto update failing" --label "bot" \
- --state open \
- --search "Auto update failing for ${pkg_name} in:title type:issue" \
- --json title | jq -r '.[] | .title'
- )"
- return 1
+ echo # Newline.
+ echo "INFO: Updating ${TERMUX_PKG_NAME} [Current version: ${TERMUX_PKG_VERSION}]"
+ termux_pkg_auto_update
}
declare -A _FAILED_UPDATES=()
+declare -a _ALREADY_SEEN=() # Array of packages successfully updated or skipped.
_run_update() {
local pkg_dir="$1"
- # Check if this `pkg_dir` has a `build.sh` file.
- if [[ ! -f "${pkg_dir}/build.sh" ]]; then
- # Fail if detected a non-package directory.
- termux_error_exit "ERROR: directory '${pkg_dir}' is not a package."
- elif [[ "${GITHUB_ACTIONS:-}" == "true" ]] && _gh_check_issue_exists "$(basename "${pkg_dir}")"; then
- # Skip if issue with same title already exists.
- echo "INFO: Skipping '$(basename "${pkg_dir}")', an update issue for it hasn't been resolved yet."
- return
- fi
# Run each package update in separate process since we include their environment variables.
local output=""
{
@@ -147,14 +119,87 @@ _run_update() {
# shellcheck disable=SC2181
if [[ $? -ne 0 ]]; then
_FAILED_UPDATES["$(basename "${pkg_dir}")"]="${output}"
+ else
+ _ALREADY_SEEN+=("$(basename "${pkg_dir}")")
fi
}
+declare -a _CACHED_ISSUE_TITLES=()
+# Check if an issue with same title already exists and is open.
+_gh_check_issue_exists() {
+ local pkg_name="$1"
+ if [[ -z "${_CACHED_ISSUE_TITLES[*]}" ]]; then
+ while read -r title; do
+ _CACHED_ISSUE_TITLES+=("'${title}'") # An extra quote ('') is added to avoid false positive matches.
+ done <<<"$(
+ gh issue list \
+ --label "auto update failing" --label "bot" \
+ --state open \
+ --search "Auto update failing for in:title type:issue" \
+ --json title | jq -r '.[] | .title'
+ )"
+ fi
+ # shellcheck disable=SC2076 # We want literal match here, not regex based.
+ if [[ "${_CACHED_ISSUE_TITLES[*]}" =~ "'Auto update failing for ${pkg_name}'" ]]; then
+ return 0
+ fi
+ return 1
+}
+
+_should_update() {
+ local pkg_dir="$1"
+
+ if [[ ! -f "${pkg_dir}/build.sh" ]]; then
+ # Fail if detected a non-package directory.
+ termux_error_exit "ERROR: directory '${pkg_dir}' is not a package."
+ fi
+
+ # shellcheck disable=SC2076
+ if ! grep -q '^TERMUX_PKG_AUTO_UPDATE=true$' "${pkg_dir}/build.sh" ||
+ [[ " ${_ALREADY_SEEN[*]} ${!_FAILED_UPDATES[*]} " =~ " $(basename "${pkg_dir}") " ]]; then
+ return 1 # Skip.
+ fi
+ if [[ "${GITHUB_ACTIONS:-}" == "true" ]] && _gh_check_issue_exists "$(basename "${pkg_dir}")"; then
+ echo "INFO: Skipping '$(basename "${pkg_dir}")', an update issue for it hasn't been resolved yet."
+ return 1
+ fi
+
+ return 0
+}
+
+shopt -s extglob
+_update_dependencies() {
+ local pkg_dir="$1"
+
+ if ! grep -qE "^(TERMUX_PKG_DEPENDS|TERMUX_PKG_BUILD_DEPENDS|TERMUX_SUBPKG_DEPENDS)=" \
+ "${pkg_dir}"/+(build|*.subpackage).sh; then
+ return 0
+ fi
+ # shellcheck disable=SC2086 # Allow splitting of TERMUX_PACKAGES_DIRECTORIES.
+ while read -r dep dep_dir; do
+ if [[ -z $dep ]]; then
+ continue
+ elif [[ "${dep}" == "ERROR" ]]; then
+ termux_error_exit "ERROR: Obtaining update order failed for $(basename "${pkg_dir}")"
+ fi
+ _should_update "${dep_dir}" && _run_update "${dep_dir}"
+ done <<<"$("${TERMUX_SCRIPTDIR}"/scripts/buildorder.py "${pkg_dir}" $TERMUX_PACKAGES_DIRECTORIES || echo "ERROR")"
+}
+
echo "INFO: Running update for: $*"
if [[ "$1" == "@all" ]]; then
for repo_dir in $(jq --raw-output 'keys | .[]' "${TERMUX_SCRIPTDIR}/repo.json"); do
for pkg_dir in "${repo_dir}"/*; do
+ ! _should_update "${pkg_dir}" && continue # Skip if not needed.
+ # Update all its dependencies first.
+ _update_dependencies "${pkg_dir}"
+ # NOTE: I am not cheacking whether dependencies were updated successfully or not.
+ # There is no way I could know whether this package will build with current
+ # available verions of its dependencies or needs new ones.
+ # So, whatever the case may be. We just need packages to be updated in order
+ # and not care about anything else in between. If something fails to update,
+ # it will be reported by failure handling code, so no worries.
_run_update "${pkg_dir}"
done
done
@@ -168,11 +213,14 @@ else
fi
done
fi
- _run_update "${pkg}" # Here, `pkg` is a directory.
+ # Here `pkg` is a directory.
+ ! _should_update "${pkg}" && continue
+ _update_dependencies "${pkg}"
+ _run_update "${pkg}"
done
fi
-################################################Failure handling#################################################
+################################################FAILURE HANDLING#################################################
_gh_create_new_issue() {
local pkg_name="$1"
@@ -197,7 +245,7 @@ _gh_create_new_issue() {
Here's the output of the update script:
Show log
- ${_FAILED_UPDATES["${pkg_name}"]}
+ ${_FAILED_UPDATES["${pkg_name}"]}