This repository was archived by the owner on Feb 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 674
feat: add a detach mode to the CLI
#3568
Merged
Merged
Changes from 1 commit
Commits
Show all changes
71 commits
Select commit
Hold shift + click to select a range
fcc4228
feat: allow users to specify a option, which causes Ganache to start…
jeffsmale90 7a787f2
Stream stderr from the child to the parent
jeffsmale90 301c500
Tidy up of --detach argument parsing
jeffsmale90 7dec4c0
Improve detach configuration
jeffsmale90 9ed54db
Add tests for parsing detach arguments. Change default value to false…
jeffsmale90 20579ae
Make parent aware of detached instances, and allow stopping them via cli
jeffsmale90 1da7911
improve args tests, remove placeholder
jeffsmale90 9cc5b59
Implement , and allow different actions to be executed via the CLI
jeffsmale90 e5d7e60
Clean up orphaned instance process files. uses a terrible hack to fet…
jeffsmale90 295b1a3
Implement `instances` command with subcommands. Clean up orphaned ins…
jeffsmale90 75ffbb0
Tidy up args types and parsing
jeffsmale90 17732d7
Refactor, add flavor to instance data, and to list output. Change ins…
jeffsmale90 dea1ddb
Fix createFlatChildArgs import in args.test.ts
jeffsmale90 07a4b03
Merge branch 'develop' into feat/detach-mode
jeffsmale90 a74d0a3
Update package-lock.json files - required for new deps
jeffsmale90 1eaea51
Fix module resolution
jeffsmale90 cba7589
Tidy ups and refactors
jeffsmale90 c39cae6
Tidy up arg parsing
jeffsmale90 bc61cb1
Revert package-lock.json files
jeffsmale90 f5650f2
Fix miss-typed action name
jeffsmale90 90a2305
Remove dependency on ps-list, move data files to Ganache/instances, i…
jeffsmale90 c1e5f43
Remove kebab-case names when expanding arguments. Add tests for expan…
jeffsmale90 757220b
Reintroduce ps-list, only list instances where the process co
jeffsmale90 c432c35
Move createFlatChildArgs() to detach.ts, add version to list, ensure …
jeffsmale90 2dec992
Create instances directory recursively, because now it's
jeffsmale90 773f21a
Tidy ups from code review, add section on Detached mode to README.
jeffsmale90 5fb72d1
Fix incorrect command name in README.md
jeffsmale90 9bf6064
Merge branch 'develop' into feat/detach-mode
jeffsmale90 d27e6bc
Update to use @trufflesuite/ps-list instead of ps-list
jeffsmale90 eafc679
If no instances are found, using , print a friendly message instead o…
jeffsmale90 e6ae996
Revert ganache package version to match develop
jeffsmale90 eb14694
Merge branch 'develop' into feat/detach-mode
jeffsmale90 876b972
Bump @trufflesuite/ps-list to include support for node 12
jeffsmale90 208b149
upgrade @trufflesuite/ps-list to support nodejs < 12.17.0
jeffsmale90 5f4b80d
Merge branch 'develop' into feat/detach-mode
jeffsmale90 6b61cba
Improve wording of `--detach` description in README.md
jeffsmale90 7f36f1f
Switched out for (existing dependency via marked-terminal)
jeffsmale90 ac5aba0
Move instance list sorting to the consumer that needs the list sorted
jeffsmale90 bfc5cf9
use detached instance friendly name for instance file (instead of pid)
jeffsmale90 1a52d4c
pass original process.args to startDetachedInstance, calculate expect…
jeffsmale90 7a4c256
Fix 'cmd' argument for win32 platform
jeffsmale90 67d11fc
Add attribution for duration formatter
jeffsmale90 683c201
Change all detach mode file access to async
jeffsmale90 60ae164
Adds warning messages if instances removed
jeffsmale90 1726ec9
Add PID to warning message.
jeffsmale90 0811874
Remove unnecessary detach.test.ts
jeffsmale90 485ff64
improvements / refactor as per pr review.
jeffsmale90 1701140
Don't check for existence of the folder each time - just catch the Er…
jeffsmale90 78a9d0c
Accidentally recreated the instance name twice
jeffsmale90 04719a6
Move comment to relevant code
jeffsmale90 3ea9968
Improvements to detach re PR
jeffsmale90 6a7f3b3
Revert package-lock.json
jeffsmale90 c5c0c31
_Actually_ fix package-lock.json this time
jeffsmale90 bc8d269
Remove nyc dev-dependency from cli/package.json - correct, but irrele…
jeffsmale90 aa72840
Strip the detach argument correctly before passing arguments to child…
jeffsmale90 4e8f933
Add tests for duration formatting - move implementation into detach.ts
jeffsmale90 6b49cbb
Rename formatDuration to formatUptime, add --detach example to README…
jeffsmale90 0435951
Revert shrinkwrap :/
jeffsmale90 959c6dc
Pin cli-table dependency to latest release
jeffsmale90 dfb8b72
Fix failing test
jeffsmale90 c495cc9
Improve duration formatting, improve readme
jeffsmale90 c16cb20
Annoyingly, args parsing is complicated. Don't try to strip out the d…
jeffsmale90 b272237
Instance files now have .json extension. Remove any files / folders f…
jeffsmale90 c85d022
Remove unused import
jeffsmale90 359cb6b
Handle errors betterer
jeffsmale90 f94442f
Shorten duration formatting, combine host and port, right align PID i…
jeffsmale90 26af55e
RH align Uptime
jeffsmale90 d717d3f
remove unnecessary type assertion, remove datapath suffix
jeffsmale90 393702c
Use unlink instead of rm, because node 12
jeffsmale90 0507aa4
Support ndoe 12 correctly for removal of files and directories
jeffsmale90 2d92da1
Make PowerShell example consistent with non-Windows example
jeffsmale90 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
This file contains hidden or 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
This file contains hidden or 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,167 @@ | ||
| import { fork } from "child_process"; | ||
| import createProcessName from "./process-name"; | ||
| import envPaths from "env-paths"; | ||
| import { | ||
| existsSync, | ||
| mkdirSync, | ||
| rmSync, | ||
| writeFileSync, | ||
| readdirSync, | ||
| readFileSync | ||
| } from "fs"; | ||
| import path from "path"; | ||
|
|
||
| export type DetachedInstance = { | ||
| friendlyName: string; | ||
| pid: number; | ||
| startTime: number; | ||
| }; | ||
|
|
||
| const dataPath = envPaths(`ganache`).data; | ||
|
jeffsmale90 marked this conversation as resolved.
Outdated
|
||
| if (!existsSync(dataPath)) mkdirSync(dataPath); | ||
|
|
||
| const READY_MESSAGE = "ready"; | ||
|
|
||
| /** | ||
| * Notify that the detached instance has started and is ready to receive requests. | ||
| */ | ||
| export function notifyDetachedInstanceReady() { | ||
| // in "detach" mode, the parent will wait until the "ready" message is | ||
| // received before disconnecting from the child process. | ||
| process.send(READY_MESSAGE); | ||
| } | ||
|
|
||
| /** | ||
| * Attempt to find and remove the instance file for a detached instance. | ||
| * @param {number} pid the pid of the detached instance | ||
| * @returns boolean indicating whether the instance file was cleaned up successfully | ||
| */ | ||
| export function cleanupDetachedInstanceFile(pid: number): boolean { | ||
| const instanceFilename = `${dataPath}/${pid}`; | ||
| if (existsSync(instanceFilename)) { | ||
| rmSync(instanceFilename); | ||
|
davidmurdoch marked this conversation as resolved.
Outdated
|
||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Register a new detached instance. Creates an instance file containing | ||
| * information about the instance. | ||
| * @param {DetachedInstance} instance | ||
| */ | ||
| function registerDetachedInstance(instance: DetachedInstance) { | ||
| const instanceFilename = `${dataPath}/${instance.pid}`; | ||
|
|
||
| writeFileSync( | ||
| instanceFilename, | ||
| `${instance.friendlyName}|${instance.startTime}` | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Attempts to stop a detached instance with the specified instance name by | ||
| * sending a SIGTERM signal. Returns a boolean indicating whether the process | ||
| * was found. If the PID is identified, but the process is not found, any | ||
| * corresponding instance file will be removed. | ||
| * | ||
| * Note: This does not guarantee that the instance actually stops. | ||
| * @param {string} instanceName | ||
|
davidmurdoch marked this conversation as resolved.
|
||
| * @returns boolean indicating whether the instance was found. | ||
| */ | ||
| export function stopDetachedInstance(instanceName: string): boolean { | ||
| const instance = findInstanceByName(instanceName); | ||
|
|
||
| if (instance) { | ||
| try { | ||
| process.kill(instance.pid, "SIGTERM"); | ||
|
MicaiahReid marked this conversation as resolved.
Outdated
|
||
| } catch (err) { | ||
| // process.kill throws if the process was not found (or was a group process in Windows) | ||
| cleanupDetachedInstanceFile(instance.pid); | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Start an instance of Ganache in detached mode. | ||
| * @param {string[]} argv arguments to be passed to the new instance. | ||
| * @returns {Promise<DetachedInstance>} resolves to the DetachedInstance once it | ||
| * is started and ready to receive requests. | ||
| */ | ||
| export async function startDetachedInstance( | ||
| argv: string[] | ||
| ): Promise<DetachedInstance> { | ||
| const module = argv[1]; | ||
| const args = argv.slice(1).splice(argv.indexOf("--detach"), 1); | ||
|
|
||
| const child = fork(module, args, { | ||
| stdio: ["ignore", "ignore", "pipe", "ipc"], | ||
| detached: true | ||
| }); | ||
|
|
||
| // Any messages output to stderr by the child process (before the `ready` | ||
| // event is emitted) will be streamed to stderr on the parent. | ||
| child.stderr.pipe(process.stderr); | ||
|
|
||
| let friendlyName: string; | ||
| do { | ||
| friendlyName = createProcessName(); | ||
| } while (findInstanceByName(friendlyName)); | ||
|
|
||
| await new Promise<void>((resolve, reject) => { | ||
| child.on("message", message => { | ||
| if (message === READY_MESSAGE) { | ||
| resolve(); | ||
| } | ||
| }); | ||
|
|
||
| child.on("error", err => { | ||
| // This only happens if there's an error starting the child process, not if | ||
| // the application throws within the child process. | ||
| reject(err); | ||
| }); | ||
|
|
||
| child.on("exit", (code: number) => { | ||
| // If the child process exits before the parent, something has gone wrong, | ||
| // so let the user know (even if the exit code is 0). | ||
| reject(new Error(`The child process exited with code ${code}`)); | ||
| }); | ||
| }); | ||
|
|
||
| // destroy the ReadableStream exposed by the child process, to allow the | ||
| // parent to exit gracefully. | ||
| child.stderr.destroy(); | ||
| child.unref(); | ||
| child.disconnect(); | ||
|
|
||
| const instance = { | ||
| startTime: Date.now(), | ||
| pid: child.pid, | ||
| friendlyName | ||
| }; | ||
|
|
||
| registerDetachedInstance(instance); | ||
|
|
||
| return instance; | ||
| } | ||
|
|
||
| function findInstanceByName( | ||
| friendlyName: string | ||
| ): DetachedInstance | undefined { | ||
| const files = readdirSync(dataPath); | ||
|
davidmurdoch marked this conversation as resolved.
Outdated
|
||
| for (let i = 0; i < files.length; i++) { | ||
| const filepath = path.join(dataPath, files[i]); | ||
| const content = readFileSync(filepath).toString("utf8"); | ||
| const [name, startTime] = content.split("|"); | ||
| if (name === friendlyName) { | ||
| return { | ||
| friendlyName, | ||
| pid: parseInt(files[i]), | ||
| startTime: parseInt(startTime) | ||
| }; | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or 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,83 @@ | ||
| export default function createFriendlyName() { | ||
| const name = [...Array(3)].map((_, i) => { | ||
| const partSource = nameParts[i]; | ||
| const partIndex = Math.floor(Math.random() * partSource.length); | ||
| return partSource[partIndex]; | ||
| }); | ||
|
|
||
| return name.join("-"); | ||
| } | ||
|
|
||
| const adjectives = [ | ||
| "baked", | ||
| "candied", | ||
| "deepfried", | ||
| "frozen", | ||
| "hot", | ||
| "molten", | ||
| "pureed", | ||
| "salted", | ||
| "spiced", | ||
| "sticky" | ||
| ]; | ||
| const flavours = [ | ||
|
jeffsmale90 marked this conversation as resolved.
Outdated
|
||
| "almond", | ||
| "apple", | ||
| "banana", | ||
| "blackforest", | ||
| "caramel", | ||
| "cherry", | ||
| "chocolate", | ||
| "cinnamon", | ||
| "coconut", | ||
| "coffee", | ||
| "cream", | ||
| "custard", | ||
| "fruit", | ||
| "ginger", | ||
| "gingerbread", | ||
| "jelly", | ||
| "lemon", | ||
| "lime", | ||
| "milk", | ||
| "nut", | ||
| "orange", | ||
| "peanut", | ||
| "plum", | ||
| "poppy-seed", | ||
| "rhubarb", | ||
| "strawberry", | ||
| "sugar", | ||
| "tiramisu" | ||
| ]; | ||
| const kinds = [ | ||
| "bar", | ||
| "biscuit", | ||
| "brownie", | ||
| "cake", | ||
| "cheesecake", | ||
| "cookie", | ||
| "crumble", | ||
| "cupcake", | ||
| "doughnut", | ||
| "drizzle", | ||
| "dumpling", | ||
| "friand", | ||
| "ganache", | ||
| "loaf", | ||
| "macaroon", | ||
| "mousse", | ||
| "muffin", | ||
| "pastry", | ||
| "pie", | ||
| "pudding", | ||
| "sponge", | ||
| "strudel", | ||
| "tart", | ||
| "torte", | ||
| "trifle", | ||
| "truffle", | ||
| "waffle" | ||
| ]; | ||
|
|
||
| const nameParts = [adjectives, flavours, kinds]; | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.