1 | import npath from 'path';
|
2 | import { promisify } from 'util';
|
3 |
|
4 | import _glob from 'glob';
|
5 | import _ from 'underscore';
|
6 |
|
7 | import getBuild from './get-build.js';
|
8 | import maybeWrite from './maybe-write.js';
|
9 | import setExt from './set-ext.js';
|
10 | import sortObj from './sort-obj.js';
|
11 | import writeBuffer from './write-buffer.js';
|
12 |
|
13 | const glob = promisify(_glob);
|
14 |
|
15 | const flattenBuilds = build =>
|
16 | [].concat(build, ..._.map(build.builds, flattenBuilds));
|
17 |
|
18 | const saveManifest = async ({ env, manifest, onError, onResult }) => {
|
19 | const { manifestPath } = env;
|
20 | if (!manifestPath) return;
|
21 |
|
22 | const buffer = Buffer.from(JSON.stringify(sortObj(manifest)));
|
23 | const size = buffer.length;
|
24 | const sourcePath = `[manifest:${env.name}]`;
|
25 | const targetPath = manifestPath;
|
26 | try {
|
27 | const didChange = await maybeWrite({ buffer, targetPath });
|
28 | await onResult({ didChange, size, sourcePath, targetPath });
|
29 | } catch (error) {
|
30 | await onError({ error, sourcePath });
|
31 | }
|
32 | };
|
33 |
|
34 | const saveBuild = async ({
|
35 | build: { buffers, path },
|
36 | manifest,
|
37 | onError,
|
38 | onResult,
|
39 | target
|
40 | }) => {
|
41 | manifest[path] = await Promise.all(
|
42 | buffers.map(async (buffer, i) => {
|
43 | const size = buffer.length;
|
44 | const sourcePath =
|
45 | i === 0 ? path : setExt(path, `~${i + 1}${npath.extname(path)}`);
|
46 | try {
|
47 | const { didChange, targetPath } = await writeBuffer({
|
48 | buffer,
|
49 | path: sourcePath,
|
50 | target
|
51 | });
|
52 | await onResult({ didChange, size, sourcePath, targetPath });
|
53 | return targetPath;
|
54 | } catch (error) {
|
55 | await onError({ error, sourcePath });
|
56 | }
|
57 | })
|
58 | );
|
59 | };
|
60 |
|
61 | const saveBuilds = ({ env, manifest, onError, onResult }) =>
|
62 | Promise.all(
|
63 | _.map(env.builds, async (target, pattern) => {
|
64 | return Promise.all(
|
65 | _.map(await glob(pattern, { nodir: true }), async path => {
|
66 | try {
|
67 | const builds = flattenBuilds(await getBuild({ env, path, target }));
|
68 | await Promise.all(
|
69 | _.map(builds, async build => {
|
70 | await saveBuild({ build, manifest, onError, onResult, target });
|
71 | })
|
72 | );
|
73 | } catch (error) {
|
74 | await onError({ error, sourcePath: path });
|
75 | }
|
76 | })
|
77 | );
|
78 | })
|
79 | );
|
80 |
|
81 | const buildConfig = async ({ built, config, onResult, started }) => {
|
82 | let failed = false;
|
83 |
|
84 | const onError = async ({ error, sourcePath }) => {
|
85 | failed = true;
|
86 | await onResult({ error, sourcePath });
|
87 | };
|
88 |
|
89 | await Promise.all(
|
90 | _.map(config, async env => {
|
91 | if (started.has(env) || !_.all(env.requires, env => built.has(env))) {
|
92 | return;
|
93 | }
|
94 |
|
95 | started.add(env);
|
96 | const manifest = {};
|
97 |
|
98 | await saveBuilds({ env, manifest, onError, onResult });
|
99 | if (failed) return;
|
100 |
|
101 | await saveManifest({ env, manifest, onError, onResult });
|
102 | if (failed) return;
|
103 |
|
104 | built.add(env);
|
105 | await buildConfig({ built, config, onResult, started });
|
106 | })
|
107 | );
|
108 | };
|
109 |
|
110 | export default ({ config, onResult = _.noop }) =>
|
111 | buildConfig({ built: new Set(), config, onResult, started: new Set() });
|