1. #!/usr/bin/env node
    
  2. 
    
  3. 'use strict';
    
  4. 
    
  5. const {exec} = require('child-process-promise');
    
  6. const chalk = require('chalk');
    
  7. const {join} = require('path');
    
  8. const semver = require('semver');
    
  9. const yargs = require('yargs');
    
  10. const fs = require('fs');
    
  11. 
    
  12. const INSTALL_PACKAGES = ['react-dom', 'react', 'react-test-renderer'];
    
  13. const REGRESSION_FOLDER = 'build-regression';
    
  14. 
    
  15. const ROOT_PATH = join(__dirname, '..', '..');
    
  16. 
    
  17. const buildPath = join(ROOT_PATH, `build`, 'oss-experimental');
    
  18. const regressionBuildPath = join(ROOT_PATH, REGRESSION_FOLDER);
    
  19. 
    
  20. const argv = yargs(process.argv.slice(2)).argv;
    
  21. 
    
  22. const version = process.argv[2];
    
  23. const shouldReplaceBuild = !!argv.replaceBuild;
    
  24. 
    
  25. async function downloadRegressionBuild() {
    
  26.   console.log(chalk.bold.white(`Downloading React v${version}\n`));
    
  27. 
    
  28.   // Make build directory for temporary modules we're going to download
    
  29.   // from NPM
    
  30.   console.log(
    
  31.     chalk.white(
    
  32.       `Make Build directory at ${chalk.underline.blue(regressionBuildPath)}\n`
    
  33.     )
    
  34.   );
    
  35.   await exec(`mkdir ${regressionBuildPath}`);
    
  36. 
    
  37.   // Install all necessary React packages that have the same version
    
  38.   const downloadPackagesStr = INSTALL_PACKAGES.reduce(
    
  39.     (str, name) => `${str} ${name}@${version}`,
    
  40.     ''
    
  41.   );
    
  42.   await exec(
    
  43.     `npm install --prefix ${REGRESSION_FOLDER} ${downloadPackagesStr}`
    
  44.   );
    
  45. 
    
  46.   // If we shouldn't replace the build folder, we can stop here now
    
  47.   // before we modify anything
    
  48.   if (!shouldReplaceBuild) {
    
  49.     return;
    
  50.   }
    
  51. 
    
  52.   // Remove all the packages that we downloaded in the original build folder
    
  53.   // so we can move the modules from the regression build over
    
  54.   const removePackagesStr = INSTALL_PACKAGES.reduce(
    
  55.     (str, name) => `${str} ${join(buildPath, name)}`,
    
  56.     ''
    
  57.   );
    
  58.   console.log(
    
  59.     chalk.white(
    
  60.       `Removing ${removePackagesStr
    
  61.         .split(' ')
    
  62.         .map(str => chalk.underline.blue(str) + '\n')
    
  63.         .join(' ')}\n`
    
  64.     )
    
  65.   );
    
  66.   await exec(`rm -r ${removePackagesStr}`);
    
  67. 
    
  68.   // Move all packages that we downloaded to the original build folder
    
  69.   // We need to separately move the scheduler package because it might
    
  70.   // be called schedule
    
  71.   const movePackageString = INSTALL_PACKAGES.reduce(
    
  72.     (str, name) => `${str} ${join(regressionBuildPath, 'node_modules', name)}`,
    
  73.     ''
    
  74.   );
    
  75.   console.log(
    
  76.     chalk.white(
    
  77.       `Moving ${movePackageString
    
  78.         .split(' ')
    
  79.         .map(str => chalk.underline.blue(str) + '\n')
    
  80.         .join(' ')} to ${chalk.underline.blue(buildPath)}\n`
    
  81.     )
    
  82.   );
    
  83.   await exec(`mv ${movePackageString} ${buildPath}`);
    
  84. 
    
  85.   // For React versions earlier than 18.0.0, we explicitly scheduler v0.20.1, which
    
  86.   // is the first version that has unstable_mock, which DevTools tests need, but also
    
  87.   // has Scheduler.unstable_trace, which, although we don't use in DevTools tests
    
  88.   // is imported by older React versions and will break if it's not there
    
  89.   if (semver.lte(semver.coerce(version).version, '18.0.0')) {
    
  90.     await exec(`npm install --prefix ${REGRESSION_FOLDER} [email protected]`);
    
  91.   }
    
  92. 
    
  93.   // In v16.5, scheduler is called schedule. We need to make sure we also move
    
  94.   // this over. Otherwise the code will break.
    
  95.   if (fs.existsSync(join(regressionBuildPath, 'node_modules', 'schedule'))) {
    
  96.     console.log(chalk.white(`Downloading schedule\n`));
    
  97.     await exec(
    
  98.       `mv ${join(regressionBuildPath, 'node_modules', 'schedule')} ${buildPath}`
    
  99.     );
    
  100.   } else {
    
  101.     console.log(chalk.white(`Downloading scheduler\n`));
    
  102.     await exec(`rm -r ${join(buildPath, 'scheduler')}`);
    
  103.     await exec(
    
  104.       `mv ${join(
    
  105.         regressionBuildPath,
    
  106.         'node_modules',
    
  107.         'scheduler'
    
  108.       )} ${buildPath}`
    
  109.     );
    
  110.   }
    
  111. }
    
  112. 
    
  113. async function main() {
    
  114.   try {
    
  115.     if (!version) {
    
  116.       console.log(chalk.red('Must specify React version to download'));
    
  117.       return;
    
  118.     }
    
  119.     await downloadRegressionBuild();
    
  120.   } catch (e) {
    
  121.     console.log(chalk.red(e));
    
  122.   } finally {
    
  123.     // We shouldn't remove the regression-build folder unless we're using
    
  124.     // it to replace the build folder
    
  125.     if (shouldReplaceBuild) {
    
  126.       console.log(chalk.bold.white(`Removing regression build`));
    
  127.       await exec(`rm -r ${regressionBuildPath}`);
    
  128.     }
    
  129.   }
    
  130. }
    
  131. 
    
  132. main();