electrobun 1.7.0-beta.0 → 1.7.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cli/index.ts +257 -237
package/package.json
CHANGED
package/src/cli/index.ts
CHANGED
|
@@ -1126,9 +1126,9 @@ async function createAppImage(
|
|
|
1126
1126
|
},
|
|
1127
1127
|
);
|
|
1128
1128
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1129
|
+
// Create AppRun script (the entry point)
|
|
1130
|
+
const appBundleBasename = basename(resolvedAppBundlePath);
|
|
1131
|
+
const appRunContent = `#!/bin/bash
|
|
1132
1132
|
# AppRun script for ${appFileName}
|
|
1133
1133
|
HERE="$(dirname "$(readlink -f "\${0}")")"
|
|
1134
1134
|
EXEC="\${HERE}/usr/bin/${appBundleBasename}/bin/launcher"
|
|
@@ -1144,9 +1144,9 @@ exec "\${EXEC}" "\$@"
|
|
|
1144
1144
|
writeFileSync(appRunPath, appRunContent);
|
|
1145
1145
|
execSync(`chmod +x ${escapePathForTerminal(appRunPath)}`);
|
|
1146
1146
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1147
|
+
// Create .desktop file in AppDir root
|
|
1148
|
+
// Always include Icon field since we always create an icon (either real or placeholder)
|
|
1149
|
+
const desktopContent = `[Desktop Entry]
|
|
1150
1150
|
Version=1.0
|
|
1151
1151
|
Type=Application
|
|
1152
1152
|
Name=${config.app.name}
|
|
@@ -1161,7 +1161,7 @@ Categories=Utility;
|
|
|
1161
1161
|
const desktopPath = join(appDirPath, `${appFileName}.desktop`);
|
|
1162
1162
|
writeFileSync(desktopPath, desktopContent);
|
|
1163
1163
|
|
|
1164
|
-
|
|
1164
|
+
// Copy icon if available, or create a minimal placeholder
|
|
1165
1165
|
if (
|
|
1166
1166
|
config.build.linux?.icon &&
|
|
1167
1167
|
existsSync(join(projectRoot, config.build.linux.icon))
|
|
@@ -1181,72 +1181,72 @@ Categories=Utility;
|
|
|
1181
1181
|
// Create a minimal 1x1 transparent PNG as placeholder to satisfy appimagetool
|
|
1182
1182
|
// This prevents "Icon entry not found" errors
|
|
1183
1183
|
const placeholderPNG = Buffer.from([
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1184
|
+
0x89,
|
|
1185
|
+
0x50,
|
|
1186
|
+
0x4e,
|
|
1187
|
+
0x47,
|
|
1188
|
+
0x0d,
|
|
1189
|
+
0x0a,
|
|
1190
|
+
0x1a,
|
|
1191
|
+
0x0a, // PNG signature
|
|
1192
|
+
0x00,
|
|
1193
|
+
0x00,
|
|
1194
|
+
0x00,
|
|
1195
|
+
0x0d,
|
|
1196
|
+
0x49,
|
|
1197
|
+
0x48,
|
|
1198
|
+
0x44,
|
|
1199
|
+
0x52, // IHDR chunk
|
|
1200
|
+
0x00,
|
|
1201
|
+
0x00,
|
|
1202
|
+
0x00,
|
|
1203
|
+
0x01,
|
|
1204
|
+
0x00,
|
|
1205
|
+
0x00,
|
|
1206
|
+
0x00,
|
|
1207
|
+
0x01, // 1x1 dimensions
|
|
1208
|
+
0x08,
|
|
1209
|
+
0x06,
|
|
1210
|
+
0x00,
|
|
1211
|
+
0x00,
|
|
1212
|
+
0x00,
|
|
1213
|
+
0x1f,
|
|
1214
|
+
0x15,
|
|
1215
|
+
0xc4, // 8-bit RGBA
|
|
1216
|
+
0x89,
|
|
1217
|
+
0x00,
|
|
1218
|
+
0x00,
|
|
1219
|
+
0x00,
|
|
1220
|
+
0x0b,
|
|
1221
|
+
0x49,
|
|
1222
|
+
0x44,
|
|
1223
|
+
0x41, // IDAT chunk
|
|
1224
|
+
0x54,
|
|
1225
|
+
0x08,
|
|
1226
|
+
0x99,
|
|
1227
|
+
0x01,
|
|
1228
|
+
0x00,
|
|
1229
|
+
0x00,
|
|
1230
|
+
0x05,
|
|
1231
|
+
0x00,
|
|
1232
|
+
0x01,
|
|
1233
|
+
0x06,
|
|
1234
|
+
0x7a,
|
|
1235
|
+
0x81,
|
|
1236
|
+
0x7c,
|
|
1237
|
+
0x00,
|
|
1238
|
+
0x00,
|
|
1239
|
+
0x00, // IEND chunk
|
|
1240
|
+
0x00,
|
|
1241
|
+
0x49,
|
|
1242
|
+
0x45,
|
|
1243
|
+
0x4e,
|
|
1244
|
+
0x44,
|
|
1245
|
+
0xae,
|
|
1246
|
+
0x42,
|
|
1247
|
+
0x60,
|
|
1248
|
+
0x82,
|
|
1249
|
+
]);
|
|
1250
1250
|
|
|
1251
1251
|
const iconDestPath = join(appDirPath, `${appFileName}.png`);
|
|
1252
1252
|
const dirIconPath = join(appDirPath, ".DirIcon");
|
|
@@ -1259,18 +1259,18 @@ Categories=Utility;
|
|
|
1259
1259
|
);
|
|
1260
1260
|
}
|
|
1261
1261
|
|
|
1262
|
-
|
|
1262
|
+
// Generate the AppImage using appimagetool
|
|
1263
1263
|
const appImagePath = join(buildFolder, `${appFileName}.AppImage`);
|
|
1264
1264
|
if (existsSync(appImagePath)) {
|
|
1265
1265
|
unlinkSync(appImagePath);
|
|
1266
1266
|
}
|
|
1267
1267
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1268
|
+
// console.log(`DEBUG: AppDir path: ${appDirPath}`);
|
|
1269
|
+
// console.log(`DEBUG: Does AppDir exist? ${existsSync(appDirPath)}`);
|
|
1270
1270
|
console.log(`Generating AppImage: ${appImagePath}`);
|
|
1271
1271
|
const appImageArch = ARCH === "arm64" ? "aarch64" : "x86_64";
|
|
1272
1272
|
|
|
1273
|
-
|
|
1273
|
+
// Use full path to appimagetool if not in PATH
|
|
1274
1274
|
let appimagetoolBase = "appimagetool";
|
|
1275
1275
|
try {
|
|
1276
1276
|
execSync("which appimagetool", { stdio: "ignore" });
|
|
@@ -1287,7 +1287,7 @@ Categories=Utility;
|
|
|
1287
1287
|
}
|
|
1288
1288
|
}
|
|
1289
1289
|
|
|
1290
|
-
|
|
1290
|
+
// Get the command with proper environment for vendored libfuse2
|
|
1291
1291
|
const appimagetoolCmd = getAppImageToolCommand().replace(
|
|
1292
1292
|
"appimagetool",
|
|
1293
1293
|
appimagetoolBase,
|
|
@@ -1311,14 +1311,14 @@ Categories=Utility;
|
|
|
1311
1311
|
throw error;
|
|
1312
1312
|
}
|
|
1313
1313
|
|
|
1314
|
-
|
|
1314
|
+
// Verify the AppImage was created
|
|
1315
1315
|
if (!existsSync(appImagePath)) {
|
|
1316
1316
|
throw new Error(
|
|
1317
1317
|
`AppImage was not created at expected path: ${appImagePath}`,
|
|
1318
1318
|
);
|
|
1319
1319
|
}
|
|
1320
1320
|
|
|
1321
|
-
|
|
1321
|
+
// Extract and copy icon for desktop shortcut
|
|
1322
1322
|
const iconExtractPath = join(buildFolder, `${appFileName}.png`);
|
|
1323
1323
|
if (
|
|
1324
1324
|
config.build.linux?.icon &&
|
|
@@ -1330,23 +1330,23 @@ Categories=Utility;
|
|
|
1330
1330
|
} else {
|
|
1331
1331
|
// Create placeholder icon for desktop shortcut
|
|
1332
1332
|
const placeholderPNG = Buffer.from([
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1333
|
+
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
|
1334
|
+
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
|
|
1335
|
+
0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x15, 0xc4, 0x89, 0x00, 0x00, 0x00,
|
|
1336
|
+
0x0b, 0x49, 0x44, 0x41, 0x54, 0x08, 0x99, 0x01, 0x00, 0x00, 0x05, 0x00,
|
|
1337
|
+
0x01, 0x06, 0x7a, 0x81, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e,
|
|
1338
|
+
0x44, 0xae, 0x42, 0x60, 0x82,
|
|
1339
|
+
]);
|
|
1340
1340
|
writeFileSync(iconExtractPath, new Uint8Array(placeholderPNG));
|
|
1341
1341
|
console.log(
|
|
1342
1342
|
`✓ Created placeholder icon for desktop shortcut: ${iconExtractPath}`,
|
|
1343
1343
|
);
|
|
1344
1344
|
}
|
|
1345
1345
|
|
|
1346
|
-
|
|
1346
|
+
// Create desktop shortcut alongside the AppImage
|
|
1347
1347
|
const desktopShortcutPath = join(buildFolder, `${appFileName}.desktop`);
|
|
1348
1348
|
|
|
1349
|
-
|
|
1349
|
+
const desktopShortcutContent = `[Desktop Entry]
|
|
1350
1350
|
Version=1.0
|
|
1351
1351
|
Type=Application
|
|
1352
1352
|
Name=${config.app.name}
|
|
@@ -2661,20 +2661,36 @@ ${schemesXml}
|
|
|
2661
2661
|
}
|
|
2662
2662
|
}
|
|
2663
2663
|
|
|
2664
|
-
//
|
|
2665
|
-
//
|
|
2666
|
-
//
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2664
|
+
// Create a content hash for version.json. In non-dev builds this is used
|
|
2665
|
+
// by the updater to detect changes. For dev builds we skip it since
|
|
2666
|
+
// the updater isn't relevant.
|
|
2667
|
+
let hash: string;
|
|
2668
|
+
if (buildEnvironment === "dev") {
|
|
2669
|
+
hash = "dev";
|
|
2670
|
+
} else {
|
|
2671
|
+
// Walk the app bundle and create an in-memory tar for hashing
|
|
2672
|
+
// (no temp file on disk). This runs after ASAR packing so the
|
|
2673
|
+
// hash reflects the final shipped bundle contents.
|
|
2674
|
+
console.time("Generate Bundle hash");
|
|
2675
|
+
const bundleFiles: Record<string, Blob> = {};
|
|
2676
|
+
const bundleBase = basename(appBundleFolderPath);
|
|
2677
|
+
const entries = readdirSync(appBundleFolderPath, {
|
|
2678
|
+
recursive: true,
|
|
2679
|
+
});
|
|
2680
|
+
for (const entry of entries) {
|
|
2681
|
+
const entryPath = entry.toString();
|
|
2682
|
+
const fullPath = join(appBundleFolderPath, entryPath);
|
|
2683
|
+
if (statSync(fullPath).isFile()) {
|
|
2684
|
+
bundleFiles[join(bundleBase, entryPath)] = Bun.file(fullPath);
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
const archiveBytes = await new Bun.Archive(bundleFiles).bytes();
|
|
2688
|
+
// Note: wyhash is the default in Bun.hash but that may change in the future
|
|
2689
|
+
// so we're being explicit here.
|
|
2690
|
+
hash = Bun.hash.wyhash(archiveBytes, 43770n).toString(36);
|
|
2691
|
+
console.timeEnd("Generate Bundle hash");
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2678
2694
|
// const bunVersion = execSync(`${bunBinarySourcePath} --version`).toString().trim();
|
|
2679
2695
|
|
|
2680
2696
|
// version.json inside the app bundle
|
|
@@ -2820,9 +2836,7 @@ ${schemesXml}
|
|
|
2820
2836
|
);
|
|
2821
2837
|
|
|
2822
2838
|
const appImageTarPath = join(buildFolder, `${appFileName}.tar`);
|
|
2823
|
-
console.log(
|
|
2824
|
-
`Creating tar of installer contents: ${appImageTarPath}`,
|
|
2825
|
-
);
|
|
2839
|
+
console.log(`Creating tar of installer contents: ${appImageTarPath}`);
|
|
2826
2840
|
|
|
2827
2841
|
// Tar the inner directory
|
|
2828
2842
|
createTar(appImageTarPath, tempDirPath, [appFileName]);
|
|
@@ -2965,15 +2979,15 @@ ${schemesXml}
|
|
|
2965
2979
|
const decompressResult = Bun.spawnSync(
|
|
2966
2980
|
[
|
|
2967
2981
|
zstdPath,
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2982
|
+
"decompress",
|
|
2983
|
+
"-i",
|
|
2984
|
+
prevVersionCompressedTarballPath,
|
|
2985
|
+
"-o",
|
|
2986
|
+
prevTarballPath,
|
|
2987
|
+
],
|
|
2988
|
+
{
|
|
2989
|
+
cwd: buildFolder,
|
|
2990
|
+
stdout: "inherit",
|
|
2977
2991
|
stderr: "inherit",
|
|
2978
2992
|
},
|
|
2979
2993
|
);
|
|
@@ -3209,7 +3223,10 @@ ${schemesXml}
|
|
|
3209
3223
|
)} -ov -format ULFO ${escapePathForTerminal(dmgCreationPath)}`,
|
|
3210
3224
|
);
|
|
3211
3225
|
|
|
3212
|
-
if (
|
|
3226
|
+
if (
|
|
3227
|
+
buildEnvironment === "stable" &&
|
|
3228
|
+
dmgCreationPath !== finalDmgPath
|
|
3229
|
+
) {
|
|
3213
3230
|
renameSync(dmgCreationPath, finalDmgPath);
|
|
3214
3231
|
}
|
|
3215
3232
|
artifactsToUpload.push(finalDmgPath);
|
|
@@ -3320,7 +3337,10 @@ ${schemesXml}
|
|
|
3320
3337
|
|
|
3321
3338
|
artifactsToUpload.forEach((filePath) => {
|
|
3322
3339
|
const filename = basename(filePath);
|
|
3323
|
-
const destination = join(
|
|
3340
|
+
const destination = join(
|
|
3341
|
+
artifactFolder,
|
|
3342
|
+
`${platformPrefix}-${filename}`,
|
|
3343
|
+
);
|
|
3324
3344
|
try {
|
|
3325
3345
|
renameSync(filePath, destination);
|
|
3326
3346
|
} catch {
|
|
@@ -3862,57 +3882,57 @@ ${schemesXml}
|
|
|
3862
3882
|
const wrapperAppDirPath = join(buildFolder, `${wrapperName}.AppDir`);
|
|
3863
3883
|
|
|
3864
3884
|
// Clean up any existing AppDir
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3885
|
+
if (existsSync(wrapperAppDirPath)) {
|
|
3886
|
+
rmSync(wrapperAppDirPath, { recursive: true, force: true });
|
|
3887
|
+
}
|
|
3888
|
+
mkdirSync(wrapperAppDirPath, { recursive: true });
|
|
3869
3889
|
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3890
|
+
try {
|
|
3891
|
+
// Create usr/bin directory structure
|
|
3892
|
+
const usrBinPath = join(wrapperAppDirPath, "usr", "bin");
|
|
3893
|
+
mkdirSync(usrBinPath, { recursive: true });
|
|
3874
3894
|
|
|
3875
|
-
|
|
3876
|
-
|
|
3895
|
+
// Create self-extracting binary with embedded archive (following magic markers pattern)
|
|
3896
|
+
const targetPaths = getPlatformPaths("linux", ARCH);
|
|
3877
3897
|
|
|
3878
|
-
|
|
3879
|
-
|
|
3898
|
+
// Read the extractor binary
|
|
3899
|
+
const extractorBinary = readFileSync(targetPaths.EXTRACTOR);
|
|
3880
3900
|
|
|
3881
|
-
|
|
3882
|
-
|
|
3901
|
+
// Read the compressed archive
|
|
3902
|
+
const compressedArchive = readFileSync(compressedTarPath);
|
|
3883
3903
|
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3904
|
+
// Create metadata JSON
|
|
3905
|
+
const metadata = {
|
|
3906
|
+
identifier: config.app.identifier,
|
|
3907
|
+
name: config.app.name,
|
|
3908
|
+
channel: buildEnvironment,
|
|
3909
|
+
hash: hash,
|
|
3910
|
+
};
|
|
3911
|
+
const metadataJson = JSON.stringify(metadata);
|
|
3912
|
+
const metadataBuffer = Buffer.from(metadataJson, "utf8");
|
|
3913
|
+
|
|
3914
|
+
// Create marker buffers
|
|
3915
|
+
const metadataMarker = Buffer.from("ELECTROBUN_METADATA_V1", "utf8");
|
|
3916
|
+
const archiveMarker = Buffer.from("ELECTROBUN_ARCHIVE_V1", "utf8");
|
|
3917
|
+
|
|
3918
|
+
// Combine extractor + metadata marker + metadata + archive marker + archive
|
|
3919
|
+
const combinedBuffer = Buffer.concat([
|
|
3920
|
+
new Uint8Array(extractorBinary),
|
|
3921
|
+
new Uint8Array(metadataMarker),
|
|
3922
|
+
new Uint8Array(metadataBuffer),
|
|
3923
|
+
new Uint8Array(archiveMarker),
|
|
3924
|
+
new Uint8Array(compressedArchive),
|
|
3925
|
+
]);
|
|
3926
|
+
|
|
3927
|
+
// Write the self-extracting binary to AppImage/usr/bin/
|
|
3928
|
+
const wrapperExtractorPath = join(usrBinPath, wrapperName);
|
|
3929
|
+
writeFileSync(wrapperExtractorPath, new Uint8Array(combinedBuffer), {
|
|
3930
|
+
mode: 0o755,
|
|
3931
|
+
});
|
|
3932
|
+
execSync(`chmod +x ${escapePathForTerminal(wrapperExtractorPath)}`);
|
|
3913
3933
|
|
|
3914
|
-
|
|
3915
|
-
|
|
3934
|
+
// Create AppRun script
|
|
3935
|
+
const appRunContent = `#!/bin/bash
|
|
3916
3936
|
# AppRun script for ${wrapperName}
|
|
3917
3937
|
HERE="$(dirname "$(readlink -f "\${0}")")"
|
|
3918
3938
|
EXEC="\${HERE}/usr/bin/${wrapperName}"
|
|
@@ -3921,17 +3941,17 @@ EXEC="\${HERE}/usr/bin/${wrapperName}"
|
|
|
3921
3941
|
exec "\${EXEC}" "\$@"
|
|
3922
3942
|
`;
|
|
3923
3943
|
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3944
|
+
const appRunPath = join(wrapperAppDirPath, "AppRun");
|
|
3945
|
+
writeFileSync(appRunPath, appRunContent);
|
|
3946
|
+
execSync(`chmod +x ${escapePathForTerminal(appRunPath)}`);
|
|
3927
3947
|
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3948
|
+
// Check if icon will be available
|
|
3949
|
+
const hasWrapperIcon =
|
|
3950
|
+
config.build.linux?.icon &&
|
|
3951
|
+
existsSync(join(projectRoot, config.build.linux.icon));
|
|
3932
3952
|
|
|
3933
|
-
|
|
3934
|
-
|
|
3953
|
+
// Create desktop file
|
|
3954
|
+
const desktopContent = `[Desktop Entry]
|
|
3935
3955
|
Version=1.0
|
|
3936
3956
|
Type=Application
|
|
3937
3957
|
Name=${config.app.name} Installer
|
|
@@ -3941,88 +3961,88 @@ Terminal=false
|
|
|
3941
3961
|
Categories=Utility;
|
|
3942
3962
|
`;
|
|
3943
3963
|
|
|
3944
|
-
|
|
3945
|
-
|
|
3964
|
+
const desktopPath = join(wrapperAppDirPath, `${wrapperName}.desktop`);
|
|
3965
|
+
writeFileSync(desktopPath, desktopContent);
|
|
3946
3966
|
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3967
|
+
// Copy icon if available
|
|
3968
|
+
if (hasWrapperIcon) {
|
|
3969
|
+
const iconSourcePath = join(projectRoot, config.build.linux.icon);
|
|
3970
|
+
const iconDestPath = join(wrapperAppDirPath, `${wrapperName}.png`);
|
|
3971
|
+
const dirIconPath = join(wrapperAppDirPath, ".DirIcon");
|
|
3952
3972
|
|
|
3953
|
-
|
|
3954
|
-
|
|
3973
|
+
cpSync(iconSourcePath, iconDestPath, { dereference: true });
|
|
3974
|
+
cpSync(iconSourcePath, dirIconPath, { dereference: true });
|
|
3955
3975
|
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3976
|
+
console.log(
|
|
3977
|
+
`Copied icon for wrapper AppImage: ${iconSourcePath} -> ${iconDestPath}`,
|
|
3978
|
+
);
|
|
3979
|
+
}
|
|
3960
3980
|
|
|
3961
|
-
|
|
3962
|
-
|
|
3981
|
+
// Ensure appimagetool is available
|
|
3982
|
+
await ensureAppImageTooling();
|
|
3963
3983
|
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3984
|
+
// Generate the wrapper AppImage
|
|
3985
|
+
if (existsSync(wrapperAppImagePath)) {
|
|
3986
|
+
unlinkSync(wrapperAppImagePath);
|
|
3987
|
+
}
|
|
3968
3988
|
|
|
3969
|
-
|
|
3970
|
-
|
|
3989
|
+
console.log(`Creating wrapper AppImage: ${wrapperAppImagePath}`);
|
|
3990
|
+
const appImageArch = ARCH === "arm64" ? "aarch64" : "x86_64";
|
|
3971
3991
|
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3992
|
+
// Use appimagetool to create the wrapper AppImage
|
|
3993
|
+
let appimagetoolBase = "appimagetool";
|
|
3994
|
+
try {
|
|
3995
|
+
execSync("which appimagetool", { stdio: "ignore" });
|
|
3996
|
+
} catch {
|
|
3997
|
+
const localBinPath = join(
|
|
3998
|
+
process.env["HOME"] || "",
|
|
3999
|
+
".local",
|
|
4000
|
+
"bin",
|
|
4001
|
+
"appimagetool",
|
|
4002
|
+
);
|
|
4003
|
+
if (existsSync(localBinPath)) {
|
|
4004
|
+
appimagetoolBase = localBinPath;
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
4007
|
+
|
|
4008
|
+
// Get the command with proper environment for vendored libfuse2
|
|
4009
|
+
const appimagetoolCmd = getAppImageToolCommand().replace(
|
|
3981
4010
|
"appimagetool",
|
|
4011
|
+
appimagetoolBase,
|
|
3982
4012
|
);
|
|
3983
|
-
if (existsSync(localBinPath)) {
|
|
3984
|
-
appimagetoolBase = localBinPath;
|
|
3985
|
-
}
|
|
3986
|
-
}
|
|
3987
4013
|
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
4014
|
+
try {
|
|
4015
|
+
execSync(
|
|
4016
|
+
`ARCH=${appImageArch} ${appimagetoolCmd} --no-appstream ${escapePathForTerminal(wrapperAppDirPath)} ${escapePathForTerminal(wrapperAppImagePath)}`,
|
|
4017
|
+
{
|
|
4018
|
+
stdio: "inherit",
|
|
4019
|
+
env: { ...process.env, ARCH: appImageArch },
|
|
4020
|
+
},
|
|
4021
|
+
);
|
|
4022
|
+
} catch (error) {
|
|
4023
|
+
console.error("Failed to create wrapper AppImage:", error);
|
|
4024
|
+
throw error;
|
|
4025
|
+
}
|
|
3993
4026
|
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
},
|
|
4001
|
-
);
|
|
4002
|
-
} catch (error) {
|
|
4003
|
-
console.error("Failed to create wrapper AppImage:", error);
|
|
4004
|
-
throw error;
|
|
4005
|
-
}
|
|
4027
|
+
// Verify the wrapper AppImage was created
|
|
4028
|
+
if (!existsSync(wrapperAppImagePath)) {
|
|
4029
|
+
throw new Error(
|
|
4030
|
+
`Wrapper AppImage was not created at expected path: ${wrapperAppImagePath}`,
|
|
4031
|
+
);
|
|
4032
|
+
}
|
|
4006
4033
|
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
`Wrapper AppImage was not created at expected path: ${wrapperAppImagePath}`,
|
|
4034
|
+
const stats = statSync(wrapperAppImagePath);
|
|
4035
|
+
console.log(
|
|
4036
|
+
`✓ Linux wrapper AppImage created: ${wrapperAppImagePath} (${(stats.size / 1024 / 1024).toFixed(2)} MB)`,
|
|
4011
4037
|
);
|
|
4012
|
-
}
|
|
4013
|
-
|
|
4014
|
-
const stats = statSync(wrapperAppImagePath);
|
|
4015
|
-
console.log(
|
|
4016
|
-
`✓ Linux wrapper AppImage created: ${wrapperAppImagePath} (${(stats.size / 1024 / 1024).toFixed(2)} MB)`,
|
|
4017
|
-
);
|
|
4018
4038
|
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4039
|
+
return wrapperAppImagePath;
|
|
4040
|
+
} finally {
|
|
4041
|
+
if (existsSync(wrapperAppDirPath)) {
|
|
4042
|
+
rmSync(wrapperAppDirPath, { recursive: true, force: true });
|
|
4043
|
+
}
|
|
4023
4044
|
}
|
|
4024
4045
|
}
|
|
4025
|
-
}
|
|
4026
4046
|
|
|
4027
4047
|
function codesignAppBundle(
|
|
4028
4048
|
appBundleOrDmgPath: string,
|