mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-08-04 20:03:23 +02:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ef8dc8312 | |||
| 53df629af3 | |||
| 5271863a59 | |||
| 468dba3f24 | |||
| 09e9918b8a | |||
| 64cd328363 | |||
| 6d63e3e476 | |||
| 3a846721ec | |||
| ac866bf816 | |||
| 5d202e2a4a | |||
| 888dfae126 | |||
| 60e8ed77c4 | |||
| cf942fb445 | |||
| 0c24310e90 | |||
| 336cdda47d | |||
| 268a6957a7 | |||
| e21a11c190 |
@@ -518,14 +518,43 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## 2026-08-04
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Obsidian-LiveSync ([#16233](https://github.com/community-scripts/ProxmoxVE/pull/16233))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- Opencloud: Pin version to 7.4.0 [@vhsdream](https://github.com/vhsdream) ([#16257](https://github.com/community-scripts/ProxmoxVE/pull/16257))
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- AFFiNE: fix version and build type reported by the app itself [@MickLesk](https://github.com/MickLesk) ([#16251](https://github.com/community-scripts/ProxmoxVE/pull/16251))
|
||||||
|
- Passbolt: fetch GPG key from Passbolt's own host instead of the flaky keyserver [@MickLesk](https://github.com/MickLesk) ([#16248](https://github.com/community-scripts/ProxmoxVE/pull/16248))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- tools.func: never delete ubuntu.sources (or other distro base sources) as orphaned [@MickLesk](https://github.com/MickLesk) ([#16250](https://github.com/community-scripts/ProxmoxVE/pull/16250))
|
||||||
|
- tools.func: complete a stale/partial backup manifest instead of trusting it as-is [@MickLesk](https://github.com/MickLesk) ([#16252](https://github.com/community-scripts/ProxmoxVE/pull/16252))
|
||||||
|
|
||||||
## 2026-08-03
|
## 2026-08-03
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Correction to link in Paperless-NGX update script [@jsspen](https://github.com/jsspen) ([#16241](https://github.com/community-scripts/ProxmoxVE/pull/16241))
|
||||||
- fix restore env in split pro [@johanngrobe](https://github.com/johanngrobe) ([#16228](https://github.com/community-scripts/ProxmoxVE/pull/16228))
|
- fix restore env in split pro [@johanngrobe](https://github.com/johanngrobe) ([#16228](https://github.com/community-scripts/ProxmoxVE/pull/16228))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- core: read all interactive prompts from /dev/tty, drain leftover input on read failure (hotfix) [@MickLesk](https://github.com/MickLesk) ([#16235](https://github.com/community-scripts/ProxmoxVE/pull/16235))
|
||||||
|
|
||||||
## 2026-08-02
|
## 2026-08-02
|
||||||
|
|
||||||
### 🆕 New Scripts
|
### 🆕 New Scripts
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ TURBO
|
|||||||
|
|
||||||
export NODE_OPTIONS="--max-old-space-size=2048"
|
export NODE_OPTIONS="--max-old-space-size=2048"
|
||||||
$STD yarn install
|
$STD yarn install
|
||||||
|
$STD bash ./scripts/set-version.sh "$(cat ~/.affine_app)"
|
||||||
|
export BUILD_TYPE=stable
|
||||||
$STD npm install -g typescript
|
$STD npm install -g typescript
|
||||||
|
|
||||||
$STD yarn affine @affine/native build
|
$STD yarn affine @affine/native build
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
____ __ _ ___ __ _ _____
|
||||||
|
/ __ \/ /_ _____(_)___/ (_)___ _____ / / (_) _____ / ___/__ ______ _____
|
||||||
|
/ / / / __ \/ ___/ / __ / / __ `/ __ \______/ / / / | / / _ \\__ \/ / / / __ \/ ___/
|
||||||
|
/ /_/ / /_/ (__ ) / /_/ / / /_/ / / / /_____/ /___/ /| |/ / __/__/ / /_/ / / / / /__
|
||||||
|
\____/_.___/____/_/\__,_/_/\__,_/_/ /_/ /_____/_/ |___/\___/____/\__, /_/ /_/\___/
|
||||||
|
/____/
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: MickLesk (CanbiZ)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/vrtmrz/obsidian-livesync | https://couchdb.apache.org/
|
||||||
|
|
||||||
|
APP="Obsidian-LiveSync"
|
||||||
|
var_tags="${var_tags:-documents;notes}"
|
||||||
|
var_cpu="${var_cpu:-1}"
|
||||||
|
var_ram="${var_ram:-1024}"
|
||||||
|
var_disk="${var_disk:-8}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_arm64="${var_arm64:-yes}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
|
||||||
|
if [[ ! -f /opt/couchdb/etc/local.d/obsidian-livesync.ini ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Stopping CouchDB"
|
||||||
|
systemctl stop couchdb
|
||||||
|
msg_ok "Stopped CouchDB"
|
||||||
|
|
||||||
|
create_backup /var/lib/couchdb /opt/couchdb/etc/local.d/obsidian-livesync.ini /opt/obsidian-livesync/.env
|
||||||
|
|
||||||
|
msg_info "Updating Container OS"
|
||||||
|
$STD apt update
|
||||||
|
$STD apt upgrade -y
|
||||||
|
msg_ok "Updated Container OS"
|
||||||
|
|
||||||
|
systemctl stop couchdb
|
||||||
|
restore_backup
|
||||||
|
|
||||||
|
msg_info "Starting CouchDB"
|
||||||
|
systemctl start couchdb
|
||||||
|
msg_ok "Started CouchDB"
|
||||||
|
msg_ok "Updated successfully!"
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
start
|
||||||
|
build_container
|
||||||
|
description
|
||||||
|
|
||||||
|
msg_ok "Completed successfully!\n"
|
||||||
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
|
echo -e "${INFO}${YW}Configure the Self-hosted LiveSync plugin with the credentials in /opt/obsidian-livesync/.env${CL}"
|
||||||
|
echo -e "${GATEWAY}${BGN}http://${IP}:5984/_utils/${CL}"
|
||||||
+1
-1
@@ -30,7 +30,7 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
RELEASE="v7.3.0"
|
RELEASE="v7.4.0"
|
||||||
if check_for_gh_release "OpenCloud" "opencloud-eu/opencloud" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then
|
if check_for_gh_release "OpenCloud" "opencloud-eu/opencloud" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then
|
||||||
msg_info "Stopping services"
|
msg_info "Stopping services"
|
||||||
systemctl stop opencloud opencloud-wopi
|
systemctl stop opencloud opencloud-wopi
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ function update_script() {
|
|||||||
echo -e ""
|
echo -e ""
|
||||||
msg_custom "🔄" "Migration required to new data structure (/opt/paperless_data/)"
|
msg_custom "🔄" "Migration required to new data structure (/opt/paperless_data/)"
|
||||||
msg_custom "📖" "Please follow the migration guide:"
|
msg_custom "📖" "Please follow the migration guide:"
|
||||||
echo -e "${GATEWAY}${BGN}https://github.com/community-scripts/ProxmoxVE/discussions/9223${CL}"
|
echo -e "${GATEWAY}${BGN}https://github.com/community-scripts/ProxmoxVE/pull/9223${CL}"
|
||||||
echo -e ""
|
echo -e ""
|
||||||
msg_custom "⚠️" "Update aborted. Please migrate your data first."
|
msg_custom "⚠️" "Update aborted. Please migrate your data first."
|
||||||
exit 253
|
exit 253
|
||||||
|
|||||||
+1
-1
@@ -143,7 +143,7 @@ EOF
|
|||||||
fi
|
fi
|
||||||
msg_ok "Migrated Configuration"
|
msg_ok "Migrated Configuration"
|
||||||
|
|
||||||
create_backup /opt/termix/data /opt/termix/uploads
|
create_backup /opt/termix/data /opt/termix/uploads /opt/termix/.env
|
||||||
|
|
||||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "termix" "Termix-SSH/Termix" "tarball"
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "termix" "Termix-SSH/Termix" "tarball"
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ $STD yarn config set enableTelemetry 0
|
|||||||
export NODE_OPTIONS="--max-old-space-size=4096"
|
export NODE_OPTIONS="--max-old-space-size=4096"
|
||||||
export TSC_COMPILE_ON_ERROR=true
|
export TSC_COMPILE_ON_ERROR=true
|
||||||
$STD yarn install
|
$STD yarn install
|
||||||
|
$STD bash ./scripts/set-version.sh "$(cat ~/.affine_app)"
|
||||||
|
export BUILD_TYPE=stable
|
||||||
$STD npm install -g typescript
|
$STD npm install -g typescript
|
||||||
$STD yarn affine @affine/native build
|
$STD yarn affine @affine/native build
|
||||||
$STD yarn affine @affine/server-native build
|
$STD yarn affine @affine/server-native build
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: MickLesk (CanbiZ)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/vrtmrz/obsidian-livesync | https://couchdb.apache.org/
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
setup_deb822_repo \
|
||||||
|
"couchdb" \
|
||||||
|
"https://couchdb.apache.org/repo/keys.asc" \
|
||||||
|
"https://apache.jfrog.io/artifactory/couchdb-deb/" \
|
||||||
|
"$(get_os_info codename)" \
|
||||||
|
"main"
|
||||||
|
|
||||||
|
msg_info "Installing CouchDB"
|
||||||
|
COUCHDB_ADMIN_USER="admin"
|
||||||
|
COUCHDB_PASSWORD="$(openssl rand -hex 24)"
|
||||||
|
COUCHDB_COOKIE="$(openssl rand -hex 16)"
|
||||||
|
|
||||||
|
cat <<EOF | debconf-set-selections
|
||||||
|
couchdb couchdb/mode select standalone
|
||||||
|
couchdb couchdb/mode seen true
|
||||||
|
couchdb couchdb/bindaddress string 0.0.0.0
|
||||||
|
couchdb couchdb/bindaddress seen true
|
||||||
|
couchdb couchdb/cookie string ${COUCHDB_COOKIE}
|
||||||
|
couchdb couchdb/cookie seen true
|
||||||
|
couchdb couchdb/adminpass password ${COUCHDB_PASSWORD}
|
||||||
|
couchdb couchdb/adminpass seen true
|
||||||
|
couchdb couchdb/adminpass_again password ${COUCHDB_PASSWORD}
|
||||||
|
couchdb couchdb/adminpass_again seen true
|
||||||
|
EOF
|
||||||
|
DEBIAN_FRONTEND=noninteractive $STD apt-get install -y couchdb
|
||||||
|
|
||||||
|
cat <<EOF >/root/.couchdb.credentials
|
||||||
|
COUCHDB_ADMIN_USER="${COUCHDB_ADMIN_USER}"
|
||||||
|
COUCHDB_ADMIN_PASSWORD="${COUCHDB_PASSWORD}"
|
||||||
|
COUCHDB_COOKIE="${COUCHDB_COOKIE}"
|
||||||
|
EOF
|
||||||
|
msg_ok "Installed CouchDB"
|
||||||
|
|
||||||
|
msg_info "Configuring CouchDB"
|
||||||
|
mkdir -p /opt/couchdb/etc/local.d /opt/obsidian-livesync
|
||||||
|
cat <<EOF >/opt/couchdb/etc/local.d/obsidian-livesync.ini
|
||||||
|
[couchdb]
|
||||||
|
single_node = true
|
||||||
|
max_document_size = 50000000
|
||||||
|
|
||||||
|
[admins]
|
||||||
|
admin = ${COUCHDB_PASSWORD}
|
||||||
|
|
||||||
|
[chttpd]
|
||||||
|
bind_address = 0.0.0.0
|
||||||
|
port = 5984
|
||||||
|
max_http_request_size = 4294967296
|
||||||
|
|
||||||
|
[chttpd_auth]
|
||||||
|
require_valid_user = true
|
||||||
|
|
||||||
|
[httpd]
|
||||||
|
enable_cors = true
|
||||||
|
WWW-Authenticate = Basic realm="couchdb"
|
||||||
|
|
||||||
|
[cors]
|
||||||
|
credentials = true
|
||||||
|
origins = app://obsidian.md,capacitor://localhost,http://localhost
|
||||||
|
headers = accept, authorization, content-type, origin, referer
|
||||||
|
methods = GET, PUT, POST, HEAD, DELETE
|
||||||
|
max_age = 3600
|
||||||
|
EOF
|
||||||
|
cat <<EOF >/opt/obsidian-livesync/.env
|
||||||
|
COUCHDB_URL=http://${LOCAL_IP}:5984
|
||||||
|
COUCHDB_USER=admin
|
||||||
|
COUCHDB_PASSWORD=${COUCHDB_PASSWORD}
|
||||||
|
COUCHDB_DATABASE=obsidiannotes
|
||||||
|
EOF
|
||||||
|
chmod 600 /opt/obsidian-livesync/.env
|
||||||
|
msg_ok "Configured CouchDB"
|
||||||
|
|
||||||
|
msg_info "Creating LiveSync Database"
|
||||||
|
systemctl enable -q couchdb
|
||||||
|
systemctl restart couchdb
|
||||||
|
for _ in {1..30}; do
|
||||||
|
curl -fsS -u "admin:${COUCHDB_PASSWORD}" -X PUT http://127.0.0.1:5984/obsidiannotes >/dev/null 2>&1 && break
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
msg_ok "Created LiveSync Database"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
@@ -64,7 +64,7 @@ $STD sudo -u cool coolconfig set-admin-password --user=admin --password="$COOLPA
|
|||||||
echo "$COOLPASS" >~/.coolpass
|
echo "$COOLPASS" >~/.coolpass
|
||||||
msg_ok "Installed Collabora Online"
|
msg_ok "Installed Collabora Online"
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v7.3.0" "/usr/bin" "opencloud-*-linux-$(arch_resolve)"
|
fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v7.4.0" "/usr/bin" "opencloud-*-linux-$(arch_resolve)"
|
||||||
mv /usr/bin/OpenCloud /usr/bin/opencloud
|
mv /usr/bin/OpenCloud /usr/bin/opencloud
|
||||||
|
|
||||||
msg_info "Configuring OpenCloud"
|
msg_info "Configuring OpenCloud"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ create_self_signed_cert
|
|||||||
|
|
||||||
setup_deb822_repo \
|
setup_deb822_repo \
|
||||||
"passbolt" \
|
"passbolt" \
|
||||||
"https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=0x3D1A0346C8E1802F774AEF21DE8B853FC155581D" \
|
"https://download.passbolt.com/pub.key" \
|
||||||
"https://download.passbolt.com/ce/debian" \
|
"https://download.passbolt.com/ce/debian" \
|
||||||
"buster" \
|
"buster" \
|
||||||
"stable"
|
"stable"
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ network_check() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $ipv4_connected == false ]]; then
|
if [[ $ipv4_connected == false ]]; then
|
||||||
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
|
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt </dev/tty
|
||||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
|
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||||
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
|
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
|
||||||
else
|
else
|
||||||
|
|||||||
+2
-1
@@ -3917,7 +3917,7 @@ run_addon_updates() {
|
|||||||
name="${a##*/update_}"
|
name="${a##*/update_}"
|
||||||
printf 'Do you also want to update addon "%s"? (y/N) [60s]: ' "$name"
|
printf 'Do you also want to update addon "%s"? (y/N) [60s]: ' "$name"
|
||||||
ans=""
|
ans=""
|
||||||
if read -r -t 60 ans; then :; else echo; fi
|
if read -r -t 60 ans </dev/tty; then :; else echo; fi
|
||||||
case "${ans,,}" in
|
case "${ans,,}" in
|
||||||
y | yes)
|
y | yes)
|
||||||
bash "$a" || msg_warn "Addon update for $name failed (rc=$?)"
|
bash "$a" || msg_warn "Addon update for $name failed (rc=$?)"
|
||||||
@@ -5729,6 +5729,7 @@ EOF
|
|||||||
# read itself failed (e.g. broken/closed stdin, I/O error) rather than
|
# read itself failed (e.g. broken/closed stdin, I/O error) rather than
|
||||||
# timing out - don't guess and destroy the container on a read we
|
# timing out - don't guess and destroy the container on a read we
|
||||||
# couldn't actually capture; keep it since that's the reversible choice.
|
# couldn't actually capture; keep it since that's the reversible choice.
|
||||||
|
while read -r -t 0.1 -n 1 _ </dev/tty 2>/dev/null; do :; done
|
||||||
echo ""
|
echo ""
|
||||||
msg_error "Could not read your response (stdin error) - keeping container ${CTID} for safety."
|
msg_error "Could not read your response (stdin error) - keeping container ${CTID} for safety."
|
||||||
msg_error "Remove it manually if not needed: pct destroy ${CTID}"
|
msg_error "Remove it manually if not needed: pct destroy ${CTID}"
|
||||||
|
|||||||
+7
-7
@@ -754,7 +754,7 @@ msg_info() {
|
|||||||
# Pause mode: Wait for Enter after each step
|
# Pause mode: Wait for Enter after each step
|
||||||
if [[ "${DEV_MODE_PAUSE:-false}" == "true" ]]; then
|
if [[ "${DEV_MODE_PAUSE:-false}" == "true" ]]; then
|
||||||
echo -en "\n${YWB}[PAUSE]${CL} Press Enter to continue..." >&2
|
echo -en "\n${YWB}[PAUSE]${CL} Press Enter to continue..." >&2
|
||||||
read -r
|
read -r </dev/tty
|
||||||
fi
|
fi
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
@@ -769,7 +769,7 @@ msg_info() {
|
|||||||
if [[ "${DEV_MODE_PAUSE:-false}" == "true" ]]; then
|
if [[ "${DEV_MODE_PAUSE:-false}" == "true" ]]; then
|
||||||
stop_spinner
|
stop_spinner
|
||||||
echo -en "\n${YWB}[PAUSE]${CL} Press Enter to continue..." >&2
|
echo -en "\n${YWB}[PAUSE]${CL} Press Enter to continue..." >&2
|
||||||
read -r
|
read -r </dev/tty
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1217,7 +1217,7 @@ prompt_confirm() {
|
|||||||
# Interactive prompt with timeout
|
# Interactive prompt with timeout
|
||||||
echo -en "${YW}${message} ${hint} (auto-${default} in ${timeout}s): ${CL}"
|
echo -en "${YW}${message} ${hint} (auto-${default} in ${timeout}s): ${CL}"
|
||||||
|
|
||||||
if read -t "$timeout" -r response; then
|
if read -t "$timeout" -r response </dev/tty; then
|
||||||
# User provided input
|
# User provided input
|
||||||
response="${response,,}" # lowercase
|
response="${response,,}" # lowercase
|
||||||
case "$response" in
|
case "$response" in
|
||||||
@@ -1310,7 +1310,7 @@ prompt_input() {
|
|||||||
# Interactive prompt with timeout
|
# Interactive prompt with timeout
|
||||||
echo -en "${YW}${message}${hint} (auto-default in ${timeout}s): ${CL}" >&2
|
echo -en "${YW}${message}${hint} (auto-default in ${timeout}s): ${CL}" >&2
|
||||||
|
|
||||||
if read -t "$timeout" -r response; then
|
if read -t "$timeout" -r response </dev/tty; then
|
||||||
# User provided input (or pressed Enter for empty)
|
# User provided input (or pressed Enter for empty)
|
||||||
if [[ -n "$response" ]]; then
|
if [[ -n "$response" ]]; then
|
||||||
echo "$response"
|
echo "$response"
|
||||||
@@ -1412,7 +1412,7 @@ prompt_input_required() {
|
|||||||
|
|
||||||
echo -en "${YW}${message} (required, timeout ${timeout}s): ${CL}" >&2
|
echo -en "${YW}${message} (required, timeout ${timeout}s): ${CL}" >&2
|
||||||
|
|
||||||
if read -t "$timeout" -r response; then
|
if read -t "$timeout" -r response </dev/tty; then
|
||||||
if [[ -z "$response" ]]; then
|
if [[ -z "$response" ]]; then
|
||||||
echo -e "${YW}This field is required. Please enter a value. (attempt ${attempts}/3)${CL}" >&2
|
echo -e "${YW}This field is required. Please enter a value. (attempt ${attempts}/3)${CL}" >&2
|
||||||
fi
|
fi
|
||||||
@@ -1507,7 +1507,7 @@ prompt_select() {
|
|||||||
echo -en "${YW}Select [1-${num_options}] (auto-select ${default} in ${timeout}s): ${CL}" >&2
|
echo -en "${YW}Select [1-${num_options}] (auto-select ${default} in ${timeout}s): ${CL}" >&2
|
||||||
|
|
||||||
local response
|
local response
|
||||||
if read -t "$timeout" -r response; then
|
if read -t "$timeout" -r response </dev/tty; then
|
||||||
if [[ -z "$response" ]]; then
|
if [[ -z "$response" ]]; then
|
||||||
# Empty response, use default
|
# Empty response, use default
|
||||||
echo "${options[$((default - 1))]}"
|
echo "${options[$((default - 1))]}"
|
||||||
@@ -1590,7 +1590,7 @@ prompt_password() {
|
|||||||
# Interactive prompt with timeout (silent input)
|
# Interactive prompt with timeout (silent input)
|
||||||
echo -en "${YW}${message}${hint} (timeout ${timeout}s): ${CL}" >&2
|
echo -en "${YW}${message}${hint} (timeout ${timeout}s): ${CL}" >&2
|
||||||
|
|
||||||
if read -t "$timeout" -rs response; then
|
if read -t "$timeout" -rs response </dev/tty; then
|
||||||
echo "" >&2 # Newline after hidden input
|
echo "" >&2 # Newline after hidden input
|
||||||
if [[ -n "$response" ]]; then
|
if [[ -n "$response" ]]; then
|
||||||
# Validate minimum length
|
# Validate minimum length
|
||||||
|
|||||||
@@ -499,7 +499,7 @@ error_handler() {
|
|||||||
|
|
||||||
local response=""
|
local response=""
|
||||||
local read_rc
|
local read_rc
|
||||||
read -t 60 -r response
|
read -t 60 -r response </dev/tty
|
||||||
read_rc=$?
|
read_rc=$?
|
||||||
if [[ $read_rc -eq 0 ]]; then
|
if [[ $read_rc -eq 0 ]]; then
|
||||||
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
|
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
|
||||||
@@ -543,6 +543,7 @@ error_handler() {
|
|||||||
# read itself failed (e.g. broken/closed stdin, I/O error) rather than
|
# read itself failed (e.g. broken/closed stdin, I/O error) rather than
|
||||||
# timing out - don't guess and destroy the container on a read we
|
# timing out - don't guess and destroy the container on a read we
|
||||||
# couldn't actually capture; keep it since that's the reversible choice.
|
# couldn't actually capture; keep it since that's the reversible choice.
|
||||||
|
while read -r -t 0.1 -n 1 _ </dev/tty 2>/dev/null; do :; done
|
||||||
echo ""
|
echo ""
|
||||||
if declare -f msg_error >/dev/null 2>&1; then
|
if declare -f msg_error >/dev/null 2>&1; then
|
||||||
msg_error "Could not read your response (stdin error) - keeping container ${CTID} for safety."
|
msg_error "Could not read your response (stdin error) - keeping container ${CTID} for safety."
|
||||||
|
|||||||
+1
-1
@@ -201,7 +201,7 @@ network_check() {
|
|||||||
|
|
||||||
# If both IPv4 and IPv6 checks fail, prompt the user
|
# If both IPv4 and IPv6 checks fail, prompt the user
|
||||||
if [[ $ipv4_connected == false && $ipv6_connected == false ]]; then
|
if [[ $ipv4_connected == false && $ipv6_connected == false ]]; then
|
||||||
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
|
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt </dev/tty
|
||||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
|
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||||
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
|
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
|
||||||
else
|
else
|
||||||
|
|||||||
+27
-26
@@ -1292,14 +1292,17 @@ create_temp_dir() {
|
|||||||
# - Copies each given file/directory into a persistent store at
|
# - Copies each given file/directory into a persistent store at
|
||||||
# /opt/<NSAPP>.backup, mirroring its absolute path inside the store, and
|
# /opt/<NSAPP>.backup, mirroring its absolute path inside the store, and
|
||||||
# records it in a manifest so restore_backup needs no arguments.
|
# records it in a manifest so restore_backup needs no arguments.
|
||||||
# - Idempotent: if a store from a previous (failed) run already exists, it is
|
# - Idempotent per path: a path already recorded in the manifest (from this
|
||||||
# left untouched and no new backup is taken. This keeps the last-known-good
|
# run or a previous failed one) is left untouched, keeping the
|
||||||
# data instead of overwriting it with now-partially-updated data on retry.
|
# last-known-good copy instead of overwriting it with now-partially-updated
|
||||||
|
# data on retry. Any requested path NOT yet in the manifest is backed up
|
||||||
|
# now and appended - so a manifest left incomplete by an interrupted prior
|
||||||
|
# run gets completed instead of silently missing paths on restore.
|
||||||
# - Missing source paths are skipped with a warning (not fatal).
|
# - Missing source paths are skipped with a warning (not fatal).
|
||||||
# - Aborts the update on copy failure: if any file/dir cannot be backed up,
|
# - Aborts the update on copy failure: if any file/dir cannot be backed up,
|
||||||
# the half-written store is removed and the script exits, so the update
|
# the script exits before the update runs against unprotected data (the
|
||||||
# never runs against unprotected data (and a retry re-attempts a clean
|
# paths already recorded are left in place, so a retry only redoes the one
|
||||||
# backup rather than skipping it).
|
# that failed).
|
||||||
#
|
#
|
||||||
# restore_backup
|
# restore_backup
|
||||||
# - Copies every path recorded in the manifest back to its origin (replacing
|
# - Copies every path recorded in the manifest back to its origin (replacing
|
||||||
@@ -1318,19 +1321,17 @@ create_backup() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ -f "$manifest" ]]; then
|
if ! mkdir -p "$store" || ! touch "$manifest"; then
|
||||||
msg_ok "Existing backup found at ${store}, skipping backup"
|
msg_error "Backup failed: could not create store at ${store} - aborting update"
|
||||||
return 0
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg_info "Backing up data"
|
msg_info "Backing up data"
|
||||||
if ! mkdir -p "$store" || ! : >"$manifest"; then
|
|
||||||
msg_error "Backup failed: could not create store at ${store} - aborting update"
|
|
||||||
rm -rf "$store"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
for path in "$@"; do
|
for path in "$@"; do
|
||||||
path="${path%/}"
|
path="${path%/}"
|
||||||
|
if grep -qxF "$path" "$manifest" 2>/dev/null; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [[ ! -e "$path" ]]; then
|
if [[ ! -e "$path" ]]; then
|
||||||
msg_warn "Skipping backup of '${path}' (not found)"
|
msg_warn "Skipping backup of '${path}' (not found)"
|
||||||
continue
|
continue
|
||||||
@@ -1338,7 +1339,6 @@ create_backup() {
|
|||||||
dest="${store}/files${path}"
|
dest="${store}/files${path}"
|
||||||
if ! mkdir -p "$(dirname "$dest")" || ! cp -a "$path" "$dest"; then
|
if ! mkdir -p "$(dirname "$dest")" || ! cp -a "$path" "$dest"; then
|
||||||
msg_error "Backup of '${path}' failed - aborting update"
|
msg_error "Backup of '${path}' failed - aborting update"
|
||||||
rm -rf "$store"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "$path" >>"$manifest"
|
echo "$path" >>"$manifest"
|
||||||
@@ -1466,7 +1466,7 @@ prompt_for_github_token() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
local reply
|
local reply
|
||||||
read -rp "${TAB}Would you like to enter a GitHub Personal Access Token (PAT)? [y/N]: " reply
|
read -rp "${TAB}Would you like to enter a GitHub Personal Access Token (PAT)? [y/N]: " reply </dev/tty
|
||||||
reply="${reply:-n}"
|
reply="${reply:-n}"
|
||||||
|
|
||||||
if [[ ! "${reply,,}" =~ ^(y|yes)$ ]]; then
|
if [[ ! "${reply,,}" =~ ^(y|yes)$ ]]; then
|
||||||
@@ -1475,7 +1475,7 @@ prompt_for_github_token() {
|
|||||||
|
|
||||||
local token
|
local token
|
||||||
while true; do
|
while true; do
|
||||||
read -rp "${TAB}Enter your GitHub PAT: " token
|
read -rp "${TAB}Enter your GitHub PAT: " token </dev/tty
|
||||||
# Trim leading/trailing whitespace
|
# Trim leading/trailing whitespace
|
||||||
token="$(echo "$token" | xargs)"
|
token="$(echo "$token" | xargs)"
|
||||||
if [[ -z "$token" ]]; then
|
if [[ -z "$token" ]]; then
|
||||||
@@ -2040,8 +2040,9 @@ cleanup_orphaned_sources() {
|
|||||||
local basename_file
|
local basename_file
|
||||||
basename_file=$(basename "$sources_file")
|
basename_file=$(basename "$sources_file")
|
||||||
|
|
||||||
# NEVER remove debian.sources - this is the standard Debian repository
|
# NEVER remove the distro's own base sources file (debian.sources,
|
||||||
if [[ "$basename_file" == "debian.sources" ]]; then
|
# ubuntu.sources, ...)
|
||||||
|
if [[ "$basename_file" == "$(get_os_info id).sources" ]]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -2113,7 +2114,7 @@ ensure_apt_working() {
|
|||||||
# Step 4: More aggressive - remove all third-party sources
|
# Step 4: More aggressive - remove all third-party sources
|
||||||
msg_warn "APT update still failing, removing third-party sources"
|
msg_warn "APT update still failing, removing third-party sources"
|
||||||
find /etc/apt/sources.list.d/ -type f \( -name "*.sources" -o -name "*.list" \) \
|
find /etc/apt/sources.list.d/ -type f \( -name "*.sources" -o -name "*.list" \) \
|
||||||
! -name "debian.sources" -delete 2>/dev/null || true
|
! -name "$(get_os_info id).sources" -delete 2>/dev/null || true
|
||||||
|
|
||||||
# Final attempt
|
# Final attempt
|
||||||
if ! $STD apt update; then
|
if ! $STD apt update; then
|
||||||
@@ -3973,7 +3974,7 @@ _gh_scan_older_releases() {
|
|||||||
local use_fallback="y"
|
local use_fallback="y"
|
||||||
if [[ -t 0 ]]; then
|
if [[ -t 0 ]]; then
|
||||||
msg_warn "Release ${skip_tag} has no matching asset. Previous release ${rel_tag} has a compatible asset."
|
msg_warn "Release ${skip_tag} has no matching asset. Previous release ${rel_tag} has a compatible asset."
|
||||||
read -rp "Use version ${rel_tag} instead? [Y/n] (auto-yes in 60s): " -t 60 use_fallback || use_fallback="y"
|
read -rp "Use version ${rel_tag} instead? [Y/n] (auto-yes in 60s): " -t 60 use_fallback </dev/tty || use_fallback="y"
|
||||||
use_fallback="${use_fallback:-y}"
|
use_fallback="${use_fallback:-y}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -4796,7 +4797,7 @@ EOF
|
|||||||
for entry in "${compose_updates[@]}"; do
|
for entry in "${compose_updates[@]}"; do
|
||||||
IFS='|' read -r name image compose_workdir compose_service <<<"$entry"
|
IFS='|' read -r name image compose_workdir compose_service <<<"$entry"
|
||||||
reply=""
|
reply=""
|
||||||
if read -r -t 60 -p "${TAB3}Update ${name} (${image}) via Compose? <y/N> (auto-no in 60s): " reply; then
|
if read -r -t 60 -p "${TAB3}Update ${name} (${image}) via Compose? <y/N> (auto-no in 60s): " reply </dev/tty; then
|
||||||
echo ""
|
echo ""
|
||||||
else
|
else
|
||||||
echo ""
|
echo ""
|
||||||
@@ -4814,7 +4815,7 @@ EOF
|
|||||||
for entry in "${standalone_updates[@]}"; do
|
for entry in "${standalone_updates[@]}"; do
|
||||||
IFS='|' read -r name image <<<"$entry"
|
IFS='|' read -r name image <<<"$entry"
|
||||||
reply=""
|
reply=""
|
||||||
if read -r -t 60 -p "${TAB3}Pull new image for ${name} (${image})? <y/N> (auto-no in 60s): " reply; then
|
if read -r -t 60 -p "${TAB3}Pull new image for ${name} (${image})? <y/N> (auto-no in 60s): " reply </dev/tty; then
|
||||||
echo ""
|
echo ""
|
||||||
else
|
else
|
||||||
echo ""
|
echo ""
|
||||||
@@ -5409,7 +5410,7 @@ setup_hwaccel() {
|
|||||||
# Read with 60 second timeout
|
# Read with 60 second timeout
|
||||||
local selection=""
|
local selection=""
|
||||||
echo -n "Select GPU(s) to configure (1-${gpu_count}, A=all) [timeout 60s, default=all]: "
|
echo -n "Select GPU(s) to configure (1-${gpu_count}, A=all) [timeout 60s, default=all]: "
|
||||||
if read -r -t 60 selection; then
|
if read -r -t 60 selection </dev/tty; then
|
||||||
selection="${selection^^}" # uppercase
|
selection="${selection^^}" # uppercase
|
||||||
else
|
else
|
||||||
echo ""
|
echo ""
|
||||||
@@ -5457,7 +5458,7 @@ setup_hwaccel() {
|
|||||||
echo ""
|
echo ""
|
||||||
msg_custom "🎮" "${GN}" "NVIDIA GPU passthrough detected"
|
msg_custom "🎮" "${GN}" "NVIDIA GPU passthrough detected"
|
||||||
local nvidia_reply=""
|
local nvidia_reply=""
|
||||||
read -r -t 60 -p "${TAB3}⚙️ Install NVIDIA driver libraries in the container? [Y/n] (auto-yes in 60s): " nvidia_reply || nvidia_reply=""
|
read -r -t 60 -p "${TAB3}⚙️ Install NVIDIA driver libraries in the container? [Y/n] (auto-yes in 60s): " nvidia_reply </dev/tty || nvidia_reply=""
|
||||||
case "${nvidia_reply,,}" in
|
case "${nvidia_reply,,}" in
|
||||||
n | no) install_nvidia_drivers="no" ;;
|
n | no) install_nvidia_drivers="no" ;;
|
||||||
*) install_nvidia_drivers="yes" ;;
|
*) install_nvidia_drivers="yes" ;;
|
||||||
@@ -9755,7 +9756,7 @@ _gl_scan_older_releases() {
|
|||||||
local use_fallback="y"
|
local use_fallback="y"
|
||||||
if [[ -t 0 ]]; then
|
if [[ -t 0 ]]; then
|
||||||
msg_warn "Release ${skip_tag} has no matching asset. Previous release ${rel_tag} has a compatible asset."
|
msg_warn "Release ${skip_tag} has no matching asset. Previous release ${rel_tag} has a compatible asset."
|
||||||
read -rp "Use version ${rel_tag} instead? [Y/n] (auto-yes in 60s): " -t 60 use_fallback || use_fallback="y"
|
read -rp "Use version ${rel_tag} instead? [Y/n] (auto-yes in 60s): " -t 60 use_fallback </dev/tty || use_fallback="y"
|
||||||
use_fallback="${use_fallback:-y}"
|
use_fallback="${use_fallback:-y}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user