mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-02-03 20:03:25 +01:00
feat(autocaliweb): migrate from GitHub to Codeberg (#11440)
- Add Codeberg API functions: codeberg_api_call, get_latest_codeberg_release, check_for_codeberg_release - Add fetch_and_deploy_codeberg_release function for Codeberg releases - Update autocaliweb install and update scripts to use Codeberg - Update autocaliweb.json documentation and website URLs
This commit is contained in:
committed by
GitHub
parent
b36609dfd5
commit
627587c54b
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: vhsdream
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/gelbphoenix/autocaliweb
|
||||
# Source: https://codeberg.org/gelbphoenix/autocaliweb
|
||||
|
||||
APP="Autocaliweb"
|
||||
var_tags="${var_tags:-ebooks}"
|
||||
@@ -30,8 +30,8 @@ function update_script() {
|
||||
|
||||
setup_uv
|
||||
|
||||
RELEASE=$(get_latest_github_release "gelbphoenix/autocaliweb")
|
||||
if check_for_gh_release "autocaliweb" "gelbphoenix/autocaliweb"; then
|
||||
RELEASE=$(get_latest_codeberg_release "gelbphoenix/autocaliweb")
|
||||
if check_for_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop autocaliweb metadata-change-detector acw-ingest-service acw-auto-zipper
|
||||
msg_ok "Stopped Services"
|
||||
@@ -39,7 +39,7 @@ function update_script() {
|
||||
INSTALL_DIR="/opt/autocaliweb"
|
||||
export VIRTUAL_ENV="${INSTALL_DIR}/venv"
|
||||
$STD tar -cf ~/autocaliweb_bkp.tar "$INSTALL_DIR"/{metadata_change_logs,dirs.json,.env,scripts/ingest_watcher.sh,scripts/auto_zipper_wrapper.sh,scripts/metadata_change_detector_wrapper.sh}
|
||||
fetch_and_deploy_gh_release "autocaliweb" "gelbphoenix/autocaliweb" "tarball" "latest" "/opt/autocaliweb"
|
||||
fetch_and_deploy_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb" "tarball" "latest" "/opt/autocaliweb"
|
||||
|
||||
msg_info "Updating Autocaliweb"
|
||||
cd "$INSTALL_DIR"
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
"interface_port": 8083,
|
||||
"documentation": "https://github.com/gelbphoenix/autocaliweb/wiki",
|
||||
"documentation": "https://codeberg.org/gelbphoenix/autocaliweb/wiki",
|
||||
"config_path": "/etc/autocaliweb",
|
||||
"website": "https://github.com/gelbphoenix/autocaliweb",
|
||||
"website": "https://codeberg.org/gelbphoenix/autocaliweb",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/autocaliweb.webp",
|
||||
"description": "A modern web management system for eBooks, eComics and PDFs",
|
||||
"install_methods": [
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: vhsdream
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/gelbphoenix/autocaliweb
|
||||
# Source: https://codeberg.org/gelbphoenix/autocaliweb
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
@@ -56,7 +56,7 @@ msg_ok "Installed Calibre"
|
||||
|
||||
setup_uv
|
||||
|
||||
fetch_and_deploy_gh_release "autocaliweb" "gelbphoenix/autocaliweb" "tarball" "latest" "/opt/autocaliweb"
|
||||
fetch_and_deploy_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb" "tarball" "latest" "/opt/autocaliweb"
|
||||
|
||||
msg_info "Configuring Autocaliweb"
|
||||
INSTALL_DIR="/opt/autocaliweb"
|
||||
@@ -111,8 +111,8 @@ msg_info "Initializing databases"
|
||||
KEPUBIFY_PATH=$(command -v kepubify 2>/dev/null || echo "/usr/bin/kepubify")
|
||||
EBOOK_CONVERT_PATH=$(command -v ebook-convert 2>/dev/null || echo "/usr/bin/ebook-convert")
|
||||
CALIBRE_BIN_DIR=$(dirname "$EBOOK_CONVERT_PATH")
|
||||
curl -fsSL https://github.com/gelbphoenix/autocaliweb/raw/refs/heads/main/library/metadata.db -o "$CALIBRE_LIB_DIR"/metadata.db
|
||||
curl -fsSL https://github.com/gelbphoenix/autocaliweb/raw/refs/heads/main/library/app.db -o "$CONFIG_DIR"/app.db
|
||||
curl -fsSL https://codeberg.org/gelbphoenix/autocaliweb/raw/branch/main/library/metadata.db -o "$CALIBRE_LIB_DIR"/metadata.db
|
||||
curl -fsSL https://codeberg.org/gelbphoenix/autocaliweb/raw/branch/main/library/app.db -o "$CONFIG_DIR"/app.db
|
||||
sqlite3 "$CONFIG_DIR/app.db" <<EOS
|
||||
UPDATE settings SET
|
||||
config_kepubifypath='$KEPUBIFY_PATH',
|
||||
|
||||
626
misc/tools.func
626
misc/tools.func
@@ -821,6 +821,54 @@ github_api_call() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Codeberg API call with retry logic
|
||||
# ------------------------------------------------------------------------------
|
||||
codeberg_api_call() {
|
||||
local url="$1"
|
||||
local output_file="${2:-/dev/stdout}"
|
||||
local max_retries=3
|
||||
local retry_delay=2
|
||||
|
||||
for attempt in $(seq 1 $max_retries); do
|
||||
local http_code
|
||||
http_code=$(curl -fsSL -w "%{http_code}" -o "$output_file" \
|
||||
-H "Accept: application/json" \
|
||||
"$url" 2>/dev/null || echo "000")
|
||||
|
||||
case "$http_code" in
|
||||
200)
|
||||
return 0
|
||||
;;
|
||||
403)
|
||||
# Rate limit - retry
|
||||
if [[ $attempt -lt $max_retries ]]; then
|
||||
msg_warn "Codeberg API rate limit, waiting ${retry_delay}s... (attempt $attempt/$max_retries)"
|
||||
sleep "$retry_delay"
|
||||
retry_delay=$((retry_delay * 2))
|
||||
continue
|
||||
fi
|
||||
msg_error "Codeberg API rate limit exceeded."
|
||||
return 1
|
||||
;;
|
||||
404)
|
||||
msg_error "Codeberg API endpoint not found: $url"
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
if [[ $attempt -lt $max_retries ]]; then
|
||||
sleep "$retry_delay"
|
||||
continue
|
||||
fi
|
||||
msg_error "Codeberg API call failed with HTTP $http_code"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
should_upgrade() {
|
||||
local current="$1"
|
||||
local target="$2"
|
||||
@@ -1385,6 +1433,37 @@ get_latest_github_release() {
|
||||
echo "$version"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Get latest Codeberg release version
|
||||
# ------------------------------------------------------------------------------
|
||||
get_latest_codeberg_release() {
|
||||
local repo="$1"
|
||||
local strip_v="${2:-true}"
|
||||
local temp_file=$(mktemp)
|
||||
|
||||
# Codeberg API: get all releases and pick the first non-draft/non-prerelease
|
||||
if ! codeberg_api_call "https://codeberg.org/api/v1/repos/${repo}/releases" "$temp_file"; then
|
||||
rm -f "$temp_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local version
|
||||
# Codeberg uses same JSON structure but releases endpoint returns array
|
||||
version=$(jq -r '[.[] | select(.draft==false and .prerelease==false)][0].tag_name // empty' "$temp_file")
|
||||
|
||||
if [[ "$strip_v" == "true" ]]; then
|
||||
version="${version#v}"
|
||||
fi
|
||||
|
||||
rm -f "$temp_file"
|
||||
|
||||
if [[ -z "$version" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$version"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Debug logging (only if DEBUG=1)
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -1559,6 +1638,119 @@ check_for_gh_release() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Checks for new Codeberg release (latest tag).
|
||||
#
|
||||
# Description:
|
||||
# - Queries the Codeberg API for the latest release tag
|
||||
# - Compares it to a local cached version (~/.<app>)
|
||||
# - If newer, sets global CHECK_UPDATE_RELEASE and returns 0
|
||||
#
|
||||
# Usage:
|
||||
# if check_for_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb" [optional] "v0.11.3"; then
|
||||
# # trigger update...
|
||||
# fi
|
||||
# exit 0
|
||||
# } (end of update_script not from the function)
|
||||
#
|
||||
# Notes:
|
||||
# - Requires `jq` (auto-installed if missing)
|
||||
# - Does not modify anything, only checks version state
|
||||
# - Does not support pre-releases
|
||||
# ------------------------------------------------------------------------------
|
||||
check_for_codeberg_release() {
|
||||
local app="$1"
|
||||
local source="$2"
|
||||
local pinned_version_in="${3:-}" # optional
|
||||
local app_lc="${app,,}"
|
||||
local current_file="$HOME/.${app_lc}"
|
||||
|
||||
msg_info "Checking for update: ${app}"
|
||||
|
||||
# DNS check
|
||||
if ! getent hosts codeberg.org >/dev/null 2>&1; then
|
||||
msg_error "Network error: cannot resolve codeberg.org"
|
||||
return 1
|
||||
fi
|
||||
|
||||
ensure_dependencies jq
|
||||
|
||||
# Fetch releases from Codeberg API
|
||||
local releases_json=""
|
||||
releases_json=$(curl -fsSL --max-time 20 \
|
||||
-H 'Accept: application/json' \
|
||||
"https://codeberg.org/api/v1/repos/${source}/releases" 2>/dev/null) || {
|
||||
msg_error "Unable to fetch releases for ${app}"
|
||||
return 1
|
||||
}
|
||||
|
||||
mapfile -t raw_tags < <(jq -r '.[] | select(.draft==false and .prerelease==false) | .tag_name' <<<"$releases_json")
|
||||
if ((${#raw_tags[@]} == 0)); then
|
||||
msg_error "No stable releases found for ${app}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local clean_tags=()
|
||||
for t in "${raw_tags[@]}"; do
|
||||
clean_tags+=("${t#v}")
|
||||
done
|
||||
|
||||
local latest_raw="${raw_tags[0]}"
|
||||
local latest_clean="${clean_tags[0]}"
|
||||
|
||||
# current installed (stored without v)
|
||||
local current=""
|
||||
if [[ -f "$current_file" ]]; then
|
||||
current="$(<"$current_file")"
|
||||
else
|
||||
# Migration: search for any /opt/*_version.txt
|
||||
local legacy_files
|
||||
mapfile -t legacy_files < <(find /opt -maxdepth 1 -type f -name "*_version.txt" 2>/dev/null)
|
||||
if ((${#legacy_files[@]} == 1)); then
|
||||
current="$(<"${legacy_files[0]}")"
|
||||
echo "${current#v}" >"$current_file"
|
||||
rm -f "${legacy_files[0]}"
|
||||
fi
|
||||
fi
|
||||
current="${current#v}"
|
||||
|
||||
# Pinned version handling
|
||||
if [[ -n "$pinned_version_in" ]]; then
|
||||
local pin_clean="${pinned_version_in#v}"
|
||||
local match_raw=""
|
||||
for i in "${!clean_tags[@]}"; do
|
||||
if [[ "${clean_tags[$i]}" == "$pin_clean" ]]; then
|
||||
match_raw="${raw_tags[$i]}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z "$match_raw" ]]; then
|
||||
msg_error "Pinned version ${pinned_version_in} not found upstream"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$current" != "$pin_clean" ]]; then
|
||||
CHECK_UPDATE_RELEASE="$match_raw"
|
||||
msg_ok "Update available: ${app} ${current:-not installed} → ${pin_clean}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
msg_ok "No update available: ${app} is already on pinned version (${current})"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# No pinning → use latest
|
||||
if [[ -z "$current" || "$current" != "$latest_clean" ]]; then
|
||||
CHECK_UPDATE_RELEASE="$latest_raw"
|
||||
msg_ok "Update available: ${app} ${current:-not installed} → ${latest_clean}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
msg_ok "No update available: ${app} (${latest_clean})"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Creates and installs self-signed certificates.
|
||||
#
|
||||
@@ -1648,6 +1840,440 @@ function ensure_usr_local_bin_persist() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Downloads and deploys latest Codeberg release (source, binary, tarball, asset).
|
||||
#
|
||||
# Description:
|
||||
# - Fetches latest release metadata from Codeberg API
|
||||
# - Supports the following modes:
|
||||
# - tarball: Source code tarball (default if omitted)
|
||||
# - source: Alias for tarball (same behavior)
|
||||
# - binary: .deb package install (arch-dependent)
|
||||
# - prebuild: Prebuilt .tar.gz archive (e.g. Go binaries)
|
||||
# - singlefile: Standalone binary (no archive, direct chmod +x install)
|
||||
# - tag: Direct tag download (bypasses Release API)
|
||||
# - Handles download, extraction/installation and version tracking in ~/.<app>
|
||||
#
|
||||
# Parameters:
|
||||
# $1 APP - Application name (used for install path and version file)
|
||||
# $2 REPO - Codeberg repository in form user/repo
|
||||
# $3 MODE - Release type:
|
||||
# tarball → source tarball (.tar.gz)
|
||||
# binary → .deb file (auto-arch matched)
|
||||
# prebuild → prebuilt archive (e.g. tar.gz)
|
||||
# singlefile→ standalone binary (chmod +x)
|
||||
# tag → direct tag (bypasses Release API)
|
||||
# $4 VERSION - Optional release tag (default: latest)
|
||||
# $5 TARGET_DIR - Optional install path (default: /opt/<app>)
|
||||
# $6 ASSET_FILENAME - Required for:
|
||||
# - prebuild → archive filename or pattern
|
||||
# - singlefile→ binary filename or pattern
|
||||
#
|
||||
# Examples:
|
||||
# # 1. Minimal: Fetch and deploy source tarball
|
||||
# fetch_and_deploy_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb"
|
||||
#
|
||||
# # 2. Binary install via .deb asset (architecture auto-detected)
|
||||
# fetch_and_deploy_codeberg_release "myapp" "myuser/myapp" "binary"
|
||||
#
|
||||
# # 3. Prebuilt archive (.tar.gz) with asset filename match
|
||||
# fetch_and_deploy_codeberg_release "myapp" "myuser/myapp" "prebuild" "latest" "/opt/myapp" "myapp_Linux_x86_64.tar.gz"
|
||||
#
|
||||
# # 4. Single binary (chmod +x)
|
||||
# fetch_and_deploy_codeberg_release "myapp" "myuser/myapp" "singlefile" "v1.0.0" "/opt/myapp" "myapp-linux-amd64"
|
||||
#
|
||||
# # 5. Explicit tag version
|
||||
# fetch_and_deploy_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb" "tag" "v0.11.3" "/opt/autocaliweb"
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
function fetch_and_deploy_codeberg_release() {
|
||||
local app="$1"
|
||||
local repo="$2"
|
||||
local mode="${3:-tarball}" # tarball | binary | prebuild | singlefile | tag
|
||||
local version="${4:-latest}"
|
||||
local target="${5:-/opt/$app}"
|
||||
local asset_pattern="${6:-}"
|
||||
|
||||
local app_lc=$(echo "${app,,}" | tr -d ' ')
|
||||
local version_file="$HOME/.${app_lc}"
|
||||
|
||||
local api_timeout="--connect-timeout 10 --max-time 60"
|
||||
local download_timeout="--connect-timeout 15 --max-time 900"
|
||||
|
||||
local current_version=""
|
||||
[[ -f "$version_file" ]] && current_version=$(<"$version_file")
|
||||
|
||||
ensure_dependencies jq
|
||||
|
||||
### Tag Mode (bypass Release API) ###
|
||||
if [[ "$mode" == "tag" ]]; then
|
||||
if [[ "$version" == "latest" ]]; then
|
||||
msg_error "Mode 'tag' requires explicit version (not 'latest')"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local tag_name="$version"
|
||||
[[ "$tag_name" =~ ^v ]] && version="${tag_name:1}" || version="$tag_name"
|
||||
|
||||
if [[ "$current_version" == "$version" ]]; then
|
||||
$STD msg_ok "$app is already up-to-date (v$version)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# DNS check
|
||||
if ! getent hosts "codeberg.org" &>/dev/null; then
|
||||
msg_error "DNS resolution failed for codeberg.org – check /etc/resolv.conf or networking"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local tmpdir
|
||||
tmpdir=$(mktemp -d) || return 1
|
||||
|
||||
msg_info "Fetching Codeberg tag: $app ($tag_name)"
|
||||
|
||||
local safe_version="${version//@/_}"
|
||||
safe_version="${safe_version//\//_}"
|
||||
local filename="${app_lc}-${safe_version}.tar.gz"
|
||||
local download_success=false
|
||||
|
||||
# Codeberg archive URL format: https://codeberg.org/{owner}/{repo}/archive/{tag}.tar.gz
|
||||
local archive_url="https://codeberg.org/$repo/archive/${tag_name}.tar.gz"
|
||||
if curl $download_timeout -fsSL -o "$tmpdir/$filename" "$archive_url"; then
|
||||
download_success=true
|
||||
fi
|
||||
|
||||
if [[ "$download_success" != "true" ]]; then
|
||||
msg_error "Download failed for $app ($tag_name)"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
mkdir -p "$target"
|
||||
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
|
||||
rm -rf "${target:?}/"*
|
||||
fi
|
||||
|
||||
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
|
||||
msg_error "Failed to extract tarball"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
}
|
||||
|
||||
local unpack_dir
|
||||
unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1)
|
||||
|
||||
shopt -s dotglob nullglob
|
||||
cp -r "$unpack_dir"/* "$target/"
|
||||
shopt -u dotglob nullglob
|
||||
|
||||
echo "$version" >"$version_file"
|
||||
msg_ok "Deployed: $app ($version)"
|
||||
rm -rf "$tmpdir"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Codeberg API: https://codeberg.org/api/v1/repos/{owner}/{repo}/releases
|
||||
local api_url="https://codeberg.org/api/v1/repos/$repo/releases"
|
||||
if [[ "$version" != "latest" ]]; then
|
||||
# Get release by tag: /repos/{owner}/{repo}/releases/tags/{tag}
|
||||
api_url="https://codeberg.org/api/v1/repos/$repo/releases/tags/$version"
|
||||
fi
|
||||
|
||||
# dns pre check
|
||||
if ! getent hosts "codeberg.org" &>/dev/null; then
|
||||
msg_error "DNS resolution failed for codeberg.org – check /etc/resolv.conf or networking"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local max_retries=3 retry_delay=2 attempt=1 success=false resp http_code
|
||||
|
||||
while ((attempt <= max_retries)); do
|
||||
resp=$(curl $api_timeout -fsSL -w "%{http_code}" -o /tmp/codeberg_rel.json "$api_url") && success=true && break
|
||||
sleep "$retry_delay"
|
||||
((attempt++))
|
||||
done
|
||||
|
||||
if ! $success; then
|
||||
msg_error "Failed to fetch release metadata from $api_url after $max_retries attempts"
|
||||
return 1
|
||||
fi
|
||||
|
||||
http_code="${resp:(-3)}"
|
||||
[[ "$http_code" != "200" ]] && {
|
||||
msg_error "Codeberg API returned HTTP $http_code"
|
||||
return 1
|
||||
}
|
||||
|
||||
local json tag_name
|
||||
json=$(</tmp/codeberg_rel.json)
|
||||
|
||||
# For "latest", the API returns an array - take the first (most recent) release
|
||||
if [[ "$version" == "latest" ]]; then
|
||||
json=$(echo "$json" | jq '.[0]')
|
||||
fi
|
||||
|
||||
tag_name=$(echo "$json" | jq -r '.tag_name // .name // empty')
|
||||
[[ "$tag_name" =~ ^v ]] && version="${tag_name:1}" || version="$tag_name"
|
||||
|
||||
if [[ "$current_version" == "$version" ]]; then
|
||||
$STD msg_ok "$app is already up-to-date (v$version)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local tmpdir
|
||||
tmpdir=$(mktemp -d) || return 1
|
||||
local filename="" url=""
|
||||
|
||||
msg_info "Fetching Codeberg release: $app ($version)"
|
||||
|
||||
### Tarball Mode ###
|
||||
if [[ "$mode" == "tarball" || "$mode" == "source" ]]; then
|
||||
local safe_version="${version//@/_}"
|
||||
safe_version="${safe_version//\//_}"
|
||||
filename="${app_lc}-${safe_version}.tar.gz"
|
||||
local download_success=false
|
||||
|
||||
# Codeberg archive URL format
|
||||
local archive_url="https://codeberg.org/$repo/archive/${tag_name}.tar.gz"
|
||||
if curl $download_timeout -fsSL -o "$tmpdir/$filename" "$archive_url"; then
|
||||
download_success=true
|
||||
fi
|
||||
|
||||
if [[ "$download_success" != "true" ]]; then
|
||||
msg_error "Download failed for $app ($tag_name)"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
mkdir -p "$target"
|
||||
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
|
||||
rm -rf "${target:?}/"*
|
||||
fi
|
||||
|
||||
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
|
||||
msg_error "Failed to extract tarball"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
}
|
||||
local unpack_dir
|
||||
unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1)
|
||||
|
||||
shopt -s dotglob nullglob
|
||||
cp -r "$unpack_dir"/* "$target/"
|
||||
shopt -u dotglob nullglob
|
||||
|
||||
### Binary Mode ###
|
||||
elif [[ "$mode" == "binary" ]]; then
|
||||
local arch
|
||||
arch=$(dpkg --print-architecture 2>/dev/null || uname -m)
|
||||
[[ "$arch" == "x86_64" ]] && arch="amd64"
|
||||
[[ "$arch" == "aarch64" ]] && arch="arm64"
|
||||
|
||||
local assets url_match=""
|
||||
# Codeberg assets are in .assets[].browser_download_url
|
||||
assets=$(echo "$json" | jq -r '.assets[].browser_download_url')
|
||||
|
||||
# If explicit filename pattern is provided, match that first
|
||||
if [[ -n "$asset_pattern" ]]; then
|
||||
for u in $assets; do
|
||||
case "${u##*/}" in
|
||||
$asset_pattern)
|
||||
url_match="$u"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
# Fall back to architecture heuristic
|
||||
if [[ -z "$url_match" ]]; then
|
||||
for u in $assets; do
|
||||
if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then
|
||||
url_match="$u"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Fallback: any .deb file
|
||||
if [[ -z "$url_match" ]]; then
|
||||
for u in $assets; do
|
||||
[[ "$u" =~ \.deb$ ]] && url_match="$u" && break
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ -z "$url_match" ]]; then
|
||||
msg_error "No suitable .deb asset found for $app"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
filename="${url_match##*/}"
|
||||
curl $download_timeout -fsSL -o "$tmpdir/$filename" "$url_match" || {
|
||||
msg_error "Download failed: $url_match"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
}
|
||||
|
||||
chmod 644 "$tmpdir/$filename"
|
||||
$STD apt install -y "$tmpdir/$filename" || {
|
||||
$STD dpkg -i "$tmpdir/$filename" || {
|
||||
msg_error "Both apt and dpkg installation failed"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
### Prebuild Mode ###
|
||||
elif [[ "$mode" == "prebuild" ]]; then
|
||||
local pattern="${6%\"}"
|
||||
pattern="${pattern#\"}"
|
||||
[[ -z "$pattern" ]] && {
|
||||
msg_error "Mode 'prebuild' requires 6th parameter (asset filename pattern)"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
}
|
||||
|
||||
local asset_url=""
|
||||
for u in $(echo "$json" | jq -r '.assets[].browser_download_url'); do
|
||||
filename_candidate="${u##*/}"
|
||||
case "$filename_candidate" in
|
||||
$pattern)
|
||||
asset_url="$u"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -z "$asset_url" ]] && {
|
||||
msg_error "No asset matching '$pattern' found"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
}
|
||||
|
||||
filename="${asset_url##*/}"
|
||||
curl $download_timeout -fsSL -o "$tmpdir/$filename" "$asset_url" || {
|
||||
msg_error "Download failed: $asset_url"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
}
|
||||
|
||||
local unpack_tmp
|
||||
unpack_tmp=$(mktemp -d)
|
||||
mkdir -p "$target"
|
||||
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
|
||||
rm -rf "${target:?}/"*
|
||||
fi
|
||||
|
||||
if [[ "$filename" == *.zip ]]; then
|
||||
ensure_dependencies unzip
|
||||
unzip -q "$tmpdir/$filename" -d "$unpack_tmp" || {
|
||||
msg_error "Failed to extract ZIP archive"
|
||||
rm -rf "$tmpdir" "$unpack_tmp"
|
||||
return 1
|
||||
}
|
||||
elif [[ "$filename" == *.tar.* || "$filename" == *.tgz ]]; then
|
||||
tar --no-same-owner -xf "$tmpdir/$filename" -C "$unpack_tmp" || {
|
||||
msg_error "Failed to extract TAR archive"
|
||||
rm -rf "$tmpdir" "$unpack_tmp"
|
||||
return 1
|
||||
}
|
||||
else
|
||||
msg_error "Unsupported archive format: $filename"
|
||||
rm -rf "$tmpdir" "$unpack_tmp"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local top_dirs
|
||||
top_dirs=$(find "$unpack_tmp" -mindepth 1 -maxdepth 1 -type d | wc -l)
|
||||
local top_entries inner_dir
|
||||
top_entries=$(find "$unpack_tmp" -mindepth 1 -maxdepth 1)
|
||||
if [[ "$(echo "$top_entries" | wc -l)" -eq 1 && -d "$top_entries" ]]; then
|
||||
inner_dir="$top_entries"
|
||||
shopt -s dotglob nullglob
|
||||
if compgen -G "$inner_dir/*" >/dev/null; then
|
||||
cp -r "$inner_dir"/* "$target/" || {
|
||||
msg_error "Failed to copy contents from $inner_dir to $target"
|
||||
rm -rf "$tmpdir" "$unpack_tmp"
|
||||
return 1
|
||||
}
|
||||
else
|
||||
msg_error "Inner directory is empty: $inner_dir"
|
||||
rm -rf "$tmpdir" "$unpack_tmp"
|
||||
return 1
|
||||
fi
|
||||
shopt -u dotglob nullglob
|
||||
else
|
||||
shopt -s dotglob nullglob
|
||||
if compgen -G "$unpack_tmp/*" >/dev/null; then
|
||||
cp -r "$unpack_tmp"/* "$target/" || {
|
||||
msg_error "Failed to copy contents to $target"
|
||||
rm -rf "$tmpdir" "$unpack_tmp"
|
||||
return 1
|
||||
}
|
||||
else
|
||||
msg_error "Unpacked archive is empty"
|
||||
rm -rf "$tmpdir" "$unpack_tmp"
|
||||
return 1
|
||||
fi
|
||||
shopt -u dotglob nullglob
|
||||
fi
|
||||
|
||||
### Singlefile Mode ###
|
||||
elif [[ "$mode" == "singlefile" ]]; then
|
||||
local pattern="${6%\"}"
|
||||
pattern="${pattern#\"}"
|
||||
[[ -z "$pattern" ]] && {
|
||||
msg_error "Mode 'singlefile' requires 6th parameter (asset filename pattern)"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
}
|
||||
|
||||
local asset_url=""
|
||||
for u in $(echo "$json" | jq -r '.assets[].browser_download_url'); do
|
||||
filename_candidate="${u##*/}"
|
||||
case "$filename_candidate" in
|
||||
$pattern)
|
||||
asset_url="$u"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -z "$asset_url" ]] && {
|
||||
msg_error "No asset matching '$pattern' found"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
}
|
||||
|
||||
filename="${asset_url##*/}"
|
||||
mkdir -p "$target"
|
||||
|
||||
local use_filename="${USE_ORIGINAL_FILENAME:-false}"
|
||||
local target_file="$app"
|
||||
[[ "$use_filename" == "true" ]] && target_file="$filename"
|
||||
|
||||
curl $download_timeout -fsSL -o "$target/$target_file" "$asset_url" || {
|
||||
msg_error "Download failed: $asset_url"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ "$target_file" != *.jar && -f "$target/$target_file" ]]; then
|
||||
chmod +x "$target/$target_file"
|
||||
fi
|
||||
|
||||
else
|
||||
msg_error "Unknown mode: $mode"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$version" >"$version_file"
|
||||
msg_ok "Deployed: $app ($version)"
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Downloads and deploys latest GitHub release (source, binary, tarball, asset).
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user