import { walkSync } from "https://deno.land/std@v0.34.0/fs/mod.ts";import * as path from "https://deno.land/std@v0.34.0/path/mod.ts";
class DrakeError extends Error { constructor(message?: string) { super(message); this.name = "DrakeError"; }}
export function abort(message: string): void { throw new DrakeError(message);}
export function quote(values: string[], sep: string = " "): string { values = values.map(value => `"${value.replace(/"/g, '\\"')}"`); return values.join(sep);}
export function readFile(filename: string): string { return new TextDecoder("utf-8").decode(Deno.readFileSync(filename));}
export function writeFile(filename: string, text: string): void { Deno.writeFileSync(filename, new TextEncoder().encode(text));}
export function updateFile( filename: string, find: RegExp, replace: string): void { writeFile(filename, readFile(filename).replace(find, replace));}
export function isNormalTask(name: string): boolean { return /^\w[\w-]*$/.test(name);}
export function isFileTask(name: string): boolean { return !isNormalTask(name);}
export function normalizePath(name: string): string { name = path.normalize(name); if (!path.isAbsolute(name)) { if (!name.startsWith(".")) { name = "." + path.sep + name; } } return name;}
export function normalizeTaskName(name: string): string { name = name.trim(); if (name === "") { abort("blank task name"); } if (path.isGlob(name)) { abort(`wildcard task name not allowed: ${name}`); } if (isFileTask(name)) { name = normalizePath(name); } return name;}
export function normalizePrereqs(prereqs: string[]): string[] { const result: string[] = []; for (let prereq of prereqs) { prereq = prereq.trim(); if (prereq === "") { abort("blank prerequisite name"); } if (!isFileTask(prereq)) { result.push(prereq); } else if (path.isGlob(prereq)) { result.push(...glob(prereq)); } else { result.push(normalizePath(prereq)); } } return result;}
export function glob(...patterns: string[]): string[] { const regexps = patterns.map(pat => path.globToRegExp(path.normalize(pat))); const iter = walkSync(".", { match: regexps, includeDirs: false }); return Array.from(iter, info => normalizePath(info.filename));}
function launch(command: string): Promise<Deno.ProcessStatus> { let args: string[]; const shellVar = Deno.build.os === "win" ? "COMSPEC" : "SHELL"; const shellExe = Deno.env(shellVar) as string; if (!shellExe) { abort(`cannot locate shell: missing ${shellVar} environment variable`); } if (Deno.build.os === "win") { args = [shellExe, "/C", command]; } else { args = [shellExe, "-c", command]; } const p = Deno.run({ args: args, stdout: "inherit" }); return p.status();}
export async function sh(commands: string | string[]) { if (typeof commands === "string") { commands = [commands]; } const promises = []; for (const cmd of commands) { promises.push(launch(cmd)); } const results = await Promise.all(promises); for (const i in results) { const cmd = commands[i]; const code = results[i].code; if (code === undefined) { abort(`sh: ${cmd}: undefined exit code`); } if (code !== 0) { abort(`sh: ${cmd}: error code: ${code}`); } }}