@sap/cli-core
Version:
Command-Line Interface (CLI) Core Module
130 lines (129 loc) • 4.6 kB
JavaScript
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" };
};