diff --git a/package-lock.json b/package-lock.json index 5b8558f..51c6208 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@figma/nodegit": "^0.28.0-figma.6", + "commander": "^12.1.0", "dockerode": "^4.0.2", "dotenv": "^16.4.5", "express": "^4.19.2", @@ -2071,6 +2072,14 @@ "color-support": "bin.js" } }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "engines": { + "node": ">=18" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", diff --git a/package.json b/package.json index 167bc2e..877514d 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "license": "MIT", "main": "bin/index.js", "bin": { - "buttler": "./bin/index.js" + "buttler": "./bin/cli.js" }, "files": [ "bin/" @@ -48,6 +48,7 @@ }, "dependencies": { "@figma/nodegit": "^0.28.0-figma.6", + "commander": "^12.1.0", "dockerode": "^4.0.2", "dotenv": "^16.4.5", "express": "^4.19.2", diff --git a/src/cli.ts b/src/cli.ts new file mode 100644 index 0000000..90c7067 --- /dev/null +++ b/src/cli.ts @@ -0,0 +1,66 @@ +#!/usr/bin/env node +import { spawn } from "node:child_process"; +import fs from "node:fs/promises"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { Command } from "commander"; + +const program = new Command(); + +async function checkFile(filePath: string) { + try { + await fs.access(filePath); + return true; + } catch { + return false; + } +} + +function spawnChildProcess(detached: boolean) { + const __filename = fileURLToPath(import.meta.url); + const __dirname = dirname(__filename); + const appPath = resolve(__dirname, "index.js"); + const child = spawn("node", [appPath], { + detached, + stdio: detached ? "ignore" : "inherit", + env: { + PORT: "2083", + }, + }); + if (detached) child.unref(); + return child.pid; +} + +program.command("start").description("starts the application").action(async () => { + const pidFilePath = resolve(process.cwd(), "PID"); + const exists = await checkFile(pidFilePath); + if (exists) { + return console.warn("the application is already running"); + } + const pid = spawnChildProcess(true); + await fs.writeFile(pidFilePath, `${pid}`, "utf8"); + console.log("the application has started"); +}); + +program.command("stop").description("stops the application").action(async () => { + const pidFilePath = resolve(process.cwd(), "PID"); + const exists = await checkFile(pidFilePath); + if (!exists) { + return console.warn("the application was not running"); + } + const content = await fs.readFile(pidFilePath, "utf-8"); + const pid = parseInt(content); + if (isNaN(pid)) { + return console.error("Invalid PID"); + } + try { + process.kill(pid); + console.log("the application is stopped"); + } catch { + console.warn("the application was crashed"); + } finally { + await fs.unlink(pidFilePath); + } +}); + +program.parse(process.argv); diff --git a/src/index.ts b/src/index.ts index c9deaed..8e7562e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,3 @@ -#!/usr/bin/env node import http from "node:http"; import readline from "node:readline"; import dotenv from "dotenv";