fix: (regression beta) update on mac was no longer working
Massimo Melina committed
Mar 11, 2026 at 15:50 UTC
6f9d4984a0966ba3292ef8c90395d21abf3ef73f
2 files changed
+33
-7
src/const.ts
+14
@@ -12,6 +12,20 @@ export * from './cross-const'
12
export const API_VERSION = 13
13
export const COMPATIBLE_API_VERSION = 1 // the day we break with the past, we'll update this
14
15
+// you can add arguments with this file, currently used for the update process on mac/linux.
16
+// we are using homedir because it's the only stable path both the old and new process can agree on (open() doesn't preserve cwd)
17
+export const ARGS_FILE = join(homedir(), 'hfs-args')
18
+try {
19
+ const s = fs.readFileSync(ARGS_FILE, 'utf-8')
20
+ console.log('additional arguments', s)
21
+ _.defaults(argv, minimist(JSON.parse(s)))
22
+ fs.unlinkSync(ARGS_FILE)
23
+}
24
+catch(e: any) {
25
+ if (e?.code !== 'ENOENT')
26
+ console.error(ARGS_FILE, String(e))
27
+}
28
+
29
export const DEV = process.env.DEV ? 'DEV' : ''
30
export const ORIGINAL_CWD = process.cwd()
31
export const HFS_STARTED = new Date()
src/update.ts
+19
-7
@@ -1,13 +1,14 @@
1
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
import { apiGithubPaginated, getProjectInfo, getRepoInfo } from './github'
4
-import { HFS_REPO, IS_BINARY, IS_WINDOWS, PREVIOUS_TAG, RUNNING_BETA } from './const'
4
+import { ARGS_FILE, HFS_REPO, IS_BINARY, IS_WINDOWS, IS_MAC, PREVIOUS_TAG, RUNNING_BETA } from './const'
5
import { dirname, join } from 'path'
6
import { spawn, spawnSync } from 'child_process'
7
import { DAY, exists, debounceAsync, unzip, prefix, xlate, HOUR, httpStream, statWithTimeout } from './misc'
8
-import { createReadStream, existsSync, renameSync, unlinkSync } from 'fs'
8
+import { createReadStream, existsSync, renameSync, unlinkSync, writeFileSync } from 'fs'
9
import { pluginsWatcher } from './plugins'
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'
14
import { onProcessExit } from './first'
@@ -189,12 +190,23 @@ if (argv.updating) { // we were launched with a temporary name, restore original
190
// have to relaunch with the new name, or otherwise the next update will fail with EBUSY on hfs.exe
191
console.log(`renamed binary file to "${argv.updating}" and now restarting`)
192
// if you change anything, be sure to test launching both double-clicking and in a terminal
192
- if (IS_WINDOWS) // windows-only; this method on Mac works only once, and without the console
193
+ if (IS_WINDOWS) // windows-only; this method on mac+linux works only once, and without the console
194
onProcessExit(() =>
195
spawn(cmdEscape(dest), ['--updated', '--cwd .'], { detached: true, shell: true, stdio: [0,1,2] }) ) // launch+sync here would cause the old process to stay open, locking ports
195
- else if (process.stdin.isTTY && process.stdout.isTTY) // keep interactive terminal users attached to the restarted process
196
- spawnSync(dest, ['--updated', '--cwd', process.cwd()], { stdio: [0, 1, 2] })
197
- else
198
- spawn(dest, ['--updated', '--cwd', process.cwd()], { detached: true, stdio: 'ignore' }).unref()
196
+ else if (IS_MAC) {
197
+ // open() is the only consistent way that I could find working on macos preserving console input/output over relaunching,
198
+ // and it doesn't let us pass cli arguments, so we pass them through a temp file consumed at the next startup.
199
+ // For the record, on mac you can: write "./hfs arg1 arg2" to /tmp/tmp.sh with 0o700, and then spawn "open -a Terminal /tmp/tmp.sh"
200
+ try { writeFileSync(ARGS_FILE, JSON.stringify(['--updated', '--cwd', process.cwd()])) }
201
+ catch {}
202
+ console.log('open-ing')
203
+ void open(dest)
204
+ }
205
+ else { // linux and other *nix
206
+ if (process.stdin.isTTY && process.stdout.isTTY) // in interactive terminals, block this bridge process on the restarted hfs so the terminal session stays attached
207
+ spawnSync(dest, ['--updated', '--cwd', process.cwd()], { stdio: [0, 1, 2] })
208
+ else
209
+ spawn(dest, ['--updated', '--cwd', process.cwd()], { detached: true, stdio: 'ignore' }).unref()
210
+ }
211
process.exit()
212
}