diff --git a/package.json b/package.json index 1ecad94..d62bb74 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@endeavorance/rundir", "type": "module", "module": "src/cli.ts", - "version": "0.2.0", + "version": "0.1.1", "bin": { "rundir": "build/cli.js" }, diff --git a/src/cli.ts b/src/cli.ts index d27544a..481dab2 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,4 +1,5 @@ import { existsSync } from "node:fs"; +import { homedir } from "node:os"; import path from "node:path"; import { parseArgs } from "node:util"; import { $, Glob } from "bun"; @@ -19,20 +20,13 @@ class CLIError extends Error { } } -class NoRundirError extends CLIError { - name = "NoRundirError"; - - constructor() { - super("No rundir found in current directory tree"); - } -} - const TEMPLATE_FILE_PATH = process.env["RUNDIR_TEMPLATE"] ?? null; const DEFAULT_TEMPLATE = ` #!/usr/bin/env bash # Description... `.trim(); const VERSION = pkg.version; +const RUNDIR_PATH = path.join(process.cwd(), ".run"); const COMMENT_STARTERS = ["#", "//", "--"]; const COMMANDS = ["ls", "help", "new", "create", "which", "x", "run"] as const; type Command = (typeof COMMANDS)[number]; @@ -58,19 +52,19 @@ function parseCommand(command: string): Command { * @param fromPath The path to start searching from * @returns The path to the rundir, or null if not found */ -function getRundirPath(fromPath?: string): string { +function findNearestRundir(fromPath?: string): string | null { const currentDir = fromPath ?? process.cwd(); - const potentialPath = path.resolve(currentDir, ".run"); + const potentialPath = path.join(currentDir, ".run"); if (currentDir === path.dirname(currentDir)) { - throw new NoRundirError(); + return null; } if (existsSync(potentialPath)) { return potentialPath; } - return getRundirPath(path.dirname(currentDir)); + return findNearestRundir(path.dirname(currentDir)); } /** @@ -79,12 +73,14 @@ function getRundirPath(fromPath?: string): string { * @param name The name of the script * @returns The absolute path to the script */ -function getScriptPath(name: string): string { - return path.resolve(getRundirPath(), name); -} +function makeScriptPath(name: string): string { + const rundir = findNearestRundir(); -async function scriptExists(name: string): Promise { - return Bun.file(getScriptPath(name)).exists(); + if (!rundir) { + throw new CLIError("No rundir found in the current directory tree."); + } + + return path.join(rundir, name); } /** @@ -98,23 +94,22 @@ async function scriptExists(name: string): Promise { * @param name The name of the script to find the path of */ async function findScriptPath(name: string): Promise { - const currentRundir = getRundirPath(); + let currentDir = process.cwd(); - if (!currentRundir) { - throw new NoRundirError(); + while (currentDir !== path.dirname(currentDir)) { + const potentialPath = path.join(currentDir, ".run", name); + if (await Bun.file(potentialPath).exists()) { + return potentialPath; + } + currentDir = path.dirname(currentDir); } - const expectedPath = path.resolve(currentRundir, name); - - const checkFile = Bun.file(expectedPath); - - const exists = await checkFile.exists(); - - if (!exists) { - return null; + const homeDirPath = path.join(homedir(), ".run", name); + if (await Bun.file(homeDirPath).exists()) { + return homeDirPath; } - return expectedPath; + return null; } /** @@ -182,9 +177,8 @@ async function readScriptData(scriptName: string): Promise { */ async function ls(scriptName?: string) { if (scriptName) { - const pathname = getScriptPath(scriptName); - const exists = await scriptExists(pathname); - if (!exists) { + const pathname = await findScriptPath(scriptName); + if (pathname === null) { throw new CLIError(`Script "${scriptName}" not found.`); } @@ -192,7 +186,7 @@ async function ls(scriptName?: string) { return; } - const currentRundir = getRundirPath(); + const currentRundir = findNearestRundir(); const filesInDir = new Glob(`${currentRundir}/*`).scan(); const scriptLines: string[] = []; @@ -215,7 +209,14 @@ async function ls(scriptName?: string) { * @command */ async function which() { - console.log(getRundirPath()); + const nearest = findNearestRundir(); + + if (!nearest) { + console.error("No rundir found in the current directory tree."); + process.exit(1); + } + + console.log(path.resolve(nearest)); } /** @@ -223,7 +224,7 @@ async function which() { * @command */ async function newScript(name: string) { - const scriptPath = getScriptPath(name); + const scriptPath = makeScriptPath(name); const scriptFile = Bun.file(scriptPath); let template = DEFAULT_TEMPLATE; @@ -244,7 +245,7 @@ async function newScript(name: string) { await Bun.write(scriptFile, template); await $`chmod +x ${scriptPath}`; - console.log(scriptFile); + console.log(name); } /** @@ -259,23 +260,7 @@ async function runScript(name: string) { process.exit(1); } - const rundir = path.dirname(scriptPath); - const cwd = path.resolve(rundir, ".."); - - const proc = Bun.spawn([scriptPath], { - cwd, - env: { - ...process.env, - RUNDIR_PATH: rundir, - RUNDIR_CWD: cwd, - RUNDIR_SCRIPT_PATH: scriptPath, - }, - stdout: Bun.stdout, - stderr: Bun.stderr, - stdin: Bun.stdin, - }); - - await proc.exited; + await $`${scriptPath}`; } /**