From b6241e2ae7ec681794842af61c65aca90d73e2dc Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 00:40:41 +0300 Subject: [PATCH 01/26] epm play: add claude.ai --- pack.d/claude.sh | 28 ++++++++++++++++++++++++++++ play.d/claude.ai.sh | 41 +++++++++++++++++++++++++++++++++++++++++ repack.d/claude.sh | 14 ++++++++++++++ 3 files changed, 83 insertions(+) create mode 100755 pack.d/claude.sh create mode 100755 play.d/claude.ai.sh create mode 100755 repack.d/claude.sh diff --git a/pack.d/claude.sh b/pack.d/claude.sh new file mode 100755 index 000000000..ac872f0f5 --- /dev/null +++ b/pack.d/claude.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +TAR="$1" +RETURNTARNAME="$2" +VERSION="$3" + +. $(dirname $0)/common.sh + +PRODUCTDIR=opt/claude.ai +install -D -m755 $TAR $PRODUCTDIR/claude || fatal + +[ -n "$VERSION" ] || fatal "can't pack with empty VERSION" + +PKGNAME=$PRODUCT-$VERSION + +erc pack $PKGNAME.tar $PRODUCTDIR + +cat <$PKGNAME.tar.eepm.yaml +name: $PRODUCT +version: $VERSION +group: Networking/Instant messaging +license: Proprietary +url: https://claude.ai/ +summary: Claude is a next generation AI assistant +description: Claude is a next generation AI assistant built by Anthropic +EOF + +return_tar $PKGNAME.tar diff --git a/play.d/claude.ai.sh b/play.d/claude.ai.sh new file mode 100755 index 000000000..23898cdaf --- /dev/null +++ b/play.d/claude.ai.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +PKGNAME=claude +SUPPORTEDARCHES="x86_64 aarch64" +VERSION="$2" +DESCRIPTION="Claude is a next generation AI assistant built by Anthropic" +URL="https://claude.ai/" + +. $(dirname $0)/common.sh + +arch="$(epm print info -a)" +case "$arch" in + x86_64) + arch=x64 + ;; + aarch64) + arch=arm64 + ;; +esac + +# TODO: Darwin support +os="linux" + +platform="${os}-${arch}" + +GCS_BUCKET="https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases" +#GCS_BUCKET="$(eget -O- https://claude.ai/install.sh | grep "^GCS_BUCKET=" | sed -e 's|^GCS_BUCKET=||' -e 's|^"||' -e 's|"$||')" +#[ -n "$GCS_BUCKET" ] || fatal "Can't download https://claude.ai/install.sh" + +if [ "$VERSION" = "*" ] ; then + VERSION="$(eget -O- "$GCS_BUCKET/stable")" || fatal "Can't get version from $GCS_BUCKET/stable" +fi + +# ["platforms","linux-x64","checksum"] +checksum="$(get_json_value "$GCS_BUCKET/$version/manifest.json" '["platforms","'$platform'","checksum"]')" + +PKGURL="$GCS_BUCKET/$VERSION/$platform/claude" + +# TODO: compare checksum + +install_pack_pkgurl $VERSION $checksum diff --git a/repack.d/claude.sh b/repack.d/claude.sh new file mode 100755 index 000000000..fff66c923 --- /dev/null +++ b/repack.d/claude.sh @@ -0,0 +1,14 @@ +#!/bin/sh -x + +# It will be run with two args: buildroot spec +BUILDROOT="$1" +SPEC="$2" + +PRODUCT=claude +PRODUCTDIR=/opt/claude.ai + +. $(dirname $0)/common.sh + +add_bin_link_command + +add_libs_requires From 5e263bb583d0d4b72a35cfc2dac3294494e72ca4 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 00:56:43 +0300 Subject: [PATCH 02/26] add test_list_app.sh --- tests/test_list_app.sh | 96 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100755 tests/test_list_app.sh diff --git a/tests/test_list_app.sh b/tests/test_list_app.sh new file mode 100755 index 000000000..6402aaa0c --- /dev/null +++ b/tests/test_list_app.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +psdir=../play.d + +# bash specific +startwith() +{ + # rhas "$1" "^$2" + [[ "$1" = ${2}* ]] +} + + +__list_all_app() +{ + cd $psdir || fatal + for i in *.sh ; do + local name=${i/.sh/} + [ -n "$IGNOREi586" ] && startwith "$name" "i586-" && continue + startwith "$name" "common" && continue + echo "$name" + done + cd - >/dev/null +} + +# args: script, host arch +__get_app_description() +{ + local arch="$2" + #__run_script "$1" --description "$arch" 2>/dev/null + #return + if grep -q '^SUPPORTEDARCHES=.*\<'"$arch"'\>' "$psdir/$1.sh" || grep -q "^SUPPORTEDARCHES=[\"'][\"']$" "$psdir/$1.sh" || ! grep -q "^SUPPORTEDARCHES=" "$psdir/$1.sh" ; then + grep -oP "^DESCRIPTION=[\"']*\K[^\"']+" "$psdir/$1.sh" | sed -e 's| *#*$||' + fi +} + + +#for i in $(__list_all_app) ; do +# n="$(__get_app_description $i x86_64)" +# [ -z "$n" ] || echo $i +#done | wc -l + +__get_fast_short_list_app() +{ + local arch="$1" + [ -n "$arch" ] || fatal + local IGNOREi586 + [ "$arch" = "x86_64" ] && IGNOREi586='NoNo' || IGNOREi586='i586-' + grep -L -E "^DESCRIPTION=(''|\"\")" $psdir/*.sh | xargs grep -l -E "^SUPPORTEDARCHES=(''|\"\"|.*\<$arch\>)" | xargs basename -s .sh | grep -v -E "(^$IGNOREi586|^common)" +} + +#__get_fast_short_list_app x86_64 +#__get_fast_short_list_app x86 + +__get_fast_quiet_list_app() +{ + local arch="$1" + [ -n "$arch" ] || fatal + local IGNOREi586 + [ "$arch" = "x86_64" ] && IGNOREi586='NoNo' || IGNOREi586='i586-' + grep -l -E "^SUPPORTEDARCHES=(''|\"\"|.*\<$arch\>)" $psdir/*.sh | xargs grep -oP "^DESCRIPTION=[\"']*\K[^\"']+" | sed -e "s|.*/\(.*\).sh:|\1 - |" | grep -v -E "(^$IGNOREi586|^common|#.*$)" +} + +__get_fast_list_app() +{ + local arch="$1" + [ -n "$arch" ] || fatal + local IGNOREi586 + [ "$arch" = "x86_64" ] && IGNOREi586='NoNo' || IGNOREi586='i586-' + grep -l -E "^SUPPORTEDARCHES=(''|\"\"|.*\<$arch\>)" $psdir/*.sh | xargs grep -oP "^DESCRIPTION=[\"']*\K[^\"']+" | sed -e "s|.*/\(.*\).sh:| \1 - |" | grep -v -E "(^$IGNOREi586|^common|#.*$)" +} + +#__get_fast_list_app x86_64 + +__get_fast_list_pkg() +{ + local arch="$1" + [ -n "$arch" ] || fatal + local IGNOREi586 + + local tmplist + tmplist="$(mktemp)" || fatal + #remove_on_exit $tmplist + + local tmplist1 + tmplist1="$(mktemp)" || fatal + #remove_on_exit $tmplist1 + + [ "$arch" = "x86_64" ] && IGNOREi586='NoNo' || IGNOREi586='i586-' + + __get_fast_short_list_app $arch | LC_ALL=C sort >$tmplist + grep -l -E "^SUPPORTEDARCHES=(''|\"\"|.*\<$arch\>)" $psdir/*.sh | xargs grep -oP "^PKGNAME=[\"']*\K[^\"']+" | sed -e "s|.*/\(.*\).sh:|\1 |" | grep -v -E "(^$IGNOREi586|^common|#.*$)" | LC_ALL=C sort >$tmplist1 + LC_ALL=C join -j 1 -a 1 $tmplist $tmplist1 + # TODO: if right column is missed, run script +} + +__get_fast_list_pkg x86_64 From 3afd02126255549bfc3c9b1dd2c3e0fd2df8fbe3 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 00:57:24 +0300 Subject: [PATCH 03/26] add tests ALTLinuxc9f2/etc/os-release --- tests/etc/ALTLinuxc9f2/etc/os-release | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/etc/ALTLinuxc9f2/etc/os-release diff --git a/tests/etc/ALTLinuxc9f2/etc/os-release b/tests/etc/ALTLinuxc9f2/etc/os-release new file mode 100644 index 000000000..7f3ba0399 --- /dev/null +++ b/tests/etc/ALTLinuxc9f2/etc/os-release @@ -0,0 +1,11 @@ +NAME="ALT Linux" +VERSION="10.2.1" +ID=altlinux +VERSION_ID=10.2.1 +PRETTY_NAME="ALT SP Workstation 11100-01" +ANSI_COLOR="1;33" +CPE_NAME="cpe:/o:alt:spworkstation:10.2.1" +BUILD_ID="ALT SP Workstation 10.2" +ALT_BRANCH_ID="c10f2" +HOME_URL="https://basealt.ru/" +BUG_REPORT_URL="mailto:support_altsp@ivk.ru" From 9d18fd7ef6bf20b0be42bbca4123ba1837c5d354 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 00:58:31 +0300 Subject: [PATCH 04/26] tests: add test_startwith.sh test_status.sh --- tests/test_startwith.sh | 39 +++++++++++++++++++++++++++++++++++++++ tests/test_status.sh | 22 ++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100755 tests/test_startwith.sh create mode 100755 tests/test_status.sh diff --git a/tests/test_startwith.sh b/tests/test_startwith.sh new file mode 100755 index 000000000..ce2644f07 --- /dev/null +++ b/tests/test_startwith.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +startwith() +{ + # rhas "$1" "^$2" + #echo "${#2}" + #echo "${1:0:${#2}}" + [ "${1:0:${#2}}" = "$2" ] + #[[ "$1" = ${2}* ]] +} + + +check_ok() +{ + startwith "$1" "$2" && echo "OK for '$1' with '$2'" || echo "FATAL with '$1': result FALSE do not match with '$2'" +} + +check_notok() +{ + startwith "$1" "$2" && echo "FATAL with '$1': result TRUE do not match with '$2'" || echo "OK for '$1' with '$2'" +} + +check_ok "/abs" "/" +check_notok "../abs" "/" +check_ok "../abs" ".." +check_ok "common-file.abs" "common" + +startwith_inlist() +{ + local str="$1" + local i + for i in "$@" ; do + startwith "$str" "$i" && return + done + return 1 +} + +startwith_inlist "file-1.2.3.rpm" "base" "name" "filer" "file" && echo OK +startwith_inlist "files-1.2.3.rpm" "base" "name" "filer" "file" || echo OK diff --git a/tests/test_status.sh b/tests/test_status.sh new file mode 100755 index 000000000..5cdc258fe --- /dev/null +++ b/tests/test_status.sh @@ -0,0 +1,22 @@ + +__status_repacked() +{ + local repacked="$(epm print field Description for "$1" | grep -qi "alien" 2>/dev/null)" + local packager="$(epm print field Packager for "$1" 2>/dev/null)" + + local rpmversion="$(epm print field Version for "$1" 2>/dev/null)" + [ -n "$rpmversion" ] || return + + [ "$packager" = "EPM " ] && return 0 + [ "$packager" = "EPM " ] && return 0 + + return 1 +} + +LIST="hiddify mc" + +#__status_repacked $LIST +#echo $? + +FORMAT="%{Name} %{Version} %{Packager}\n" +a= rpmquery --queryformat "$FORMAT" -a | grep "EPM Date: Tue, 16 Dec 2025 12:18:07 +0300 Subject: [PATCH 05/26] epm play: add ocenaudio (eterbug #18748) --- play.d/ocenaudio.sh | 64 +++++++++++++++++++++++++++++++++++++++++++ repack.d/ocenaudio.sh | 31 +++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100755 play.d/ocenaudio.sh create mode 100755 repack.d/ocenaudio.sh diff --git a/play.d/ocenaudio.sh b/play.d/ocenaudio.sh new file mode 100755 index 000000000..e5f7e5fda --- /dev/null +++ b/play.d/ocenaudio.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +PKGNAME=ocenaudio +SUPPORTEDARCHES="x86_64" +VERSION="$2" +DESCRIPTION="Easy, fast and powerful audio editor" +URL="https://www.ocenaudio.com/" + +. $(dirname $0)/common.sh + +warn_version_is_not_supported + +pkgtype="$(epm print info -p)" + +case "$(epm print info -e)" in + openSUSE/15*) + distro="opensuse15" + ;; + Fedora/39) + distro="fedora39" + ;; + Fedora/4*) + distro="fedora40" + ;; + RockyLinux/9*) + distro="rockylinux9.3" + ;; + Debian/11*) + distro="debian11" + ;; + Debian/12*) + distro="debian12" + ;; + Debian/13*) + distro="debian13" + ;; + Ubuntu/20.*) + distro="ubuntu20.04" + ;; + Ubuntu/22.*) + distro="ubuntu22.04" + ;; + Ubuntu/24.*) + distro="ubuntu24.04" + ;; + ALTLinux/Sisyphus) + distro="fedora40" + ;; + ALTLinux/p11) + distro="debian12" + pkgtype="deb" + ;; + ALTLinux/p10) + distro="debian11" + pkgtype="deb" + ;; + *) + distro="debian12" + pkgtype="deb" +esac + +PKGURL="https://www.ocenaudio.com/downloads/index.php/ocenaudio_${distro}.${pkgtype}" + +install_pkgurl diff --git a/repack.d/ocenaudio.sh b/repack.d/ocenaudio.sh new file mode 100755 index 000000000..849235e8d --- /dev/null +++ b/repack.d/ocenaudio.sh @@ -0,0 +1,31 @@ +#!/bin/sh -x +# It will run with two args: buildroot spec +BUILDROOT="$1" +SPEC="$2" + +. $(dirname $0)/common.sh + +add_bin_exec_command $PRODUCT $PRODUCTDIR/bin/$PRODUCT + +fix_desktop_file /opt/ocenaudio/bin/ocenaudio $PRODUCT + +if ! is_soname_present libbz2.so.1.0 ; then + # fIXME: https://bugzilla.altlinux.org/35320 + ignore_lib_requires 'libbz2.so.1.0' + is_soname_present libbz2.so.1 || fatal "Can't find libbz2.so.1" + ln -s -v $(get_path_by_soname "libbz2.so.1") .$PRODUCTDIR/lib/libbz2.so.1.0 + pack_file $PRODUCTDIR/lib/libbz2.so.1.0 + add_unirequires libbz2.so.1 +fi + +case "$(epm print info -e)" in + ALTLinux/p10|Debian/11*) + # Application depends on external Qt5 libraries + add_unirequires libQt5Concurrent.so.5 libQt5Core.so.5 libQt5Gui.so.5 libQt5Network.so.5 libQt5Widgets.so.5 + ;; + *) + add_unirequires libQt6Concurrent.so.6 libQt6Core.so.6 libQt6Gui.so.6 libQt6Network.so.6 libQt6Widgets.so.6 +esac + +add_libs_requires + From 5e61306e09bca7670ffbde8b3482db28a78d10d0 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 01:06:43 +0300 Subject: [PATCH 06/26] epm play: rename claude.ai -> claude --- play.d/{claude.ai.sh => claude.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename play.d/{claude.ai.sh => claude.sh} (100%) diff --git a/play.d/claude.ai.sh b/play.d/claude.sh similarity index 100% rename from play.d/claude.ai.sh rename to play.d/claude.sh From c4e4a503285321c8cd3853496f990c1d32b6a3ae Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 03:58:41 +0300 Subject: [PATCH 07/26] epm play: add claude-desktop --- pack.d/claude-desktop.sh | 37 +++++++++++++++++++++++++++++++++++++ play.d/claude-desktop.sh | 27 +++++++++++++++++++++++++++ repack.d/claude-desktop.sh | 30 ++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 pack.d/claude-desktop.sh create mode 100755 play.d/claude-desktop.sh create mode 100644 repack.d/claude-desktop.sh diff --git a/pack.d/claude-desktop.sh b/pack.d/claude-desktop.sh new file mode 100644 index 000000000..6acc1adb4 --- /dev/null +++ b/pack.d/claude-desktop.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +TAR="$1" +RETURNTARNAME="$2" +VERSION="$3" + +. $(dirname $0)/common.sh + +PKGNAME=$PRODUCT-$VERSION.tar + +PRODUCTDIR=/opt/eepm-wine/$PRODUCT +INSTALLER="$(basename "$TAR")" + +mkdir -p .$PRODUCTDIR/ + +# c:/users/lav/AppData/Local/AnthropicClaude/claude.exe +cat < .$PRODUCTDIR/run.sh +#!/bin/sh +# AppData\Roaming +# APPDATA=\$(wine cmd /c echo %appdata% | tr -d '\r') +# AppData\Local +LOCALAPPDATA="\$(wine cmd /c echo %localappdata% | tr -d '\r')" +RUNFILE="\$LOCALAPPDATA\\\\AnthropicClaude\\\\claude.exe" + +URUNFILE="\$(winepath -u "\$RUNFILE")" +if [ ! -f "\$URUNFILE" ] ; then + INSTALLER="$PRODUCTDIR/$INSTALLER" + exec wine "\$INSTALLER" +fi +exec wine "\$RUNFILE" "\$@" +EOF +chmod 755 .$PRODUCTDIR/run.sh + +cp $TAR .$PRODUCTDIR +erc pack $PKGNAME opt/eepm-wine + +return_tar $PKGNAME diff --git a/play.d/claude-desktop.sh b/play.d/claude-desktop.sh new file mode 100755 index 000000000..f2cadd608 --- /dev/null +++ b/play.d/claude-desktop.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +PKGNAME=claude-desktop +SUPPORTEDARCHES="x86_64 aarch64" +VERSION="$2" +DESCRIPTION="Claude Desktop (Wine based)" +URL="https://claude.com/download" + +. $(dirname $0)/common.sh + +if ! is_command wine ; then + epm play wine || fatal +fi + +warn_version_is_not_supported + +#https://claude.ai/redirect/claudedotcom.v1.1029bab3-186e-4985-87e7-b2a711d887b4/api/desktop/win32/arm64/exe/latest/redirect +#https://claude.ai/redirect/claudedotcom.v1.1029bab3-186e-4985-87e7-b2a711d887b4/api/desktop/win32/x64/exe/latest/redirect + +# https://claude.ai/api/desktop/win32/x64/exe/latest/redirect +# https://claude.ai/api/desktop/win32/arm64/exe/latest/redirect + +VERSION="1.1029" +#PKGURL="https://storage.googleapis.com/osprey-downloads-c02f6a0d-347c-492b-a752-3e0651722e97/nest-win-x64/Claude-Setup-x64.exe" +PKGURL="ipfs://Qme1jkcU95P5dCWTs5sMxsvUruBfaVQMrAhY2585AfsoVJ?filename=Claude-Setup-x64.exe" + +install_pack_pkgurl $VERSION diff --git a/repack.d/claude-desktop.sh b/repack.d/claude-desktop.sh new file mode 100644 index 000000000..88a959096 --- /dev/null +++ b/repack.d/claude-desktop.sh @@ -0,0 +1,30 @@ +#!/bin/sh -x +# It will run with two args: buildroot spec +BUILDROOT="$1" + +SPEC="$2" + +PRODUCT=claude-desktop +PRODUCTDIR=/opt/eepm-wine/$PRODUCT + +. $(dirname $0)/common.sh + +add_requires '/usr/bin/wine' + +add_bin_link_command $PRODUCT $PRODUCTDIR/run.sh + +cat < Date: Wed, 17 Dec 2025 15:23:05 +0300 Subject: [PATCH 08/26] epm packages: improve help --- bin/epm-packages | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/bin/epm-packages b/bin/epm-packages index 593204acd..89c450c1e 100644 --- a/bin/epm-packages +++ b/bin/epm-packages @@ -21,10 +21,12 @@ load_helper epm-sh-warmup __epm_packages_help() { - message "package management list" - get_help HELPCMD $SHAREDIR/epm-packages + message "Print installed packages" + message "Options:" + get_help HELPOPTIONS $SHAREDIR/epm-packages message ' Examples: + epm qa --short epm packages --sort epm packages --sort=size epm packages --last @@ -94,18 +96,21 @@ epm_packages() local CMD case "$1" in - -h|--help|help) # HELPCMD: help + -h|--help|help) # HELPOPTIONS: help __epm_packages_help return ;; - --sort=size|--sort) # HELPCMD: list package(s) by size, most + --sort=size|--sort) # HELPOPTIONS: list package(s) by size, most __epm_packages_sort return ;; - --last|--sort=time) # HELPCMD: list package(s) by install time, most + --last|--sort=time) # HELPOPTIONS: list package(s) by install time, most __epm_packages_last return ;; + --short) # HELPOPTIONS: print out short package names + # for help entry only + ;; "") ;; *) From 79be8bcbcd3974add98e368705a0a916eff0f787 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 15:31:39 +0300 Subject: [PATCH 09/26] epm play wps-office: improve conflicts --- repack.d/wps-office.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/repack.d/wps-office.sh b/repack.d/wps-office.sh index d94e22d2d..0382d4999 100755 --- a/repack.d/wps-office.sh +++ b/repack.d/wps-office.sh @@ -12,6 +12,11 @@ PKGNAME=$(basename $0 .sh) if [ "$PKGNAME" = "wps-office-cn" ] ; then subst "s|^\(Name:.*\)$|Name: $PKGNAME|" $SPEC add_conflicts wps-office + add_conflicts wpsoffice + add_conflicts wpsoffice-cn +else + add_conflicts wps-office-cn + add_conflicts wpsoffice-cn fi remove_dir /etc/cron.d From ee8dcfa915a98d246e53b9278d615c6a33726ecf Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 17:48:43 +0300 Subject: [PATCH 10/26] add CLAUDE.md documentation for Claude Code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- CLAUDE.md | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.ru.md | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 CLAUDE.md create mode 100644 CLAUDE.ru.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..8f3fc601d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,103 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +EEPM (Etersoft EPM) is a universal package manager wrapper that provides a unified interface across all Linux distributions. It wraps native package managers (apt, yum, dnf, zypper, pacman, etc.) with consistent commands. + +Main commands: +- `epm` - package management (install, remove, search, etc.) +- `serv` - service management wrapper (systemd, sysvinit) +- `distr_info` - distribution detection utility + +## Development Setup + +No build step required - this is a shell script project. Run directly from checkout: +```bash +./bin/epm --help +./bin/epm play --list +``` + +## Testing + +Run individual test scripts from the `tests/` directory: +```bash +./tests/test_distr_info.sh +./tests/test_versions.sh +./tests/test_json.sh +``` + +Code quality checks: +```bash +./check_code.sh # Run shellcheck and checkbashisms on all scripts +./check_code.sh bin/epm-install # Check specific file +``` + +## Architecture + +### Core Scripts (`bin/`) + +- `epm` - main entry point, loads helpers via `load_helper` function +- `epm-sh-functions` - shared shell functions (output, colors, tty detection) +- `epm-*` - command implementations (epm-install, epm-remove, epm-search, etc.) +- `serv` - service management entry point +- `serv-*` - service command implementations +- `distr_info` - standalone distribution detection script +- `tools_*` - internal utility scripts + +The `epm` script uses dynamic helper loading: +```bash +load_helper epm-sh-functions # Load shared functions +load_helper epm-install # Load specific command +``` + +### Play Scripts (`play.d/`) + +Scripts for installing applications from official sources (not repositories). Each script: +- Sources `common.sh` for shared functionality +- Defines: `PKGNAME`, `DESCRIPTION`, `VERSION`, `URL`, `SUPPORTEDARCHES` +- Handles `--description`, `--package-name`, `--installed`, `--remove`, `--info`, `--update`, `--run` +- Downloads and installs packages using `epm` commands + +Example structure: +```bash +BASEPKGNAME=AppName +SUPPORTEDARCHES="x86_64" +DESCRIPTION="App description" +. $(dirname $0)/common.sh +# Download and install logic +``` + +### Repack Scripts (`repack.d/`) + +Scripts for converting packages between formats (rpm↔deb) with distro-specific fixes. + +### Pack Scripts (`pack.d/`) + +Scripts for creating packages from tarballs/binaries. Work in temp directory, return tarball via `return_tar`. + +### Prescription Scripts (`prescription.d/`) + +Meta-package recipes that install groups of related packages. + +## Key Functions in common.sh + +- `epm` - wrapper that shows commands being run +- `eget` - wget-like download utility (`epm tool eget`) +- `get_github_url` / `get_github_tag` - GitHub release helpers +- `install_pkgurl` / `install_pack_pkgurl` - package installation +- `is_glibc_enough` / `is_stdcpp_enough` - version requirement checks +- `fatal` / `info` - output helpers + +## Adding New Play Scripts + +1. Create `play.d/appname.sh` +2. Define required variables (PKGNAME, DESCRIPTION, SUPPORTEDARCHES) +3. Source `common.sh` +4. Implement download/version detection logic +5. Call `install_pkgurl` or `install_pack_pkgurl` + +## Shell Compatibility + +All scripts must be POSIX-compatible (avoid bashisms). Use `#!/bin/sh` for most scripts. The `check_code.sh` script verifies this with `checkbashisms`. diff --git a/CLAUDE.ru.md b/CLAUDE.ru.md new file mode 100644 index 000000000..ca837d660 --- /dev/null +++ b/CLAUDE.ru.md @@ -0,0 +1,103 @@ +# CLAUDE.ru.md + +Π­Ρ‚ΠΎΡ‚ Ρ„Π°ΠΉΠ» содСрТит руководство для Claude Code (claude.ai/code) ΠΏΡ€ΠΈ Ρ€Π°Π±ΠΎΡ‚Π΅ с ΠΊΠΎΠ΄ΠΎΠΌ Π² этом Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ. + +## ΠžΠ±Π·ΠΎΡ€ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° + +EEPM (Etersoft EPM) β€” ΡƒΠ½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½Π°Ρ ΠΎΠ±Ρ‘Ρ€Ρ‚ΠΊΠ° Π½Π°Π΄ ΠΏΠ°ΠΊΠ΅Ρ‚Π½Ρ‹ΠΌΠΈ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π°ΠΌΠΈ, ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‰Π°Ρ Π΅Π΄ΠΈΠ½Ρ‹ΠΉ интСрфСйс для всСх дистрибутивов Linux. ΠžΠ±ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅Ρ‚ Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ ΠΏΠ°ΠΊΠ΅Ρ‚Π½Ρ‹Π΅ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Ρ‹ (apt, yum, dnf, zypper, pacman ΠΈ Π΄Ρ€.) Π΅Π΄ΠΈΠ½Ρ‹ΠΌΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌΠΈ. + +ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹: +- `epm` β€” ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠ°ΠΊΠ΅Ρ‚Π°ΠΌΠΈ (установка, ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅, поиск ΠΈ Ρ‚.Π΄.) +- `serv` β€” ΠΎΠ±Ρ‘Ρ€Ρ‚ΠΊΠ° для управлСния сСрвисами (systemd, sysvinit) +- `distr_info` β€” ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π° опрСдСлСния дистрибутива + +## Настройка для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ + +Π‘Π±ΠΎΡ€ΠΊΠ° Π½Π΅ трСбуСтся β€” это ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ Π½Π° shell-скриптах. Запуск прямо ΠΈΠ· checkout: +```bash +./bin/epm --help +./bin/epm play --list +``` + +## ВСстированиС + +Запуск ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… тСстов ΠΈΠ· ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π° `tests/`: +```bash +./tests/test_distr_info.sh +./tests/test_versions.sh +./tests/test_json.sh +``` + +ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° качСства ΠΊΠΎΠ΄Π°: +```bash +./check_code.sh # Запуск shellcheck ΠΈ checkbashisms для всСх скриптов +./check_code.sh bin/epm-install # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° +``` + +## АрхитСктура + +### ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ скрипты (`bin/`) + +- `epm` β€” главная Ρ‚ΠΎΡ‡ΠΊΠ° Π²Ρ…ΠΎΠ΄Π°, Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ Ρ…Π΅Π»ΠΏΠ΅Ρ€Ρ‹ Ρ‡Π΅Ρ€Π΅Π· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ `load_helper` +- `epm-sh-functions` β€” ΠΎΠ±Ρ‰ΠΈΠ΅ shell-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ (Π²Ρ‹Π²ΠΎΠ΄, Ρ†Π²Π΅Ρ‚Π°, ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ tty) +- `epm-*` β€” Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΊΠΎΠΌΠ°Π½Π΄ (epm-install, epm-remove, epm-search ΠΈ Π΄Ρ€.) +- `serv` β€” Ρ‚ΠΎΡ‡ΠΊΠ° Π²Ρ…ΠΎΠ΄Π° для управлСния сСрвисами +- `serv-*` β€” Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΊΠΎΠΌΠ°Π½Π΄ сСрвисов +- `distr_info` β€” Π°Π²Ρ‚ΠΎΠ½ΠΎΠΌΠ½Ρ‹ΠΉ скрипт опрСдСлСния дистрибутива +- `tools_*` β€” Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠ΅ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ + +Π‘ΠΊΡ€ΠΈΠΏΡ‚ `epm` ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡Π΅ΡΠΊΡƒΡŽ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ Ρ…Π΅Π»ΠΏΠ΅Ρ€ΠΎΠ²: +```bash +load_helper epm-sh-functions # Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° ΠΎΠ±Ρ‰ΠΈΡ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ +load_helper epm-install # Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΉ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ +``` + +### Play-скрипты (`play.d/`) + +Π‘ΠΊΡ€ΠΈΠΏΡ‚Ρ‹ для установки ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ с ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Ρ… сайтов (Π½Π΅ ΠΈΠ· Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠ΅Π²). ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ скрипт: +- ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ `common.sh` для ΠΎΠ±Ρ‰Π΅ΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ +- ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅Ρ‚: `PKGNAME`, `DESCRIPTION`, `VERSION`, `URL`, `SUPPORTEDARCHES` +- ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚: `--description`, `--package-name`, `--installed`, `--remove`, `--info`, `--update`, `--run` +- Π‘ΠΊΠ°Ρ‡ΠΈΠ²Π°Π΅Ρ‚ ΠΈ устанавливаСт ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ Ρ‡Π΅Ρ€Π΅Π· ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ `epm` + +Випичная структура: +```bash +BASEPKGNAME=AppName +SUPPORTEDARCHES="x86_64" +DESCRIPTION="ОписаниС прилоТСния" +. $(dirname $0)/common.sh +# Π›ΠΎΠ³ΠΈΠΊΠ° скачивания ΠΈ установки +``` + +### Repack-скрипты (`repack.d/`) + +Π‘ΠΊΡ€ΠΈΠΏΡ‚Ρ‹ для ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ² ΠΌΠ΅ΠΆΠ΄Ρƒ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π°ΠΌΠΈ (rpm↔deb) с дистрибутив-спСцифичными исправлСниями. + +### Pack-скрипты (`pack.d/`) + +Π‘ΠΊΡ€ΠΈΠΏΡ‚Ρ‹ для создания ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ² ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²ΠΎΠ²/Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠΎΠ². Π Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ Π²ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΌ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‚ Π°Ρ€Ρ…ΠΈΠ² Ρ‡Π΅Ρ€Π΅Π· `return_tar`. + +### Prescription-скрипты (`prescription.d/`) + +Π Π΅Ρ†Π΅ΠΏΡ‚Ρ‹ ΠΌΠ΅Ρ‚Π°-ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ² для установки Π³Ρ€ΡƒΠΏΠΏ связанных ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ². + +## ΠšΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π² common.sh + +- `epm` β€” ΠΎΠ±Ρ‘Ρ€Ρ‚ΠΊΠ°, ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‰Π°Ρ выполняСмыС ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ +- `eget` β€” wget-подобная ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π° Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ (`epm tool eget`) +- `get_github_url` / `get_github_tag` β€” Ρ…Π΅Π»ΠΏΠ΅Ρ€Ρ‹ для Ρ€Π΅Π»ΠΈΠ·ΠΎΠ² GitHub +- `install_pkgurl` / `install_pack_pkgurl` β€” установка ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ² +- `is_glibc_enough` / `is_stdcpp_enough` β€” ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠΉ ΠΊ вСрсиям +- `fatal` / `info` β€” Ρ…Π΅Π»ΠΏΠ΅Ρ€Ρ‹ Π²Ρ‹Π²ΠΎΠ΄Π° + +## Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½ΠΎΠ²Ρ‹Ρ… play-скриптов + +1. Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ `play.d/appname.sh` +2. ΠžΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ (PKGNAME, DESCRIPTION, SUPPORTEDARCHES) +3. ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ `common.sh` +4. Π Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π»ΠΎΠ³ΠΈΠΊΡƒ скачивания/опрСдСлСния вСрсии +5. Π’Ρ‹Π·Π²Π°Ρ‚ΡŒ `install_pkgurl` ΠΈΠ»ΠΈ `install_pack_pkgurl` + +## Π‘ΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ с shell + +ВсС скрипты Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ POSIX-совмСстимыми (ΠΈΠ·Π±Π΅Π³Π°Ρ‚ΡŒ башизмов). Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ `#!/bin/sh` для Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²Π° скриптов. Π‘ΠΊΡ€ΠΈΠΏΡ‚ `check_code.sh` провСряСт это Ρ‡Π΅Ρ€Π΅Π· `checkbashisms`. From 671bc31529a21b06f55d7173f5a0d8dd3b0c93c9 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 18:12:28 +0300 Subject: [PATCH 11/26] get_json_value: fix error code propagation on download failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous implementation piped eget output directly to parse_json_value, which lost the exit code from eget. Now we capture eget output first and return early on failure, preserving the error code. πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- play.d/common.sh | 4 +++- repack.d/common.sh | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/play.d/common.sh b/play.d/common.sh index b481badd0..277f431db 100755 --- a/play.d/common.sh +++ b/play.d/common.sh @@ -166,7 +166,9 @@ parse_json_value() get_json_value() { if is_url "$1" ; then - eget -q -O- "$1" | parse_json_value "$2" + local toutput + toutput="$(eget -q -O- "$1")" || return + echo "$toutput" | parse_json_value "$2" else [ -s "$1" ] || fatal "File $1 is missed, can't get json" parse_json_value "$2" < "$1" diff --git a/repack.d/common.sh b/repack.d/common.sh index 817e2d2f8..2eda325bb 100755 --- a/repack.d/common.sh +++ b/repack.d/common.sh @@ -94,7 +94,9 @@ parse_json_value() get_json_value() { if is_url "$1" ; then - eget -q -O- "$1" | parse_json_value "$2" + local toutput + toutput="$(eget -q -O- "$1")" || return + echo "$toutput" | parse_json_value "$2" else [ -s "$1" ] || fatal "File $1 is missed, can't get json" parse_json_value "$2" < "$1" From 80708a7e8550dd292ee11892d5f627b384f30029 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 18:14:20 +0300 Subject: [PATCH 12/26] eget: fix double downloading on error --- bin/tools_eget | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bin/tools_eget b/bin/tools_eget index 32799746f..a153d456a 100755 --- a/bin/tools_eget +++ b/bin/tools_eget @@ -1161,6 +1161,8 @@ url_scat() { local URL="$1" download_with_mirroring __wget "$URL" -O- && return + local RES=$? + [ -n "$quiet" ] || return $RES unset_quiet download_with_mirroring __wget "$URL" -O- } @@ -1219,6 +1221,8 @@ url_scat() { local URL="$1" download_with_mirroring __curl "$URL" --output - && return + local RES=$? + [ -n "$quiet" ] || return $RES unset_quiet download_with_mirroring __curl "$URL" --output - } @@ -1279,6 +1283,8 @@ url_scat() { local URL="$1" download_with_mirroring __aria2 -x1 -s1 --allow-piece-length-change=false -o - "$URL" && return + local RES=$? + [ -n "$quiet" ] || return $RES unset_quiet download_with_mirroring __aria2 -x1 -s1 --allow-piece-length-change=false -o - "$URL" } @@ -1337,6 +1343,8 @@ url_scat() fatal "Improve me (via temp. file?)" local URL="$1" download_with_mirroring __axel -o - "$URL" && return + local RES=$? + [ -n "$quiet" ] || return $RES unset_quiet download_with_mirroring __axel -o - "$URL" } From 5ed61f11fc43048698650ab6960264fda5d8af04 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 18:38:44 +0300 Subject: [PATCH 13/26] epm play.d/common.sh: make info() print to stderr --- play.d/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/play.d/common.sh b/play.d/common.sh index 277f431db..67c370aaf 100755 --- a/play.d/common.sh +++ b/play.d/common.sh @@ -15,7 +15,7 @@ fatal() info() { - echo "$*" + echo "$*" >&2 } [ -n "$BIGTMPDIR" ] || [ -d "/var/tmp" ] && BIGTMPDIR="/var/tmp" || BIGTMPDIR="/tmp" From a726e5e0b3b3ddf823255b30d687aeac13be9435 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 20:58:47 +0300 Subject: [PATCH 14/26] epm play.d/common.sh: add fetch_url() helper --- play.d/common.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/play.d/common.sh b/play.d/common.sh index 67c370aaf..7c09866a1 100755 --- a/play.d/common.sh +++ b/play.d/common.sh @@ -91,6 +91,14 @@ eget() epm tool eget "$@" } +fetch_url() +{ + local URL + [ "$1" = "-O-" ] && URL="$2" || URL="$1" + info "Fetching $URL ..." + $EPM --quiet tool eget -q "$@" +} + is_supported_arch() { @@ -167,7 +175,7 @@ get_json_value() { if is_url "$1" ; then local toutput - toutput="$(eget -q -O- "$1")" || return + toutput="$(fetch_url -O- "$1")" || return echo "$toutput" | parse_json_value "$2" else [ -s "$1" ] || fatal "File $1 is missed, can't get json" From 5db5aa0cc63ed88d598be2daf55898c820c570c9 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 21:36:09 +0300 Subject: [PATCH 15/26] epm play claude: get GCS_BUCKET dynamically, fix typos --- play.d/claude.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/play.d/claude.sh b/play.d/claude.sh index 23898cdaf..da935d5d8 100755 --- a/play.d/claude.sh +++ b/play.d/claude.sh @@ -23,16 +23,17 @@ os="linux" platform="${os}-${arch}" -GCS_BUCKET="https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases" -#GCS_BUCKET="$(eget -O- https://claude.ai/install.sh | grep "^GCS_BUCKET=" | sed -e 's|^GCS_BUCKET=||' -e 's|^"||' -e 's|"$||')" -#[ -n "$GCS_BUCKET" ] || fatal "Can't download https://claude.ai/install.sh" +#GCS_BUCKET="https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases" +GCS_BUCKET="$(fetch_url -O- https://claude.ai/install.sh | grep "^GCS_BUCKET=" | sed -e 's|^GCS_BUCKET=||' -e 's|^"||' -e 's|"$||')" +[ -n "$GCS_BUCKET" ] || fatal "Can't download https://claude.ai/install.sh" if [ "$VERSION" = "*" ] ; then - VERSION="$(eget -O- "$GCS_BUCKET/stable")" || fatal "Can't get version from $GCS_BUCKET/stable" + VERSION="$(fetch_url -O- "$GCS_BUCKET/stable")" || fatal "Can't get version from $GCS_BUCKET/stable" + [ -n "$VERSION" ] || fatal "Got empty version from $GCS_BUCKET/stable" fi # ["platforms","linux-x64","checksum"] -checksum="$(get_json_value "$GCS_BUCKET/$version/manifest.json" '["platforms","'$platform'","checksum"]')" +checksum="$(get_json_value "$GCS_BUCKET/$VERSION/manifest.json" '["platforms","'$platform'","checksum"]')" || fatal "Can't get checksum" PKGURL="$GCS_BUCKET/$VERSION/$platform/claude" From 7107a30393c19128acd5b6b499ccc60493e24177 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 22:01:50 +0300 Subject: [PATCH 16/26] epm play.d/common.sh: add --quiet support to epm() wrapper --- play.d/common.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/play.d/common.sh b/play.d/common.sh index 7c09866a1..b23dcf170 100755 --- a/play.d/common.sh +++ b/play.d/common.sh @@ -79,6 +79,7 @@ epm() { #if [ "$1" = "tool" ] ; then # __showcmd_shifted 1 "$@" + [ "$1" = "--quiet" ] && shift && $EPM --quiet "$@" && return if [ "$1" != "print" ] && [ "$1" != "tool" ] && [ "$1" != "status" ] ; then showcmd "$(basename $EPM) $*" fi @@ -167,7 +168,7 @@ parse_json_value() { local field="$1" echo "$field" | grep -q -E "^\[" || field='["'$field'"]' - epm tool json -b | grep -m1 -F "$field" | sed -e 's|.*[[:space:]]||' | sed -e 's|"\(.*\)"|\1|g' + epm --quiet tool json -b | grep -m1 -F "$field" | sed -e 's|.*[[:space:]]||' | sed -e 's|"\(.*\)"|\1|g' } # URL/file ["version"] From 53e416e97d18a83ec9dac10ac6506178f6583bac Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 17 Dec 2025 22:21:23 +0300 Subject: [PATCH 17/26] epm play: fetch_url() always outputs to stdout --- play.d/claude.sh | 4 ++-- play.d/common.sh | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/play.d/claude.sh b/play.d/claude.sh index da935d5d8..1e4f373cd 100755 --- a/play.d/claude.sh +++ b/play.d/claude.sh @@ -24,11 +24,11 @@ os="linux" platform="${os}-${arch}" #GCS_BUCKET="https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases" -GCS_BUCKET="$(fetch_url -O- https://claude.ai/install.sh | grep "^GCS_BUCKET=" | sed -e 's|^GCS_BUCKET=||' -e 's|^"||' -e 's|"$||')" +GCS_BUCKET="$(fetch_url https://claude.ai/install.sh | grep "^GCS_BUCKET=" | sed -e 's|^GCS_BUCKET=||' -e 's|^"||' -e 's|"$||')" [ -n "$GCS_BUCKET" ] || fatal "Can't download https://claude.ai/install.sh" if [ "$VERSION" = "*" ] ; then - VERSION="$(fetch_url -O- "$GCS_BUCKET/stable")" || fatal "Can't get version from $GCS_BUCKET/stable" + VERSION="$(fetch_url "$GCS_BUCKET/stable")" || fatal "Can't get version from $GCS_BUCKET/stable" [ -n "$VERSION" ] || fatal "Got empty version from $GCS_BUCKET/stable" fi diff --git a/play.d/common.sh b/play.d/common.sh index b23dcf170..c15a9acc3 100755 --- a/play.d/common.sh +++ b/play.d/common.sh @@ -94,10 +94,8 @@ eget() fetch_url() { - local URL - [ "$1" = "-O-" ] && URL="$2" || URL="$1" - info "Fetching $URL ..." - $EPM --quiet tool eget -q "$@" + info "Fetching $1 ..." + $EPM --quiet tool eget -q -O- "$1" } @@ -176,7 +174,7 @@ get_json_value() { if is_url "$1" ; then local toutput - toutput="$(fetch_url -O- "$1")" || return + toutput="$(fetch_url "$1")" || return echo "$toutput" | parse_json_value "$2" else [ -s "$1" ] || fatal "File $1 is missed, can't get json" From 881ad0fa77ffd5bedf0b8f1bb680b1a9487ac79a Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Fri, 19 Dec 2025 00:26:58 +0300 Subject: [PATCH 18/26] epm tool json --get-json-value: add helper to fetch JSON value from URL --- bin/epm-tool | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bin/epm-tool b/bin/epm-tool index 3fc967a7e..512baaba5 100644 --- a/bin/epm-tool +++ b/bin/epm-tool @@ -59,6 +59,16 @@ epm_tool() estrlist "$@" ;; "json") # HELPCMD: json operations + # epm tool json --get-json-value URL field + if [ "$1" = "--get-json-value" ] ; then + local url="$2" + local field="$3" + [ -n "$url" ] || fatal "Use: epm tool json --get-json-value URL field" + [ -n "$field" ] || fatal "Use: epm tool json --get-json-value URL field" + echo "$field" | grep -q -E "^\[" || field='["'$field'"]' + eget -q -O- "$url" | $CMDSHELL $SHAREDIR/tools_json -b | grep -m1 -F "$field" | sed -e 's|.*[[:space:]]||' | sed -e 's|"\(.*\)"|\1|g' + return + fi showcmd json "$@" $CMDSHELL $SHAREDIR/tools_json "$@" ;; From 4a8d65206f9525b1167baf8858196dbb663d5e63 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Fri, 19 Dec 2025 00:28:45 +0300 Subject: [PATCH 19/26] epm play sunshine: use API instead of HTML page (fix Anubis block) --- play.d/sunshine.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/play.d/sunshine.sh b/play.d/sunshine.sh index 031599c9a..51567cbd0 100644 --- a/play.d/sunshine.sh +++ b/play.d/sunshine.sh @@ -15,8 +15,8 @@ is_openssl_enough 3 || fatal "There is no needed OpenSSL 3 in the system." arch=$(epm print info -a) # TODO: common way to install from Fedora copr -# FIXME: Anubis doesn't allow download -BUILD_ID=$(eget --list https://copr.fedorainfracloud.org/coprs/lizardbyte/stable/package/Sunshine/ | grep -o 'build/[0-9]\+' | cut -d/ -f2 | sort -n | tail -n1) +# use API instead of HTML page (Anubis bot protection blocks scraping) +BUILD_ID=$(epm tool json --get-json-value "https://copr.fedorainfracloud.org/api_3/build/list?ownername=lizardbyte&projectname=stable&packagename=Sunshine&status=succeeded" '["items",0,"id"]') PKGURL=$(eget --list --latest https://download.copr.fedorainfracloud.org/results/lizardbyte/stable/fedora-41-$arch/0$BUILD_ID-Sunshine/ "Sunshine-*.$arch.rpm") From 02644e36a2c370bd8d8be44dffc8527a0c2d0a71 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Fri, 19 Dec 2025 02:03:22 +0300 Subject: [PATCH 20/26] tests: add fetch_url error handling test --- tests/test_fetch_url.sh | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100755 tests/test_fetch_url.sh diff --git a/tests/test_fetch_url.sh b/tests/test_fetch_url.sh new file mode 100755 index 000000000..fc99d5fc8 --- /dev/null +++ b/tests/test_fetch_url.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +# Test that fetch_url returns error code on failure + +TESTDIR=$(realpath "$(dirname "$0")") +export SHAREDIR="$TESTDIR/../bin" +export PATH="$SHAREDIR:$PATH" + +. "$SHAREDIR/epm-sh-functions" + +test_fetch_url_success() +{ + local result + result="$(fetch_url "https://httpbin.org/get")" || { + echo "FAILED: fetch_url should succeed for valid URL" + return 1 + } + [ -n "$result" ] || { + echo "FAILED: fetch_url returned empty result for valid URL" + return 1 + } + echo "OK: fetch_url succeeds for valid URL" +} + +test_fetch_url_failure() +{ + local result + result="$(fetch_url "https://httpbin.org/status/404")" && { + echo "FAILED: fetch_url should fail for 404 URL" + return 1 + } + echo "OK: fetch_url returns error for 404 URL" +} + +test_fetch_url_or_return() +{ + inner_func() + { + local res + res="$(fetch_url "https://httpbin.org/status/404")" || return 1 + echo "should not reach here" + return 0 + } + + inner_func && { + echo "FAILED: || return should propagate error" + return 1 + } + echo "OK: || return works correctly with fetch_url" +} + +echo "Testing fetch_url error handling..." +test_fetch_url_success +test_fetch_url_failure +test_fetch_url_or_return From 2a97dca7fe6d28a8aaac9efba64071d7fbab9775 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Fri, 19 Dec 2025 02:11:59 +0300 Subject: [PATCH 21/26] epm-sh-functions: implement fetch_url() and use it --- bin/epm-epm_install | 2 +- bin/epm-play | 2 +- bin/epm-sh-altlinux | 6 ++---- bin/epm-sh-functions | 6 ++++++ bin/epm-update | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/bin/epm-epm_install b/bin/epm-epm_install index ce71c1776..e7ed04c95 100644 --- a/bin/epm-epm_install +++ b/bin/epm-epm_install @@ -87,7 +87,7 @@ __epm_korinf_install_eepm() # TODO: installing via task # as now, can't install one package from task if false && [ "$BASEDISTRNAME" = "alt" ] && [ -z "$direct" ] ; then - local task="$(docmd eget -O- https://eepm.ru/vendor/alt/task)" + local task="$(fetch_url https://eepm.ru/vendor/alt/task)" if [ -n "$task" ] ; then docmd epm install $task:eepm return diff --git a/bin/epm-play b/bin/epm-play index dae62a81c..7d62cb59a 100644 --- a/bin/epm-play +++ b/bin/epm-play @@ -327,7 +327,7 @@ __get_latest_package_version() [ -n "$pkg" ] || return 1 - ver="$(epm tool eget -q -O- "https://eepm.ru/app-versions/$pkg" 2>/dev/null)" + ver="$(fetch_url "https://eepm.ru/app-versions/$pkg")" if [ -n "$ver" ] ; then echo "$ver" diff --git a/bin/epm-sh-altlinux b/bin/epm-sh-altlinux index c3c21b849..d30055bc6 100644 --- a/bin/epm-sh-altlinux +++ b/bin/epm-sh-altlinux @@ -50,8 +50,7 @@ get_task_packages_list() local tn="$1" local res - showcmd "eget -q -O- $ALTTASKURL/$tn/plan/add-bin" - res="$(eget -q -O- $ALTTASKURL/$tn/plan/add-bin)" || return + res="$(fetch_url $ALTTASKURL/$tn/plan/add-bin)" || return echo "$res" | cut -f1-3 | grep -E "(noarch|$DISTRARCH)$" | cut -f1 } @@ -60,8 +59,7 @@ get_task_arepo_packages_list() local tn="$1" local res - showcmd "eget -q -O- $ALTTASKURL/$tn/plan/arepo-add-x86_64-i586" - res="$(eget -q -O- $ALTTASKURL/$tn/plan/arepo-add-x86_64-i586)" || return + res="$(fetch_url $ALTTASKURL/$tn/plan/arepo-add-x86_64-i586)" || return echo "$res" | cut -f1 } diff --git a/bin/epm-sh-functions b/bin/epm-sh-functions index f321205e2..dd66edf1e 100644 --- a/bin/epm-sh-functions +++ b/bin/epm-sh-functions @@ -794,6 +794,12 @@ eget() $EGET "$@" } +fetch_url() +{ + info "Fetching $1 ..." + eget -q -O- "$1" +} + # FIXME: sudocmd_eget() { diff --git a/bin/epm-update b/bin/epm-update index 8e5983fe0..5590ca609 100644 --- a/bin/epm-update +++ b/bin/epm-update @@ -28,7 +28,7 @@ get_latest_version() URL="https://eepm.ru/app-versions" #update_url_if_need_mirrored local var - var="$(epm tool eget -q -O- "$URL/$1")" || return + var="$(fetch_url "$URL/$1")" || return echo "$var" | head -n1 | cut -d" " -f1 } From 634385bc49ee666bcefca118c44b0bd2038b6a29 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Fri, 19 Dec 2025 02:23:50 +0300 Subject: [PATCH 22/26] implement parse_json_value/values and change get_json_value/values() to use it; fix all places where it were used --- bin/epm-desktop | 11 +++-------- bin/epm-provides | 2 +- bin/epm-requires | 4 ++-- bin/epm-sh-functions | 33 +++++++++++++++++++++++++++++---- bin/epm-tool | 3 +-- 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/bin/epm-desktop b/bin/epm-desktop index 5831c06df..b7d1d2e71 100644 --- a/bin/epm-desktop +++ b/bin/epm-desktop @@ -61,9 +61,7 @@ get_value() local de_name="$1" local key="$2" - local json="$(get_json $de_name)" - - get_json_value "$key" < "$json" + get_json $de_name | parse_json_value "$key" } @@ -73,9 +71,7 @@ get_values() local de_name="$1" local key="$2" - local json="$(get_json $de_name)" - - get_json_values "$key" < "$json" | xargs + get_json $de_name | parse_json_values "$key" | xargs } @@ -102,8 +98,7 @@ get_repo_version() local package=$(get_main_package "$de_name") - info "Trying get info of package $package from remote ALT DB ..." - local latest_version="$(eget --quiet --timeout 10 -O- $(__get_api_url $package) | get_json_value '["packages",0,"version"]')" + local latest_version="$(get_json_value "$(__get_api_url $package)" '["packages",0,"version"]')" if [ -n "$latest_version" ] ; then echo "$latest_version" diff --git a/bin/epm-provides b/bin/epm-provides index 4ded0b38a..7c81c9915 100644 --- a/bin/epm-provides +++ b/bin/epm-provides @@ -77,7 +77,7 @@ case $PMTYPE in if is_installed $pkg_names ; then CMD="rpm -q --provides" else - docmd apm system info --full --format=json $pkg_names | get_json_values "data packageInfo provides" + docmd apm system info --full --format=json $pkg_names | parse_json_values "data packageInfo provides" return fi ;; diff --git a/bin/epm-requires b/bin/epm-requires index 0312daac6..1550a0782 100644 --- a/bin/epm-requires +++ b/bin/epm-requires @@ -147,9 +147,9 @@ case $PMTYPE in return else if [ -n "$short" ] ; then - docmd apm system info --full --format=json $pkg_names | get_json_values "data packageInfo depends" | __epm_filter_out_base_alt_reqs | sed -e "s| .*||" + docmd apm system info --full --format=json $pkg_names | parse_json_values "data packageInfo depends" | __epm_filter_out_base_alt_reqs | sed -e "s| .*||" else - docmd apm system info --full --format=json $pkg_names | get_json_values "data packageInfo depends" | __epm_filter_out_base_alt_reqs + docmd apm system info --full --format=json $pkg_names | parse_json_values "data packageInfo depends" | __epm_filter_out_base_alt_reqs fi return fi diff --git a/bin/epm-sh-functions b/bin/epm-sh-functions index dd66edf1e..94cd53e41 100644 --- a/bin/epm-sh-functions +++ b/bin/epm-sh-functions @@ -842,22 +842,47 @@ print_sha256sum() done } - -# copied from parse_json_value from play.d/common.sh -get_json_value() +parse_json_value() { local field="$1" echo "$field" | grep -q -E "^\[" || field='["'$field'"]' epm --quiet tool json -b | grep -m1 -F "$field" | sed -e 's|.*\][[:space:]]||' | sed -e 's|"\(.*\)"|\1|g' } -get_json_values() +# URL/file ["version"] +get_json_value() +{ + if is_url "$1" ; then + local toutput + toutput="$(fetch_url "$1")" || return + echo "$toutput" | parse_json_value "$2" + else + [ -s "$1" ] || fatal "File $1 is missed, can't get json" + parse_json_value "$2" < "$1" + fi +} + +parse_json_values() { local field="$1" echo "$field" | grep -q -E "^\[" || field="\[$(echo "$field" | sed 's/[^ ]*/"&"/g' | sed 's/ /,/g'),[0-9]*\]" epm --quiet tool json -b | grep "^$field" | sed -e 's|.*\][[:space:]]||' | sed -e 's|"\(.*\)"|\1|g' } +# URL/file ["version"] +get_json_values() +{ + if is_url "$1" ; then + local toutput + toutput="$(fetch_url "$1")" || return + echo "$toutput" | parse_json_values "$2" + else + [ -s "$1" ] || fatal "File $1 is missed, can't get json" + parse_json_values "$2" < "$1" + fi +} + + __epm_assure_7zip() { # install 7zip in any case (can be used) diff --git a/bin/epm-tool b/bin/epm-tool index 512baaba5..4b9094935 100644 --- a/bin/epm-tool +++ b/bin/epm-tool @@ -65,8 +65,7 @@ epm_tool() local field="$3" [ -n "$url" ] || fatal "Use: epm tool json --get-json-value URL field" [ -n "$field" ] || fatal "Use: epm tool json --get-json-value URL field" - echo "$field" | grep -q -E "^\[" || field='["'$field'"]' - eget -q -O- "$url" | $CMDSHELL $SHAREDIR/tools_json -b | grep -m1 -F "$field" | sed -e 's|.*[[:space:]]||' | sed -e 's|"\(.*\)"|\1|g' + get_json_value "$url" "$field" return fi showcmd json "$@" From ba955be26d64837eb5f74b4e22565528e385f792 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Fri, 19 Dec 2025 02:36:17 +0300 Subject: [PATCH 23/26] get_json_value: use epm tool json --get-json-value --- pack.d/common.sh | 7 +------ play.d/common.sh | 9 +-------- repack.d/common.sh | 9 +-------- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/pack.d/common.sh b/pack.d/common.sh index a7ed880b8..09421fe1e 100755 --- a/pack.d/common.sh +++ b/pack.d/common.sh @@ -89,12 +89,7 @@ parse_json_value() # URL/file ["version"] get_json_value() { - if is_url "$1" ; then - eget -q -O- "$1" | parse_json_value "$2" - else - [ -s "$1" ] || fatal "File $1 is missed, can't get json" - parse_json_value "$2" < "$1" - fi + epm tool json --get-json-value "$1" "$2" } diff --git a/play.d/common.sh b/play.d/common.sh index c15a9acc3..f2f1c4cd7 100755 --- a/play.d/common.sh +++ b/play.d/common.sh @@ -172,14 +172,7 @@ parse_json_value() # URL/file ["version"] get_json_value() { - if is_url "$1" ; then - local toutput - toutput="$(fetch_url "$1")" || return - echo "$toutput" | parse_json_value "$2" - else - [ -s "$1" ] || fatal "File $1 is missed, can't get json" - parse_json_value "$2" < "$1" - fi + epm tool json --get-json-value "$1" "$2" } snap_get_pkgurl() diff --git a/repack.d/common.sh b/repack.d/common.sh index 2eda325bb..8fccba23f 100755 --- a/repack.d/common.sh +++ b/repack.d/common.sh @@ -93,14 +93,7 @@ parse_json_value() # URL/file ["version"] get_json_value() { - if is_url "$1" ; then - local toutput - toutput="$(eget -q -O- "$1")" || return - echo "$toutput" | parse_json_value "$2" - else - [ -s "$1" ] || fatal "File $1 is missed, can't get json" - parse_json_value "$2" < "$1" - fi + epm tool json --get-json-value "$1" "$2" } From b7f022eeab8bb783dcc0f231f8398c6e9e12b847 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Fri, 19 Dec 2025 02:39:57 +0300 Subject: [PATCH 24/26] epm tool json: add --help --- bin/epm-tool | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/bin/epm-tool b/bin/epm-tool index 4b9094935..edf0c4220 100644 --- a/bin/epm-tool +++ b/bin/epm-tool @@ -59,6 +59,23 @@ epm_tool() estrlist "$@" ;; "json") # HELPCMD: json operations + if [ "$1" = "--help" ] || [ "$1" = "-h" ] ; then + echo "epm tool json - JSON parsing tool" + echo + echo "Usage:" + echo " epm tool json [options] - parse JSON from stdin" + echo " epm tool json --get-json-value URL field - get field value from JSON URL" + echo + echo "Options:" + echo " -b Brief output (leaf only + prune empty)" + echo " -l Leaf only" + echo " -p Prune empty" + echo + echo "Examples:" + echo " echo '{\"version\":\"1.0\"}' | epm tool json -b" + echo " epm tool json --get-json-value https://api.example.com/info.json version" + return + fi # epm tool json --get-json-value URL field if [ "$1" = "--get-json-value" ] ; then local url="$2" From b8f9a6a404ce16adf05188b17485fcbb271b99cb Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Fri, 19 Dec 2025 02:56:24 +0300 Subject: [PATCH 25/26] epm play: fix viber --- play.d/viber.sh | 3 ++- repack.d/viber.sh | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/play.d/viber.sh b/play.d/viber.sh index 3a39de5f6..f9d5094c6 100755 --- a/play.d/viber.sh +++ b/play.d/viber.sh @@ -10,6 +10,7 @@ URL="https://viber.com" warn_version_is_not_supported -PKGURL="https://download.cdn.viber.com/desktop/Linux/viber.AppImage" +#PKGURL="https://download.cdn.viber.com/desktop/Linux/viber.AppImage" +PKGURL="https://download.cdn.viber.com/desktop/Linux/viber.rpm" install_pkgurl diff --git a/repack.d/viber.sh b/repack.d/viber.sh index 8cd8daba4..ee5cb05d5 100755 --- a/repack.d/viber.sh +++ b/repack.d/viber.sh @@ -11,6 +11,8 @@ PRODUCTDIR=/opt/viber # handle AppImage if [ -f ".$PRODUCTDIR/.DirIcon" ] ; then + # remove bundled libEGL_mesa which requires unavailable libglapi.so.0 + remove_file $PRODUCTDIR/usr/lib/libEGL_mesa.so.0 ignore_lib_requires libQt6LabsSettings.so.6 libQt6LabsSharedImage.so.6 libQt6LabsWavefrontMesh.so.6 libQt6WebEngineQuickDelegatesQml.so.6 libQt6LabsQmlModels.so.6 add_libs_requires exit From cdd387eb78769975fcc0fcdf9b7ce419a047ad5b Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Fri, 19 Dec 2025 14:09:02 +0300 Subject: [PATCH 26/26] epm play: add virtualbox-bin (install VirtualBox from official .run) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- pack.d/virtualbox.sh | 85 ++++++++++++++++++++++++++++++++++++++ play.d/virtualbox-bin.sh | 26 ++++++++++++ repack.d/VirtualBox-7.2.sh | 22 ++++++++++ repack.d/virtualbox.sh | 14 +++++++ 4 files changed, 147 insertions(+) create mode 100644 pack.d/virtualbox.sh create mode 100755 play.d/virtualbox-bin.sh create mode 100755 repack.d/VirtualBox-7.2.sh create mode 100644 repack.d/virtualbox.sh diff --git a/pack.d/virtualbox.sh b/pack.d/virtualbox.sh new file mode 100644 index 000000000..2dd7b5840 --- /dev/null +++ b/pack.d/virtualbox.sh @@ -0,0 +1,85 @@ +#!/bin/sh + +TAR="$1" +RETURNTARNAME="$2" + +. $(dirname $0)/common.sh + +# VirtualBox-7.2.4-170995-Linux_amd64.run +BASENAME=$(basename "$TAR" .run) +VERSION=$(echo "$BASENAME" | sed -e 's|VirtualBox-||' -e 's|-Linux_amd64||') +# 7.2.4-170995 -> 7.2.4 +VERSION=$(echo "$VERSION" | sed -e 's|-[0-9]*$||') + +PKGNAME=$PRODUCT-$VERSION + +# Extract .run without executing +chmod +x "$TAR" +"$TAR" --noexec --nox11 --target vbox-installer || fatal "Can't extract VirtualBox installer" + +cd vbox-installer || fatal "Can't enter vbox-installer" + +# Extract the main archive +erc VirtualBox.tar.bz2 || fatal "Can't extract VirtualBox.tar.bz2" + +cd .. || fatal + +PRODUCTDIR=opt/VirtualBox +mkdir -p $PRODUCTDIR +mv vbox-installer/* $PRODUCTDIR/ + +# Remove installer leftovers +rm -f $PRODUCTDIR/VirtualBox.tar.bz2 +rm -f $PRODUCTDIR/*.sh +rm -f $PRODUCTDIR/LICENSE +rm -rf vbox-installer + +# Set SUID on required executables +for exe in VirtualBoxVM VBoxHeadless VBoxNetAdpCtl VBoxNetDHCP VBoxNetNAT VBoxVolInfo ; do + [ -f "$PRODUCTDIR/$exe" ] && chmod 4755 "$PRODUCTDIR/$exe" +done + +# Create /usr/bin symlinks via VBox.sh wrapper +mkdir -p usr/bin +for cmd in VirtualBox VirtualBoxVM VBoxManage VBoxSDL VBoxHeadless VBoxAutostart VBoxBalloonCtrl VBoxBugReport VBoxDTrace VBoxVRDP ; do + [ -f "$PRODUCTDIR/$cmd" ] || [ -L "$PRODUCTDIR/$cmd" ] && ln -s /opt/VirtualBox/VBox.sh "usr/bin/$cmd" +done + +# Install desktop file +mkdir -p usr/share/applications +cp $PRODUCTDIR/virtualbox.desktop usr/share/applications/ 2>/dev/null || true + +# Install icons +for size in 16 32 48 64 128 ; do + mkdir -p "usr/share/icons/hicolor/${size}x${size}/apps" + cp "$PRODUCTDIR/icons/${size}x${size}/virtualbox.png" "usr/share/icons/hicolor/${size}x${size}/apps/" 2>/dev/null || true +done + +# Install MIME types +mkdir -p usr/share/mime/packages +cp $PRODUCTDIR/virtualbox.xml usr/share/mime/packages/ 2>/dev/null || true + +# Install udev rules +mkdir -p usr/lib/udev/rules.d +cp $PRODUCTDIR/60-vboxdrv.rules usr/lib/udev/rules.d/ 2>/dev/null || true + +# Install modprobe config +mkdir -p usr/lib/modprobe.d +echo "install vboxdrv /sbin/modprobe --ignore-install vboxdrv && /sbin/modprobe vboxnetflt && /sbin/modprobe vboxnetadp" > usr/lib/modprobe.d/virtualbox.conf + +# Create sysusers.d for vboxusers group +mkdir -p usr/lib/sysusers.d +echo "g vboxusers - -" > usr/lib/sysusers.d/virtualbox.conf + +erc pack $PKGNAME.tar opt usr || fatal + +cat <$PRODUCT.eepm.yaml +name: $PRODUCT +group: Emulators +license: GPL-2.0-only AND GPL-3.0-only AND CDDL-1.0 +url: https://www.virtualbox.org +summary: VirtualBox - powerful x86 and AMD64/Intel64 virtualization +description: Oracle VM VirtualBox is a powerful cross-platform virtualization product for enterprise and home use. +EOF + +return_tar $PKGNAME.tar diff --git a/play.d/virtualbox-bin.sh b/play.d/virtualbox-bin.sh new file mode 100755 index 000000000..3da9281bb --- /dev/null +++ b/play.d/virtualbox-bin.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +PKGNAME=virtualbox +SUPPORTEDARCHES="x86_64" +VERSION="$2" +DESCRIPTION="VirtualBox from the official site" +URL="https://www.virtualbox.org" + +. $(dirname $0)/common.sh + +if [ "$VERSION" = "*" ] ; then + VERSION="$(fetch_url "https://download.virtualbox.org/virtualbox/LATEST.TXT")" || fatal "Can't get version" + VERSION="$(echo "$VERSION" | tr -d '[:space:]')" +fi + +BASEURL="https://download.virtualbox.org/virtualbox/$VERSION" + +# VirtualBox-7.2.4-170995-Linux_amd64.run +PKGURL="$(eget --list --latest "$BASEURL/" "VirtualBox-${VERSION}-*-Linux_amd64.run")" + +[ -n "$PKGURL" ] || fatal "Can't get package URL" + +install_pack_pkgurl + +echo +echo "Note: Add needed users to vboxusers group via # usermod -a -G vboxusers " diff --git a/repack.d/VirtualBox-7.2.sh b/repack.d/VirtualBox-7.2.sh new file mode 100755 index 000000000..938d4086b --- /dev/null +++ b/repack.d/VirtualBox-7.2.sh @@ -0,0 +1,22 @@ +#!/bin/sh -x +# It will run with two args: buildroot spec +BUILDROOT="$1" +SPEC="$2" + +PRODUCT=VirtualBox +PRODUCTDIR=/usr/lib/virtualbox + +. $(dirname $0)/common.sh + +# conflict with the distro package +add_conflicts virtualbox + +# create vboxusers group via systemd-sysusers +cat <