Skip to content

Commit af33162

Browse files
committed
Upacking fixes
1 parent 7252264 commit af33162

4 files changed

Lines changed: 85 additions & 19 deletions

File tree

app/docs/short_term_backlog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
Updater text area style
2+
Logs on installation
13
Installer on update
24
Downloading update... 8% - changes the text for a while for smth
35
Show update install dialog only when program is not in the tray

app/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"url": "https://github.com/HyperlinksSpace/HyperlinksSpaceBot.git"
99
},
1010
"main": "expo-router/entry",
11-
"version": "53.0.1305",
11+
"version": "53.0.1306",
1212
"type": "module",
1313
"engines": {
1414
"node": ">=18 <=22"

app/windows/build.cjs

Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,13 @@ async function downloadToFile(netFetch, url, destPath, onProgress) {
279279
* apparent stalls streaming huge files through Node). Fall back to extract-zip.
280280
* Pulse callback keeps the updater UI moving during large single-file writes (e.g. app.asar).
281281
*/
282-
async function extractPortableZipToDir(zipPath, extractDir, logFn, pulse, unpackLo, unpackHi) {
282+
/**
283+
* @param {object} [opts]
284+
* @param {string} [opts.verifyExeBase] If set, after system tar succeeds we require resolveZipAppContentRoot
285+
* to find the app; otherwise we clear and fall back to extract-zip (tar can exit 0 with a bad tree for some zips).
286+
*/
287+
async function extractPortableZipToDir(zipPath, extractDir, logFn, pulse, unpackLo, unpackHi, opts = {}) {
288+
const verifyExeBase = opts.verifyExeBase;
283289
const runExtractZip = async () => {
284290
logUpdater("extract", `extract-zip (yauzl) → ${extractDir}`);
285291
const extractZip = require("extract-zip");
@@ -354,6 +360,21 @@ async function extractPortableZipToDir(zipPath, extractDir, logFn, pulse, unpack
354360
clearInterval(hb);
355361
}
356362
logFn(`[updater] system tar done in ${Date.now() - t0}ms`);
363+
if (verifyExeBase) {
364+
const root = resolveZipAppContentRoot(extractDir, verifyExeBase);
365+
if (!root) {
366+
logFn(
367+
`[updater] system tar left no recognizable main exe (wanted basename like ${verifyExeBase}); clearing extract dir and using extract-zip`,
368+
);
369+
logUpdater("extract", "tar output verification failed → extract-zip");
370+
try {
371+
fs.rmSync(extractDir, { recursive: true, force: true });
372+
} catch (_) {}
373+
fs.mkdirSync(extractDir, { recursive: true });
374+
await runExtractZip();
375+
return;
376+
}
377+
}
357378
return;
358379
} catch (e) {
359380
logFn(`[updater] system tar failed (${e?.message || e}); clearing partial extract, retrying with extract-zip`);
@@ -381,18 +402,49 @@ function sha512Base64OfFile(filePath) {
381402
function resolveZipAppContentRoot(extractDir, exeBaseName) {
382403
const direct = path.join(extractDir, exeBaseName);
383404
if (fs.existsSync(direct)) return extractDir;
384-
let entries = [];
385-
try {
386-
entries = fs.readdirSync(extractDir, { withFileTypes: true });
387-
} catch (_) {
388-
return null;
389-
}
390-
for (const ent of entries) {
391-
if (!ent.isDirectory()) continue;
392-
const sub = path.join(extractDir, ent.name);
393-
if (fs.existsSync(path.join(sub, exeBaseName))) return sub;
405+
406+
/** Names to treat as the main app exe (portable zip vs running binary name can differ). */
407+
const altNames = new Set([exeBaseName]);
408+
if (process.platform === "win32") {
409+
altNames.add("Hyperlinks Space App.exe");
410+
altNames.add("HyperlinksSpaceApp.exe");
394411
}
395-
return null;
412+
413+
const matchesMainExe = (fileName) => {
414+
const lower = fileName.toLowerCase();
415+
for (const n of altNames) {
416+
if (lower === n.toLowerCase()) return true;
417+
}
418+
return false;
419+
};
420+
421+
/** Prefer shallowest match; skip common subtrees that are not the main exe. */
422+
const hits = [];
423+
const MAX_DEPTH = 6;
424+
const walk = (dir, depth) => {
425+
if (depth > MAX_DEPTH) return;
426+
let entries = [];
427+
try {
428+
entries = fs.readdirSync(dir, { withFileTypes: true });
429+
} catch (_) {
430+
return;
431+
}
432+
for (const ent of entries) {
433+
if (!ent.isFile()) continue;
434+
if (!/\.exe$/i.test(ent.name)) continue;
435+
if (matchesMainExe(ent.name)) hits.push({ root: dir, depth });
436+
}
437+
for (const ent of entries) {
438+
if (!ent.isDirectory()) continue;
439+
const n = ent.name.toLowerCase();
440+
if (n === "resources" || n === "locales") continue;
441+
walk(path.join(dir, ent.name), depth + 1);
442+
}
443+
};
444+
walk(extractDir, 0);
445+
if (hits.length === 0) return null;
446+
hits.sort((a, b) => a.depth - b.depth || a.root.length - b.root.length);
447+
return hits[0].root;
396448
}
397449

398450
/**
@@ -841,6 +893,7 @@ function setupAutoUpdater() {
841893
...partial,
842894
});
843895
};
896+
let versionsPrepareOk = false;
844897
try {
845898
const meta = await resolveWindowsZipSidecarMeta((u) => net.fetch(u), currentVersion);
846899
if (meta.version !== remoteV) {
@@ -909,7 +962,9 @@ function setupAutoUpdater() {
909962
percent: UNPACK_PROGRESS_LO,
910963
});
911964

912-
await extractPortableZipToDir(zipPath, extractDir, log, pushUi, UNPACK_PROGRESS_LO, UNPACK_PROGRESS_HI);
965+
await extractPortableZipToDir(zipPath, extractDir, log, pushUi, UNPACK_PROGRESS_LO, UNPACK_PROGRESS_HI, {
966+
verifyExeBase: exeBase,
967+
});
913968

914969
pushUi({ text: "Finalizing…", percent: 98 });
915970

@@ -936,9 +991,13 @@ function setupAutoUpdater() {
936991
}).show();
937992
} catch (_) {}
938993
}
994+
versionsPrepareOk = true;
939995
} catch (e) {
940-
logUpdater("prepare", `FAILED ${e?.message || e}`);
941-
log(`[updater] versions sidecar failed: ${e?.message || e}`);
996+
const errMsg = e?.message || e;
997+
const errStack = typeof e?.stack === "string" ? e.stack : "";
998+
logUpdater("prepare", `FAILED ${errMsg}`);
999+
log(`[updater] versions sidecar failed: ${errMsg}`);
1000+
if (errStack) log(`[updater] versions sidecar stack: ${errStack.split("\n").slice(0, 8).join(" | ")}`);
9421001
log(
9431002
`[updater] Ensure latest GitHub release includes latest.yml, ${WIN_PORTABLE_ZIP_PREFIX}<version>.zip (zip build), and optionally zip-latest.yml from cleanup for sha512.`,
9441003
);
@@ -960,7 +1019,12 @@ function setupAutoUpdater() {
9601019
}
9611020
} finally {
9621021
zipPrepareInFlight = false;
963-
logUpdater("prepare", "zipPrepareInFlight=false");
1022+
logUpdater(
1023+
"prepare",
1024+
versionsPrepareOk
1025+
? "zipPrepareInFlight=false (success)"
1026+
: "zipPrepareInFlight=false (incomplete — look for prepare FAILED above)",
1027+
);
9641028
}
9651029
};
9661030

0 commit comments

Comments
 (0)