// Copyright 2020 The Dart Authors. 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'; import 'dart:convert'; import 'dart:io'; import 'package:frontend_server_client/frontend_server_client.dart'; import 'package:path/path.dart' as p; import 'package:vm_service/vm_service.dart'; import 'package:vm_service/vm_service_io.dart'; void main(List args) async { try { watch.start(); if (args.isNotEmpty) { throw ArgumentError('No command line args are supported'); } var client = await FrontendServerClient.start( 'org-dartlang-root:///$app', outputDill, p.join(sdkDir, 'lib', '_internal', 'vm_platform_strong.dill'), target: 'vm', fileSystemRoots: [p.url.current], fileSystemScheme: 'org-dartlang-root', verbose: true); _print('compiling $app'); var result = await client.compile(); client.accept(); _print('done compiling $app'); Process appProcess; final vmServiceCompleter = Completer(); appProcess = await Process.start(Platform.resolvedExecutable, ['--enable-vm-service', result.dillOutput!]); final sawHelloWorld = Completer(); appProcess.stdout .transform(utf8.decoder) .transform(const LineSplitter()) .listen((line) { stdout.writeln('APP -> $line'); if (line == 'hello/world') { sawHelloWorld.complete(); } if (line.startsWith( 'The Dart DevTools debugger and profiler is available at:')) { var observatoryUri = '${line.split(' ').last.replaceFirst('http', 'ws')}ws'; vmServiceCompleter.complete(vmServiceConnectUri(observatoryUri)); } }); appProcess.stderr .transform(utf8.decoder) .transform(const LineSplitter()) .listen((line) { stderr.writeln('APP -> $line'); }); final vmService = await vmServiceCompleter.future; await sawHelloWorld.future; _print('editing $app'); var appFile = File(app); var originalContent = await appFile.readAsString(); var newContent = originalContent.replaceFirst('hello', 'goodbye'); await appFile.writeAsString(newContent); _print('recompiling $app with edits'); result = await client.compile([Uri.parse('org-dartlang-root:///$app')]); client.accept(); _print('done recompiling $app'); _print('reloading $app'); var vm = await vmService.getVM(); await vmService.reloadSources(vm.isolates!.first.id!, rootLibUri: result.dillOutput!); _print('restoring $app to original contents'); await appFile.writeAsString(originalContent); _print('exiting'); await client.shutdown().timeout(const Duration(seconds: 1), onTimeout: () { client.kill(); return 1; }); } finally { Directory(p.join('.dart_tool', 'out')).deleteSync(recursive: true); } } void _print(String message) { print('${watch.elapsed}: $message'); } final app = 'example/app/main.dart'; final outputDill = p.join('.dart_tool', 'out', 'example_app.dill'); final sdkDir = p.dirname(p.dirname(Platform.resolvedExecutable)); final watch = Stopwatch();