@senchou/cli
Version:
Generate TypeScript for Kubernetes resources.
328 lines (287 loc) • 10.3 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
import arg from "arg";
import littlelog from "@littlethings/log";
import kleur from "kleur";
import fs from "fs";
import path from "path";
import mkdirp from "mkdirp";
import core from "@senchou/core";
const rootArgs = {
"--help": Boolean,
"-h": "--help",
"--verbose": arg.COUNT,
"-v": "--verbose"
};
const args = arg(rootArgs, {
permissive: true
});
if (args["--verbose"]) {
switch (args["--verbose"]) {
default:
case 0:
break;
case 1:
littlelog.setVerbosity("INFO");
break;
case 2:
littlelog.setVerbosity("DEBUG");
break;
case 3:
littlelog.setVerbosity("TRACE");
break;
}
if (args["--verbose"] > 3) {
littlelog.setVerbosity("TRACE");
}
} else {
littlelog.setVerbosity("INFO");
}
var log = littlelog.create("@senchou/cli");
const help$2 = () => {
const message = `
${kleur.bold(`DESCRIPTION`)}
Manage Kubernetes manifests with TypeScript.
${kleur.bold(`USAGE`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou`)} <command> [options]
${kleur.bold(`COMMANDS`)}
k8s Import types for a Kubernetes release
crd Import types for a CustomResourceDefinition
${kleur.bold(`OPTIONS`)}
--help, -h Show this help message
--verbose, -v Set logging verbosity
${kleur.bold(`EXAMPLE`)}
${kleur.dim(`$ # Get help for commands.`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou k8s`)} --help
${kleur.dim(`$`)} ${kleur.bold(`senchou crd`)} --help
${kleur.dim(`$ # Run Senchou with verbose logging.`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou`)} -v
${kleur.dim(`$`)} ${kleur.bold(`senchou`)} -vv
${kleur.dim(`$`)} ${kleur.bold(`senchou`)} -vvv
${kleur.dim(`$ # Run Senchou with no logging.`)}
${kleur.dim(`$`)} LOG_LEVEL=SILENT ${kleur.bold(`senchou`)}
${kleur.dim(`$ # Run Senchou with timestamps.`)}
${kleur.dim(`$`)} LOG_TIMESTAMP=TRUE ${kleur.bold(`senchou`)}
${kleur.dim(`$ # Filter logs from Senchou (based on log prefix).`)}
${kleur.dim(`$`)} DEBUG="^some-regex$" ${kleur.bold(`senchou`)}
`;
console.log(message);
};
const help$1 = () => {
const message = `
${kleur.bold(`DESCRIPTION`)}
Import types for a Kubernetes release.
${kleur.bold(`USAGE`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou k8s [version]`)}
${kleur.bold(`OPTIONS`)}
--help, -h Show this help message
--output, -o Set the output directory (default: ./senchou)
--force, -f Remove any conflicting files before writing
${kleur.bold(`EXAMPLE`)}
${kleur.dim(`$ # Import the default Kubernetes release's types.`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou k8s`)}
${kleur.dim(`$ # Import a specific Kubernetes release's types.`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou k8s`)} 1.20.0
${kleur.dim(`$ # Import to a custom directory.`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou k8s`)} --output ./my-code
${kleur.dim(`$ # Overwrite an existing "k8s.ts" file.`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou k8s`)} --force
`;
console.log(message);
};
const getArgs$1 = () => {
return arg(__spreadProps(__spreadValues({}, rootArgs), {
"--output": String,
"-o": "--output",
"--force": Boolean,
"-f": "--force"
}));
};
const resolveRelativePath = (relativePath) => {
if (path.isAbsolute(relativePath)) {
return relativePath;
} else {
return path.resolve(process.cwd(), relativePath);
}
};
const command$1 = async () => {
const args2 = getArgs$1();
if (args2["--help"]) {
help$1();
process.exit(0);
}
const output = args2["--output"] ? resolveRelativePath(args2["--output"]) : resolveRelativePath("senchou");
const version = args2._[1];
log.debug(`Creating directory "${output}".`);
await mkdirp(output);
const file = path.resolve(output, "k8s.ts");
if (fs.existsSync(file)) {
if (args2["--force"]) {
fs.rmSync(file);
} else {
log.fatal(`File already exists at path "${file}".`);
log.fatal(`Remove the file and try again or use the "--force" option.`);
process.exit(1);
}
}
const specifier = `k8s${version ? `@${version}` : ""}`;
log.trace(`Importing schema for "${specifier}".`);
const schema = await core.import.kubernetes(specifier);
log.trace(`Generating code for schema.`);
const code = await core.generate.kubernetes(schema);
log.debug(`Writing code to file "${file}".`);
fs.writeFileSync(file, code);
};
const help = () => {
const message = `
${kleur.bold(`DESCRIPTION`)}
Import types for a CustomResourceDefinition.
${kleur.bold(`USAGE`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou crd <protocol>:<specifier>`)}
${kleur.bold(`OPTIONS`)}
--help, -h Show this help message
--output, -o Set the output directory (default: ./senchou)
--force, -f Remove any conflicting files before writing
--name, -n Set the name of the output file (appended with ".ts")
${kleur.bold(`PROTOCOLS`)}
${kleur.bold("github")}
CRDs can be imported from GitHub using the "github"
protocol. To fetch from GitHub, you must supply an
owner and repository name like the following.
${kleur.dim(`$ # github:owner/repo`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou crd github:traefik/traefik-helm-chart`)}
Tags can also be used to fetch CRDs from a specific
release.
${kleur.dim(`$ # github:owner/repo@tag`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou crd github:traefik/traefik-helm-chart@v10.14.0`)}
${kleur.bold(`EXAMPLE`)}
${kleur.dim(`$ # Import types for Traefik from GitHub.`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou crd`)} github:traefik/traefik-helm-chart
${kleur.dim(`$ # Import a specific version's types.`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou crd`)} github:traefik/traefik-helm-chart@v10.14.0
${kleur.dim(`$ # Import to a custom directory.`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou crd`)} github:traefik/traefik-helm-chart --output ./my-code
${kleur.dim(`$ # Name the output file.`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou crd`)} github:traefik/traefik-helm-chart --name traefik
${kleur.dim(`$ # Overwrite an existing file.`)}
${kleur.dim(`$`)} ${kleur.bold(`senchou crd`)} github:traefik/traefik-helm-chart --force
`;
console.log(message);
};
const getArgs = () => {
return arg(__spreadProps(__spreadValues({}, rootArgs), {
"--output": String,
"-o": "--output",
"--force": Boolean,
"-f": "--force",
"--name": String,
"-n": "--name"
}));
};
const specifierToFileName = (specifier) => {
if (specifier.startsWith("github:")) {
const suffix = specifier.split("github:")[1];
const path2 = suffix.split("@")[0];
const repo = path2.split("/")[1];
return repo;
} else {
return specifier.replace(/[^A-Za-z0-9]/g, "-");
}
};
const importCRD = async (specifier) => {
if (specifier.startsWith("github:")) {
return core.import.github(specifier.substring("github:".length));
} else {
log.fatal(`Unknown protocol "${specifier}" for CRD.`);
process.exit(1);
}
};
const command = async () => {
const args2 = getArgs();
if (args2["--help"]) {
help();
process.exit(0);
}
if (!args2._[1]) {
log.fatal("No specifier entered.");
help();
process.exit(1);
}
const specifier = args2._[1];
const output = args2["--output"] ? resolveRelativePath(args2["--output"]) : resolveRelativePath("senchou");
const name = args2["--name"] ? args2["--name"] : specifierToFileName(specifier);
log.trace(`Using name "${name}" for resource.`);
log.debug(`Creating directory "${output}".`);
await mkdirp(output);
const file = path.resolve(output, `${name}.ts`);
if (fs.existsSync(file)) {
if (args2["--force"]) {
fs.rmSync(file);
} else {
log.fatal(`File already exists at path "${file}".`);
log.fatal(`Remove the file and try again or use the "--force" option.`);
process.exit(1);
}
}
log.trace(`Importing definitions for "${specifier}".`);
const definitions = await importCRD(specifier);
log.trace(`Generating code for definitions.`);
const code = await core.generate.crd(definitions);
log.debug(`Writing code to file "${file}".`);
fs.writeFileSync(file, code);
};
const commands = {
k8s: command$1,
crd: command
};
const main = async () => {
var _a;
log.trace("Init.");
log.trace("Parsing root arguments.");
const args2 = arg(rootArgs, {
permissive: true
});
if (args2["--help"] && args2._.length === 0) {
log.trace("Printing root help message.");
help$2();
process.exit(0);
}
if (args2._.length === 0) {
log.fatal("No command specified.");
log.trace("Printing root help message due to error.");
help$2();
process.exit(1);
}
const command2 = (_a = args2._) == null ? void 0 : _a[0];
if (command2 && command2 in commands) {
log.trace(`Executing command "${command2}".`);
await commands[command2]();
} else {
log.fatal(`Unknown command "${command2}".`);
process.exit(1);
}
};
main().catch((error) => {
var _a, _b, _c;
log.fatal(error.message || error);
for (const line of (_c = (_b = (_a = error.stack) == null ? void 0 : _a.split("\n")) == null ? void 0 : _b.slice(1)) != null ? _c : []) {
log.fatal(`${line}`);
}
});