This repository has been archived by the owner on Dec 13, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ✨ Add self updating for standalone executable
Copied from eea905e3fe9a7b1507af0fac27939e73417db76a of meiszwflz/LemLink
- Loading branch information
Showing
4 changed files
with
140 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"standalone": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,20 @@ | ||
var argv = require('yargs/yargs')(process.argv.slice(2)).argv; | ||
import yargs from "yargs"; | ||
import { standalone } from "../config.json"; | ||
import { SelfUpdateUtility } from "./update"; | ||
|
||
if (argv.ships > 3 && argv.distance < 53.5) { | ||
console.log('Plunder more riffiwobbles!'); | ||
} else { | ||
console.log('Retreat from the xupptumblers!'); | ||
} | ||
if (standalone) SelfUpdateUtility.init(); | ||
|
||
yargs(process.argv.slice(2)).command( | ||
"update", | ||
"update", | ||
{ | ||
url: { | ||
alias: "u", | ||
describe: "the URL to download the new executable from", | ||
}, | ||
}, | ||
async (argv) => { | ||
if (typeof argv.url === "string") | ||
await SelfUpdateUtility.get().updateCLI(argv.url); | ||
}, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { renameSync, unlinkSync, createWriteStream, existsSync } from "fs"; | ||
import child_process = require("child_process"); | ||
import { get as httpGet, type IncomingMessage } from "http"; | ||
import { standalone } from "../config.json"; | ||
|
||
/** | ||
* self updates the cli executable | ||
* @warning DO NOT USE THIS IF NOT PART OF STANDALONE EXECUTABLE | ||
*/ | ||
export class SelfUpdateUtility { | ||
/** | ||
* So how the heck does this CLI update itself? | ||
* | ||
* 1. Attempt to download new executable from downloadUrl to newPath | ||
* 2. Rename current executable to oldPath | ||
* 3. Rename newly downloaded executable to filePath | ||
* 4. On startup of the cli, we attempt to remove oldPath | ||
*/ | ||
|
||
protected readonly filePath: string; // normal executable path | ||
protected readonly newPath: string; // the new executable that will be downloaded | ||
protected readonly oldPath: string; | ||
|
||
private static singleton?: SelfUpdateUtility; | ||
/** | ||
* self updates the cli executable | ||
* @warning DO NOT USE THIS IF NOT PART OF STANDALONE EXECUTABLE | ||
*/ | ||
private constructor() { | ||
if (!standalone) | ||
throw new Error( | ||
"LemLink is not part of a standalone executable, and thus cannot self update", | ||
); | ||
const nodeExecutablePath = process.env._; | ||
if (nodeExecutablePath === undefined) { | ||
throw new Error("Could not find node executable path"); | ||
} | ||
|
||
this.filePath = nodeExecutablePath; | ||
this.newPath = this.filePath + "-new"; | ||
this.oldPath = this.filePath + "-old"; | ||
|
||
this.attemptToDeleteOldPathFile(); | ||
} | ||
|
||
/** | ||
* Should be run at the start of CLI program | ||
*/ | ||
public static init(): void { | ||
if (this.singleton !== undefined) { | ||
console.error( | ||
"Self Update Utility has already been initialized, canceling init..", | ||
); | ||
return; | ||
} | ||
this.singleton = new SelfUpdateUtility(); | ||
} | ||
|
||
public static get(): SelfUpdateUtility { | ||
if (this.singleton === undefined) | ||
throw new Error( | ||
"Self Update Utility was not initialized at the start of CLI program!!", | ||
); | ||
return this.singleton; | ||
} | ||
|
||
/** | ||
* @returns true if oldPath exists, false if otherwise | ||
*/ | ||
private attemptToDeleteOldPathFile(): boolean { | ||
if (existsSync(this.oldPath)) { | ||
unlinkSync(this.oldPath); | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* Replaces the current CLI executable with the one found at {@link downloadUrl} | ||
* @param downloadUrl url from which a new executable should be downloaded | ||
*/ | ||
public async updateCLI(downloadUrl: string): Promise<void> { | ||
/** | ||
* See top of this file for info on how this works | ||
*/ | ||
console.log("Downloading new file..."); | ||
const fileStream = createWriteStream(this.newPath); | ||
|
||
const response = await new Promise<IncomingMessage>((resolve) => | ||
httpGet(downloadUrl, resolve), | ||
); | ||
|
||
response.pipe(fileStream); | ||
await new Promise((resolve) => fileStream.on("finish", resolve)); | ||
fileStream.close(); | ||
|
||
console.log("File downloaded successfully."); | ||
|
||
console.log("Replacing current file..."); | ||
renameSync(this.filePath, this.oldPath); | ||
renameSync(this.newPath, this.filePath); | ||
console.log("Replaced current file successfully!"); | ||
|
||
console.log("Restarting..."); | ||
child_process.spawn( | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
process.argv.shift()!, | ||
process.argv, | ||
{ | ||
cwd: process.cwd(), | ||
detached: true, | ||
stdio: "inherit", | ||
shell: true, | ||
}, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters