@ 261105.4
current
import path from 'node:path';

import {
  minor, major, backport, deps, listPatches
} from '../../lib/update-v8/index.js';
import { defaultBaseDir } from '../../lib/update-v8/constants.js';
import { checkCwd } from '../../lib/update-v8/common.js';
import { forceRunAsync } from '../../lib/run.js';
import { error } from '../../lib/figures.js';

export const command = 'v8 [major|minor|backport|deps|list-patches]';
export const describe = 'Update or patch the V8 engine';

export function builder(yargs) {
  yargs
    .command({
      command: 'major',
      desc: 'Do a major upgrade. Replaces the whole deps/v8 directory',
      handler,
      builder: (yargs) => {
        yargs.option('branch', {
          describe: 'Branch of the V8 repository to use for the upgrade',
          default: 'lkgr'
        });
        yargs.option('version-bump', {
          type: 'boolean',
          describe: 'Bump the NODE_MODULE_VERSION constant',
          default: true
        });
        yargs.option('concurrent', {
          type: 'boolean',
          describe: 'Update dependencies concurrently',
          default: true,
        });
        yargs.option('cargo', {
          describe: 'The cargo binary that will be executed when updating the Rust crates',
          default: 'cargo',
        });
      }
    })
    .command({
      command: 'minor',
      desc: 'Do a minor patch of the current V8 version',
      handler
    })
    .command({
      command: 'backport <sha..>',
      desc: 'Backport one or more commits from the V8 repository',
      handler,
      builder: (yargs) => {
        yargs
          .option('bump', {
            type: 'boolean',
            describe: 'Bump V8 embedder version number or patch version',
            default: true
          })
          .option('gpg-sign', {
            alias: 'S',
            type: 'boolean',
            describe: 'GPG-sign commits',
            default: false
          })
          .option('preserve-original-author', {
            type: 'boolean',
            describe: 'Preserve original commit author and date',
            default: true
          })
          .option('squash', {
            type: 'boolean',
            describe:
                'If multiple commits are backported, squash them into one. When ' +
                '`--squash` is passed, `--preserve-original-author` will be ignored',
            default: false
          });
      }
    })
    .command({
      command: 'deps',
      desc: 'Update V8 dependencies from the DEPS file',
      handler,
      builder: (yargs) => {
        yargs
          .option('concurrent', {
            type: 'boolean',
            describe: 'Update dependencies concurrently',
            default: true,
          });
      }
    })
    .command({
      command: 'list-patches',
      desc: 'List the V8 patches carried since the last V8 import',
      handler,
      builder: (yargs) => {
        yargs
          .option('target', {
            type: 'string',
            describe: 'V8 release line to upgrade to, as MAJOR.MINOR. ' +
              'Reports whether its lkgr branch contains each patch'
          })
          .option('base', {
            describe: 'Node.js ref to read the V8 patches from',
            default: 'upstream/main'
          })
          .option('fetch', {
            type: 'boolean',
            describe: 'Fetch V8 and the remote branch of --base first',
            default: true
          })
          .option('check-diff', {
            type: 'boolean',
            describe: 'Compare each cherry-pick diff with its upstream commit',
            default: false
          })
          .option('tsv', {
            type: 'boolean',
            describe: 'Print tab-separated rows instead of an aligned table',
            default: false
          });
      }
    })
    .demandCommand(1, 'Please provide a valid command')
    .option('node-dir', {
      describe: 'Directory of a Node.js clone',
      default: process.cwd()
    })
    .option('base-dir', {
      describe: 'Directory where V8 should be cloned',
      default: defaultBaseDir
    })
    .option('v8-dir', {
      describe: 'Directory of an existing V8 clone'
    })
    .option('verbose', {
      type: 'boolean',
      describe: 'Enable verbose output',
      default: false
    });
}

export function handler(argv) {
  const options = Object.assign({}, argv);
  options.nodeDir = path.resolve(options.nodeDir);
  options.baseDir = path.resolve(options.baseDir);
  if (!options.v8Dir) {
    options.v8Dir = path.join(options.baseDir, 'v8');
  } else {
    options.v8Dir = path.resolve(options.v8Dir);
  }

  options.execGitNode = function execGitNode(cmd, args, input) {
    args.unshift(cmd);
    return forceRunAsync('git', args, {
      ignoreFailure: false,
      input,
      spawnArgs: {
        cwd: options.nodeDir,
        stdio: input ? ['pipe', 'inherit', 'inherit'] : 'inherit'
      }
    });
  };

  options.execGitV8 = function execGitV8(...args) {
    return forceRunAsync('git', args, {
      ignoreFailure: false,
      captureStdout: true,
      spawnArgs: { cwd: options.v8Dir, stdio: ['ignore', 'pipe', 'inherit'] }
    });
  };

  Promise.resolve()
    .then(async() => {
      await checkCwd(options);
      // First element of argv is 'v8'
      const kind = argv._[1];
      options[kind] = true;
      switch (kind) {
        case 'minor':
          return minor(options);
        case 'major':
          return major(options);
        case 'backport':
          return backport(options);
        case 'deps':
          return deps(options);
        case 'list-patches':
          return listPatches(options);
      }
    })
    .catch((err) => {
      console.error(
        error,
        options.verbose ? err.stack : err.message
      );
      process.exitCode = 1;
    });
}