UNPKG

@travetto/pack

Version:

Code packing utilities

96 lines (81 loc) 3.29 kB
import fs from 'node:fs/promises'; import { spawn, type SpawnOptions } from 'node:child_process'; import path from 'node:path'; import { AppError, ExecUtil, Runtime, RuntimeIndex } from '@travetto/runtime'; import { ActiveShellCommand } from './shell.ts'; export class PackUtil { /** * Generate .env file */ static buildEnvFile(env: Record<string, string | number | boolean | undefined>): string[] { return Object.entries(env) .filter(([, value]) => (value !== undefined)) .map(([key, value]) => `${key}=${value}`); } /** * Remove directory, determine if errors should be ignored * @param sourceDirectory The folder to copy * @param destinationDirectory The folder to copy to */ static async copyRecursive(sourceDirectory: string, destinationDirectory: string, inclusive: boolean = false, ignoreFailure = false): Promise<void> { try { let final = destinationDirectory; if (!inclusive) { final = path.resolve(destinationDirectory, path.basename(sourceDirectory)); } await fs.mkdir(final, { recursive: true }); await fs.cp(sourceDirectory, final, { recursive: true }); } catch { if (!ignoreFailure) { throw new Error(`Failed to copy ${sourceDirectory} to ${destinationDirectory}`); } } } /** * Finalize eject output */ static async writeEjectOutput(workspace: string, module: string, output: AsyncIterable<string>, file: string): Promise<void> { const repoRoot = Runtime.workspaceRelative('.'); const vars = { ROOT: path.resolve(), TRV_OUT: RuntimeIndex.outputRoot, REPO_ROOT: repoRoot, DIST: workspace, MODULE: module }; const replaceArgs = (text: string): string => Object.entries(vars) .reduce((result, [key, value]) => result.replaceAll(value, ActiveShellCommand.var(key)), text); const preamble = ActiveShellCommand.script( Object.entries(vars).map(([key, value]) => ActiveShellCommand.export(key, value).join(' ')), ).contents; let stream: fs.FileHandle | undefined; if (!(file === '-' || file === '/dev/stdout')) { await fs.mkdir(path.dirname(file), { recursive: true }); await fs.writeFile(file, '', 'utf8'); stream = await fs.open(file, 'w', 0o755); } const write = (text: string): Promise<unknown> | unknown => stream ? stream.write(`${text}\n`) : process.stdout.write(`${text}\n`); for (const line of preamble) { write(line); } for await (const line of output) { await write(replaceArgs(line)); } await write('\n'); await stream?.close(); } /** * Track result response */ static async runCommand(cmd: string[], options: SpawnOptions = {}): Promise<string> { const { valid, code, stderr, message, stdout } = await ExecUtil.getResult(spawn(cmd[0], cmd.slice(1), { stdio: [0, 'pipe', 'pipe'], ...options, }), { catch: true }); if (!valid) { process.exitCode = code; throw new AppError(stderr || message || 'An unexpected error has occurred'); } return stdout; } /** * Write a file directly */ static async writeRawFile(file: string, contents: string[], mode?: string): Promise<void> { await fs.writeFile(file, contents.join('\n'), { encoding: 'utf8', mode }); } }