// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
// We need to use the 'io' prefix here, otherwise io.exitCode will shadow
// CommandOutput.exitCode in subclasses of CommandOutput.
import 'dart:io' as io;

import 'command_output.dart';
import 'configuration.dart';
import 'path.dart';
import 'test_case.dart';
import 'utils.dart';

/// A command executed as a step in a test case.
abstract class Command {
  /// A descriptive name for this command.
  final String displayName;

  /// When cloning a command object to run it multiple times, we give
  /// the different copies distinct values for index.
  final int index;

  /// Number of times this command *can* be retried.
  int get maxNumRetries => 2;

  /// Reproduction command.
  String get reproductionCommand;

  /// We compute the Command.hashCode lazily and cache it here, since it might
  /// be expensive to compute (and hashCode is called often).
  int? _cachedHashCode;

  Command._(this.displayName, {this.index = 0});

  /// A virtual clone method for a member of the Command hierarchy.
  /// Two clones with the same index will be equal, with different indices
  /// will be distinct. Used to run tests multiple times, since identical
  /// commands are only run once by the dependency graph scheduler.
  Command indexedCopy(int index);

  CommandOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int pid = 0,
  ]) => CommandOutput(
    this,
    exitCode,
    timedOut,
    stdout,
    stderr,
    time,
    compilationSkipped,
    pid,
  );

  @override
  int get hashCode {
    if (_cachedHashCode == null) {
      var builder = HashCodeBuilder();
      _buildHashCode(builder);
      _cachedHashCode = builder.value;
    }
    return _cachedHashCode!;
  }

  @override
  operator ==(Object other) =>
      identical(this, other) ||
      (runtimeType == other.runtimeType && _equal(other as Command));

  void _buildHashCode(HashCodeBuilder builder) {
    builder.add(displayName);
    builder.add(index);
  }

  bool _equal(covariant Command other) =>
      hashCode == other.hashCode &&
      displayName == other.displayName &&
      index == other.index;

  @override
  String toString() => reproductionCommand;

  bool get outputIsUpToDate => false;
}

class ProcessCommand extends Command {
  /// Path to the executable of this command.
  String executable;

  /// Command line arguments to the executable.
  final List<String> arguments;

  /// Environment for the command.
  final Map<String, String> environmentOverrides;

  /// Working directory for the command.
  final String? workingDirectory;

  ProcessCommand(
    super.displayName,
    this.executable,
    this.arguments, [
    this.environmentOverrides = const {},
    this.workingDirectory,
    int index = 0,
  ]) : super._(index: index) {
    if (io.Platform.operatingSystem == 'windows') {
      // Windows can't handle the first command if it is a .bat file or the like
      // with the slashes going the other direction.
      // NOTE: Issue 1306
      executable = executable.replaceAll('/', '\\');
    }
  }

  @override
  ProcessCommand indexedCopy(int index) {
    return ProcessCommand(
      displayName,
      executable,
      arguments,
      environmentOverrides,
      workingDirectory,
      index,
    );
  }

  @override
  void _buildHashCode(HashCodeBuilder builder) {
    super._buildHashCode(builder);
    builder.addJson(executable);
    builder.addJson(workingDirectory);
    builder.addJson(arguments);
    builder.addJson(environmentOverrides);
  }

  @override
  bool _equal(ProcessCommand other) =>
      super._equal(other) &&
      executable == other.executable &&
      deepJsonCompare(arguments, other.arguments) &&
      workingDirectory == other.workingDirectory &&
      deepJsonCompare(environmentOverrides, other.environmentOverrides);

  @override
  String get reproductionCommand {
    var env = StringBuffer();
    environmentOverrides.forEach(
      (key, value) => (io.Platform.operatingSystem == 'windows')
          ? env.write('set $key=${escapeCommandLineArgument(value)} & ')
          : env.write('$key=${escapeCommandLineArgument(value)} '),
    );
    var command = [
      executable,
      ...nonBatchArguments,
      ...arguments,
    ].map(escapeCommandLineArgument).join(' ');
    if (workingDirectory != null) {
      command = "$command (working directory: $workingDirectory)";
    }
    return "$env$command";
  }

  @override
  bool get outputIsUpToDate => false;

  /// Additional arguments to prepend before [arguments] when running the
  /// process in batch mode.
  List<String> get batchArguments => const [];

  /// Additional arguments to prepend before [arguments] when running the
  /// process in non-batch mode.
  List<String> get nonBatchArguments => const [];
}

class CompilationCommand extends ProcessCommand {
  /// The primary output file that will be created by this command.
  final String outputFile;

  /// If true, then the compilation is run even if the input files are older
  /// than the output file.
  final bool _alwaysCompile;
  final List<Uri> _bootstrapDependencies;

  CompilationCommand(
    String displayName,
    this.outputFile,
    this._bootstrapDependencies,
    String executable,
    List<String> arguments,
    Map<String, String> environmentOverrides, {
    required this._alwaysCompile,
    String? workingDirectory,
    int index = 0,
  }) : super(
         displayName,
         executable,
         arguments,
         environmentOverrides,
         workingDirectory,
         index,
       );

  @override
  CompilationCommand indexedCopy(int index) => CompilationCommand(
    displayName,
    outputFile,
    _bootstrapDependencies,
    executable,
    arguments,
    environmentOverrides,
    alwaysCompile: _alwaysCompile,
    workingDirectory: workingDirectory,
    index: index,
  );

  @override
  CommandOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int pid = 0,
  ]) {
    if (displayName == 'precompiler' ||
        displayName == 'app_jit' ||
        displayName == 'dart2bytecode' ||
        displayName == 'modaot') {
      return VMCommandOutput(
        this,
        exitCode,
        timedOut,
        stdout,
        stderr,
        time,
        pid,
      );
    } else if (displayName == 'dart2wasm') {
      return Dart2WasmCompilerCommandOutput(
        this,
        exitCode,
        timedOut,
        stdout,
        stderr,
        time,
        compilationSkipped,
      );
    }

    return CompilationCommandOutput(
      this,
      exitCode,
      timedOut,
      stdout,
      stderr,
      time,
      compilationSkipped,
    );
  }

  @override
  bool get outputIsUpToDate {
    if (_alwaysCompile) return false;

    var file = io.File(Path("$outputFile.deps").toNativePath());
    if (!file.existsSync()) return false;

    var lines = file.readAsLinesSync();
    var dependencies = <Uri>[];
    for (var line in lines) {
      line = line.trim();
      if (line.isNotEmpty) {
        dependencies.add(Uri.parse(line));
      }
    }

    dependencies.addAll(_bootstrapDependencies);
    var jsOutputLastModified = TestUtils.lastModifiedCache.getLastModified(
      Uri(scheme: 'file', path: outputFile),
    );
    if (jsOutputLastModified == null) return false;

    for (var dependency in dependencies) {
      var dependencyLastModified = TestUtils.lastModifiedCache.getLastModified(
        dependency,
      );
      if (dependencyLastModified == null ||
          dependencyLastModified.isAfter(jsOutputLastModified)) {
        return false;
      }
    }
    return true;
  }

  @override
  List<String> get batchArguments {
    return [...arguments.where((arg) => arg.startsWith('--enable-experiment'))];
  }

  @override
  void _buildHashCode(HashCodeBuilder builder) {
    super._buildHashCode(builder);
    builder.addJson(outputFile);
    builder.addJson(_alwaysCompile);
    builder.addJson(_bootstrapDependencies);
  }

  @override
  bool _equal(CompilationCommand other) =>
      super._equal(other) &&
      outputFile == other.outputFile &&
      _alwaysCompile == other._alwaysCompile &&
      deepJsonCompare(_bootstrapDependencies, other._bootstrapDependencies);
}

class Dart2jsCompilationCommand extends CompilationCommand {
  final bool useSdk;

  Dart2jsCompilationCommand(
    String outputFile,
    List<Uri> bootstrapDependencies,
    String executable,
    List<String> arguments,
    Map<String, String> environmentOverrides, {
    required this.useSdk,
    required super.alwaysCompile,
    super.workingDirectory,
    super.index = 0,
  }) : super(
         "dart2js",
         outputFile,
         bootstrapDependencies,
         executable,
         arguments,
         environmentOverrides,
       );

  @override
  Dart2jsCompilationCommand indexedCopy(int index) => Dart2jsCompilationCommand(
    outputFile,
    _bootstrapDependencies,
    executable,
    arguments,
    environmentOverrides,
    useSdk: useSdk,
    alwaysCompile: _alwaysCompile,
    workingDirectory: workingDirectory,
    index: index,
  );

  @override
  CommandOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int? pid = 0,
  ]) {
    return Dart2jsCompilerCommandOutput(
      this,
      exitCode,
      timedOut,
      stdout,
      stderr,
      time,
      compilationSkipped,
    );
  }

  @override
  List<String> get batchArguments {
    return <String>[
      if (useSdk) ...['compile', 'js'],
      ...super.batchArguments,
    ];
  }

  @override
  List<String> get nonBatchArguments {
    return <String>[
      if (useSdk) ...['compile', 'js'],
      ...super.nonBatchArguments,
    ];
  }

  @override
  void _buildHashCode(HashCodeBuilder builder) {
    super._buildHashCode(builder);
    builder.addJson(useSdk);
  }

  @override
  bool _equal(Dart2jsCompilationCommand other) {
    return super._equal(other) && useSdk == other.useSdk;
  }
}

class DevCompilerCompilationCommand extends CompilationCommand {
  final String compilerPath;

  final bool enableHostAsserts;

  DevCompilerCompilationCommand(
    String outputFile,
    List<Uri> bootstrapDependencies,
    String executable,
    List<String> arguments,
    Map<String, String> environmentOverrides, {
    required this.compilerPath,
    required super.alwaysCompile,
    required this.enableHostAsserts,
    super.workingDirectory,
    super.index = 0,
  }) : super(
         "ddc",
         outputFile,
         bootstrapDependencies,
         executable,
         arguments,
         environmentOverrides,
       );

  @override
  DevCompilerCompilationCommand indexedCopy(int index) =>
      DevCompilerCompilationCommand(
        outputFile,
        _bootstrapDependencies,
        executable,
        arguments,
        environmentOverrides,
        compilerPath: compilerPath,
        alwaysCompile: _alwaysCompile,
        enableHostAsserts: enableHostAsserts,
        workingDirectory: workingDirectory,
        index: index,
      );

  @override
  CommandOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int pid = 0,
  ]) {
    return DevCompilerCommandOutput(
      this,
      exitCode,
      timedOut,
      stdout,
      stderr,
      time,
      compilationSkipped,
      pid,
    );
  }

  @override
  List<String> get batchArguments {
    return <String>[
      if (enableHostAsserts) '--enable-asserts',
      compilerPath,
      ...super.batchArguments,
    ];
  }

  @override
  List<String> get nonBatchArguments {
    return <String>[
      if (enableHostAsserts) '--enable-asserts',
      compilerPath,
      ...super.nonBatchArguments,
    ];
  }

  @override
  void _buildHashCode(HashCodeBuilder builder) {
    super._buildHashCode(builder);
    builder.addJson(compilerPath);
  }

  @override
  bool _equal(DevCompilerCompilationCommand other) {
    return super._equal(other) && compilerPath == other.compilerPath;
  }
}

class FastaCompilationCommand extends CompilationCommand {
  final Uri _compilerLocation;

  FastaCompilationCommand(
    this._compilerLocation,
    String outputFile,
    List<Uri> bootstrapDependencies,
    String executable,
    List<String> arguments,
    Map<String, String> environmentOverrides,
    String? workingDirectory, {
    super.index = 0,
  }) : super(
         "fasta",
         outputFile,
         bootstrapDependencies,
         executable,
         arguments,
         environmentOverrides,
         alwaysCompile: true,
         workingDirectory: workingDirectory,
       );

  @override
  FastaCompilationCommand indexedCopy(int index) => FastaCompilationCommand(
    _compilerLocation,
    outputFile,
    _bootstrapDependencies,
    executable,
    arguments,
    environmentOverrides,
    workingDirectory,
    index: index,
  );

  @override
  FastaCommandOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int? pid = 0,
  ]) => FastaCommandOutput(
    this,
    exitCode,
    timedOut,
    stdout,
    stderr,
    time,
    compilationSkipped,
  );

  @override
  List<String> get batchArguments {
    return <String>[
      ...super.batchArguments,
      '--enable-asserts',
      _compilerLocation.resolve("batch.dart").toFilePath(),
    ];
  }

  @override
  String get reproductionCommand {
    String relativizeAndEscape(String argument) {
      if (workingDirectory != null) {
        argument = argument.replaceAll(
          workingDirectory!,
          Uri.directory(".").toFilePath(),
        );
      }
      return escapeCommandLineArgument(argument);
    }

    var buffer = StringBuffer();
    if (workingDirectory != null && !io.Platform.isWindows) {
      buffer.write("(cd ");
      buffer.write(escapeCommandLineArgument(workingDirectory!));
      buffer.write(" ; ");
    }
    environmentOverrides.forEach((key, value) {
      if (io.Platform.isWindows) {
        buffer.write("set ");
      }
      buffer.write(key);
      buffer.write("=");
      buffer.write(relativizeAndEscape(value));
      if (io.Platform.isWindows) {
        buffer.write(" &");
      }
      buffer.write(" ");
    });
    buffer.writeAll(
      [
        executable,
        _compilerLocation.toFilePath(),
        ...arguments,
      ].map(relativizeAndEscape),
      " ",
    );
    if (workingDirectory != null) {
      if (io.Platform.isWindows) {
        buffer.write(" (working directory: $workingDirectory)");
      } else {
        buffer.write(" )");
      }
    }
    return "$buffer";
  }

  @override
  void _buildHashCode(HashCodeBuilder builder) {
    super._buildHashCode(builder);
    builder.addJson(_compilerLocation);
  }

  @override
  bool _equal(FastaCompilationCommand other) {
    return super._equal(other) && _compilerLocation == other._compilerLocation;
  }
}

class VMKernelCompilationCommand extends CompilationCommand {
  VMKernelCompilationCommand(
    String outputFile,
    List<Uri> bootstrapDependencies,
    String executable,
    List<String> arguments,
    Map<String, String> environmentOverrides, {
    required super.alwaysCompile,
    super.index = 0,
  }) : super(
         'vm_compile_to_kernel',
         outputFile,
         bootstrapDependencies,
         executable,
         arguments,
         environmentOverrides,
       );

  @override
  VMKernelCompilationCommand indexedCopy(int index) =>
      VMKernelCompilationCommand(
        outputFile,
        _bootstrapDependencies,
        executable,
        arguments,
        environmentOverrides,
        alwaysCompile: _alwaysCompile,
        index: index,
      );

  @override
  VMKernelCompilationCommandOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int? pid = 0,
  ]) => VMKernelCompilationCommandOutput(
    this,
    exitCode,
    timedOut,
    stdout,
    stderr,
    time,
    compilationSkipped,
  );

  @override
  int get maxNumRetries => 1;
}

class BrowserTestCommand extends Command {
  Runtime get browser => configuration.runtime;
  final String url;
  final TestConfiguration configuration;

  BrowserTestCommand(this.url, this.configuration, {super.index = 0})
    : super._(configuration.runtime.name);

  @override
  BrowserTestCommand indexedCopy(int index) =>
      BrowserTestCommand(url, configuration, index: index);

  @override
  void _buildHashCode(HashCodeBuilder builder) {
    super._buildHashCode(builder);
    builder.addJson(browser.name);
    builder.addJson(url);
    builder.add(configuration);
  }

  @override
  bool _equal(BrowserTestCommand other) =>
      super._equal(other) &&
      browser == other.browser &&
      url == other.url &&
      identical(configuration, other.configuration);

  @override
  String get reproductionCommand {
    var parts = [
      io.Platform.resolvedExecutable,
      'pkg/test_runner/bin/launch_browser.dart',
      browser.name,
      url,
    ];
    return parts.map(escapeCommandLineArgument).join(' ');
  }

  @override
  int get maxNumRetries => 4;
}

class AnalysisCommand extends ProcessCommand {
  final List<String> commonAnalyzerCliArguments;

  AnalysisCommand(
    String executable,
    List<String> arguments,
    this.commonAnalyzerCliArguments,
    Map<String, String> environmentOverrides, {
    int index = 0,
  }) : super(
         'dart2analyzer',
         executable,
         arguments,
         environmentOverrides,
         null,
         index,
       );

  @override
  AnalysisCommand indexedCopy(int index) => AnalysisCommand(
    executable,
    arguments,
    commonAnalyzerCliArguments,
    environmentOverrides,
    index: index,
  );

  @override
  CommandOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int? pid = 0,
  ]) => AnalysisCommandOutput(
    this,
    exitCode,
    timedOut,
    stdout,
    stderr,
    time,
    compilationSkipped,
  );

  @override
  List<String> get batchArguments => commonAnalyzerCliArguments;

  @override
  List<String> get nonBatchArguments => commonAnalyzerCliArguments;

  @override
  bool _equal(covariant ProcessCommand other) {
    return other is AnalysisCommand &&
        super._equal(other) &&
        deepJsonCompare(
          commonAnalyzerCliArguments,
          other.commonAnalyzerCliArguments,
        );
  }
}

class SpecParseCommand extends ProcessCommand {
  SpecParseCommand(
    String executable,
    List<String> arguments,
    Map<String, String> environmentOverrides, {
    int index = 0,
  }) : super(
         'spec_parser',
         executable,
         arguments,
         environmentOverrides,
         null,
         index,
       );

  @override
  SpecParseCommand indexedCopy(int index) => SpecParseCommand(
    executable,
    arguments,
    environmentOverrides,
    index: index,
  );

  @override
  SpecParseCommandOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int? pid = 0,
  ]) => SpecParseCommandOutput(
    this,
    exitCode,
    timedOut,
    stdout,
    stderr,
    time,
    compilationSkipped,
  );
}

class VMCommand extends ProcessCommand {
  VMCommand(
    String executable,
    List<String> arguments,
    Map<String, String> environmentOverrides, {
    int index = 0,
  }) : super('vm', executable, arguments, environmentOverrides, null, index);

  @override
  VMCommand indexedCopy(int index) =>
      VMCommand(executable, arguments, environmentOverrides, index: index);

  @override
  CommandOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int pid = 0,
  ]) => VMCommandOutput(this, exitCode, timedOut, stdout, stderr, time, pid);
}

// Run a VM test under RR, and copy the trace if it crashes. Using a helper
// script like the precompiler does not work because the RR traces are large
// and we must diligently erase them for non-crashes even if the test times
// out and would be killed by the harness, so the copying and cleanup logic
// must be in the harness.
class RRCommand extends Command {
  ProcessCommand originalCommand;
  late ProcessCommand wrappedCommand;
  late io.Directory recordingDir;
  late io.Directory savedDir;

  RRCommand(this.originalCommand)
    : super._(originalCommand.displayName, index: originalCommand.index) {
    final suffix = "/rr-trace-${originalCommand.hashCode}";
    recordingDir = io.Directory(io.Directory.systemTemp.path + suffix);
    savedDir = io.Directory("out$suffix");
    final executable = "rr";
    final arguments = <String>[
      "record",
      "--chaos",
      "--output-trace-dir=${recordingDir.path}",
    ];
    arguments.add(originalCommand.executable);
    arguments.addAll(originalCommand.nonBatchArguments);
    arguments.addAll(originalCommand.arguments);
    wrappedCommand = ProcessCommand(
      originalCommand.displayName,
      executable,
      arguments,
      originalCommand.environmentOverrides,
      originalCommand.workingDirectory,
      originalCommand.index,
    );
  }

  @override
  RRCommand indexedCopy(int index) =>
      RRCommand(originalCommand.indexedCopy(index));

  Future<CommandOutput> run(
    int timeout,
    TestConfiguration configuration,
  ) async {
    // rr will fail if the output trace directory already exists. Delete any
    // that might be leftover from interrupting the harness.
    if (await recordingDir.exists()) {
      await recordingDir.delete(recursive: true);
    }
    final output = await RunningProcess(
      wrappedCommand,
      timeout,
      configuration: configuration,
    ).run();
    if (output.hasCrashed) {
      if (await savedDir.exists()) {
        await savedDir.delete(recursive: true);
      }
      await recordingDir.rename(savedDir.path);
      await io.File(
        "${savedDir.path}/command.txt",
      ).writeAsString(wrappedCommand.reproductionCommand);
      await io.File("${savedDir.path}/stdout.txt").writeAsBytes(output.stdout);
      await io.File("${savedDir.path}/stderr.txt").writeAsBytes(output.stderr);
    } else if (await recordingDir.exists()) {
      await recordingDir.delete(recursive: true);
    }

    final compilationSkipped = false;
    switch (displayName) {
      case 'app_jit':
      case 'precompiler':
      case 'run_vm_unittest':
      case 'vm':
        return VMCommandOutput(
          this,
          output.exitCode,
          output.hasTimedOut,
          output.stdout,
          output.stderr,
          output.time,
          output.pid,
        );
      case 'dart2wasm':
        return Dart2WasmCompilerCommandOutput(
          this,
          output.exitCode,
          output.hasTimedOut,
          output.stdout,
          output.stderr,
          output.time,
          compilationSkipped,
        );
      case 'dart2js':
        return Dart2jsCompilerCommandOutput(
          this,
          output.exitCode,
          output.hasTimedOut,
          output.stdout,
          output.stderr,
          output.time,
          compilationSkipped,
        );
      case 'ddc':
        return DevCompilerCommandOutput(
          this,
          output.exitCode,
          output.hasTimedOut,
          output.stdout,
          output.stderr,
          output.time,
          compilationSkipped,
          output.pid,
        );
    }
    throw "Don't know how to interpret output for $displayName";
  }

  @override
  String get reproductionCommand =>
      "${wrappedCommand.reproductionCommand} (rr replay ${savedDir.path})";

  @override
  void _buildHashCode(HashCodeBuilder builder) {
    originalCommand._buildHashCode(builder);
    builder.add(42);
  }

  @override
  bool _equal(RRCommand other) =>
      hashCode == other.hashCode &&
      originalCommand._equal(other.originalCommand);
}

abstract class AdbCommand {
  String get buildPath;
  List<String> get extraLibraries;
}

class AdbPrecompilationCommand extends Command implements AdbCommand {
  @override
  final String buildPath; // Path to the output directory of the build.
  final String processTestFilename;
  final String abstractSocketTestFilename;
  final String precompiledTestDirectory;
  final List<String> arguments;
  final bool useElf;
  @override
  final List<String> extraLibraries;

  AdbPrecompilationCommand(
    this.buildPath,
    this.processTestFilename,
    this.abstractSocketTestFilename,
    this.precompiledTestDirectory,
    this.arguments,
    this.useElf,
    this.extraLibraries, {
    super.index = 0,
  }) : super._("adb_precompilation");

  @override
  AdbPrecompilationCommand indexedCopy(int index) => AdbPrecompilationCommand(
    buildPath,
    processTestFilename,
    abstractSocketTestFilename,
    precompiledTestDirectory,
    arguments,
    useElf,
    extraLibraries,
    index: index,
  );

  @override
  VMCommandOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int pid = 0,
  ]) => VMCommandOutput(this, exitCode, timedOut, stdout, stderr, time, pid);

  @override
  _buildHashCode(HashCodeBuilder builder) {
    super._buildHashCode(builder);
    builder.add(buildPath);
    builder.add(precompiledTestDirectory);
    builder.add(arguments);
    builder.add(useElf);
    extraLibraries.forEach(builder.add);
  }

  @override
  bool _equal(AdbPrecompilationCommand other) =>
      super._equal(other) &&
      buildPath == other.buildPath &&
      useElf == other.useElf &&
      arguments == other.arguments &&
      precompiledTestDirectory == other.precompiledTestDirectory &&
      deepJsonCompare(extraLibraries, other.extraLibraries);

  @override
  String toString() =>
      'Steps to push precompiled runner and precompiled code '
      'to an attached device. Uses (and requires) adb.';

  @override
  String get reproductionCommand => throw UnimplementedError();
}

class AdbDartkCommand extends Command implements AdbCommand {
  @override
  final String buildPath;
  final String processTestFilename;
  final String abstractSocketTestFilename;
  final String kernelFile;
  final List<String> arguments;
  @override
  final List<String> extraLibraries;

  AdbDartkCommand(
    this.buildPath,
    this.processTestFilename,
    this.abstractSocketTestFilename,
    this.kernelFile,
    this.arguments,
    this.extraLibraries, {
    super.index = 0,
  }) : super._("adb_precompilation");

  @override
  AdbDartkCommand indexedCopy(int index) => AdbDartkCommand(
    buildPath,
    processTestFilename,
    abstractSocketTestFilename,
    kernelFile,
    arguments,
    extraLibraries,
    index: index,
  );

  @override
  _buildHashCode(HashCodeBuilder builder) {
    super._buildHashCode(builder);
    builder.add(buildPath);
    builder.add(kernelFile);
    builder.add(arguments);
    builder.add(extraLibraries);
  }

  @override
  bool _equal(AdbDartkCommand other) =>
      super._equal(other) &&
      buildPath == other.buildPath &&
      arguments == other.arguments &&
      extraLibraries == other.extraLibraries &&
      kernelFile == other.kernelFile;

  @override
  VMCommandOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int pid = 0,
  ]) => VMCommandOutput(this, exitCode, timedOut, stdout, stderr, time, pid);

  @override
  String toString() =>
      'Steps to push Dart VM and Dill file '
      'to an attached device. Uses (and requires) adb.';

  @override
  String get reproductionCommand => throw UnimplementedError();
}

class JSCommandLineCommand extends ProcessCommand {
  JSCommandLineCommand(
    String displayName,
    String executable,
    List<String> arguments, [
    Map<String, String> environmentOverrides = const {},
    int index = 0,
  ]) : super(
         displayName,
         executable,
         arguments,
         environmentOverrides,
         null,
         index,
       );

  @override
  JSCommandLineCommand indexedCopy(int index) => JSCommandLineCommand(
    displayName,
    executable,
    arguments,
    environmentOverrides,
    index,
  );

  @override
  JSCommandLineOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int? pid = 0,
  ]) => JSCommandLineOutput(this, exitCode, timedOut, stdout, stderr, time);
}

class Dart2WasmCommandLineCommand extends ProcessCommand {
  Dart2WasmCommandLineCommand(
    String displayName,
    String executable,
    List<String> arguments, [
    Map<String, String> environmentOverrides = const {},
    int index = 0,
  ]) : super(
         displayName,
         executable,
         arguments,
         environmentOverrides,
         null,
         index,
       );

  @override
  Dart2WasmCommandLineCommand indexedCopy(int index) =>
      Dart2WasmCommandLineCommand(
        displayName,
        executable,
        arguments,
        environmentOverrides,
        index,
      );

  @override
  Dart2WasmCommandLineOutput createOutput(
    int exitCode,
    bool timedOut,
    List<int> stdout,
    List<int> stderr,
    Duration time,
    bool compilationSkipped, [
    int? pid = 0,
  ]) => Dart2WasmCommandLineOutput(
    this,
    exitCode,
    timedOut,
    stdout,
    stderr,
    time,
  );
}

/// [ScriptCommand]s are executed by dart code.
abstract class ScriptCommand extends Command {
  ScriptCommand._(super.displayName) : super._();

  Future<ScriptCommandOutput> run();
}
