UNPKG

@sap/cli-core

Version:

Command-Line Interface (CLI) Core Module

167 lines (166 loc) 6.42 kB
import path from "path"; import { get } from "../logger/index.js"; import { CLI_DESCRIPTION, CLI_NAME, CLI_SAP_HELP, OPTION_FILE_PATH, OPTION_FORCE, OPTION_HELP, OPTION_HOST, OPTION_INPUT, OPTION_OPTIONS_FILE, OPTION_OUTPUT, OPTION_VERBOSE, OPTION_VERSION, ROOT_COMMAND, } from "../constants.js"; import { init as initCache } from "../cache/index.js"; import { get as getConfig, set as setConfig, setCustomConfig, initialize as initializeConfig, } from "../config/index.js"; import { buildOption, createCommand, registerLongName, } from "../utils/commands.js"; import { clear as clearDiscovery } from "../discovery/index.js"; import { get as getSettings } from "../settings/index.js"; import { addCommandsFromFolder, getOptionValueFromArgv } from "./utils.js"; import { getValueFromOptionsFile } from "../commands/handler/options/utils.js"; import { getGenericOptionsHelp, getVersion } from "../config/core.js"; import { ResultHandlerImpl } from "../result/ResultHandlerImpl.js"; import { ResultHandlerFactory } from "../result/ResultHandlerFactory.js"; import { SecretsStorageImpl } from "../cache/secrets/SecretsStorageImpl.js"; import { SecretsStorageSingleton } from "../cache/secrets/SecretsStorageSingleton.js"; import { replaceLeadingTrailingSingleQuotes } from "../commands/handler/utils.js"; let program; let initialized = false; const getLogger = () => get("dwc.dwc"); const MANDATORY_OPTIONS = [ OPTION_VERSION, OPTION_HELP, OPTION_HOST, OPTION_FILE_PATH, OPTION_FORCE, OPTION_OUTPUT, OPTION_VERBOSE, OPTION_INPUT, OPTION_OPTIONS_FILE, ]; const setTenant = async () => { const config = getConfig(); if (config.host) { return; } const readHostFromArgv = async () => getOptionValueFromArgv(ROOT_COMMAND, OPTION_HOST); const readHostFromOptionsFile = async () => { const filePath = getOptionValueFromArgv(ROOT_COMMAND, OPTION_OPTIONS_FILE); return getValueFromOptionsFile(filePath, OPTION_HOST); }; const readHostFromOptions = async () => { if (!config.options?.[OPTION_HOST.longName]) { throw new Error("host not found in options"); } return config.options[OPTION_HOST.longName]; }; const strategies = [ { func: readHostFromArgv, name: "read host from argv", }, { func: readHostFromOptionsFile, name: "read host from options-file", }, { func: readHostFromOptions, name: "read host from options", }, ]; const { trace } = getLogger(); for (const { name, func } of strategies) { trace(`trying to ${name}`); try { // eslint-disable-next-line no-await-in-loop const host = replaceLeadingTrailingSingleQuotes(await func()); setConfig({ tenant: host, options: { ...config.options, [OPTION_HOST.longName]: host }, }); break; } catch (err) { trace(`failed to ${name}`, err); } } }; const setHost = async () => { const settings = await getSettings(); if (settings.host) { setConfig({ options: { [OPTION_HOST.longName]: settings.host } }); } }; const initCacheTolerant = async () => { try { await initCache(); } catch { // ignore } }; const registerMandatoryOptions = () => { MANDATORY_OPTIONS.forEach((option) => registerLongName(ROOT_COMMAND, option)); }; async function setupSecretsStorage() { const instance = new SecretsStorageImpl(); await instance.initializeStorage(); SecretsStorageSingleton.SINGLETON = instance; } export const init = async () => { const { debug } = getLogger(); if (initialized) { return; } initialized = true; const resultHandler = new ResultHandlerImpl(); ResultHandlerFactory.set(resultHandler); registerMandatoryOptions(); await setHost(); await setTenant(); await initCacheTolerant(); await setupSecretsStorage(); const cliName = getConfig()[CLI_NAME]; program = createCommand(); program.name(cliName); program.version(getVersion(), "-v, --version", "output the current version"); program.description(getConfig()[CLI_DESCRIPTION]); program.showHelpAfterError(`Make sure to always define the host using the --host option or by running ${cliName}` + ` config host set "<Server_URL>". Did you initialize the CLI by running ${cliName} config` + ` cache init --host "<Server_URL>"?` + ` Add option --help, -h or go to ${getConfig()[CLI_SAP_HELP]} for additional information.`); program.addOption(await buildOption(ROOT_COMMAND, OPTION_HOST)); program.addOption(await buildOption(ROOT_COMMAND, OPTION_OPTIONS_FILE)); program.configureHelp({ sortSubcommands: true }); program.addHelpText("afterAll", `Only command-specific options are listed here. To learn more about available generic options,` + ` visit ${getGenericOptionsHelp()}`); const commandsPath = path.join(import.meta.dirname, "..", "commands"); await addCommandsFromFolder(commandsPath, program); debug("cli initialized"); }; export const executeCommand = async (command) => { await program.parseAsync(command?.split(" ") ?? undefined); }; const buildCommandsObject = (name, command, object = {}) => { const commandName = name || "dwc"; // eslint-disable-next-line no-param-reassign object[commandName] = async (options) => { await executeCommand(new Array(2) .fill("dummy") .concat(name.split(" ").concat(options ? Object.entries(options).reduce((prev, curr) => { const [key, value] = curr; return prev.concat([key, value]); }, []) : [])) .join(" ")); return ResultHandlerFactory.get().getResult(); }; /* istanbul ignore next */ command.commands.forEach((c) => { buildCommandsObject(name ? `${name} ${c.name()}` : c.name(), c, object); }); return object; }; const reinitialize = (host) => { initialized = false; initializeConfig(); setConfig({ tenant: host }); setCustomConfig(); clearDiscovery(); }; export const getCommands = async (host) => { reinitialize(host); await init(); return buildCommandsObject("", program); };