mirror of
https://github.com/Cheviiot/Nivora.git
synced 2026-08-03 15:51:12 +00:00
Maintain a validated cross-distribution package catalog. Automate upstream updates, isolated builds, diagnostics, and direct publication. Build the official GitHub Desktop sources for Linux with working OAuth.
295 lines
8.7 KiB
Bash
Executable File
295 lines
8.7 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
readonly -a PACKAGES=(
|
|
adwyra
|
|
anidesk
|
|
balena-etcher
|
|
chatbox
|
|
clash-verge-rev
|
|
claude-desktop
|
|
codex
|
|
fisher
|
|
github-desktop
|
|
happ
|
|
netbird
|
|
nivora-stplr
|
|
opencode
|
|
parsec
|
|
pineconemc
|
|
tailscale
|
|
ventoy
|
|
vual
|
|
yandex-browser-stable
|
|
)
|
|
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_root="$(cd "${script_dir}/.." && pwd)"
|
|
|
|
die() {
|
|
echo "package_updates: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
require_package() {
|
|
local requested="$1"
|
|
local package
|
|
for package in "${PACKAGES[@]}"; do
|
|
[[ "$package" == "$requested" ]] && return 0
|
|
done
|
|
die "unknown package: ${requested}"
|
|
}
|
|
|
|
current_version() {
|
|
stplr-spec get-field --path "${repo_root}/$1/Staplerfile" version
|
|
}
|
|
|
|
github_json() {
|
|
local url="$1"
|
|
local -a headers=(
|
|
-H 'Accept: application/vnd.github+json'
|
|
-H 'X-GitHub-Api-Version: 2022-11-28'
|
|
)
|
|
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
|
|
headers+=(-H "Authorization: Bearer ${GITHUB_TOKEN}")
|
|
fi
|
|
curl --retry 3 --retry-delay 2 --retry-all-errors \
|
|
--connect-timeout 30 --max-time 120 -fsSL "${headers[@]}" "$url"
|
|
}
|
|
|
|
git_latest_stable_tag() {
|
|
local repository="$1"
|
|
local attempt tag=''
|
|
|
|
for attempt in 1 2 3; do
|
|
tag="$(
|
|
GIT_TERMINAL_PROMPT=0 timeout 60s \
|
|
git ls-remote --tags --refs "https://github.com/${repository}.git" 'refs/tags/v*' |
|
|
awk '{sub("refs/tags/", "", $2); print $2}' |
|
|
grep -Eiv '(^|[-_.])(alpha|beta|rc|pre|preview)([-_.0-9]|$)' |
|
|
sort -V |
|
|
tail -1
|
|
)" || tag=''
|
|
if [[ -n "$tag" ]]; then
|
|
printf '%s\n' "$tag"
|
|
return 0
|
|
fi
|
|
sleep "$((attempt * 2))"
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
github_latest_release() {
|
|
local repository="$1"
|
|
local tag=''
|
|
tag="$(
|
|
github_json "https://api.github.com/repos/${repository}/releases?per_page=30" |
|
|
jq -r '
|
|
[
|
|
.[]
|
|
| select(.draft == false and .prerelease == false)
|
|
| .tag_name
|
|
| select(test("(?:^|[-_.])(alpha|beta|rc|pre|preview)(?:[-_.0-9]|$)"; "i") | not)
|
|
][0] // empty
|
|
' 2>/dev/null
|
|
)" || tag=''
|
|
|
|
if [[ -z "$tag" ]]; then
|
|
tag="$(git_latest_stable_tag "$repository")" || tag=''
|
|
fi
|
|
|
|
[[ -n "$tag" ]] || {
|
|
echo "package_updates: cannot determine latest release for ${repository}" >&2
|
|
return 1
|
|
}
|
|
printf '%s\n' "${tag#v}"
|
|
}
|
|
|
|
latest_anidesk() {
|
|
local version
|
|
version="$(
|
|
GIT_TERMINAL_PROMPT=0 timeout 60s \
|
|
git ls-remote --tags --refs https://github.com/theDesConnet/AniDesk.git 'refs/tags/v*' |
|
|
awk '{sub("refs/tags/v", "", $2); print $2}' |
|
|
sort -V |
|
|
tail -1
|
|
)"
|
|
[[ -n "$version" ]] || die 'cannot determine latest AniDesk version'
|
|
printf '%s\n' "$version"
|
|
}
|
|
|
|
latest_chatbox() {
|
|
local version
|
|
version="$(
|
|
github_json 'https://api.github.com/repos/chatboxai/chatbox/releases?per_page=30' |
|
|
jq -er '
|
|
[
|
|
.[]
|
|
| select(.draft == false and .prerelease == false)
|
|
| . as $release
|
|
| $release.assets[]?
|
|
| select(.name | test("^Chatbox-[0-9]+(?:\\.[0-9]+)+-amd64\\.deb$"))
|
|
| $release.tag_name
|
|
][0]
|
|
' |
|
|
sed 's/^v//'
|
|
)" || die 'cannot determine latest Chatbox Linux release'
|
|
printf '%s\n' "$version"
|
|
}
|
|
|
|
latest_claude_desktop() {
|
|
local version
|
|
version="$(
|
|
curl --retry 3 --retry-delay 2 --retry-all-errors \
|
|
--connect-timeout 30 --max-time 120 -fsSL \
|
|
'https://downloads.claude.ai/claude-desktop/apt/stable/dists/stable/main/binary-amd64/Packages' |
|
|
awk '
|
|
/^Package: claude-desktop$/ { selected = 1; next }
|
|
/^Package: / { selected = 0 }
|
|
selected && /^Version: / { print $2 }
|
|
' |
|
|
sort -V |
|
|
tail -1
|
|
)"
|
|
[[ -n "$version" ]] || die 'cannot determine latest Claude Desktop version'
|
|
printf '%s\n' "$version"
|
|
}
|
|
|
|
latest_parsec() {
|
|
local temp_dir version
|
|
temp_dir="$(mktemp -d)"
|
|
curl --retry 3 --retry-delay 2 --retry-all-errors \
|
|
--connect-timeout 30 --max-time 300 -fsSL \
|
|
-o "${temp_dir}/parsec.deb" \
|
|
'https://builds.parsec.app/package/parsec-linux.deb'
|
|
(
|
|
cd "$temp_dir"
|
|
ar x parsec.deb
|
|
tar -xOf control.tar.* ./control
|
|
) >"${temp_dir}/control"
|
|
version="$(awk '$1 == "Version:" {print $2; exit}' "${temp_dir}/control")"
|
|
[[ -n "$version" ]] || die 'cannot determine latest Parsec version'
|
|
printf '%s\n' "$version"
|
|
find "$temp_dir" -mindepth 1 -delete
|
|
rmdir "$temp_dir"
|
|
}
|
|
|
|
latest_tailscale() {
|
|
local effective version
|
|
effective="$(
|
|
curl --retry 3 --retry-delay 2 --retry-all-errors \
|
|
--connect-timeout 30 --max-time 120 -fsSLI -o /dev/null \
|
|
-w '%{url_effective}' \
|
|
'https://pkgs.tailscale.com/stable/tailscale_latest_amd64.tgz'
|
|
)"
|
|
version="$(sed -n 's/.*tailscale_\([0-9][0-9.]*\)_amd64\.tgz.*/\1/p' <<<"$effective")"
|
|
[[ -n "$version" ]] || die 'cannot determine latest Tailscale version'
|
|
printf '%s\n' "$version"
|
|
}
|
|
|
|
latest_yandex_browser() {
|
|
local version
|
|
version="$(
|
|
curl --retry 3 --retry-delay 2 --retry-all-errors \
|
|
--connect-timeout 30 --max-time 120 -fsSL \
|
|
'https://repo.yandex.ru/yandex-browser/deb/dists/stable/main/binary-amd64/Packages.gz' |
|
|
gzip -dc |
|
|
awk '
|
|
/^Package: yandex-browser-stable$/ { selected = 1; next }
|
|
/^Package: / { selected = 0 }
|
|
selected && /^Version: / {
|
|
version = $2
|
|
sub(/-[^-]+$/, "", version)
|
|
print version
|
|
}
|
|
' |
|
|
sort -V |
|
|
tail -1
|
|
)"
|
|
[[ -n "$version" ]] || die 'cannot determine latest Yandex Browser version'
|
|
printf '%s\n' "$version"
|
|
}
|
|
|
|
latest_version() {
|
|
case "$1" in
|
|
adwyra) github_latest_release Cheviiot/Adwyra ;;
|
|
anidesk) latest_anidesk ;;
|
|
balena-etcher) github_latest_release balena-io/etcher ;;
|
|
chatbox) latest_chatbox ;;
|
|
clash-verge-rev) github_latest_release clash-verge-rev/clash-verge-rev ;;
|
|
claude-desktop) latest_claude_desktop ;;
|
|
codex) github_latest_release Boria138/codex-app-linux ;;
|
|
fisher) github_latest_release jorgebucaran/fisher ;;
|
|
github-desktop)
|
|
github_latest_release desktop/desktop | sed 's/^release-//'
|
|
;;
|
|
happ) github_latest_release Happ-proxy/happ-desktop ;;
|
|
netbird) github_latest_release netbirdio/netbird ;;
|
|
nivora-stplr) current_version nivora-stplr ;;
|
|
opencode) github_latest_release anomalyco/opencode ;;
|
|
parsec) latest_parsec ;;
|
|
pineconemc) github_latest_release ElyPrismLauncher/Launcher ;;
|
|
tailscale) latest_tailscale ;;
|
|
ventoy) github_latest_release ventoy/Ventoy ;;
|
|
vual) github_latest_release Cheviiot/Vual ;;
|
|
yandex-browser-stable) latest_yandex_browser ;;
|
|
*) die "unknown package: $1" ;;
|
|
esac
|
|
}
|
|
|
|
check_package() {
|
|
local package="$1"
|
|
local current latest
|
|
require_package "$package"
|
|
current="$(current_version "$package")" || return
|
|
latest="$(latest_version "$package")" || return
|
|
printf '%s %s\n' "$current" "$latest"
|
|
}
|
|
|
|
check_all() {
|
|
local package current latest status versions
|
|
local updates=0
|
|
printf '%-24s %-24s %-24s %s\n' PACKAGE CURRENT LATEST STATUS
|
|
for package in "${PACKAGES[@]}"; do
|
|
versions="$(check_package "$package")" || return
|
|
read -r current latest <<<"$versions"
|
|
status=current
|
|
if [[ "$current" != "$latest" ]]; then
|
|
status=update
|
|
updates=1
|
|
fi
|
|
printf '%-24s %-24s %-24s %s\n' "$package" "$current" "$latest" "$status"
|
|
done
|
|
[[ "$updates" -eq 0 ]] || return 10
|
|
}
|
|
|
|
outdated_packages() {
|
|
local package current latest versions
|
|
for package in "${PACKAGES[@]}"; do
|
|
versions="$(check_package "$package")" || return
|
|
read -r current latest <<<"$versions"
|
|
if [[ "$current" != "$latest" ]]; then
|
|
printf '%s\n' "$package"
|
|
fi
|
|
done
|
|
}
|
|
|
|
case "${1:-}" in
|
|
check)
|
|
[[ "$#" -eq 2 ]] || die 'usage: package_updates.sh check <package>'
|
|
check_package "$2"
|
|
;;
|
|
check-all)
|
|
[[ "$#" -eq 1 ]] || die 'usage: package_updates.sh check-all'
|
|
check_all
|
|
;;
|
|
outdated)
|
|
[[ "$#" -eq 1 ]] || die 'usage: package_updates.sh outdated'
|
|
outdated_packages
|
|
;;
|
|
*)
|
|
die 'usage: package_updates.sh {check <package>|check-all|outdated}'
|
|
;;
|
|
esac
|