couchbase-index-manager
Version:
Manage Couchbase indexes during the CI/CD process
194 lines • 7.43 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefinitionLoader = void 0;
const tslib_1 = require("tslib");
const chalk_1 = tslib_1.__importDefault(require("chalk"));
const fs_1 = tslib_1.__importDefault(require("fs"));
const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
const lodash_1 = require("lodash");
const path_1 = tslib_1.__importDefault(require("path"));
const util_1 = tslib_1.__importDefault(require("util"));
const configuration_1 = require("../configuration");
const index_definition_1 = require("./index-definition");
const node_map_1 = require("./node-map");
const lstat = util_1.default.promisify(fs_1.default.lstat);
const readdir = util_1.default.promisify(fs_1.default.readdir);
const readFile = util_1.default.promisify(fs_1.default.readFile);
const INDEX_EXTENSIONS = ['.json', '.yaml', '.yml'];
function validateConfiguration(validatorSet, configuration) {
var _a;
let key;
for (key in validatorSet) {
try {
if (key !== 'post_validate') {
(_a = validatorSet[key]) === null || _a === void 0 ? void 0 : _a.call(configuration, configuration[key]);
}
}
catch (e) {
throw new Error(`${e} in ${configuration.name || 'unk'}.${new String(key)}`);
}
}
// Don't perform post_validate step on overrides, as overrides
// don't have the full set of properties.
if (validatorSet.post_validate && !(0, configuration_1.isOverride)(configuration)) {
try {
validatorSet.post_validate.call(configuration);
}
catch (e) {
throw new Error(`${e} in ${configuration.name || 'unk'}`);
}
}
}
/**
* Loads index definitions from disk or stdin
*/
class DefinitionLoader {
constructor(logger) {
this.logger = logger || console;
}
/**
* Loads definitions from disk
*/
async loadDefinitions(paths) {
const definitions = [];
const nodeMap = new node_map_1.NodeMap();
let files = [];
for (const filePath of paths) {
if (filePath === '-') {
// read from stdin
await this.loadFromStdIn((def) => this.processConfiguration(definitions, nodeMap, def));
continue;
}
try {
if ((await lstat(filePath)).isDirectory()) {
const filesInDir = await readdir(filePath);
const joinedFilesInDir = filesInDir.map((fileName) => path_1.default.join(filePath, fileName));
files.push(...joinedFilesInDir);
}
else {
files.push(filePath);
}
}
catch (_a) {
throw new Error('Path not found');
}
}
// Only look at specific file types
files = files.filter((filename) => INDEX_EXTENSIONS.includes(path_1.default.extname(filename).toLowerCase()));
for (let i = 0; i < files.length; i++) {
await this.loadDefinition(files[i], (def) => this.processConfiguration(definitions, nodeMap, def));
}
return {
definitions,
nodeMap,
};
}
/**
* Loads index definitions from a file
*/
async loadDefinition(filename, handler) {
const ext = path_1.default.extname(filename).toLowerCase();
const contents = await readFile(filename, 'utf8');
if (ext === '.json') {
handler(JSON.parse(contents));
}
else if (ext === '.yaml' || ext === '.yml') {
js_yaml_1.default.loadAll(contents, handler);
}
}
/**
* @private
* Loads index definitions from stdin
*/
loadFromStdIn(handler) {
return new Promise((resolve, reject) => {
process.stdin.resume();
process.stdin.setEncoding('utf8');
let data = '';
process.stdin.on('data', (chunk) => {
data += chunk.toString();
});
process.stdin.on('end', () => {
try {
if (/^\s*{/.exec(data)) {
// Appears to be JSON
handler(JSON.parse(data));
}
else {
// Assume it's YAML
js_yaml_1.default.loadAll(data, handler);
}
resolve();
}
catch (e) {
reject(e);
}
});
});
}
/**
* Processes a definition and adds to the current definitions or
* applies overrides to the matching definition
*/
processConfiguration(definitions, nodeMap, configuration) {
let match;
if ((0, configuration_1.isOverride)(configuration) || (0, configuration_1.isIndex)(configuration)) {
match = definitions.find((p) => (0, configuration_1.isSameIndex)(p, configuration));
}
if (configuration.type === undefined) {
configuration.type = configuration_1.ConfigurationType.Index;
}
this.validateConfiguration(configuration, match);
if ((0, configuration_1.isNodeMap)(configuration)) {
if (configuration.map && (0, lodash_1.isObjectLike)(configuration.map)) {
nodeMap.merge(configuration.map);
}
else {
throw new Error('Invalid nodeMap');
}
}
else if ((0, configuration_1.isOverride)(configuration)) {
// Override definition
if (match) {
match.applyOverride(configuration);
}
else {
// Ignore overrides with no matching index
this.logger.warn(chalk_1.default.yellowBright(`No index definition found '${configuration.name}'`));
}
}
else if ((0, configuration_1.isIndex)(configuration)) {
// Regular index definition
if (match) {
throw new Error(`Duplicate index definition '${configuration.name}'`);
}
definitions.push(new index_definition_1.IndexDefinition(configuration));
}
else {
throw new Error(`Unknown definition type '${configuration.type}'`);
}
}
/**
* Validates a definition based on its type, throwing an exception
* if there is a problem.
*/
validateConfiguration(configuration, match) {
let effectiveType = configuration.type;
if (effectiveType === configuration_1.ConfigurationType.Override && match) {
// Use validators based on the type of definition being overriden
if (match instanceof index_definition_1.IndexDefinition) {
effectiveType = configuration_1.ConfigurationType.Index;
}
}
switch (effectiveType) {
case configuration_1.ConfigurationType.Index:
validateConfiguration(configuration_1.IndexValidators, configuration);
break;
case configuration_1.ConfigurationType.NodeMap:
validateConfiguration(configuration_1.NodeMapValidators, configuration);
break;
}
}
}
exports.DefinitionLoader = DefinitionLoader;
//# sourceMappingURL=definition-loader.js.map