1
+'use strict';
2
+
3
+/* eslint-disable no-for-of-loops/no-for-of-loops */
4
+
5
+const fs = require('fs');
6
+const {spawnSync} = require('child_process');
7
+const tmp = require('tmp');
8
+
9
+// Runs the build script for both stable and experimental release channels,
10
+// by configuring an environment variable.
11
+
12
+if (process.env.CIRCLE_NODE_TOTAL) {
13
+ // In CI, we use multiple concurrent processes. Allocate half the processes to
14
+ // build the stable channel, and the other half for experimental. Override
15
+ // the environment variables to "trick" the underlying build script.
16
+ const total = parseInt(process.env.CIRCLE_NODE_TOTAL, 10);
17
+ const halfTotal = Math.floor(total / 2);
18
+ const index = parseInt(process.env.CIRCLE_NODE_INDEX, 10);
19
+ if (index < halfTotal) {
20
+ const nodeTotal = halfTotal;
21
+ const nodeIndex = index;
22
+ buildForChannel('stable', nodeTotal, nodeIndex);
23
+ processStable('./build');
24
+ } else {
25
+ const nodeTotal = total - halfTotal;
26
+ const nodeIndex = index - halfTotal;
27
+ buildForChannel('experimental', nodeTotal, nodeIndex);
28
+ processExperimental('./build');
29
+ }
30
+
31
+ // TODO: Currently storing artifacts as `./build2` so that it doesn't conflict
32
+ // with old build job. Remove once we migrate rest of build/test pipeline.
33
+ fs.renameSync('./build', './build2');
34
+} else {
35
+ // Running locally, no concurrency. Move each channel's build artifacts into
36
+ // a temporary directory so that they don't conflict.
37
+ buildForChannel('stable', '', '');
38
+ const stableDir = tmp.dirSync().name;
39
+ fs.renameSync('./build', stableDir);
40
+ processStable(stableDir);
41
+
42
+ buildForChannel('experimental', '', '');
43
+ const experimentalDir = tmp.dirSync().name;
44
+ fs.renameSync('./build', experimentalDir);
45
+ processExperimental(experimentalDir);
46
+
47
+ // Then merge the experimental folder into the stable one. processExperimental
48
+ // will have already removed conflicting files.
49
+ //
50
+ // In CI, merging is handled automatically by CircleCI's workspace feature.
51
+ spawnSync('rsync', ['-ar', experimentalDir + '/', stableDir + '/']);
52
+
53
+ // Now restore the combined directory back to its original name
54
+ // TODO: Currently storing artifacts as `./build2` so that it doesn't conflict
55
+ // with old build job. Remove once we migrate rest of build/test pipeline.
56
+ fs.renameSync(stableDir, './build2');
57
+}
58
+
59
+function buildForChannel(channel, nodeTotal, nodeIndex) {
60
+ spawnSync('node', ['./scripts/rollup/build.js', ...process.argv.slice(2)], {
61
+ stdio: ['pipe', process.stdout, process.stderr],
62
+ env: {
63
+ ...process.env,
64
+ RELEASE_CHANNEL: channel,
65
+ CIRCLE_NODE_TOTAL: nodeTotal,
66
+ CIRCLE_NODE_INDEX: nodeIndex,
67
+ },
68
+ });
69
+}
70
+
71
+function processStable(buildDir) {
72
+ if (fs.existsSync(buildDir + '/node_modules')) {
73
+ fs.renameSync(buildDir + '/node_modules', buildDir + '/oss-stable');
74
+ }
75
+
76
+ if (fs.existsSync(buildDir + '/facebook-www')) {
77
+ for (const fileName of fs.readdirSync(buildDir + '/facebook-www')) {
78
+ const filePath = buildDir + '/facebook-www/' + fileName;
79
+ const stats = fs.statSync(filePath);
80
+ if (!stats.isDirectory()) {
81
+ fs.renameSync(filePath, filePath.replace('.js', '.classic.js'));
82
+ }
83
+ }
84
+ }
85
+
86
+ if (fs.existsSync(buildDir + '/sizes')) {
87
+ fs.renameSync(buildDir + '/sizes', buildDir + '/sizes-stable');
88
+ }
89
+}
90
+
91
+function processExperimental(buildDir) {
92
+ if (fs.existsSync(buildDir + '/node_modules')) {
93
+ fs.renameSync(buildDir + '/node_modules', buildDir + '/oss-experimental');
94
+ }
95
+
96
+ if (fs.existsSync(buildDir + '/facebook-www')) {
97
+ for (const fileName of fs.readdirSync(buildDir + '/facebook-www')) {
98
+ const filePath = buildDir + '/facebook-www/' + fileName;
99
+ const stats = fs.statSync(filePath);
100
+ if (!stats.isDirectory()) {
101
+ fs.renameSync(filePath, filePath.replace('.js', '.modern.js'));
102
+ }
103
+ }
104
+ }
105
+
106
+ if (fs.existsSync(buildDir + '/sizes')) {
107
+ fs.renameSync(buildDir + '/sizes', buildDir + '/sizes-experimental');
108
+ }
109
+
110
+ // Delete all other artifacts that weren't handled above. We assume they are
111
+ // duplicates of the corresponding artifacts in the stable channel. Ideally,
112
+ // the underlying build script should not have produced these files in the
113
+ // first place.
114
+ for (const pathName of fs.readdirSync(buildDir)) {
115
+ if (
116
+ pathName !== 'oss-experimental' &&
117
+ pathName !== 'facebook-www' &&
118
+ pathName !== 'sizes-experimental'
119
+ ) {
120
+ spawnSync('rm', ['-rm', buildDir + '/' + pathName]);
121
+ }
122
+ }
123
+}