85d2225e0c
* Fix loading within the CLI * Remove app * Remove promise handle * Add initial travis file * Add libxkbfile dependency * Add libxkbfile-dev * Add build script * Fix malformed bash statement * Remove yarn from script * Improve build script * Extract upx before usage * Only run upx if on linux * Ensure resource directory exists * Pack runnable binary * Export binary with platform * Improve build process * Install upx before running install script * Update typescript version before running nexe * Add os.release() function for multi-platform support * Update travis.yml to improve deployment * Add on CI * Update to v1.31.0 * Add libsecret * Update build target * Skip cleanup * Fix built-in extensions * Add basics for apps * Create custom DNS server * Fix forking within CLI. Fixes TS language features * Fix filename resolve * Fix default extensions path * Add custom dialog * Store workspace path * Remove outfiles * Cleanup * Always authed outside of CLI * Use location.host for client * Remove useless app interface * Remove debug file for building wordlist * Use chromes tcp host * Update patch * Build browser app before packaging * Replace all css containing file:// URLs, fix webviews * Fix save * Fix mkdir
115 lines
2.8 KiB
TypeScript
115 lines
2.8 KiB
TypeScript
import * as cp from "child_process";
|
|
import { logger, Logger, field, time } from "@coder/logger";
|
|
|
|
export interface CommandResult {
|
|
readonly exitCode: number;
|
|
readonly stdout: string;
|
|
readonly stderr: string;
|
|
}
|
|
|
|
const execute = (command: string, args: string[] = [], options: cp.SpawnOptions, logger: Logger): Promise<CommandResult> => {
|
|
let resolve: (result: CommandResult) => void;
|
|
const prom = new Promise<CommandResult>(res => resolve = res);
|
|
|
|
const stdout: string[] = [];
|
|
const stderr: string[] = [];
|
|
const complete = (exitCode: number): void => {
|
|
resolve({
|
|
stderr: stderr.join(""),
|
|
stdout: stdout.join(""),
|
|
exitCode,
|
|
});
|
|
};
|
|
logger.info(`Executing '${command} ${JSON.stringify(args)}'`, field("options", options));
|
|
const proc = cp.spawn(command, args.length > 0 ? args : [], options);
|
|
proc.on("close", (code) => {
|
|
complete(code);
|
|
});
|
|
proc.on("exit", (code) => {
|
|
complete(code!);
|
|
});
|
|
proc.stdout.on("data", (d) => {
|
|
stdout.push(d.toString());
|
|
logger.debug("stdio", field("stdout", d.toString()));
|
|
});
|
|
proc.stderr.on("data", (d) => {
|
|
stderr.push(d.toString());
|
|
logger.debug("stdio", field("stderr", d.toString()));
|
|
});
|
|
|
|
return prom;
|
|
};
|
|
|
|
export type TaskFunction = (runner: Runner) => void | Promise<void>;
|
|
|
|
export interface Runner {
|
|
|
|
cwd: string;
|
|
execute(command: string, args?: string[], env?: object): Promise<CommandResult>;
|
|
}
|
|
|
|
export interface Task {
|
|
readonly name: string;
|
|
readonly func: TaskFunction;
|
|
}
|
|
|
|
const tasks = new Map<string, Task>();
|
|
const activated = new Map<string, Promise<void>>();
|
|
|
|
export const register = (name: string, func: TaskFunction): () => void | Promise<void> => {
|
|
if (tasks.has(name)) {
|
|
throw new Error(`Task "${name}" already registered`);
|
|
}
|
|
|
|
tasks.set(name, {
|
|
name,
|
|
func,
|
|
});
|
|
|
|
return (): void | Promise<void> => {
|
|
return run(name);
|
|
};
|
|
};
|
|
|
|
export const run = (name: string = process.argv[2]): void | Promise<void> => {
|
|
const task = tasks.get(name);
|
|
if (!task) {
|
|
logger.error("Task not found.", field("name", name), field("available", Array.from(tasks.keys())));
|
|
|
|
return process.exit(1);
|
|
}
|
|
if (activated.has(name)) {
|
|
return activated.get(name);
|
|
}
|
|
let cwd: string = process.cwd();
|
|
const log = logger.named(name);
|
|
const timer = time(Number.MAX_SAFE_INTEGER);
|
|
log.info("Starting...");
|
|
const prom = task.func({
|
|
set cwd(path: string) {
|
|
cwd = path;
|
|
},
|
|
execute(command: string, args: string[] = [], env?: object): Promise<CommandResult> {
|
|
return execute(command, args, {
|
|
cwd,
|
|
env: env as NodeJS.ProcessEnv,
|
|
}, log);
|
|
},
|
|
});
|
|
|
|
if (prom) {
|
|
activated.set(name, prom);
|
|
prom.then(() => {
|
|
log.info("Completed!", field("time", timer));
|
|
}).catch((ex) => {
|
|
activated.delete(name);
|
|
log.error(`Failed: ${ex.message}`);
|
|
log.error(`Stack: ${ex.stack}`);
|
|
|
|
return process.exit(1);
|
|
});
|
|
}
|
|
|
|
return prom;
|
|
};
|