Skip to content

Commit

Permalink
Restructuring to start supporting breakpoints and sourcemaps (#377)
Browse files Browse the repository at this point in the history
  • Loading branch information
alan-knight authored May 8, 2019
1 parent b14d736 commit 7d14c3b
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 30 deletions.
49 changes: 32 additions & 17 deletions dwds/lib/src/chrome_proxy_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:pub_semver/pub_semver.dart' as semver;
import 'package:vm_service_lib/vm_service_lib.dart';
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';

import 'debugger.dart';
import 'helpers.dart';

/// A proxy from the chrome debug protocol to the dart vm service protocol.
Expand Down Expand Up @@ -38,6 +39,9 @@ class ChromeProxyService implements VmServiceInterface {
/// This may be null during a hot restart or page refresh.
Isolate _isolate;

/// Provides debugger-related functionality.
Debugger debugger;

/// Fields that are specific to the current [_isolate].
///
/// These need to get cleared whenever [destroyIsolate] is called.
Expand Down Expand Up @@ -71,7 +75,6 @@ class ChromeProxyService implements VmServiceInterface {
'$appInstanceId');
}
var tabConnection = await appTab.connect();
await tabConnection.debugger.enable();
await tabConnection.runtime.enable();

// TODO: What about `architectureBits`, `targetCPU`, `hostCPU` and `pid`?
Expand All @@ -81,10 +84,16 @@ class ChromeProxyService implements VmServiceInterface {
..startTime = DateTime.now().millisecondsSinceEpoch
..version = Platform.version;
var service = ChromeProxyService._(vm, appTab, tabConnection, assetHandler);
await service._initialize();
await service.createIsolate();
return service;
}

Future<Null> _initialize() async {
debugger = Debugger(this);
await debugger.initialize();
}

/// Creates a new [_isolate].
///
/// Only one isolate at a time is supported, but they should be cleaned up
Expand Down Expand Up @@ -133,12 +142,12 @@ class ChromeProxyService implements VmServiceInterface {
_vm.isolates.add(isolateRef);
_isolate = isolate;

_streamNotify(
streamNotify(
'Isolate',
Event()
..kind = EventKind.kIsolateStart
..isolate = isolateRef);
_streamNotify(
streamNotify(
'Isolate',
Event()
..kind = EventKind.kIsolateRunnable
Expand All @@ -148,7 +157,7 @@ class ChromeProxyService implements VmServiceInterface {
// isolate, but devtools doesn't recognize extensions after a page refresh
// otherwise.
for (var extensionRpc in isolate.extensionRPCs) {
_streamNotify(
streamNotify(
'Isolate',
Event()
..kind = EventKind.kServiceExtensionAdded
Expand All @@ -162,7 +171,7 @@ class ChromeProxyService implements VmServiceInterface {
/// Clears out [_isolate] and all related cached information.
void destroyIsolate() {
if (_isolate == null) return;
_streamNotify(
streamNotify(
'Isolate',
Event()
..kind = EventKind.kIsolateExit
Expand All @@ -180,8 +189,8 @@ class ChromeProxyService implements VmServiceInterface {

@override
Future<Breakpoint> addBreakpoint(String isolateId, String scriptId, int line,
{int column}) {
throw UnimplementedError();
{int column}) async {
return debugger.addBreakpoint(isolateId, scriptId, line, column: column);
}

@override
Expand Down Expand Up @@ -501,7 +510,7 @@ function($argsString) {

@override
Future<ScriptList> getScripts(String isolateId) async {
var scripts = await _getScripts(isolateId);
var scripts = await scriptRefs(isolateId);
return ScriptList()..scripts = scripts;
}

Expand All @@ -518,7 +527,11 @@ function($argsString) {
..source = script;
}

Future<List<ScriptRef>> _getScripts(String isolateId) async {
/// Internal method to list all scripts in the isolate.
///
/// This is used as the underlying mechanism
/// for [getScripts].
Future<List<ScriptRef>> scriptRefs(String isolateId) async {
var isolate = _getIsolate(isolateId);
var scripts = <ScriptRef>[];
for (var lib in isolate.libraries) {
Expand All @@ -527,6 +540,8 @@ function($argsString) {
if (lib.id.startsWith('dart:') || lib.id.endsWith('.bootstrap')) continue;
scripts.addAll((await _getLibrary(isolateId, lib.id)).scripts);
}
// TODO(alanknight): Is this the same as the values in _scriptRefs after
// constructing all the libraries? Make that clearer.
return scripts;
}

Expand Down Expand Up @@ -613,7 +628,7 @@ function($argsString) {

@override
Future<ReloadReport> reloadSources(String isolateId,
{bool force, bool pause, String rootLibUri, String packagesUri}) {
{bool force, bool pause, String rootLibUri, String packagesUri}) async {
throw UnimplementedError();
}

Expand Down Expand Up @@ -673,7 +688,7 @@ function($argsString) {
@override
Future<Success> setVMName(String name) async {
_vm.name = name;
_streamNotify(
streamNotify(
'VM',
Event()
..kind = EventKind.kVMUpdate
Expand Down Expand Up @@ -761,11 +776,11 @@ function($argsString) {
} else {
event.kind = EventKind.kPauseInterrupted;
}
_streamNotify('Debug', event);
streamNotify('Debug', event);
});
resumeSubscription = tabConnection.debugger.onResumed.listen((e) {
if (_isolate == null) return;
_streamNotify(
streamNotify(
'Debug',
Event()
..kind = EventKind.kResume
Expand Down Expand Up @@ -808,15 +823,15 @@ function($argsString) {
case 'dart.developer.registerExtension':
var service = event.args[1].value as String;
_isolate.extensionRPCs.add(service);
_streamNotify(
streamNotify(
'Isolate',
Event()
..kind = EventKind.kServiceExtensionAdded
..extensionRPC = service
..isolate = isolateRef);
break;
case 'dart.developer.postEvent':
_streamNotify(
streamNotify(
'Extension',
Event()
..kind = EventKind.kExtension
Expand All @@ -836,7 +851,7 @@ function($argsString) {
// up the library for a given instance to create it though.
// https://github.com/dart-lang/sdk/issues/36771.
..classRef = ClassRef();
_streamNotify(
streamNotify(
'Debug',
Event()
..kind = EventKind.kInspect
Expand All @@ -852,7 +867,7 @@ function($argsString) {

/// Adds [event] to the stream with [streamId] if there is anybody listening
/// on that stream.
void _streamNotify(String streamId, Event event) {
void streamNotify(String streamId, Event event) {
var controller = _streamControllers[streamId];
if (controller == null) return;
controller.add(event);
Expand Down
23 changes: 23 additions & 0 deletions dwds/lib/src/debugger.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'dart:async';

import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
import 'package:vm_service_lib/vm_service_lib.dart';

import 'chrome_proxy_service.dart';

class Debugger {
Debugger(this.mainProxy);

ChromeProxyService mainProxy;

WipDebugger get chromeDebugger => mainProxy.tabConnection.debugger;

Future<Null> initialize() async {
await chromeDebugger.enable();
}

Future<Breakpoint> addBreakpoint(String isolateId, String scriptId, int line,
{int column}) async {
throw UnimplementedError();
}
}
45 changes: 32 additions & 13 deletions dwds/test/chrome_proxy_service_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,38 @@ void main() {
await context.tearDown();
});

test('addBreakPoint', () {
expect(() => service.addBreakpoint(null, null, null),
throwsUnimplementedError);
});
group('breakpoints', () {
VM vm;
Isolate isolate;
ScriptList scripts;
ScriptRef mainScript;

test('addBreakpointAtEntry', () {
expect(() => service.addBreakpointAtEntry(null, null),
throwsUnimplementedError);
});
setUp(() async {
vm = await service.getVM();
isolate = await service.getIsolate(vm.isolates.first.id) as Isolate;
scripts = await service.getScripts(isolate.id);
mainScript =
scripts.scripts.firstWhere((each) => each.uri.contains('main.dart'));
});

test('addBreakpointWithScriptUri', () {
expect(() => service.addBreakpointWithScriptUri(null, null, null),
throwsUnimplementedError);
test('addBreakPoint', () async {
// TODO: Reloading causes other tests to fail. Investigate.
// await reload();
expect(() => service.addBreakpoint(isolate.id, mainScript.id, 19),
throwsUnimplementedError);
var breakpoints = isolate.breakpoints;
expect(breakpoints, isEmpty);
});

test('addBreakpointAtEntry', () {
expect(() => service.addBreakpointAtEntry(null, null),
throwsUnimplementedError);
});

test('addBreakpointWithScriptUri', () {
expect(() => service.addBreakpointWithScriptUri(null, null, null),
throwsUnimplementedError);
});
});

group('callServiceExtension', () {
Expand Down Expand Up @@ -358,15 +377,15 @@ void main() {
pauseCompleter.complete();
});
var resumeCompleter = Completer();
var resumseSub = tabConnection.debugger.onResumed.listen((_) {
var resumeSub = tabConnection.debugger.onResumed.listen((_) {
resumeCompleter.complete();
});
expect(await service.pause(isolateId), const TypeMatcher<Success>());
await pauseCompleter.future;
expect(await service.resume(isolateId), const TypeMatcher<Success>());
await resumeCompleter.future;
await pauseSub.cancel();
await resumseSub.cancel();
await resumeSub.cancel();
});

test('registerService', () async {
Expand Down

0 comments on commit 7d14c3b

Please sign in to comment.