@cdwr/core
Version:
A set of core utilities for the Codeware ecosystem.
398 lines (384 loc) • 12.5 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// packages/core/src/utils.ts
var utils_exports = {};
__export(utils_exports, {
dockerBuild: () => dockerBuild,
exec: () => exec,
getPackageVersion: () => getPackageVersion,
isDebugEnabled: () => isDebugEnabled,
killPort: () => killPort,
killProcessAndPorts: () => killProcessAndPorts,
killProcessTree: () => killProcessTree,
logDebug: () => logDebug,
logError: () => logError,
logInfo: () => logInfo,
logSuccess: () => logSuccess,
logWarning: () => logWarning,
runCommand: () => runCommand,
spawn: () => spawn,
spawnPty: () => spawnPty,
whoami: () => whoami
});
module.exports = __toCommonJS(utils_exports);
// packages/core/src/lib/utils/docker-build.ts
var import_fs = require("fs");
var import_path = require("path");
var import_docker_cli_js = require("docker-cli-js");
var import_tiny_invariant = __toESM(require("tiny-invariant"), 1);
// packages/core/src/lib/utils/log-utils.ts
var import_chalk = __toESM(require("chalk"), 1);
function isDebugEnabled() {
return process.env["CDWR_DEBUG_LOGGING"] === "true" || process.env["NX_VERBOSE_LOGGING"] === "true";
}
function logDebug(title, body) {
if (!isDebugEnabled()) {
return;
}
const message = `${import_chalk.default.reset.inverse.bold.cyan(
" DEBUG "
)} ${import_chalk.default.bold.cyan(title)}`;
return consoleLogger(message, body);
}
function logInfo(title, body) {
const message = `${import_chalk.default.reset.inverse.bold.blue(
" INFO "
)} ${import_chalk.default.bold.blue(title)}`;
return consoleLogger(message, body);
}
function logError(title, body) {
const message = `${import_chalk.default.reset.inverse.bold.red(" ERROR ")} ${import_chalk.default.bold.red(
title
)}`;
return consoleLogger(message, body);
}
function logSuccess(title, body) {
const message = `${import_chalk.default.reset.inverse.bold.green(
" SUCCESS "
)} ${import_chalk.default.bold.green(title)}`;
return consoleLogger(message, body);
}
function logWarning(title, body) {
const message = `${import_chalk.default.reset.inverse.bold.yellow(
" WARNING "
)} ${import_chalk.default.bold.yellow(title)}`;
return consoleLogger(message, body);
}
function consoleLogger(message, body) {
process.stdout.write("\n");
process.stdout.write(`${getLogPrefix()} ${message}
`);
if (body) {
process.stdout.write(`${body}
`);
}
process.stdout.write("\n");
}
function getLogPrefix() {
const prefix = process.env["CDWR_LOG_PREFIX"] ?? "E2E";
return `${import_chalk.default.reset.inverse.bold.yellow(` ${prefix.trim()} `)}`;
}
// packages/core/src/lib/utils/docker-build.ts
var dockerBuild = async (image, quiet) => {
const { context, dockerfile, name, tag, args } = image;
const dockerfilePath = (0, import_path.join)(context, dockerfile);
(0, import_tiny_invariant.default)(!!context?.length, "Context path must be provided");
(0, import_tiny_invariant.default)(!!dockerfile?.length, "Doockerfile path must be provided");
(0, import_tiny_invariant.default)(!!name?.length, "Image name must be provided");
(0, import_tiny_invariant.default)(
(0, import_fs.existsSync)((0, import_path.join)(dockerfilePath)),
`Dockerfile not found: ${dockerfilePath}`
);
const buildTag = `${name}:${tag}`;
if (!quiet) {
logInfo(`[${buildTag}] Context: '${image.context}'`);
logInfo(`[${buildTag}] Dockerfile: '${image.dockerfile}'`);
logInfo(
`[${buildTag}] Args: ${image?.args ? JSON.stringify(image.args) : "{}"}`
);
}
const buildArgs = args && Object.keys(args).map((key) => `--build-arg ${key}=${args[key]}`).join(" ") || "";
const cmd = `build -f ${dockerfilePath} -t ${buildTag} ${buildArgs} ${quiet ? "-q" : ""} ${context}`;
if (!quiet) {
logInfo(`[${buildTag}] Building image...`);
}
try {
const data = await (0, import_docker_cli_js.dockerCommand)(cmd, { echo: !quiet });
if (!quiet) {
logInfo(`[${buildTag}] Build success: ${data.response[0]}`);
}
} catch (error) {
logError(`[${buildTag}] Build failed`);
logError(`[${buildTag}] Command: '${cmd}'`);
throw error;
}
};
// packages/core/src/lib/utils/promisified-exec.ts
var import_child_process = require("child_process");
var import_util = require("util");
var exec = (0, import_util.promisify)(import_child_process.exec);
var execFile = (0, import_util.promisify)(import_child_process.execFile);
// packages/core/src/lib/utils/get-package-version.ts
function getNpmExecutable() {
if (process.platform === "win32") {
return process.env["npm_execpath"] || "npm.cmd";
}
return "npm";
}
async function getPackageVersion(packageName) {
let version;
try {
const { stdout } = await execFile(getNpmExecutable(), [
"list",
packageName,
"--depth=0",
"--json"
]);
const { dependencies } = JSON.parse(stdout);
const pkg = dependencies && dependencies[packageName];
version = pkg?.version;
} catch (error) {
logDebug(
`Failed to get version for package ${packageName}`,
error.message
);
}
return version ?? "";
}
// packages/core/src/lib/utils/kill-port.ts
var import_kill_port = __toESM(require("kill-port"), 1);
var import_tcp_port_used = require("tcp-port-used");
var KILL_PORT_DELAY = 5e3;
async function killPort(port, options) {
const delay = options?.delay ?? KILL_PORT_DELAY;
const verbose = options?.verbose;
if (await (0, import_tcp_port_used.check)(port)) {
let killPortResult;
try {
if (verbose) {
logInfo(`Attempting to close port ${port}`);
}
killPortResult = await (0, import_kill_port.default)(port);
await new Promise((resolve) => setTimeout(() => resolve(), delay));
if (await (0, import_tcp_port_used.check)(port)) {
logError(`Port ${port} still open`, JSON.stringify(killPortResult));
} else {
if (verbose) {
logSuccess(`Port ${port} successfully closed`);
}
return true;
}
} catch {
logError(`Port ${port} closing failed`);
}
return false;
} else {
return true;
}
}
// packages/core/src/lib/utils/kill-process-tree.ts
var import_util2 = require("util");
var import_tree_kill = __toESM(require("tree-kill"), 1);
var killProcessTree = (0, import_util2.promisify)(import_tree_kill.default);
// packages/core/src/lib/utils/kill-process-and-ports.ts
async function killProcessAndPorts(pid, ports) {
if (pid) {
await killProcessTree(pid, "SIGKILL");
}
for (const port of ports ?? []) {
await killPort(port);
}
}
// packages/core/src/lib/utils/promisified-spawn.ts
var import_child_process2 = require("child_process");
function spawn(command, args, options) {
return new Promise((resolve, reject) => {
const process2 = (0, import_child_process2.spawn)(command, args, {
...options,
stdio: "pipe"
});
const stdoutChunks = [];
const stderrChunks = [];
process2.stdout.on("data", (data) => {
stdoutChunks.push(Buffer.from(data));
});
process2.stderr.on("data", (data) => {
stderrChunks.push(Buffer.from(data));
});
process2.on("close", (code) => {
const stdout = Buffer.concat(stdoutChunks).toString();
const stderr = Buffer.concat(stderrChunks).toString();
if (code === 0) {
resolve({ stdout, stderr });
} else {
reject(new Error(`Process exited with code ${code}
Error: ${stderr}`));
}
});
process2.on("error", reject);
});
}
// packages/core/src/lib/utils/run-command.ts
var import_child_process3 = require("child_process");
var import_testing = require("@nx/plugin/testing");
function runCommand(command, options) {
const cwd = options?.cwd ?? (0, import_testing.tmpProjPath)();
const doneFn = options?.doneFn;
const env = options?.env ?? process.env;
const errorDetector = options?.errorDetector;
const verbose = options?.verbose;
if (verbose) {
logDebug("Running command...", command);
}
const controller = new AbortController();
const { signal } = controller;
const p = (0, import_child_process3.exec)(command, {
cwd,
encoding: "utf-8",
env,
signal
});
return new Promise((resolve, reject) => {
let output = "";
let complete = false;
const checkLog = (log) => {
if (verbose) {
logDebug(log);
}
output += log;
if (errorDetector && log.match(errorDetector)) {
logDebug(
"Error detector found a match, terminate command with failure",
log
);
return terminate(output, "fail");
}
if (doneFn && doneFn(log) && !complete) {
complete = true;
logDebug("Predicate function met, terminate command successfully", log);
terminate(output, "success");
}
};
const terminate = (result, status) => {
if (!signal.aborted) {
controller.abort();
}
if (status === "success") {
resolve(result);
} else {
reject(result);
}
};
p.stdout?.on("data", checkLog);
p.stderr?.on("data", checkLog);
p.on("error", (err) => {
if (signal.aborted) {
return;
}
logError("Received error event");
terminate(err.message, "fail");
});
p.on("exit", (code) => {
if (doneFn && !complete) {
logError(
"Command output:",
output.split("\n").map((l) => ` ${l}`).join("\n")
);
reject(`Exited with ${code}`);
} else {
terminate(output, "success");
}
});
});
}
// packages/core/src/lib/utils/spawn-pty.ts
var import_node_pty_prebuilt_multiarch = require("@homebridge/node-pty-prebuilt-multiarch");
function spawnPty(command, args, options) {
return new Promise((resolve, reject) => {
const ptyData = [];
const ptyProcess = (0, import_node_pty_prebuilt_multiarch.spawn)(command, args, {
cwd: process.cwd(),
encoding: "utf-8",
env: process.env
});
ptyProcess.onData((data) => {
ptyData.push(data);
if (options?.prompt) {
const answer = options.prompt(data);
if (answer) {
ptyProcess.write(`${answer}
`);
}
}
});
ptyProcess.onExit(({ exitCode }) => {
const output = ptyData.join("");
if (exitCode === 0) {
resolve(output);
} else {
reject(
new Error(`Process exited with code ${exitCode}
Output: ${output}`)
);
}
});
});
}
// packages/core/src/lib/utils/whoami.ts
var import_npm_whoami = __toESM(require("npm-whoami"), 1);
async function whoami() {
return new Promise((resolve) => {
(0, import_npm_whoami.default)((err, user) => {
if (err || !user) {
resolve("");
} else {
resolve(user);
}
});
});
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
dockerBuild,
exec,
getPackageVersion,
isDebugEnabled,
killPort,
killProcessAndPorts,
killProcessTree,
logDebug,
logError,
logInfo,
logSuccess,
logWarning,
runCommand,
spawn,
spawnPty,
whoami
});