@samitouri / QOSami-HFS / commits / 5d85bdaa

harden code: error in case of bad zip on update

Massimo Melina committed Dec 12, 2025 at 23:56 UTC 5d85bdaa68f6558035b96585d834ba1f99bab4bf
3 files changed +11 -6
src/github.ts
+1 -1
@@ -139,7 +139,7 @@ export async function downloadPlugin(repo: Repo, { branch='', overwrite=false }=
139 if (wasRunning)
140 if (await waitFor(() => getPluginInfo(folder), { timeout: 10_000 }))
141 void startPlugin(folder) // don't wait, in case it fails to start. We still use startPlugin instead of enablePlugin, as it will take care of disabling other themes.
142 - .catch(console.warn)
142 + .catch(e => console.warn(String(e)))
143 events.emit('pluginDownloaded', { id: folder, repo })
144 return folder
145 }
src/update.ts
+9 -4
@@ -7,7 +7,7 @@ import { spawn, spawnSync } from 'child_process'
7 import { DAY, exists, debounceAsync, unzip, prefix, xlate, HOUR, httpWithBody, statWithTimeout } from './misc'
8 import { createReadStream, existsSync, renameSync, unlinkSync, writeFileSync } from 'fs'
9 import { pluginsWatcher } from './plugins'
10 -import { chmod, rename, writeFile } from 'fs/promises'
10 +import { chmod, rename, writeFile, rm } from 'fs/promises'
11 import open from 'open'
12 import { currentVersion, defineConfig, versionToScalar } from './config'
13 import { cmdEscape, RUNNING_AS_SERVICE } from './util-os'
@@ -150,12 +150,17 @@ export async function update(tagOrUrl: string='') {
150 await unzip(createReadStream(LOCAL_UPDATE), path =>
151 join(binPath, path === binFile ? newBinFile : path))
152 const newBin = join(binPath, newBinFile)
153 + if (!existsSync(newBin)) {
154 + if (url) // the file was downloaded, and the UI would show the "update from local file" button until we remove it
155 + await rm(LOCAL_UPDATE).catch(e => console.warn(String(e)))
156 + throw "Missing executable in the archive"
157 + }
158 if (!IS_WINDOWS) {
159 const { mode } = await statWithTimeout(bin)
160 await chmod(newBin, mode).catch(console.error)
161 }
162 await rename(INSTALLED_FN, PREVIOUS_FN).catch(e => e?.code !== 'ENOENT' && console.warn(String(e)))
158 - await rename(LOCAL_UPDATE, INSTALLED_FN).catch(console.warn)
163 + await rename(LOCAL_UPDATE, INSTALLED_FN).catch(e => console.warn(String(e)))
164 onProcessExit(() => {
165 const oldBinFile = 'old-' + binFile
166 const oldBin = join(binPath, oldBinFile)
@@ -182,8 +187,8 @@ if (argv.updating) { // we were launched with a temporary name, restore original
187 const bin = process.execPath
188 const dest = join(dirname(bin), argv.updating)
189 renameSync(bin, dest)
185 - // have to relaunch with new name, or otherwise next update will fail with EBUSY on hfs.exe
186 - console.log("renamed binary file to", argv.updating, "and restarting")
190 + // have to relaunch with the new name, or otherwise next update will fail with EBUSY on hfs.exe
191 + console.log(`renamed binary file to "${argv.updating}" and now restarting`)
192 // be sure to test launching both double-clicking and in a terminal
193 if (IS_WINDOWS) // this method on Mac works only once, and without console
194 onProcessExit(() =>
src/upload.ts
+1 -1
@@ -186,7 +186,7 @@ export function uploadWriter(base: VfsNode, baseUri: string, path: string, ctx:
186 let dest = fullPath // final destination, considering numbering if necessary
187 if (dontOverwriteUploading.get() && !await overwriteAnyway() && fs.existsSync(dest)) {
188 if (overwriteRequestedButForbidden) {
189 - await rm(tempName).catch(console.warn)
189 + await rm(tempName).catch(e => console.warn(String(e)))
190 releaseFile()
191 return fail() // status code set by overwriteAnyway
192 }