fix(install-manager): 优化已安装应用列表获取逻辑并改进安装成功提示

使用 `apm list --installed` 命令替代直接读取文件系统来获取已安装应用列表,提高可靠性
改进安装成功提示信息,更清晰地说明重启和立即使用的选项
This commit is contained in:
2026-03-29 12:43:05 +08:00
parent aec1faf964
commit 596515e0a4

View File

@@ -240,7 +240,7 @@ ipcMain.on("queue-install", async (event, download_json) => {
title: "APM 安装成功", title: "APM 安装成功",
message: "恭喜您APM 已成功安装", message: "恭喜您APM 已成功安装",
detail: detail:
"APM 应用需重启后方可展示和使用,若完成安装后无法在应用列表中展示,请重启电脑后继续。", "恭喜您APM 已成功安装!您的应用已在安装中~\n首次安装APM后需要重启电脑后方可在启动器展示应用。您可在应用安装完毕后择机重启电脑\n若您需要立即使用应用可在应用安装后在应用商店中打开您的应用。",
buttons: ["确定"], buttons: ["确定"],
defaultId: 0, defaultId: 0,
}); });
@@ -763,16 +763,21 @@ ipcMain.handle("list-installed", async () => {
const apmBasePath = "/var/lib/apm/apm/files/ace-env/var/lib/apm"; const apmBasePath = "/var/lib/apm/apm/files/ace-env/var/lib/apm";
try { try {
if (!fs.existsSync(apmBasePath)) { // 使用 apm list --installed 获取所有已安装应用
logger.warn(`APM base path not found: ${apmBasePath}`); const { code, stdout } = await runCommandCapture("apm", [
"list",
"--installed",
]);
if (code !== 0) {
logger.warn(`Failed to list installed packages: ${stdout}`);
return { return {
success: false, success: false,
message: "APM base path not found", message: "Failed to list installed packages",
apps: [], apps: [],
}; };
} }
const packages = fs.readdirSync(apmBasePath, { withFileTypes: true });
const installedApps: Array<{ const installedApps: Array<{
pkgname: string; pkgname: string;
name: string; name: string;
@@ -784,52 +789,40 @@ ipcMain.handle("list-installed", async () => {
isDependency: boolean; isDependency: boolean;
}> = []; }> = [];
for (const pkg of packages) { const cleanStdout = stdout.replace(
if (!pkg.isDirectory()) continue; // eslint-disable-next-line no-control-regex
/\x1b\[[0-9;]*m/g,
"",
);
const lines = cleanStdout.split("\n");
const pkgname = pkg.name; for (const line of lines) {
const pkgPath = path.join(apmBasePath, pkgname); const trimmed = line.trim();
if (
const { code, stdout } = await runCommandCapture("apm", [ !trimmed ||
"list", trimmed.startsWith("Listing") ||
pkgname, trimmed.startsWith("[INFO]") ||
]); trimmed.startsWith("警告")
if (code !== 0) { )
logger.warn(`Failed to list package ${pkgname}: ${stdout}`);
continue; continue;
}
const cleanStdout = stdout.replace( // 解析格式: pkgname/repo,section version arch [flags]
// eslint-disable-next-line no-control-regex const match = trimmed.match(
/\x1b\[[0-9;]*m/g, /^(\S+)\/\S+,\S+\s+(\S+)\s+(\S+)\s+\[(.+)\]$/,
"",
); );
const lines = cleanStdout.split("\n"); if (!match) continue;
for (const line of lines) { const [, pkgname, version, arch, flags] = match;
const trimmed = line.trim();
if (
!trimmed ||
trimmed.startsWith("Listing") ||
trimmed.startsWith("[INFO]") ||
trimmed.startsWith("警告")
)
continue;
const match = trimmed.match( // 从桌面文件获取应用名称和图标
/^(\S+)\/\S+,\S+\s+(\S+)\s+(\S+)\s+\[(.+)\]$/, let appName = pkgname;
); let icon = "";
if (!match) continue; const pkgPath = path.join(apmBasePath, pkgname);
const entriesPath = path.join(pkgPath, "entries", "applications");
const hasEntries = fs.existsSync(entriesPath);
const [, listedPkgname, version, arch, flags] = match; if (hasEntries) {
if (listedPkgname !== pkgname) continue; try {
let appName = pkgname;
let icon = "";
const entriesPath = path.join(pkgPath, "entries", "applications");
const hasEntries = fs.existsSync(entriesPath);
if (hasEntries) {
const desktopFiles = fs.readdirSync(entriesPath); const desktopFiles = fs.readdirSync(entriesPath);
for (const file of desktopFiles) { for (const file of desktopFiles) {
if (file.endsWith(".desktop")) { if (file.endsWith(".desktop")) {
@@ -842,19 +835,21 @@ ipcMain.handle("list-installed", async () => {
break; break;
} }
} }
} catch (e) {
logger.warn(`Failed to read desktop file for ${pkgname}: ${e}`);
} }
installedApps.push({
pkgname,
name: appName,
version,
arch,
flags,
origin: "apm",
icon: icon || undefined,
isDependency: !hasEntries,
});
} }
installedApps.push({
pkgname,
name: appName,
version,
arch,
flags,
origin: "apm",
icon: icon || undefined,
isDependency: !hasEntries,
});
} }
installedApps.sort((a, b) => { installedApps.sort((a, b) => {