UNPKG

@sap/cli-core

Version:

Command-Line Interface (CLI) Core Module

130 lines (129 loc) 4.6 kB
import fs from "fs-extra"; import path from "path"; import { getPath, readFile as readFileFromCache, writeFile as writeFileToCache, } from "../cache/index.js"; import { getDiscoveryPaths, getVersion } from "../config/core.js"; import { get as getConfig } from "../config/index.js"; import { DISCOVERY_DOCUMENT_PREFIX, DISCOVERY_METADATA_PATH, } from "../constants.js"; import { get } from "../logger/index.js"; import { parseVersion, sha256 } from "../utils/utils.js"; import { validate } from "./utils.js"; const getLogger = () => get("discovery"); let initialized = false; let document; let metadata; function getHash(tenant) { return sha256(`${tenant}${JSON.stringify(getDiscoveryPaths())}`).replace(/[/\\]/g, "_"); } const getDocumentName = () => { const { trace } = getLogger(); const config = getConfig(); const hash = getHash(config.publicfqdn); const name = `${DISCOVERY_DOCUMENT_PREFIX}${hash}.json`; trace(`calculating document name for host ${config.host}, name ${name}`); return name; }; export const getPathToDiscoveryDocument = () => getPath(getDocumentName()); const initMetadata = async () => { const { error } = getLogger(); if (!metadata) { try { metadata = JSON.parse(await readFileFromCache(DISCOVERY_METADATA_PATH)); } catch (err) { error("error while reading discovery metadata", err.stack); metadata = []; } } }; export const getMetadata = async () => { await initMetadata(); return metadata; }; export const addMetadata = async ({ tenant, addedAt, }) => { await initMetadata(); metadata = metadata.filter((t) => t.tenant !== tenant); const hash = getHash(tenant); metadata.push({ tenant, addedAt, hash }); await writeFileToCache(DISCOVERY_METADATA_PATH, JSON.stringify(metadata)); }; export const clear = () => { initialized = false; document = undefined; metadata = undefined; }; /* jscpd:ignore-start */ export const init = async () => { const { trace, error, debug } = getLogger(); if (initialized) { return document; } initialized = true; /* jscpd:ignore-end */ let schema; try { trace("reading discovery document"); const file = await readFileFromCache(getDocumentName()); document = JSON.parse(file); } catch (err) { error("error while reading discovery document", err.stack); throw err; } try { trace("reading schema document"); try { const file = await fs.readFile(path.join(import.meta.dirname, "..", "..", "schemas", "discovery.json"), "utf-8"); schema = JSON.parse(file); } catch (err) { debug("failed reading schema, trying again", err.stack); // path changes after build const file = await fs.readFile(path.join(import.meta.dirname, "..", "schemas", "discovery.json"), "utf-8"); schema = JSON.parse(file); } } catch (err) { error("error while reading schema document", err.stack); throw err; } debug("validating discovery document against schema"); const result = await validate(schema, document); if (result.result === "INVALID") { error("discovery document contains invalid data", result.errors); throw new Error("discovery document contains invalid data"); } return document; }; export const compareEtags = async () => { const { debug, error } = getLogger(); try { const doc = await init(); const config = getConfig(); if (config.etag && doc) { const etag = sha256(JSON.stringify(doc)); if (config.etag === etag) { debug("etags match: %s", config.etag); return true; } debug("etags do not match. server: %s, client: %s", config.etag, etag); return false; } debug("etag is not available"); } catch (err) { error("failed to compare etags", err.stack); } return true; }; export const checkVersion = async () => { const { debug } = getLogger(); const doc = await init(); const local = parseVersion(getVersion()); const server = parseVersion(doc.info["x-document-version"]); if (local.major < server.major || (local.major === server.major && local.minor < server.minor)) { debug(`CLI is outdated (local: ${JSON.stringify(local)}, server: ${JSON.stringify(server)})`); return { status: "OUTDATED" }; } return { status: "UPTODATE" }; };