Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/devtools_app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ dependencies:
sse: ^4.1.2
stack_trace: ^1.12.0
string_scanner: ^1.4.0
unified_analytics: ^7.0.0
unified_analytics: ^8.4.0
vm_service: ^15.3.0
vm_service_protos: ^2.0.0
vm_snapshot_analysis: ^0.7.6
Expand Down
8 changes: 8 additions & 0 deletions packages/devtools_shared/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ found in the LICENSE file or at https://developers.google.com/open-source/licens
`DeeplinkManager`.
* Add `UniversalLinkSettings.fromErrorJson`, `UniversalLinkSettings.error`, and
`UniversalLinkSettings.error` getter to surface iOS universal link settings errors.
* `DeeplinkManager` now builds the environment for the `flutter` processes it
starts with `getEnvironment()` from `package:unified_analytics`, so
`DASH__TOOL` passes on this process's root tool. A known `ide` still overrides
it, and an unknown `ide` now falls back to the inherited root tool instead of
always using `devtools`. When `suppressAnalytics` is false, an inherited
`DASH__SUPPRESS_ANALYTICS=true` is now passed on instead of being reset to
`false`.
* Require `package:unified_analytics` `^8.4.0`.

# 14.0.0

Expand Down
77 changes: 46 additions & 31 deletions packages/devtools_shared/lib/src/deeplink/deeplink_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'dart:io';

import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
import 'package:unified_analytics/unified_analytics.dart';

import 'xcode_build_options.dart';

Expand Down Expand Up @@ -53,26 +54,22 @@ class DeeplinkManager {
_iosBuildOptionsCache.clear();
}

// TODO(https://github.com/flutter/devtools/issues/9702): Use the `DashTool`
// and `DashEnvVar` enums and `getEnvironment()` helper directly from
// `package:unified_analytics` once the pinned Flutter candidate SDK in this
// repository is bumped to a stable Dart SDK version >= 3.10.0 (resolving the
// dev SDK version solving conflict on CI).
/// Mappings from case-insensitive IDE query parameter values to their
/// corresponding DashTool canonical label strings used by `package:unified_analytics`.
/// Mappings from case-insensitive IDE query parameter values to the
/// [DashTool] that should be reported as the root tool of the `flutter`
/// processes DevTools starts for that IDE.
///
/// Contains multiple spelling and format variations (with/without hyphens
/// or suffixes) passed by different IDE integrations to ensure O(1) lookup.
static const _ideToDashToolMap = <String, String>{
'vs-code': 'vscode-plugins',
'vscode': 'vscode-plugins',
'vscodeplugins': 'vscode-plugins',
'intellij-idea': 'intellij-plugins',
'intellij': 'intellij-plugins',
'intellijplugins': 'intellij-plugins',
'android-studio': 'android-studio-plugins',
'androidstudio': 'android-studio-plugins',
'androidstudioplugins': 'android-studio-plugins',
static const _ideToDashTool = <String, DashTool>{
'vs-code': DashTool.vscodePlugins,
'vscode': DashTool.vscodePlugins,
'vscodeplugins': DashTool.vscodePlugins,
'intellij-idea': DashTool.intellijPlugins,
'intellij': DashTool.intellijPlugins,
'intellijplugins': DashTool.intellijPlugins,
'android-studio': DashTool.androidStudioPlugins,
'androidstudio': DashTool.androidStudioPlugins,
'androidstudioplugins': DashTool.androidStudioPlugins,
};

/// A regex to retrieve the file path from the stdout of iOS or Android
Expand All @@ -91,27 +88,45 @@ class DeeplinkManager {
required String? ide,
required bool suppressAnalytics,
}) {
final environment = <String, String>{
...Platform.environment,
'DASH__SUPPRESS_ANALYTICS': suppressAnalytics.toString(),
'DASH__TOOL': ide != null ? _mapIdeToDashToolLabel(ide) : 'devtools',
};

return Process.run(
executable,
arguments,
workingDirectory: workingDirectory,
environment: environment,
environment: buildEnvironment(
ide: ide,
suppressAnalytics: suppressAnalytics,
),
);
}

String _mapIdeToDashToolLabel(String ide) {
final lowerIde = ide.toLowerCase();
final mappedTool = _ideToDashToolMap[lowerIde];
if (mappedTool != null) {
return mappedTool;
}
return 'devtools';
/// Returns the environment for a `flutter` process that DevTools starts.
///
/// Uses `getEnvironment()` from `package:unified_analytics`, which sets
/// `DASH__SUPPRESS_ANALYTICS` and passes on the root tool from this
/// process's `DASH__TOOL` (falling back to `devtools`). If [ide] names a
/// known IDE, its [DashTool] overrides `DASH__TOOL`, because the IDE that
/// opened DevTools is the user's entry point for this request.
///
/// If [suppressAnalytics] is true, analytics are always suppressed.
/// `getEnvironment()` alone would let an inherited
/// `DASH__SUPPRESS_ANALYTICS=false` (which `dart` sets for the processes it
/// starts) win over it.
// TODO(https://github.com/dart-lang/tools/issues/2803): Pass the IDE as a
// `fallbackRootTool` to `getEnvironment()` once it supports one.
@visibleForTesting
Map<String, String> buildEnvironment({
required String? ide,
required bool suppressAnalytics,
}) {
final ideTool = ide == null ? null : _ideToDashTool[ide.toLowerCase()];
return {
...getEnvironment(
currentTool: DashTool.devtools,
suppressAnalytics: suppressAnalytics,
),
if (ideTool != null) DashEnvVar.tool.name: ideTool.label,
if (suppressAnalytics) DashEnvVar.suppressAnalytics.name: 'true',
};
}

@visibleForTesting
Expand Down
1 change: 1 addition & 0 deletions packages/devtools_shared/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies:
web_socket_channel: '>=2.4.0 <4.0.0'
webkit_inspection_protocol: ">=0.5.0 <2.0.0"
yaml: ^3.1.2
unified_analytics: ^8.4.0
yaml_edit: ^2.1.1

dev_dependencies:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'dart:io';
import 'package:collection/collection.dart';
import 'package:devtools_shared/src/deeplink/deeplink_manager.dart';
import 'package:test/test.dart';
import 'package:unified_analytics/unified_analytics.dart';

void main() {
group('DeeplinkManager', () {
Expand Down Expand Up @@ -435,6 +436,94 @@ Running Gradle task 'printBuildVariants'... 10.4s
},
);
});

group('DeeplinkManager.buildEnvironment', () {
final manager = DeeplinkManager();
// What `getEnvironment()` passes on when DevTools starts a sub-tool and no
// IDE override applies: this process's root tool, or `devtools`.
final inheritedRootTool = getEnvironment(
currentTool: DashTool.devtools,
)[DashEnvVar.tool.name];

test('sets DASH__TOOL to the IDE that opened DevTools', () {
for (final MapEntry(key: ide, value: tool) in {
'VS-Code': DashTool.vscodePlugins,
'vscode': DashTool.vscodePlugins,
'IntelliJ-IDEA': DashTool.intellijPlugins,
'intellijplugins': DashTool.intellijPlugins,
'Android-Studio': DashTool.androidStudioPlugins,
'androidstudio': DashTool.androidStudioPlugins,
}.entries) {
final environment = manager.buildEnvironment(
ide: ide,
suppressAnalytics: false,
);
expect(environment[DashEnvVar.tool.name], tool.label, reason: ide);
}
});

test('uses the inherited root tool when there is no known IDE', () {
expect(inheritedRootTool, isNotNull);
for (final ide in [null, 'unknown-ide']) {
final environment = manager.buildEnvironment(
ide: ide,
suppressAnalytics: false,
);
expect(environment[DashEnvVar.tool.name], inheritedRootTool);
}
});

test('never passes on a shared component or an invalid label', () {
final environment = manager.buildEnvironment(
ide: 'VS-Code',
suppressAnalytics: false,
);
expect(
() => DashTool.fromLabel(environment[DashEnvVar.tool.name]!),
returnsNormally,
);
expect(
DashTool.fromLabel(environment[DashEnvVar.tool.name]!).canBeRootTool,
isTrue,
);
});

test('suppresses analytics when requested, even if inherited is false', () {
// `dart test` runs under `dart`, which sets
// DASH__SUPPRESS_ANALYTICS=false for its child processes.
expect(
manager.buildEnvironment(
ide: null,
suppressAnalytics: true,
)[DashEnvVar.suppressAnalytics.name],
'true',
);
});

test('otherwise passes on the inherited suppression value', () {
expect(
manager.buildEnvironment(
ide: null,
suppressAnalytics: false,
)[DashEnvVar.suppressAnalytics.name],
areAnalyticsSuppressed().toString(),
);
});

test('keeps the rest of the process environment', () {
final environment = manager.buildEnvironment(
ide: null,
suppressAnalytics: false,
);
for (final MapEntry(:key, :value) in Platform.environment.entries) {
if (key == DashEnvVar.tool.name ||
key == DashEnvVar.suppressAnalytics.name) {
continue;
}
expect(environment[key], value, reason: key);
}
});
});
}

class StubbedDeeplinkManager extends DeeplinkManager {
Expand Down
20 changes: 10 additions & 10 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -899,26 +899,26 @@ packages:
dependency: transitive
description:
name: test
sha256: de5d145b0afff7921e5e788a880f52d7e5f3ae24068a202f6fd3b58e4ba26323
sha256: "44b2fccf4407bcdb5e105c064c5d6b5e2a640c87761f8b03cdce8cf532d98cfa"
url: "https://pub.dev"
source: hosted
version: "1.32.0"
version: "1.33.0"
test_api:
dependency: transitive
description:
name: test_api
sha256: "0a10344e901e5b2e63819567951cb6a06673ed6b84f40462188ff5a0c41f371f"
sha256: "47481c58bb92d0b1d218f0510ff5647e768f8e1256d07077a151fb520923b51d"
url: "https://pub.dev"
source: hosted
version: "0.7.14"
version: "0.7.15"
test_core:
dependency: transitive
description:
name: test_core
sha256: "80f3fb49087454e07e7e07c67578cfdd156c8c3a5227d8b3f47c7b2d019c2e93"
sha256: "9dec4c178bd61493e1cd2060ffe701fcb61c43da2493e99590fb1b0cc82eb4af"
url: "https://pub.dev"
source: hosted
version: "0.6.20"
version: "0.6.21"
typed_data:
dependency: transitive
description:
Expand All @@ -931,10 +931,10 @@ packages:
dependency: transitive
description:
name: unified_analytics
sha256: d581cd7007f5a60594195ee5d35337edea7d53757e4cff5a2f5168b82ec31d05
sha256: "4013958a461aafcd9b80baf96b85e1537ae10991a05e7b05f34e4bee6202dfb0"
url: "https://pub.dev"
source: hosted
version: "7.0.2"
version: "8.4.0"
url_launcher:
dependency: transitive
description:
Expand Down Expand Up @@ -1003,10 +1003,10 @@ packages:
dependency: transitive
description:
name: vector_math
sha256: "92b9910f66ed1057fd4da7b040ae7c74cafacf885bdc81be496928d5049b032d"
sha256: fa49e1674cb84acb900141714e6c6e1f9ae099827c24d141430ff6819db4e1bc
url: "https://pub.dev"
source: hosted
version: "2.4.3"
version: "2.4.4"
vm_service:
dependency: transitive
description:
Expand Down
Loading