feat(build): add loong64

- Downgrad electron for the sake of loong64
- Add my project to CREDIT.md

Signed-off-by: Elysia <a.elysia@proton.me>
This commit is contained in:
Elysia
2026-04-19 00:16:35 +08:00
parent 994dbaf9b9
commit 6a9091b2ec
9 changed files with 229 additions and 140 deletions
+21 -1
View File
@@ -22,4 +22,24 @@
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.
SOFTWARE.
2. https://github.com/elysia-best/apm-app-store MulanPSL-2.0
Copyright (c) 2026-present The Spark Project Contributors
apm-store is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
+40 -11
View File
@@ -376,7 +376,9 @@ export const loadUpdateCenterItems = async (
storeFilter: StoreFilter = "both",
runCommand: UpdateCenterCommandRunner = runCommandCapture,
): Promise<UpdateCenterLoadItemsResult> => {
console.log(`[UpdateCenter] loadUpdateCenterItems called with storeFilter=${storeFilter}`);
console.log(
`[UpdateCenter] loadUpdateCenterItems called with storeFilter=${storeFilter}`,
);
const [sparkEnabled, apmEnabled] = await Promise.all([
isSourceEnabled(storeFilter, "spark")
? isCommandAvailable(runCommand, "aptss")
@@ -385,7 +387,9 @@ export const loadUpdateCenterItems = async (
? isCommandAvailable(runCommand, "apm")
: Promise.resolve(false),
]);
console.log(`[UpdateCenter] sparkEnabled=${sparkEnabled}, apmEnabled=${apmEnabled}`);
console.log(
`[UpdateCenter] sparkEnabled=${sparkEnabled}, apmEnabled=${apmEnabled}`,
);
const [aptssResult, apmResult, aptssInstalledResult, apmInstalledResult] =
await Promise.all([
@@ -409,10 +413,18 @@ export const loadUpdateCenterItems = async (
: Promise.resolve({ code: 0, stdout: "", stderr: "" }),
]);
console.log(`[UpdateCenter] aptssResult: code=${aptssResult.code}, stdout=${aptssResult.stdout.substring(0, 500)}, stderr=${aptssResult.stderr.substring(0, 500)}`);
console.log(`[UpdateCenter] apmResult: code=${apmResult.code}, stdout=${apmResult.stdout.substring(0, 500)}, stderr=${apmResult.stderr.substring(0, 500)}`);
console.log(`[UpdateCenter] aptssInstalledResult: code=${aptssInstalledResult.code}, stdout=${aptssInstalledResult.stdout.substring(0, 500)}`);
console.log(`[UpdateCenter] apmInstalledResult: code=${apmInstalledResult.code}, stdout=${apmInstalledResult.stdout.substring(0, 500)}`);
console.log(
`[UpdateCenter] aptssResult: code=${aptssResult.code}, stdout=${aptssResult.stdout.substring(0, 500)}, stderr=${aptssResult.stderr.substring(0, 500)}`,
);
console.log(
`[UpdateCenter] apmResult: code=${apmResult.code}, stdout=${apmResult.stdout.substring(0, 500)}, stderr=${apmResult.stderr.substring(0, 500)}`,
);
console.log(
`[UpdateCenter] aptssInstalledResult: code=${aptssInstalledResult.code}, stdout=${aptssInstalledResult.stdout.substring(0, 500)}`,
);
console.log(
`[UpdateCenter] apmInstalledResult: code=${apmInstalledResult.code}, stdout=${apmInstalledResult.stdout.substring(0, 500)}`,
);
const aptssAvailable =
sparkEnabled && (aptssResult.code === 0 || aptssInstalledResult.code === 0);
@@ -438,8 +450,14 @@ export const loadUpdateCenterItems = async (
apmEnabled && apmResult.code === 0
? parseApmUpgradableOutput(apmResult.stdout)
: [];
console.log(`[UpdateCenter] parsed aptssItems count=${aptssItems.length}`, aptssItems.map((i) => `${i.pkgname} ${i.currentVersion}->${i.nextVersion}`));
console.log(`[UpdateCenter] parsed apmItems count=${apmItems.length}`, apmItems.map((i) => `${i.pkgname} ${i.currentVersion}->${i.nextVersion}`));
console.log(
`[UpdateCenter] parsed aptssItems count=${aptssItems.length}`,
aptssItems.map((i) => `${i.pkgname} ${i.currentVersion}->${i.nextVersion}`),
);
console.log(
`[UpdateCenter] parsed apmItems count=${apmItems.length}`,
apmItems.map((i) => `${i.pkgname} ${i.currentVersion}->${i.nextVersion}`),
);
const installedSources = buildInstalledSourceMap(
aptssAvailable && aptssInstalledResult.code === 0
@@ -461,15 +479,26 @@ export const loadUpdateCenterItems = async (
? enrichApmItems(categorizedApmItems, runCommand)
: Promise.resolve({ items: [], warnings: [] }),
]);
console.log(`[UpdateCenter] enrichedAptssItems: count=${enrichedAptssItems.items.length}, warnings=${enrichedAptssItems.warnings.length}`, enrichedAptssItems.warnings);
console.log(`[UpdateCenter] enrichedApmItems: count=${enrichedApmItems.items.length}, warnings=${enrichedApmItems.warnings.length}`, enrichedApmItems.warnings);
console.log(
`[UpdateCenter] enrichedAptssItems: count=${enrichedAptssItems.items.length}, warnings=${enrichedAptssItems.warnings.length}`,
enrichedAptssItems.warnings,
);
console.log(
`[UpdateCenter] enrichedApmItems: count=${enrichedApmItems.items.length}, warnings=${enrichedApmItems.warnings.length}`,
enrichedApmItems.warnings,
);
const mergedItems = mergeUpdateSources(
enrichItemIcons(enrichedAptssItems.items),
enrichItemIcons(enrichedApmItems.items),
installedSources,
);
console.log(`[UpdateCenter] mergedItems count=${mergedItems.length}`, mergedItems.map((i) => `${i.pkgname} (${i.source}) ${i.currentVersion}->${i.nextVersion}`));
console.log(
`[UpdateCenter] mergedItems count=${mergedItems.length}`,
mergedItems.map(
(i) => `${i.pkgname} (${i.source}) ${i.currentVersion}->${i.nextVersion}`,
),
);
return {
items: mergedItems,
+21 -7
View File
@@ -263,16 +263,26 @@ const compareVersions = (left: string, right: string): number => {
export const parseAptssUpgradableOutput = (
output: string,
): UpdateCenterItem[] => {
console.log(`[UpdateCenter] parseAptssUpgradableOutput input (first 1000 chars): ${output.substring(0, 1000)}`);
console.log(
`[UpdateCenter] parseAptssUpgradableOutput input (first 1000 chars): ${output.substring(0, 1000)}`,
);
const result = parseUpgradableOutput(output, "aptss");
console.log(`[UpdateCenter] parseAptssUpgradableOutput result count=${result.length}`);
console.log(
`[UpdateCenter] parseAptssUpgradableOutput result count=${result.length}`,
);
return result;
};
export const parseApmUpgradableOutput = (output: string): UpdateCenterItem[] => {
console.log(`[UpdateCenter] parseApmUpgradableOutput input (first 1000 chars): ${output.substring(0, 1000)}`);
export const parseApmUpgradableOutput = (
output: string,
): UpdateCenterItem[] => {
console.log(
`[UpdateCenter] parseApmUpgradableOutput input (first 1000 chars): ${output.substring(0, 1000)}`,
);
const result = parseUpgradableOutput(output, "apm");
console.log(`[UpdateCenter] parseApmUpgradableOutput result count=${result.length}`);
console.log(
`[UpdateCenter] parseApmUpgradableOutput result count=${result.length}`,
);
return result;
};
@@ -283,10 +293,14 @@ export const parsePrintUrisOutput = (
"downloadUrl" | "fileName" | "size" | "sha512"
> | null => {
const trimmed = output.trim();
console.log(`[UpdateCenter] parsePrintUrisOutput input (first 500 chars): ${trimmed.substring(0, 500)}`);
console.log(
`[UpdateCenter] parsePrintUrisOutput input (first 500 chars): ${trimmed.substring(0, 500)}`,
);
const match = trimmed.match(PRINT_URIS_PATTERN);
if (!match) {
console.log(`[UpdateCenter] parsePrintUrisOutput: no match found for pattern ${PRINT_URIS_PATTERN}`);
console.log(
`[UpdateCenter] parsePrintUrisOutput: no match found for pattern ${PRINT_URIS_PATTERN}`,
);
return null;
}
+10 -3
View File
@@ -166,7 +166,9 @@ export const createUpdateCenterService = (
storeFilter: StoreFilter = currentStoreFilter,
): Promise<UpdateCenterServiceState> => {
currentStoreFilter = storeFilter;
console.log(`[UpdateCenter] service.refresh called with storeFilter=${storeFilter}`);
console.log(
`[UpdateCenter] service.refresh called with storeFilter=${storeFilter}`,
);
queue.startRefresh();
emit();
@@ -176,11 +178,16 @@ export const createUpdateCenterService = (
const loadedItems = normalizeLoadedItems(
await options.loadItems(currentStoreFilter),
);
console.log(`[UpdateCenter] loadItems returned: items=${loadedItems.items.length}, warnings=${loadedItems.warnings.length}`, loadedItems.warnings);
console.log(
`[UpdateCenter] loadItems returned: items=${loadedItems.items.length}, warnings=${loadedItems.warnings.length}`,
loadedItems.warnings,
);
const items = sortIgnoredItems(
applyIgnoredEntries(loadedItems.items, ignoredEntries),
);
console.log(`[UpdateCenter] after applying ignored: items=${items.length}`);
console.log(
`[UpdateCenter] after applying ignored: items=${items.length}`,
);
queue.setItems(items);
queue.finishRefresh(loadedItems.warnings);
return emit();
+12 -7
View File
@@ -98,13 +98,18 @@ logger.info("User Agent: " + getUserAgent());
/** 根据启动参数 --no-apm / --no-spark 决定只展示的来源 */
function getStoreFilterFromArgv(): "spark" | "apm" | "both" {
const argv = process.argv;
const noApm = argv.includes("--no-apm");
const noSpark = argv.includes("--no-spark");
if (noApm && noSpark) return "both";
if (noApm) return "spark";
if (noSpark) return "apm";
return "both";
if (process.arch === "loong64") {
// Currently loong64 only have spark support
return "spark";
} else {
const argv = process.argv;
const noApm = argv.includes("--no-apm");
const noSpark = argv.includes("--no-spark");
if (noApm && noSpark) return "both";
if (noApm) return "spark";
if (noSpark) return "apm";
return "both";
}
}
ipcMain.handle("get-store-filter", (): "spark" | "apm" | "both" =>
+17 -15
View File
@@ -1,12 +1,12 @@
{
"name": "spark-store",
"version": "5.0.0beta4",
"version": "5.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "spark-store",
"version": "5.0.0beta4",
"version": "5.0.0",
"license": "GPL-3.0",
"dependencies": {
"@tailwindcss/vite": "^4.1.18",
@@ -28,7 +28,7 @@
"@vue/test-utils": "^2.4.3",
"conventional-changelog": "^7.1.1",
"conventional-changelog-angular": "^8.1.0",
"electron": "^40.0.0",
"electron": "^39.2.7",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.5",
@@ -4870,15 +4870,15 @@
}
},
"node_modules/electron": {
"version": "40.8.5",
"resolved": "https://registry.npmjs.org/electron/-/electron-40.8.5.tgz",
"integrity": "sha512-pgTY/VPQKaiU4sTjfU96iyxCXrFm4htVPCMRT4b7q9ijNTRgtLmLvcmzp2G4e7xDrq9p7OLHSmu1rBKFf6Y1/A==",
"version": "39.2.7",
"resolved": "https://registry.npmjs.org/electron/-/electron-39.2.7.tgz",
"integrity": "sha512-KU0uFS6LSTh4aOIC3miolcbizOFP7N1M46VTYVfqIgFiuA2ilfNaOHLDS9tCMvwwHRowAsvqBrh9NgMXcTOHCQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@electron/get": "^2.0.0",
"@types/node": "^24.9.0",
"@types/node": "^22.7.7",
"extract-zip": "^2.0.1"
},
"bin": {
@@ -4889,19 +4889,21 @@
}
},
"node_modules/electron/node_modules/@types/node": {
"version": "24.12.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz",
"integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==",
"version": "22.19.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz",
"integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
"undici-types": "~6.21.0"
}
},
"node_modules/electron/node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
},
"node_modules/emoji-regex": {
"version": "8.0.0",
+2 -1
View File
@@ -30,6 +30,7 @@
"build:vite": "vue-tsc --noEmit && vite build --mode production",
"build:rpm": "vue-tsc --noEmit && vite build --mode production && electron-builder --config electron-builder.yml --linux rpm",
"build:deb": "vue-tsc --noEmit && vite build --mode production && electron-builder --config electron-builder.yml --linux deb",
"build:deb-loong64": "vue-tsc --noEmit && vite build --mode production && env ELECTRON_MIRROR=https://github.com/darkyzhou/electron-loong64/releases/download/ electron_use_remote_checksums=1 electron-builder --config electron-builder.yml --loong64 --linux deb",
"preview": "vite preview --mode debug",
"lint": "eslint --ext .ts,.vue src electron",
"lint:fix": "eslint --ext .ts,.vue src electron --fix",
@@ -56,7 +57,7 @@
"@vue/test-utils": "^2.4.3",
"conventional-changelog": "^7.1.1",
"conventional-changelog-angular": "^8.1.0",
"electron": "^40.0.0",
"electron": "^39.2.7",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.5",
@@ -191,15 +191,18 @@ describe("update-center load items", () => {
],
});
const result = await loadUpdateCenterItems("both", async (command, args) => {
const key = `${command} ${args.join(" ")}`;
const match = commandResults.get(key);
if (!match) {
throw new Error(`Missing mock for ${key}`);
}
const result = await loadUpdateCenterItems(
"both",
async (command, args) => {
const key = `${command} ${args.join(" ")}`;
const match = commandResults.get(key);
if (!match) {
throw new Error(`Missing mock for ${key}`);
}
return match;
});
return match;
},
);
expect(result.warnings).toEqual([]);
expect(result.items).toContainEqual({
@@ -233,61 +236,64 @@ describe("update-center load items", () => {
],
});
const result = await loadUpdateCenterItems("both", async (command, args) => {
const key = `${command} ${args.join(" ")}`;
const result = await loadUpdateCenterItems(
"both",
async (command, args) => {
const key = `${command} ${args.join(" ")}`;
if (key === WHICH_APTSS_KEY) {
return { code: 0, stdout: "/usr/bin/aptss\n", stderr: "" };
}
if (key === WHICH_APTSS_KEY) {
return { code: 0, stdout: "/usr/bin/aptss\n", stderr: "" };
}
if (key === WHICH_APM_KEY) {
return { code: 127, stdout: "", stderr: "apm: command not found" };
}
if (key === WHICH_APM_KEY) {
return { code: 127, stdout: "", stderr: "apm: command not found" };
}
if (key === APTSS_LIST_UPGRADABLE_KEY) {
return {
code: 0,
stdout: "spark-notes/stable 2.0.0 amd64 [upgradable from: 1.0.0]",
stderr: "",
};
}
if (key === APTSS_LIST_UPGRADABLE_KEY) {
return {
code: 0,
stdout: "spark-notes/stable 2.0.0 amd64 [upgradable from: 1.0.0]",
stderr: "",
};
}
if (key === DPKG_QUERY_INSTALLED_KEY) {
return {
code: 0,
stdout: "spark-notes\tinstall ok installed\n",
stderr: "",
};
}
if (key === DPKG_QUERY_INSTALLED_KEY) {
return {
code: 0,
stdout: "spark-notes\tinstall ok installed\n",
stderr: "",
};
}
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 === 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 === 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 === 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") {
return {
code: 127,
stdout: "",
stderr: "apm: command not found",
};
}
if (key === "apm list --upgradable" || key === "apm list --installed") {
return {
code: 127,
stdout: "",
stderr: "apm: command not found",
};
}
throw new Error(`Unexpected command ${key}`);
});
throw new Error(`Unexpected command ${key}`);
},
);
expect(result.items).toEqual([
{
@@ -416,52 +422,55 @@ describe("update-center load items", () => {
],
});
const result = await loadUpdateCenterItems("both", async (command, args) => {
const key = `${command} ${args.join(" ")}`;
const result = await loadUpdateCenterItems(
"both",
async (command, args) => {
const key = `${command} ${args.join(" ")}`;
if (key === WHICH_APTSS_KEY) {
return { code: 0, stdout: "/usr/bin/aptss\n", stderr: "" };
}
if (key === WHICH_APTSS_KEY) {
return { code: 0, stdout: "/usr/bin/aptss\n", stderr: "" };
}
if (key === WHICH_APM_KEY) {
return { code: 127, stdout: "", stderr: "apm: command not found" };
}
if (key === WHICH_APM_KEY) {
return { code: 127, stdout: "", stderr: "apm: command not found" };
}
if (key === APTSS_LIST_UPGRADABLE_KEY) {
return {
code: 0,
stdout: "spark-notes/stable 2.0.0 amd64 [upgradable from: 1.0.0]",
stderr: "",
};
}
if (key === APTSS_LIST_UPGRADABLE_KEY) {
return {
code: 0,
stdout: "spark-notes/stable 2.0.0 amd64 [upgradable from: 1.0.0]",
stderr: "",
};
}
if (key === DPKG_QUERY_INSTALLED_KEY) {
return {
code: 0,
stdout: "spark-notes\tinstall ok installed\n",
stderr: "",
};
}
if (key === DPKG_QUERY_INSTALLED_KEY) {
return {
code: 0,
stdout: "spark-notes\tinstall ok installed\n",
stderr: "",
};
}
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 === 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") {
return {
code: 127,
stdout: "",
stderr: "apm: command not found",
};
}
if (key === "apm list --upgradable" || key === "apm list --installed") {
return {
code: 127,
stdout: "",
stderr: "apm: command not found",
};
}
throw new Error(`Unexpected command ${key}`);
});
throw new Error(`Unexpected command ${key}`);
},
);
expect(result.items).toEqual([
{
+3 -1
View File
@@ -47,7 +47,9 @@
v-if="store.loading.value && store.filteredItems.value.length === 0"
class="flex min-h-0 flex-1 items-center justify-center p-6"
>
<div class="flex flex-col items-center gap-3 text-slate-500 dark:text-slate-400">
<div
class="flex flex-col items-center gap-3 text-slate-500 dark:text-slate-400"
>
<i class="fas fa-circle-notch fa-spin text-3xl"></i>
<p class="text-sm">正在检查更新</p>
</div>