Compare commits
2 commits
9a1202f0fc
...
e794f241ba
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e794f241ba | ||
|
|
1f001dc306 |
4 changed files with 32 additions and 8 deletions
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "folio",
|
"name": "folio",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "folio",
|
"name": "folio",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tiptap/core": "^2.27.2",
|
"@tiptap/core": "^2.27.2",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "folio",
|
"name": "folio",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"description": "A simple, local, open-source desktop writing app.",
|
"description": "A simple, local, open-source desktop writing app.",
|
||||||
"productName": "Folio",
|
"productName": "Folio",
|
||||||
"author": "Folio Contributors",
|
"author": "Folio Contributors",
|
||||||
|
|
|
||||||
|
|
@ -1254,6 +1254,9 @@ handleIpc("folio:performUpdate", async () => {
|
||||||
app.getPath("temp"),
|
app.getPath("temp"),
|
||||||
`folio-update-${process.pid}.sh`
|
`folio-update-${process.pid}.sh`
|
||||||
);
|
);
|
||||||
|
// Persistent, append-only handoff log: survives the swap and tells us
|
||||||
|
// exactly where a failed update stopped (temp files can vanish).
|
||||||
|
const updateLog = path.join(app.getPath("userData"), "update.log");
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
script,
|
script,
|
||||||
buildInstallerScript({
|
buildInstallerScript({
|
||||||
|
|
@ -1261,6 +1264,7 @@ handleIpc("folio:performUpdate", async () => {
|
||||||
tarball,
|
tarball,
|
||||||
installDir: cfg.installDir,
|
installDir: cfg.installDir,
|
||||||
relaunch: cfg.launcher,
|
relaunch: cfg.launcher,
|
||||||
|
log: updateLog,
|
||||||
}),
|
}),
|
||||||
{ mode: 0o700 }
|
{ mode: 0o700 }
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,8 @@ export interface InstallerSpec {
|
||||||
tarball: string;
|
tarball: string;
|
||||||
installDir: string;
|
installDir: string;
|
||||||
relaunch: string;
|
relaunch: string;
|
||||||
|
/** Optional append-only log; the script narrates every step into it. */
|
||||||
|
log?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The handoff script. Deliberately forgiving (no set -e): on any failure it
|
// The handoff script. Deliberately forgiving (no set -e): on any failure it
|
||||||
|
|
@ -170,7 +172,10 @@ export interface InstallerSpec {
|
||||||
// user without an app. The old tree is kept as .old.<pid> and pruned only
|
// user without an app. The old tree is kept as .old.<pid> and pruned only
|
||||||
// after a successful swap.
|
// after a successful swap.
|
||||||
export function buildInstallerScript(spec: InstallerSpec): string {
|
export function buildInstallerScript(spec: InstallerSpec): string {
|
||||||
const { pid, tarball, installDir, relaunch } = spec;
|
const { pid, tarball, installDir, relaunch, log } = spec;
|
||||||
|
const logLine = log
|
||||||
|
? `say() { echo "$(date '+%F %T') $*" >> ${shQuote(log)} 2>/dev/null; }`
|
||||||
|
: "say() { :; }";
|
||||||
return [
|
return [
|
||||||
"#!/bin/sh",
|
"#!/bin/sh",
|
||||||
"# Folio updater — waits for the app to exit, swaps in the new version,",
|
"# Folio updater — waits for the app to exit, swaps in the new version,",
|
||||||
|
|
@ -181,29 +186,44 @@ export function buildInstallerScript(spec: InstallerSpec): string {
|
||||||
`RELAUNCH=${shQuote(relaunch)}`,
|
`RELAUNCH=${shQuote(relaunch)}`,
|
||||||
`NEW="$INSTALL.update-new.$$"`,
|
`NEW="$INSTALL.update-new.$$"`,
|
||||||
`OLD="$INSTALL.old.$$"`,
|
`OLD="$INSTALL.old.$$"`,
|
||||||
|
logLine,
|
||||||
|
'say "handoff start pid=$PID tarball=$TARBALL"',
|
||||||
"# Wait (bounded to ~2 minutes) for the app process to exit.",
|
"# Wait (bounded to ~2 minutes) for the app process to exit.",
|
||||||
"i=0",
|
"i=0",
|
||||||
'while [ "$PID" -gt 0 ] 2>/dev/null && kill -0 "$PID" 2>/dev/null && [ "$i" -lt 400 ]; do sleep 0.3; i=$((i+1)); done',
|
'while [ "$PID" -gt 0 ] 2>/dev/null && kill -0 "$PID" 2>/dev/null && [ "$i" -lt 400 ]; do sleep 0.3; i=$((i+1)); done',
|
||||||
|
'kill -0 "$PID" 2>/dev/null && say "WARN: app still alive after wait window" || say "app exited after ${i} polls"',
|
||||||
'rm -rf "$NEW"',
|
'rm -rf "$NEW"',
|
||||||
'mkdir -p "$NEW"',
|
'mkdir -p "$NEW" || { say "FAIL: mkdir $NEW"; "$RELAUNCH" >/dev/null 2>&1 & exit 1; }',
|
||||||
'if tar -xzf "$TARBALL" -C "$NEW"; then',
|
'if tar -xzf "$TARBALL" -C "$NEW"; then',
|
||||||
' # electron-builder nests everything under a top-level dir; flatten it.',
|
' say "extracted ok"',
|
||||||
|
' # electron-builder nests everything under a top-level dir; flatten it',
|
||||||
|
" # by adopting the nested dir itself (mv of the dir, not a glob — globs",
|
||||||
|
" # miss dotfiles and a partial mv leaves a broken tree).",
|
||||||
' if [ ! -e "$NEW/folio" ]; then',
|
' if [ ! -e "$NEW/folio" ]; then',
|
||||||
' ONLY=$(find "$NEW" -mindepth 1 -maxdepth 1 -type d | head -n 1)',
|
' ONLY=$(find "$NEW" -mindepth 1 -maxdepth 1 -type d | head -n 1)',
|
||||||
' [ -n "$ONLY" ] && mv "$ONLY"/* "$NEW"/ 2>/dev/null',
|
' REST=$(find "$NEW" -mindepth 1 -maxdepth 1 | wc -l)',
|
||||||
|
' if [ -n "$ONLY" ] && [ "$REST" -eq 1 ]; then',
|
||||||
|
' mv "$ONLY" "$NEW.new" && rm -rf "$NEW" && mv "$NEW.new" "$NEW" && say "flattened nested dir"',
|
||||||
" fi",
|
" fi",
|
||||||
|
" fi",
|
||||||
|
"else",
|
||||||
|
' say "FAIL: tar extract failed"',
|
||||||
"fi",
|
"fi",
|
||||||
'if [ -x "$NEW/folio" ]; then',
|
'if [ -x "$NEW/folio" ]; then',
|
||||||
' [ -e "$INSTALL" ] && mv "$INSTALL" "$OLD"',
|
' [ -e "$INSTALL" ] && mv "$INSTALL" "$OLD" && say "moved old install aside"',
|
||||||
' if mv "$NEW" "$INSTALL"; then',
|
' if mv "$NEW" "$INSTALL"; then',
|
||||||
|
' say "SWAP OK — new version installed"',
|
||||||
' rm -rf "$OLD" "$INSTALL.update-new".* "$INSTALL.old".* 2>/dev/null',
|
' rm -rf "$OLD" "$INSTALL.update-new".* "$INSTALL.old".* 2>/dev/null',
|
||||||
' rm -f "$TARBALL"',
|
' rm -f "$TARBALL"',
|
||||||
" else",
|
" else",
|
||||||
|
' say "FAIL: mv NEW->INSTALL; restoring old"',
|
||||||
' [ -e "$OLD" ] && mv "$OLD" "$INSTALL"',
|
' [ -e "$OLD" ] && mv "$OLD" "$INSTALL"',
|
||||||
" fi",
|
" fi",
|
||||||
"else",
|
"else",
|
||||||
|
' say "FAIL: no executable at $NEW/folio; keeping old install"',
|
||||||
' rm -rf "$NEW"',
|
' rm -rf "$NEW"',
|
||||||
"fi",
|
"fi",
|
||||||
|
'say "relaunching"',
|
||||||
'"$RELAUNCH" >/dev/null 2>&1 &',
|
'"$RELAUNCH" >/dev/null 2>&1 &',
|
||||||
"",
|
"",
|
||||||
].join("\n");
|
].join("\n");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue