From f267288dac976f712d2eb7b3e6a2fd0f5b178ad0 Mon Sep 17 00:00:00 2001 From: L0RD-ZER0 <68327382+L0RD-ZER0@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:27:11 +0530 Subject: [PATCH 1/2] feat: add option to wait on apt locks Signed-off-by: L0RD-ZER0 <68327382+L0RD-ZER0@users.noreply.github.com> --- functions | 41 +++++++++++++++++++++++++++-------------- setup.sh | 15 ++++++++++++++- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/functions b/functions index 13de446..e871a13 100644 --- a/functions +++ b/functions @@ -3,6 +3,19 @@ # These functions have been adapted from # https://github.com/dokku/dokku/blob/master/plugins/common/functions +# DPkg lock-wait tiers, activated by EE_APT_LOCK_WAIT. Duplicated from +# setup.sh so this file is self-contained when sourced by migrate.sh or +# remote-migrate. +if [ -n "${EE_APT_LOCK_WAIT:-}" ]; then + _EE_APT_LOCK_UPDATE="-o DPkg::Lock::Timeout=900" + _EE_APT_LOCK_LIGHT_INSTALL="-o DPkg::Lock::Timeout=900" + _EE_APT_LOCK_INSTALL="-o DPkg::Lock::Timeout=1800" +else + _EE_APT_LOCK_UPDATE="${_EE_APT_LOCK_UPDATE:-}" + _EE_APT_LOCK_LIGHT_INSTALL="${_EE_APT_LOCK_LIGHT_INSTALL:-}" + _EE_APT_LOCK_INSTALL="${_EE_APT_LOCK_INSTALL:-}" +fi + has_tty() { declare desc="return 0 if we have a tty" if [[ "$(/usr/bin/tty || true)" == "not a tty" ]]; then @@ -220,7 +233,7 @@ get_ondrej_php_ppa_release_status() { # unsatisfiable deps (e.g. a PPA build needing a libxml2 the OS lacks) are caught # before touching the system. ee_php_cli_installable() { - apt-get install -s "php${1}-cli" >/dev/null 2>&1 + apt-get $_EE_APT_LOCK_LIGHT_INSTALL install -s "php${1}-cli" >/dev/null 2>&1 } # Add the third-party PHP repo (ondrej/php on Ubuntu, sury on Debian), pinned to @@ -228,7 +241,7 @@ ee_php_cli_installable() { ee_php_add_thirdparty_repo() { [ "$EE_PHP_THIRDPARTY_ADDED" == "1" ] && return 0 if [ "$EE_LINUX_DISTRO" == "Ubuntu" ]; then - apt-get install -y software-properties-common curl ca-certificates + apt-get $_EE_APT_LOCK_INSTALL install -y software-properties-common curl ca-certificates add-apt-repository -y ppa:ondrej/php || true local want use="" c f want="$(lsb_release -sc)" @@ -251,13 +264,13 @@ ee_php_add_thirdparty_repo() { return 1 fi elif [ "$EE_LINUX_DISTRO" == "Debian" ]; then - apt-get install -y apt-transport-https lsb-release ca-certificates curl locales locales-all + apt-get $_EE_APT_LOCK_INSTALL install -y apt-transport-https lsb-release ca-certificates curl locales locales-all export LC_ALL=en_US.UTF-8 export LANG=en_US.UTF-8 curl -fsSL https://packages.sury.org/php/apt.gpg -o /etc/apt/trusted.gpg.d/php.gpg echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list fi - apt-get update + apt-get $_EE_APT_LOCK_UPDATE update EE_PHP_THIRDPARTY_ADDED=1 return 0 } @@ -267,7 +280,7 @@ ee_php_drop_thirdparty_repo() { [ "$EE_PHP_THIRDPARTY_ADDED" == "1" ] || return 0 if [ "$EE_LINUX_DISTRO" == "Ubuntu" ]; then rm -f /etc/apt/sources.list.d/ondrej-ubuntu-php* /etc/apt/preferences.d/ee-ondrej-php - apt-get update + apt-get $_EE_APT_LOCK_UPDATE update EE_PHP_THIRDPARTY_ADDED="" fi } @@ -290,13 +303,13 @@ ee_select_and_install_php() { # Native: drop any probe PPA so it isn't shadowed. ee_php_drop_thirdparty_repo ee_log_info2 "Installing PHP ${v} (native)" - apt-get install -y "php${v}-cli" + apt-get $_EE_APT_LOCK_INSTALL install -y "php${v}-cli" EE_INSTALLED_PHP_VERSION="$v" return 0 fi if ee_php_add_thirdparty_repo && ee_php_cli_installable "$v"; then ee_log_info2 "Installing PHP ${v} (third-party repo)" - apt-get install -y "php${v}-cli" + apt-get $_EE_APT_LOCK_INSTALL install -y "php${v}-cli" EE_INSTALLED_PHP_VERSION="$v" return 0 fi @@ -327,12 +340,12 @@ function setup_php() { ee_log_info2 "No PHP pinned; trying in order (version-first): ${candidates}" fi - apt-get update + apt-get $_EE_APT_LOCK_UPDATE update ee_select_and_install_php $candidates || true # Unpinned fallback: distro default php-cli, so an unknown OS still gets a php. if [ -z "$EE_INSTALLED_PHP_VERSION" ] && [ -z "$EE_PHP_VERSION" ]; then - if apt-get install -y php-cli && command -v php >/dev/null 2>&1; then + if apt-get $_EE_APT_LOCK_INSTALL install -y php-cli && command -v php >/dev/null 2>&1; then EE_INSTALLED_PHP_VERSION="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;' 2>/dev/null)" [ -n "$EE_INSTALLED_PHP_VERSION" ] && ee_log_info2 "Fell back to distro default php-cli (${EE_INSTALLED_PHP_VERSION})" fi @@ -359,7 +372,7 @@ function setup_php_extensions() { if command -v php >/dev/null 2>&1; then php_extensions=(curl sqlite3 zip) if ! command -v gawk >/dev/null 2>&1; then - apt-get install gawk -y + apt-get $_EE_APT_LOCK_LIGHT_INSTALL install gawk -y fi # Use the version setup_php installed; else detect from the `php` symlink. default_php_version="${EE_INSTALLED_PHP_VERSION:-}" @@ -378,7 +391,7 @@ function setup_php_extensions() { fi done if [ -n "$packages" ]; then - apt-get install -y $packages + apt-get $_EE_APT_LOCK_INSTALL install -y $packages fi fi } @@ -407,7 +420,7 @@ function setup_host_dependencies() { if [ "$EE_LINUX_DISTRO" == "Ubuntu" ] || [ "$EE_LINUX_DISTRO" == "Debian" ]; then if ! command -v ip >> $LOG_FILE 2>&1; then ee_log_info2 "Installing iproute2" - apt-get install iproute2 -y + apt-get $_EE_APT_LOCK_LIGHT_INSTALL install iproute2 -y fi fi } @@ -431,11 +444,11 @@ function check_dependencies() { # can find their packages. On a freshly booted machine the apt cache # is typically empty and installs would fail without this. ee_log_info2 "Updating apt cache" - apt-get update + apt-get $_EE_APT_LOCK_UPDATE update if ! command -v sqlite3 >/dev/null 2>&1; then ee_log_info2 "Installing sqlite3" - apt-get install sqlite3 -y + apt-get $_EE_APT_LOCK_LIGHT_INSTALL install sqlite3 -y fi setup_host_dependencies diff --git a/setup.sh b/setup.sh index da79cad..4a9a6e6 100644 --- a/setup.sh +++ b/setup.sh @@ -7,6 +7,19 @@ export LOG_FILE="$EE_ROOT_DIR/logs/install.log" # Ensure EE_QUIET_OUTPUT is always defined so that set -u does not cause # "unbound variable" errors when the sourced functions file checks it. export EE_QUIET_OUTPUT="${EE_QUIET_OUTPUT:-}" +export EE_APT_LOCK_WAIT="${EE_APT_LOCK_WAIT:-}" + +# When EE_APT_LOCK_WAIT is set, wait for the dpkg/apt lock instead of +# failing immediately. Tier variables are left empty (no-op) when unset. +if [ -n "$EE_APT_LOCK_WAIT" ]; then + _EE_APT_LOCK_UPDATE="-o DPkg::Lock::Timeout=900" + _EE_APT_LOCK_LIGHT_INSTALL="-o DPkg::Lock::Timeout=900" + _EE_APT_LOCK_INSTALL="-o DPkg::Lock::Timeout=1800" +else + _EE_APT_LOCK_UPDATE="" + _EE_APT_LOCK_LIGHT_INSTALL="" + _EE_APT_LOCK_INSTALL="" +fi # Run apt/dpkg non-interactively so package installation never blocks on a # debconf or needrestart prompt during an unattended setup. @@ -34,7 +47,7 @@ function bootstrap() { if ! command -v wget > /dev/null 2>&1; then packages="${packages} wget" fi - apt-get update && apt-get install $packages -y + apt-get $_EE_APT_LOCK_UPDATE update && apt-get $_EE_APT_LOCK_LIGHT_INSTALL install $packages -y fi # Use the locally patched functions file when present (set via EE_LOCAL_FUNCTIONS), From 8baec11d115141ceb809da656c00137357cf741e Mon Sep 17 00:00:00 2001 From: L0RD-ZER0 <68327382+L0RD-ZER0@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:33:40 +0530 Subject: [PATCH 2/2] fix: address review changes --- functions | 34 ++++++++++++++++++++++++---------- setup.sh | 17 ++++++++++++++--- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/functions b/functions index e871a13..dba1c32 100644 --- a/functions +++ b/functions @@ -4,18 +4,30 @@ # https://github.com/dokku/dokku/blob/master/plugins/common/functions # DPkg lock-wait tiers, activated by EE_APT_LOCK_WAIT. Duplicated from -# setup.sh so this file is self-contained when sourced by migrate.sh or -# remote-migrate. +# setup.sh so the tier vars stay defined (no-op) when this file is sourced +# standalone by migrate.sh / remote-migrate — note those scripts' own +# apt-get calls and remote (ssh) installs do not inherit the wait. +# Any non-empty EE_APT_LOCK_WAIT (e.g. =1) enables the dpkg lock-wait; it is an +# on/off flag, not a duration (the timeouts below are fixed). Tier variables +# are left empty (no-op) when unset. if [ -n "${EE_APT_LOCK_WAIT:-}" ]; then - _EE_APT_LOCK_UPDATE="-o DPkg::Lock::Timeout=900" _EE_APT_LOCK_LIGHT_INSTALL="-o DPkg::Lock::Timeout=900" _EE_APT_LOCK_INSTALL="-o DPkg::Lock::Timeout=1800" else - _EE_APT_LOCK_UPDATE="${_EE_APT_LOCK_UPDATE:-}" _EE_APT_LOCK_LIGHT_INSTALL="${_EE_APT_LOCK_LIGHT_INSTALL:-}" _EE_APT_LOCK_INSTALL="${_EE_APT_LOCK_INSTALL:-}" fi +ee_apt_update() { + local i + for i in $(seq 1 30); do + apt-get update && return 0 + ee_log_info2 "apt lists lock busy; retrying in 10s" + sleep 10 + done + apt-get update +} + has_tty() { declare desc="return 0 if we have a tty" if [[ "$(/usr/bin/tty || true)" == "not a tty" ]]; then @@ -233,7 +245,9 @@ get_ondrej_php_ppa_release_status() { # unsatisfiable deps (e.g. a PPA build needing a libxml2 the OS lacks) are caught # before touching the system. ee_php_cli_installable() { - apt-get $_EE_APT_LOCK_LIGHT_INSTALL install -s "php${1}-cli" >/dev/null 2>&1 + # apt-get install -s uses Debug::NoLocking + # + apt-get install -s "php${1}-cli" >/dev/null 2>&1 } # Add the third-party PHP repo (ondrej/php on Ubuntu, sury on Debian), pinned to @@ -242,7 +256,7 @@ ee_php_add_thirdparty_repo() { [ "$EE_PHP_THIRDPARTY_ADDED" == "1" ] && return 0 if [ "$EE_LINUX_DISTRO" == "Ubuntu" ]; then apt-get $_EE_APT_LOCK_INSTALL install -y software-properties-common curl ca-certificates - add-apt-repository -y ppa:ondrej/php || true + (add-apt-repository -ny ppa:ondrej/php && ee_apt_update) || true local want use="" c f want="$(lsb_release -sc)" if [ "$(get_ondrej_php_ppa_release_status "$want")" == "200" ]; then @@ -270,7 +284,7 @@ ee_php_add_thirdparty_repo() { curl -fsSL https://packages.sury.org/php/apt.gpg -o /etc/apt/trusted.gpg.d/php.gpg echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list fi - apt-get $_EE_APT_LOCK_UPDATE update + ee_apt_update EE_PHP_THIRDPARTY_ADDED=1 return 0 } @@ -280,7 +294,7 @@ ee_php_drop_thirdparty_repo() { [ "$EE_PHP_THIRDPARTY_ADDED" == "1" ] || return 0 if [ "$EE_LINUX_DISTRO" == "Ubuntu" ]; then rm -f /etc/apt/sources.list.d/ondrej-ubuntu-php* /etc/apt/preferences.d/ee-ondrej-php - apt-get $_EE_APT_LOCK_UPDATE update + ee_apt_update EE_PHP_THIRDPARTY_ADDED="" fi } @@ -340,7 +354,7 @@ function setup_php() { ee_log_info2 "No PHP pinned; trying in order (version-first): ${candidates}" fi - apt-get $_EE_APT_LOCK_UPDATE update + ee_apt_update ee_select_and_install_php $candidates || true # Unpinned fallback: distro default php-cli, so an unknown OS still gets a php. @@ -444,7 +458,7 @@ function check_dependencies() { # can find their packages. On a freshly booted machine the apt cache # is typically empty and installs would fail without this. ee_log_info2 "Updating apt cache" - apt-get $_EE_APT_LOCK_UPDATE update + ee_apt_update if ! command -v sqlite3 >/dev/null 2>&1; then ee_log_info2 "Installing sqlite3" diff --git a/setup.sh b/setup.sh index 4a9a6e6..5ae801d 100644 --- a/setup.sh +++ b/setup.sh @@ -12,15 +12,26 @@ export EE_APT_LOCK_WAIT="${EE_APT_LOCK_WAIT:-}" # When EE_APT_LOCK_WAIT is set, wait for the dpkg/apt lock instead of # failing immediately. Tier variables are left empty (no-op) when unset. if [ -n "$EE_APT_LOCK_WAIT" ]; then - _EE_APT_LOCK_UPDATE="-o DPkg::Lock::Timeout=900" _EE_APT_LOCK_LIGHT_INSTALL="-o DPkg::Lock::Timeout=900" _EE_APT_LOCK_INSTALL="-o DPkg::Lock::Timeout=1800" else - _EE_APT_LOCK_UPDATE="" _EE_APT_LOCK_LIGHT_INSTALL="" _EE_APT_LOCK_INSTALL="" fi +# Retry-based apt-get update that tolerates a busy apt lists lock. +# Defined here for bootstrap(); the functions file overrides with its own +# copy (identical, but uses ee_log_info2 for logging). +ee_apt_update() { + local i + for i in $(seq 1 30); do + apt-get update && return 0 + echo "=====> apt lists lock busy; retrying in 10s" + sleep 10 + done + apt-get update +} + # Run apt/dpkg non-interactively so package installation never blocks on a # debconf or needrestart prompt during an unattended setup. export DEBIAN_FRONTEND=noninteractive @@ -47,7 +58,7 @@ function bootstrap() { if ! command -v wget > /dev/null 2>&1; then packages="${packages} wget" fi - apt-get $_EE_APT_LOCK_UPDATE update && apt-get $_EE_APT_LOCK_LIGHT_INSTALL install $packages -y + ee_apt_update && apt-get $_EE_APT_LOCK_LIGHT_INSTALL install $packages -y fi # Use the locally patched functions file when present (set via EE_LOCAL_FUNCTIONS),