mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[dds/dap] Allow debug adapters to override the org-dartlang-sdk URI for the Dart SDK
Change-Id: I74432315d4bfa8e9890e0bd86fa0fa67d591f7fb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/265322 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Ben Konyi <bkonyi@google.com>
This commit is contained in:
parent
762c507553
commit
96294014e3
|
@ -324,6 +324,9 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
|
||||||
/// yet been made.
|
/// yet been made.
|
||||||
vm.VmServiceInterface? vmService;
|
vm.VmServiceInterface? vmService;
|
||||||
|
|
||||||
|
/// The root of the Dart SDK containing the VM running the debug adapter.
|
||||||
|
late final String sdkRoot;
|
||||||
|
|
||||||
/// The DDS instance that was started and that [vmService] is connected to.
|
/// The DDS instance that was started and that [vmService] is connected to.
|
||||||
///
|
///
|
||||||
/// `null` if the session is running in noDebug mode of the connection has not
|
/// `null` if the session is running in noDebug mode of the connection has not
|
||||||
|
@ -446,6 +449,9 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
|
||||||
}) : super(channel, onError: onError) {
|
}) : super(channel, onError: onError) {
|
||||||
channel.closed.then((_) => shutdown());
|
channel.closed.then((_) => shutdown());
|
||||||
|
|
||||||
|
final vmPath = Platform.resolvedExecutable;
|
||||||
|
sdkRoot = path.dirname(path.dirname(vmPath));
|
||||||
|
|
||||||
_isolateManager = IsolateManager(this);
|
_isolateManager = IsolateManager(this);
|
||||||
_converter = ProtocolConverter(this);
|
_converter = ProtocolConverter(this);
|
||||||
}
|
}
|
||||||
|
@ -1310,6 +1316,56 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The default location for [dartlangSdkRootUri].
|
||||||
|
final _defaultDartlangSdkRootUri = Uri.parse('org-dartlang-sdk:///sdk');
|
||||||
|
|
||||||
|
/// The (org-dartlang-sdk) URI for the root of the Dart SDK.
|
||||||
|
///
|
||||||
|
/// This can be overriden by debug adapters like Flutter where the Dart SDK
|
||||||
|
/// root is at another path (such as
|
||||||
|
/// `org-dartlang-sdk:///third_party/dart/sdk/`).
|
||||||
|
Uri get dartlangSdkRootUri => _defaultDartlangSdkRootUri;
|
||||||
|
|
||||||
|
/// Converts a URI in the form org-dartlang-sdk:///sdk/lib/collection/hash_set.dart
|
||||||
|
/// to a local file path based on the current SDK.
|
||||||
|
String? convertOrgDartlangSdkToPath(Uri uri) {
|
||||||
|
// org-dartlang-sdk URIs can be in multiple forms:
|
||||||
|
//
|
||||||
|
// - org-dartlang-sdk:///sdk/lib/collection/hash_set.dart
|
||||||
|
// - org-dartlang-sdk:///runtime/lib/convert_patch.dart
|
||||||
|
//
|
||||||
|
// We currently only handle the sdk folder, as we don't know which runtime
|
||||||
|
// is being used (this code is shared) and do not want to map to the wrong
|
||||||
|
// sources.
|
||||||
|
if (uri.pathSegments.isNotEmpty &&
|
||||||
|
uri.path.startsWith(dartlangSdkRootUri.path)) {
|
||||||
|
return path.joinAll([
|
||||||
|
sdkRoot,
|
||||||
|
...uri.pathSegments.skip(dartlangSdkRootUri.pathSegments.length),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a file path inside the current SDK root into a URI in the form
|
||||||
|
/// org-dartlang-sdk:///sdk/lib/collection/hash_set.dart.
|
||||||
|
Uri? convertPathToOrgDartlangSdk(String input) {
|
||||||
|
if (path.isWithin(sdkRoot, input)) {
|
||||||
|
final relative = path.relative(input, from: sdkRoot);
|
||||||
|
return Uri(
|
||||||
|
scheme: dartlangSdkRootUri.scheme,
|
||||||
|
host: '',
|
||||||
|
pathSegments: [
|
||||||
|
...dartlangSdkRootUri.pathSegments,
|
||||||
|
...path.split(relative)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// [sourceRequest] is called by the client to request source code for a given
|
/// [sourceRequest] is called by the client to request source code for a given
|
||||||
/// source.
|
/// source.
|
||||||
///
|
///
|
||||||
|
|
|
@ -4,10 +4,8 @@
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:path/path.dart' as path;
|
|
||||||
import 'package:vm_service/vm_service.dart' as vm;
|
import 'package:vm_service/vm_service.dart' as vm;
|
||||||
|
|
||||||
import '../rpc_error_codes.dart';
|
import '../rpc_error_codes.dart';
|
||||||
|
@ -67,9 +65,6 @@ class IsolateManager {
|
||||||
/// first time the user resumes.
|
/// first time the user resumes.
|
||||||
bool autoResumeStartingIsolates = true;
|
bool autoResumeStartingIsolates = true;
|
||||||
|
|
||||||
/// The root of the Dart SDK containing the VM running the debug adapter.
|
|
||||||
late final String sdkRoot;
|
|
||||||
|
|
||||||
/// Tracks breakpoints last provided by the client so they can be sent to new
|
/// Tracks breakpoints last provided by the client so they can be sent to new
|
||||||
/// isolates that appear after initial breakpoints were sent.
|
/// isolates that appear after initial breakpoints were sent.
|
||||||
final Map<String, List<SourceBreakpoint>> _clientBreakpointsByUri = {};
|
final Map<String, List<SourceBreakpoint>> _clientBreakpointsByUri = {};
|
||||||
|
@ -115,10 +110,7 @@ class IsolateManager {
|
||||||
/// Any leading character matched in place of the dollar is in the first capture.
|
/// Any leading character matched in place of the dollar is in the first capture.
|
||||||
final _braceNotPrefixedByDollarOrBackslashPattern = RegExp(r'(^|[^\\\$]){');
|
final _braceNotPrefixedByDollarOrBackslashPattern = RegExp(r'(^|[^\\\$]){');
|
||||||
|
|
||||||
IsolateManager(this._adapter) {
|
IsolateManager(this._adapter);
|
||||||
final vmPath = Platform.resolvedExecutable;
|
|
||||||
sdkRoot = path.dirname(path.dirname(vmPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A list of all current active isolates.
|
/// A list of all current active isolates.
|
||||||
///
|
///
|
||||||
|
@ -866,7 +858,8 @@ class ThreadInfo {
|
||||||
// URIs directly for SDK sources (we do not need to convert to 'dart:'),
|
// URIs directly for SDK sources (we do not need to convert to 'dart:'),
|
||||||
// however this method is Future-returning in case this changes in future
|
// however this method is Future-returning in case this changes in future
|
||||||
// and we need to include a call to lookupPackageUris here.
|
// and we need to include a call to lookupPackageUris here.
|
||||||
return _convertPathToOrgDartlangSdk(filePath) ?? Uri.file(filePath);
|
return _manager._adapter.convertPathToOrgDartlangSdk(filePath) ??
|
||||||
|
Uri.file(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Batch resolves source URIs from the VM to a file path for the package lib
|
/// Batch resolves source URIs from the VM to a file path for the package lib
|
||||||
|
@ -982,28 +975,6 @@ class ThreadInfo {
|
||||||
/// that are round-tripped to the client.
|
/// that are round-tripped to the client.
|
||||||
int storeData(Object data) => _manager.storeData(this, data);
|
int storeData(Object data) => _manager.storeData(this, data);
|
||||||
|
|
||||||
/// Converts a URI in the form org-dartlang-sdk:///sdk/lib/collection/hash_set.dart
|
|
||||||
/// to a local file path based on the current SDK.
|
|
||||||
String? _convertOrgDartlangSdkToPath(Uri uri) {
|
|
||||||
// org-dartlang-sdk URIs can be in multiple forms:
|
|
||||||
//
|
|
||||||
// - org-dartlang-sdk:///sdk/lib/collection/hash_set.dart
|
|
||||||
// - org-dartlang-sdk:///runtime/lib/convert_patch.dart
|
|
||||||
//
|
|
||||||
// We currently only handle the sdk folder, as we don't know which runtime
|
|
||||||
// is being used (this code is shared) and do not want to map to the wrong
|
|
||||||
// sources.
|
|
||||||
if (uri.pathSegments.isNotEmpty && uri.pathSegments.first == 'sdk') {
|
|
||||||
// TODO(dantup): Do we need to worry about this content not matching
|
|
||||||
// up with what's local (eg. for Flutter the VM running the app is
|
|
||||||
// on another device to the VM running this DA).
|
|
||||||
final sdkRoot = _manager.sdkRoot;
|
|
||||||
return path.joinAll([sdkRoot, ...uri.pathSegments.skip(1)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri? _convertPathToGoogle3Uri(String input) {
|
Uri? _convertPathToGoogle3Uri(String input) {
|
||||||
const search = '/google3/';
|
const search = '/google3/';
|
||||||
if (input.startsWith('/google') && input.contains(search)) {
|
if (input.startsWith('/google') && input.contains(search)) {
|
||||||
|
@ -1019,22 +990,6 @@ class ThreadInfo {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a file path inside the current SDK root into a URI in the form
|
|
||||||
/// org-dartlang-sdk:///sdk/lib/collection/hash_set.dart.
|
|
||||||
Uri? _convertPathToOrgDartlangSdk(String input) {
|
|
||||||
final sdkRoot = _manager.sdkRoot;
|
|
||||||
if (path.isWithin(sdkRoot, input)) {
|
|
||||||
final relative = path.relative(input, from: sdkRoot);
|
|
||||||
return Uri(
|
|
||||||
scheme: 'org-dartlang-sdk',
|
|
||||||
host: '',
|
|
||||||
pathSegments: ['sdk', ...path.split(relative)],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts a URI to a file path.
|
/// Converts a URI to a file path.
|
||||||
///
|
///
|
||||||
/// Supports file:// URIs and org-dartlang-sdk:// URIs.
|
/// Supports file:// URIs and org-dartlang-sdk:// URIs.
|
||||||
|
@ -1043,8 +998,8 @@ class ThreadInfo {
|
||||||
return null;
|
return null;
|
||||||
} else if (input.isScheme('file')) {
|
} else if (input.isScheme('file')) {
|
||||||
return input.toFilePath();
|
return input.toFilePath();
|
||||||
} else if (input.isScheme('org-dartlang-sdk')) {
|
} else if (input.isScheme(_manager._adapter.dartlangSdkRootUri.scheme)) {
|
||||||
return _convertOrgDartlangSdkToPath(input);
|
return _manager._adapter.convertOrgDartlangSdkToPath(input);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
67
pkg/dds/test/dap/base_adapter_test.dart
Normal file
67
pkg/dds/test/dap/base_adapter_test.dart
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
// Copyright (c) 2022, 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:path/path.dart' as path;
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
main() {
|
||||||
|
group('dart base adapter', () {
|
||||||
|
final vmPath = Platform.resolvedExecutable;
|
||||||
|
final sdkRoot = path.dirname(path.dirname(vmPath));
|
||||||
|
|
||||||
|
final sdkCorePath = path.join(sdkRoot, 'lib', 'core.dart');
|
||||||
|
final defaultCoreUri = Uri.parse('org-dartlang-sdk:///sdk/lib/core.dart');
|
||||||
|
|
||||||
|
group('default org-dartlang-sdk', () {
|
||||||
|
final adapter = MockDartCliDebugAdapter();
|
||||||
|
|
||||||
|
test('can SDK paths to org-dartlang-sdk:///', () async {
|
||||||
|
expect(
|
||||||
|
adapter.convertPathToOrgDartlangSdk(sdkCorePath),
|
||||||
|
defaultCoreUri,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('converts org-dartlang-sdk:/// to SDK paths', () async {
|
||||||
|
expect(
|
||||||
|
adapter.convertOrgDartlangSdkToPath(defaultCoreUri),
|
||||||
|
sdkCorePath,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('custom org-dartlang-sdk', () {
|
||||||
|
final adapter = MockDartCliDebugAdapter()
|
||||||
|
..dartlangSdkRootUriOverride =
|
||||||
|
Uri.parse('org-dartlang-sdk:///custom/sdk');
|
||||||
|
final customCoreUri =
|
||||||
|
Uri.parse('org-dartlang-sdk:///custom/sdk/lib/core.dart');
|
||||||
|
|
||||||
|
test('converts SDK paths to custom org-dartlang-sdk:///', () async {
|
||||||
|
expect(
|
||||||
|
adapter.convertPathToOrgDartlangSdk(sdkCorePath),
|
||||||
|
customCoreUri,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('converts custom org-dartlang-sdk:/// to SDK paths', () async {
|
||||||
|
expect(
|
||||||
|
adapter.convertOrgDartlangSdkToPath(customCoreUri),
|
||||||
|
sdkCorePath,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('does not convert default org-dartlang-sdk:///', () async {
|
||||||
|
expect(
|
||||||
|
adapter.convertOrgDartlangSdkToPath(defaultCoreUri),
|
||||||
|
isNull,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -30,6 +30,15 @@ class MockDartCliDebugAdapter extends DartCliDebugAdapter {
|
||||||
stdinController.sink, stdoutController.stream, channel);
|
stdinController.sink, stdoutController.stream, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An override for [dartlangSdkRootUri].
|
||||||
|
///
|
||||||
|
/// If not set, the default base value will be used.
|
||||||
|
Uri? dartlangSdkRootUriOverride;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Uri get dartlangSdkRootUri =>
|
||||||
|
dartlangSdkRootUriOverride ?? super.dartlangSdkRootUri;
|
||||||
|
|
||||||
MockDartCliDebugAdapter._(
|
MockDartCliDebugAdapter._(
|
||||||
this.stdin, this.stdout, ByteStreamServerChannel channel)
|
this.stdin, this.stdout, ByteStreamServerChannel channel)
|
||||||
: super(channel);
|
: super(channel);
|
||||||
|
|
Loading…
Reference in a new issue