e1eade612a
This CL refactors the native assets implementation in Dartdev: * It introduces a `DartNativeAssetsBuilder` that wraps all logic. * The code now explicitly searches for a package config, and invokes `pub get` if that file does not exist but a pubspec does. (For most `dartdev` commands, `pub get` was already running later implicitly.) * The code now explicitly searches for a `runPackageName` and skips building native assets if a package name cannot be found. Change-Id: Ib5562fc64c3a756c99fee2e2daa763eb6fb1e855 Cq-Include-Trybots: luci.dart.try:pkg-linux-debug-try,pkg-linux-release-arm64-try,pkg-linux-release-try,pkg-mac-release-arm64-try,pkg-mac-release-try,pkg-win-release-arm64-try,pkg-win-release-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/404583 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Hossein Yousefi <yousefi@google.com> Reviewed-by: Ben Konyi <bkonyi@google.com>
137 lines
4.6 KiB
Dart
137 lines
4.6 KiB
Dart
// Copyright (c) 2020, 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:io';
|
|
import 'dart:isolate';
|
|
|
|
/// Contains methods used to communicate DartDev results back to the VM.
|
|
///
|
|
/// Messages are received in runtime/bin/dartdev_isolate.cc.
|
|
abstract class VmInteropHandler {
|
|
/// Initializes [VmInteropHandler] to utilize [port] to communicate with the
|
|
/// VM.
|
|
static void initialize(SendPort? port) => _port = port;
|
|
|
|
/// Notifies the VM to run [script] with [args] upon DartDev exit.
|
|
///
|
|
/// If [packageConfigOverride] is given, that is where the packageConfig is found.
|
|
///
|
|
/// If [markMainIsolateAsSystemIsolate] is given and set to true, the spawned
|
|
/// isolate will run with `--mark-main-isolate-as-system-isolate` enabled.
|
|
///
|
|
/// If [useExecProcess] is given and set to true, the script is executed by
|
|
/// execing it (On Linux/Mac the exec call is used, on Windows a new child
|
|
/// process is started).
|
|
static void run(
|
|
String script,
|
|
List<String> args, {
|
|
String? packageConfigOverride,
|
|
// TODO(bkonyi): remove once DartDev moves to AOT and this flag can be
|
|
// provided directly to the process spawned by `dart run` and `dart test`.
|
|
//
|
|
// See https://github.com/dart-lang/sdk/issues/53576
|
|
bool markMainIsolateAsSystemIsolate = false,
|
|
bool useExecProcess = false,
|
|
}) {
|
|
List<String> argsList;
|
|
if (useExecProcess && Platform.isWindows) {
|
|
// On Windows if a new process is used to execute the script we
|
|
// need to escape the script path and all the arguments as we
|
|
// construct a single command line string to be passed to the
|
|
// Windows process create call.
|
|
if (script.contains(' ') && !script.contains('"')) {
|
|
// Escape paths that may contain spaces
|
|
script = '"$script"';
|
|
}
|
|
argsList = [
|
|
for (int i = 0; i < args.length; i++) _windowsArgumentEscape(args[i]),
|
|
];
|
|
} else {
|
|
// Copy the list so it doesn't get GC'd underneath us.
|
|
argsList = args.toList();
|
|
}
|
|
final port = _port;
|
|
if (port == null) return;
|
|
final message = <dynamic>[
|
|
useExecProcess ? _kResultRunExec : _kResultRun,
|
|
script,
|
|
packageConfigOverride,
|
|
markMainIsolateAsSystemIsolate,
|
|
argsList
|
|
];
|
|
port.send(message);
|
|
}
|
|
|
|
/// Notifies the VM that DartDev has completed running. If provided a
|
|
/// non-zero [exitCode], the VM will terminate with the given exit code.
|
|
static void exit(int? exitCode) {
|
|
final port = _port;
|
|
if (port == null) return;
|
|
final message = <dynamic>[_kResultExit, exitCode];
|
|
port.send(message);
|
|
}
|
|
|
|
/// This code is identical to the one in process_patch.dart, please ensure
|
|
/// changes made here are also done in process_patch.dart.
|
|
/// TODO : figure out if this functionality can be abstracted out to a
|
|
/// common place.
|
|
static String _windowsArgumentEscape(String argument) {
|
|
if (argument.isEmpty) {
|
|
return '""';
|
|
}
|
|
var result = argument;
|
|
if (argument.contains('\t') ||
|
|
argument.contains(' ') ||
|
|
argument.contains('"')) {
|
|
// Produce something that the C runtime on Windows will parse
|
|
// back as this string.
|
|
|
|
// Replace any number of '\' followed by '"' with
|
|
// twice as many '\' followed by '\"'.
|
|
var backslash = '\\'.codeUnitAt(0);
|
|
var sb = StringBuffer();
|
|
var nextPos = 0;
|
|
var quotePos = argument.indexOf('"', nextPos);
|
|
while (quotePos != -1) {
|
|
var numBackslash = 0;
|
|
var pos = quotePos - 1;
|
|
while (pos >= 0 && argument.codeUnitAt(pos) == backslash) {
|
|
numBackslash++;
|
|
pos--;
|
|
}
|
|
sb.write(argument.substring(nextPos, quotePos - numBackslash));
|
|
for (var i = 0; i < numBackslash; i++) {
|
|
sb.write(r'\\');
|
|
}
|
|
sb.write(r'\"');
|
|
nextPos = quotePos + 1;
|
|
quotePos = argument.indexOf('"', nextPos);
|
|
}
|
|
sb.write(argument.substring(nextPos, argument.length));
|
|
result = sb.toString();
|
|
|
|
// Add '"' at the beginning and end and replace all '\' at
|
|
// the end with two '\'.
|
|
sb = StringBuffer('"');
|
|
sb.write(result);
|
|
nextPos = argument.length - 1;
|
|
while (argument.codeUnitAt(nextPos) == backslash) {
|
|
sb.write('\\');
|
|
nextPos--;
|
|
}
|
|
sb.write('"');
|
|
result = sb.toString();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Note: keep in sync with runtime/bin/dartdev_isolate.h
|
|
static const int _kResultRun = 1;
|
|
static const int _kResultRunExec = 2;
|
|
static const int _kResultExit = 3;
|
|
|
|
static SendPort? _port;
|
|
}
|