1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 |
|
7 | var _promise = require('babel-runtime/core-js/promise');
|
8 |
|
9 | var _promise2 = _interopRequireDefault(_promise);
|
10 |
|
11 | var _maxSafeInteger = require('babel-runtime/core-js/number/max-safe-integer');
|
12 |
|
13 | var _maxSafeInteger2 = _interopRequireDefault(_maxSafeInteger);
|
14 |
|
15 | var _from = require('babel-runtime/core-js/array/from');
|
16 |
|
17 | var _from2 = _interopRequireDefault(_from);
|
18 |
|
19 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
|
20 |
|
21 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
|
22 |
|
23 | var _lodash = require('lodash');
|
24 |
|
25 | var _lodash2 = _interopRequireDefault(_lodash);
|
26 |
|
27 | var _path = require('path');
|
28 |
|
29 | var _path2 = _interopRequireDefault(_path);
|
30 |
|
31 | var _readdirEnhanced = require('readdir-enhanced');
|
32 |
|
33 | var _readdirEnhanced2 = _interopRequireDefault(_readdirEnhanced);
|
34 |
|
35 | var _State = require('./State');
|
36 |
|
37 | var _State2 = _interopRequireDefault(_State);
|
38 |
|
39 | var _StateConsumer = require('./StateConsumer');
|
40 |
|
41 | var _StateConsumer2 = _interopRequireDefault(_StateConsumer);
|
42 |
|
43 | var _File = require('./File');
|
44 |
|
45 | var _File2 = _interopRequireDefault(_File);
|
46 |
|
47 | var _Rule = require('./Rule');
|
48 |
|
49 | var _Rule2 = _interopRequireDefault(_Rule);
|
50 |
|
51 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
52 |
|
53 | const VALID_COMMAND_PATTERN = /^(build|clean|graph|load|log|save|scrub)$/;
|
54 |
|
55 | class DiCy extends _StateConsumer2.default {
|
56 | static create(filePath, options = {}) {
|
57 | return (0, _asyncToGenerator3.default)(function* () {
|
58 | const schema = yield DiCy.getOptionDefinitions();
|
59 | const state = new _State2.default(filePath, schema);
|
60 | const builder = new DiCy(state, state.getJobOptions());
|
61 |
|
62 | yield builder.initialize();
|
63 | yield builder.setInstanceOptions(options);
|
64 |
|
65 | state.assignOptions(options);
|
66 |
|
67 | return builder;
|
68 | })();
|
69 | }
|
70 |
|
71 | initialize() {
|
72 | var _this = this;
|
73 |
|
74 | return (0, _asyncToGenerator3.default)(function* () {
|
75 | const ruleClassPath = _path2.default.join(__dirname, 'Rules');
|
76 | const entries = yield _readdirEnhanced2.default.async(ruleClassPath);
|
77 | _this.state.ruleClasses = entries.map(function (entry) {
|
78 | return require(_path2.default.join(ruleClassPath, entry)).default;
|
79 | });
|
80 | })();
|
81 | }
|
82 |
|
83 | setInstanceOptions(options = {}) {
|
84 | var _this2 = this;
|
85 |
|
86 | return (0, _asyncToGenerator3.default)(function* () {
|
87 | const instance = yield _this2.getFile('dicy-instance.yaml-ParsedYAML');
|
88 | if (instance) instance.value = options;
|
89 | })();
|
90 | }
|
91 |
|
92 | analyzePhase(command, phase) {
|
93 | var _this3 = this;
|
94 |
|
95 | return (0, _asyncToGenerator3.default)(function* () {
|
96 | _this3.checkForKill();
|
97 |
|
98 | for (const ruleClass of _this3.ruleClasses) {
|
99 | const jobNames = ruleClass.ignoreJobName ? [null] : _this3.options.jobNames;
|
100 | for (const jobName of jobNames) {
|
101 | const rule = yield ruleClass.analyzePhase(_this3.state, command, phase, _this3.state.getJobOptions(jobName));
|
102 | if (rule) {
|
103 | yield _this3.addRule(rule);
|
104 | }
|
105 | }
|
106 | }
|
107 | })();
|
108 | }
|
109 |
|
110 | analyzeFiles(command, phase) {
|
111 | var _this4 = this;
|
112 |
|
113 | return (0, _asyncToGenerator3.default)(function* () {
|
114 | _this4.checkForKill();
|
115 |
|
116 | while (true) {
|
117 | const file = (0, _from2.default)(_this4.files).find(function (file) {
|
118 | return !file.analyzed;
|
119 | });
|
120 |
|
121 | if (!file) break;
|
122 |
|
123 | for (const ruleClass of _this4.ruleClasses) {
|
124 | const jobNames = file.jobNames.size === 0 ? [null] : (0, _from2.default)(file.jobNames.values());
|
125 | for (const jobName of jobNames) {
|
126 | const rules = yield ruleClass.analyzeFile(_this4.state, command, phase, _this4.state.getJobOptions(jobName), file);
|
127 | for (const rule of rules) {
|
128 | yield _this4.addRule(rule);
|
129 | }
|
130 | }
|
131 | }
|
132 |
|
133 | file.analyzed = true;
|
134 | }
|
135 | })();
|
136 | }
|
137 |
|
138 | getAvailableRules(command) {
|
139 | return this.ruleClasses.filter(rule => !command || rule.commands.has(command)).map(rule => ({ name: rule.name, description: rule.description }));
|
140 | }
|
141 |
|
142 | evaluateRule(rule, action) {
|
143 | var _this5 = this;
|
144 |
|
145 | return (0, _asyncToGenerator3.default)(function* () {
|
146 | _this5.checkForKill();
|
147 |
|
148 | if (rule.failures.has(action)) {
|
149 | _this5.info(`Skipping rule ${rule.id} because of previous failure.`);
|
150 | return false;
|
151 | }
|
152 |
|
153 | yield rule.evaluate(action);
|
154 | return true;
|
155 | })();
|
156 | }
|
157 |
|
158 | evaluate(command, phase, action) {
|
159 | var _this6 = this;
|
160 |
|
161 | return (0, _asyncToGenerator3.default)(function* () {
|
162 | _this6.checkForKill();
|
163 |
|
164 | const primaryCount = function (ruleGroup) {
|
165 | return ruleGroup.reduce(function (total, rule) {
|
166 | return total + rule.parameters.reduce(function (count, parameter) {
|
167 | return parameter.filePath === _this6.filePath ? count + 1 : count;
|
168 | }, 0);
|
169 | }, 0);
|
170 | };
|
171 | const evaluationNeeded = function (rule) {
|
172 | return rule.actions.has(action) && rule.command === command && rule.phase === phase;
|
173 | };
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 | const rules = _lodash2.default.flatten(_lodash2.default.sortBy(_this6.components.map(function (component) {
|
186 | const ruleGroup = _lodash2.default.sortBy(component.filter(evaluationNeeded), [function (rule) {
|
187 | return rule.inputs.length;
|
188 | }]);
|
189 |
|
190 | return ruleGroup.reduce(function (current, rule) {
|
191 |
|
192 | const rank = ruleGroup.reduce(function (count, otherRule) {
|
193 | return _this6.isGrandparentOf(rule, otherRule) ? count + 1 : count;
|
194 | }, 0);
|
195 |
|
196 |
|
197 | if (rank < current.rank) return { rank, rules: [rule]
|
198 |
|
199 | };if (rank === current.rank) current.rules.push(rule);
|
200 |
|
201 |
|
202 | return current;
|
203 | }, { rank: _maxSafeInteger2.default, rules: [] }).rules;
|
204 | }), [primaryCount]));
|
205 |
|
206 | if (rules.length === 0) return false;
|
207 |
|
208 | let didEvaluation = false;
|
209 |
|
210 | for (const rule of rules) {
|
211 | yield _this6.checkUpdates(command, phase);
|
212 | didEvaluation = (yield _this6.evaluateRule(rule, action)) || didEvaluation;
|
213 | }
|
214 |
|
215 | yield _this6.checkUpdates(command, phase);
|
216 |
|
217 | return didEvaluation;
|
218 | })();
|
219 | }
|
220 |
|
221 | checkUpdates(command, phase) {
|
222 | var _this7 = this;
|
223 |
|
224 | return (0, _asyncToGenerator3.default)(function* () {
|
225 | _this7.checkForKill();
|
226 |
|
227 | for (const file of _this7.files) {
|
228 | for (const rule of _this7.state.getInputRules(file)) {
|
229 | yield rule.addFileActions(file, command, phase);
|
230 | }
|
231 | file.hasBeenUpdated = false;
|
232 | }
|
233 | })();
|
234 | }
|
235 |
|
236 | kill(message = 'Build was killed.') {
|
237 | if (!this.killToken) return _promise2.default.resolve();
|
238 |
|
239 | if (!this.killToken.promise) {
|
240 | this.killToken.error = new Error(message);
|
241 | this.killToken.promise = new _promise2.default(resolve => {
|
242 |
|
243 | this.killToken.resolve = resolve;
|
244 | this.killChildProcesses();
|
245 | });
|
246 | }
|
247 |
|
248 | return this.killToken.promise;
|
249 | }
|
250 |
|
251 | run(...commands) {
|
252 | var _this8 = this;
|
253 |
|
254 | return (0, _asyncToGenerator3.default)(function* () {
|
255 | if (_this8.killToken) {
|
256 | _this8.error('Build currently in progress');
|
257 | return false;
|
258 | }
|
259 |
|
260 | const invalidCommands = commands.filter(function (command) {
|
261 | return !VALID_COMMAND_PATTERN.test(command);
|
262 | });
|
263 | if (invalidCommands.length !== 0) {
|
264 | _this8.error(`Aborting due to receiving the following invalid commands: ${invalidCommands.join(', ')}`);
|
265 | return false;
|
266 | }
|
267 |
|
268 | _this8.killToken = {};
|
269 |
|
270 | let success = true;
|
271 |
|
272 | try {
|
273 | for (const command of commands) {
|
274 | for (const phase of ['initialize', 'execute', 'finalize']) {
|
275 | yield _this8.runPhase(command, phase);
|
276 | }
|
277 | }
|
278 | success = (0, _from2.default)(_this8.rules).every(function (rule) {
|
279 | return rule.failures.size === 0;
|
280 | });
|
281 | } catch (error) {
|
282 | success = false;
|
283 | _this8.error(error.stack);
|
284 | } finally {
|
285 | if (_this8.killToken && _this8.killToken.resolve) {
|
286 | success = false;
|
287 | _this8.killToken.resolve();
|
288 | }
|
289 | _this8.killToken = null;
|
290 | }
|
291 |
|
292 | return success;
|
293 | })();
|
294 | }
|
295 |
|
296 | runPhase(command, phase) {
|
297 | var _this9 = this;
|
298 |
|
299 | return (0, _asyncToGenerator3.default)(function* () {
|
300 | _this9.checkForKill();
|
301 |
|
302 | for (const file of _this9.files) {
|
303 | file.hasBeenUpdated = file.hasBeenUpdatedCache;
|
304 | file.analyzed = false;
|
305 | }
|
306 |
|
307 | for (const rule of _this9.rules) {
|
308 | yield rule.phaseInitialize(command, phase);
|
309 | }
|
310 |
|
311 | yield _this9.analyzePhase(command, phase);
|
312 |
|
313 | for (let cycle = 0; cycle < _this9.options.phaseCycles; cycle++) {
|
314 | let didEvaluation = false;
|
315 |
|
316 | for (const action of ['parse', 'updateDependencies', 'run']) {
|
317 | yield _this9.analyzeFiles(command, phase);
|
318 | didEvaluation = (yield _this9.evaluate(command, phase, action)) || didEvaluation;
|
319 | }
|
320 |
|
321 | if ((0, _from2.default)(_this9.files).every(function (file) {
|
322 | return file.analyzed;
|
323 | }) && (0, _from2.default)(_this9.rules).every(function (rule) {
|
324 | return rule.command !== command || rule.phase !== phase || !rule.needsEvaluation;
|
325 | })) break;
|
326 |
|
327 | if (!didEvaluation) break;
|
328 | }
|
329 | })();
|
330 | }
|
331 |
|
332 | static getOptionDefinitions() {
|
333 | return (0, _asyncToGenerator3.default)(function* () {
|
334 | const filePath = _path2.default.resolve(__dirname, '..', 'resources', 'option-schema.yaml');
|
335 | const schema = yield _File2.default.load(filePath);
|
336 | const options = [];
|
337 | for (const name in schema) {
|
338 | const option = schema[name];
|
339 | option.name = name;
|
340 | options.push(option);
|
341 | }
|
342 | return options;
|
343 | })();
|
344 | }
|
345 |
|
346 | updateOptions(options = {}, user = false) {
|
347 | var _this10 = this;
|
348 |
|
349 | return (0, _asyncToGenerator3.default)(function* () {
|
350 | const normalizedOptions = {};
|
351 | const filePath = _this10.resolvePath(user ? '$HOME/.dicy.yaml' : '$ROOTDIR/$NAME.yaml');
|
352 |
|
353 | if (yield _File2.default.canRead(filePath)) {
|
354 | const currentOptions = yield _File2.default.safeLoad(filePath);
|
355 | _this10.state.assignSubOptions(normalizedOptions, currentOptions);
|
356 | }
|
357 |
|
358 | _this10.state.assignSubOptions(normalizedOptions, options);
|
359 | yield _File2.default.safeDump(filePath, normalizedOptions);
|
360 |
|
361 | return normalizedOptions;
|
362 | })();
|
363 | }
|
364 | }
|
365 | exports.default = DiCy; |
\ | No newline at end of file |