Files
sdk/pkg/test_runner/lib/src/command.dart
T
Paul Berry bd0b10802b Bump infra packages to language version 3.12.
This CL is part of an effort to bump the SDK requirement to `3.12.0-0`
for all the packages in `pkg` that are not published to `pub`, so that
we can get better testing of the "private named parameters" feature.

(Packages that *are* published to `pub` can't be safely bumped yet,
because SDK 3.12 hasn't been released, and I don't want to block those
packages' ability to publish useful updates to customers.)

This change covers the following packages, which are owned by
OWNERS_INFRA:
- pkg/smith
- pkg/status_file
- pkg/test_runner

Changes to `pubspec.yaml` files were made manually.

Changes to `.dart` files were made automatically (with some
exceptions), using `dart fix` to migrate to using private named
parameters where it is possible to do so without changing
semantics. Note that this migration is conservative; see
https://github.com/dart-lang/sdk/issues/58607 for details.

The exceptions are:
- pkg/test_runner/lib/src/compiler_configuration.dart
- pkg/test_runner/lib/src/path.dart

These files contained code that triggered the
`use_null_aware_elements` lint, so I manually fixed the instances of
the lint. (The lint didn't previously fire because the test runner
used to be on language version 3.5.0, which was before the "null aware
elements" feature existed.)

Change-Id: Ia5d99ba5fc2d5aacbec5b091348be1d26a6a6964
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/487882
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2026-03-16 10:32:47 -07:00

985 lines
30 KiB
Dart

// 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;
}
/// This is just a Pair(String, Map) class with hashCode and operator ==
class AddFlagsKey {
final String flags;
final Map env;
AddFlagsKey(this.flags, this.env);
// Just use object identity for environment map
@override
bool operator ==(Object other) =>
other is AddFlagsKey && flags == other.flags && env == other.env;
@override
int get hashCode => flags.hashCode ^ env.hashCode;
}
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 CompareAnalyzerCfeCommand extends ProcessCommand {
CompareAnalyzerCfeCommand(String executable, List<String> arguments,
Map<String, String> environmentOverrides, {int index = 0})
: super('compare_analyzer_cfe', executable, arguments,
environmentOverrides, null, index);
@override
CompareAnalyzerCfeCommand indexedCopy(int index) =>
CompareAnalyzerCfeCommand(executable, arguments, environmentOverrides,
index: index);
@override
CompareAnalyzerCfeCommandOutput createOutput(
int exitCode,
bool timedOut,
List<int> stdout,
List<int> stderr,
Duration time,
bool compilationSkipped,
[int? pid = 0]) =>
CompareAnalyzerCfeCommandOutput(
this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
}
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();
}