mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-04-30 03:10:16 +08:00
update 修复更新工具缺少软件名检查的问题
This commit is contained in:
@@ -33,14 +33,20 @@ export interface UpdateCenterLoadItemsResult {
|
|||||||
warnings: string[];
|
warnings: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
type StoreCategoryMap = Map<string, string>;
|
interface RemoteAppMetadata {
|
||||||
|
category: string;
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type StoreAppMetadataMap = Map<string, RemoteAppMetadata>;
|
||||||
|
|
||||||
interface RemoteCategoryAppEntry {
|
interface RemoteCategoryAppEntry {
|
||||||
|
Name?: string;
|
||||||
Pkgname?: string;
|
Pkgname?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const REMOTE_STORE_BASE_URL = "https://erotica.spark-app.store";
|
const REMOTE_STORE_BASE_URL = "https://erotica.spark-app.store";
|
||||||
const categoryCache = new Map<string, Promise<StoreCategoryMap>>();
|
const categoryCache = new Map<string, Promise<StoreAppMetadataMap>>();
|
||||||
|
|
||||||
const APTSS_LIST_UPGRADABLE_COMMAND = {
|
const APTSS_LIST_UPGRADABLE_COMMAND = {
|
||||||
command: "bash",
|
command: "bash",
|
||||||
@@ -157,16 +163,22 @@ const loadAptssItemMetadata = async (
|
|||||||
> => {
|
> => {
|
||||||
console.log(`[DEBUG] Loading APTSS metadata for ${item.pkgname}`);
|
console.log(`[DEBUG] Loading APTSS metadata for ${item.pkgname}`);
|
||||||
const printUrisCommand = getAptssPrintUrisCommand(item.pkgname);
|
const printUrisCommand = getAptssPrintUrisCommand(item.pkgname);
|
||||||
console.log(`[DEBUG] APTSS command: ${printUrisCommand.command} ${printUrisCommand.args.join(' ')}`);
|
console.log(
|
||||||
|
`[DEBUG] APTSS command: ${printUrisCommand.command} ${printUrisCommand.args.join(" ")}`,
|
||||||
|
);
|
||||||
|
|
||||||
const metadataResult = await runCommand(
|
const metadataResult = await runCommand(
|
||||||
printUrisCommand.command,
|
printUrisCommand.command,
|
||||||
printUrisCommand.args,
|
printUrisCommand.args,
|
||||||
);
|
);
|
||||||
console.log(`[DEBUG] APTSS metadata result code: ${metadataResult.code}`);
|
console.log(`[DEBUG] APTSS metadata result code: ${metadataResult.code}`);
|
||||||
console.log(`[DEBUG] APTSS metadata stdout: ${metadataResult.stdout.substring(0, 500)}`);
|
console.log(
|
||||||
console.log(`[DEBUG] APTSS metadata stderr: ${metadataResult.stderr.substring(0, 500)}`);
|
`[DEBUG] APTSS metadata stdout: ${metadataResult.stdout.substring(0, 500)}`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`[DEBUG] APTSS metadata stderr: ${metadataResult.stderr.substring(0, 500)}`,
|
||||||
|
);
|
||||||
|
|
||||||
const commandError = getCommandError(
|
const commandError = getCommandError(
|
||||||
`aptss metadata query for ${item.pkgname}`,
|
`aptss metadata query for ${item.pkgname}`,
|
||||||
metadataResult,
|
metadataResult,
|
||||||
@@ -178,7 +190,7 @@ const loadAptssItemMetadata = async (
|
|||||||
|
|
||||||
const metadata = parsePrintUrisOutput(metadataResult.stdout);
|
const metadata = parsePrintUrisOutput(metadataResult.stdout);
|
||||||
console.log(`[DEBUG] APTSS parsed metadata:`, metadata);
|
console.log(`[DEBUG] APTSS parsed metadata:`, metadata);
|
||||||
|
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
return {
|
return {
|
||||||
item: null,
|
item: null,
|
||||||
@@ -252,7 +264,7 @@ const loadJson = async <T>(url: string): Promise<T> => {
|
|||||||
|
|
||||||
const loadStoreCategoryMap = async (
|
const loadStoreCategoryMap = async (
|
||||||
storeArch: string,
|
storeArch: string,
|
||||||
): Promise<StoreCategoryMap> => {
|
): Promise<StoreAppMetadataMap> => {
|
||||||
const categories = await loadJson<Record<string, unknown>>(
|
const categories = await loadJson<Record<string, unknown>>(
|
||||||
`${REMOTE_STORE_BASE_URL}/${storeArch}/categories.json`,
|
`${REMOTE_STORE_BASE_URL}/${storeArch}/categories.json`,
|
||||||
);
|
);
|
||||||
@@ -266,7 +278,7 @@ const loadStoreCategoryMap = async (
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const categoryMap: StoreCategoryMap = new Map();
|
const categoryMap: StoreAppMetadataMap = new Map();
|
||||||
for (const entry of categoryEntries) {
|
for (const entry of categoryEntries) {
|
||||||
if (entry.status !== "fulfilled") {
|
if (entry.status !== "fulfilled") {
|
||||||
continue;
|
continue;
|
||||||
@@ -274,7 +286,10 @@ const loadStoreCategoryMap = async (
|
|||||||
|
|
||||||
for (const app of entry.value.apps) {
|
for (const app of entry.value.apps) {
|
||||||
if (app.Pkgname && !categoryMap.has(app.Pkgname)) {
|
if (app.Pkgname && !categoryMap.has(app.Pkgname)) {
|
||||||
categoryMap.set(app.Pkgname, entry.value.category);
|
categoryMap.set(app.Pkgname, {
|
||||||
|
category: entry.value.category,
|
||||||
|
name: app.Name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,7 +297,9 @@ const loadStoreCategoryMap = async (
|
|||||||
return categoryMap;
|
return categoryMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStoreCategoryMap = (storeArch: string): Promise<StoreCategoryMap> => {
|
const getStoreCategoryMap = (
|
||||||
|
storeArch: string,
|
||||||
|
): Promise<StoreAppMetadataMap> => {
|
||||||
const cached = categoryCache.get(storeArch);
|
const cached = categoryCache.get(storeArch);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
return cached;
|
return cached;
|
||||||
@@ -311,8 +328,14 @@ const enrichItemCategories = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const categoryMap = await getStoreCategoryMap(storeArch);
|
const categoryMap = await getStoreCategoryMap(storeArch);
|
||||||
const category = categoryMap.get(item.pkgname);
|
const metadata = categoryMap.get(item.pkgname);
|
||||||
return category ? { ...item, category } : item;
|
return metadata
|
||||||
|
? {
|
||||||
|
...item,
|
||||||
|
category: metadata.category,
|
||||||
|
...(metadata.name ? { name: metadata.name } : {}),
|
||||||
|
}
|
||||||
|
: item;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ const toState = (
|
|||||||
items: snapshot.items.map((item) => ({
|
items: snapshot.items.map((item) => ({
|
||||||
taskKey: getTaskKey(item),
|
taskKey: getTaskKey(item),
|
||||||
packageName: item.pkgname,
|
packageName: item.pkgname,
|
||||||
displayName: item.pkgname,
|
displayName: item.name || item.pkgname,
|
||||||
currentVersion: item.currentVersion,
|
currentVersion: item.currentVersion,
|
||||||
newVersion: item.nextVersion,
|
newVersion: item.nextVersion,
|
||||||
source: item.source,
|
source: item.source,
|
||||||
@@ -191,9 +191,7 @@ export const createUpdateCenterService = (
|
|||||||
async start(taskKeys) {
|
async start(taskKeys) {
|
||||||
const snapshot = queue.getSnapshot();
|
const snapshot = queue.getSnapshot();
|
||||||
const selectedItems = snapshot.items.filter(
|
const selectedItems = snapshot.items.filter(
|
||||||
(item) =>
|
(item) => taskKeys.includes(getTaskKey(item)) && !item.ignored,
|
||||||
taskKeys.includes(getTaskKey(item)) &&
|
|
||||||
!item.ignored,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (selectedItems.length === 0) {
|
if (selectedItems.length === 0) {
|
||||||
@@ -235,7 +233,9 @@ export const createUpdateCenterService = (
|
|||||||
webContents.send("queue-install", JSON.stringify(installTaskData));
|
webContents.send("queue-install", JSON.stringify(installTaskData));
|
||||||
|
|
||||||
// 从更新中心的 items 中移除该应用(不再显示在更新列表中)
|
// 从更新中心的 items 中移除该应用(不再显示在更新列表中)
|
||||||
currentItems = currentItems.filter((i) => getTaskKey(i) !== getTaskKey(item));
|
currentItems = currentItems.filter(
|
||||||
|
(i) => getTaskKey(i) !== getTaskKey(item),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新队列中的 items
|
// 更新队列中的 items
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface InstalledSourceState {
|
|||||||
|
|
||||||
export interface UpdateCenterItem {
|
export interface UpdateCenterItem {
|
||||||
pkgname: string;
|
pkgname: string;
|
||||||
|
name?: string;
|
||||||
source: UpdateSource;
|
source: UpdateSource;
|
||||||
currentVersion: string;
|
currentVersion: string;
|
||||||
nextVersion: string;
|
nextVersion: string;
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ const DPKG_QUERY_INSTALLED_KEY =
|
|||||||
const APM_PRINT_URIS_KEY =
|
const APM_PRINT_URIS_KEY =
|
||||||
"bash -lc amber-pm-debug /usr/bin/apt -c /opt/durapps/spark-store/bin/apt-fast-conf/aptss-apt.conf download spark-weather --print-uris";
|
"bash -lc amber-pm-debug /usr/bin/apt -c /opt/durapps/spark-store/bin/apt-fast-conf/aptss-apt.conf download spark-weather --print-uris";
|
||||||
|
|
||||||
|
const APTSS_WEATHER_PRINT_URIS_KEY =
|
||||||
|
"bash -lc /usr/bin/apt download spark-weather --print-uris -c /opt/durapps/spark-store/bin/apt-fast-conf/aptss-apt.conf -o Dir::Etc::sourcelist=/opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/aptss.list -o Dir::Etc::sourceparts=/dev/null";
|
||||||
|
|
||||||
|
const APTSS_NOTES_PRINT_URIS_KEY =
|
||||||
|
"bash -lc /usr/bin/apt download spark-notes --print-uris -c /opt/durapps/spark-store/bin/apt-fast-conf/aptss-apt.conf -o Dir::Etc::sourcelist=/opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/aptss.list -o Dir::Etc::sourceparts=/dev/null";
|
||||||
|
|
||||||
const loadUpdateCenterModule = async (
|
const loadUpdateCenterModule = async (
|
||||||
remoteStore: Record<string, RemoteStoreResponse>,
|
remoteStore: Record<string, RemoteStoreResponse>,
|
||||||
) => {
|
) => {
|
||||||
@@ -141,19 +147,28 @@ describe("update-center load items", () => {
|
|||||||
stderr: "",
|
stderr: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
APTSS_WEATHER_PRINT_URIS_KEY,
|
||||||
|
{
|
||||||
|
code: 0,
|
||||||
|
stdout:
|
||||||
|
"'https://example.invalid/spark-weather_2.0.0_amd64.deb' spark-weather_2.0.0_amd64.deb 123456 SHA512:deadbeef",
|
||||||
|
stderr: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
const { loadUpdateCenterItems } = await loadUpdateCenterModule({
|
const { loadUpdateCenterItems } = await loadUpdateCenterModule({
|
||||||
"https://erotica.spark-app.store/amd64-store/categories.json": {
|
"https://erotica.spark-app.store/amd64-store/categories.json": {
|
||||||
tools: { zh: "Tools" },
|
tools: { zh: "Tools" },
|
||||||
},
|
},
|
||||||
"https://erotica.spark-app.store/amd64-store/tools/applist.json": [
|
"https://erotica.spark-app.store/amd64-store/tools/applist.json": [
|
||||||
{ Pkgname: "spark-weather" },
|
{ Name: "Spark Weather", Pkgname: "spark-weather" },
|
||||||
],
|
],
|
||||||
"https://erotica.spark-app.store/amd64-apm/categories.json": {
|
"https://erotica.spark-app.store/amd64-apm/categories.json": {
|
||||||
tools: { zh: "Tools" },
|
tools: { zh: "Tools" },
|
||||||
},
|
},
|
||||||
"https://erotica.spark-app.store/amd64-apm/tools/applist.json": [
|
"https://erotica.spark-app.store/amd64-apm/tools/applist.json": [
|
||||||
{ Pkgname: "spark-weather" },
|
{ Name: "Spark Weather", Pkgname: "spark-weather" },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -175,6 +190,7 @@ describe("update-center load items", () => {
|
|||||||
nextVersion: "3.0.0",
|
nextVersion: "3.0.0",
|
||||||
arch: "amd64",
|
arch: "amd64",
|
||||||
category: "tools",
|
category: "tools",
|
||||||
|
name: "Spark Weather",
|
||||||
remoteIcon:
|
remoteIcon:
|
||||||
"https://erotica.spark-app.store/amd64-apm/tools/spark-weather/icon.png",
|
"https://erotica.spark-app.store/amd64-apm/tools/spark-weather/icon.png",
|
||||||
downloadUrl: "https://example.invalid/spark-weather_3.0.0_amd64.deb",
|
downloadUrl: "https://example.invalid/spark-weather_3.0.0_amd64.deb",
|
||||||
@@ -194,7 +210,7 @@ describe("update-center load items", () => {
|
|||||||
office: { zh: "Office" },
|
office: { zh: "Office" },
|
||||||
},
|
},
|
||||||
"https://erotica.spark-app.store/amd64-store/office/applist.json": [
|
"https://erotica.spark-app.store/amd64-store/office/applist.json": [
|
||||||
{ Pkgname: "spark-notes" },
|
{ Name: "Spark Notes", Pkgname: "spark-notes" },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -217,6 +233,15 @@ describe("update-center load items", () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key === APTSS_NOTES_PRINT_URIS_KEY) {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
stdout:
|
||||||
|
"'https://example.invalid/spark-notes_2.0.0_amd64.deb' spark-notes_2.0.0_amd64.deb 654321 SHA512:beadfeed",
|
||||||
|
stderr: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (key === "apm list --upgradable" || key === "apm list --installed") {
|
if (key === "apm list --upgradable" || key === "apm list --installed") {
|
||||||
return {
|
return {
|
||||||
code: 127,
|
code: 127,
|
||||||
@@ -236,8 +261,13 @@ describe("update-center load items", () => {
|
|||||||
nextVersion: "2.0.0",
|
nextVersion: "2.0.0",
|
||||||
arch: "amd64",
|
arch: "amd64",
|
||||||
category: "office",
|
category: "office",
|
||||||
|
name: "Spark Notes",
|
||||||
remoteIcon:
|
remoteIcon:
|
||||||
"https://erotica.spark-app.store/amd64-store/office/spark-notes/icon.png",
|
"https://erotica.spark-app.store/amd64-store/office/spark-notes/icon.png",
|
||||||
|
downloadUrl: "https://example.invalid/spark-notes_2.0.0_amd64.deb",
|
||||||
|
fileName: "spark-notes_2.0.0_amd64.deb",
|
||||||
|
size: 654321,
|
||||||
|
sha512: "beadfeed",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expect(result.warnings).toEqual([
|
expect(result.warnings).toEqual([
|
||||||
@@ -289,6 +319,7 @@ describe("update-center load items", () => {
|
|||||||
currentVersion: "1.0.0",
|
currentVersion: "1.0.0",
|
||||||
nextVersion: "2.0.0",
|
nextVersion: "2.0.0",
|
||||||
arch: "amd64",
|
arch: "amd64",
|
||||||
|
name: "Spark Notes",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -298,7 +329,7 @@ describe("update-center load items", () => {
|
|||||||
};
|
};
|
||||||
remoteStore[
|
remoteStore[
|
||||||
"https://erotica.spark-app.store/amd64-store/office/applist.json"
|
"https://erotica.spark-app.store/amd64-store/office/applist.json"
|
||||||
] = [{ Pkgname: "spark-notes" }];
|
] = [{ Name: "Spark Notes", Pkgname: "spark-notes" }];
|
||||||
|
|
||||||
const secondResult = await loadUpdateCenterItems(runCommand);
|
const secondResult = await loadUpdateCenterItems(runCommand);
|
||||||
|
|
||||||
@@ -310,6 +341,7 @@ describe("update-center load items", () => {
|
|||||||
nextVersion: "2.0.0",
|
nextVersion: "2.0.0",
|
||||||
arch: "amd64",
|
arch: "amd64",
|
||||||
category: "office",
|
category: "office",
|
||||||
|
name: "Spark Notes",
|
||||||
remoteIcon:
|
remoteIcon:
|
||||||
"https://erotica.spark-app.store/amd64-store/office/spark-notes/icon.png",
|
"https://erotica.spark-app.store/amd64-store/office/spark-notes/icon.png",
|
||||||
},
|
},
|
||||||
@@ -323,7 +355,7 @@ describe("update-center load items", () => {
|
|||||||
tools: { zh: "Tools" },
|
tools: { zh: "Tools" },
|
||||||
},
|
},
|
||||||
"https://erotica.spark-app.store/amd64-store/office/applist.json": [
|
"https://erotica.spark-app.store/amd64-store/office/applist.json": [
|
||||||
{ Pkgname: "spark-notes" },
|
{ Name: "Spark Notes", Pkgname: "spark-notes" },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -346,6 +378,15 @@ describe("update-center load items", () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key === APTSS_NOTES_PRINT_URIS_KEY) {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
stdout:
|
||||||
|
"'https://example.invalid/spark-notes_2.0.0_amd64.deb' spark-notes_2.0.0_amd64.deb 654321 SHA512:beadfeed",
|
||||||
|
stderr: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (key === "apm list --upgradable" || key === "apm list --installed") {
|
if (key === "apm list --upgradable" || key === "apm list --installed") {
|
||||||
return {
|
return {
|
||||||
code: 127,
|
code: 127,
|
||||||
@@ -365,6 +406,7 @@ describe("update-center load items", () => {
|
|||||||
nextVersion: "2.0.0",
|
nextVersion: "2.0.0",
|
||||||
arch: "amd64",
|
arch: "amd64",
|
||||||
category: "office",
|
category: "office",
|
||||||
|
name: "Spark Notes",
|
||||||
remoteIcon:
|
remoteIcon:
|
||||||
"https://erotica.spark-app.store/amd64-store/office/spark-notes/icon.png",
|
"https://erotica.spark-app.store/amd64-store/office/spark-notes/icon.png",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -262,6 +262,27 @@ describe("update-center/ipc", () => {
|
|||||||
await startPromise;
|
await startPromise;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("service item snapshots prefer resolved app names over package names", async () => {
|
||||||
|
const service = createUpdateCenterService({
|
||||||
|
loadItems: async () => [
|
||||||
|
{
|
||||||
|
...createItem(),
|
||||||
|
name: "Spark Weather",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const snapshot = await service.refresh();
|
||||||
|
|
||||||
|
expect(snapshot.items).toMatchObject([
|
||||||
|
{
|
||||||
|
taskKey: "aptss:spark-weather",
|
||||||
|
packageName: "spark-weather",
|
||||||
|
displayName: "Spark Weather",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it("concurrent start calls still serialize through one processing pipeline", async () => {
|
it("concurrent start calls still serialize through one processing pipeline", async () => {
|
||||||
const startedTaskIds: number[] = [];
|
const startedTaskIds: number[] = [];
|
||||||
const releases: Array<() => void> = [];
|
const releases: Array<() => void> = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user