@atomist/sdm-core
Version:
Atomist Software Delivery Machine - Implementation
231 lines • 9.94 kB
JavaScript
/*
* Copyright © 2019 Atomist, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const automation_client_1 = require("@atomist/automation-client");
const sdm_1 = require("@atomist/sdm");
const _ = require("lodash");
const array_1 = require("../../util/misc/array");
const CompressingGoalCache_1 = require("./CompressingGoalCache");
exports.CacheInputGoalDataKey = "@atomist/sdm/input";
exports.CacheOutputGoalDataKey = "@atomist/sdm/output";
const DefaultGoalCache = new CompressingGoalCache_1.CompressingGoalCache();
/**
* Goal listener that performs caching after a goal has been run.
* @param options The options for caching
* @param classifier Whether only a specific classifier, as defined in the options,
* needs to be cached. If omitted, all classifiers are cached.
* @param classifiers Additional classifiers that need to be created.
*/
function cachePut(options, classifier, ...classifiers) {
const allClassifiers = [];
if (classifier) {
allClassifiers.push(classifier, ...(classifiers || []));
}
const entries = !!classifier ?
options.entries.filter(pattern => allClassifiers.includes(pattern.classifier)) :
options.entries;
const listenerName = `caching outputs`;
return {
name: listenerName,
listener: (p, gi) => __awaiter(this, void 0, void 0, function* () {
if (!!isCacheEnabled(gi) && !process.env.ATOMIST_ISOLATED_GOAL_INIT) {
const goalCache = cacheStore(gi);
for (const entry of entries) {
const files = [];
if (isGlobFilePattern(entry.pattern)) {
files.push(...(yield getFilePathsThroughPattern(p, entry.pattern.globPattern)));
}
else if (isDirectoryPattern(entry.pattern)) {
files.push(entry.pattern.directory);
}
if (!_.isEmpty(files)) {
yield goalCache.put(gi, p, files, entry.classifier);
}
}
// Set outputs on the goal data
const { goalEvent } = gi;
const data = JSON.parse(goalEvent.data || "{}");
const newData = {
[exports.CacheOutputGoalDataKey]: [
...(data[exports.CacheOutputGoalDataKey] || []),
...entries,
],
};
goalEvent.data = JSON.stringify(Object.assign(Object.assign({}, (JSON.parse(goalEvent.data || "{}"))), newData));
}
}),
pushTest: options.pushTest,
events: [sdm_1.GoalProjectListenerEvent.after],
};
}
exports.cachePut = cachePut;
function isGlobFilePattern(toBeDetermined) {
return toBeDetermined.globPattern !== undefined;
}
function isDirectoryPattern(toBeDetermined) {
return toBeDetermined.directory !== undefined;
}
function pushTestSucceeds(pushTest, gi, p) {
return __awaiter(this, void 0, void 0, function* () {
return (pushTest || sdm_1.AnyPush).mapping({
push: gi.goalEvent.push,
project: p,
id: gi.id,
configuration: gi.configuration,
addressChannels: gi.addressChannels,
context: gi.context,
preferences: gi.preferences,
credentials: gi.credentials,
});
});
}
function invokeCacheMissListeners(optsToUse, p, gi, event) {
return __awaiter(this, void 0, void 0, function* () {
for (const cacheMissFallback of array_1.toArray(optsToUse.onCacheMiss)) {
const allEvents = [sdm_1.GoalProjectListenerEvent.before, sdm_1.GoalProjectListenerEvent.after];
if ((cacheMissFallback.events || allEvents).filter(e => e === event).length > 0
&& (yield pushTestSucceeds(cacheMissFallback.pushTest, gi, p))) {
yield cacheMissFallback.listener(p, gi, event);
}
}
});
}
exports.NoOpGoalProjectListenerRegistration = {
name: "NoOpListener",
listener: () => __awaiter(void 0, void 0, void 0, function* () {
}),
pushTest: sdm_1.AnyPush,
};
/**
* Goal listener that performs cache restores before a goal has been run.
* @param options The options for caching
* @param classifier Whether only a specific classifier, as defined in the options,
* needs to be restored. If omitted, all classifiers defined in the options are restored.
* @param classifiers Additional classifiers that need to be restored.
*/
function cacheRestore(options, classifier, ...classifiers) {
const allClassifiers = [];
if (classifier) {
allClassifiers.push(classifier, ...(classifiers || []));
}
const optsToUse = Object.assign({ onCacheMiss: exports.NoOpGoalProjectListenerRegistration }, options);
const classifiersToBeRestored = [];
if (allClassifiers.length > 0) {
classifiersToBeRestored.push(...allClassifiers);
}
else {
classifiersToBeRestored.push(...optsToUse.entries.map(entry => entry.classifier));
}
const listenerName = `restoring inputs`;
return {
name: listenerName,
listener: (p, gi, event) => __awaiter(this, void 0, void 0, function* () {
if (!!isCacheEnabled(gi)) {
const goalCache = cacheStore(gi);
for (const c of classifiersToBeRestored) {
try {
yield goalCache.retrieve(gi, p, c);
}
catch (e) {
yield invokeCacheMissListeners(optsToUse, p, gi, event);
}
}
}
else {
yield invokeCacheMissListeners(optsToUse, p, gi, event);
}
// Set inputs on the goal data
const { goalEvent } = gi;
const data = JSON.parse(goalEvent.data || "{}");
const newData = {
[exports.CacheInputGoalDataKey]: [
...(data[exports.CacheInputGoalDataKey] || []),
...classifiersToBeRestored.map(c => ({
classifier: c,
})),
],
};
goalEvent.data = JSON.stringify(Object.assign(Object.assign({}, (JSON.parse(goalEvent.data || "{}"))), newData));
}),
pushTest: optsToUse.pushTest,
events: [sdm_1.GoalProjectListenerEvent.before],
};
}
exports.cacheRestore = cacheRestore;
/**
* Goal listener that cleans up the cache restores after a goal has been run.
* @param options The options for caching
* @param classifier Whether only a specific classifier, as defined in the options,
* needs to be removed. If omitted, all classifiers are removed.
* @param classifiers Additional classifiers that need to be removed.
*/
function cacheRemove(options, classifier, ...classifiers) {
const allClassifiers = [];
if (classifier) {
allClassifiers.push(...[classifier, ...classifiers]);
}
const classifiersToBeRemoved = [];
if (allClassifiers.length > 0) {
classifiersToBeRemoved.push(...allClassifiers);
}
else {
classifiersToBeRemoved.push(...options.entries.map(entry => entry.classifier));
}
const listenerName = `removing outputs`;
return {
name: listenerName,
listener: (p, gi) => __awaiter(this, void 0, void 0, function* () {
if (!!isCacheEnabled(gi)) {
const goalCache = cacheStore(gi);
for (const c of classifiersToBeRemoved) {
yield goalCache.remove(gi, c);
}
}
}),
pushTest: options.pushTest,
events: [sdm_1.GoalProjectListenerEvent.after],
};
}
exports.cacheRemove = cacheRemove;
function getFilePathsThroughPattern(project, globPattern) {
return __awaiter(this, void 0, void 0, function* () {
const oldExcludes = automation_client_1.DefaultExcludes;
automation_client_1.DefaultExcludes.splice(0, automation_client_1.DefaultExcludes.length); // necessary evil
try {
return yield automation_client_1.projectUtils.gatherFromFiles(project, globPattern, (f) => __awaiter(this, void 0, void 0, function* () { return f.path; }));
}
finally {
automation_client_1.DefaultExcludes.push(...oldExcludes);
}
});
}
function isCacheEnabled(gi) {
return _.get(gi.configuration, "sdm.cache.enabled", false);
}
function cacheStore(gi) {
return _.get(gi.configuration, "sdm.cache.store", DefaultGoalCache);
}
//# sourceMappingURL=goalCaching.js.map
;