mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-04-26 09:20:18 +08:00
完成aptss对接
This commit is contained in:
@@ -180,7 +180,7 @@ ipcMain.on("queue-install", async (event, download_json) => {
|
||||
}
|
||||
|
||||
if (metalinkUrl && filename) {
|
||||
execParams.push("aptss", "ssaudit", `${downloadDir}/${filename}`);
|
||||
execParams.push("ssinstall", `${downloadDir}/${filename}` , "--delete-after-install");
|
||||
} else {
|
||||
execParams.push("aptss", "install", "-y", pkgname);
|
||||
}
|
||||
@@ -395,36 +395,34 @@ ipcMain.handle("check-installed", async (_event, pkgname: string) => {
|
||||
logger.warn("check-installed missing pkgname");
|
||||
return false;
|
||||
}
|
||||
let isInstalled = false;
|
||||
|
||||
logger.info(`检查应用是否已安装: ${pkgname}`);
|
||||
|
||||
const child = spawn(
|
||||
SHELL_CALLER_PATH,
|
||||
["aptss", "list", "--installed", pkgname],
|
||||
{
|
||||
shell: true,
|
||||
env: process.env,
|
||||
},
|
||||
);
|
||||
const checkScript = "/opt/spark-store/extras/check-is-installed";
|
||||
let isInstalled = false;
|
||||
|
||||
let output = "";
|
||||
|
||||
child.stdout.on("data", (data) => {
|
||||
output += data.toString();
|
||||
const child = spawn(checkScript, [pkgname], {
|
||||
shell: false,
|
||||
env: process.env,
|
||||
});
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
child.on("error", (err) => {
|
||||
logger.error(`check-installed 执行失败: ${err?.message || err}`);
|
||||
resolve();
|
||||
});
|
||||
|
||||
child.on("close", (code) => {
|
||||
if (code === 0 && output.includes(pkgname)) {
|
||||
if (code === 0) {
|
||||
isInstalled = true;
|
||||
logger.info(`应用已安装: ${pkgname}`);
|
||||
} else {
|
||||
logger.info(`应用未安装: ${pkgname}`);
|
||||
logger.info(`应用未安装: ${pkgname} (exit ${code})`);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
return isInstalled;
|
||||
});
|
||||
|
||||
@@ -447,7 +445,7 @@ ipcMain.on("remove-installed", async (_event, pkgname: string) => {
|
||||
}
|
||||
const child = spawn(
|
||||
execCommand,
|
||||
[...execParams, "aptss", "remove", "-y", pkgname],
|
||||
[...execParams, "aptss", "remove", pkgname ],
|
||||
{
|
||||
shell: true,
|
||||
env: process.env,
|
||||
@@ -571,7 +569,7 @@ ipcMain.handle("launch-app", async (_event, pkgname: string) => {
|
||||
}
|
||||
|
||||
const execCommand = "/opt/spark-store/extras/host-spawn";
|
||||
const execParams = ["/opt/spark-store/extras/apm-launcher", "launch", pkgname];
|
||||
const execParams = ["/opt/spark-store/extras/app-launcher", "launch", pkgname];
|
||||
|
||||
logger.info(
|
||||
`Launching app: ${pkgname} with command: ${execCommand} ${execParams.join(" ")}`,
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===== 日志函数(简化版)=====
|
||||
log.info() { echo "INFO: $*"; }
|
||||
log.warn() { echo "WARN: $*"; }
|
||||
log.error() { echo "ERROR: $*"; }
|
||||
log.debug() { :; } # APM 场景下可禁用 debug 日志
|
||||
|
||||
# ===== APM 专用桌面文件扫描(单文件)=====
|
||||
function scan_apm_desktop_log() {
|
||||
unset desktop_file_path
|
||||
local pkg_name="$1"
|
||||
local desktop_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/${pkg_name}/entries/applications"
|
||||
|
||||
[ -d "$desktop_dir" ] || return 1
|
||||
|
||||
while IFS= read -r -d '' path; do
|
||||
[ -f "$path" ] || continue
|
||||
if ! grep -q 'NoDisplay=true' "$path" 2>/dev/null; then
|
||||
log.info "Found valid APM desktop file: $path"
|
||||
export desktop_file_path="$path"
|
||||
return 0
|
||||
fi
|
||||
done < <(find "$desktop_dir" -name "*.desktop" -type f -print0 2>/dev/null)
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# ===== APM 专用桌面文件扫描(多文件列表)=====
|
||||
function scan_apm_desktop_list() {
|
||||
local pkg_name="$1"
|
||||
local desktop_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/${pkg_name}/entries/applications"
|
||||
local result=""
|
||||
|
||||
[ -d "$desktop_dir" ] || { echo ""; return; }
|
||||
|
||||
while IFS= read -r -d '' path; do
|
||||
[ -f "$path" ] || continue
|
||||
if ! grep -q 'NoDisplay=true' "$path" 2>/dev/null; then
|
||||
result+="${path},"
|
||||
fi
|
||||
done < <(find "$desktop_dir" -name "*.desktop" -type f -print0 2>/dev/null)
|
||||
|
||||
echo "${result%,}"
|
||||
}
|
||||
|
||||
# ===== 启动应用 =====
|
||||
function launch_app() {
|
||||
local desktop_path="${1#file://}"
|
||||
local exec_cmd
|
||||
|
||||
# 提取并清理 Exec 行(移除字段代码如 %f %u 等)
|
||||
exec_cmd=$(grep -m1 '^Exec=' "$desktop_path" | cut -d= -f2- | sed 's/%[fFuUdDnNickvm]*//g; s/^[[:space:]]*//; s/[[:space:]]*$//')
|
||||
[ -z "$exec_cmd" ] && return 1
|
||||
|
||||
log.info "Launching: $exec_cmd"
|
||||
${SHELL:-bash} -c "$exec_cmd" &
|
||||
}
|
||||
|
||||
# 导出函数供 ACE 环境调用
|
||||
export -f launch_app scan_apm_desktop_log scan_apm_desktop_list log.info log.error
|
||||
|
||||
# ===== 主逻辑 =====
|
||||
[ $# -lt 2 ] && {
|
||||
log.error "Usage: $0 {check|list|launch|start} <apm-package-name>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
action="$1"
|
||||
pkg_name="$2"
|
||||
|
||||
case "$action" in
|
||||
check)
|
||||
if scan_apm_desktop_log "$pkg_name"; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
list)
|
||||
if result=$(scan_apm_desktop_list "$pkg_name"); [ -n "$result" ]; then
|
||||
echo "$result"
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
launch|start)
|
||||
if scan_apm_desktop_log "$pkg_name" && launch_app "$desktop_file_path"; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
log.error "Invalid command: $action (supported: check|list|launch|start)"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
164
extras/app-launcher
Executable file
164
extras/app-launcher
Executable file
@@ -0,0 +1,164 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===== ACE环境配置 =====
|
||||
readonly ACE_ENVIRONMENTS=(
|
||||
"bookworm-run:amber-ce-bookworm"
|
||||
"trixie-run:amber-ce-trixie"
|
||||
"deepin23-run:amber-ce-deepin23"
|
||||
"sid-run:amber-ce-sid"
|
||||
)
|
||||
|
||||
# ===== 日志和函数 =====
|
||||
[ -f /opt/durapps/spark-store/bin/bashimport/log.amber ] && \
|
||||
source /opt/durapps/spark-store/bin/bashimport/log.amber || {
|
||||
log.info() { echo "INFO: $*"; }
|
||||
log.warn() { echo "WARN: $*"; }
|
||||
log.error() { echo "ERROR: $*"; }
|
||||
log.debug() { echo "DEBUG: $*"; }
|
||||
}
|
||||
|
||||
# ===== 功能函数 =====
|
||||
function scan_desktop_file_log() {
|
||||
unset desktop_file_path
|
||||
local package_name=$1
|
||||
# 标准desktop文件检测
|
||||
while IFS= read -r path; do
|
||||
[ -z "$(grep 'NoDisplay=true' "$path")" ] && {
|
||||
log.info "Found valid desktop file: $path"
|
||||
export desktop_file_path="$path"
|
||||
return 0
|
||||
}
|
||||
done < <(dpkg -L "$package_name" 2>/dev/null | grep -E '/usr/share/applications/.*\.desktop$|/opt/apps/.*/entries/applications/.*\.desktop$')
|
||||
|
||||
# 深度环境特殊处理
|
||||
while IFS= read -r path; do
|
||||
[ -z "$(grep 'NoDisplay=true' "$path")" ] && {
|
||||
log.info "Found deepin desktop file: $path"
|
||||
export desktop_file_path="$path"
|
||||
return 0
|
||||
}
|
||||
done < <(find /opt/apps/$package_name -path '*/entries/applications/*.desktop' 2>/dev/null)
|
||||
return 1
|
||||
}
|
||||
|
||||
function scan_desktop_file() {
|
||||
local package_name=$1 result=""
|
||||
# 标准结果收集
|
||||
while IFS= read -r path; do
|
||||
[ -z "$(grep 'NoDisplay=true' "$path")" ] && result+="$path,"
|
||||
done < <(dpkg -L "$package_name" 2>/dev/null | grep -E '/usr/share/applications/.*\.desktop$|/opt/apps/.*/entries/applications/.*\.desktop$')
|
||||
|
||||
# 深度环境补充扫描
|
||||
while IFS= read -r path; do
|
||||
[ -z "$(grep 'NoDisplay=true' "$path")" ] && result+="$path,"
|
||||
done < <(find /opt/apps/$package_name -path '*/entries/applications/*.desktop' 2>/dev/null)
|
||||
|
||||
echo "${result%,}"
|
||||
}
|
||||
|
||||
function launch_app() {
|
||||
local DESKTOP_FILE_PATH="${1#file://}"
|
||||
# 提取并净化Exec命令
|
||||
exec_command=$(grep -m1 '^Exec=' "$DESKTOP_FILE_PATH" | cut -d= -f2- | sed 's/%.//g')
|
||||
[ -z "$exec_command" ] && return 1
|
||||
[ ! -z "$IS_ACE_ENV" ] && HOST_PREFIX="host-spawn"
|
||||
exec_command="${HOST_PREFIX} $exec_command"
|
||||
log.info "Launching: $exec_command"
|
||||
${SHELL:-bash} -c " $exec_command" &
|
||||
|
||||
}
|
||||
|
||||
# 导出函数以便在ACE环境中使用
|
||||
export -f launch_app scan_desktop_file scan_desktop_file_log log.info log.warn log.debug log.error
|
||||
|
||||
# ===== ACE环境执行器 =====
|
||||
function ace_runner() {
|
||||
local action=$1
|
||||
local target=$2
|
||||
|
||||
for ace_entry in "${ACE_ENVIRONMENTS[@]}"; do
|
||||
local ace_cmd=${ace_entry%%:*}
|
||||
local ace_env=${ace_entry#*:}
|
||||
|
||||
if ! command -v "$ace_cmd" >/dev/null; then
|
||||
log.debug "$ace_cmd not found, skipping..."
|
||||
continue
|
||||
fi
|
||||
|
||||
log.info "Attempting in $ace_env environment..."
|
||||
|
||||
case "$action" in
|
||||
check)
|
||||
if "$ace_cmd" scan_desktop_file_log "$target"; then
|
||||
log.info "Found desktop file in $ace_env"
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
list)
|
||||
local result
|
||||
if result=$("$ace_cmd" scan_desktop_file "$target"); then
|
||||
echo "$result"
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
launch|start)
|
||||
"$ace_cmd" scan_desktop_file_log "$target"
|
||||
if desktop_path=$("$ace_cmd" scan_desktop_file_log "$target"); then
|
||||
log.info "Launching from $ace_env..."
|
||||
"$ace_cmd" launch_app $("$ace_cmd" scan_desktop_file "$target")
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
log.debug "Attempt in $ace_env failed"
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# ===== 主逻辑 =====
|
||||
[ $# -lt 2 ] && {
|
||||
log.error "Usage: $0 {check|launch|list|start} package_name/desktop_file"
|
||||
exit 1
|
||||
}
|
||||
|
||||
case $1 in
|
||||
check)
|
||||
# 当前环境检查
|
||||
if scan_desktop_file_log "$2"; then
|
||||
exit 0
|
||||
else
|
||||
# 非ACE环境下执行ACE环境扫描
|
||||
[ -z "$IS_ACE_ENV" ] && ace_runner check "$2"
|
||||
exit $?
|
||||
fi
|
||||
;;
|
||||
|
||||
list)
|
||||
# 当前环境列表
|
||||
if result=$(scan_desktop_file "$2"); then
|
||||
echo "$result"
|
||||
exit 0
|
||||
else
|
||||
# 非ACE环境下执行ACE环境扫描
|
||||
[ -z "$IS_ACE_ENV" ] && ace_runner list "$2"
|
||||
exit $?
|
||||
fi
|
||||
;;
|
||||
|
||||
launch|start)
|
||||
# 当前环境启动
|
||||
if scan_desktop_file_log "$2" && launch_app "$desktop_file_path"; then
|
||||
exit 0
|
||||
else
|
||||
# 非ACE环境下通过ACE环境启动
|
||||
[ -z "$IS_ACE_ENV" ] && ace_runner launch "$2"
|
||||
exit $?
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
log.error "Invalid command: $1"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
45
extras/check-is-installed
Executable file
45
extras/check-is-installed
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
readonly ACE_ENVIRONMENTS=(
|
||||
"bookworm-run:amber-ce-bookworm"
|
||||
"trixie-run:amber-ce-trixie"
|
||||
"deepin23-run:amber-ce-deepin23"
|
||||
"sid-run:amber-ce-sid"
|
||||
)
|
||||
dpkg -s "$1" > /dev/null
|
||||
RET="$?"
|
||||
if [[ "$RET" != "0" ]] &&[[ "$IS_ACE_ENV" == "" ]];then ## 如果未在ACE环境中
|
||||
|
||||
|
||||
|
||||
for ace_entry in "${ACE_ENVIRONMENTS[@]}"; do
|
||||
ace_cmd=${ace_entry%%:*}
|
||||
if command -v "$ace_cmd" >/dev/null 2>&1; then
|
||||
echo "----------------------------------------"
|
||||
echo "正在检查 $ace_cmd 环境的安装..."
|
||||
echo "----------------------------------------"
|
||||
|
||||
# 在ACE环境中执行安装检测
|
||||
$ace_cmd dpkg -l | grep "^ii $1 " > /dev/null
|
||||
try_run_ret="$?"
|
||||
|
||||
|
||||
# 最终检测结果处理
|
||||
if [ "$try_run_ret" -eq 0 ]; then
|
||||
echo "----------------------------------------"
|
||||
echo "在 $ace_cmd 环境中找到了安装"
|
||||
echo "----------------------------------------"
|
||||
exit $try_run_ret
|
||||
else
|
||||
echo "----------------------------------------"
|
||||
echo "在 $ace_cmd 环境中未能找到安装,继续查找"
|
||||
echo "----------------------------------------"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "----------------------------------------"
|
||||
echo "所有已安装的 ACE 环境中未能找到安装,退出"
|
||||
echo "----------------------------------------"
|
||||
exit "$RET"
|
||||
fi
|
||||
## 如果在ACE环境中或者未出错
|
||||
exit "$RET"
|
||||
@@ -2,18 +2,77 @@
|
||||
|
||||
# 检查是否提供了至少一个参数
|
||||
if [[ $# -eq 0 ]]; then
|
||||
echo "错误:未提供命令参数。用法: $0 aptss <子命令> [参数...]"
|
||||
echo "错误:未提供命令参数。用法: $0 [aptss|ssinstall] <子命令> [参数...]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 严格验证第一个参数必须是 "aptss"
|
||||
if [[ "$1" != "aptss" ]]; then
|
||||
echo "拒绝执行:仅允许执行 'aptss' 命令。收到的第一个参数: '$1'"
|
||||
# 获取第一个参数
|
||||
first_arg="$1"
|
||||
|
||||
# 根据第一个参数决定执行哪个命令
|
||||
if [[ "$first_arg" == "ssinstall" ]]; then
|
||||
# 执行 ssinstall 命令(跳过第一个参数)
|
||||
/usr/bin/ssinstall "${@:2}" 2>&1
|
||||
exit_code=$?
|
||||
elif [[ "$first_arg" == "aptss" ]]; then
|
||||
# 检查是否为 remove 子命令(第二个参数)
|
||||
if [[ "$2" == "remove" ]]; then
|
||||
# 获取要卸载的软件包名称(第三个参数及以后)
|
||||
packages="${@:3}"
|
||||
|
||||
|
||||
# 检查可用的对话框程序
|
||||
if command -v garma &> /dev/null; then
|
||||
# 使用 garma 询问确认
|
||||
garma --question \
|
||||
--title="确认卸载" \
|
||||
--text="正在准备卸载: $packages\n若这是您下达的卸载指令,请选择确认继续卸载" \
|
||||
--ok-label="确认卸载" \
|
||||
--cancel-label="取消" \
|
||||
--width=400
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
# 用户确认,执行卸载
|
||||
/usr/bin/aptss "${@:2}" -y 2>&1
|
||||
exit_code=$?
|
||||
else
|
||||
# 用户取消
|
||||
echo "操作已取消"
|
||||
exit 0
|
||||
fi
|
||||
elif command -v zenity &> /dev/null; then
|
||||
# 使用 zenity 询问确认
|
||||
zenity --question \
|
||||
--title="确认卸载" \
|
||||
--text="正在准备卸载: $packages\n\n若这是您下达的卸载指令,请选择确认继续卸载" \
|
||||
--ok-label="确认卸载" \
|
||||
--cancel-label="取消" \
|
||||
--width=400
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
# 用户确认,执行卸载
|
||||
/usr/bin/aptss "${@:2}" -y 2>&1
|
||||
exit_code=$?
|
||||
else
|
||||
# 用户取消
|
||||
echo "操作已取消"
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
# 既没有 garma 也没有 zenity,拒绝卸载
|
||||
echo "错误:未找到 garma 或 zenity,无法显示确认对话框。卸载操作已拒绝。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
else
|
||||
# 非 remove 命令,直接执行
|
||||
/usr/bin/aptss "${@:2}" 2>&1
|
||||
exit_code=$?
|
||||
fi
|
||||
else
|
||||
# 其他情况,拒绝执行
|
||||
echo "拒绝执行:仅允许执行 'aptss' 或 'ssinstall' 命令。收到的第一个参数: '$first_arg'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 执行 aptss 命令(跳过第一个参数 "aptss")
|
||||
/usr/bin/aptss "${@:2}" 2>&1
|
||||
exit_code=$?
|
||||
|
||||
exit $exit_code
|
||||
@@ -89,7 +89,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
<!-- <div
|
||||
class="mt-4 rounded-2xl border border-slate-200/60 bg-slate-50/70 px-4 py-3 text-sm text-slate-600 dark:border-slate-800/60 dark:bg-slate-900/60 dark:text-slate-300"
|
||||
>
|
||||
首次安装 APM 后需要重启系统以在启动器中看到应用入口。可前往
|
||||
@@ -100,7 +100,7 @@
|
||||
>APM Releases</a
|
||||
>
|
||||
获取 APM。
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div v-if="screenshots.length" class="mt-6 grid gap-3 sm:grid-cols-2">
|
||||
<img
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
type="button"
|
||||
class="inline-flex items-center gap-2 rounded-2xl bg-gradient-to-r from-brand to-brand-dark px-4 py-2 text-sm font-semibold text-white shadow-lg transition hover:-translate-y-0.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand/40"
|
||||
@click="handleUpdate"
|
||||
title="启动 apm-update-tool"
|
||||
title="检查可更新的软件包列表"
|
||||
>
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
<span>软件更新</span>
|
||||
</button>
|
||||
<button
|
||||
<!-- <button
|
||||
type="button"
|
||||
class="inline-flex items-center gap-2 rounded-2xl bg-slate-900/90 px-4 py-2 text-sm font-semibold text-white shadow-lg shadow-slate-900/40 transition hover:-translate-y-0.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-900/40 dark:bg-white/90 dark:text-slate-900"
|
||||
@click="handleList"
|
||||
@@ -17,7 +17,7 @@
|
||||
>
|
||||
<i class="fas fa-download"></i>
|
||||
<span>应用管理</span>
|
||||
</button>
|
||||
</button> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user