|
| 1 | +/** |
| 2 | + * @fileoverview Builds all external sources. This clears the data/ folder here |
| 3 | + * and runs all scripts in build/, which can write new files there. |
| 4 | + * |
| 5 | + * This is intended for use by Cloud Build, or by site devs doing local work. |
| 6 | + */ |
| 7 | + |
| 8 | +const fs = require('fs'); |
| 9 | +const path = require('path'); |
| 10 | +const glob = require('glob'); |
| 11 | +const childProcess = require('child_process'); |
| 12 | +const crypto = require('crypto'); |
| 13 | +const syncTestdata = require('./lib/sync-testdata'); |
| 14 | + |
| 15 | +async function run() { |
| 16 | + let errors = 0; |
| 17 | + |
| 18 | + const scripts = glob.sync('build/*.js', {cwd: __dirname}); |
| 19 | + scripts.sort(); // run in alphabetical order |
| 20 | + |
| 21 | + const projectRoot = path.join(__dirname, '..'); |
| 22 | + |
| 23 | + const dataTarget = path.join(__dirname, 'data'); |
| 24 | + fs.rmSync(dataTarget, {recursive: true, force: true}); |
| 25 | + fs.mkdirSync(dataTarget, {recursive: true}); |
| 26 | + |
| 27 | + // If this is a CI build, we start with everything found in "fallback/". It won't win, but it |
| 28 | + // will be used in cases where credentials and such aren't available. |
| 29 | + if (process.env.CI) { |
| 30 | + const all = await syncTestdata(); |
| 31 | + console.info('! Using fallback before build in CI, copied:', all); |
| 32 | + } |
| 33 | + |
| 34 | + /** @type {childProcess.CommonExecOptions} */ |
| 35 | + const options = {cwd: projectRoot, stdio: 'inherit'}; |
| 36 | + |
| 37 | + for (const script of scripts) { |
| 38 | + const r = path.join(__dirname, script); |
| 39 | + console.info('> Running', r); |
| 40 | + try { |
| 41 | + childProcess.execFileSync('node', [r], options); |
| 42 | + } catch (e) { |
| 43 | + // We don't log the error here, as we're already getting STDERR piped above. |
| 44 | + console.warn(`! Failed to execute "${script}" (${e.status})`); |
| 45 | + ++errors; |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | + // Determine the hash for everything in data/. |
| 50 | + const hash = crypto.createHash('sha256'); |
| 51 | + const allFiles = glob.sync('data/**/*', {cwd: __dirname}); |
| 52 | + if (!allFiles.length) { |
| 53 | + throw new Error('no files generated, cowardly refusing to hash'); |
| 54 | + } |
| 55 | + |
| 56 | + // Sort allFiles, in case glob.sync is inconsistent. |
| 57 | + allFiles.sort(); |
| 58 | + |
| 59 | + for (const f of allFiles) { |
| 60 | + const p = path.join(__dirname, f); |
| 61 | + const bytes = fs.readFileSync(p); |
| 62 | + hash.update(bytes); |
| 63 | + } |
| 64 | + const digest = hash.digest('hex'); |
| 65 | + console.info( |
| 66 | + `@ Generated digest=${digest} for ${allFiles.length} files:`, |
| 67 | + allFiles |
| 68 | + ); |
| 69 | + fs.writeFileSync(path.join(__dirname, 'data/.hash'), digest); |
| 70 | + |
| 71 | + // If there were any errors, return with a non-zero status code anyway. |
| 72 | + if (errors) { |
| 73 | + // eslint-disable-next-line no-process-exit |
| 74 | + process.exit(1); |
| 75 | + } |
| 76 | + |
| 77 | + // Mark this local environment as being build-only, so it won't automatically sync. |
| 78 | + const payload = |
| 79 | + '// This file blocks synchronizing local data, because you ran `npm run build-external`.\n' + |
| 80 | + '// Delete it to bring back automatic sync when you run `npm run dev`.'; |
| 81 | + fs.writeFileSync(path.join(__dirname, 'local-build-flag'), payload); |
| 82 | +} |
| 83 | + |
| 84 | +run(); |
0 commit comments