diff --git a/.changeset/rotten-gifts-breathe.md b/.changeset/rotten-gifts-breathe.md new file mode 100644 index 00000000..bbe1cf75 --- /dev/null +++ b/.changeset/rotten-gifts-breathe.md @@ -0,0 +1,5 @@ +--- +"@plutolang/cli": patch +--- + +feat(cli): enable graceful exit diff --git a/apps/cli/src/builder/project.ts b/apps/cli/src/builder/project.ts index 9eae4db6..5098ada0 100644 --- a/apps/cli/src/builder/project.ts +++ b/apps/cli/src/builder/project.ts @@ -1,7 +1,9 @@ +import { resolve } from "path"; import { input, select } from "@inquirer/prompts"; import { LanguageType, PlatformType, ProvisionType, config } from "@plutolang/base"; + import { createStack } from "./stack"; -import { resolve } from "path"; +import { handleIquirerError } from "./utils"; export interface CreateProjectArgs { name?: string; @@ -27,14 +29,14 @@ export async function createProject(args: CreateProjectArgs): Promise (await input({ message: "Stack name", default: "dev", - })); + }).catch(handleIquirerError)); args.platformType = args.platformType ?? @@ -43,7 +45,7 @@ export async function createStack(args: CreateStackArgs): Promise disabled: "(Coming soon)", }, ], - })); + }).catch(handleIquirerError)); args.provisionType = args.provisionType ?? @@ -60,7 +62,7 @@ export async function createStack(args: CreateStackArgs): Promise disabled: "(Coming soon)", }, ], - })); + }).catch(handleIquirerError)); - return new config.Stack(args.name, args.platformType, args.provisionType); + return new config.Stack(args.name!, args.platformType!, args.provisionType!); } diff --git a/apps/cli/src/builder/utils.ts b/apps/cli/src/builder/utils.ts new file mode 100644 index 00000000..d5d04063 --- /dev/null +++ b/apps/cli/src/builder/utils.ts @@ -0,0 +1,5 @@ +import { ExitError } from "../errors"; + +export function handleIquirerError(): any { + throw new ExitError(); +} diff --git a/apps/cli/src/commands/init.ts b/apps/cli/src/commands/init.ts index 2568ed1c..6d2b0eae 100644 --- a/apps/cli/src/commands/init.ts +++ b/apps/cli/src/commands/init.ts @@ -1,9 +1,13 @@ import fs from "fs"; import path from "path"; +import assert from "assert"; + import { createProject } from "../builder"; import logger from "../log"; import { dumpProject, isPlutoProject } from "../utils"; + import { NewOptions, genInitFiles } from "./new"; +import { formatError } from "./utils"; export async function init(opts: NewOptions) { if (isPlutoProject("./")) { @@ -27,7 +31,8 @@ export async function init(opts: NewOptions) { platformType: opts.platform, provisionType: opts.provision, rootpath: "./", - }); + }).catch(formatError); + assert(proj, "Failed to create a project."); genInitFiles("./", proj.language); const pkgJsonPath = path.join("./", "package.json"); diff --git a/apps/cli/src/commands/new.ts b/apps/cli/src/commands/new.ts index de9fcedd..33aa20da 100644 --- a/apps/cli/src/commands/new.ts +++ b/apps/cli/src/commands/new.ts @@ -1,10 +1,11 @@ import path from "path"; -import fs from "fs"; +import assert from "assert"; +import * as fs from "fs-extra"; import { ProvisionType, PlatformType, LanguageType } from "@plutolang/base"; -import { createProject } from "../builder"; import logger from "../log"; import { dumpProject } from "../utils"; -import { ensureDirSync } from "fs-extra"; +import { createProject } from "../builder"; +import { formatError } from "./utils"; const TEMPLATE_DIR = path.join(__dirname, "../../template"); @@ -23,7 +24,8 @@ export async function create(opts: NewOptions) { language: opts.language, platformType: opts.platform, provisionType: opts.provision, - }); + }).catch(formatError); + assert(proj, "Failed to create a project."); genInitFiles(proj.name, proj.language); const pkgJsonPath = path.join(proj.name, "package.json"); @@ -35,7 +37,7 @@ export async function create(opts: NewOptions) { } export function genInitFiles(destdir: string, language: string) { - ensureDirSync(destdir); + fs.ensureDirSync(destdir); const queue: string[] = [""]; while (queue.length) { diff --git a/apps/cli/src/commands/stack_new.ts b/apps/cli/src/commands/stack_new.ts index add631eb..17ffb8ed 100644 --- a/apps/cli/src/commands/stack_new.ts +++ b/apps/cli/src/commands/stack_new.ts @@ -1,8 +1,10 @@ +import assert from "assert"; import { ProvisionType, PlatformType } from "@plutolang/base"; import { createStack } from "../builder"; import logger from "../log"; import { dumpProject, isPlutoProject, loadProject } from "../utils"; import { resolve } from "path"; +import { formatError } from "./utils"; interface NewOptions { name?: string; @@ -21,7 +23,9 @@ export async function newStack(opts: NewOptions) { name: opts.name, platformType: opts.platform, provisionType: opts.provision, - }); + }).catch(formatError); + assert(sta, "Failed to create a stack."); + proj.addStack(sta); dumpProject(proj); logger.info("Created a stack."); diff --git a/apps/cli/src/commands/utils.ts b/apps/cli/src/commands/utils.ts index 9b4a856e..e098a908 100644 --- a/apps/cli/src/commands/utils.ts +++ b/apps/cli/src/commands/utils.ts @@ -1,9 +1,9 @@ import fs from "fs"; import path from "path"; import * as yaml from "js-yaml"; -import { LanguageType, ProvisionType } from "@plutolang/base"; +import { core, LanguageType, ProvisionType } from "@plutolang/base"; import { Architecture } from "@plutolang/base/arch"; -import { core } from "@plutolang/base"; +import { ExitError } from "../errors"; import { isPlutoProject, loadProject } from "../utils"; /** @@ -133,3 +133,28 @@ export function getDefaultEntrypoint(lang: LanguageType): string { throw new Error(`Invalid language type: ${lang}`); } } + +export function formatError(e: any) { + if (e instanceof ExitError) { + exitGracefully(); + return; + } + + if (e instanceof Error) { + console.error(e.message); + } else { + console.error(e); + } + + if (process.env.DEBUG) { + console.error(e); + } +} + +export function exitGracefully(sig?: string) { + if (process.env.DEBUG) { + console.warn(`\nReceived ${sig}. Exiting...`); + } + console.log("Bye~ 👋"); + process.exit(1); +} diff --git a/apps/cli/src/errors/index.ts b/apps/cli/src/errors/index.ts new file mode 100644 index 00000000..421c88c9 --- /dev/null +++ b/apps/cli/src/errors/index.ts @@ -0,0 +1,6 @@ +export class ExitError extends Error { + constructor(msg?: string) { + super(msg); + this.name = "ExitError"; + } +} diff --git a/apps/cli/src/main.ts b/apps/cli/src/main.ts index 8d51642e..7adbcd57 100644 --- a/apps/cli/src/main.ts +++ b/apps/cli/src/main.ts @@ -3,6 +3,17 @@ import * as cmd from "./commands"; import { checkUpdate, version } from "./utils"; import logger from "./log"; +function exitGracefully(sig: string) { + if (process.env.DEBUG) { + console.warn(`\nReceived ${sig}. Exiting...`); + } + console.log("\nBye~ 👋"); + process.exit(1); +} + +process.on("SIGINT", () => exitGracefully("SIGINT")); +process.on("SIGTERM", () => exitGracefully("SIGTERM")); + async function main() { checkUpdate();