1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 |
|
7 | var _from = require('babel-runtime/core-js/array/from');
|
8 |
|
9 | var _from2 = _interopRequireDefault(_from);
|
10 |
|
11 | var _keys = require('babel-runtime/core-js/object/keys');
|
12 |
|
13 | var _keys2 = _interopRequireDefault(_keys);
|
14 |
|
15 | var _getOwnPropertyNames = require('babel-runtime/core-js/object/get-own-property-names');
|
16 |
|
17 | var _getOwnPropertyNames2 = _interopRequireDefault(_getOwnPropertyNames);
|
18 |
|
19 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
|
20 |
|
21 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
|
22 |
|
23 | var _assign = require('babel-runtime/core-js/object/assign');
|
24 |
|
25 | var _assign2 = _interopRequireDefault(_assign);
|
26 |
|
27 | var _set = require('babel-runtime/core-js/set');
|
28 |
|
29 | var _set2 = _interopRequireDefault(_set);
|
30 |
|
31 | var _map = require('babel-runtime/core-js/map');
|
32 |
|
33 | var _map2 = _interopRequireDefault(_map);
|
34 |
|
35 | var _graphlib = require('graphlib');
|
36 |
|
37 | var _events = require('events');
|
38 |
|
39 | var _events2 = _interopRequireDefault(_events);
|
40 |
|
41 | var _path = require('path');
|
42 |
|
43 | var _path2 = _interopRequireDefault(_path);
|
44 |
|
45 | var _File = require('./File');
|
46 |
|
47 | var _File2 = _interopRequireDefault(_File);
|
48 |
|
49 | var _Rule = require('./Rule');
|
50 |
|
51 | var _Rule2 = _interopRequireDefault(_Rule);
|
52 |
|
53 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
54 |
|
55 | function getLabel(x) {
|
56 | return x instanceof _File2.default ? x.filePath : x.id;
|
57 | }
|
58 |
|
59 |
|
60 | class State extends _events2.default {
|
61 |
|
62 | constructor(filePath, schema = []) {
|
63 | super();
|
64 | this.files = new _map2.default();
|
65 | this.rules = new _map2.default();
|
66 | this.options = {};
|
67 | this.defaultOptions = {};
|
68 | this.optionSchema = new _map2.default();
|
69 | this.graphProperties = {};
|
70 | this.ruleClasses = [];
|
71 | this.processes = new _set2.default();
|
72 | this.targets = new _set2.default();
|
73 | this.graph = new _graphlib.Graph();
|
74 | this.optionProxies = {};
|
75 | const resolveFilePath = _path2.default.resolve(filePath);
|
76 | const { dir, base, name, ext } = _path2.default.parse(resolveFilePath);
|
77 | this.filePath = base;
|
78 | this.rootPath = dir;
|
79 | for (const option of schema) {
|
80 | this.optionSchema.set(option.name, option);
|
81 | for (const alias of option.aliases || []) {
|
82 | this.optionSchema.set(alias, option);
|
83 | }
|
84 | if (option.defaultValue) this.defaultOptions[option.name] = option.defaultValue;
|
85 | }
|
86 | this.assignOptions(this.defaultOptions);
|
87 |
|
88 | this.env = (0, _assign2.default)({}, process.env, {
|
89 | FILEPATH: base,
|
90 | ROOTDIR: dir,
|
91 | DIR: '.',
|
92 | BASE: base,
|
93 | NAME: name,
|
94 | EXT: ext
|
95 | });
|
96 | if (process.platform === 'win32') {
|
97 | (0, _assign2.default)(this.env, {
|
98 | HOME: process.env.USERPROFILE,
|
99 | PATH: process.env.Path
|
100 | });
|
101 | }
|
102 | }
|
103 |
|
104 | getTargetPaths(absolute = false) {
|
105 | var _this = this;
|
106 |
|
107 | return (0, _asyncToGenerator3.default)(function* () {
|
108 | const results = [];
|
109 | for (const target of _this.targets.values()) {
|
110 | const file = yield _this.getFile(target);
|
111 | if (file) results.push(absolute ? file.realFilePath : target);
|
112 | }
|
113 | return results;
|
114 | })();
|
115 | }
|
116 |
|
117 | getTargetFiles() {
|
118 | var _this2 = this;
|
119 |
|
120 | return (0, _asyncToGenerator3.default)(function* () {
|
121 | const results = [];
|
122 | for (const target of _this2.targets.values()) {
|
123 | const file = yield _this2.getFile(target);
|
124 | if (file) results.push(file);
|
125 | }
|
126 | return results;
|
127 | })();
|
128 | }
|
129 |
|
130 | removeTarget(filePath) {
|
131 | this.targets.delete(filePath);
|
132 | }
|
133 |
|
134 | normalizePath(filePath) {
|
135 | filePath = _path2.default.normalize(filePath);
|
136 |
|
137 | if (_path2.default.isAbsolute(filePath)) {
|
138 | const dirPaths = [this.rootPath];
|
139 |
|
140 | for (const dir of dirPaths) {
|
141 | const candidateFilePath = _path2.default.relative(dir, filePath);
|
142 | if (!candidateFilePath.startsWith('..')) {
|
143 | return candidateFilePath;
|
144 | }
|
145 | }
|
146 | }
|
147 |
|
148 | return filePath;
|
149 | }
|
150 |
|
151 | addRule(rule) {
|
152 | var _this3 = this;
|
153 |
|
154 | return (0, _asyncToGenerator3.default)(function* () {
|
155 | _this3.rules.set(rule.id, rule);
|
156 | _this3.addNode(rule.id);
|
157 | rule.addActions();
|
158 | })();
|
159 | }
|
160 |
|
161 | removeRule(rule) {
|
162 | this.rules.delete(rule.id);
|
163 | this.removeNode(rule.id);
|
164 | }
|
165 |
|
166 | addCachedRule(cache) {
|
167 | var _this4 = this;
|
168 |
|
169 | return (0, _asyncToGenerator3.default)(function* () {
|
170 | const options = _this4.getJobOptions(cache.jobName);
|
171 | const id = _this4.getRuleId(cache.name, cache.command, cache.phase, cache.jobName, cache.parameters);
|
172 | if (_this4.rules.has(id)) return;
|
173 |
|
174 | const RuleClass = _this4.ruleClasses.find(function (ruleClass) {
|
175 | return ruleClass.name === cache.name;
|
176 | });
|
177 | if (RuleClass) {
|
178 | const parameters = [];
|
179 | for (const filePath of cache.parameters) {
|
180 | const parameter = yield _this4.getFile(filePath);
|
181 | if (!parameter) break;
|
182 | parameters.push(parameter);
|
183 | }
|
184 |
|
185 | const rule = new RuleClass(_this4, cache.command, cache.phase, options, parameters);
|
186 | _this4.addNode(rule.id);
|
187 | yield rule.initialize();
|
188 | _this4.rules.set(rule.id, rule);
|
189 | yield rule.getInputs(cache.inputs);
|
190 | const outputs = yield rule.getOutputs(cache.outputs);
|
191 | if (rule.constructor.alwaysEvaluate || outputs.length !== cache.outputs.length) {
|
192 |
|
193 | rule.addActions();
|
194 | }
|
195 | for (const input of rule.inputs) {
|
196 | yield rule.addFileActions(input);
|
197 | }
|
198 | }
|
199 | })();
|
200 | }
|
201 |
|
202 | getRuleId(name, command, phase, jobName, parameters = []) {
|
203 | const items = [command, phase, jobName || ''].concat(parameters);
|
204 | return `${name}(${items.join(';')})`;
|
205 | }
|
206 |
|
207 | getRule(name, command, phase, jobName, parameters = []) {
|
208 | const id = this.getRuleId(name, command, phase, jobName, parameters);
|
209 | return this.rules.get(id);
|
210 | }
|
211 |
|
212 | addNode(x) {
|
213 | this.graph.setNode(x);
|
214 | this.graphProperties = {};
|
215 | }
|
216 |
|
217 | removeNode(x) {
|
218 | this.graph.removeNode(x);
|
219 | this.graphProperties = {};
|
220 | }
|
221 |
|
222 | hasEdge(x, y) {
|
223 | return this.graph.hasEdge(x, y);
|
224 | }
|
225 |
|
226 | addEdge(x, y) {
|
227 | this.graph.setEdge(x, y);
|
228 | this.graphProperties = {};
|
229 | }
|
230 |
|
231 | removeEdge(x, y) {
|
232 | this.graph.removeEdge(x, y);
|
233 | this.graphProperties = {};
|
234 | }
|
235 |
|
236 | getFile(filePath, { timeStamp, hash, value } = {}) {
|
237 | var _this5 = this;
|
238 |
|
239 | return (0, _asyncToGenerator3.default)(function* () {
|
240 | filePath = _this5.normalizePath(filePath);
|
241 | let file = _this5.files.get(filePath);
|
242 |
|
243 | if (!file) {
|
244 | file = yield _File2.default.create(_path2.default.resolve(_this5.rootPath, filePath), filePath, timeStamp, hash, value);
|
245 | if (!file) {
|
246 | _this5.graph.removeNode(filePath);
|
247 | _this5.emit('fileRemoved', {
|
248 | type: 'fileRemoved',
|
249 | file: filePath
|
250 | });
|
251 | return;
|
252 | }
|
253 | _this5.addNode(filePath);
|
254 | _this5.emit('fileAdded', {
|
255 | type: 'fileAdded',
|
256 | file: filePath,
|
257 | virtual: file.virtual
|
258 | });
|
259 | _this5.files.set(filePath, file);
|
260 | }
|
261 |
|
262 | return file;
|
263 | })();
|
264 | }
|
265 |
|
266 | deleteFile(file, jobName, unlink = true) {
|
267 | var _this6 = this;
|
268 |
|
269 | return (0, _asyncToGenerator3.default)(function* () {
|
270 | const invalidRules = [];
|
271 |
|
272 | for (const rule of _this6.rules.values()) {
|
273 | if (rule.jobName === jobName) {
|
274 | if (yield rule.removeFile(file)) {
|
275 |
|
276 |
|
277 | invalidRules.push(rule);
|
278 | }
|
279 | }
|
280 | }
|
281 |
|
282 | for (const rule of invalidRules) {
|
283 | _this6.removeNode(rule.id);
|
284 | }
|
285 |
|
286 | if (jobName) file.jobNames.delete(jobName);
|
287 | if (file.jobNames.size === 0) {
|
288 | if (unlink) {
|
289 | yield file.delete();
|
290 | _this6.emit('fileDeleted', {
|
291 | type: 'fileDeleted',
|
292 | file: file.filePath,
|
293 | virtual: file.virtual
|
294 | });
|
295 | }
|
296 | _this6.removeNode(file.filePath);
|
297 | _this6.files.delete(file.filePath);
|
298 | }
|
299 | })();
|
300 | }
|
301 |
|
302 | assignSubOptions(to, from) {
|
303 | for (const name in from) {
|
304 | if (from.hasOwnProperty(name)) {
|
305 | const value = from[name];
|
306 | if (typeof value !== 'object' || Array.isArray(value)) {
|
307 | const schema = this.optionSchema.get(name);
|
308 | if (schema) {
|
309 | to[schema.name] = value;
|
310 | } else if (name.startsWith('$')) {
|
311 |
|
312 | to[name] = value;
|
313 | } else {
|
314 |
|
315 | }
|
316 | } else {
|
317 | if (!(name in to)) to[name] = {};
|
318 | this.assignSubOptions(to[name], value);
|
319 | }
|
320 | }
|
321 | }
|
322 | }
|
323 |
|
324 | assignOptions(options) {
|
325 | this.assignSubOptions(this.options, options);
|
326 | }
|
327 |
|
328 | resetOptions() {
|
329 | for (const name of (0, _getOwnPropertyNames2.default)(this.options)) {
|
330 | delete this.options[name];
|
331 | }
|
332 |
|
333 | this.assignOptions(this.defaultOptions);
|
334 | }
|
335 |
|
336 | getJobOptions(jobName = null) {
|
337 | let optionProxy = this.optionProxies[jobName];
|
338 |
|
339 | if (!optionProxy) {
|
340 | this.optionProxies[jobName] = optionProxy = new Proxy(this.options, {
|
341 | get: (target, name) => {
|
342 | if (name === 'jobNames') {
|
343 | if ('jobName' in target) return [target.jobName];
|
344 | if ('jobNames' in target) return target.jobNames;
|
345 | if ('jobs' in target) return (0, _keys2.default)(target.jobs);
|
346 | return [null];
|
347 | }
|
348 |
|
349 | if (jobName) {
|
350 | if (name === 'jobName') return jobName;
|
351 | if ('jobs' in target) {
|
352 | const jobOptions = target.jobs[jobName];
|
353 | if (jobOptions && name in jobOptions) return jobOptions[name];
|
354 | }
|
355 | }
|
356 |
|
357 | const schema = this.optionSchema.get(name);
|
358 |
|
359 | if (schema && schema.type === 'boolean') {
|
360 | return !!target[name];
|
361 | }
|
362 |
|
363 | return name === 'filePath' ? this.filePath : target[name];
|
364 | },
|
365 | ownKeys: target => {
|
366 | const keys = new _set2.default(['filePath', 'jobNames']);
|
367 |
|
368 | if (jobName && 'jobs' in target) {
|
369 | const jobOptions = target.jobs[jobName];
|
370 | if (jobOptions) (0, _keys2.default)(jobOptions).forEach(key => keys.add(key));
|
371 | }
|
372 |
|
373 | this.optionSchema.forEach(option => {
|
374 | if (option.type === 'boolean') keys.add(option.name);
|
375 | });
|
376 |
|
377 | (0, _keys2.default)(target).forEach(key => keys.add(key));
|
378 |
|
379 | keys.delete('jobs');
|
380 |
|
381 | return (0, _from2.default)(keys.values());
|
382 | }
|
383 | });
|
384 | }
|
385 |
|
386 | return optionProxy;
|
387 | }
|
388 |
|
389 | get components() {
|
390 | if (!this.graphProperties.components) {
|
391 | this.graphProperties.components = _graphlib.alg.components(this.graph).map(component => component.map(id => this.rules.get(id)).filter(rule => rule)).filter(component => component.length > 0);
|
392 | }
|
393 |
|
394 | return this.graphProperties.components;
|
395 | }
|
396 |
|
397 | isGrandparentOf(x, y) {
|
398 | const xLabel = getLabel(x);
|
399 | const yLabel = getLabel(y);
|
400 |
|
401 | return this.graph.predecessors(yLabel).some(file => this.graph.predecessors(file).some(r => r === xLabel));
|
402 | }
|
403 |
|
404 | getInputRules(file) {
|
405 | const successors = this.graph.successors(file.filePath) || [];
|
406 |
|
407 | return successors.map(id => this.rules.get(id)).filter(rule => rule);
|
408 | }
|
409 |
|
410 | getOutputRules(file) {
|
411 | const predecessors = this.graph.predecessors(file.filePath) || [];
|
412 |
|
413 | return predecessors.map(id => this.rules.get(id)).filter(rule => rule);
|
414 | }
|
415 |
|
416 | isOutputOf(file, ruleId) {
|
417 | return this.graph.inEdges(file.filePath).some(edge => edge.v.startsWith(ruleId));
|
418 | }
|
419 | }
|
420 | exports.default = State; |
\ | No newline at end of file |