-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #165 from bluecadet/feat/cli
add CLI package
- Loading branch information
Showing
43 changed files
with
2,601 additions
and
2,288 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,10 @@ | ||
--- | ||
"@bluecadet/launchpad": major | ||
"@bluecadet/launchpad-scaffold": major | ||
"@bluecadet/launchpad-content": major | ||
"@bluecadet/launchpad-monitor": major | ||
"@bluecadet/launchpad-utils": major | ||
"@bluecadet/launchpad-cli": major | ||
--- | ||
|
||
Move CLI to separate package |
Large diffs are not rendered by default.
Oops, something went wrong.
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 |
---|---|---|
|
@@ -37,4 +37,4 @@ | |
"engines": { | ||
"node": ">=18" | ||
} | ||
} | ||
} |
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,48 @@ | ||
#!/usr/bin/env node | ||
|
||
import yargs from 'yargs'; | ||
import { hideBin } from 'yargs/helpers'; | ||
export { defineConfig } from './launchpad-options.js'; | ||
|
||
/** | ||
* @typedef LaunchpadArgv | ||
* @property {string} [config] | ||
* @property {(string | number)[]} [env] | ||
* @property {string} [envCascade] | ||
*/ | ||
|
||
yargs(hideBin(process.argv)) | ||
.parserConfiguration({ | ||
// See https://github.com/yargs/yargs-parser#camel-case-expansion | ||
'camel-case-expansion': false | ||
}) | ||
.option('config', { alias: 'c', describe: 'Path to your JS config file', type: 'string' }) | ||
.option('env', { alias: 'e', describe: 'Path(s) to your .env file(s)', type: 'array' }) | ||
.option('env-cascade', { alias: 'E', describe: 'cascade env variables from `.env`, `.env.<arg>`, `.env.local`, `.env.<arg>.local` in launchpad root dir', type: 'string' }) | ||
.command('start', 'Starts launchpad by updating content and starting apps.', async ({ argv }) => { | ||
const resolvedArgv = await argv; | ||
const { start } = await import('./commands/start.js'); | ||
await start(resolvedArgv); | ||
}) | ||
.command('stop', 'Stops launchpad by stopping apps and killing any existing PM2 instance.', async ({ argv }) => { | ||
const resolvedArgv = await argv; | ||
const { stop } = await import('./commands/stop.js'); | ||
await stop(resolvedArgv); | ||
}) | ||
.command('content', 'Only download content.', async ({ argv }) => { | ||
const resolvedArgv = await argv; | ||
const { content } = await import('./commands/content.js'); | ||
await content(resolvedArgv); | ||
}) | ||
.command('monitor', 'Only start apps.', async ({ argv }) => { | ||
const resolvedArgv = await argv; | ||
const { monitor } = await import('./commands/monitor.js'); | ||
await monitor(resolvedArgv); | ||
}) | ||
.command('scaffold', 'Configures the current PC for exhibit environments (with admin prompt).', async ({ argv }) => { | ||
const resolvedArgv = await argv; | ||
const { scaffold } = await import('./commands/scaffold.js'); | ||
await scaffold(resolvedArgv); | ||
}) | ||
.help() | ||
.parse(); |
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,26 @@ | ||
import { ResultAsync } from 'neverthrow'; | ||
import { ImportError } from '../errors.js'; | ||
import { loadConfigAndEnv } from '../utils/load-config-and-env.js'; | ||
|
||
/** | ||
* @param {import("../cli.js").LaunchpadArgv} argv | ||
*/ | ||
export function content(argv) { | ||
return loadConfigAndEnv(argv).andThen(config => { | ||
return importLaunchpadContent().map(({ LaunchpadContent }) => { | ||
const contentInstance = new LaunchpadContent(config.content); | ||
return contentInstance.download(); | ||
}); | ||
}).mapErr(error => { | ||
console.error('Content failed to download.'); | ||
console.error(error.message); | ||
process.exit(1); | ||
}); | ||
} | ||
|
||
export function importLaunchpadContent() { | ||
return ResultAsync.fromPromise( | ||
import('@bluecadet/launchpad-content'), | ||
() => new ImportError('Could not find module "@bluecadet/launchpad-content". Make sure you have installed it.') | ||
); | ||
} |
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,32 @@ | ||
import { ResultAsync } from 'neverthrow'; | ||
import { ImportError, MonitorError } from '../errors.js'; | ||
import { loadConfigAndEnv } from '../utils/load-config-and-env.js'; | ||
|
||
/** | ||
* @param {import("../cli.js").LaunchpadArgv} argv | ||
*/ | ||
export function monitor(argv) { | ||
return loadConfigAndEnv(argv).andThen(config => { | ||
return importLaunchpadMonitor() | ||
.map(({ LaunchpadMonitor }) => { | ||
return new LaunchpadMonitor(config.monitor); | ||
}) | ||
.andThrough((monitorInstance) => { | ||
return ResultAsync.fromPromise(monitorInstance.connect(), () => new MonitorError('Failed to connect to monitor')); | ||
}) | ||
.andThrough((monitorInstance) => { | ||
return ResultAsync.fromPromise(monitorInstance.start(), () => new MonitorError('Failed to start monitor')); | ||
}); | ||
}).mapErr(error => { | ||
console.error('Monitor failed to start.'); | ||
console.error(error.message); | ||
process.exit(1); | ||
}); | ||
} | ||
|
||
export function importLaunchpadMonitor() { | ||
return ResultAsync.fromPromise( | ||
import('@bluecadet/launchpad-monitor'), | ||
() => new ImportError('Could not find module "@bluecadet/launchpad-monitor". Make sure you have installed it.') | ||
); | ||
} |
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,8 @@ | ||
import { launchScaffold } from '@bluecadet/launchpad-scaffold'; | ||
|
||
/** | ||
* @param {import("../cli.js").LaunchpadArgv} argv | ||
*/ | ||
export async function scaffold(argv) { | ||
await launchScaffold(); | ||
} |
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,30 @@ | ||
import { loadConfigAndEnv } from '../utils/load-config-and-env.js'; | ||
import { importLaunchpadMonitor } from './monitor.js'; | ||
import { importLaunchpadContent } from './content.js'; | ||
import { ResultAsync } from 'neverthrow'; | ||
import { MonitorError } from '../errors.js'; | ||
|
||
/** | ||
* @param {import("../cli.js").LaunchpadArgv} argv | ||
*/ | ||
export async function start(argv) { | ||
return loadConfigAndEnv(argv).andThen(config => { | ||
return importLaunchpadContent().map(({ LaunchpadContent }) => { | ||
const contentInstance = new LaunchpadContent(config.content); | ||
return contentInstance.start(); | ||
}).andThen(() => importLaunchpadMonitor()) | ||
.map(({ LaunchpadMonitor }) => { | ||
return new LaunchpadMonitor(config.monitor); | ||
}) | ||
.andThrough((monitorInstance) => { | ||
return ResultAsync.fromPromise(monitorInstance.connect(), () => new MonitorError('Failed to connect to monitor')); | ||
}) | ||
.andThrough((monitorInstance) => { | ||
return ResultAsync.fromPromise(monitorInstance.start(), () => new MonitorError('Failed to start monitor')); | ||
}); | ||
}).mapErr(error => { | ||
console.error('Launchpad failed to start.'); | ||
console.error(error.message); | ||
process.exit(1); | ||
}); | ||
} |
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,10 @@ | ||
import LaunchpadMonitor from '@bluecadet/launchpad-monitor'; | ||
import { LogManager } from '@bluecadet/launchpad-utils'; | ||
|
||
/** | ||
* @param {import("../cli.js").LaunchpadArgv} argv | ||
*/ | ||
export async function stop(argv) { | ||
LogManager.configureRootLogger(); | ||
await LaunchpadMonitor.kill(); | ||
} |
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,39 @@ | ||
export class LaunchpadCLIError extends Error { | ||
/** | ||
* @param {string} message | ||
*/ | ||
constructor(message) { | ||
super(message); | ||
this.name = 'LaunchpadCLIError'; | ||
} | ||
} | ||
|
||
export class ImportError extends LaunchpadCLIError { | ||
/** | ||
* @param {string} message | ||
*/ | ||
constructor(message) { | ||
super(message); | ||
this.name = 'ImportError'; | ||
} | ||
} | ||
|
||
export class ConfigError extends LaunchpadCLIError { | ||
/** | ||
* @param {string} message | ||
*/ | ||
constructor(message) { | ||
super(message); | ||
this.name = 'ConfigError'; | ||
} | ||
} | ||
|
||
export class MonitorError extends LaunchpadCLIError { | ||
/** | ||
* @param {string} message | ||
*/ | ||
constructor(message) { | ||
super(message); | ||
this.name = 'MonitorError'; | ||
} | ||
} |
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 @@ | ||
export { defineConfig } from './launchpad-options.js'; |
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
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
File renamed without changes.
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,48 @@ | ||
import { err, errAsync, ok, ResultAsync } from 'neverthrow'; | ||
import { findConfig, loadConfigFromFile } from './config.js'; | ||
import { ConfigError } from '../errors.js'; | ||
import path from 'path'; | ||
import { resolveEnv } from './env.js'; | ||
import { resolveLaunchpadOptions } from '../launchpad-options.js'; | ||
import chalk from 'chalk'; | ||
|
||
/** | ||
* @param {import("../cli.js").LaunchpadArgv} argv | ||
* @returns {import('neverthrow').ResultAsync<import('../launchpad-options.js').ResolvedLaunchpadOptions, ConfigError>} | ||
*/ | ||
export function loadConfigAndEnv(argv) { | ||
const configPath = argv.config ?? findConfig(); | ||
|
||
if (!configPath) { | ||
return errAsync(new ConfigError('No config file found.')); | ||
} | ||
|
||
const configDir = path.dirname(configPath); | ||
|
||
if (argv.env) { | ||
// if env arg is passed, resolve paths relative to the CWD | ||
const rootDir = process.env.INIT_CWD ?? ''; | ||
resolveEnv( | ||
argv.env.map(p => path.resolve(rootDir, p.toString())) | ||
); | ||
} else if (argv.envCascade) { | ||
// if env-cascade arg is passed, resolve paths relative to the config file | ||
|
||
// Load order: .env < .env.local < .env.[override] < .env.[override].local | ||
resolveEnv([ | ||
path.resolve(configDir, '.env'), | ||
path.resolve(configDir, '.env.local'), | ||
path.resolve(configDir, `.env.${argv.envCascade}`), | ||
path.resolve(configDir, `.env.${argv.envCascade}.local`) | ||
]); | ||
} else { | ||
// default to loading .env and .env.local in the config dir | ||
resolveEnv([ | ||
path.resolve(configDir, '.env'), | ||
path.resolve(configDir, '.env.local') | ||
]); | ||
} | ||
|
||
return ResultAsync.fromPromise(loadConfigFromFile(configPath), (e) => new ConfigError(`Failed to load config file at path: ${chalk.white(configPath)}`)) | ||
.map(config => resolveLaunchpadOptions(config)); | ||
} |
Oops, something went wrong.