diff --git a/README.md b/README.md index 75fc268..99190d8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # APM 原理和软件包制作流程 -spec还未完全确定,现在是demo阶段 + +源码在 src 原理:https://www.cnblogs.com/arnoldlu/p/13055501.html diff --git a/src/DEBIAN/control b/src/DEBIAN/control new file mode 100755 index 0000000..5a77580 --- /dev/null +++ b/src/DEBIAN/control @@ -0,0 +1,13 @@ +Package: apm +Source: amber-ce +Version: 1.0.5 +Architecture: amd64 +Maintainer: shenmo +Installed-Size: 48672 +Depends: bubblewrap, flatpak, zenity, policykit-1 | pkexec | polkit-1 | polkit, systemd, procps,coreutils,fuse-overlayfs +Section: misc +Conflicts: ace-host-integration +Priority: optional +Multi-Arch: foreign +Homepage: https://gitee.com/amber-ce/amber-pm/ +Description: bwrap wrapper for install and running debs inside a Amber-PM container diff --git a/src/DEBIAN/postinst b/src/DEBIAN/postinst new file mode 100755 index 0000000..2e83b14 --- /dev/null +++ b/src/DEBIAN/postinst @@ -0,0 +1,30 @@ +#!/bin/bash +export PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE" + + +case "$1" in + configure) +/var/lib/apm/$PACKAGE_NAME/files/bin/ace-init +systemctl daemon-reload +systemctl enable gxde-apm-fixer +systemctl enable apm-daily-update +systemctl start gxde-apm-fixer +systemctl start apm-daily-update + + if [ -f /usr/lib/sysctl.d/apm.conf ];then + sysctl -p /usr/lib/sysctl.d/apm.conf + fi + + +;; + triggered) + amber-pm-configure-nvidia-host + amber-pm-dstore-patch + + ;; +esac + + + + +true diff --git a/src/DEBIAN/postrm b/src/DEBIAN/postrm new file mode 100755 index 0000000..1fcc0c0 --- /dev/null +++ b/src/DEBIAN/postrm @@ -0,0 +1,20 @@ +#!/bin/bash +PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE" +systemctl stop gxde-apm-fixer +systemctl disable gxde-apm-fixer +systemctl stop apm-daily-update +systemctl disable apm-daily-update + + + +if [ "$1" = "remove" ] || [ "$1" = "purge" ];then + +echo "清理卸载残留" + +rm -rf /var/lib/apm/$PACKAGE_NAME +else +echo "非卸载,跳过清理" +fi + + + diff --git a/src/DEBIAN/triggers b/src/DEBIAN/triggers new file mode 100755 index 0000000..85f66a8 --- /dev/null +++ b/src/DEBIAN/triggers @@ -0,0 +1 @@ +interest-noawait /var/lib/apm diff --git a/src/etc/X11/Xsession.d/20apm b/src/etc/X11/Xsession.d/20apm new file mode 100755 index 0000000..fadc22c --- /dev/null +++ b/src/etc/X11/Xsession.d/20apm @@ -0,0 +1,17 @@ + + + + +# Ensure base distro defaults xdg path are set if nothing filed up some +# defaults yet. +if [ -z "$XDG_DATA_DIRS" ]; then + export XDG_DATA_DIRS="/usr/local/share:/usr/share" +fi + +# Desktop files (used by desktop environments within both X11 and Wayland) are +# looked for in XDG_DATA_DIRS; make sure it includes the relevant directory for ACE +ACE_path="/var/lib/apm/apm/files/ace-env/usr/share/" +if [ -n "${XDG_DATA_DIRS##*${ACE_path}}" ] && [ -n "${XDG_DATA_DIRS##*${ACE_path}:*}" ]; then + export XDG_DATA_DIRS="${XDG_DATA_DIRS}:${ACE_path}" +fi + diff --git a/src/etc/profile.d/apm.sh b/src/etc/profile.d/apm.sh new file mode 100755 index 0000000..003bcc1 --- /dev/null +++ b/src/etc/profile.d/apm.sh @@ -0,0 +1,16 @@ + + + +# Ensure base distro defaults xdg path are set if nothing filed up some +# defaults yet. +if [ -z "$XDG_DATA_DIRS" ]; then + export XDG_DATA_DIRS="/usr/local/share:/usr/share" +fi + +# Desktop files (used by desktop environments within both X11 and Wayland) are +# looked for in XDG_DATA_DIRS; make sure it includes the relevant directory for ACE +ACE_path="/var/lib/apm/apm/files/ace-env/usr/share/" +if [ -n "${XDG_DATA_DIRS##*${ACE_path}}" ] && [ -n "${XDG_DATA_DIRS##*${ACE_path}:*}" ]; then + export XDG_DATA_DIRS="${XDG_DATA_DIRS}:${ACE_path}" +fi + diff --git a/src/usr/bin/amber-pm-configure-nvidia b/src/usr/bin/amber-pm-configure-nvidia new file mode 120000 index 0000000..6da0d67 --- /dev/null +++ b/src/usr/bin/amber-pm-configure-nvidia @@ -0,0 +1 @@ +../../var/lib/apm/apm/files/bin/amber-ce-configure-nvidia \ No newline at end of file diff --git a/src/usr/bin/amber-pm-configure-nvidia-host b/src/usr/bin/amber-pm-configure-nvidia-host new file mode 100755 index 0000000..245200e --- /dev/null +++ b/src/usr/bin/amber-pm-configure-nvidia-host @@ -0,0 +1,21 @@ +#!/bin/bash + +APM_BASE="/var/lib/apm" + +# 遍历 /var/lib/apm 下的所有目录 +for dir in "$APM_BASE"/*/; do + # 移除末尾的斜杠获取目录名 + dirname=$(basename "$dir") + + # 跳过名为 "apm" 的目录 + if [[ "$dirname" == "apm" ]]; then + continue + fi + + # 检查是否存在 /var/lib/apm/目录名/files/ace-env + if [[ -f "$dir/files/ace-env" ]]; then + echo "执行 apm-configure-nvidia: $dir" + amber-pm-configure-nvidia "$dir/files/ace-env" + fi + +done \ No newline at end of file diff --git a/src/usr/bin/amber-pm-debug b/src/usr/bin/amber-pm-debug new file mode 120000 index 0000000..49c4a86 --- /dev/null +++ b/src/usr/bin/amber-pm-debug @@ -0,0 +1 @@ +../../var/lib/apm/apm/files/bin/ace-run \ No newline at end of file diff --git a/src/usr/bin/amber-pm-dstore-patch b/src/usr/bin/amber-pm-dstore-patch new file mode 100755 index 0000000..b13eee6 --- /dev/null +++ b/src/usr/bin/amber-pm-dstore-patch @@ -0,0 +1,128 @@ +#!/bin/bash + + + + + +enumAppInfoList() { + appInfoList=() + apps="/var/lib/apm" + list=$(ls $apps 2>/dev/null) + for appID in $list; do + appInfoList+=("$appID") + done + echo "${appInfoList[@]}" +} +linkDir() { + ensureTargetDir() { + targetFile=$1 + t=$(dirname "$targetFile") + mkdir -p "$t" + } + + source=$1 + target=$2 + sourceDir=$(dirname "$source") + targetDir=$(dirname "$target") + find "$source" -type f | while read sourceFile; do + targetFile="$targetDir/${sourceFile#$sourceDir/}" + + + ensureTargetDir "$targetFile" + sourceFile=$(realpath --relative-to="$(dirname $targetFile)" "$sourceFile" ) + if [ ! -e ${targetFile} ];then + ln -sv "$sourceFile" "$targetFile" + fi + done +} + + +linkApp() { + appID=$1 + appEntriesDir="/var/lib/apm/$appID/entries" + appLibsDir="/var/lib/apm/$appID/files/lib" + autoStartDir="$appEntriesDir/autostart" + + if [ -d "$autoStartDir" ]; then + linkDir "$autoStartDir" "/etc/xdg/autostart" + fi + + # link application + sysShareDir="/usr/share" + for folder in "$appEntriesDir/applications" "$appEntriesDir/icons" "$appEntriesDir/mime" "$appEntriesDir/glib-2.0" "$appEntriesDir/services" "$appEntriesDir/GConf" "$appEntriesDir/help" "$appEntriesDir/locale" "$appEntriesDir/fcitx"; do + if [ ! -d "$folder" ]; then + continue + fi + if [ "$folder" = "$appEntriesDir/polkit" ]; then + linkDir "$folder" "/usr/share/polkit-1" + elif [ "$folder" = "$appEntriesDir/fonts/conf" ]; then + linkDir "$folder" "/etc/fonts/conf.d" + else + linkDir "$folder" "$sysShareDir/${folder##*/}" + fi + done +} + +function exec_uos_package_link(){ + +for app in $(enumAppInfoList); do + linkApp "$app" & + +done +wait +} + +function exec_v23_icon_link(){ +# Fix v23 broken icon +if [ ! -d "/usr/share/icons/hicolor/scalable/apps" ];then +mkdir -p /usr/share/icons/hicolor/scalable/apps +fi + +for icon_root_icon_path in $(ls /usr/share/icons/*.png /usr/share/icons/*.svg 2>/dev/null) +do +target_icon_path=/usr/share/icons/hicolor/scalable/apps/$(basename ${icon_root_icon_path}) +if [ ! -e ${target_icon_path} ];then +ln -sv $(realpath --relative-to=/usr/share/icons/hicolor/scalable/apps ${icon_root_icon_path}) /usr/share/icons/hicolor/scalable/apps +fi +done +} + +function exec_link_clean(){ +# remove broken links in /usr/share + + find /usr/share/applications -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/share/icons -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/share/mime/packages -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/share/glib-2.0 -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/share/dbus-1/services -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/share/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/share/help -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/share/locale -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH`/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/lib/mozilla/plugins -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/share/polkit-1/actions -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/share/fonts -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /etc/fonts/conf.d -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + + +} +function exec_uos_package_update(){ + update-icon-caches /usr/share/icons/* > /dev/null 2>&1 & + update-desktop-database -q > /dev/null 2>&1 & + update-mime-database -V /usr/share/mime > /dev/null 2>&1 & + glib-compile-schemas /usr/share/glib-2.0/schemas/ > /dev/null 2>&1 & + +} + +######################################################################################### +echo "----------------Running APM Dstore Patch----------------" +if [ ! -e /usr/bin/deepin-app-store-tool ];then +# execute linkApp function for each app and print output +exec_uos_package_link + +fi +#exec_v23_icon_link +exec_link_clean +wait +exec_uos_package_update +echo "----------------Finished----------------" diff --git a/src/usr/bin/apm b/src/usr/bin/apm new file mode 100755 index 0000000..13b6380 --- /dev/null +++ b/src/usr/bin/apm @@ -0,0 +1,173 @@ +#!/bin/bash +VERSION=1.0.5 +# 获取脚本名称用于帮助信息 +SCRIPT_NAME=$(basename "$0") +PATH_PREFIX=/var/lib/apm/apm/files/ace-env/ + +log.warn() { echo -e "[\e[33mWARN\e[0m]: \e[1m$*\e[0m"; } +log.error() { echo -e "[\e[31mERROR\e[0m]: \e[1m$*\e[0m"; } +log.info() { echo -e "[\e[96mINFO\e[0m]: \e[1m$*\e[0m"; } +log.debug() { echo -e "[\e[32mDEBUG\e[0m]: \e[1m$*\e[0m"; } + +# 帮助信息函数 +show_help() { + cat < 运行指定软件包的可执行文件 + ssaudit 使用 ssaudit 进行软件安装,详情见 spark-store + debug 显示调试系统信息 + -h, --help 显示此帮助信息 + --amber 彩蛋功能 + +EOF +} + +apm_exec(){ +mkdir -p /tmp/apm/${coredir} +fuse-overlayfs -o lowerdir="${PATH_PREFIX}/var/lib/apm/${basedir}/files/ace-env",upperdir="${PATH_PREFIX}/var/lib/apm/${coredir}/files/core/",workdir="${PATH_PREFIX}/var/lib/apm/${coredir}/files/work/" "/tmp/apm/${coredir}" + +chrootEnvPath=/tmp/apm/${coredir} /var/lib/apm/apm/files/ace-run "$@" +umount /tmp/apm/${coredir} + +} + +# 调试信息函数 +debug_info() { + log.debug "======= APM Debug Information =======" + log.debug "User: $(whoami)" + log.debug "Hostname: $(hostname)" + log.debug "OS: $(lsb_release -ds 2>/dev/null || uname -om)" + log.debug "Kernel: $(uname -sr)" + log.debug "Bash Version: ${BASH_VERSION}" + log.debug "APT Version: $(apt --version | head -n1)" + log.debug "APM APT Version: $(amber-pm-debug apt --version | head -n1)" + log.debug "=====================================" + +amber-pm-debug "$@" + +} + +# 彩蛋函数 +amber_egg() { + cat <<'EOF' + + ____ ____ + / __ )____ __________ ____ / __ )__ ______ ____ __ __ + / __ / __ `/ ___/ __ \/ __ \ / __ / / / / __ \/ __ \/ / / / + / /_/ / /_/ / / / /_/ / / / / / /_/ / /_/ / / / / / / / /_/ / +/_____/\__,_/_/ \____/_/ /_/ /_____/\__,_/_/ /_/_/ /_/\__, / + /____/ + +Amber Package Manager - Sparkling with magic! +💎 Another target tracked down by Outrider Amber! +EOF +} + +apm-nvidia-toggle(){ + +# APM 基础路径 +APM_BASE="${PATH_PREFIX}/var/lib/apm" + +# 检查基础目录是否存在 +if [[ ! -d "$APM_BASE" ]]; then + echo "错误: 目录 $APM_BASE 不存在" + exit 1 +fi + +# 遍历 /var/lib/apm 下的所有目录 +for dir in "$APM_BASE"/*/; do + # 移除末尾的斜杠得到纯目录名 + dir="${dir%/}" + + # 提取目录名(不包括完整路径) + dirname=$(basename "$dir") + # 检查目标文件是否存在 + target_file="${APM_BASE}/${dirname}/files/ace-env" + if [[ -e "$target_file" ]]; then + + # 将目录传递给 amber-pm-configure-nvidia + amber-pm-configure-nvidia "$target_file" + + + fi +done +} +# 主命令处理 +case "$1" in + install|full-upgrade|upgrade|reinstall) + command=$1 + shift + amber-pm-debug aptss "$command" "$@" + apm-nvidia-toggle + ;; + remove|autoremove|search|policy|list|update) + # 特殊APT命令:移除第一个参数后传递其余参数 + command=$1 + shift + amber-pm-debug aptss "$command" "$@" + ;; + run) + # 运行包命令:第二个参数必须是包名 + if [ -z "$2" ]; then + log.error "Package name required for 'run' command" + show_help + exit 1 + fi + + # 检查包是否已安装 + pkg="$2" + shift 2 # 移除 'run' 和包名 + + if ! ls "${PATH_PREFIX}/var/lib/apm/$pkg" >/dev/null 2>&1; then + # 如果带前缀的目录不存在,尝试不带前缀的目录 + if ls "/var/lib/apm/$pkg" >/dev/null 2>&1; then + # 如果不带前缀的目录存在,清空 PATH_PREFIX + PATH_PREFIX="" + else + # 如果两个目录都不存在,报错退出 + log.error "Package not installed: $pkg" + exit 1 + fi + fi + + coredir=$pkg + basedir=$(cat ${PATH_PREFIX}/var/lib/apm/${coredir}/info) + + + # 检测是否有额外命令参数 + if [ $# -gt 0 ]; then + # 有额外参数:执行用户提供的命令 + log.info "Running user command: $*" + apm_exec "$@" + else + # 没有额外参数:提示 + log.info "Usage: $SCRIPT_NAME run $pkg [EXEC_PATH]" + exit 1 + fi + ;; + debug) + debug_info + ;; + ssaudit) + ssaudit "$@" --native + ;; + -h|--help) + show_help + ;; + --amber) + amber_egg + ;; + *) + show_help + ;; +esac diff --git a/src/usr/lib/sysctl.d/apm.conf b/src/usr/lib/sysctl.d/apm.conf new file mode 100755 index 0000000..10177b4 --- /dev/null +++ b/src/usr/lib/sysctl.d/apm.conf @@ -0,0 +1,6 @@ +# ACE app runs in a container, need privileges within user namespace, so we need to set it +kernel.unprivileged_userns_clone=1 +# Ubuntu 24.04 has more limitation on unprivileged user namespace,so we have to disable them. +# refer to https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces +kernel.apparmor_restrict_unprivileged_unconfined=0 +kernel.apparmor_restrict_unprivileged_userns=0 diff --git a/src/usr/lib/systemd/system/apm-daily-update.service b/src/usr/lib/systemd/system/apm-daily-update.service new file mode 100755 index 0000000..8ab86ff --- /dev/null +++ b/src/usr/lib/systemd/system/apm-daily-update.service @@ -0,0 +1,14 @@ +[Unit] +Description=APM GXDE Fixer +After=apt-daily.service network.target network-online.target systemd-networkd.service NetworkManager.service connman.service + + +[Service] +Type=simple +RemainAfterExit=yes +ExecStart=/var/lib/apm/apm/files/bin/ace-gxde-fixer +Restart=on-failure +RestartSec=10 + +[Install] +WantedBy=multi-user.target diff --git a/src/usr/lib/systemd/system/gxde-apm-fixer.service b/src/usr/lib/systemd/system/gxde-apm-fixer.service new file mode 100755 index 0000000..d783cf6 --- /dev/null +++ b/src/usr/lib/systemd/system/gxde-apm-fixer.service @@ -0,0 +1,14 @@ +[Unit] +Description=APM GXDE Fixer +After=apt-daily.service network.target network-online.target systemd-networkd.service NetworkManager.service connman.service + + +[Service] +Type=simple +RemainAfterExit=yes +ExecStart=apm update +Restart=on-failure +RestartSec=10 + +[Install] +WantedBy=multi-user.target diff --git a/src/usr/lib/systemd/user-environment-generators/60-apm b/src/usr/lib/systemd/user-environment-generators/60-apm new file mode 100755 index 0000000..666e1d7 --- /dev/null +++ b/src/usr/lib/systemd/user-environment-generators/60-apm @@ -0,0 +1,17 @@ +#!/bin/bash + + + +# Ensure base distro defaults xdg path are set if nothing filed up some +# defaults yet. +if [ -z "$XDG_DATA_DIRS" ]; then + export XDG_DATA_DIRS="/usr/local/share:/usr/share" +fi + +# Desktop files (used by desktop environments within both X11 and Wayland) are +# looked for in XDG_DATA_DIRS; make sure it includes the relevant directory for ACE +ACE_path="/var/lib/apm/apm/files/ace-env/usr/share/" +if [ -n "${XDG_DATA_DIRS##*${ACE_path}}" ] && [ -n "${XDG_DATA_DIRS##*${ACE_path}:*}" ]; then + export XDG_DATA_DIRS="${XDG_DATA_DIRS}:${ACE_path}" +fi + diff --git a/src/usr/share/bash-completion/completions/apm b/src/usr/share/bash-completion/completions/apm new file mode 100755 index 0000000..34388da --- /dev/null +++ b/src/usr/share/bash-completion/completions/apm @@ -0,0 +1,214 @@ +# Debian apt(8) completion -*- shell-script -*- + +_apm() +{ + local sourcesdir="/etc/apt/sources.list.d" + local cur prev words cword + _init_completion || return + + local GENERIC_APT_GET_OPTIONS=' + -d --download-only + -y --assume-yes + --assume-no + -u --show-upgraded + -m --ignore-missing + -t --target-release + --download + --fix-missing + --ignore-hold + --upgrade + --only-upgrade + --allow-change-held-packages + --allow-remove-essential + --allow-downgrades + --print-uris + --trivial-only + --remove + --arch-only + --allow-unauthenticated + --allow-insecure-repositories + --install-recommends + --install-suggests + --no-install-recommends + --no-install-suggests + --fix-policy + ' + + # see if the user selected a command already + local COMMANDS=( + "ssupdate" + "list" + "search" + "show" "showsrc" + "install" "remove" "purge" "autoremove" "autopurge" + "update" + "upgrade" "full-upgrade" "dist-upgrade" + "edit-sources" + "help" + "source" "build-dep" + "clean" "autoclean" + "download" "changelog" + "moo" + "depends" "rdepends" + "policy") + + local command i + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${COMMANDS[@]} =~ ${words[i]} ]]; then + command=${words[i]} + break + fi + done + + + + # supported options per command + if [[ "$cur" == -* ]]; then + case $command in + install|remove|purge|upgrade|dist-upgrade|full-upgrade|autoremove) + COMPREPLY=( $( compgen -W '--show-progress + --fix-broken --purge --verbose-versions --auto-remove + -s --simulate --dry-run + --download + --fix-missing + --fix-policy + --ignore-hold + --force-yes + --trivial-only + --reinstall --solver + -t --target-release'"$GENERIC_APT_GET_OPTIONS" -- "$cur" ) ) + return 0 + ;; + update) + COMPREPLY=( $( compgen -W '--list-cleanup + --print-uris + --allow-insecure-repositories + ' -- "$cur" ) ) + return 0 + ;; + list) + COMPREPLY=( $( compgen -W '--installed --upgradable + --manual-installed + -v --verbose + -a --all-versions + -t --target-release + ' -- "$cur" ) ) + return 0 + ;; + show) + COMPREPLY=( $( compgen -W '-a --all-versions + ' -- "$cur" ) ) + return 0 + ;; + depends|rdepends) + COMPREPLY=( $( compgen -W '-i + --important + --installed + --pre-depends + --depends + --recommends + --suggests + --replaces + --breaks + --conflicts + --enhances + --recurse + --implicit' -- "$cur" ) ) + return 0 + ;; + search) + COMPREPLY=( $( compgen -W ' + -n --names-only + -f --full' -- "$cur" ) ) + return 0 + ;; + showsrc) + COMPREPLY=( $( compgen -W ' + --only-source' -- "$cur" ) ) + return 0 + ;; + source) + COMPREPLY=( $( compgen -W ' + -s --simulate --dry-run + -b --compile --build + -P --build-profiles + --diff-only --debian-only + --tar-only + --dsc-only + -t --target-release + '"$GENERIC_APT_GET_OPTIONS" -- "$cur" ) ) + return 0 + ;; + build-dep) + COMPREPLY=( $( compgen -W ' + -a --host-architecture + -s --simulate --dry-run + -P --build-profiles + -t --target-release + --purge --solver + '"$GENERIC_APT_GET_OPTIONS" -- "$cur" ) ) + return 0 + ;; + moo) + COMPREPLY=( $( compgen -W ' + --color + ' -- "$cur" ) ) + return 0 + ;; + clean|autoclean) + COMPREPLY=( $( compgen -W ' + -s --simulate --dry-run + ' -- "$cur" ) ) + return 0 + ;; + esac + fi + + # specific command arguments + if [[ -n $command ]]; then + case $command in + remove|purge|autoremove) + # Debian system + + + COMPREPLY=( $( compgen -W "$(ls /var/lib/apm/apm/files/ace-env/var/lib/apm/ )" $cur ) ) + + return 0 + ;; + show|list|download|changelog|depends|rdepends) + COMPREPLY=( $( amber-pm-debug apt-cache --no-generate pkgnames "$cur" -o Dir::Cache="/var/lib/aptss/" \ + 2> /dev/null ) ) + return 0 + ;; + install) + COMPREPLY=( $( amber-pm-debug apt-cache --no-generate pkgnames "$cur" -o Dir::Cache="/var/lib/aptss/" \ + 2> /dev/null ) ) + if [[ "$cur" == ./* || "$cur" == /* ]]; then + _filedir "deb" + fi + return 0 + ;; + source|build-dep|showsrc|policy) + COMPREPLY=( $( amber-pm-debug apt-cache --no-generate pkgnames "$cur" -o Dir::Cache="/var/lib/aptss/" \ + 2> /dev/null ) $( apt-cache dumpavail -o Dir::Cache="/var/lib/aptss/" | \ + command grep "^Source: $cur" | sort -u | cut -f2 -d" " ) ) + return 0 + ;; + moo) + COMPREPLY=( $( compgen -W 'moo' \ + -- "$cur" ) ) + return 0 + ;; + esac + fi + + # no command yet, show what commands we have + if [ "$command" = "" ]; then + COMPREPLY=( $( compgen -W '${COMMANDS[@]}' -- "$cur" ) ) + fi + + return 0 +} && +complete -F _apm apm + +# ex: ts=4 sw=4 et filetype=sh diff --git a/src/var/lib/apm/apm/ACE logo.png b/src/var/lib/apm/apm/ACE logo.png new file mode 100755 index 0000000..817ea0a Binary files /dev/null and b/src/var/lib/apm/apm/ACE logo.png differ diff --git a/src/var/lib/apm/apm/ACE-transparent.png b/src/var/lib/apm/apm/ACE-transparent.png new file mode 100755 index 0000000..0b91028 Binary files /dev/null and b/src/var/lib/apm/apm/ACE-transparent.png differ diff --git a/src/var/lib/apm/apm/ACE-uninstaller-orig.png b/src/var/lib/apm/apm/ACE-uninstaller-orig.png new file mode 100755 index 0000000..29532ed Binary files /dev/null and b/src/var/lib/apm/apm/ACE-uninstaller-orig.png differ diff --git a/src/var/lib/apm/apm/files/ace-run b/src/var/lib/apm/apm/files/ace-run new file mode 100755 index 0000000..90bc0ce --- /dev/null +++ b/src/var/lib/apm/apm/files/ace-run @@ -0,0 +1,141 @@ +#!/bin/bash + + + +chrootEnvPath="${chrootEnvPath:-$(pwd)/ace-env}" + + + +non_root_user=$(who | awk '{print $1}' | head -n 1) +uid=$(id -u $non_root_user) + + +#### This part is for args pharm +if [ "$1" = "" ];then +container_command="bash" +else +container_command="$1" +shift +for arg in "$@"; do + arg="$(echo "${arg}x" | sed 's|'\''|'\'\\\\\'\''|g')" + arg="${arg%x}" + container_command="${container_command} '${arg}'" +done +fi +######################################################################################### +##########合成bwrap 1. 基础函数配置段 +# 初始化 EXEC_COMMAND 为 bwrap 基础指令 +EXEC_COMMAND="bwrap --dev-bind / / bwrap" + +# add_command 函数定义 +function add_command() { + # 参数拼接,考虑到转义和空格的处理 + for arg in "$@"; do + EXEC_COMMAND="${EXEC_COMMAND} ${arg}" + done +} + +function add_env_var() { + local var_name="${1}" + local var_value="${2}" + if [ "$var_value" != "" ]; then + add_command "--setenv $var_name $var_value" + + fi +} +##########合成bwrap 2. 特殊需求函数配置段 +function cursor_theme_dir_integration() { + +local directory="" +if [ "$(id -u)" = "0" ]; then #####We don't want bother root to install themes,but will try to fix the unwriteable issue + mkdir -p $chrootEnvPath/usr/share/icons + chmod 777 -R $chrootEnvPath/usr/share/icons + return +fi + +for directory in "/usr/share/icons"/*; do + # 检查是否为目录 + if [ -d "$directory" ]; then + # 检查目录中是否存在 cursors 文件 + if [ -d "$directory/cursors" ]; then + if [ -w $chrootEnvPath/usr/share/icons ];then + add_command "--ro-bind-try $directory $directory" + fi + fi + fi +done + + + + + + + +} +##########合成bwrap 3. 环境变量和目录绑定配置段 +# 添加环境变量和其他初始设置 +ENV_VARS=( + "FAKEROOTDONTTRYCHOWN 1" + "PULSE_SERVER /run/user/\$uid/pulse/native" + "PATH /amber-ce-tools/bin-override:\$PATH" + "IS_ACE_ENV 1" + "GTK_USE_PORTAL 1" + "XDG_DATA_DIRS /amber-ce-tools/additional-data-dir-in-container:\$XDG_DATA_DIRS" +) + +BIND_DIRS=( + "--dev-bind $chrootEnvPath/ /" + "--dev-bind-try /media /media" + "--dev-bind-try /mnt /mnt" + "--dev-bind-try /tmp /tmp" + "--dev-bind-try /data /data" + "--dev-bind-try /dev /dev" + "--proc /proc" + "--dev-bind /sys /sys" + "--dev-bind /run /run" + "--dev-bind-try /run/user/\$uid/pulse /run/user/\$uid/pulse" + "--dev-bind / /host" + "--ro-bind-try /usr/share/themes /usr/local/share/themes" + "--ro-bind-try /usr/share/icons /usr/share/icons" + "--ro-bind-try /usr/share/fonts /usr/local/share/fonts" + "--dev-bind-try /etc/resolv.conf /etc/resolv.conf" + "--dev-bind-try /home /home" +) +EXTRA_ARGS=( + "--hostname Amber-PM" + "--unshare-uts" + "--cap-add CAP_SYS_ADMIN" +) + +EXTRA_SCRIPTS=( +# cursor_theme_dir_integration +) + +##########合成bwrap 4. 合成并执行指令 +# 逐一添加到 EXEC_COMMAND +for var in "${ENV_VARS[@]}"; do + add_env_var $var +done + +for var in "${BIND_DIRS[@]}"; do + add_command "$var" +done + +for var in "${EXTRA_ARGS[@]}"; do + add_command "$var" +done + +for var in "${EXTRA_SCRIPTS[@]}"; do + $var +done + +# 添加最终的 bash 命令 +add_command "bash -c \"${container_command}\"" + +# 输出完整的 EXEC_COMMAND 以查看 +# echo "${EXEC_COMMAND}" + +# 注意: 实际执行时,请确保所有变量(如 $uid, $chrootEnvPath 等)都已正确定义 +eval ${EXEC_COMMAND} + + diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/DEBIAN/control b/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/DEBIAN/control new file mode 100755 index 0000000..acc208a --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/DEBIAN/control @@ -0,0 +1,9 @@ +Package: ace-host-integration +Version: 1.2.2 +Section: misc +Priority: optional +Depends: bash +Maintainer: shenmo +Architecture: all +Conflicts: apm +Description: ace-host-integration diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/DEBIAN/postinst b/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/DEBIAN/postinst new file mode 100755 index 0000000..cd35848 --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/DEBIAN/postinst @@ -0,0 +1,4 @@ +#!/bin/bash +if [ "${1}" = "triggered" ];then +/opt/ace-host-integration/ace-host-integration +fi diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/DEBIAN/triggers b/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/DEBIAN/triggers new file mode 100755 index 0000000..342ec04 --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/DEBIAN/triggers @@ -0,0 +1,2 @@ +interest-noawait /var/lib/apm +interest-noawait /usr/share/applications diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/etc/environment.d/90is_ace_env.conf b/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/etc/environment.d/90is_ace_env.conf new file mode 100755 index 0000000..8548ff0 --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/etc/environment.d/90is_ace_env.conf @@ -0,0 +1 @@ +IS_ACE_ENV=1 diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/opt/ace-host-integration/ace-host-integration b/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/opt/ace-host-integration/ace-host-integration new file mode 100755 index 0000000..face45a --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/ace-host-integration/opt/ace-host-integration/ace-host-integration @@ -0,0 +1,98 @@ +#!/bin/bash +# ===== Log ===== +# log.info xxx +# log.warn xxx +# log.info xxx +# log.debug xxx +# 带颜色的echo +function log.color_output() { + local color=$1 + shift 1 + + echo >&2 -e "\033[${color}m$@\033[0m" + return 0 +} + +# Log is named without prefix "utils." for convenience +# Usage: log.log ...content +function log.log() { + if [[ $# < 2 ]]; then + return -1 + fi + + local level=$1 + shift 1 + + case $level in + error) log.color_output "0;31" "[ERROR] $@" ;; + warn) log.color_output "1;33" "[WARN] $@" ;; + info) log.color_output "1;37" "[INFO] $@" ;; + debug) log.color_output "1;30" "[DEBUG] $@" ;; + esac + + return 0 +} + +function log.error() { log.log "error" "$@"; } +function log.warn() { log.log "warn" $@; } +function log.info() { log.log "info" $@; } +function log.debug() { log.log "debug" $@; } + +function do_integrate(){ + local file=$1 + if [ -f "$file" ]; then + # 获取文件名(不带.desktop后缀)作为X-AMBER-CE-DESKTOP-NAME的值 + local desktop_name=$(basename "$file" .desktop) + + # 检查是否已经处理过(通过检查X-AMBER-CE-DESKTOP-NAME字段) + if ! grep -q "^X-AMBER-CE-DESKTOP-NAME=" "$file"; then + echo "$file is detected. Processing host system integration..." + + # 修改Exec行(如果尚未修改) + if ! grep -q "^Exec=apm-debug " "$file"; then + sed -i 's|^Exec=\(.*\)|Exec=apm-debug \1|' "$file" + fi + + # 删除TryExec行 + sed -i '/^TryExec=/d' "$file" + + # 修改Name行(包括本地化Name) + sed -i '/^Name=/ s/$/ (Amber-PM)/' "$file" + sed -i "/^Name\[${LANGUAGE}\]=/ s/\$/ (Amber-PM)/" "$file" + + # 修改GenericName行(包括本地化GenericName) + sed -i '/^GenericName=/ s/$/ (Amber-PM)/' "$file" + sed -i "/^GenericName\[${LANGUAGE}\]=/ s/\$/ (Amber-PM)/" "$file" + + # 添加X-AMBER-CE-DESKTOP-NAME字段 + echo "X-AMBER-CE-DESKTOP-NAME=${desktop_name}" >> "$file" + + # 处理Icon行 + icon_line=$(grep "^Icon=" "$file") + if [[ "$icon_line" == "Icon=/"* ]]; then + # 如果Icon=后面接的是/,则添加前缀 + sed -i 's|^Icon=/|Icon=/lib/apm/apm/files/ace-env/|' "$file" + fi + fi + fi + chmod +x "$file" +} + +if [ "${IS_ACE_ENV}" != "" ]; then + if [ -e /opt/apps/ ]; then + for app_dir in $(/apm/); do + for file in /opt/apps/$app_dir/entries/applications/*.desktop; do + do_integrate "$file" + done + done + else + log.warn "No /opt/apps directory. Skip..." + fi + + for file in /usr/share/applications/*.desktop; do + do_integrate "$file" + done + find "/usr/share/applications/" -xtype l -delete +else + log.error "DO NOT run me on host OS" +fi \ No newline at end of file diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/ace-upgrader/ace-upgrader b/src/var/lib/apm/apm/files/amber-ce-tools/ace-upgrader/ace-upgrader new file mode 100755 index 0000000..219eec7 --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/ace-upgrader/ace-upgrader @@ -0,0 +1,176 @@ +#!/bin/bash + + + + +############################################################# +# ===== Log ===== +# log.info xxx +# log.warn xxx +# log.info xxx +# log.debug xxx +# 带颜色的echo +function log.color_output() { + local color=$1 + shift 1 + + echo >&2 -e "\033[${color}m$@\033[0m" + return 0 +} + +# Log is named without prefix "utils." for convenience +# Usage: log.log ...content +function log.log() { + if [[ $# < 2 ]]; then + return -1 + fi + + local level=$1 + shift 1 + + case $level in + error) log.color_output "0;31" "[ERROR] $@" ;; + warn) log.color_output "1;33" "[WARN] $@" ;; + info) log.color_output "1;37" "[INFO] $@" ;; + debug) log.color_output "1;30" "[DEBUG] $@" ;; + esac + + return 0 +} + +function log.error() { log.log "error" "$@"; } +function log.warn() { log.log "warn" $@; } +function log.info() { log.log "info" $@; } +function log.debug() { log.log "debug" $@; } + + +# 发送通知 +function notify-send() { + + + # Detect user using the display + local user=$(who | awk '{print $1}' | head -n 1) + + # Detect uid of the user + local uid=$(id -u $user) + log.debug "User is $user and the uid of it is $uid" + sudo -u $user DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${uid}/bus notify-send $@ +} + + +# 检测网络链接畅通 +function network-check() +{ + # 超时时间 + local timeout=15 + + # 目标网站 + local target=www.baidu.com + + # 获取响应状态码 + local ret_code=`curl -I -s --connect-timeout ${timeout} ${target} -w %{http_code} | tail -n1` + + if [ "x$ret_code" = "x200" ] ; then + # 网络畅通 + return 0 + else + # 网络不畅通 + return 1 + fi +} +############################################################### + +if [ "$(id -u)" != "0" ]; then +log.error "Nope we need root to run" +exit -1 +fi + +network-check +if [ $? -ne 0 ] ; then + log.error "NETWORK_FAIL" + exit -1 +fi + +# The code above is modified from https://blog.csdn.net/yaxuan88521/article/details/120516298 + + + + +if command -v aptss ;then +APT_COMMAND=aptss +/usr/bin/apt update +log.info "Using aptss to operate the upgrade process since we detect it." +elif [ -e /usr/bin/apt ];then +APT_COMMAND=/usr/bin/apt +log.info "Using apt to operate the upgrade process." +else +log.error "Nope we support debian only now" +exit -1 +fi +${APT_COMMAND} clean +${APT_COMMAND} update + +updatetext=`${APT_COMMAND} update 2>&1` + +until [ "`echo $updatetext | grep E: `" = "" ];do +log.info "UPDATE_ERROR_AND_WAIT_15_SEC" +sleep 15 +updatetext=`${APT_COMMAND} update 2>&1` + + + +done + + +# 获取可升级包的数量 +update_app_number=$(env LANGUAGE=en_US ${APT_COMMAND} list --upgradable 2>/dev/null | grep -c upgradable) + +if [ "$update_app_number" -le 0 ] ; then + exit 0 +fi + +# 获取用户选择的要更新的应用 +PKG_LIST="$(env LANGUAGE=en_US ${APT_COMMAND} list --upgradable | awk NR\>1)" +# 指定分隔符为 \n +IFS_OLD="$IFS" +IFS=$'\n' + +for line in $PKG_LIST ; do + PKG_NAME=$(echo $line | awk -F ' ' '{print $1}') + PKG_NEW_VER=$(echo $line | awk -F ' ' '{print $2}') + PKG_CUR_VER=$(echo $line | awk -F ' ' '{print $3}') + +# dpkg --compare-versions $PKG_NEW_VER le $PKG_CUR_VER + +# if [ $? -eq 0 ] ; then +# let update_app_number=$update_app_number-1 +# continue +# fi + + ## 检测是否是 hold 状态 + PKG_STA=$(dpkg-query -W -f='${db:Status-Want}' $PKG_NAME) + if [ "$PKG_STA" = "hold" ] ; then + let update_app_number=$update_app_number-1 + fi +done + +# 还原分隔符 +IFS="$IFS_OLD" +if [ $update_app_number -le 0 ] ; then + log.info "No package need to upgrade after ignoring those holded ones. exit" + exit 0 +fi + + +## 如果都是hold或者版本一致的那就直接退出,否则把剩余的给提醒了 + + +user=$(who | awk '{print $1}' | head -n 1) + + log.info "ACE Amber-PM 环境中有 $update_app_number 个软件包可升级,正在自动升级" +notify-send -a apm "ACE Amber-PM" "ACE Amber-PM环境中有${update_app_number}个软件包可升级,执行自动升级..." + +${APT_COMMAND} clean +${APT_COMMAND} full-upgrade -y +${APT_COMMAND} clean +notify-send -a apm "ACE兼容环境" "自动升级结束" diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/additional-data-dir-in-container/README.md b/src/var/lib/apm/apm/files/amber-ce-tools/additional-data-dir-in-container/README.md new file mode 100755 index 0000000..c520540 --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/additional-data-dir-in-container/README.md @@ -0,0 +1 @@ +# File in this dir will be seen as one of XDG_DATA_DIRS in ACE container. diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/additional-data-dir-in-container/applications/ace-run-in-host-os.desktop b/src/var/lib/apm/apm/files/amber-ce-tools/additional-data-dir-in-container/applications/ace-run-in-host-os.desktop new file mode 100755 index 0000000..8481303 --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/additional-data-dir-in-container/applications/ace-run-in-host-os.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Exec=xdg-open %U +MimeType=inode/directory;application/x-mimearchive;x-scheme-handler/http;x-scheme-handler/https;application/msword;application/vnd.openxmlformats-officedocument.wordprocessingml.document;application/vnd.ms-excel;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;application/vnd.ms-powerpoint;application/vnd.openxmlformats-officedocument.presentationml.presentation;application/x-gzip;application/zip;application/rar;application/x-tar;application/pdf;application/rtf;image/gif;image/jpeg;image/jp2;image/png;image/tiff;image/bmp;image/svg+xml;image/webp;image/x-icon;application/kswps;application/kset;application/ksdps;application/x-photoshop;application/x-coreldraw;application/x-shockwave-flash;text/plain;application/x-javascript;text/javascript;text/css;text/html;application/xhtml+xml;text/xml;text/x-vcard;application/x-httpd-php;application/java-archive;application/vnd.android.package-archive;application/octet-stream;application/x-x509-user-cert;audio/mpeg;audio/midi;audio/x-wav;audio/x-mpegurl;audio/x-m4a;audio/ogg;audio/x-realaudio;video/mp4;video/mpeg;video/quicktime;video/x-m4v;video/x-ms-wmv;video/x-msvideo;video/webm;video/x-flv;application/xhtml_xml; +Name=ace-run-in-host-os +NoDisplay=true +Terminal=false +TryExec= +Type=Application +Version=1.0 + diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/README.md b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/README.md new file mode 100755 index 0000000..e69de29 diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/apm-debug b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/apm-debug new file mode 100755 index 0000000..19f2804 --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/apm-debug @@ -0,0 +1,4 @@ +#!/bin/bash +### We do not want users to install ACE in ACE. +echo "Running ACE in ACE is NOT Tested or recommended. Exit" +exit 1 \ No newline at end of file diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/bwrap b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/bwrap new file mode 100755 index 0000000..519fdcd --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/bwrap @@ -0,0 +1,2 @@ +#!/bin/bash +host-spawn /var/lib/apm/apm/files/bin/ace-run-bwrap "$@" diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/gio b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/gio new file mode 100755 index 0000000..2b272f5 --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/gio @@ -0,0 +1,6 @@ +#!/bin/bash +if [ "$1" = "open" ];then +xdg-open ${@:2} +else +/usr/bin/gio $@ +fi diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/host-spawn-aarch64 b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/host-spawn-aarch64 new file mode 100755 index 0000000..1716965 Binary files /dev/null and b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/host-spawn-aarch64 differ diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/host-spawn-loongarch64 b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/host-spawn-loongarch64 new file mode 100755 index 0000000..0bea20a Binary files /dev/null and b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/host-spawn-loongarch64 differ diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/host-spawn-x86_64 b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/host-spawn-x86_64 new file mode 100755 index 0000000..854150f Binary files /dev/null and b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/host-spawn-x86_64 differ diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/pkexec b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/pkexec new file mode 100755 index 0000000..85cc6cd --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/pkexec @@ -0,0 +1,6 @@ +#!/bin/bash +if [ "$UID" = "0" ];then +$@ +else +host-spawn pkexec apm-debug $@ +fi diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/sudo b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/sudo new file mode 100755 index 0000000..0e8993c --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/sudo @@ -0,0 +1,6 @@ +#!/bin/bash +if [ "$UID" = "0" ];then +/usr/bin/sudo $@ +else +host-spawn sudo apm-debug sudo env IS_ACE_ENV="1" PATH="/amber-ce-tools/bin-override:$PATH" "$@" +fi diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/xdg-open b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/xdg-open new file mode 100755 index 0000000..fa6b007 --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/bin-override/xdg-open @@ -0,0 +1,1072 @@ +#!/bin/sh +#--------------------------------------------- +# xdg-open +# +# Utility script to open a URL in the registered default application. +# +# Refer to the usage() function below for usage. +# +# Copyright 2009-2010, Fathi Boudra +# Copyright 2009-2010, Rex Dieter +# Copyright 2006, Kevin Krammer +# Copyright 2006, Jeremy White +# +# LICENSE: +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#--------------------------------------------- + +manualpage() +{ +cat << _MANUALPAGE +Name + +xdg-open - opens a file or URL in the user's preferred application + +Synopsis + +xdg-open { file | URL } + +xdg-open { --help | --manual | --version } + +Description + +xdg-open opens a file or URL in the user's preferred application. If a URL is +provided the URL will be opened in the user's preferred web browser. If a file +is provided the file will be opened in the preferred application for files of +that type. xdg-open supports file, ftp, http and https URLs. + +xdg-open is for use inside a desktop session only. It is not recommended to use +xdg-open as root. + +Options + +--help + Show command synopsis. +--manual + Show this manual page. +--version + Show the xdg-utils version information. + +Exit Codes + +An exit code of 0 indicates success while a non-zero exit code indicates +failure. The following failure codes can be returned: + +1 + Error in command line syntax. +2 + One of the files passed on the command line did not exist. +3 + A required tool could not be found. +4 + The action failed. + +See Also + +xdg-mime(1), xdg-settings(1), MIME applications associations specification + +Examples + +xdg-open 'http://www.freedesktop.org/' + +Opens the freedesktop.org website in the user's default browser. + +xdg-open /tmp/foobar.png + +Opens the PNG image file /tmp/foobar.png in the user's default image viewing +application. + +_MANUALPAGE +} + +usage() +{ +cat << _USAGE +xdg-open - opens a file or URL in the user's preferred application + +Synopsis + +xdg-open { file | URL } + +xdg-open { --help | --manual | --version } + +_USAGE +} + +#@xdg-utils-common@ + +#---------------------------------------------------------------------------- +# Common utility functions included in all XDG wrapper scripts +#---------------------------------------------------------------------------- + +DEBUG() +{ + [ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && return 0; + [ ${XDG_UTILS_DEBUG_LEVEL} -lt $1 ] && return 0; + shift + echo "$@" >&2 +} + +# This handles backslashes but not quote marks. +first_word() +{ + read first rest + echo "$first" +} + +#------------------------------------------------------------- +# map a binary to a .desktop file +binary_to_desktop_file() +{ + search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" + binary="`which "$1"`" + binary="`readlink -f "$binary"`" + base="`basename "$binary"`" + IFS=: + for dir in $search; do + unset IFS + [ "$dir" ] || continue + [ -d "$dir/applications" ] || [ -d "$dir/applnk" ] || continue + for file in "$dir"/applications/*.desktop "$dir"/applications/*/*.desktop "$dir"/applnk/*.desktop "$dir"/applnk/*/*.desktop; do + [ -r "$file" ] || continue + # Check to make sure it's worth the processing. + grep -q "^Exec.*$base" "$file" || continue + # Make sure it's a visible desktop file (e.g. not "preferred-web-browser.desktop"). + grep -Eq "^(NoDisplay|Hidden)=true" "$file" && continue + command="`grep -E "^Exec(\[[^]=]*])?=" "$file" | cut -d= -f 2- | first_word`" + command="`which "$command"`" + if [ x"`readlink -f "$command"`" = x"$binary" ]; then + # Fix any double slashes that got added path composition + echo "$file" | sed -e 's,//*,/,g' + return + fi + done + done +} + +#------------------------------------------------------------- +# map a .desktop file to a binary +desktop_file_to_binary() +{ + search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" + desktop="`basename "$1"`" + IFS=: + for dir in $search; do + unset IFS + [ "$dir" ] && [ -d "$dir/applications" ] || [ -d "$dir/applnk" ] || continue + # Check if desktop file contains - + if [ "${desktop#*-}" != "$desktop" ]; then + vendor=${desktop%-*} + app=${desktop#*-} + if [ -r $dir/applications/$vendor/$app ]; then + file_path=$dir/applications/$vendor/$app + elif [ -r $dir/applnk/$vendor/$app ]; then + file_path=$dir/applnk/$vendor/$app + fi + fi + if test -z "$file_path" ; then + for indir in "$dir"/applications/ "$dir"/applications/*/ "$dir"/applnk/ "$dir"/applnk/*/; do + file="$indir/$desktop" + if [ -r "$file" ]; then + file_path=$file + break + fi + done + fi + if [ -r "$file_path" ]; then + # Remove any arguments (%F, %f, %U, %u, etc.). + command="`grep -E "^Exec(\[[^]=]*])?=" "$file_path" | cut -d= -f 2- | first_word`" + command="`which "$command"`" + readlink -f "$command" + return + fi + done +} + +#------------------------------------------------------------- +# Exit script on successfully completing the desired operation + +exit_success() +{ + if [ $# -gt 0 ]; then + echo "$@" + echo + fi + + exit 0 +} + + +#----------------------------------------- +# Exit script on malformed arguments, not enough arguments +# or missing required option. +# prints usage information + +exit_failure_syntax() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + echo "Try 'xdg-open --help' for more information." >&2 + else + usage + echo "Use 'man xdg-open' or 'xdg-open --manual' for additional info." + fi + + exit 1 +} + +#------------------------------------------------------------- +# Exit script on missing file specified on command line + +exit_failure_file_missing() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + fi + + exit 2 +} + +#------------------------------------------------------------- +# Exit script on failure to locate necessary tool applications + +exit_failure_operation_impossible() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + fi + + exit 3 +} + +#------------------------------------------------------------- +# Exit script on failure returned by a tool application + +exit_failure_operation_failed() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + fi + + exit 4 +} + +#------------------------------------------------------------ +# Exit script on insufficient permission to read a specified file + +exit_failure_file_permission_read() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + fi + + exit 5 +} + +#------------------------------------------------------------ +# Exit script on insufficient permission to write a specified file + +exit_failure_file_permission_write() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + fi + + exit 6 +} + +check_input_file() +{ + if [ ! -e "$1" ]; then + exit_failure_file_missing "file '$1' does not exist" + fi + if [ ! -r "$1" ]; then + exit_failure_file_permission_read "no permission to read file '$1'" + fi +} + +check_vendor_prefix() +{ + file_label="$2" + [ -n "$file_label" ] || file_label="filename" + file=`basename "$1"` + case "$file" in + [[:alpha:]]*-*) + return + ;; + esac + + echo "xdg-open: $file_label '$file' does not have a proper vendor prefix" >&2 + echo 'A vendor prefix consists of alpha characters ([a-zA-Z]) and is terminated' >&2 + echo 'with a dash ("-"). An example '"$file_label"' is '"'example-$file'" >&2 + echo "Use --novendor to override or 'xdg-open --manual' for additional info." >&2 + exit 1 +} + +check_output_file() +{ + # if the file exists, check if it is writeable + # if it does not exists, check if we are allowed to write on the directory + if [ -e "$1" ]; then + if [ ! -w "$1" ]; then + exit_failure_file_permission_write "no permission to write to file '$1'" + fi + else + DIR=`dirname "$1"` + if [ ! -w "$DIR" ] || [ ! -x "$DIR" ]; then + exit_failure_file_permission_write "no permission to create file '$1'" + fi + fi +} + +#---------------------------------------- +# Checks for shared commands, e.g. --help + +check_common_commands() +{ + while [ $# -gt 0 ] ; do + parm="$1" + shift + + case "$parm" in + --help) + usage + echo "Use 'man xdg-open' or 'xdg-open --manual' for additional info." + exit_success + ;; + + --manual) + manualpage + exit_success + ;; + + --version) + echo "xdg-open 1.1.3" + exit_success + ;; + esac + done +} + +check_common_commands "$@" + +[ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && unset XDG_UTILS_DEBUG_LEVEL; +if [ ${XDG_UTILS_DEBUG_LEVEL-0} -lt 1 ]; then + # Be silent + xdg_redirect_output=" > /dev/null 2> /dev/null" +else + # All output to stderr + xdg_redirect_output=" >&2" +fi + +#-------------------------------------- +# Checks for known desktop environments +# set variable DE to the desktop environments name, lowercase + +detectDE() +{ + # see https://bugs.freedesktop.org/show_bug.cgi?id=34164 + unset GREP_OPTIONS + + if [ -n "${XDG_CURRENT_DESKTOP}" ]; then + case "${XDG_CURRENT_DESKTOP}" in + # only recently added to menu-spec, pre-spec X- still in use + Cinnamon|X-Cinnamon) + DE=cinnamon; + ;; + ENLIGHTENMENT) + DE=enlightenment; + ;; + # GNOME, GNOME-Classic:GNOME, or GNOME-Flashback:GNOME + GNOME*) + DE=gnome; + ;; + KDE) + DE=kde; + ;; + # Deepin Desktop Environments + DEEPIN|Deepin|deepin) + DE=dde; + ;; + LXDE) + DE=lxde; + ;; + LXQt) + DE=lxqt; + ;; + MATE) + DE=mate; + ;; + XFCE) + DE=xfce + ;; + X-Generic) + DE=generic + ;; + esac + fi + + if [ x"$DE" = x"" ]; then + # classic fallbacks + if [ x"$KDE_FULL_SESSION" != x"" ]; then DE=kde; + elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then DE=gnome; + elif [ x"$MATE_DESKTOP_SESSION_ID" != x"" ]; then DE=mate; + elif `dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.gnome.SessionManager > /dev/null 2>&1` ; then DE=gnome; + elif xprop -root _DT_SAVE_MODE 2> /dev/null | grep ' = \"xfce4\"$' >/dev/null 2>&1; then DE=xfce; + elif xprop -root 2> /dev/null | grep -i '^xfce_desktop_window' >/dev/null 2>&1; then DE=xfce + elif echo $DESKTOP | grep -q '^Enlightenment'; then DE=enlightenment; + elif [ x"$LXQT_SESSION_CONFIG" != x"" ]; then DE=lxqt; + fi + fi + + if [ x"$DE" = x"" ]; then + # fallback to checking $DESKTOP_SESSION + case "$DESKTOP_SESSION" in + gnome) + DE=gnome; + ;; + LXDE|Lubuntu) + DE=lxde; + ;; + MATE) + DE=mate; + ;; + xfce|xfce4|'Xfce Session') + DE=xfce; + ;; + esac + fi + + if [ x"$DE" = x"" ]; then + # fallback to uname output for other platforms + case "$(uname 2>/dev/null)" in + CYGWIN*) + DE=cygwin; + ;; + Darwin) + DE=darwin; + ;; + esac + fi + + if [ x"$DE" = x"gnome" ]; then + # gnome-default-applications-properties is only available in GNOME 2.x + # but not in GNOME 3.x + which gnome-default-applications-properties > /dev/null 2>&1 || DE="gnome3" + fi + + if [ -f "$XDG_RUNTIME_DIR/flatpak-info" ]; then + DE="flatpak" + fi +} + +#---------------------------------------------------------------------------- +# kfmclient exec/openURL can give bogus exit value in KDE <= 3.5.4 +# It also always returns 1 in KDE 3.4 and earlier +# Simply return 0 in such case + +kfmclient_fix_exit_code() +{ + version=`LC_ALL=C.UTF-8 kde-config --version 2>/dev/null | grep '^KDE'` + major=`echo $version | sed 's/KDE.*: \([0-9]\).*/\1/'` + minor=`echo $version | sed 's/KDE.*: [0-9]*\.\([0-9]\).*/\1/'` + release=`echo $version | sed 's/KDE.*: [0-9]*\.[0-9]*\.\([0-9]\).*/\1/'` + test "$major" -gt 3 && return $1 + test "$minor" -gt 5 && return $1 + test "$release" -gt 4 && return $1 + return 0 +} + +#---------------------------------------------------------------------------- +# Returns true if there is a graphical display attached. + +has_display() +{ + if [ -n "$DISPLAY" ] || [ -n "$WAYLAND_DISPLAY" ]; then + return 0 + else + return 1 + fi +} + +# This handles backslashes but not quote marks. +last_word() +{ + read first rest + echo "$rest" +} + +# Get the value of a key in a desktop file's Desktop Entry group. +# Example: Use get_key foo.desktop Exec +# to get the values of the Exec= key for the Desktop Entry group. +get_key() +{ + local file="${1}" + local key="${2}" + local desktop_entry="" + + IFS_="${IFS}" + IFS="" + while read line + do + case "$line" in + "[Desktop Entry]") + desktop_entry="y" + ;; + # Reset match flag for other groups + "["*) + desktop_entry="" + ;; + "${key}="*) + # Only match Desktop Entry group + if [ -n "${desktop_entry}" ] + then + echo "${line}" | cut -d= -f 2- + fi + esac + done < "${file}" + IFS="${IFS_}" +} + +# Returns true if argument is a file:// URL or path +is_file_url_or_path() +{ + if echo "$1" | grep -q '^file://' \ + || ! echo "$1" | egrep -q '^[[:alpha:]+\.\-]+:'; then + return 0 + else + return 1 + fi +} + +# If argument is a file URL, convert it to a (percent-decoded) path. +# If not, leave it as it is. +file_url_to_path() +{ + local file="$1" + if echo "$file" | grep -q '^file:///'; then + file=${file#file://} + file=${file%%#*} + file=$(echo "$file" | sed -r 's/\?.*$//') + local printf=printf + if [ -x /usr/bin/printf ]; then + printf=/usr/bin/printf + fi + file=$($printf "$(echo "$file" | sed -e 's@%\([a-f0-9A-F]\{2\}\)@\\x\1@g')") + fi + echo "$file" +} + +open_cygwin() +{ + cygstart "$1" + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_darwin() +{ + open "$1" + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_kde() +{ + if [ -n "${KDE_SESSION_VERSION}" ]; then + case "${KDE_SESSION_VERSION}" in + 4) + kde-open "$1" + ;; + 5) + kde-open${KDE_SESSION_VERSION} "$1" + ;; + esac + else + kfmclient exec "$1" + kfmclient_fix_exit_code $? + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_dde() +{ + if dde-open -version >/dev/null 2>&1; then + dde-open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_gnome3() +{ + if gio help open 2>/dev/null 1>&2; then + gio open "$1" + elif gvfs-open --help 2>/dev/null 1>&2; then + gvfs-open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_gnome() +{ + if gio help open 2>/dev/null 1>&2; then + gio open "$1" + elif gvfs-open --help 2>/dev/null 1>&2; then + gvfs-open "$1" + elif gnome-open --help 2>/dev/null 1>&2; then + gnome-open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_mate() +{ + if gio help open 2>/dev/null 1>&2; then + gio open "$1" + elif gvfs-open --help 2>/dev/null 1>&2; then + gvfs-open "$1" + elif mate-open --help 2>/dev/null 1>&2; then + mate-open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_xfce() +{ + if exo-open --help 2>/dev/null 1>&2; then + exo-open "$1" + elif gio help open 2>/dev/null 1>&2; then + gio open "$1" + elif gvfs-open --help 2>/dev/null 1>&2; then + gvfs-open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_enlightenment() +{ + if enlightenment_open --help 2>/dev/null 1>&2; then + enlightenment_open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_flatpak() +{ + gdbus call --session \ + --dest org.freedesktop.portal.Desktop \ + --object-path /org/freedesktop/portal/desktop \ + --method org.freedesktop.portal.OpenURI.OpenURI \ + "" "$1" {} + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +#----------------------------------------- +# Recursively search .desktop file + +search_desktop_file() +{ + local default="$1" + local dir="$2" + local target="$3" + + local file="" + # look for both vendor-app.desktop, vendor/app.desktop + if [ -r "$dir/$default" ]; then + file="$dir/$default" + elif [ -r "$dir/`echo $default | sed -e 's|-|/|'`" ]; then + file="$dir/`echo $default | sed -e 's|-|/|'`" + fi + + if [ -r "$file" ] ; then + command="$(get_key "${file}" "Exec" | first_word)" + command_exec=`which $command 2>/dev/null` + icon="$(get_key "${file}" "Icon")" + # FIXME: Actually LC_MESSAGES should be used as described in + # http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s04.html + localised_name="$(get_key "${file}" "Name")" + set -- $(get_key "${file}" "Exec" | last_word) + # We need to replace any occurrence of "%f", "%F" and + # the like by the target file. We examine each + # argument and append the modified argument to the + # end then shift. + local args=$# + local replaced=0 + while [ $args -gt 0 ]; do + case $1 in + %[c]) + replaced=1 + arg="${localised_name}" + shift + set -- "$@" "$arg" + ;; + %[fFuU]) + replaced=1 + arg="$target" + shift + set -- "$@" "$arg" + ;; + %[i]) + replaced=1 + shift + set -- "$@" "--icon" "$icon" + ;; + *) + arg="$1" + shift + set -- "$@" "$arg" + ;; + esac + args=$(( $args - 1 )) + done + [ $replaced -eq 1 ] || set -- "$@" "$target" + "$command_exec" "$@" + + if [ $? -eq 0 ]; then + exit_success + fi + fi + + for d in $dir/*/; do + [ -d "$d" ] && search_desktop_file "$default" "$d" "$target" + done +} + + +open_generic_xdg_mime() +{ + filetype="$2" + default=`xdg-mime query default "$filetype"` + if [ -n "$default" ] ; then + xdg_user_dir="$XDG_DATA_HOME" + [ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share" + + xdg_system_dirs="$XDG_DATA_DIRS" + [ -n "$xdg_system_dirs" ] || xdg_system_dirs=/usr/local/share/:/usr/share/ + +DEBUG 3 "$xdg_user_dir:$xdg_system_dirs" + for x in `echo "$xdg_user_dir:$xdg_system_dirs" | sed 's/:/ /g'`; do + search_desktop_file "$default" "$x/applications/" "$1" + done + fi +} + +open_generic_xdg_file_mime() +{ + filetype=`xdg-mime query filetype "$1" | sed "s/;.*//"` + open_generic_xdg_mime "$1" "$filetype" +} + +open_generic_xdg_x_scheme_handler() +{ + scheme="`echo $1 | sed -n 's/\(^[[:alnum:]+\.-]*\):.*$/\1/p'`" + if [ -n $scheme ]; then + filetype="x-scheme-handler/$scheme" + open_generic_xdg_mime "$1" "$filetype" + fi +} + +open_envvar() +{ + local url="$1" + local oldifs="$IFS" + local browser browser_with_arg + + IFS=":" + for browser in $BROWSER; do + IFS="$oldifs" + + if [ -z "$browser" ]; then + continue + fi + + if echo "$browser" | grep -q %s; then + # Use loop to insert URL for avoid argument injection. + # See https://bugs.freedesktop.org/show_bug.cgi?id=103807 + shift $# + for arg in $browser; do + set -- "$@" "$(printf -- "$arg" "$url")" + done + "$@" + else + $browser "$url" + fi + + if [ $? -eq 0 ]; then + exit_success + fi + done +} + +open_generic() +{ + if is_file_url_or_path "$1"; then + local file="$(file_url_to_path "$1")" + + check_input_file "$file" + + if has_display; then + filetype=`xdg-mime query filetype "$file" | sed "s/;.*//"` + open_generic_xdg_mime "$file" "$filetype" + fi + + if which run-mailcap 2>/dev/null 1>&2; then + run-mailcap --action=view "$file" + if [ $? -eq 0 ]; then + exit_success + fi + fi + + if has_display && mimeopen -v 2>/dev/null 1>&2; then + mimeopen -L -n "$file" + if [ $? -eq 0 ]; then + exit_success + fi + fi + fi + + if has_display; then + open_generic_xdg_x_scheme_handler "$1" + fi + + if [ -n "$BROWSER" ]; then + open_envvar "$1" + fi + + # if BROWSER variable is not set, check some well known browsers instead + if [ x"$BROWSER" = x"" ]; then + BROWSER=www-browser:links2:elinks:links:lynx:w3m + if has_display; then + BROWSER=x-www-browser:firefox:iceweasel:seamonkey:mozilla:epiphany:konqueror:chromium:chromium-browser:google-chrome:$BROWSER + fi + fi + + open_envvar "$1" + + exit_failure_operation_impossible "no method available for opening '$1'" +} + +open_lxde() +{ + + # pcmanfm only knows how to handle file:// urls and filepaths, it seems. + if pcmanfm --help >/dev/null 2>&1 -a is_file_url_or_path "$1"; then + local file="$(file_url_to_path "$1")" + + # handle relative paths + if ! echo "$file" | grep -q ^/; then + file="$(pwd)/$file" + fi + + pcmanfm "$file" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_lxqt() +{ + open_generic "$1" +} + +[ x"$1" != x"" ] || exit_failure_syntax + +url= +while [ $# -gt 0 ] ; do + parm="$1" + shift + + case "$parm" in + -*) + exit_failure_syntax "unexpected option '$parm'" + ;; + + *) + if [ -n "$url" ] ; then + exit_failure_syntax "unexpected argument '$parm'" + fi + url="$parm" + ;; + esac +done + +if [ -z "${url}" ] ; then + exit_failure_syntax "file or URL argument missing" +fi + +if [ -e "${url}" ] ;then + url=`realpath ${url}` +fi + +detectDE + +if [ x"$DE" = x"" ]; then + DE=generic +fi + +DEBUG 2 "Selected DE $DE" + +# sanitize BROWSER (avoid caling ourselves in particular) +case "${BROWSER}" in + *:"xdg-open"|"xdg-open":*) + BROWSER=$(echo $BROWSER | sed -e 's|:xdg-open||g' -e 's|xdg-open:||g') + ;; + "xdg-open") + BROWSER= + ;; +esac + +open_deepin(){ + gdbus call --session --dest com.deepin.SessionManager --object-path /com/deepin/StartManager --method com.deepin.StartManager.RunCommand "xdg-open" "['${1}']" + #gdbus call --session --dest com.deepin.linglong.AppManager --object-path /com/deepin/linglong/PackageManager --method com.deepin.linglong.PackageManager.RunCommand "xdg-open" "['${1}']" +} + +open_ACE(){ +host-spawn xdg-open $@ +} + +open_other_sys(){ + systemd-run --user --service-type=forking /usr/bin/xdg-open "${1}" +} + +case "$DE" in + kde) + open_ACE "$url" + ;; + + dde) + open_ACE "$url" + ;; + + gnome3|cinnamon) + open_ACE "$url" + ;; + + gnome) + open_ACE "$url" + ;; + + mate) + open_ACE "$url" + ;; + + xfce) + open_ACE "$url" + ;; + + lxde) + open_ACE "$url" + ;; + + lxqt) + open_ACE "$url" + ;; + + enlightenment) + open_ACE "$url" + ;; + + cygwin) + open_ACE "$url" + ;; + + darwin) + open_ACE "$url" + ;; + + flatpak) + open_ACE "$url" + ;; + + generic) + open_ACE "$url" + ;; + + *) + exit_failure_operation_impossible "no method available for opening '$url'" + ;; +esac diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/container-init/init.sh b/src/var/lib/apm/apm/files/amber-ce-tools/container-init/init.sh new file mode 100755 index 0000000..dc7b66f --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/container-init/init.sh @@ -0,0 +1,143 @@ +#!/bin/bash +if [ "$IS_ACE_ENV" != "1" ];then +echo "ONLY RUN ME IN ACE" +exit +fi + + + + printf "ACE: Setting up sudo...\n" + mkdir -p /etc/sudoers.d + # Do not check fqdn when doing sudo, it will not work anyways + if ! grep -q 'Defaults !fqdn' /etc/sudoers.d/sudoers; then + printf "Defaults !fqdn\n" >> /etc/sudoers.d/sudoers + fi + # Ensure passwordless sudo is set up for user + if ! grep -q "\"${container_user_name}\" ALL = (root) NOPASSWD:ALL" /etc/sudoers.d/sudoers; then + printf "\"%s\" ALL = (root) NOPASSWD:ALL\n" "${container_user_name}" >> /etc/sudoers.d/sudoers + fi + + + + +printf "ACE: Setting up groups...\n" +# If not existing, ensure we have a group for our user. +if ! grep -q "^${container_user_name}:" /etc/group; then + if ! groupadd --force --gid "${container_user_gid}" "${container_user_name}"; then + # It may occur that we have users with unsupported user name (eg. on LDAP or AD) + # So let's try and force the group creation this way. + printf "%s:x:%s:" "${container_user_name}" "${container_user_gid}" >> /etc/group + fi +fi + +printf "ACE: Setting up users...\n" + +# Setup kerberos integration with the host +if [ -d "/run/host/var/kerberos" ] && + [ -d "/etc/krb5.conf.d" ] && + [ ! -e "/etc/krb5.conf.d/kcm_default_ccache" ]; then + + cat << EOF > "/etc/krb5.conf.d/kcm_default_ccache" +# # To disable the KCM credential cache, comment out the following lines. +[libdefaults] + default_ccache_name = KCM: +EOF +fi + +# If we have sudo/wheel groups, let's add the user to them. +additional_groups="" +if grep -q "^sudo" /etc/group; then + additional_groups="sudo" +elif grep -q "^wheel" /etc/group; then + additional_groups="wheel" +fi + +# Let's add our user to the container. if the user already exists, enforce properties. +# +# In case of AD or LDAP usernames, it is possible we will have a backslach in the name. +# In that case grep would fail, so we replace the backslash with a point to make the regex work. +# shellcheck disable=SC1003 +if ! grep -q "^$(printf '%s' "${container_user_name}" | tr '\\' '.'):" /etc/passwd && + ! grep -q "^.*:.*:${container_user_uid}:" /etc/passwd; then + if ! useradd \ + --home-dir "${container_user_home}" \ + --no-create-home \ + --groups "${additional_groups}" \ + --shell "${SHELL:-"/bin/bash"}" \ + --uid "${container_user_uid}" \ + --gid "${container_user_gid}" \ + "${container_user_name}"; then + + printf "Warning: there was a problem setting up the user\n" + printf "Warning: trying manual addition\n" + printf "%s:x:%s:%s:%s:%s:%s" \ + "${container_user_name}" "${container_user_uid}" \ + "${container_user_gid}" "${container_user_name}" \ + "${container_user_home}" "${SHELL:-"/bin/bash"}" >> /etc/passwd + printf "%s::1::::::" "${container_user_name}" >> /etc/shadow + fi +# Ensure we're not using the specified SHELL. Run it only once, so that future +# user's preferences are not overwritten at each start. +elif [ ! -e /etc/passwd.done ]; then + # This situation is presented when podman or docker already creates the user + # for us inside container. We should modify the user's prepopulated shadowfile + # entry though as per user's active preferences. + + # If the user was there with a different username, get that username so + # we can modify it + if ! grep -q "^$(printf '%s' "${container_user_name}" | tr '\\' '.'):" /etc/passwd; then + user_to_modify=$(getent passwd "${container_user_uid}" | cut -d: -f1) + fi + + if ! usermod \ + --home "${container_user_home}" \ + --shell "${SHELL:-"/bin/bash"}" \ + --groups "${additional_groups}" \ + --uid "${container_user_uid}" \ + --gid "${container_user_gid}" \ + --login "${container_user_name}" \ + "${user_to_modify:-"${container_user_name}"}"; then + + printf "Warning: there was a problem setting up the user\n" + fi + touch /etc/passwd.done +fi + +# We generate a random password to initialize the entry for the user and root. +temporary_password="$(cat /proc/sys/kernel/random/uuid)" +printf "%s\n%s\n" "${temporary_password}" "${temporary_password}" | passwd root +printf "%s:%s" "${container_user_name}" "${temporary_password}" | chpasswd -e +# Delete password for root and user +printf "%s:" "root" | chpasswd -e +printf "%s:" "${container_user_name}" | chpasswd -e + +mkdir -p /usr/share/fonts +mkdir -p /usr/share/icons +mkdir -p /usr/share/themes + +## init host-spawn +unlink /amber-ce-tools/bin-override/host-spawn +ln -sfv /amber-ce-tools/bin-override/host-spawn-$(uname -m) /amber-ce-tools/bin-override/host-spawn + + + + + +exit 0 + +## install host-integration +pushd /amber-ce-tools/ace-host-integration + +dpkg-deb -Z xz -b . ../ace-host-integration.deb + +popd +apt install --reinstall /amber-ce-tools/ace-host-integration.deb -y + + +cd /amber-ce-tools/data-dir/ +ln -sfv ../../usr/share/applications/ . +ln -sfv ../../usr/share/icons/ . +#ln -svf ../../usr/share/mime . +rm -vf ./mime +update-desktop-database /usr/share/applications || true +update-mime-database /usr/share/mime || true diff --git a/src/var/lib/apm/apm/files/amber-ce-tools/data-dir/README.md b/src/var/lib/apm/apm/files/amber-ce-tools/data-dir/README.md new file mode 100755 index 0000000..1954e05 --- /dev/null +++ b/src/var/lib/apm/apm/files/amber-ce-tools/data-dir/README.md @@ -0,0 +1 @@ +# App in this dir will be integrated to host os. Will create symbol link when installing diff --git a/src/var/lib/apm/apm/files/bin/ace-gxde-fixer b/src/var/lib/apm/apm/files/bin/ace-gxde-fixer new file mode 100755 index 0000000..f4c25c7 --- /dev/null +++ b/src/var/lib/apm/apm/files/bin/ace-gxde-fixer @@ -0,0 +1,7 @@ +#!/bin/bash +if [ "$UID" != "0" ];then +pkexec $0 +exit +fi + +apm-debug amber-pm-dstore-patch diff --git a/src/var/lib/apm/apm/files/bin/ace-init b/src/var/lib/apm/apm/files/bin/ace-init new file mode 100755 index 0000000..bb07c71 --- /dev/null +++ b/src/var/lib/apm/apm/files/bin/ace-init @@ -0,0 +1,116 @@ +#!/bin/bash + +if [ "$(id -u)" != "0" ]; then + echo "当前用户不是 root 用户,退出" + exit +fi +if [ "$PACKAGE_NAME" = "" ];then +curdir=`realpath $0` +parent_dir=`dirname $curdir` +pparent_dir=`dirname $parent_dir` +ppparent_dir=`dirname $pparent_dir` +PKGNAME=`basename $ppparent_dir` +else + +PKGNAME=$PACKAGE_NAME +fi +chrootEnvPath=/var/lib/apm/$PKGNAME/files/ace-env +#if [ ! -e $chrootEnvPath ];then +echo "Uncompress the env...." +tar -xvf $chrootEnvPath.tar.xz -C /var/lib/apm/$PKGNAME/files/ +#fi + +HERE="$(dirname $(realpath $0))" + +function get_current_user() { + # 优先通过 who 命令获取用户 + local user + user=$(who | awk '{print $1}' | head -n 1 2>/dev/null) + + # 如果 who 无输出,则通过 loginctl 获取 + if [[ -z "$user" ]]; then + user=$(loginctl list-sessions --no-legend 2>/dev/null | awk '{print $3}' | head -n 1) + fi + + # 返回最终结果(可能为空) + echo "${user}" +} +non_root_user=$(get_current_user) +uid=$(id -u $non_root_user) + +function bookworm-run(){ +bwrap --dev-bind $chrootEnvPath/ / \ + --setenv PULSE_SERVER /run/user/$uid/pulse/native \ + --setenv PATH /amber-ce-tools/bin-override:$PATH \ + --setenv IS_ACE_ENV "1" \ + --dev-bind-try /media /media \ + --dev-bind-try /tmp /tmp \ + --dev /dev \ + --dev-bind-try /dev/dri /dev/dri \ + --proc /proc \ + --dev-bind / /host \ + --dev-bind /sys /sys \ + --dev-bind /run /run \ + --dev-bind-try /run/user/$uid/pulse /run/user/$uid/pulse \ + --bind-try /usr/share/themes /usr/local/share/themes \ + --bind-try /usr/share/icons /usr/local/share/icons \ + --bind-try /usr/share/fonts /usr/local/share/fonts \ + --hostname Amber-PM \ + --unshare-uts \ + --dev-bind-try /etc/resolv.conf /etc/resolv.conf \ + --dev-bind-try /home /home \ + $@ + + +} + +echo "Update the flamescion container tools" +cp -r `dirname $chrootEnvPath`/amber-ce-tools/ $chrootEnvPath + + +export container_user_gid="$(sudo -u $non_root_user id -rg)" +export container_user_home="/home/${non_root_user}" +export container_user_name="${non_root_user}" +export container_user_uid="$(sudo -u $non_root_user id -ru)" + + + + +#####init + + +bookworm-run bash /amber-ce-tools/container-init/init.sh +rm $chrootEnvPath/etc/localtime +cp $(realpath /etc/localtime) $chrootEnvPath/etc/localtime +chmod 777 $chrootEnvPath/etc/localtime +bookworm-run cp /host/etc/locale.gen /etc/locale.gen && locale-gen +bookworm-run touch /finish.flag +bookworm-run apt clean +bookworm-run chown -R $(get_current_user) /usr/lib/locale/ +sudo -u $(get_current_user) bwrap --dev-bind $chrootEnvPath/ / \ + --setenv PULSE_SERVER /run/user/$uid/pulse/native \ + --setenv PATH /amber-ce-tools/bin-override:$PATH \ + --setenv IS_ACE_ENV "1" \ + --dev-bind $chrootEnvPath/ / \ + --dev-bind-try /media /media \ + --dev-bind-try /tmp /tmp \ + --dev /dev \ + --dev-bind-try /dev/dri /dev/dri \ + --proc /proc \ + --dev-bind /sys /sys \ + --dev-bind /run /run \ + --dev-bind-try /run/user/$uid/pulse /run/user/$uid/pulse \ + --dev-bind / /host \ + --bind-try /usr/share/themes /usr/local/share/themes \ + --bind-try /usr/share/icons /usr/local/share/icons \ + --bind-try /usr/share/fonts /usr/local/share/fonts \ + --hostname Amber-PM \ + --unshare-uts \ + --dev-bind-try /etc/resolv.conf /etc/resolv.conf \ + --dev-bind-try /home /home \ + locale-gen +bookworm-run update-locale LANG=$LANG +chown -R root $chrootEnvPath +chmod 777 -R $chrootEnvPath/usr/share/icons +rm -vfr $chrootEnvPath/dev/* +true \ No newline at end of file diff --git a/src/var/lib/apm/apm/files/bin/ace-run b/src/var/lib/apm/apm/files/bin/ace-run new file mode 100755 index 0000000..adf907c --- /dev/null +++ b/src/var/lib/apm/apm/files/bin/ace-run @@ -0,0 +1,154 @@ +#!/bin/bash + +curdir=`realpath $0` +parent_dir=`dirname $curdir` +pparent_dir=`dirname $parent_dir` +ppparent_dir=`dirname $pparent_dir` +PKGNAME=`basename $ppparent_dir` +export ACE_PACKAGE_NAME=$PKGNAME + +chrootEnvPath=/var/lib/apm/$PKGNAME/files/ace-env + +if [ ! -e $chrootEnvPath/finish.flag ];then + +if [ "$(id -u)" = "0" ]; then + `dirname $chrootEnvPath`/bin/ace-init +else +pkexec `dirname $chrootEnvPath`/bin/ace-init +fi + + +fi +non_root_user=$(who | awk '{print $1}' | head -n 1) +uid=$(id -u $non_root_user) + + +#### This part is for args pharm +if [ "$1" = "" ];then +container_command="bash" +else +container_command="$1" +shift +for arg in "$@"; do + arg="$(echo "${arg}x" | sed 's|'\''|'\'\\\\\'\''|g')" + arg="${arg%x}" + container_command="${container_command} '${arg}'" +done +fi +######################################################################################### +##########合成bwrap 1. 基础函数配置段 +# 初始化 EXEC_COMMAND 为 bwrap 基础指令 +EXEC_COMMAND="bwrap --dev-bind / / bwrap" + +# add_command 函数定义 +function add_command() { + # 参数拼接,考虑到转义和空格的处理 + for arg in "$@"; do + EXEC_COMMAND="${EXEC_COMMAND} ${arg}" + done +} + +function add_env_var() { + local var_name="${1}" + local var_value="${2}" + if [ "$var_value" != "" ]; then + add_command "--setenv $var_name $var_value" + + fi +} +##########合成bwrap 2. 特殊需求函数配置段 +function cursor_theme_dir_integration() { + +local directory="" +if [ "$(id -u)" = "0" ]; then #####We don't want bother root to install themes,but will try to fix the unwriteable issue + mkdir -p $chrootEnvPath/usr/share/icons + chmod 777 -R $chrootEnvPath/usr/share/icons + return +fi + +for directory in "/usr/share/icons"/*; do + # 检查是否为目录 + if [ -d "$directory" ]; then + # 检查目录中是否存在 cursors 文件 + if [ -d "$directory/cursors" ]; then + if [ -w $chrootEnvPath/usr/share/icons ];then + add_command "--ro-bind-try $directory $directory" + fi + fi + fi +done + + + + + + + +} +##########合成bwrap 3. 环境变量和目录绑定配置段 +# 添加环境变量和其他初始设置 +ENV_VARS=( + "FAKEROOTDONTTRYCHOWN 1" + "PULSE_SERVER /run/user/\$uid/pulse/native" + "PATH /amber-ce-tools/bin-override:\$PATH" + "IS_ACE_ENV 1" + "IS_APM_ENV 1" + "XDG_DATA_DIRS /amber-ce-tools/additional-data-dir-in-container:\$XDG_DATA_DIRS" +) + +BIND_DIRS=( + "--dev-bind $chrootEnvPath/ /" + "--dev-bind-try /media /media" + "--dev-bind-try /mnt /mnt" + "--dev-bind-try /tmp /tmp" + "--dev-bind-try /data /data" + "--dev-bind-try /dev /dev" + "--proc /proc" + "--dev-bind /sys /sys" + "--dev-bind /run /run" + "--dev-bind-try /run/user/\$uid/pulse /run/user/\$uid/pulse" + "--dev-bind / /host" + "--ro-bind-try /usr/share/themes /usr/local/share/themes" + "--ro-bind-try /usr/share/icons /usr/local/share/icons" + "--ro-bind-try /usr/share/fonts /usr/local/share/fonts" + "--dev-bind-try /etc/resolv.conf /etc/resolv.conf" + "--dev-bind-try /home /home" +) +EXTRA_ARGS=( + "--hostname Amber-PM" + "--unshare-uts" + "--cap-add CAP_SYS_ADMIN" +) + +EXTRA_SCRIPTS=( +# cursor_theme_dir_integration +) + +##########合成bwrap 4. 合成并执行指令 +# 逐一添加到 EXEC_COMMAND +for var in "${ENV_VARS[@]}"; do + add_env_var $var +done + +for var in "${BIND_DIRS[@]}"; do + add_command "$var" +done + +for var in "${EXTRA_ARGS[@]}"; do + add_command "$var" +done + +for var in "${EXTRA_SCRIPTS[@]}"; do + $var +done + +# 添加最终的 bash 命令 +add_command "bash -c \"${container_command}\"" + +# 输出完整的 EXEC_COMMAND 以查看 +# echo "${EXEC_COMMAND}" + +# 注意: 实际执行时,请确保所有变量(如 $uid, $chrootEnvPath 等)都已正确定义 +eval ${EXEC_COMMAND} + + diff --git a/src/var/lib/apm/apm/files/bin/ace-run-bwrap b/src/var/lib/apm/apm/files/bin/ace-run-bwrap new file mode 100755 index 0000000..cec85f0 --- /dev/null +++ b/src/var/lib/apm/apm/files/bin/ace-run-bwrap @@ -0,0 +1,155 @@ +#!/bin/bash + +curdir=`realpath $0` +parent_dir=`dirname $curdir` +pparent_dir=`dirname $parent_dir` +ppparent_dir=`dirname $pparent_dir` +PKGNAME=`basename $ppparent_dir` +export ACE_PACKAGE_NAME=$PKGNAME + +chrootEnvPath=/var/lib/apm/$PKGNAME/files/ace-env + +if [ ! -e $chrootEnvPath/finish.flag ];then + +if [ "$(id -u)" = "0" ]; then + `dirname $chrootEnvPath`/bin/ace-init +else +pkexec `dirname $chrootEnvPath`/bin/ace-init +fi + + +fi +non_root_user=$(who | awk '{print $1}' | head -n 1) +uid=$(id -u $non_root_user) + + +#### This part is for args pharm +if [ "$1" = "" ];then +container_command="bash" +else +container_command="$1" +shift +for arg in "$@"; do + arg="$(echo "${arg}x" | sed 's|'\''|'\'\\\\\'\''|g')" + arg="${arg%x}" + container_command="${container_command} '${arg}'" +done +fi +######################################################################################### +##########合成bwrap 1. 基础函数配置段 +# 初始化 EXEC_COMMAND 为 bwrap 基础指令 +EXEC_COMMAND="bwrap --dev-bind / / bwrap" + +# add_command 函数定义 +function add_command() { + # 参数拼接,考虑到转义和空格的处理 + for arg in "$@"; do + EXEC_COMMAND="${EXEC_COMMAND} ${arg}" + done +} + +function add_env_var() { + local var_name="${1}" + local var_value="${2}" + if [ "$var_value" != "" ]; then + add_command "--setenv $var_name $var_value" + + fi +} +##########合成bwrap 2. 特殊需求函数配置段 +function cursor_theme_dir_integration() { + +local directory="" +if [ "$(id -u)" = "0" ]; then #####We don't want bother root to install themes,but will try to fix the unwriteable issue + mkdir -p $chrootEnvPath/usr/share/icons + chmod 777 -R $chrootEnvPath/usr/share/icons + return +fi + +for directory in "/usr/share/icons"/*; do + # 检查是否为目录 + if [ -d "$directory" ]; then + # 检查目录中是否存在 cursors 文件 + if [ -d "$directory/cursors" ]; then + if [ -w $chrootEnvPath/usr/share/icons ];then + add_command "--ro-bind-try $directory $directory" + fi + fi + fi +done + + + + + + + +} +##########合成bwrap 3. 环境变量和目录绑定配置段 +# 添加环境变量和其他初始设置 +ENV_VARS=( + "FAKEROOTDONTTRYCHOWN 1" + "PULSE_SERVER /run/user/\$uid/pulse/native" + "PATH /amber-ce-tools/bin-override:\$PATH" + "IS_ACE_ENV 1" + "XDG_DATA_DIRS /amber-ce-tools/additional-data-dir-in-container:\$XDG_DATA_DIRS" +) + +BIND_DIRS=( + "--dev-bind $chrootEnvPath/ /" + "--dev-bind-try /media /media" + "--dev-bind-try /mnt /mnt" + "--dev-bind-try /tmp /tmp" + "--dev-bind-try /data /data" + "--dev-bind-try /dev /dev" + "--proc /proc" + "--dev-bind /sys /sys" + "--dev-bind /run /run" + "--dev-bind-try /run/user/\$uid/pulse /run/user/\$uid/pulse" + "--dev-bind / /host" + "--ro-bind-try /usr/share/themes /usr/local/share/themes" + "--ro-bind-try /usr/share/icons /usr/local/share/icons" + "--ro-bind-try /usr/share/fonts /usr/local/share/fonts" + "--dev-bind-try /etc/resolv.conf /etc/resolv.conf" + "--dev-bind-try /home /home" +) +EXTRA_ARGS=( + "--hostname Amber-PM" + "--unshare-uts" +# "--cap-add CAP_SYS_ADMIN" +) + +EXTRA_SCRIPTS=( + cursor_theme_dir_integration +) + +##########合成bwrap 4. 合成并执行指令 +# 逐一添加到 EXEC_COMMAND +for var in "${ENV_VARS[@]}"; do + add_env_var $var +done + +for var in "${BIND_DIRS[@]}"; do + add_command "$var" +done + +for var in "${EXTRA_ARGS[@]}"; do + add_command "$var" +done + +for var in "${EXTRA_SCRIPTS[@]}"; do + $var +done + + + +# 添加最终的 bash 命令 +add_command "bash -c \"/usr/bin/bwrap ${container_command}\"" + +# 输出完整的 EXEC_COMMAND 以查看 +# echo "${EXEC_COMMAND}" + +# 注意: 实际执行时,请确保所有变量(如 $uid, $chrootEnvPath 等)都已正确定义 +eval ${EXEC_COMMAND} + + diff --git a/src/var/lib/apm/apm/files/bin/ace-uninstall-helper b/src/var/lib/apm/apm/files/bin/ace-uninstall-helper new file mode 100755 index 0000000..cfbb7b5 --- /dev/null +++ b/src/var/lib/apm/apm/files/bin/ace-uninstall-helper @@ -0,0 +1,91 @@ +#!/bin/bash + +if [ "$UID" != "0" ];then +echo "Need to be run as root." +exit 1 +fi +# 清除先前的变量值 +unset ABSOLUTE_PATH IN_CONTAINER_PATH PKGNAME_GUESS DPKG_LIST_FILE ACE_ENV_PATH + +# 定义环境路径变量 +ACE_ENV_PATH="/var/lib/apm/apm/files/ace-env" + +# 检查参数个数 +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +# 保存并验证绝对路径 +ABSOLUTE_PATH=$1 +if [[ $ABSOLUTE_PATH != "$ACE_ENV_PATH"* ]]; then + echo "Error: Invalid path. Must start with $ACE_ENV_PATH" + exit 1 +fi + +# 验证是否为desktop文件 +if [[ ! $ABSOLUTE_PATH == *.desktop ]]; then + if [ ! -e $ABSOLUTE_PATH ];then + echo "$ABSOLUTE_PATH does not exist. May have already been uninstalled. Ignore it." + exit + else + echo "Error: The file is not a desktop file." + exit 1 + fi +fi + +# 截取路径 +IN_CONTAINER_PATH=${ABSOLUTE_PATH#"$ACE_ENV_PATH"} + +# 截取并保存包名 +PKGNAME_GUESS=$(basename "$ABSOLUTE_PATH" .desktop) + +# 检查dpkg列表文件 +DPKG_INFO_PATH="$ACE_ENV_PATH/var/lib/dpkg/info" +if [ -f "$DPKG_INFO_PATH/$PKGNAME_GUESS.list" ]; then + DPKG_LIST_FILE="$DPKG_INFO_PATH/$PKGNAME_GUESS.list" +elif ls "$DPKG_INFO_PATH/${PKGNAME_GUESS}:*.list" 1> /dev/null 2>&1; then + DPKG_LIST_FILE=$(ls "$DPKG_INFO_PATH/${PKGNAME_GUESS}:*.list" | head -n 1) +else + echo "Warn:No dpkg list file found for $PKGNAME_GUESS.desktop,try to scan to search for the package" +fi + +# 验证文件并执行操作 +if [ -f "$DPKG_LIST_FILE" ]; then + + if grep -q "$IN_CONTAINER_PATH" "$DPKG_LIST_FILE" || grep -q "/var/lib/apm/$PKGNAME_GUESS/entries/applications/$PKGNAME_GUESS.desktop" "$DPKG_LIST_FILE"; then + apm-debug apt autopurge $PKGNAME_GUESS -y + ret=$? + if [ "$ret" = "0" ];then + echo "Operation succeeded." + exit + else + echo "Operation failed." + exit $ret + fi + + else + echo "Warn: Path not found in the dpkg list file,try to scan to search for the package" + fi +fi + # 遍历所有list文件 As fallback + for file in "$DPKG_INFO_PATH"/*.list; do + if grep -q "$IN_CONTAINER_PATH" "$file"; then + PKGNAME_GUESS=$(basename "$file" .list | cut -d':' -f1) + echo "Get pkgname $PKGNAME_GUESS, uninstalling..." + apm-debug apt autopurge $PKGNAME_GUESS -y + ret=$? + if [ "$ret" = "0" ];then + echo "Operation succeeded." + exit 0 + else + echo "Operation failed." + exit $ret + fi + + fi + done + echo "Error: No matching package found." + exit 1 + + diff --git a/src/var/lib/apm/apm/files/bin/ace-uninstall-helper-gui b/src/var/lib/apm/apm/files/bin/ace-uninstall-helper-gui new file mode 100755 index 0000000..72b613f --- /dev/null +++ b/src/var/lib/apm/apm/files/bin/ace-uninstall-helper-gui @@ -0,0 +1,77 @@ +#!/bin/bash +if [ "$UID" != "0" ];then +pkexec $0 +exit +fi +# 定义应用列表文件路径 +ACE_dir="/var/lib/apm/apm/files/ace-env" +HERE="$(dirname $(realpath $0))" +# 读取所有.desktop文件,并构造应用列表 +app_list=() +for file in "$ACE_dir"/usr/share/applications/*.desktop; do + if [ ! -e "$file" ];then ##可能是软链接,对主机来说无用 + file=$ACE_dir$(readlink $file) + fi + if [ "$(grep -m 1 '^NoDisplay=' "$file" | cut -d '=' -f 2)" = "true" ] || [ "$(grep -m 1 '^NoDisplay=' "$file" | cut -d '=' -f 2)" = "True" ];then + continue + fi + # 读取应用名称和简介 + name_orig=$(grep -m 1 '^Name=' "$file" | cut -d '=' -f 2) + name_i18n=$(grep -m 1 "^Name\[${LANGUAGE}\]\=" "$file" | cut -d '=' -f 2) + if [ -z "$name_i18n" ] ;then + name=$name_orig + else + name=$name_i18n + fi + comment_orig=$(grep -m 1 '^Comment=' "$file" | cut -d '=' -f 2) + comment_i18n=$(grep -m 1 "^Comment\[${LANGUAGE}\]\=" "$file" | cut -d '=' -f 2) + if [ -z "$comment_i18n" ] ;then + comment=$comment_orig + else + comment=$comment_i18n + fi + # 如果没有简介,则显示"N/A" + [[ -z "$comment" ]] && comment="N/A" + # 添加到应用列表数组 + app_list+=("false" "$name" "$comment" "$file") +done + +# 使用 Zenity 显示应用列表,并获取用户选择 +selected_apps=$(zenity --list --title "应用列表" --column "是否卸载" --column "应用名称" --column "应用介绍" --column "desktop文件位置" --checklist "${app_list[@]}" --print-column=4 --hide-column=4 --separator=" " --width=800 --height=400) + + +# 检查用户是否做出了选择 +if [ -n "$selected_apps" ]; then + # 卸载选中的应用 + (for app_desktop_path in $selected_apps; do + ${HERE}/ace-uninstall-helper "$app_desktop_path" + ret=$? + if [ "$ret" != "0" ];then + zenity --error --width 768 --text "$app_desktop_path 卸载失败,中止操作\n请手动执行\nsudo $0 $app_desktop_path \n查看报错!" + exit 1 + break + fi + done ) & + + cmd_pid=$! + + + (while kill -0 $cmd_pid 2> /dev/null; do + echo "# 正在执行..." + sleep 1 + done)| zenity --progress --text="正在执行卸载操作..." --pulsate --auto-close --no-cancel --width 400 +wait $cmd_pid +cmd_status=$? + + if [ "$cmd_status" = "1" ];then + zenity --error --width 200 --text "卸载过程出现错误" + exit 1 + else + zenity --info --width 200 --text "选定应用已卸载" + fi + + +else + zenity --info --text "未选择任何应用" +fi + diff --git a/src/var/lib/apm/apm/files/bin/amber-ce-configure-nvidia b/src/var/lib/apm/apm/files/bin/amber-ce-configure-nvidia new file mode 100755 index 0000000..f52ea7b --- /dev/null +++ b/src/var/lib/apm/apm/files/bin/amber-ce-configure-nvidia @@ -0,0 +1,71 @@ +#!/bin/bash +log.warn() { echo -e "[\e[33mWARN\e[0m]: \e[1m$*\e[0m"; } +log.error() { echo -e "[\e[31mERROR\e[0m]: \e[1m$*\e[0m"; } +log.info() { echo -e "[\e[96mINFO\e[0m]: \e[1m$*\e[0m"; } +log.debug() { echo -e "[\e[32mDEBUG\e[0m]: \e[1m$*\e[0m"; } + +if [ "$UID" != "0" ];then +log.error "需要以root权限运行 Need to be run as root." +exit 1 +fi + +if [ -z "$1" ];then +log.error "需要把ace-env所在的路径设置为第一个参数" +exit 1 +fi + +# 1\. 获取宿主机 NVIDIA 驱动版本 +nvidia_version=$(cat /sys/module/nvidia/version 2>/dev/null) +if [ -z "$nvidia_version" ]; then + log.warn "无法获取 NVIDIA 驱动版本 Can not determine NVIDIA Driver version" + exit 1 +fi + +# 2\. 目标目录准备 +ACE_DIR="$1" +if [[ ! -e "${ACE_DIR}" ]];then +log.error "未检测到 apm安装,请安装后再试 apm is not detected. Please try again after installation" +log.info "请按回车关闭... Press Enter to close..." +read +exit 1 +fi +mkdir -p "$ACE_DIR/usr/lib" "$ACE_DIR/usr/lib32" + +log.info "正在链接 NVIDIA 驱动库 Linking NVIDIA Driver Libs" + +# 3\. 收集库文件路径 +lib_list=$(ldconfig -p | grep -Ei "nvidia|libcuda" | cut -d'>' -f2) + +# 4\. 复制库文件 +copied=0 +for lib in $lib_list; do + resolved=$(readlink -f "$lib") # 解析符号链接 + if file "$resolved" | grep -q "32-bit"; then + ln -sf "/host/$resolved" "$ACE_DIR/usr/lib32/$(basename $lib)" + else + ln -sf "/host/$resolved" "$ACE_DIR/usr/lib/$(basename $lib)" + copied=1 + fi +done + +# 5\. 复制辅助文件 +additional_files=( + /usr/share/vulkan/icd.d/nvidia_icd.json + /usr/share/egl/egl_external_platform.d/20_nvidia_xcb.json +) +for file in "${additional_files[@]}"; do + if [ -f "$file" ]; then + file=$(readlink -f "$file") + dir=$(dirname "$file") + mkdir -p "$ACE_DIR/$dir" + ln -sf "/host/$file" "$ACE_DIR/$dir" + fi +done + +# 6\. 标记版本 +if [ $copied -eq 1 ]; then + echo "$nvidia_version" > "$ACE_DIR/current_version" + log.info "NVIDIA 驱动库已成功链接 Nvidia Driver Libs are successfully linked. " +else + log.info "未找到有效 NVIDIA 库文件 No valid NVIDIA Driver Libs found." +fi \ No newline at end of file diff --git a/src/var/lib/apm/apm/files/build-container.sh b/src/var/lib/apm/apm/files/build-container.sh new file mode 100755 index 0000000..77f9f4f --- /dev/null +++ b/src/var/lib/apm/apm/files/build-container.sh @@ -0,0 +1,60 @@ +#!/bin/bash +set -e +if [ `which debootstrap` = "" ];then +echo "Need to install debootstrap!" +exit +fi + +if [ `which systemd-nspawn` = "" ];then +echo "Need to install systemd-container!" +exit +fi +if [ "$2" = "" ];then +echo "Usage: $0 ARCHITECTURE CODENAME" +exit +fi + +sudo cp /usr/share/debootstrap/scripts/sid /usr/share/debootstrap/scripts/crimson -v +sudo cp /usr/share/debootstrap/scripts/sid /usr/share/debootstrap/scripts/beige -v + +CODENAME=$2 + +# Set distroname and components based on codename +if [ "$CODENAME" = "beige" ] || [ "$CODENAME" = "crimson" ]; then + DISTRONAME="deepin/beige" + COMPONENTS="main,community,commercial" + GPG_CHECK="--no-check-gpg" +else + DISTRONAME="debian" + COMPONENTS="main,contrib,non-free,non-free-firmware" + GPG_CHECK="" +fi + +if [ "$1" = "amd64" ] || [ "$1" = "x86_64" ];then +ARCH="amd64" +ARCH_ANOTHERWAY="x64" +cd "`dirname $0`" +sudo debootstrap $GPG_CHECK --components=$COMPONENTS --include=libnotify-bin,apt-utils,bash-completion,bc,curl,dialog,diffutils,findutils,less,libnss-myhostname,libvte-common,lsof,ncurses-base,passwd,pinentry-curses,procps,sudo,time,util-linux,wget,libegl1,libvulkan1,mesa-vulkan-drivers,locales,libglib2.0-bin --arch=${ARCH} $2 ./ace-env https://mirrors.cernet.edu.cn/${DISTRONAME}/ + +elif [ "$1" = "arm64" ] || [ "$1" = "arm" ]|| [ "$1" = "aarch64" ];then +ARCH="arm64" +ARCH_ANOTHERWAY="arm64" +cd "`dirname $0`" +sudo debootstrap $GPG_CHECK --components=$COMPONENTS --include=libnotify-bin,apt-utils,bash-completion,bc,curl,dialog,diffutils,findutils,less,libnss-myhostname,libvte-common,lsof,ncurses-base,passwd,pinentry-curses,procps,sudo,time,util-linux,wget,libegl1,libvulkan1,mesa-vulkan-drivers,locales,libglib2.0-bin --arch=${ARCH} $2 ./ace-env https://mirrors.cernet.edu.cn/${DISTRONAME}/ + +elif [ "$1" = "loong64" ] || [ "$1" = "loongarch64" ];then + if [ "$CODENAME" = "beige" ] || [ "$CODENAME" = "crimson" ]; then + ARCH="loong64" + ARCH_ANOTHERWAY="loongarch64" + cd "`dirname $0`" + sudo debootstrap $GPG_CHECK --components=$COMPONENTS --include=libnotify-bin,apt-utils,bash-completion,bc,curl,dialog,diffutils,findutils,less,libnss-myhostname,libvte-common,lsof,ncurses-base,passwd,pinentry-curses,procps,sudo,time,util-linux,wget,libegl1,libvulkan1,mesa-vulkan-drivers,locales,libglib2.0-bin --arch=${ARCH} $2 ./ace-env https://mirrors.cernet.edu.cn/${DISTRONAME}/ + else + echo "LoongArch64 is only supported on Deepin (beige/crimson)" + exit 1 + fi +fi + +sudo rm -rf ace-env/var/cache/apt/archives/*.deb +sudo rm -vfr ace-env/dev/* +sudo tar -I 'xz -T0' -cvf ace-env.tar.xz ace-env/* +sudo rm -rf ace-env \ No newline at end of file