better and simplified automatic update for macos

Massimo Melina committed Mar 4, 2026 at 23:55 UTC cc61fae0a093b234a09d6ad024721c066d9bdb94
2 files changed +9 -30
src/const.ts
-10
@@ -12,16 +12,6 @@ export * from './cross-const'
12 export const API_VERSION = 12.97
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 -export const ARGS_FILE = join(homedir(), 'hfs-args')
17 -try {
18 - const s = fs.readFileSync(ARGS_FILE, 'utf-8')
19 - console.log('additional arguments', s)
20 - _.defaults(argv, minimist(JSON.parse(s)))
21 - fs.unlinkSync(ARGS_FILE)
22 -}
23 -catch {}
24 -
15 export const DEV = process.env.DEV ? 'DEV' : ''
16 export const ORIGINAL_CWD = process.cwd()
17 export const HFS_STARTED = new Date()
src/update.ts
+9 -20
@@ -1,14 +1,13 @@
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 { ARGS_FILE, HFS_REPO, IS_BINARY, IS_WINDOWS, IS_MAC, PREVIOUS_TAG, RUNNING_BETA } from './const'
4 +import { HFS_REPO, IS_BINARY, IS_WINDOWS, 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, writeFileSync } from 'fs'
8 +import { createReadStream, existsSync, renameSync, unlinkSync } from 'fs'
9 import { pluginsWatcher } from './plugins'
10 import { chmod, rename, writeFile, rm } from 'fs/promises'
11 -import open from 'open'
11 import { currentVersion, defineConfig, versionToScalar } from './config'
12 import { cmdEscape, RUNNING_AS_SERVICE } from './util-os'
13 import { onProcessExit } from './first'
@@ -145,7 +144,7 @@ export async function update(tagOrUrl: string='') {
144 }
145 const bin = process.execPath
146 const binPath = dirname(bin)
148 - const binFile = 'hfs' + (IS_WINDOWS ? '.exe' : '') // currently running bin could have been renamed
147 + const binFile = 'hfs' + (IS_WINDOWS ? '.exe' : '') // the bin we are currently running could have been renamed
148 let newBinFile = binFile
149 do { newBinFile = 'new-' + newBinFile }
150 while (existsSync(join(binPath, newBinFile)))
@@ -194,22 +193,12 @@ if (argv.updating) { // we were launched with a temporary name, restore original
193 // have to relaunch with the new name, or otherwise the next update will fail with EBUSY on hfs.exe
194 console.log(`renamed binary file to "${argv.updating}" and now restarting`)
195 // if you change anything, be sure to test launching both double-clicking and in a terminal
197 - if (IS_WINDOWS) // windows-only; this method on Mac works only once, and without console
196 + if (IS_WINDOWS) // windows-only; this method on Mac works only once, and without the console
197 onProcessExit(() =>
199 - launch(dest, ['--updated', '--cwd .']) ) // launch+sync here would cause old process to stay open, locking ports
200 - else if (IS_MAC) {
201 - // open() is the only consistent way that I could find working on macos preserving console input/output over relaunching,
202 - // and it doesn't let us pass cli arguments, so we pass them through a temp file consumed at the next startup.
203 - // 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"
204 - try { writeFileSync(ARGS_FILE, JSON.stringify(['--updated', '--cwd', process.cwd().replaceAll(' ', '\\ ')])) }
205 - catch {}
206 - void open(dest)
207 - }
208 - else { // linux and other *nix
209 - if (process.stdin.isTTY && process.stdout.isTTY) // in interactive terminals, block this bridge process on the restarted hfs so the terminal session stays attached
210 - spawnSync(dest, ['--updated', '--cwd', process.cwd()], { stdio: [0, 1, 2] })
211 - else
212 - spawn(dest, ['--updated', '--cwd', process.cwd()], { detached: true, stdio: 'ignore' }).unref()
213 - }
198 + launch(dest, ['--updated', '--cwd .']) ) // launch+sync here would cause the old process to stay open, locking ports
199 + else if (process.stdin.isTTY && process.stdout.isTTY) // keep interactive terminal users attached to the restarted process
200 + spawnSync(dest, ['--updated', '--cwd', process.cwd()], { stdio: [0, 1, 2] })
201 + else
202 + spawn(dest, ['--updated', '--cwd', process.cwd()], { detached: true, stdio: 'ignore' }).unref()
203 process.exit()
204 }