mirror of
https://github.com/dart-lang/sdk
synced 2024-10-02 23:49:17 +00:00
Reland "[ VM / DartDev ] Launch DartDev in an isolate within a single main Dart process"
This reverts commit 7e373831ce
.
Change-Id: Ib94d793a5753ec6352cd9a65e35f726a63336368
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/154830
Reviewed-by: Siva Annamalai <asiva@google.com>
This commit is contained in:
parent
204d22467b
commit
157ebfe50f
23
BUILD.gn
23
BUILD.gn
|
@ -61,7 +61,10 @@ group("runtime") {
|
|||
# TODO(bkonyi): this dep causes a segfault on Android XARM_X64 builds.
|
||||
# See issue #41776.
|
||||
if (dart_target_arch != "arm") {
|
||||
deps += [ "utils/dartdev:dartdev" ]
|
||||
deps += [
|
||||
"utils/dartdev:dartdev",
|
||||
"utils/dds:dds",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,9 +162,7 @@ if (is_fuchsia) {
|
|||
data_deps = [ "runtime/bin:dart" ]
|
||||
manifest = "build/fuchsia/dart.cmx"
|
||||
|
||||
resource_files = [
|
||||
".packages",
|
||||
]
|
||||
resource_files = [ ".packages" ]
|
||||
resource_dirs = [
|
||||
"tests/standalone",
|
||||
"pkg/async_helper",
|
||||
|
@ -178,13 +179,15 @@ if (is_fuchsia) {
|
|||
|
||||
resources = []
|
||||
foreach(file, resource_files) {
|
||||
resources += [{
|
||||
path = file
|
||||
dest = "data/" + file
|
||||
}]
|
||||
resources += [
|
||||
{
|
||||
path = file
|
||||
dest = "data/" + file
|
||||
},
|
||||
]
|
||||
}
|
||||
resources += exec_script(
|
||||
"tools/fuchsia/find_resources.py", resource_dirs, "json")
|
||||
resources +=
|
||||
exec_script("tools/fuchsia/find_resources.py", resource_dirs, "json")
|
||||
}
|
||||
|
||||
fuchsia_package("dart_sdk_fuchsia_test_package") {
|
||||
|
|
|
@ -2,18 +2,12 @@
|
|||
// 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:async';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:dartdev/dartdev.dart';
|
||||
import 'package:pedantic/pedantic.dart' show unawaited;
|
||||
|
||||
/// The entry point for dartdev.
|
||||
Future<void> main(List<String> args) async {
|
||||
// Ignore SIGINT to ensure DartDev doesn't exit before any of its
|
||||
// spawned children. Draining the stream returned by watch() effectively
|
||||
// sends the signals to the void.
|
||||
//
|
||||
// See https://github.com/dart-lang/sdk/issues/42092 for context.
|
||||
unawaited(ProcessSignal.sigint.watch().drain());
|
||||
await runDartdev(args);
|
||||
Future<void> main(List<String> args, SendPort port) async {
|
||||
await runDartdev(args, port);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:io' as io;
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:analyzer/src/dart/analysis/experiments.dart';
|
||||
import 'package:args/args.dart';
|
||||
|
@ -21,11 +22,13 @@ import 'src/commands/run.dart';
|
|||
import 'src/commands/test.dart';
|
||||
import 'src/core.dart';
|
||||
import 'src/experiments.dart';
|
||||
import 'src/vm_interop_handler.dart';
|
||||
|
||||
/// This is typically called from bin/, but given the length of the method and
|
||||
/// analytics logic, it has been moved here. Also note that this method calls
|
||||
/// [io.exit(code)] directly.
|
||||
Future<void> runDartdev(List<String> args) async {
|
||||
Future<void> runDartdev(List<String> args, SendPort port) async {
|
||||
VmInteropHandler.initialize(port);
|
||||
final stopwatch = Stopwatch();
|
||||
int result;
|
||||
|
||||
|
@ -68,6 +71,12 @@ Future<void> runDartdev(List<String> args) async {
|
|||
io.exit(0);
|
||||
}
|
||||
|
||||
// --launch-dds is provided by the VM if the VM service is to be enabled. In
|
||||
// that case, we need to launch DDS as well.
|
||||
// TODO(bkonyi): add support for pub run (#42726)
|
||||
if (args.contains('--launch-dds')) {
|
||||
RunCommand.launchDds = true;
|
||||
}
|
||||
String commandName;
|
||||
|
||||
try {
|
||||
|
@ -79,6 +88,12 @@ Future<void> runDartdev(List<String> args) async {
|
|||
args = List.from(args)..remove('--disable-dartdev-analytics');
|
||||
}
|
||||
|
||||
// Run also can't be called with '--launch-dds', remove it if it's
|
||||
// contained in args.
|
||||
if (args.contains('--launch-dds')) {
|
||||
args = List.from(args)..remove('--launch-dds');
|
||||
}
|
||||
|
||||
// Before calling to run, send the first ping to analytics to have the first
|
||||
// ping, as well as the command itself, running in parallel.
|
||||
if (analytics.enabled) {
|
||||
|
@ -133,7 +148,7 @@ Future<void> runDartdev(List<String> args) async {
|
|||
analytics.enabled = true;
|
||||
}
|
||||
analytics.close();
|
||||
io.exit(exitCode);
|
||||
VmInteropHandler.exit(exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,6 +181,11 @@ class DartdevRunner<int> extends CommandRunner {
|
|||
help: 'Disable anonymous analytics for this `dart *` run',
|
||||
hide: true);
|
||||
|
||||
// Another hidden flag used by the VM to indicate that DDS should be
|
||||
// launched. Should be removed for all commands other than `run`.
|
||||
argParser.addFlag('launch-dds',
|
||||
negatable: false, hide: true, help: 'Launch DDS.');
|
||||
|
||||
addCommand(AnalyzeCommand());
|
||||
addCommand(CreateCommand(verbose: verbose));
|
||||
addCommand(CompileCommand());
|
||||
|
@ -192,7 +212,7 @@ class DartdevRunner<int> extends CommandRunner {
|
|||
io.stderr.writeln(
|
||||
"Error when reading '$firstArg': No such file or directory.");
|
||||
// This is the exit code used by the frontend.
|
||||
io.exit(254);
|
||||
VmInteropHandler.exit(254);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ class AnalyzeCommand extends DartdevCommand<int> {
|
|||
});
|
||||
|
||||
await analysisCompleter.future;
|
||||
|
||||
await server.dispose();
|
||||
progress.finish(showTiming: true);
|
||||
|
||||
errors.sort();
|
||||
|
|
|
@ -4,18 +4,20 @@
|
|||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:args/args.dart';
|
||||
import 'package:dds/dds.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
import '../core.dart';
|
||||
import '../experiments.dart';
|
||||
import '../sdk.dart';
|
||||
import '../utils.dart';
|
||||
import '../vm_interop_handler.dart';
|
||||
|
||||
class RunCommand extends DartdevCommand<int> {
|
||||
static bool launchDds = false;
|
||||
@override
|
||||
final ArgParser argParser = ArgParser.allowAnything();
|
||||
|
||||
|
@ -60,21 +62,19 @@ Run a Dart file.''');
|
|||
// The command line arguments after 'run'
|
||||
var args = argResults.arguments.toList();
|
||||
|
||||
var argsContainFileOrHelp = false;
|
||||
var argsContainFile = false;
|
||||
for (var arg in args) {
|
||||
// The arg.contains('.') matches a file name pattern, i.e. some 'foo.dart'
|
||||
if (arg.contains('.') ||
|
||||
arg == '--help' ||
|
||||
arg == '-h' ||
|
||||
arg == 'help') {
|
||||
argsContainFileOrHelp = true;
|
||||
break;
|
||||
if (arg.contains('.')) {
|
||||
argsContainFile = true;
|
||||
} else if (arg == '--help' || arg == '-h' || arg == 'help') {
|
||||
printUsage();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
final cwd = Directory.current;
|
||||
|
||||
if (!argsContainFileOrHelp && cwd.existsSync()) {
|
||||
if (!argsContainFile && cwd.existsSync()) {
|
||||
var foundImplicitFileToRun = false;
|
||||
var cwdName = cwd.name;
|
||||
for (var entity in cwd.listSync(followLinks: false)) {
|
||||
|
@ -100,6 +100,8 @@ Run a Dart file.''');
|
|||
'Could not find the implicit file to run: '
|
||||
'bin$separator$cwdName.dart.',
|
||||
);
|
||||
// Error exit code, as defined in runtime/bin/error_exit.h
|
||||
return 255;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,213 +119,43 @@ Run a Dart file.''');
|
|||
// service intermediary which implements the VM service protocol and
|
||||
// provides non-VM specific extensions (e.g., log caching, client
|
||||
// synchronization).
|
||||
if (args.any((element) =>
|
||||
element.startsWith('--observe') ||
|
||||
element.startsWith('--enable-vm-service'))) {
|
||||
return await _DebuggingSession(this, args).start();
|
||||
} else {
|
||||
// Starting in ProcessStartMode.inheritStdio mode means the child process
|
||||
// can detect support for ansi chars.
|
||||
final process = await Process.start(
|
||||
sdk.dart, ['--disable-dart-dev', ...args],
|
||||
mode: ProcessStartMode.inheritStdio);
|
||||
return process.exitCode;
|
||||
_DebuggingSession debugSession;
|
||||
if (launchDds) {
|
||||
debugSession = _DebuggingSession();
|
||||
await debugSession.start();
|
||||
}
|
||||
|
||||
final script = Directory.current.uri
|
||||
.resolve(args.firstWhere((e) => !e.startsWith('-')))
|
||||
.toFilePath();
|
||||
final runArgs = args.length == 1 ? <String>[] : args.sublist(1);
|
||||
VmInteropHandler.run(script, runArgs);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class _DebuggingSession {
|
||||
_DebuggingSession(this._runCommand, List<String> args)
|
||||
: _args = args.toList() {
|
||||
// Process flags that are meant to configure the VM service HTTP server or
|
||||
// dump VM service connection information to a file. Since the VM service
|
||||
// clients won't actually be connecting directly to the service, we'll make
|
||||
// DDS appear as if it is the actual VM service.
|
||||
for (final arg in _args) {
|
||||
final isObserve = arg.startsWith('--observe');
|
||||
if (isObserve || arg.startsWith('--enable-vm-service')) {
|
||||
if (isObserve) {
|
||||
_observe = true;
|
||||
}
|
||||
if (arg.contains('=') || arg.contains(':')) {
|
||||
// These flags can be provided by the embedder so we need to check for
|
||||
// both `=` and `:` separators.
|
||||
final observatoryBindInfo =
|
||||
(arg.contains('=') ? arg.split('=') : arg.split(':'))[1]
|
||||
.split('/');
|
||||
_port = int.tryParse(observatoryBindInfo.first) ?? 0;
|
||||
if (observatoryBindInfo.length > 1) {
|
||||
try {
|
||||
_bindAddress = Uri.http(observatoryBindInfo[1], '');
|
||||
} on FormatException {
|
||||
// TODO(bkonyi): log invalid parse? The VM service just ignores
|
||||
// bad input flags.
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (arg.startsWith('--write-service-info=')) {
|
||||
try {
|
||||
final split = arg.split('=');
|
||||
if (split[1].isNotEmpty) {
|
||||
_serviceInfoUri = Uri.parse(split[1]);
|
||||
} else {
|
||||
_runCommand.usageException(
|
||||
'Invalid URI argument to --write-service-info: "${split[1]}"');
|
||||
}
|
||||
} on FormatException {
|
||||
// TODO(bkonyi): log invalid parse? The VM service just ignores bad
|
||||
// input flags.
|
||||
// Ignore.
|
||||
}
|
||||
} else if (arg == '--disable-service-auth-codes') {
|
||||
_disableServiceAuthCodes = true;
|
||||
Future<void> start() async {
|
||||
final serviceInfo = await Service.getInfo();
|
||||
final process = await Process.start(
|
||||
sdk.dart,
|
||||
[
|
||||
if (dirname(sdk.dart).endsWith('bin'))
|
||||
sdk.ddsSnapshot
|
||||
else
|
||||
absolute(dirname(sdk.dart), 'gen', 'dds.dart.snapshot'),
|
||||
serviceInfo.serverUri.toString()
|
||||
],
|
||||
mode: ProcessStartMode.detachedWithStdio);
|
||||
final completer = Completer<void>();
|
||||
StreamSubscription sub;
|
||||
sub = process.stderr.transform(utf8.decoder).listen((event) {
|
||||
if (event == 'DDS started') {
|
||||
sub.cancel();
|
||||
completer.complete();
|
||||
}
|
||||
}
|
||||
|
||||
// Strip --observe and --write-service-info from the arguments as we'll be
|
||||
// providing our own.
|
||||
_args.removeWhere(
|
||||
(arg) =>
|
||||
arg.startsWith('--observe') ||
|
||||
arg.startsWith('--enable-vm-service') ||
|
||||
arg.startsWith('--write-service-info'),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<int> start() async {
|
||||
// Output the service information for the target process to a temporary
|
||||
// file so we can avoid scraping stderr for the service URI.
|
||||
final serviceInfoDir =
|
||||
await Directory.systemTemp.createTemp('dart_service');
|
||||
final serviceInfoUri = serviceInfoDir.uri.resolve('service_info.json');
|
||||
final serviceInfoFile = await File.fromUri(serviceInfoUri).create();
|
||||
|
||||
// Start using ProcessStartMode.normal and forward stdio manually as we
|
||||
// need to filter the true VM service URI and replace it with the DDS URI.
|
||||
_process = await Process.start(
|
||||
sdk.dart,
|
||||
[
|
||||
'--disable-dart-dev',
|
||||
// We don't care which port the VM service binds to.
|
||||
_observe ? '--observe=0' : '--enable-vm-service=0',
|
||||
'--write-service-info=$serviceInfoUri',
|
||||
..._args,
|
||||
],
|
||||
);
|
||||
_forwardAndFilterStdio(_process);
|
||||
|
||||
// Start DDS once the VM service has finished starting up.
|
||||
await Future.any([
|
||||
_waitForRemoteServiceUri(serviceInfoFile).then(_startDDS),
|
||||
_process.exitCode,
|
||||
]);
|
||||
|
||||
return _process.exitCode.then((exitCode) async {
|
||||
// Shutdown DDS if it was started and wait for the process' stdio streams
|
||||
// to close so we don't truncate program output.
|
||||
await Future.wait([
|
||||
if (_dds != null) _dds.shutdown(),
|
||||
_stderrDone,
|
||||
_stdoutDone,
|
||||
]);
|
||||
return exitCode;
|
||||
});
|
||||
|
||||
await completer.future;
|
||||
}
|
||||
|
||||
Future<Uri> _waitForRemoteServiceUri(File serviceInfoFile) async {
|
||||
// Wait for VM service to write its connection info to disk.
|
||||
while (await serviceInfoFile.length() <= 5) {
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
}
|
||||
final serviceInfoStr = await serviceInfoFile.readAsString();
|
||||
return Uri.parse(jsonDecode(serviceInfoStr)['uri']);
|
||||
}
|
||||
|
||||
Future<void> _startDDS(Uri remoteVmServiceUri) async {
|
||||
_dds = await DartDevelopmentService.startDartDevelopmentService(
|
||||
remoteVmServiceUri,
|
||||
serviceUri: _bindAddress.replace(port: _port),
|
||||
enableAuthCodes: !_disableServiceAuthCodes,
|
||||
);
|
||||
if (_serviceInfoUri != null) {
|
||||
// Output the service connection information.
|
||||
await File.fromUri(_serviceInfoUri).writeAsString(
|
||||
json.encode({
|
||||
'uri': _dds.uri.toString(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
_ddsCompleter.complete();
|
||||
}
|
||||
|
||||
void _forwardAndFilterStdio(Process process) {
|
||||
// Since VM service clients cannot connect to the real VM service once DDS
|
||||
// has started, replace all instances of the real VM service's URI with the
|
||||
// DDS URI. Clients should only know that they are connected to DDS if they
|
||||
// explicitly request that information via the protocol.
|
||||
String filterObservatoryUri(String msg) {
|
||||
if (_dds == null) {
|
||||
return msg;
|
||||
}
|
||||
if (msg.contains('Observatory listening on') ||
|
||||
msg.contains('Connect to Observatory at')) {
|
||||
// Search for the VM service URI in the message and replace it.
|
||||
msg = msg.replaceFirst(
|
||||
RegExp(r'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.'
|
||||
r'[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)'),
|
||||
_dds.uri.toString(),
|
||||
);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
// Wait for DDS to start before handling any stdio events from the target
|
||||
// to ensure we don't let any unfiltered messages slip through.
|
||||
// TODO(bkonyi): consider filtering on bytes rather than decoding the UTF8.
|
||||
_stderrDone = process.stderr
|
||||
.transform(const Utf8Decoder(allowMalformed: true))
|
||||
.listen((event) async {
|
||||
await _waitForDDS();
|
||||
stderr.write(filterObservatoryUri(event));
|
||||
}).asFuture();
|
||||
|
||||
_stdoutDone = process.stdout
|
||||
.transform(const Utf8Decoder(allowMalformed: true))
|
||||
.listen((event) async {
|
||||
await _waitForDDS();
|
||||
stdout.write(filterObservatoryUri(event));
|
||||
}).asFuture();
|
||||
|
||||
stdin.listen(
|
||||
(event) async {
|
||||
await _waitForDDS();
|
||||
process.stdin.add(event);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _waitForDDS() async {
|
||||
if (!_ddsCompleter.isCompleted) {
|
||||
// No need to wait for DDS if the process has already exited.
|
||||
await Future.any([
|
||||
_ddsCompleter.future,
|
||||
_process.exitCode,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Uri _bindAddress = Uri.http('127.0.0.1', '');
|
||||
bool _disableServiceAuthCodes = false;
|
||||
DartDevelopmentService _dds;
|
||||
bool _observe = false;
|
||||
int _port = 8181;
|
||||
Process _process;
|
||||
Uri _serviceInfoUri;
|
||||
Future _stderrDone;
|
||||
Future _stdoutDone;
|
||||
|
||||
final List<String> _args;
|
||||
final Completer<void> _ddsCompleter = Completer();
|
||||
final RunCommand _runCommand;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,9 @@ class Sdk {
|
|||
|
||||
String get dartfmt => path.absolute(sdkPath, 'bin', _binName('dartfmt'));
|
||||
|
||||
String get ddsSnapshot =>
|
||||
path.absolute(sdkPath, 'bin', 'snapshots', 'dds.dart.snapshot');
|
||||
|
||||
String get pub => path.absolute(sdkPath, 'bin', _binName('pub'));
|
||||
|
||||
static String _binName(String base) =>
|
||||
|
|
40
pkg/dartdev/lib/src/vm_interop_handler.dart
Normal file
40
pkg/dartdev/lib/src/vm_interop_handler.dart
Normal file
|
@ -0,0 +1,40 @@
|
|||
// 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:isolate';
|
||||
|
||||
/// Contains methods used to communicate DartDev results back to the VM.
|
||||
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.
|
||||
static void run(String script, List<String> args) {
|
||||
assert(_port != null);
|
||||
if (_port == null) return;
|
||||
final message = List<dynamic>.filled(3, null)
|
||||
..[0] = _kResultRun
|
||||
..[1] = script
|
||||
..[2] = args;
|
||||
_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) {
|
||||
assert(_port != null);
|
||||
if (_port == null) return;
|
||||
final message = List<dynamic>.filled(2, null)
|
||||
..[0] = _kResultExit
|
||||
..[1] = exitCode;
|
||||
_port.send(message);
|
||||
}
|
||||
|
||||
// Note: keep in sync with runtime/bin/dartdev_isolate.h
|
||||
static const int _kResultRun = 1;
|
||||
static const int _kResultExit = 2;
|
||||
|
||||
static SendPort _port;
|
||||
}
|
|
@ -79,13 +79,51 @@ void help() {
|
|||
var result = p.runSync('--help', ['--verbose']);
|
||||
|
||||
expect(result.exitCode, 0);
|
||||
expect(result.stdout, contains('migrate '));
|
||||
expect(result.stdout, isEmpty);
|
||||
expect(result.stderr,
|
||||
contains('The following options are only used for VM development'));
|
||||
});
|
||||
|
||||
test('--help -v', () {
|
||||
p = project();
|
||||
var result = p.runSync('--help', ['-v']);
|
||||
|
||||
expect(result.exitCode, 0);
|
||||
expect(result.stdout, isEmpty);
|
||||
expect(result.stderr,
|
||||
contains('The following options are only used for VM development'));
|
||||
});
|
||||
|
||||
test('help', () {
|
||||
p = project();
|
||||
var result = p.runSync('help', []);
|
||||
|
||||
expect(result.exitCode, 0);
|
||||
expect(result.stderr, isEmpty);
|
||||
expect(result.stdout, contains(DartdevRunner.dartdevDescription));
|
||||
expect(result.stdout,
|
||||
contains('Usage: dart [<vm-flags>] <command|dart-file> [<arguments>]'));
|
||||
expect(result.stdout, contains('Global options:'));
|
||||
expect(result.stdout, contains('Available commands:'));
|
||||
expect(result.stdout, contains('analyze '));
|
||||
expect(result.stdout, contains('create '));
|
||||
expect(result.stdout, contains('compile '));
|
||||
expect(result.stdout, contains('format '));
|
||||
expect(result.stdout, contains('migrate '));
|
||||
});
|
||||
|
||||
test('help --verbose', () {
|
||||
p = project();
|
||||
var result = p.runSync('help', ['--verbose']);
|
||||
|
||||
expect(result.exitCode, 0);
|
||||
expect(result.stdout, contains('migrate '));
|
||||
});
|
||||
|
||||
test('help -v', () {
|
||||
p = project();
|
||||
var result = p.runSync('help', ['-v']);
|
||||
|
||||
expect(result.exitCode, 0);
|
||||
expect(result.stdout, contains('migrate '));
|
||||
});
|
||||
|
|
|
@ -55,7 +55,6 @@ class TestProject {
|
|||
String workingDir,
|
||||
}) {
|
||||
var arguments = [
|
||||
absolutePathToDartdevFile,
|
||||
command,
|
||||
if (command == 'migrate')
|
||||
// TODO(srawlins): Enable `pub outdated` in tests.
|
||||
|
@ -64,7 +63,6 @@ class TestProject {
|
|||
];
|
||||
|
||||
arguments.add('--disable-dartdev-analytics');
|
||||
|
||||
return Process.runSync(
|
||||
Platform.resolvedExecutable,
|
||||
arguments,
|
||||
|
|
18
pkg/dds/bin/dds.dart
Normal file
18
pkg/dds/bin/dds.dart
Normal file
|
@ -0,0 +1,18 @@
|
|||
// 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 'package:dds/dds.dart';
|
||||
|
||||
/// A simple program which starts a [DartDevelopmentService] instance with a
|
||||
/// basic configuration.
|
||||
///
|
||||
/// Takes the VM service URI as its single argument.
|
||||
Future<void> main(List<String> args) async {
|
||||
if (args.isEmpty) return;
|
||||
final remoteVmServiceUri = Uri.parse(args.first);
|
||||
await DartDevelopmentService.startDartDevelopmentService(remoteVmServiceUri);
|
||||
stderr.write('DDS started');
|
||||
}
|
|
@ -30,12 +30,26 @@ class _ClientManager {
|
|||
);
|
||||
clients.add(client);
|
||||
client.listen().then((_) => removeClient(client));
|
||||
if (clients.length == 1) {
|
||||
dds.isolateManager.initialize().then((_) {
|
||||
dds.streamManager.streamListen(
|
||||
null,
|
||||
_StreamManager.kDebugStream,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Cleanup state for a disconnected client.
|
||||
void removeClient(_DartDevelopmentServiceClient client) {
|
||||
_clearClientName(client);
|
||||
clients.remove(client);
|
||||
if (clients.isEmpty) {
|
||||
dds.streamManager.streamCancel(
|
||||
null,
|
||||
_StreamManager.kDebugStream,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Cleanup clients on DDS shutdown.
|
||||
|
|
|
@ -85,7 +85,6 @@ class _RunningIsolate {
|
|||
if (_resumeApprovalsByName.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If all the required approvals are present, we should resume.
|
||||
return _resumeApprovalsByName.containsAll(requiredClientApprovals);
|
||||
}
|
||||
|
|
|
@ -117,12 +117,15 @@ class _StreamManager {
|
|||
) async {
|
||||
assert(stream != null && stream.isNotEmpty);
|
||||
if (!streamListeners.containsKey(stream)) {
|
||||
// This will return an RPC exception if the stream doesn't exist. This
|
||||
// will throw and the exception will be forwarded to the client.
|
||||
final result = await dds._vmServiceClient.sendRequest('streamListen', {
|
||||
'streamId': stream,
|
||||
});
|
||||
assert(result['type'] == 'Success');
|
||||
if ((stream == kDebugStream && client == null) ||
|
||||
stream != kDebugStream) {
|
||||
// This will return an RPC exception if the stream doesn't exist. This
|
||||
// will throw and the exception will be forwarded to the client.
|
||||
final result = await dds._vmServiceClient.sendRequest('streamListen', {
|
||||
'streamId': stream,
|
||||
});
|
||||
assert(result['type'] == 'Success');
|
||||
}
|
||||
streamListeners[stream] = <_DartDevelopmentServiceClient>[];
|
||||
}
|
||||
if (streamListeners[stream].contains(client)) {
|
||||
|
@ -142,16 +145,18 @@ class _StreamManager {
|
|||
/// send a `streamCancel` request for `stream` to the VM service.
|
||||
Future<void> streamCancel(
|
||||
_DartDevelopmentServiceClient client,
|
||||
String stream,
|
||||
) async {
|
||||
String stream, {
|
||||
bool cancelCoreStream = false,
|
||||
}) async {
|
||||
assert(stream != null && stream.isNotEmpty);
|
||||
final listeners = streamListeners[stream];
|
||||
if (listeners == null || !listeners.contains(client)) {
|
||||
if (client != null && (listeners == null || !listeners.contains(client))) {
|
||||
throw kStreamNotSubscribedException;
|
||||
}
|
||||
listeners.remove(client);
|
||||
// Don't cancel streams DDS needs to function.
|
||||
if (listeners.isEmpty && !ddsCoreStreams.contains(stream)) {
|
||||
if (listeners.isEmpty &&
|
||||
(!ddsCoreStreams.contains(stream) || cancelCoreStream)) {
|
||||
streamListeners.remove(stream);
|
||||
// Ensure the VM service hasn't shutdown.
|
||||
if (dds._vmServiceClient.isClosed) {
|
||||
|
|
|
@ -103,6 +103,10 @@ abstract class TestCase {
|
|||
'--enable-vm-service=0', // Note: use 0 to avoid port collisions.
|
||||
'--pause_isolates_on_start',
|
||||
'--disable-service-auth-codes',
|
||||
// TODO(bkonyi): The service isolate starts before DartDev has a chance
|
||||
// to spawn DDS. We should suppress the Observatory message until DDS
|
||||
// starts (#42727).
|
||||
'--disable-dart-dev',
|
||||
outputUri.toFilePath()
|
||||
];
|
||||
vmArgs.add('$reloadCount');
|
||||
|
|
|
@ -13,6 +13,7 @@ main(List<String> args) async {
|
|||
LeakFinder heapHelper = new LeakFinder();
|
||||
|
||||
heapHelper.start([
|
||||
"--disable-dart-dev",
|
||||
"--enable-asserts",
|
||||
Platform.script.resolve("incremental_dart2js_tester.dart").toString(),
|
||||
"--addDebugBreaks",
|
||||
|
|
|
@ -56,6 +56,7 @@ benchmark
|
|||
besides
|
||||
beta
|
||||
bigger
|
||||
bkonyi
|
||||
blah
|
||||
blindly
|
||||
blocked
|
||||
|
@ -129,6 +130,7 @@ dash
|
|||
dashes
|
||||
day
|
||||
db
|
||||
dds
|
||||
debugger
|
||||
decrease
|
||||
decrements
|
||||
|
@ -502,6 +504,7 @@ slight
|
|||
smoke
|
||||
somehow
|
||||
spans
|
||||
spawn
|
||||
spell
|
||||
spellcheck
|
||||
spelled
|
||||
|
|
|
@ -453,6 +453,7 @@ main() {
|
|||
"--pause-isolates-on-exit",
|
||||
"--enable-vm-service:0",
|
||||
"--disable-service-auth-codes",
|
||||
"--disable-dart-dev",
|
||||
list.path
|
||||
]);
|
||||
|
||||
|
@ -579,6 +580,7 @@ main() {
|
|||
"--pause-isolates-on-exit",
|
||||
"--enable-vm-service:0",
|
||||
"--disable-service-auth-codes",
|
||||
"--disable-dart-dev",
|
||||
list.path
|
||||
]);
|
||||
|
||||
|
@ -658,6 +660,7 @@ main() {
|
|||
'--enable-vm-service=0', // Note: use 0 to avoid port collisions.
|
||||
'--pause_isolates_on_start',
|
||||
'--disable-service-auth-codes',
|
||||
'--disable-dart-dev',
|
||||
outputFile.path
|
||||
];
|
||||
final vm = await Process.start(Platform.resolvedExecutable, vmArgs);
|
||||
|
@ -917,6 +920,7 @@ main() {
|
|||
"--pause-isolates-on-start",
|
||||
"--enable-vm-service:0",
|
||||
"--disable-service-auth-codes",
|
||||
"--disable-dart-dev",
|
||||
scriptOrDill.path
|
||||
]);
|
||||
|
||||
|
|
|
@ -878,6 +878,8 @@ dart_executable("dart") {
|
|||
}
|
||||
extra_sources = [
|
||||
"builtin.cc",
|
||||
"dartdev_isolate.cc",
|
||||
"dartdev_isolate.h",
|
||||
"dfe.cc",
|
||||
"dfe.h",
|
||||
"gzip.cc",
|
||||
|
|
|
@ -15,8 +15,6 @@ builtin_impl_sources = [
|
|||
"crypto_linux.cc",
|
||||
"crypto_macos.cc",
|
||||
"crypto_win.cc",
|
||||
"dartdev_utils.cc",
|
||||
"dartdev_utils.h",
|
||||
"dartutils.cc",
|
||||
"dartutils.h",
|
||||
"directory.cc",
|
||||
|
|
262
runtime/bin/dartdev_isolate.cc
Normal file
262
runtime/bin/dartdev_isolate.cc
Normal file
|
@ -0,0 +1,262 @@
|
|||
// 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.
|
||||
|
||||
#include "bin/dartdev_isolate.h"
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "bin/directory.h"
|
||||
#include "bin/error_exit.h"
|
||||
#include "bin/exe_utils.h"
|
||||
#include "bin/file.h"
|
||||
#include "bin/lockers.h"
|
||||
#include "bin/platform.h"
|
||||
#include "bin/process.h"
|
||||
#include "include/dart_embedder_api.h"
|
||||
#include "platform/utils.h"
|
||||
|
||||
#define CHECK_RESULT(result) \
|
||||
if (Dart_IsError(result)) { \
|
||||
ProcessError(Dart_GetError(result), kErrorExitCode); \
|
||||
if (send_port_id != ILLEGAL_PORT) { \
|
||||
Dart_CloseNativePort(send_port_id); \
|
||||
} \
|
||||
Dart_ExitScope(); \
|
||||
Dart_ExitIsolate(); \
|
||||
return; \
|
||||
}
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
DartDevIsolate::DartDevRunner DartDevIsolate::runner_ =
|
||||
DartDevIsolate::DartDevRunner();
|
||||
bool DartDevIsolate::should_run_dart_dev_ = false;
|
||||
Monitor* DartDevIsolate::DartDevRunner::monitor_ = new Monitor();
|
||||
DartDevIsolate::DartDev_Result DartDevIsolate::DartDevRunner::result_ =
|
||||
DartDevIsolate::DartDev_Result_Unknown;
|
||||
char** DartDevIsolate::DartDevRunner::script_ = nullptr;
|
||||
std::unique_ptr<char*[], void (*)(char*[])>
|
||||
DartDevIsolate::DartDevRunner::argv_ =
|
||||
std::unique_ptr<char*[], void (*)(char**)>(nullptr, [](char**) {});
|
||||
intptr_t DartDevIsolate::DartDevRunner::argc_ = 0;
|
||||
|
||||
bool DartDevIsolate::ShouldParseCommand(const char* script_uri) {
|
||||
// If script_uri is not a file path or of a known URI scheme, we can assume
|
||||
// that this is a DartDev command.
|
||||
return (!File::ExistsUri(nullptr, script_uri) &&
|
||||
(strncmp(script_uri, "http://", 7) != 0) &&
|
||||
(strncmp(script_uri, "https://", 8) != 0) &&
|
||||
(strncmp(script_uri, "file://", 7) != 0) &&
|
||||
(strncmp(script_uri, "package:", 8) != 0) &&
|
||||
(strncmp(script_uri, "google3://", 10) != 0));
|
||||
}
|
||||
|
||||
const char* DartDevIsolate::TryResolveDartDevSnapshotPath() {
|
||||
// |dir_prefix| includes the last path seperator.
|
||||
auto dir_prefix = EXEUtils::GetDirectoryPrefixFromExeName();
|
||||
|
||||
// First assume we're in dart-sdk/bin.
|
||||
char* snapshot_path =
|
||||
Utils::SCreate("%ssnapshots/dartdev.dart.snapshot", dir_prefix.get());
|
||||
if (File::Exists(nullptr, snapshot_path)) {
|
||||
return snapshot_path;
|
||||
}
|
||||
free(snapshot_path);
|
||||
|
||||
// If we're not in dart-sdk/bin, we might be in one of the $SDK/out/*
|
||||
// directories. Try to use a snapshot rom a previously built SDK.
|
||||
snapshot_path = Utils::SCreate("%sdartdev.dart.snapshot", dir_prefix.get());
|
||||
if (File::Exists(nullptr, snapshot_path)) {
|
||||
return snapshot_path;
|
||||
}
|
||||
free(snapshot_path);
|
||||
|
||||
Syslog::PrintErr("Could not find DartDev snapshot.\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DartDevIsolate::DartDevRunner::Run(
|
||||
Dart_IsolateGroupCreateCallback create_isolate,
|
||||
const char* packages_file,
|
||||
char** script,
|
||||
CommandLineOptions* dart_options) {
|
||||
create_isolate_ = create_isolate;
|
||||
dart_options_ = dart_options;
|
||||
packages_file_ = packages_file;
|
||||
script_ = script;
|
||||
|
||||
MonitorLocker locker(monitor_);
|
||||
int result = Thread::Start("DartDev Runner", RunCallback,
|
||||
reinterpret_cast<uword>(this));
|
||||
if (result != 0) {
|
||||
FATAL1("Failed to start DartDev thread: %d", result);
|
||||
}
|
||||
monitor_->WaitMicros(Monitor::kNoTimeout);
|
||||
|
||||
if (result_ == DartDevIsolate::DartDev_Result_Run) {
|
||||
// Clear the DartDev dart_options and replace them with the processed
|
||||
// options provided by DartDev.
|
||||
dart_options_->Reset();
|
||||
for (intptr_t i = 0; i < argc_; ++i) {
|
||||
dart_options_->AddArguments(const_cast<const char**>(argv_.get()), argc_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Dart_CObject* GetArrayItem(Dart_CObject* message, intptr_t index) {
|
||||
return message->value.as_array.values[index];
|
||||
}
|
||||
|
||||
void DartDevIsolate::DartDevRunner::DartDevResultCallback(
|
||||
Dart_Port dest_port_id,
|
||||
Dart_CObject* message) {
|
||||
ASSERT(message->type == Dart_CObject_kArray);
|
||||
int32_t type = GetArrayItem(message, 0)->value.as_int32;
|
||||
switch (type) {
|
||||
case DartDevIsolate::DartDev_Result_Run: {
|
||||
result_ = DartDevIsolate::DartDev_Result_Run;
|
||||
ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString);
|
||||
if (*script_ != nullptr) {
|
||||
free(*script_);
|
||||
}
|
||||
*script_ = Utils::StrDup(GetArrayItem(message, 1)->value.as_string);
|
||||
ASSERT(GetArrayItem(message, 2)->type == Dart_CObject_kArray);
|
||||
Dart_CObject* args = GetArrayItem(message, 2);
|
||||
argc_ = args->value.as_array.length;
|
||||
Dart_CObject** dart_args = args->value.as_array.values;
|
||||
|
||||
auto deleter = [](char** args) {
|
||||
for (intptr_t i = 0; i < argc_; ++i) {
|
||||
free(args[i]);
|
||||
}
|
||||
delete[] args;
|
||||
};
|
||||
|
||||
argv_ =
|
||||
std::unique_ptr<char*[], void (*)(char**)>(new char*[argc_], deleter);
|
||||
for (intptr_t i = 0; i < argc_; ++i) {
|
||||
argv_[i] = Utils::StrDup(dart_args[i]->value.as_string);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DartDevIsolate::DartDev_Result_Exit: {
|
||||
ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kInt32);
|
||||
int32_t dartdev_exit_code = GetArrayItem(message, 1)->value.as_int32;
|
||||
|
||||
// If we're given a non-zero exit code, DartDev is signaling for us to
|
||||
// shutdown.
|
||||
if (dartdev_exit_code != 0) {
|
||||
Process::SetGlobalExitCode(dartdev_exit_code);
|
||||
}
|
||||
|
||||
// If DartDev hasn't signaled for us to do anything else, we can assume
|
||||
// there's nothing else for the VM to run and that we can exit.
|
||||
if (result_ == DartDevIsolate::DartDev_Result_Unknown) {
|
||||
result_ = DartDevIsolate::DartDev_Result_Exit;
|
||||
}
|
||||
|
||||
// DartDev is done processing the command. Unblock the main thread and
|
||||
// continue the launch procedure.
|
||||
DartDevRunner::monitor_->Notify();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void DartDevIsolate::DartDevRunner::RunCallback(uword args) {
|
||||
MonitorLocker locker_(DartDevRunner::monitor_);
|
||||
DartDevRunner* runner = reinterpret_cast<DartDevRunner*>(args);
|
||||
const char* dartdev_path = DartDevIsolate::TryResolveDartDevSnapshotPath();
|
||||
if (dartdev_path == nullptr) {
|
||||
ProcessError("Failed to find DartDev snapshot.", kErrorExitCode);
|
||||
return;
|
||||
}
|
||||
Dart_IsolateFlags flags;
|
||||
Dart_IsolateFlagsInitialize(&flags);
|
||||
char* error;
|
||||
Dart_Isolate dartdev_isolate = runner->create_isolate_(
|
||||
dartdev_path, "dartdev", nullptr, runner->packages_file_, &flags,
|
||||
NULL /* callback_data */, const_cast<char**>(&error));
|
||||
free(const_cast<char*>(dartdev_path));
|
||||
|
||||
if (dartdev_isolate == nullptr) {
|
||||
ProcessError(error, kErrorExitCode);
|
||||
return;
|
||||
}
|
||||
|
||||
Dart_EnterIsolate(dartdev_isolate);
|
||||
Dart_EnterScope();
|
||||
|
||||
// Retrieve the DartDev entrypoint.
|
||||
Dart_Port send_port_id = ILLEGAL_PORT;
|
||||
Dart_Handle root_lib = Dart_RootLibrary();
|
||||
Dart_Handle main_closure =
|
||||
Dart_GetField(root_lib, Dart_NewStringFromCString("main"));
|
||||
CHECK_RESULT(main_closure);
|
||||
|
||||
if (!Dart_IsClosure(main_closure)) {
|
||||
ProcessError("Unable to find 'main' in root library 'dartdev'",
|
||||
kErrorExitCode);
|
||||
Dart_ExitScope();
|
||||
Dart_ExitIsolate();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a SendPort that DartDev can use to communicate its results over.
|
||||
send_port_id = Dart_NewNativePort("dartdev", DartDevResultCallback, false);
|
||||
ASSERT(send_port_id != ILLEGAL_PORT);
|
||||
Dart_Handle send_port = Dart_NewSendPort(send_port_id);
|
||||
CHECK_RESULT(send_port);
|
||||
|
||||
const intptr_t kNumIsolateArgs = 7;
|
||||
Dart_Handle isolate_args[kNumIsolateArgs];
|
||||
isolate_args[0] = Dart_Null(); // parentPort
|
||||
isolate_args[1] = main_closure; // entryPoint
|
||||
isolate_args[2] = runner->dart_options_->CreateRuntimeOptions(); // args
|
||||
isolate_args[3] = send_port; // message
|
||||
isolate_args[4] = Dart_True(); // isSpawnUri
|
||||
isolate_args[5] = Dart_Null(); // controlPort
|
||||
isolate_args[6] = Dart_Null(); // capabilities
|
||||
|
||||
Dart_Handle isolate_lib =
|
||||
Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
|
||||
Dart_Handle result =
|
||||
Dart_Invoke(isolate_lib, Dart_NewStringFromCString("_startIsolate"),
|
||||
kNumIsolateArgs, isolate_args);
|
||||
CHECK_RESULT(result);
|
||||
CHECK_RESULT(Dart_RunLoop());
|
||||
|
||||
Dart_CloseNativePort(send_port_id);
|
||||
|
||||
Dart_ExitScope();
|
||||
Dart_ShutdownIsolate();
|
||||
}
|
||||
|
||||
void DartDevIsolate::DartDevRunner::ProcessError(const char* msg,
|
||||
int32_t exit_code) {
|
||||
Syslog::PrintErr("%s\n", msg);
|
||||
Process::SetGlobalExitCode(exit_code);
|
||||
result_ = DartDevIsolate::DartDev_Result_Exit;
|
||||
DartDevRunner::monitor_->Notify();
|
||||
}
|
||||
|
||||
DartDevIsolate::DartDev_Result DartDevIsolate::RunDartDev(
|
||||
Dart_IsolateGroupCreateCallback create_isolate,
|
||||
const char* packages_file,
|
||||
char** script,
|
||||
CommandLineOptions* dart_options) {
|
||||
runner_.Run(create_isolate, packages_file, script, dart_options);
|
||||
return runner_.result();
|
||||
}
|
||||
|
||||
#endif // if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
99
runtime/bin/dartdev_isolate.h
Normal file
99
runtime/bin/dartdev_isolate.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
// 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.
|
||||
|
||||
#ifndef RUNTIME_BIN_DARTDEV_ISOLATE_H_
|
||||
#define RUNTIME_BIN_DARTDEV_ISOLATE_H_
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "bin/thread.h"
|
||||
#include "include/dart_api.h"
|
||||
#include "include/dart_native_api.h"
|
||||
#include "platform/globals.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
class CommandLineOptions;
|
||||
|
||||
class DartDevIsolate {
|
||||
public:
|
||||
// Note: keep in sync with pkg/dartdev/lib/vm_interop_handler.dart
|
||||
typedef enum {
|
||||
DartDev_Result_Unknown = -1,
|
||||
DartDev_Result_Run = 1,
|
||||
DartDev_Result_Exit = 2,
|
||||
} DartDev_Result;
|
||||
|
||||
// Returns true if there does not exist a file at |script_uri| or the URI is
|
||||
// not an HTTP resource.
|
||||
static bool ShouldParseCommand(const char* script_uri);
|
||||
|
||||
static void set_should_run_dart_dev(bool enable) {
|
||||
should_run_dart_dev_ = enable;
|
||||
}
|
||||
|
||||
static bool should_run_dart_dev() { return should_run_dart_dev_; }
|
||||
|
||||
// Starts a DartDev instance in a new isolate and runs it to completion.
|
||||
//
|
||||
// Returns true if the VM should run the result in `script`, in which case
|
||||
// `script` and `dart_options` will have been repopulated with the correct
|
||||
// values.
|
||||
static DartDev_Result RunDartDev(
|
||||
Dart_IsolateGroupCreateCallback create_isolate,
|
||||
const char* packages_file,
|
||||
char** script,
|
||||
CommandLineOptions* dart_options);
|
||||
|
||||
protected:
|
||||
class DartDevRunner {
|
||||
public:
|
||||
DartDevRunner() {}
|
||||
|
||||
void Run(Dart_IsolateGroupCreateCallback create_isolate,
|
||||
const char* packages_file,
|
||||
char** script,
|
||||
CommandLineOptions* dart_options);
|
||||
|
||||
DartDev_Result result() const { return result_; }
|
||||
|
||||
private:
|
||||
static void DartDevResultCallback(Dart_Port dest_port_id,
|
||||
Dart_CObject* message);
|
||||
static void RunCallback(uword arg);
|
||||
static void ProcessError(const char* msg, int32_t exit_code);
|
||||
|
||||
static DartDev_Result result_;
|
||||
static char** script_;
|
||||
static std::unique_ptr<char*[], void (*)(char**)> argv_;
|
||||
static intptr_t argc_;
|
||||
|
||||
Dart_IsolateGroupCreateCallback create_isolate_;
|
||||
CommandLineOptions* dart_options_;
|
||||
const char* packages_file_;
|
||||
static Monitor* monitor_;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
};
|
||||
|
||||
private:
|
||||
// Attempts to find the DartDev snapshot. If the snapshot cannot be found,
|
||||
// the VM will shutdown.
|
||||
static const char* TryResolveDartDevSnapshotPath();
|
||||
|
||||
static DartDevRunner runner_;
|
||||
static bool should_run_dart_dev_;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(DartDevIsolate);
|
||||
};
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // RUNTIME_BIN_DARTDEV_ISOLATE_H_
|
|
@ -1,53 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#include "bin/dartdev_utils.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "bin/directory.h"
|
||||
#include "bin/exe_utils.h"
|
||||
#include "bin/file.h"
|
||||
#include "platform/utils.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
bool DartDevUtils::ShouldParseCommand(const char* script_uri) {
|
||||
// If script_uri is not a file path or of a known URI scheme, we can assume
|
||||
// that this is a DartDev command.
|
||||
return (!File::ExistsUri(nullptr, script_uri) &&
|
||||
(strncmp(script_uri, "http://", 7) != 0) &&
|
||||
(strncmp(script_uri, "https://", 8) != 0) &&
|
||||
(strncmp(script_uri, "file://", 7) != 0) &&
|
||||
(strncmp(script_uri, "package:", 8) != 0) &&
|
||||
(strncmp(script_uri, "google3://", 10) != 0));
|
||||
}
|
||||
|
||||
bool DartDevUtils::TryResolveDartDevSnapshotPath(char** script_name) {
|
||||
// |dir_prefix| includes the last path seperator.
|
||||
auto dir_prefix = EXEUtils::GetDirectoryPrefixFromExeName();
|
||||
|
||||
// First assume we're in dart-sdk/bin.
|
||||
char* snapshot_path =
|
||||
Utils::SCreate("%ssnapshots/dartdev.dart.snapshot", dir_prefix.get());
|
||||
if (File::Exists(nullptr, snapshot_path)) {
|
||||
*script_name = snapshot_path;
|
||||
return true;
|
||||
}
|
||||
free(snapshot_path);
|
||||
|
||||
// If we're not in dart-sdk/bin, we might be in one of the $SDK/out/*
|
||||
// directories. Try to use a snapshot from a previously built SDK.
|
||||
snapshot_path = Utils::SCreate("%sdartdev.dart.snapshot", dir_prefix.get());
|
||||
if (File::Exists(nullptr, snapshot_path)) {
|
||||
*script_name = snapshot_path;
|
||||
return true;
|
||||
}
|
||||
free(snapshot_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
|
@ -1,32 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#ifndef RUNTIME_BIN_DARTDEV_UTILS_H_
|
||||
#define RUNTIME_BIN_DARTDEV_UTILS_H_
|
||||
|
||||
#include "platform/globals.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
class DartDevUtils {
|
||||
public:
|
||||
// Returns true if there does not exist a file at |script_uri| or the URI is
|
||||
// not an HTTP resource.
|
||||
static bool ShouldParseCommand(const char* script_uri);
|
||||
|
||||
// Returns true if we were successfully able to find the DartDev snapshot.
|
||||
// Returns false if we were unable to find the snapshot, in which case the
|
||||
// VM should exit.
|
||||
static bool TryResolveDartDevSnapshotPath(char** script_name);
|
||||
|
||||
private:
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(DartDevUtils);
|
||||
};
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_BIN_DARTDEV_UTILS_H_
|
|
@ -12,11 +12,9 @@
|
|||
#include "bin/namespace.h"
|
||||
#include "bin/platform.h"
|
||||
#include "bin/utils.h"
|
||||
|
||||
#include "include/dart_api.h"
|
||||
#include "include/dart_native_api.h"
|
||||
#include "include/dart_tools_api.h"
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/globals.h"
|
||||
#include "platform/memory_sanitizer.h"
|
||||
|
@ -68,6 +66,29 @@ static bool IsWindowsHost() {
|
|||
#endif // defined(HOST_OS_WINDOWS)
|
||||
}
|
||||
|
||||
Dart_Handle CommandLineOptions::CreateRuntimeOptions() {
|
||||
Dart_Handle string_type = DartUtils::GetDartType("dart:core", "String");
|
||||
if (Dart_IsError(string_type)) {
|
||||
return string_type;
|
||||
}
|
||||
Dart_Handle dart_arguments =
|
||||
Dart_NewListOfTypeFilled(string_type, Dart_EmptyString(), count_);
|
||||
if (Dart_IsError(dart_arguments)) {
|
||||
return dart_arguments;
|
||||
}
|
||||
for (int i = 0; i < count_; i++) {
|
||||
Dart_Handle argument_value = DartUtils::NewString(GetArgument(i));
|
||||
if (Dart_IsError(argument_value)) {
|
||||
return argument_value;
|
||||
}
|
||||
Dart_Handle result = Dart_ListSetAt(dart_arguments, i, argument_value);
|
||||
if (Dart_IsError(result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return dart_arguments;
|
||||
}
|
||||
|
||||
int64_t DartUtils::GetIntegerValue(Dart_Handle value_obj) {
|
||||
int64_t value = 0;
|
||||
Dart_Handle result = Dart_IntegerToInt64(value_obj, &value);
|
||||
|
|
|
@ -55,6 +55,8 @@ class CommandLineOptions {
|
|||
arguments_ = NULL;
|
||||
}
|
||||
|
||||
void Reset() { count_ = 0; }
|
||||
|
||||
int count() const { return count_; }
|
||||
int max_count() const { return max_count_; }
|
||||
const char** arguments() const { return arguments_; }
|
||||
|
@ -80,6 +82,8 @@ class CommandLineOptions {
|
|||
}
|
||||
}
|
||||
|
||||
Dart_Handle CreateRuntimeOptions();
|
||||
|
||||
void operator delete(void* pointer) { abort(); }
|
||||
|
||||
private:
|
||||
|
|
|
@ -5,16 +5,13 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <memory>
|
||||
|
||||
#include "include/bin/dart_io_api.h"
|
||||
#include "include/dart_api.h"
|
||||
#include "include/dart_embedder_api.h"
|
||||
#include "include/dart_tools_api.h"
|
||||
#include <memory>
|
||||
|
||||
#include "bin/builtin.h"
|
||||
#include "bin/console.h"
|
||||
#include "bin/crashpad.h"
|
||||
#include "bin/dartdev_isolate.h"
|
||||
#include "bin/dartutils.h"
|
||||
#include "bin/dfe.h"
|
||||
#include "bin/error_exit.h"
|
||||
|
@ -31,6 +28,10 @@
|
|||
#include "bin/thread.h"
|
||||
#include "bin/utils.h"
|
||||
#include "bin/vmservice_impl.h"
|
||||
#include "include/bin/dart_io_api.h"
|
||||
#include "include/dart_api.h"
|
||||
#include "include/dart_embedder_api.h"
|
||||
#include "include/dart_tools_api.h"
|
||||
#include "platform/globals.h"
|
||||
#include "platform/growable_array.h"
|
||||
#include "platform/hashmap.h"
|
||||
|
@ -74,30 +75,6 @@ static Dart_Isolate main_isolate = NULL;
|
|||
|
||||
static void ReadFile(const char* filename, uint8_t** buffer, intptr_t* size);
|
||||
|
||||
static Dart_Handle CreateRuntimeOptions(CommandLineOptions* options) {
|
||||
int options_count = options->count();
|
||||
Dart_Handle string_type = DartUtils::GetDartType("dart:core", "String");
|
||||
if (Dart_IsError(string_type)) {
|
||||
return string_type;
|
||||
}
|
||||
Dart_Handle dart_arguments =
|
||||
Dart_NewListOfTypeFilled(string_type, Dart_EmptyString(), options_count);
|
||||
if (Dart_IsError(dart_arguments)) {
|
||||
return dart_arguments;
|
||||
}
|
||||
for (int i = 0; i < options_count; i++) {
|
||||
Dart_Handle argument_value = DartUtils::NewString(options->GetArgument(i));
|
||||
if (Dart_IsError(argument_value)) {
|
||||
return argument_value;
|
||||
}
|
||||
Dart_Handle result = Dart_ListSetAt(dart_arguments, i, argument_value);
|
||||
if (Dart_IsError(result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return dart_arguments;
|
||||
}
|
||||
|
||||
#define SAVE_ERROR_AND_EXIT(result) \
|
||||
*error = Utils::StrDup(Dart_GetError(result)); \
|
||||
if (Dart_IsCompilationError(result)) { \
|
||||
|
@ -405,6 +382,15 @@ static Dart_Isolate IsolateSetupHelper(Dart_Isolate isolate,
|
|||
CHECK_RESULT(result);
|
||||
}
|
||||
|
||||
// Disable pausing the DartDev isolate on start and exit.
|
||||
const char* isolate_name = nullptr;
|
||||
result = Dart_StringToCString(Dart_DebugName(), &isolate_name);
|
||||
CHECK_RESULT(result);
|
||||
if (strstr(isolate_name, "dartdev") != nullptr) {
|
||||
Dart_SetShouldPauseOnStart(false);
|
||||
Dart_SetShouldPauseOnExit(false);
|
||||
}
|
||||
|
||||
// Make the isolate runnable so that it is ready to handle messages.
|
||||
Dart_ExitScope();
|
||||
Dart_ExitIsolate();
|
||||
|
@ -941,8 +927,8 @@ bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) {
|
|||
// initial startup message.
|
||||
const intptr_t kNumIsolateArgs = 2;
|
||||
Dart_Handle isolate_args[kNumIsolateArgs];
|
||||
isolate_args[0] = main_closure; // entryPoint
|
||||
isolate_args[1] = CreateRuntimeOptions(dart_options); // args
|
||||
isolate_args[0] = main_closure; // entryPoint
|
||||
isolate_args[1] = dart_options->CreateRuntimeOptions(); // args
|
||||
|
||||
Dart_Handle isolate_lib =
|
||||
Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
|
||||
|
@ -1011,7 +997,7 @@ static Dart_GetVMServiceAssetsArchive GetVMServiceAssetsArchiveCallback = NULL;
|
|||
#endif // !defined(PRODUCT)
|
||||
|
||||
void main(int argc, char** argv) {
|
||||
char* script_name;
|
||||
char* script_name = nullptr;
|
||||
const int EXTRA_VM_ARGUMENTS = 10;
|
||||
CommandLineOptions vm_options(argc + EXTRA_VM_ARGUMENTS);
|
||||
CommandLineOptions dart_options(argc + EXTRA_VM_ARGUMENTS);
|
||||
|
@ -1101,9 +1087,6 @@ void main(int argc, char** argv) {
|
|||
}
|
||||
}
|
||||
|
||||
// At this point, script_name now points to either a script or a snapshot
|
||||
// determined by DartDevUtils above.
|
||||
|
||||
DartUtils::SetEnvironment(Options::environment());
|
||||
|
||||
if (Options::suppress_core_dump()) {
|
||||
|
@ -1114,19 +1097,28 @@ void main(int argc, char** argv) {
|
|||
|
||||
Loader::InitOnce();
|
||||
|
||||
if (app_snapshot == nullptr) {
|
||||
// For testing purposes we add a flag to debug-mode to use the
|
||||
// in-memory ELF loader.
|
||||
const bool force_load_elf_from_memory =
|
||||
false DEBUG_ONLY(|| Options::force_load_elf_from_memory());
|
||||
app_snapshot =
|
||||
Snapshot::TryReadAppSnapshot(script_name, force_load_elf_from_memory);
|
||||
}
|
||||
if (app_snapshot != nullptr) {
|
||||
vm_run_app_snapshot = true;
|
||||
app_snapshot->SetBuffers(&vm_snapshot_data, &vm_snapshot_instructions,
|
||||
&app_isolate_snapshot_data,
|
||||
&app_isolate_snapshot_instructions);
|
||||
auto try_load_snapshots_lambda = [&](void) -> void {
|
||||
if (app_snapshot == nullptr) {
|
||||
// For testing purposes we add a flag to debug-mode to use the
|
||||
// in-memory ELF loader.
|
||||
const bool force_load_elf_from_memory =
|
||||
false DEBUG_ONLY(|| Options::force_load_elf_from_memory());
|
||||
app_snapshot =
|
||||
Snapshot::TryReadAppSnapshot(script_name, force_load_elf_from_memory);
|
||||
}
|
||||
if (app_snapshot != nullptr) {
|
||||
vm_run_app_snapshot = true;
|
||||
app_snapshot->SetBuffers(&vm_snapshot_data, &vm_snapshot_instructions,
|
||||
&app_isolate_snapshot_data,
|
||||
&app_isolate_snapshot_instructions);
|
||||
}
|
||||
};
|
||||
|
||||
// At this point, script_name now points to a script if DartDev is disabled
|
||||
// or a valid file path was provided as the first non-flag argument.
|
||||
// Otherwise, script_name can be NULL if DartDev should be run.
|
||||
if (script_name != nullptr) {
|
||||
try_load_snapshots_lambda();
|
||||
}
|
||||
|
||||
if (Options::gen_snapshot_kind() == kAppJIT) {
|
||||
|
@ -1159,16 +1151,18 @@ void main(int argc, char** argv) {
|
|||
// Note: must read platform only *after* VM flags are parsed because
|
||||
// they might affect how the platform is loaded.
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
dfe.Init(Options::target_abi_version());
|
||||
uint8_t* application_kernel_buffer = NULL;
|
||||
intptr_t application_kernel_buffer_size = 0;
|
||||
dfe.ReadScript(script_name, &application_kernel_buffer,
|
||||
&application_kernel_buffer_size);
|
||||
if (application_kernel_buffer != NULL) {
|
||||
// Since we loaded the script anyway, save it.
|
||||
dfe.set_application_kernel_buffer(application_kernel_buffer,
|
||||
application_kernel_buffer_size);
|
||||
Options::dfe()->set_use_dfe();
|
||||
if (script_name != nullptr) {
|
||||
dfe.Init(Options::target_abi_version());
|
||||
uint8_t* application_kernel_buffer = NULL;
|
||||
intptr_t application_kernel_buffer_size = 0;
|
||||
dfe.ReadScript(script_name, &application_kernel_buffer,
|
||||
&application_kernel_buffer_size);
|
||||
if (application_kernel_buffer != NULL) {
|
||||
// Since we loaded the script anyway, save it.
|
||||
dfe.set_application_kernel_buffer(application_kernel_buffer,
|
||||
application_kernel_buffer_size);
|
||||
Options::dfe()->set_use_dfe();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1208,10 +1202,29 @@ void main(int argc, char** argv) {
|
|||
&ServiceStreamCancelCallback);
|
||||
Dart_SetFileModifiedCallback(&FileModifiedCallback);
|
||||
Dart_SetEmbedderInformationCallback(&EmbedderInformationCallback);
|
||||
bool ran_dart_dev = false;
|
||||
bool should_run_user_program = true;
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (DartDevIsolate::should_run_dart_dev() && !Options::disable_dart_dev() &&
|
||||
Options::gen_snapshot_kind() == SnapshotKind::kNone) {
|
||||
DartDevIsolate::DartDev_Result dartdev_result = DartDevIsolate::RunDartDev(
|
||||
CreateIsolateGroupAndSetup, Options::packages_file(), &script_name,
|
||||
&dart_options);
|
||||
ASSERT(dartdev_result != DartDevIsolate::DartDev_Result_Unknown);
|
||||
ran_dart_dev = true;
|
||||
should_run_user_program =
|
||||
(dartdev_result == DartDevIsolate::DartDev_Result_Run);
|
||||
if (should_run_user_program) {
|
||||
try_load_snapshots_lambda();
|
||||
}
|
||||
}
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
// Run the main isolate until we aren't told to restart.
|
||||
while (RunMainIsolate(script_name, &dart_options)) {
|
||||
Syslog::PrintErr("Restarting VM\n");
|
||||
if (should_run_user_program) {
|
||||
// Run the main isolate until we aren't told to restart.
|
||||
while (RunMainIsolate(script_name, &dart_options)) {
|
||||
Syslog::PrintErr("Restarting VM\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Terminate process exit-code handler.
|
||||
|
@ -1227,6 +1240,9 @@ void main(int argc, char** argv) {
|
|||
|
||||
delete app_snapshot;
|
||||
free(app_script_uri);
|
||||
if (ran_dart_dev && script_name != nullptr) {
|
||||
free(script_name);
|
||||
}
|
||||
|
||||
// Free copied argument strings if converted.
|
||||
if (argv_converted) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "bin/abi_version.h"
|
||||
#include "bin/dartdev_utils.h"
|
||||
#include "bin/dartdev_isolate.h"
|
||||
#include "bin/error_exit.h"
|
||||
#include "bin/options.h"
|
||||
#include "bin/platform.h"
|
||||
|
@ -35,9 +35,6 @@ static const char* kSnapshotKindNames[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static const char* kEnableExperiment1 = "--enable-experiment";
|
||||
static const char* kEnableExperiment2 = "--enable_experiment";
|
||||
|
||||
SnapshotKind Options::gen_snapshot_kind_ = kNone;
|
||||
bool Options::enable_vm_service_ = false;
|
||||
MallocGrowableArray<const char*> Options::enabled_experiments_ =
|
||||
|
@ -381,27 +378,17 @@ bool Options::ProcessEnableExperimentOption(const char* arg,
|
|||
return false;
|
||||
}
|
||||
vm_options->AddArgument(arg);
|
||||
Utils::CStringUniquePtr tmp = Utils::CreateCStringUniquePtr(
|
||||
Utils::StrDup(value));
|
||||
Utils::CStringUniquePtr tmp =
|
||||
Utils::CreateCStringUniquePtr(Utils::StrDup(value));
|
||||
char* save_ptr; // Needed for strtok_r.
|
||||
char* token = strtok_r(const_cast<char*>(tmp.get()), ",", &save_ptr);
|
||||
while (token != NULL) {
|
||||
enabled_experiments_.Add(token);
|
||||
enabled_experiments_.Add(Utils::StrDup(token));
|
||||
token = strtok_r(NULL, ",", &save_ptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ResolveDartDevSnapshotPath(const char* script,
|
||||
char** snapshot_path) {
|
||||
if (!DartDevUtils::TryResolveDartDevSnapshotPath(snapshot_path)) {
|
||||
Syslog::PrintErr(
|
||||
"Could not find DartDev snapshot and '%s' is not a valid script.\n",
|
||||
script);
|
||||
Platform::Exit(kErrorExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
int Options::ParseArguments(int argc,
|
||||
char** argv,
|
||||
bool vm_run_app_snapshot,
|
||||
|
@ -476,17 +463,11 @@ int Options::ParseArguments(int argc,
|
|||
}
|
||||
}
|
||||
|
||||
if (!Options::disable_dart_dev()) {
|
||||
// Don't start the VM service for the DartDev process. Without doing a
|
||||
// second pass over the argument list to explicitly check for
|
||||
// --disable-dart-dev, this is the earliest we can assume we know whether
|
||||
// or not we're running with DartDev enabled.
|
||||
vm_service_server_port_ = INVALID_VM_SERVICE_SERVER_PORT;
|
||||
vm_service_server_ip_ = DEFAULT_VM_SERVICE_SERVER_IP;
|
||||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
Options::dfe()->set_use_dfe();
|
||||
#else
|
||||
// DartDev is not supported in AOT.
|
||||
Options::disable_dart_dev_ = true;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (Options::deterministic()) {
|
||||
// Both an embedder and VM flag.
|
||||
|
@ -503,24 +484,31 @@ int Options::ParseArguments(int argc,
|
|||
// The arguments to the VM are at positions 1 through i-1 in argv.
|
||||
Platform::SetExecutableArguments(i, argv);
|
||||
|
||||
bool implicitly_use_dart_dev = false;
|
||||
bool run_script = false;
|
||||
int script_or_cmd_index = -1;
|
||||
|
||||
// Get the script name.
|
||||
if (i < argc) {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
// If the script name is a valid file or a URL, we'll run the script
|
||||
// directly. Otherwise, this might be a DartDev command and we need to try
|
||||
// to find the DartDev snapshot so we can forward the command and its
|
||||
// arguments.
|
||||
bool is_potential_file_path = !DartDevUtils::ShouldParseCommand(argv[i]);
|
||||
bool is_potential_file_path = !DartDevIsolate::ShouldParseCommand(argv[i]);
|
||||
bool implicitly_use_dart_dev = false;
|
||||
#else
|
||||
bool is_potential_file_path = true;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
script_or_cmd_index = i;
|
||||
if (Options::disable_dart_dev() ||
|
||||
(is_potential_file_path && !enable_vm_service_)) {
|
||||
*script_name = Utils::StrDup(argv[i]);
|
||||
run_script = true;
|
||||
i++;
|
||||
} else {
|
||||
ResolveDartDevSnapshotPath(argv[i], script_name);
|
||||
}
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
else { // NOLINT
|
||||
DartDevIsolate::set_should_run_dart_dev(true);
|
||||
}
|
||||
// Handle the special case where the user is running a Dart program without
|
||||
// using a DartDev command and wants to use the VM service. Here we'll run
|
||||
|
@ -530,10 +518,13 @@ int Options::ParseArguments(int argc,
|
|||
implicitly_use_dart_dev = true;
|
||||
dart_options->AddArgument("run");
|
||||
}
|
||||
} else if (!Options::disable_dart_dev() &&
|
||||
((Options::help_option() && !Options::verbose_option()) ||
|
||||
(argc == 1)) &&
|
||||
DartDevUtils::TryResolveDartDevSnapshotPath(script_name)) {
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
else if (!Options::disable_dart_dev() && // NOLINT
|
||||
((Options::help_option() && !Options::verbose_option()) ||
|
||||
(argc == 1))) {
|
||||
DartDevIsolate::set_should_run_dart_dev(true);
|
||||
// Let DartDev handle the default help message.
|
||||
dart_options->AddArgument("help");
|
||||
return 0;
|
||||
|
@ -541,7 +532,7 @@ int Options::ParseArguments(int argc,
|
|||
(enable_dartdev_analytics || disable_dartdev_analytics)) {
|
||||
// The analytics flags are a special case as we don't have a target script
|
||||
// or DartDev command but we still want to launch DartDev.
|
||||
ResolveDartDevSnapshotPath(argv[i], script_name);
|
||||
DartDevIsolate::set_should_run_dart_dev(true);
|
||||
|
||||
if (enable_dartdev_analytics) {
|
||||
dart_options->AddArgument("--enable-analytics");
|
||||
|
@ -550,89 +541,68 @@ int Options::ParseArguments(int argc,
|
|||
dart_options->AddArgument("--disable-analytics");
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
else { // NOLINT
|
||||
return -1;
|
||||
}
|
||||
const char** vm_argv = temp_vm_options.arguments();
|
||||
int vm_argc = temp_vm_options.count();
|
||||
|
||||
if (Options::disable_dart_dev() || run_script) {
|
||||
// Only populate the VM options if we're not running with DartDev.
|
||||
vm_options->AddArguments(vm_argv, vm_argc);
|
||||
} else if (implicitly_use_dart_dev) {
|
||||
// If we're using DartDev implicitly (e.g., dart --observe foo.dart), we
|
||||
// want to forward all the VM arguments to the spawned process to ensure
|
||||
// the program behaves as the user expects even though we're running
|
||||
// through DartDev without their knowledge.
|
||||
dart_options->AddArguments(const_cast<const char**>(argv + 1),
|
||||
script_or_cmd_index - 1);
|
||||
} else if (i > 1) {
|
||||
// If we're running with DartDev, we're going to ignore the VM options for
|
||||
// this VM instance and print a warning.
|
||||
vm_options->AddArguments(vm_argv, vm_argc);
|
||||
|
||||
int num_experiment_flags = 0;
|
||||
if (!enabled_experiments_.is_empty()) {
|
||||
for (intptr_t j = 1; j < script_or_cmd_index; ++j) {
|
||||
if ((strstr(argv[j], kEnableExperiment1) != nullptr) ||
|
||||
(strstr(argv[j], kEnableExperiment2) != nullptr)) {
|
||||
++num_experiment_flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num_experiment_flags + 1 != script_or_cmd_index) {
|
||||
Syslog::PrintErr(
|
||||
"Warning: The following flags were passed as VM options and are "
|
||||
"being "
|
||||
"ignored:\n\n");
|
||||
for (int j = 1; j < script_or_cmd_index; ++j) {
|
||||
if ((strstr(argv[j], kEnableExperiment1) == nullptr) &&
|
||||
(strstr(argv[j], kEnableExperiment2) == nullptr)) {
|
||||
Syslog::PrintErr(" %s\n", argv[j]);
|
||||
}
|
||||
}
|
||||
Syslog::PrintErr(
|
||||
"\nThese flags should be passed after the dart command (e.g., 'dart "
|
||||
"run --enable-asserts foo.dart' instead of 'dart --enable-asserts "
|
||||
"run "
|
||||
"foo.dart').\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!enabled_experiments_.is_empty() &&
|
||||
!(Options::disable_dart_dev() || run_script)) {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (!enabled_experiments_.is_empty()) {
|
||||
intptr_t num_experiments = enabled_experiments_.length();
|
||||
int option_size = strlen(kEnableExperiment1) + 1;
|
||||
for (intptr_t i = 0; i < num_experiments; ++i) {
|
||||
const char* flag = enabled_experiments_.At(i);
|
||||
option_size += strlen(flag);
|
||||
if (i + 1 != num_experiments) {
|
||||
// Account for comma if there's more experiments to add.
|
||||
++option_size;
|
||||
if (!(Options::disable_dart_dev() || run_script)) {
|
||||
const char* kEnableExperiment = "--enable-experiment=";
|
||||
int option_size = strlen(kEnableExperiment);
|
||||
for (intptr_t i = 0; i < num_experiments; ++i) {
|
||||
const char* flag = enabled_experiments_.At(i);
|
||||
option_size += strlen(flag);
|
||||
if (i + 1 != num_experiments) {
|
||||
// Account for comma if there's more experiments to add.
|
||||
++option_size;
|
||||
}
|
||||
}
|
||||
// Make room for null terminator
|
||||
++option_size;
|
||||
|
||||
char* enabled_experiments_arg = new char[option_size];
|
||||
int offset = snprintf(enabled_experiments_arg, option_size, "%s",
|
||||
kEnableExperiment);
|
||||
for (intptr_t i = 0; i < num_experiments; ++i) {
|
||||
const char* flag = enabled_experiments_.At(i);
|
||||
const char* kFormat = (i + 1 != num_experiments) ? "%s," : "%s";
|
||||
offset += snprintf(enabled_experiments_arg + offset,
|
||||
option_size - offset, kFormat, flag);
|
||||
free(const_cast<char*>(flag));
|
||||
ASSERT(offset < option_size);
|
||||
}
|
||||
DartDevIsolate::set_should_run_dart_dev(true);
|
||||
dart_options->AddArgument(enabled_experiments_arg);
|
||||
} else {
|
||||
for (intptr_t i = 0; i < num_experiments; ++i) {
|
||||
free(const_cast<char*>(enabled_experiments_.At(i)));
|
||||
}
|
||||
}
|
||||
// Make room for null terminator
|
||||
++option_size;
|
||||
|
||||
char* enabled_experiments_arg = new char[option_size];
|
||||
int offset = snprintf(enabled_experiments_arg, option_size,
|
||||
"%s=", kEnableExperiment1);
|
||||
for (intptr_t i = 0; i < num_experiments; ++i) {
|
||||
const char* flag = enabled_experiments_.At(i);
|
||||
const char* kFormat = (i + 1 != num_experiments) ? "%s," : "%s";
|
||||
offset += snprintf(enabled_experiments_arg + offset, option_size - offset,
|
||||
kFormat, flag);
|
||||
ASSERT(offset < option_size);
|
||||
}
|
||||
dart_options->AddArgument(enabled_experiments_arg);
|
||||
}
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
// Parse out options to be passed to dart main.
|
||||
while (i < argc) {
|
||||
if (!run_script) {
|
||||
OptionProcessor::TryProcess(argv[i], vm_options);
|
||||
}
|
||||
dart_options->AddArgument(argv[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!Options::disable_dart_dev() && enable_vm_service_) {
|
||||
dart_options->AddArgument("--launch-dds");
|
||||
}
|
||||
|
||||
// Verify consistency of arguments.
|
||||
|
||||
// snapshot_depfile is an alias for depfile. Passing them both is an error.
|
||||
|
|
|
@ -18,7 +18,11 @@ class _HtmlWebSocket implements CommonWebSocket {
|
|||
|
||||
void connect(String address, void onOpen(), void onMessage(dynamic data),
|
||||
void onError(), void onClose()) {
|
||||
_webSocket = new WebSocket(address);
|
||||
// The VM service will attempt to redirect our websocket connection request
|
||||
// to DDS, but the dart:html WebSocket doesn't follow redirects. If the
|
||||
// 'implicit-redirect' protocol is provided, the VM service will manually
|
||||
// forward traffic to DDS.
|
||||
_webSocket = new WebSocket(address, ['implicit-redirect']);
|
||||
_webSocket.onClose.listen((CloseEvent) => onClose());
|
||||
_webSocket.onError.listen((Event) => onError());
|
||||
_webSocket.onOpen.listen((Event) => onOpen());
|
||||
|
|
|
@ -1117,6 +1117,9 @@ void Service::HandleEvent(ServiceEvent* event) {
|
|||
}
|
||||
// Ignore events when no one is listening to the event stream.
|
||||
return;
|
||||
} else if (event->stream_info() != NULL &&
|
||||
FLAG_warn_on_pause_with_no_debugger && event->IsPause()) {
|
||||
ReportPauseOnConsole(event);
|
||||
}
|
||||
if (!ServiceIsolate::IsRunning()) {
|
||||
return;
|
||||
|
|
|
@ -47,6 +47,7 @@ declare_args() {
|
|||
# ........analysis_server.dart.snapshot
|
||||
# ........dart2js.dart.snapshot
|
||||
# ........dartanalyzer.dart.snapshot
|
||||
# ........dds.dart.snapshot
|
||||
# ........dartdev.dart.snapshot
|
||||
# ........dartdoc.dart.snapshot
|
||||
# ........dartfmt.dart.snapshot
|
||||
|
@ -133,6 +134,10 @@ _platform_sdk_snapshots = [
|
|||
"dartfmt",
|
||||
"../utils/dartfmt",
|
||||
],
|
||||
[
|
||||
"dds",
|
||||
"../utils/dds:generate_dds_snapshot",
|
||||
],
|
||||
[
|
||||
"pub",
|
||||
"../utils/pub",
|
||||
|
@ -182,6 +187,10 @@ _full_sdk_snapshots = [
|
|||
"dartfmt",
|
||||
"../utils/dartfmt",
|
||||
],
|
||||
[
|
||||
"dds",
|
||||
"../utils/dds:generate_dds_snapshot",
|
||||
],
|
||||
[
|
||||
"kernel_worker",
|
||||
"../utils/bazel:kernel_worker",
|
||||
|
|
|
@ -354,14 +354,41 @@ class Server {
|
|||
|
||||
final String path = result;
|
||||
if (path == WEBSOCKET_PATH) {
|
||||
final subprotocols = request.headers['sec-websocket-protocol'];
|
||||
if (acceptNewWebSocketConnections) {
|
||||
WebSocketTransformer.upgrade(request,
|
||||
protocolSelector:
|
||||
subprotocols == null ? null : (_) => 'implicit-redirect',
|
||||
compression: CompressionOptions.compressionOff)
|
||||
.then((WebSocket webSocket) {
|
||||
WebSocketClient(webSocket, _service);
|
||||
});
|
||||
} else {
|
||||
// Forward the websocket connection request to DDS.
|
||||
// The Javascript WebSocket implementation doesn't like websocket
|
||||
// connection requests being redirected. Instead of redirecting, we'll
|
||||
// just forward the connection manually if 'implicit-redirect' is
|
||||
// provided as a protocol.
|
||||
if (subprotocols != null) {
|
||||
if (subprotocols.contains('implicit-redirect')) {
|
||||
WebSocketTransformer.upgrade(request,
|
||||
protocolSelector: (_) => 'implicit-redirect',
|
||||
compression: CompressionOptions.compressionOff)
|
||||
.then((WebSocket webSocket) async {
|
||||
final ddsWs = await WebSocket.connect(
|
||||
_service.ddsUri!.replace(scheme: 'ws').toString());
|
||||
ddsWs.addStream(webSocket);
|
||||
webSocket.addStream(ddsWs);
|
||||
webSocket.done.then((_) {
|
||||
ddsWs.close();
|
||||
});
|
||||
ddsWs.done.then((_) {
|
||||
webSocket.close();
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
request.response.redirect(_service.ddsUri!);
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:async_helper/async_helper.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:async_helper/async_helper.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:async_helper/async_helper.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:async_helper/async_helper.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
|
|
|
@ -17,14 +17,6 @@ dartfix_files = exec_script("../../tools/list_dart_files.py",
|
|||
rebase_path("../../pkg/dartfix"),
|
||||
],
|
||||
"list lines")
|
||||
|
||||
dds_files = exec_script("../../tools/list_dart_files.py",
|
||||
[
|
||||
"absolute",
|
||||
rebase_path("../../pkg/dds"),
|
||||
],
|
||||
"list lines")
|
||||
|
||||
group("dartdev") {
|
||||
deps = [ ":copy_dartdev_snapshot" ]
|
||||
}
|
||||
|
@ -39,6 +31,6 @@ copy("copy_dartdev_snapshot") {
|
|||
application_snapshot("generate_dartdev_snapshot") {
|
||||
main_dart = "../../pkg/dartdev/bin/dartdev.dart"
|
||||
training_args = [ "--help" ]
|
||||
inputs = dartdev_files + dartfix_files + dds_files
|
||||
inputs = dartdev_files + dartfix_files
|
||||
output = "$root_gen_dir/dartdev.dart.snapshot"
|
||||
}
|
||||
|
|
30
utils/dds/BUILD.gn
Normal file
30
utils/dds/BUILD.gn
Normal file
|
@ -0,0 +1,30 @@
|
|||
# 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("../application_snapshot.gni")
|
||||
|
||||
dds_files = exec_script("../../tools/list_dart_files.py",
|
||||
[
|
||||
"absolute",
|
||||
rebase_path("../../pkg/dds"),
|
||||
],
|
||||
"list lines")
|
||||
|
||||
group("dds") {
|
||||
deps = [ ":copy_dds_snapshot" ]
|
||||
}
|
||||
|
||||
copy("copy_dds_snapshot") {
|
||||
visibility = [ ":dds" ]
|
||||
deps = [ ":generate_dds_snapshot" ]
|
||||
sources = [ "$root_gen_dir/dds.dart.snapshot" ]
|
||||
outputs = [ "$root_out_dir/dds.dart.snapshot" ]
|
||||
}
|
||||
|
||||
application_snapshot("generate_dds_snapshot") {
|
||||
main_dart = "../../pkg/dds/bin/dds.dart"
|
||||
training_args = []
|
||||
inputs = dds_files
|
||||
output = "$root_gen_dir/dds.dart.snapshot"
|
||||
}
|
Loading…
Reference in a new issue