1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-08 12:06:26 +00:00

[ DDS ] Move package:dds/vm_service_extensions.dart into package:dds_service_extensions

Reduces dependency complexity for tools which don't need the full
contents of package:dds

Change-Id: Ib9c5ce93eea72421f56114ab8a8efaa0dca6ae02
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/225240
Reviewed-by: Kenzie (Schmoll) Davisson <kenzieschmoll@google.com>
This commit is contained in:
Ben Konyi 2022-01-10 21:11:33 +00:00
parent 8ee071f535
commit 9f5ef6d5bc
17 changed files with 367 additions and 275 deletions

View File

@ -258,6 +258,12 @@
"packageUri": "lib/",
"languageVersion": "2.13"
},
{
"name": "dds_service_extensions",
"rootUri": "../pkg/dds_service_extensions",
"packageUri": "lib/",
"languageVersion": "2.13"
},
{
"name": "dev_compiler",
"rootUri": "../pkg/dev_compiler",

View File

@ -38,6 +38,7 @@ dart_style:third_party/pkg_tested/dart_style/lib
dartdev:pkg/dartdev/lib
dartdoc:third_party/pkg/dartdoc/lib
dds:pkg/dds/lib
dds_service_extensions:pkg/dds_service_extensions/lib
dev_compiler:pkg/dev_compiler/lib
devtools_server:third_party/devtools/devtools_server/lib
devtools_shared:third_party/devtools/devtools_shared/lib

View File

@ -2,275 +2,7 @@
// 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:async';
import 'dart:collection';
@Deprecated("Use 'package:dds_service_extensions' instead")
library vm_service_extensions;
import 'package:async/async.dart';
import 'package:pedantic/pedantic.dart';
import 'package:vm_service/src/vm_service.dart';
extension DdsExtension on VmService {
static bool _factoriesRegistered = false;
static Version? _ddsVersion;
/// The [getDartDevelopmentServiceVersion] RPC is used to determine what version of
/// the Dart Development Service Protocol is served by a DDS instance.
///
/// The result of this call is cached for subsequent invocations.
Future<Version> getDartDevelopmentServiceVersion() async {
if (_ddsVersion == null) {
_ddsVersion = await _callHelper<Version>(
'getDartDevelopmentServiceVersion',
);
}
return _ddsVersion!;
}
/// The [getCachedCpuSamples] RPC is used to retrieve a cache of CPU samples
/// collected under a [UserTag] with name `userTag`.
Future<CachedCpuSamples> getCachedCpuSamples(
String isolateId, String userTag) async {
if (!(await _versionCheck(1, 3))) {
throw UnimplementedError('getCachedCpuSamples requires DDS version 1.3');
}
return _callHelper<CachedCpuSamples>('getCachedCpuSamples', args: {
'isolateId': isolateId,
'userTag': userTag,
});
}
/// The [getAvailableCachedCpuSamples] RPC is used to determine which caches of CPU samples
/// are available. Caches are associated with individual [UserTag] names and are specified
/// when DDS is started via the `cachedUserTags` parameter.
Future<AvailableCachedCpuSamples> getAvailableCachedCpuSamples() async {
if (!(await _versionCheck(1, 3))) {
throw UnimplementedError(
'getAvailableCachedCpuSamples requires DDS version 1.3',
);
}
return _callHelper<AvailableCachedCpuSamples>(
'getAvailableCachedCpuSamples',
);
}
/// Retrieve the event history for `stream`.
///
/// If `stream` does not have event history collected, a parameter error is
/// returned.
Future<StreamHistory> getStreamHistory(String stream) async {
if (!(await _versionCheck(1, 2))) {
throw UnimplementedError('getStreamHistory requires DDS version 1.2');
}
return _callHelper<StreamHistory>('getStreamHistory', args: {
'stream': stream,
});
}
/// Returns the stream for a given stream id which includes historical
/// events.
///
/// If `stream` does not have event history collected, a parameter error is
/// sent over the returned [Stream].
Stream<Event> onEventWithHistory(String stream) {
late StreamController<Event> controller;
late StreamQueue<Event> streamEvents;
controller = StreamController<Event>(onListen: () async {
streamEvents = StreamQueue<Event>(onEvent(stream));
final history = (await getStreamHistory(stream)).history;
Event? firstStreamEvent;
unawaited(streamEvents.peek.then((e) {
firstStreamEvent = e;
}));
for (final event in history) {
if (firstStreamEvent != null &&
event.timestamp! > firstStreamEvent!.timestamp!) {
break;
}
controller.sink.add(event);
}
unawaited(controller.sink.addStream(streamEvents.rest));
}, onCancel: () {
try {
streamEvents.cancel();
} on StateError {
// Underlying stream may have already been cancelled.
}
});
return controller.stream;
}
/// Returns a new [Stream<Event>] of `Logging` events which outputs
/// historical events before streaming real-time events.
///
/// Note: unlike [onLoggingEvent], the returned stream is a single
/// subscription stream and a new stream is created for each invocation of
/// this getter.
Stream<Event> get onLoggingEventWithHistory => onEventWithHistory('Logging');
/// Returns a new [Stream<Event>] of `Stdout` events which outputs
/// historical events before streaming real-time events.
///
/// Note: unlike [onStdoutEvent], the returned stream is a single
/// subscription stream and a new stream is created for each invocation of
/// this getter.
Stream<Event> get onStdoutEventWithHistory => onEventWithHistory('Stdout');
/// Returns a new [Stream<Event>] of `Stderr` events which outputs
/// historical events before streaming real-time events.
///
/// Note: unlike [onStderrEvent], the returned stream is a single
/// subscription stream and a new stream is created for each invocation of
/// this getter.
Stream<Event> get onStderrEventWithHistory => onEventWithHistory('Stderr');
/// Returns a new [Stream<Event>] of `Extension` events which outputs
/// historical events before streaming real-time events.
///
/// Note: unlike [onExtensionEvent], the returned stream is a single
/// subscription stream and a new stream is created for each invocation of
/// this getter.
Stream<Event> get onExtensionEventWithHistory =>
onEventWithHistory('Extension');
Future<bool> _versionCheck(int major, int minor) async {
if (_ddsVersion == null) {
_ddsVersion = await getDartDevelopmentServiceVersion();
}
return ((_ddsVersion!.major == major && _ddsVersion!.minor! >= minor) ||
(_ddsVersion!.major! > major));
}
Future<T> _callHelper<T>(String method,
{String? isolateId, Map args = const {}}) {
if (!_factoriesRegistered) {
_registerFactories();
}
return callMethod(
method,
args: {
if (isolateId != null) 'isolateId': isolateId,
...args,
},
).then((e) => e as T);
}
static void _registerFactories() {
addTypeFactory('StreamHistory', StreamHistory.parse);
addTypeFactory(
'AvailableCachedCpuSamples',
AvailableCachedCpuSamples.parse,
);
addTypeFactory('CachedCpuSamples', CachedCpuSamples.parse);
_factoriesRegistered = true;
}
}
/// A collection of historical [Event]s from some stream.
class StreamHistory extends Response {
static StreamHistory? parse(Map<String, dynamic>? json) =>
json == null ? null : StreamHistory._fromJson(json);
StreamHistory({required List<Event> history}) : _history = history;
StreamHistory._fromJson(Map<String, dynamic> json)
: _history = json['history']
.map(
(e) => Event.parse(e),
)
.toList()
.cast<Event>() {
this.json = json;
}
@override
String get type => 'StreamHistory';
/// Historical [Event]s for a stream.
List<Event> get history => UnmodifiableListView(_history);
final List<Event> _history;
}
/// An extension of [CpuSamples] which represents a set of cached samples,
/// associated with a particular [UserTag] name.
class CachedCpuSamples extends CpuSamples {
static CachedCpuSamples? parse(Map<String, dynamic>? json) =>
json == null ? null : CachedCpuSamples._fromJson(json);
CachedCpuSamples({
required this.userTag,
this.truncated,
required int? samplePeriod,
required int? maxStackDepth,
required int? sampleCount,
required int? timeSpan,
required int? timeOriginMicros,
required int? timeExtentMicros,
required int? pid,
required List<ProfileFunction>? functions,
required List<CpuSample>? samples,
}) : super(
samplePeriod: samplePeriod,
maxStackDepth: maxStackDepth,
sampleCount: sampleCount,
timeSpan: timeSpan,
timeOriginMicros: timeOriginMicros,
timeExtentMicros: timeExtentMicros,
pid: pid,
functions: functions,
samples: samples,
);
CachedCpuSamples._fromJson(Map<String, dynamic> json)
: userTag = json['userTag']!,
truncated = json['truncated'],
super(
samplePeriod: json['samplePeriod'] ?? -1,
maxStackDepth: json['maxStackDepth'] ?? -1,
sampleCount: json['sampleCount'] ?? -1,
timeSpan: json['timeSpan'] ?? -1,
timeOriginMicros: json['timeOriginMicros'] ?? -1,
timeExtentMicros: json['timeExtentMicros'] ?? -1,
pid: json['pid'] ?? -1,
functions: List<ProfileFunction>.from(
createServiceObject(json['functions'], const ['ProfileFunction'])
as List? ??
[],
),
samples: List<CpuSample>.from(
createServiceObject(json['samples'], const ['CpuSample'])
as List? ??
[],
),
);
@override
String get type => 'CachedCpuSamples';
/// The name of the [UserTag] associated with this cache of [CpuSamples].
final String userTag;
/// Provided if the CPU sample cache has filled and older samples have been
/// dropped.
final bool? truncated;
}
/// A collection of [UserTag] names associated with caches of CPU samples.
class AvailableCachedCpuSamples extends Response {
static AvailableCachedCpuSamples? parse(Map<String, dynamic>? json) =>
json == null ? null : AvailableCachedCpuSamples._fromJson(json);
AvailableCachedCpuSamples({
required this.cacheNames,
});
AvailableCachedCpuSamples._fromJson(Map<String, dynamic> json)
: cacheNames = List<String>.from(json['cacheNames']);
@override
String get type => 'AvailableCachedUserTagCpuSamples';
/// A [List] of [UserTag] names associated with CPU sample caches.
final List<String> cacheNames;
}
export 'package:dds_service_extensions/dds_service_extensions.dart';

View File

@ -13,6 +13,7 @@ environment:
dependencies:
async: ^2.4.1
collection: ^1.15.0
dds_service_extensions: ^1.3.0
devtools_shared: ^2.3.0
json_rpc_2: ^3.0.0
meta: ^1.1.8

View File

@ -7,7 +7,7 @@ import 'dart:io';
import 'package:dds/dds.dart';
import 'package:dds/src/utils/mutex.dart';
import 'package:dds/vm_service_extensions.dart';
import 'package:dds_service_extensions/dds_service_extensions.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'package:vm_service/vm_service_io.dart';

View File

@ -5,7 +5,7 @@
import 'dart:io';
import 'package:dds/dds.dart';
import 'package:dds/vm_service_extensions.dart';
import 'package:dds_service_extensions/dds_service_extensions.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service_io.dart';
import 'common/test_helper.dart';

View File

@ -6,7 +6,7 @@ import 'dart:async';
import 'dart:io';
import 'package:dds/dds.dart';
import 'package:dds/vm_service_extensions.dart';
import 'package:dds_service_extensions/dds_service_extensions.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service_io.dart';
import 'common/test_helper.dart';

View File

@ -6,7 +6,7 @@ import 'dart:async';
import 'dart:io';
import 'package:dds/dds.dart';
import 'package:dds/vm_service_extensions.dart';
import 'package:dds_service_extensions/dds_service_extensions.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service_io.dart';
import 'common/test_helper.dart';

10
pkg/dds_service_extensions/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# Files and directories created by pub.
.dart_tool/
.packages
# Conventional directory for build outputs.
build/
# Omit committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock

View File

@ -0,0 +1,3 @@
## 1.3.0
- Moved `package:dds/vm_service_extensions.dart` into a standalone package.

View File

@ -0,0 +1,3 @@
A package used to expand the `package:vm_service` interface with support for RPCs added in the [Dart Developer Service (DDS) protocol][dds-protocol].
[dds-protocol]: https://github.com/dart-lang/sdk/blob/main/pkg/dds/dds_protocol.md

View File

@ -0,0 +1,30 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.
include: package:lints/recommended.yaml
# Uncomment the following section to specify additional rules.
# linter:
# rules:
# - camel_case_types
# analyzer:
# exclude:
# - path/to/excluded/files/**
# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options

View File

@ -0,0 +1,272 @@
// 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:async';
import 'dart:collection';
import 'package:async/async.dart';
// ignore: implementation_imports
import 'package:vm_service/src/vm_service.dart';
extension DdsExtension on VmService {
static bool _factoriesRegistered = false;
static Version? _ddsVersion;
/// The [getDartDevelopmentServiceVersion] RPC is used to determine what version of
/// the Dart Development Service Protocol is served by a DDS instance.
///
/// The result of this call is cached for subsequent invocations.
Future<Version> getDartDevelopmentServiceVersion() async {
_ddsVersion ??= await _callHelper<Version>(
'getDartDevelopmentServiceVersion',
);
return _ddsVersion!;
}
/// The [getCachedCpuSamples] RPC is used to retrieve a cache of CPU samples
/// collected under a [UserTag] with name `userTag`.
Future<CachedCpuSamples> getCachedCpuSamples(
String isolateId, String userTag) async {
if (!(await _versionCheck(1, 3))) {
throw UnimplementedError('getCachedCpuSamples requires DDS version 1.3');
}
return _callHelper<CachedCpuSamples>('getCachedCpuSamples', args: {
'isolateId': isolateId,
'userTag': userTag,
});
}
/// The [getAvailableCachedCpuSamples] RPC is used to determine which caches of CPU samples
/// are available. Caches are associated with individual [UserTag] names and are specified
/// when DDS is started via the `cachedUserTags` parameter.
Future<AvailableCachedCpuSamples> getAvailableCachedCpuSamples() async {
if (!(await _versionCheck(1, 3))) {
throw UnimplementedError(
'getAvailableCachedCpuSamples requires DDS version 1.3',
);
}
return _callHelper<AvailableCachedCpuSamples>(
'getAvailableCachedCpuSamples',
);
}
/// Retrieve the event history for `stream`.
///
/// If `stream` does not have event history collected, a parameter error is
/// returned.
Future<StreamHistory> getStreamHistory(String stream) async {
if (!(await _versionCheck(1, 2))) {
throw UnimplementedError('getStreamHistory requires DDS version 1.2');
}
return _callHelper<StreamHistory>('getStreamHistory', args: {
'stream': stream,
});
}
/// Returns the stream for a given stream id which includes historical
/// events.
///
/// If `stream` does not have event history collected, a parameter error is
/// sent over the returned [Stream].
Stream<Event> onEventWithHistory(String stream) {
late StreamController<Event> controller;
late StreamQueue<Event> streamEvents;
controller = StreamController<Event>(onListen: () async {
streamEvents = StreamQueue<Event>(onEvent(stream));
final history = (await getStreamHistory(stream)).history;
Event? firstStreamEvent;
unawaited(streamEvents.peek.then((e) {
firstStreamEvent = e;
}));
for (final event in history) {
if (firstStreamEvent != null &&
event.timestamp! > firstStreamEvent!.timestamp!) {
break;
}
controller.sink.add(event);
}
unawaited(controller.sink.addStream(streamEvents.rest));
}, onCancel: () {
try {
streamEvents.cancel();
} on StateError {
// Underlying stream may have already been cancelled.
}
});
return controller.stream;
}
/// Returns a new [Stream<Event>] of `Logging` events which outputs
/// historical events before streaming real-time events.
///
/// Note: unlike [onLoggingEvent], the returned stream is a single
/// subscription stream and a new stream is created for each invocation of
/// this getter.
Stream<Event> get onLoggingEventWithHistory => onEventWithHistory('Logging');
/// Returns a new [Stream<Event>] of `Stdout` events which outputs
/// historical events before streaming real-time events.
///
/// Note: unlike [onStdoutEvent], the returned stream is a single
/// subscription stream and a new stream is created for each invocation of
/// this getter.
Stream<Event> get onStdoutEventWithHistory => onEventWithHistory('Stdout');
/// Returns a new [Stream<Event>] of `Stderr` events which outputs
/// historical events before streaming real-time events.
///
/// Note: unlike [onStderrEvent], the returned stream is a single
/// subscription stream and a new stream is created for each invocation of
/// this getter.
Stream<Event> get onStderrEventWithHistory => onEventWithHistory('Stderr');
/// Returns a new [Stream<Event>] of `Extension` events which outputs
/// historical events before streaming real-time events.
///
/// Note: unlike [onExtensionEvent], the returned stream is a single
/// subscription stream and a new stream is created for each invocation of
/// this getter.
Stream<Event> get onExtensionEventWithHistory =>
onEventWithHistory('Extension');
Future<bool> _versionCheck(int major, int minor) async {
_ddsVersion ??= await getDartDevelopmentServiceVersion();
return ((_ddsVersion!.major == major && _ddsVersion!.minor! >= minor) ||
(_ddsVersion!.major! > major));
}
Future<T> _callHelper<T>(String method,
{String? isolateId, Map args = const {}}) {
if (!_factoriesRegistered) {
_registerFactories();
}
return callMethod(
method,
args: {
if (isolateId != null) 'isolateId': isolateId,
...args,
},
).then((e) => e as T);
}
static void _registerFactories() {
addTypeFactory('StreamHistory', StreamHistory.parse);
addTypeFactory(
'AvailableCachedCpuSamples',
AvailableCachedCpuSamples.parse,
);
addTypeFactory('CachedCpuSamples', CachedCpuSamples.parse);
_factoriesRegistered = true;
}
}
/// A collection of historical [Event]s from some stream.
class StreamHistory extends Response {
static StreamHistory? parse(Map<String, dynamic>? json) =>
json == null ? null : StreamHistory._fromJson(json);
StreamHistory({required List<Event> history}) : _history = history;
StreamHistory._fromJson(Map<String, dynamic> json)
: _history = json['history']
.map(
(e) => Event.parse(e),
)
.toList()
.cast<Event>() {
this.json = json;
}
@override
String get type => 'StreamHistory';
/// Historical [Event]s for a stream.
List<Event> get history => UnmodifiableListView(_history);
final List<Event> _history;
}
/// An extension of [CpuSamples] which represents a set of cached samples,
/// associated with a particular [UserTag] name.
class CachedCpuSamples extends CpuSamples {
static CachedCpuSamples? parse(Map<String, dynamic>? json) =>
json == null ? null : CachedCpuSamples._fromJson(json);
CachedCpuSamples({
required this.userTag,
this.truncated,
required int? samplePeriod,
required int? maxStackDepth,
required int? sampleCount,
required int? timeSpan,
required int? timeOriginMicros,
required int? timeExtentMicros,
required int? pid,
required List<ProfileFunction>? functions,
required List<CpuSample>? samples,
}) : super(
samplePeriod: samplePeriod,
maxStackDepth: maxStackDepth,
sampleCount: sampleCount,
timeSpan: timeSpan,
timeOriginMicros: timeOriginMicros,
timeExtentMicros: timeExtentMicros,
pid: pid,
functions: functions,
samples: samples,
);
CachedCpuSamples._fromJson(Map<String, dynamic> json)
: userTag = json['userTag']!,
truncated = json['truncated'],
super(
samplePeriod: json['samplePeriod'] ?? -1,
maxStackDepth: json['maxStackDepth'] ?? -1,
sampleCount: json['sampleCount'] ?? -1,
timeSpan: json['timeSpan'] ?? -1,
timeOriginMicros: json['timeOriginMicros'] ?? -1,
timeExtentMicros: json['timeExtentMicros'] ?? -1,
pid: json['pid'] ?? -1,
functions: List<ProfileFunction>.from(
createServiceObject(json['functions'], const ['ProfileFunction'])
as List? ??
[],
),
samples: List<CpuSample>.from(
createServiceObject(json['samples'], const ['CpuSample'])
as List? ??
[],
),
);
@override
String get type => 'CachedCpuSamples';
/// The name of the [UserTag] associated with this cache of [CpuSamples].
final String userTag;
/// Provided if the CPU sample cache has filled and older samples have been
/// dropped.
final bool? truncated;
}
/// A collection of [UserTag] names associated with caches of CPU samples.
class AvailableCachedCpuSamples extends Response {
static AvailableCachedCpuSamples? parse(Map<String, dynamic>? json) =>
json == null ? null : AvailableCachedCpuSamples._fromJson(json);
AvailableCachedCpuSamples({
required this.cacheNames,
});
AvailableCachedCpuSamples._fromJson(Map<String, dynamic> json)
: cacheNames = List<String>.from(json['cacheNames']);
@override
String get type => 'AvailableCachedUserTagCpuSamples';
/// A [List] of [UserTag] names associated with CPU sample caches.
final List<String> cacheNames;
}

View File

@ -0,0 +1,6 @@
// TODO: Put public facing types in this file.
/// Checks if you are awesome. Spoiler: you are.
class Awesome {
bool get isAwesome => true;
}

View File

@ -0,0 +1,18 @@
name: dds_service_extensions
description: >-
Extension methods for `package:vm_service`, used to make requests a
Dart Development Service (DDS) instance.
version: 1.3.0
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/dds_service_extensions
environment:
sdk: '>=2.13.0 <3.0.0'
dependencies:
async: ^2.4.1
vm_service: ^8.1.0
dev_dependencies:
lints: ^1.0.0

View File

@ -0,0 +1 @@
NOTE: Tests for this package can be found in `package:dds`.

View File

@ -3442,6 +3442,15 @@
"pkg/dds"
]
},
{
"name": "analyze pkg/dds_service_extensions",
"script": "out/ReleaseX64/dart-sdk/bin/dart",
"arguments": [
"analyze",
"--fatal-infos",
"pkg/dds_service_extensions"
]
},
{
"name": "analyze runtime/observatory",
"script": "out/ReleaseX64/dart-sdk/bin/dart",