!401 fix: APM安装软件后无法自动创建快捷方式的问题

Merge pull request !401 from CharOfString/Erotica
This commit is contained in:
2026-07-09 13:06:25 +00:00
committed by Gitee
3 changed files with 135 additions and 4 deletions
+3
View File
@@ -52,3 +52,6 @@ yarn.lock
test-results.json
.worktrees/
.superpowers/
# VSCode CMake Extension
build/*
+130 -2
View File
@@ -1,6 +1,8 @@
import { ipcMain, WebContents } from "electron";
import { spawn, ChildProcess } from "node:child_process";
import fs from "node:fs";
import { promises as fsp } from "node:fs";
import os from "node:os";
import path from "node:path";
import pino from "pino";
@@ -45,6 +47,117 @@ type InstallTask = {
const SHELL_CALLER_PATH = "/opt/spark-store/extras/shell-caller.sh";
// 以下路径配置参考自index.ts并且与其保持一致
// 其中,SPARK_CONFIG_DIR为配置目录,若此目录下出现ssshell-config-do-not-create-desktop文件
// 则代表「关闭『自动创建桌面启动器』功能」
const SPARK_CONFIG_DIR = path.join(
os.homedir(),
".config/spark-union/spark-store",
);
const CREATE_DESKTOP_CONFIG = "ssshell-config-do-not-create-desktop";
const CREATE_DESKTOP_CONFIG_PATH = path.join(
SPARK_CONFIG_DIR,
CREATE_DESKTOP_CONFIG,
);
// APM应用的.desktop文件可能在以下几个位置
const APM_DESKTOP_ENTRY_DIRS = [
"/var/lib/apm", // 实体机/宿主系统
"/var/lib/apm/apm/files/ace-env/var/lib/apm", // ACE容器
];
// Helper: 用XDG_DESKTOP_DIR拿桌面路径,读不到我就回退到~/Desktop
const resolveDesktopDir = async (): Promise<string> => {
const userDirsPath = path.join(os.homedir(), ".config", "user-dirs.dirs");
try {
const content = await fsp.readFile(userDirsPath, "utf-8");
const matchRes = content.match(/^XDG_DESKTOP_DIR="\$HOME\/(.+)"$/m);
if (matchRes?.[1]) {
return path.join(os.homedir(), matchRes[1]);
}
} catch {
// user-dirs.dirs无法读取
logger.warn(`Failed to get XDG_DESKTOP_DIR, I'm falling back to ~/Desktop!!`);
}
return path.join(os.homedir(), "Desktop");
};
// Helper: 为APM安装的应用创建桌面快捷方式(如果启用了「自动创建桌面启动器」)
const createApmDesktopShortcut = async (
pkgname: string,
sendLog: (msg: string) => void,
) => {
// 如上所述,配置目录里面有ssshell-config-do-not-create-desktop文件就是功能关闭
try {
await fsp.access(CREATE_DESKTOP_CONFIG_PATH);
logger.debug(
`Desktop shortcut creation has been disabled. Skipping creating it for ${pkgname}.`,
);
return;
} catch {
// 文件不存在就是功能启用 继续
}
// 解析桌面路径,确保目录存在
const desktopDir = await resolveDesktopDir();
try {
await fsp.mkdir(desktopDir, { recursive: true });
} catch (err) {
logger.warn(`Failed to create desktop directory ${desktopDir}: ${err}`);
return;
}
// 遍历APM应用的.desktop文件可能在以下几个位置
for (const baseDir of APM_DESKTOP_ENTRY_DIRS) {
const entriesPath = path.join(baseDir, pkgname, "entries", "applications");
let files: string[];
try {
files = await fsp.readdir(entriesPath);
} catch {
continue;
}
for (const file of files) {
// 忽略扩展名不符的
if (!file.endsWith(".desktop")) {
continue;
}
const srcPath = path.join(entriesPath, file);
const destPath = path.join(desktopDir, file);
// 目标已存在则跳过,继续检查下一个
try {
await fsp.access(destPath);
logger.debug(`Shortcut already exists: ${destPath}`);
sendLog(`Shortcut already exists: ${file}`);
continue;
} catch {
// 不存在,继续
}
try {
// 读取.desktop文件内容
const content = await fsp.readFile(srcPath, "utf-8");
// 写入用户桌面,顺带处理一下权限问题
await fsp.writeFile(destPath, content, { mode: 0o644 });
sendLog(`Wrote desktop shortcut: ${file}`);
logger.info(`Wrote shortcut ${destPath} for ${pkgname}.`);
return;
} catch (err) {
logger.warn(
`Failed to create desktop shortcut for ${pkgname}: ${err}`,
);
return;
}
}
}
logger.debug(`Could NOT find ${pkgname}'s .desktop file...`);
};
export const tasks = new Map<number, InstallTask>();
let idle = true; // Indicates if the installation manager is idle
@@ -584,8 +697,23 @@ async function processNextInQueue() {
stderr: result.stderr,
};
if (success) logger.info(msgObj);
else logger.error(msgObj);
if (success) {
logger.info(msgObj);
// 安装成功后,如果是APM安装的,就调用createApmDesktopShortcut
// 这个函数负责处理桌面快捷方式,它自己会读取设置并且决定要不要创建
if (task.origin === "apm" && task.pkgname) {
try {
await createApmDesktopShortcut(task.pkgname, sendLog);
} catch (err) {
logger.warn(
`Failed to create shortcut for ${task.pkgname}: ${err}`,
);
}
}
} else {
logger.error(msgObj);
}
webContents?.send("install-complete", {
id,
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "spark-store",
"version": "5.1.1",
"version": "5.1.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "spark-store",
"version": "5.1.1",
"version": "5.1.2",
"license": "GPL-3.0",
"dependencies": {
"@tailwindcss/vite": "^4.1.18",