blob: 08e80ffa7634850ff88f3a6298943012b00d46a1 [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:process/process.dart';
import 'base/io.dart' as io;
import 'base/logger.dart';
import 'convert.dart';
import 'resident_runner.dart';
/// An implementation of the devtools launcher that uses `pub global activate` to
/// start a server instance.
class DevtoolsServerLauncher extends DevtoolsLauncher {
DevtoolsServerLauncher({
@required ProcessManager processManager,
@required String dartExecutable,
@required Logger logger,
}) : _processManager = processManager,
_dartExecutable = dartExecutable,
_logger = logger;
final ProcessManager _processManager;
final String _dartExecutable;
final Logger _logger;
final Completer<void> _processStartCompleter = Completer<void>();
io.Process _devToolsProcess;
static final RegExp _serveDevToolsPattern =
RegExp(r'Serving DevTools at ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+?)\.?$');
@override
Future<void> get processStart => _processStartCompleter.future;
@override
Future<void> launch(Uri vmServiceUri, {List<String> additionalArguments}) async {
// Place this entire method in a try/catch that swallows exceptions because
// this method is guaranteed not to return a Future that throws.
try {
_devToolsProcess = await _processManager.start(<String>[
_dartExecutable,
'devtools',
'--no-launch-browser',
if (vmServiceUri != null) '--vm-uri=$vmServiceUri',
...?additionalArguments,
]);
_processStartCompleter.complete();
final Completer<Uri> completer = Completer<Uri>();
_devToolsProcess.stdout
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen((String line) {
final Match match = _serveDevToolsPattern.firstMatch(line);
if (match != null) {
final String url = match[1];
completer.complete(Uri.parse(url));
}
});
_devToolsProcess.stderr
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(_logger.printError);
devToolsUrl = await completer.future;
} on Exception catch (e, st) {
_logger.printError('Failed to launch DevTools: $e', stackTrace: st);
}
}
@override
Future<DevToolsServerAddress> serve() async {
if (activeDevToolsServer == null) {
await launch(null);
}
return activeDevToolsServer;
}
@override
Future<void> close() async {
if (devToolsUrl != null) {
devToolsUrl = null;
}
if (_devToolsProcess != null) {
_devToolsProcess.kill();
await _devToolsProcess.exitCode;
}
}
}