Unverified Commit ef146f63 authored by Zachary Anderson's avatar Zachary Anderson Committed by GitHub

[flutter_tool] Clean up usage events and custom dimensions (#36785)

parent 24f483cf
......@@ -15,8 +15,7 @@ import 'package:flutter_tools/src/context_runner.dart';
import 'package:flutter_tools/src/devfs.dart';
import 'package:flutter_tools/src/bundle.dart';
import 'package:flutter_tools/src/globals.dart';
import 'package:flutter_tools/src/reporting/disabled_usage.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
const String _kOptionPackages = 'packages';
const String _kOptionAsset = 'asset-dir';
......
......@@ -18,8 +18,7 @@ import 'package:flutter_tools/src/dart/package_map.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/globals.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/disabled_usage.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/test/coverage_collector.dart';
import 'package:flutter_tools/src/test/runner.dart';
......
......@@ -19,8 +19,7 @@ import 'src/base/utils.dart';
import 'src/context_runner.dart';
import 'src/doctor.dart';
import 'src/globals.dart';
import 'src/reporting/crash_reporting.dart';
import 'src/reporting/usage.dart';
import 'src/reporting/reporting.dart';
import 'src/runner/flutter_command.dart';
import 'src/runner/flutter_command_runner.dart';
import 'src/version.dart';
......
......@@ -24,8 +24,7 @@ import '../features.dart';
import '../flutter_manifest.dart';
import '../globals.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../runner/flutter_command.dart';
import '../reporting/reporting.dart';
import 'android_sdk.dart';
import 'android_studio.dart';
......@@ -747,11 +746,7 @@ Future<void> _buildGradleProjectV2(
printError('The Gradle failure may have been because of AndroidX incompatibilities in this Flutter app.');
printError('See https://goo.gl/CP92wY for more information on the problem and how to fix it.');
printError('*******************************************************************************************');
String commandName = '';
if (FlutterCommand.current != null) {
commandName = '-${FlutterCommand.current.name}';
}
flutterUsage.sendEvent('build$commandName', 'android-x-failure');
BuildEvent('android-x-failure').send();
}
throwToolExit('Gradle task $assembleTask failed with exit code $exitCode', exitCode: exitCode);
}
......
......@@ -14,7 +14,7 @@ import '../dart/package_map.dart';
import '../globals.dart';
import '../macos/xcode.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import 'context.dart';
import 'file_system.dart';
......
......@@ -9,7 +9,7 @@ import '../base/context.dart';
import '../base/os.dart';
import '../build_info.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import '../runner/flutter_command.dart' show DevelopmentArtifact, FlutterCommandResult;
import 'build.dart';
......@@ -38,20 +38,20 @@ class BuildAarCommand extends BuildSubCommand {
final String name = 'aar';
@override
Future<Map<String, String>> get usageValues async {
final Map<String, String> usage = <String, String>{};
Future<Map<CustomDimensions, String>> get usageValues async {
final Map<CustomDimensions, String> usage = <CustomDimensions, String>{};
final FlutterProject futterProject = _getProject();
if (futterProject == null) {
return usage;
}
if (futterProject.manifest.isModule) {
usage[kCommandBuildAarProjectType] = 'module';
usage[CustomDimensions.commandBuildAarProjectType] = 'module';
} else if (futterProject.manifest.isPlugin) {
usage[kCommandBuildAarProjectType] = 'plugin';
usage[CustomDimensions.commandBuildAarProjectType] = 'plugin';
} else {
usage[kCommandBuildAarProjectType] = 'app';
usage[CustomDimensions.commandBuildAarProjectType] = 'app';
}
usage[kCommandBuildAarTargetPlatform] =
usage[CustomDimensions.commandBuildAarTargetPlatform] =
(argResults['target-platform'] as List<String>).join(',');
return usage;
}
......
......@@ -10,7 +10,7 @@ import '../build_info.dart';
import '../bundle.dart';
import '../features.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import '../runner/flutter_command.dart' show FlutterOptions, FlutterCommandResult;
import 'build.dart';
......@@ -74,17 +74,15 @@ class BuildBundleCommand extends BuildSubCommand {
' iOS runtimes.';
@override
Future<Map<String, String>> get usageValues async {
Future<Map<CustomDimensions, String>> get usageValues async {
final String projectDir = fs.file(targetFile).parent.parent.path;
final FlutterProject futterProject = FlutterProject.fromPath(projectDir);
if (futterProject == null) {
return const <String, String>{};
return const <CustomDimensions, String>{};
}
return <String, String>{
kCommandBuildBundleTargetPlatform: argResults['target-platform'],
kCommandBuildBundleIsModule: '${futterProject.isModule}'
return <CustomDimensions, String>{
CustomDimensions.commandBuildBundleTargetPlatform: argResults['target-platform'],
CustomDimensions.commandBuildBundleIsModule: '${futterProject.isModule}'
};
}
......
......@@ -11,7 +11,7 @@ import '../base/file_system.dart';
import '../convert.dart';
import '../features.dart';
import '../globals.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import '../runner/flutter_command.dart';
import '../version.dart';
......
......@@ -23,7 +23,7 @@ import '../doctor.dart';
import '../features.dart';
import '../globals.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import '../runner/flutter_command.dart';
import '../template.dart';
import '../version.dart';
......@@ -165,11 +165,11 @@ class CreateCommand extends FlutterCommand {
String get invocation => '${runner.executableName} $name <output directory>';
@override
Future<Map<String, String>> get usageValues async {
return <String, String>{
kCommandCreateProjectType: argResults['template'],
kCommandCreateAndroidLanguage: argResults['android-language'],
kCommandCreateIosLanguage: argResults['ios-language'],
Future<Map<CustomDimensions, String>> get usageValues async {
return <CustomDimensions, String>{
CustomDimensions.commandCreateProjectType: argResults['template'],
CustomDimensions.commandCreateAndroidLanguage: argResults['android-language'],
CustomDimensions.commandCreateIosLanguage: argResults['ios-language'],
};
}
......
......@@ -9,7 +9,7 @@ import '../base/os.dart';
import '../cache.dart';
import '../dart/pub.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import '../runner/flutter_command.dart';
class PackagesCommand extends FlutterCommand {
......@@ -71,8 +71,8 @@ class PackagesGetCommand extends FlutterCommand {
}
@override
Future<Map<String, String>> get usageValues async {
final Map<String, String> usageValues = <String, String>{};
Future<Map<CustomDimensions, String>> get usageValues async {
final Map<CustomDimensions, String> usageValues = <CustomDimensions, String>{};
final String workingDirectory = argResults.rest.length == 1 ? argResults.rest[0] : null;
final String target = findProjectRoot(workingDirectory);
if (target == null) {
......@@ -82,11 +82,11 @@ class PackagesGetCommand extends FlutterCommand {
final bool hasPlugins = await rootProject.flutterPluginsFile.exists();
if (hasPlugins) {
final int numberOfPlugins = (await rootProject.flutterPluginsFile.readAsLines()).length;
usageValues[kCommandPackagesNumberPlugins] = '$numberOfPlugins';
usageValues[CustomDimensions.commandPackagesNumberPlugins] = '$numberOfPlugins';
} else {
usageValues[kCommandPackagesNumberPlugins] = '0';
usageValues[CustomDimensions.commandPackagesNumberPlugins] = '0';
}
usageValues[kCommandPackagesProjectModule] = '${rootProject.isModule}';
usageValues[CustomDimensions.commandPackagesProjectModule] = '${rootProject.isModule}';
return usageValues;
}
......@@ -100,11 +100,11 @@ class PackagesGetCommand extends FlutterCommand {
checkLastModified: false,
);
pubGetTimer.stop();
flutterUsage.sendEvent('packages-pub-get', 'success');
PubGetEvent(success: true).send();
flutterUsage.sendTiming('packages-pub-get', 'success', pubGetTimer.elapsed);
} catch (_) {
pubGetTimer.stop();
flutterUsage.sendEvent('packages-pub-get', 'failure');
PubGetEvent(success: false).send();
flutterUsage.sendTiming('packages-pub-get', 'failure', pubGetTimer.elapsed);
rethrow;
}
......
......@@ -17,7 +17,7 @@ import '../features.dart';
import '../globals.dart';
import '../macos/xcode.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import '../resident_runner.dart';
import '../resident_web_runner.dart';
import '../run_cold.dart';
......@@ -198,7 +198,7 @@ class RunCommand extends RunCommandBase {
}
@override
Future<Map<String, String>> get usageValues async {
Future<Map<CustomDimensions, String>> get usageValues async {
String deviceType, deviceOsVersion;
bool isEmulator;
......@@ -227,13 +227,13 @@ class RunCommand extends RunCommandBase {
hostLanguage.add(iosProject.isSwift ? 'swift' : 'objc');
}
return <String, String>{
kCommandRunIsEmulator: '$isEmulator',
kCommandRunTargetName: deviceType,
kCommandRunTargetOsVersion: deviceOsVersion,
kCommandRunModeName: modeName,
kCommandRunProjectModule: '${FlutterProject.current().isModule}',
kCommandRunProjectHostLanguage: hostLanguage.join(','),
return <CustomDimensions, String>{
CustomDimensions.commandRunIsEmulator: '$isEmulator',
CustomDimensions.commandRunTargetName: deviceType,
CustomDimensions.commandRunTargetOsVersion: deviceOsVersion,
CustomDimensions.commandRunModeName: modeName,
CustomDimensions.commandRunProjectModule: '${FlutterProject.current().isModule}',
CustomDimensions.commandRunProjectHostLanguage: hostLanguage.join(','),
};
}
......
......@@ -42,7 +42,7 @@ import 'macos/cocoapods_validator.dart';
import 'macos/macos_workflow.dart';
import 'macos/xcode.dart';
import 'macos/xcode_validator.dart';
import 'reporting/usage.dart';
import 'reporting/reporting.dart';
import 'run_hot.dart';
import 'version.dart';
import 'web/chrome.dart';
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:async';
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
import 'package:meta/meta.dart';
......
......@@ -31,7 +31,7 @@ import 'macos/cocoapods_validator.dart';
import 'macos/macos_workflow.dart';
import 'macos/xcode_validator.dart';
import 'proxy_validator.dart';
import 'reporting/usage.dart';
import 'reporting/reporting.dart';
import 'tester/flutter_tester.dart';
import 'version.dart';
import 'vscode/vscode_validator.dart';
......@@ -236,7 +236,7 @@ class Doctor {
break;
}
flutterUsage.sendEvent('doctorResult.${validator.runtimeType.toString()}', result.typeStr);
DoctorResultEvent(validator: validator, result: result).send();
if (result.statusInfo != null) {
printStatus('${result.coloredLeadingBox} ${validator.title} (${result.statusInfo})',
......
......@@ -16,7 +16,7 @@ import '../convert.dart';
import '../devfs.dart';
import '../globals.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import 'fuchsia_pm.dart';
import 'fuchsia_sdk.dart';
......
......@@ -24,7 +24,7 @@ import '../globals.dart';
import '../macos/cocoapod_utils.dart';
import '../macos/xcode.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import '../services.dart';
import 'code_signing.dart';
import 'xcodeproj.dart';
......@@ -472,13 +472,10 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async {
if (result.xcodeBuildExecution != null &&
result.xcodeBuildExecution.buildForPhysicalDevice &&
result.stdout?.toUpperCase()?.contains('BITCODE') == true) {
flutterUsage.sendEvent(
'Xcode',
'bitcode-failure',
parameters: <String, String>{
'build-commands': result.xcodeBuildExecution.buildCommands.toString(),
'build-settings': result.xcodeBuildExecution.buildSettings.toString(),
});
BuildEvent('xcode-bitcode-failure',
command: result.xcodeBuildExecution.buildCommands.toString(),
settings: result.xcodeBuildExecution.buildSettings.toString(),
).send();
}
if (result.xcodeBuildExecution != null &&
......
......@@ -13,7 +13,7 @@ import '../cache.dart';
import '../convert.dart';
import '../globals.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
/// Builds the Linux project through the Makefile.
Future<void> buildLinux(LinuxProject linuxProject, BuildInfo buildInfo, {String target = 'lib/main.dart'}) async {
......
......@@ -12,7 +12,7 @@ import '../convert.dart';
import '../globals.dart';
import '../ios/xcodeproj.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import 'cocoapod_utils.dart';
......
......@@ -2,17 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';
import '../base/io.dart';
import '../base/os.dart';
import '../base/platform.dart';
import '../globals.dart';
import 'usage.dart';
part of reporting;
/// Tells crash backend that the error is from the Flutter CLI.
const String _kProductId = 'Flutter_Tools';
......
......@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'usage.dart';
part of reporting;
class DisabledUsage implements Usage {
@override
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of reporting;
/// A generic usage even that does not involve custom dimensions.
///
/// If sending values for custom dimensions is required, extend this class as
/// below.
class UsageEvent {
UsageEvent(this.category, this.parameter);
final String category;
final String parameter;
void send() {
flutterUsage.sendEvent(category, parameter);
}
}
/// A usage event related to hot reload/restart.
///
/// On a successful hot reload, we collect stats that help understand scale of
/// the update. For example, [syncedLibraryCount]/[finalLibraryCount] indicates
/// how many libraries were affected by the hot reload request. Relation of
/// [invalidatedSourcesCount] to [syncedLibraryCount] should help understand
/// sync/transfer "overhead" of updating this number of source files.
class HotEvent extends UsageEvent {
HotEvent(String parameter, {
@required this.targetPlatform,
@required this.sdkName,
@required this.emulator,
@required this.fullRestart,
this.reason,
this.finalLibraryCount,
this.syncedLibraryCount,
this.syncedClassesCount,
this.syncedProceduresCount,
this.syncedBytes,
this.invalidatedSourcesCount,
this.transferTimeInMs,
this.overallTimeInMs,
}) : super('hot', parameter);
final String reason;
final String targetPlatform;
final String sdkName;
final bool emulator;
final bool fullRestart;
final int finalLibraryCount;
final int syncedLibraryCount;
final int syncedClassesCount;
final int syncedProceduresCount;
final int syncedBytes;
final int invalidatedSourcesCount;
final int transferTimeInMs;
final int overallTimeInMs;
@override
void send() {
final Map<String, String> parameters = _useCdKeys(<CustomDimensions, String>{
CustomDimensions.hotEventTargetPlatform: targetPlatform,
CustomDimensions.hotEventSdkName: sdkName,
CustomDimensions.hotEventEmulator: emulator.toString(),
CustomDimensions.hotEventFullRestart: fullRestart.toString(),
if (reason != null)
CustomDimensions.hotEventReason: reason,
if (finalLibraryCount != null)
CustomDimensions.hotEventFinalLibraryCount: finalLibraryCount.toString(),
if (syncedLibraryCount != null)
CustomDimensions.hotEventSyncedLibraryCount: syncedLibraryCount.toString(),
if (syncedClassesCount != null)
CustomDimensions.hotEventSyncedClassesCount: syncedClassesCount.toString(),
if (syncedProceduresCount != null)
CustomDimensions.hotEventSyncedProceduresCount: syncedProceduresCount.toString(),
if (syncedBytes != null)
CustomDimensions.hotEventSyncedBytes: syncedBytes.toString(),
if (invalidatedSourcesCount != null)
CustomDimensions.hotEventInvalidatedSourcesCount: invalidatedSourcesCount.toString(),
if (transferTimeInMs != null)
CustomDimensions.hotEventTransferTimeInMs: transferTimeInMs.toString(),
if (overallTimeInMs != null)
CustomDimensions.hotEventOverallTimeInMs: overallTimeInMs.toString(),
});
flutterUsage.sendEvent(category, parameter, parameters: parameters);
}
}
/// An event that reports the result of a [DoctorValidator]
class DoctorResultEvent extends UsageEvent {
DoctorResultEvent({
@required DoctorValidator validator,
@required ValidationResult result
}) : super('doctorResult.${validator.runtimeType.toString()}',
result.typeStr);
// TODO(zra): Override send() to detect a GroupedValidator and send separate
// events for each sub-validator.
}
/// An event that reports success or failure of a pub get.
class PubGetEvent extends UsageEvent {
PubGetEvent({
@required bool success,
}) : super('packages-pub-get', success ? 'success' : 'failure');
}
/// An event that reports something about a build.
class BuildEvent extends UsageEvent {
BuildEvent(String parameter, {
this.command,
this.settings,
}) : super(
'build' +
(FlutterCommand.current == null ? '' : '-${FlutterCommand.current.name}'),
parameter);
final String command;
final String settings;
@override
void send() {
final Map<String, String> parameters = _useCdKeys(<CustomDimensions, String>{
if (command != null)
CustomDimensions.buildEventCommand: command,
if (settings != null)
CustomDimensions.buildEventSettings: settings,
});
flutterUsage.sendEvent(category, parameter, parameters: parameters);
}
}
/// An event that reports the result of a top-level command.
class CommandResultEvent extends UsageEvent {
CommandResultEvent(String commandPath, FlutterCommandResult result)
: super(commandPath, result?.toString() ?? 'unspecified');
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library reporting;
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';
import 'package:usage/usage_io.dart';
import '../base/config.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/os.dart';
import '../base/platform.dart';
import '../base/time.dart';
import '../base/utils.dart';
import '../doctor.dart';
import '../features.dart';
import '../globals.dart';
import '../runner/flutter_command.dart';
import '../version.dart';
part 'crash_reporting.dart';
part 'disabled_usage.dart';
part 'events.dart';
part 'usage.dart';
This diff is collapsed.
......@@ -28,7 +28,7 @@ import '../doctor.dart';
import '../features.dart';
import '../globals.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import 'flutter_command_runner.dart';
export '../cache.dart' show DevelopmentArtifact;
......@@ -63,6 +63,21 @@ class FlutterCommandResult {
/// [FlutterCommand] will automatically measure and report the command's
/// complete time if not overridden.
final DateTime endTimeOverride;
@override
String toString() {
switch (exitStatus) {
case ExitStatus.success:
return 'success';
case ExitStatus.warning:
return 'warning';
case ExitStatus.fail:
return 'fail';
default:
assert(false);
return null;
}
}
}
/// Common flutter command line options.
......@@ -366,7 +381,8 @@ abstract class FlutterCommand extends Command<void> {
}
/// Additional usage values to be sent with the usage ping.
Future<Map<String, String>> get usageValues async => const <String, String>{};
Future<Map<CustomDimensions, String>> get usageValues async =>
const <CustomDimensions, String>{};
/// Runs this command.
///
......@@ -382,8 +398,9 @@ abstract class FlutterCommand extends Command<void> {
name: 'command',
overrides: <Type, Generator>{FlutterCommand: () => this},
body: () async {
if (flutterUsage.isFirstRun)
if (flutterUsage.isFirstRun) {
flutterUsage.printWelcome();
}
final String commandPath = await usagePath;
FlutterCommandResult commandResult;
try {
......@@ -411,21 +428,7 @@ abstract class FlutterCommand extends Command<void> {
}
// Send command result.
String result = 'unspecified';
if (commandResult != null) {
switch (commandResult.exitStatus) {
case ExitStatus.success:
result = 'success';
break;
case ExitStatus.warning:
result = 'warning';
break;
case ExitStatus.fail:
result = 'fail';
break;
}
}
flutterUsage.sendEvent(commandPath, result);
CommandResultEvent(commandPath, commandResult).send();
// Send timing.
final List<String> labels = <String>[
......@@ -476,12 +479,12 @@ abstract class FlutterCommand extends Command<void> {
setupApplicationPackages();
if (commandPath != null) {
final Map<String, String> additionalUsageValues = <String,String>{
...?await usageValues,
};
additionalUsageValues[kCommandHasTerminal] =
io.stdout.hasTerminal ? 'true' : 'false';
flutterUsage.sendCommand(commandPath, parameters: additionalUsageValues);
final Map<CustomDimensions, String> additionalUsageValues =
<CustomDimensions, String>{
...?await usageValues,
CustomDimensions.commandHasTerminal: io.stdout.hasTerminal ? 'true' : 'false',
};
Usage.command(commandPath, parameters: additionalUsageValues);
}
return await runCommand();
......
......@@ -30,7 +30,7 @@ import '../convert.dart';
import '../dart/package_map.dart';
import '../device.dart';
import '../globals.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import '../tester/flutter_tester.dart';
import '../version.dart';
import '../vmservice.dart';
......
......@@ -13,7 +13,7 @@ import '../build_info.dart';
import '../bundle.dart';
import '../globals.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
/// The [WebCompilationProxy] instance.
WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>();
......
......@@ -13,7 +13,7 @@ import '../cache.dart';
import '../convert.dart';
import '../globals.dart';
import '../project.dart';
import '../reporting/usage.dart';
import '../reporting/reporting.dart';
import 'msbuild_utils.dart';
import 'visual_studio.dart';
......
......@@ -4,22 +4,21 @@
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/base/config.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/time.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/time.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build.dart';
import 'package:flutter_tools/src/commands/config.dart';
import 'package:flutter_tools/src/commands/doctor.dart';
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/version.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import '../src/common.dart';
......@@ -94,7 +93,8 @@ void main() {
final Usage usage = Usage();
usage.sendCommand('test');
expect(fs.file('test').readAsStringSync(), contains('$enabledFlutterFeatures: enable-web'));
final String featuresKey = cdKey(CustomDimensions.enabledFlutterFeatures);
expect(fs.file('test').readAsStringSync(), contains('$featuresKey: enable-web'));
}, overrides: <Type, Generator>{
FlutterVersion: () => FlutterVersion(const SystemClock()),
Config: () => mockFlutterConfig,
......@@ -114,7 +114,8 @@ void main() {
final Usage usage = Usage();
usage.sendCommand('test');
expect(fs.file('test').readAsStringSync(), contains('$enabledFlutterFeatures: enable-web,enable-linux-desktop,enable-macos-desktop'));
final String featuresKey = cdKey(CustomDimensions.enabledFlutterFeatures);
expect(fs.file('test').readAsStringSync(), contains('$featuresKey: enable-web,enable-linux-desktop,enable-macos-desktop'));
}, overrides: <Type, Generator>{
FlutterVersion: () => FlutterVersion(const SystemClock()),
Config: () => mockFlutterConfig,
......
......@@ -3,11 +3,11 @@
// found in the LICENSE file.
import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/artifacts.dart';
import '../src/common.dart';
import '../src/context.dart';
......
......@@ -7,7 +7,7 @@ import 'package:flutter_tools/src/android/aar.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build_aar.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
import '../../src/common.dart';
......@@ -51,7 +51,7 @@ void main() {
final BuildAarCommand command = await runCommandIn(projectPath);
expect(await command.usageValues,
containsPair(kCommandBuildAarProjectType, 'module'));
containsPair(CustomDimensions.commandBuildAarProjectType, 'module'));
}, overrides: <Type, Generator>{
AarBuilder: () => mockAarBuilder,
......@@ -63,7 +63,7 @@ void main() {
final BuildAarCommand command = await runCommandIn(projectPath);
expect(await command.usageValues,
containsPair(kCommandBuildAarProjectType, 'plugin'));
containsPair(CustomDimensions.commandBuildAarProjectType, 'plugin'));
}, overrides: <Type, Generator>{
AarBuilder: () => mockAarBuilder,
......@@ -76,7 +76,7 @@ void main() {
final BuildAarCommand command = await runCommandIn(projectPath,
arguments: <String>['--target-platform=android-arm']);
expect(await command.usageValues,
containsPair(kCommandBuildAarTargetPlatform, 'android-arm'));
containsPair(CustomDimensions.commandBuildAarTargetPlatform, 'android-arm'));
}, overrides: <Type, Generator>{
AarBuilder: () => mockAarBuilder,
......
......@@ -6,11 +6,11 @@ import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/bundle.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build_bundle.dart';
import 'package:flutter_tools/src/bundle.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
import '../../src/common.dart';
......@@ -70,7 +70,7 @@ void main() {
final BuildBundleCommand command = await runCommandIn(projectPath);
expect(await command.usageValues,
containsPair(kCommandBuildBundleIsModule, 'true'));
containsPair(CustomDimensions.commandBuildBundleIsModule, 'true'));
}, timeout: allowForCreateFlutterProject);
testUsingContext('bundle getUsage indicate that project is not a module', () async {
......@@ -80,7 +80,7 @@ void main() {
final BuildBundleCommand command = await runCommandIn(projectPath);
expect(await command.usageValues,
containsPair(kCommandBuildBundleIsModule, 'false'));
containsPair(CustomDimensions.commandBuildBundleIsModule, 'false'));
}, timeout: allowForCreateFlutterProject);
testUsingContext('bundle getUsage indicate the target platform', () async {
......@@ -90,7 +90,7 @@ void main() {
final BuildBundleCommand command = await runCommandIn(projectPath);
expect(await command.usageValues,
containsPair(kCommandBuildBundleTargetPlatform, 'android-arm'));
containsPair(CustomDimensions.commandBuildBundleTargetPlatform, 'android-arm'));
}, timeout: allowForCreateFlutterProject);
testUsingContext('bundle fails to build for Windows if feature is disabled', () async {
......
......@@ -7,7 +7,7 @@ import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/create.dart';
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import '../../src/common.dart';
import '../../src/context.dart';
......@@ -43,25 +43,35 @@ void main() {
final CreateCommand command = CreateCommand();
final CommandRunner<void> runner = createTestCommandRunner(command);
await runner.run(<String>['create', '--flutter-root=flutter', '--no-pub', '--template=module', 'testy']);
expect(await command.usageValues, containsPair(kCommandCreateProjectType, 'module'));
await runner.run(<String>[
'create', '--flutter-root=flutter', '--no-pub', '--template=module', 'testy']);
expect(await command.usageValues,
containsPair(CustomDimensions.commandCreateProjectType, 'module'));
await runner.run(<String>['create', '--flutter-root=flutter', '--no-pub', '--template=app', 'testy']);
expect(await command.usageValues, containsPair(kCommandCreateProjectType, 'app'));
await runner.run(<String>[
'create', '--flutter-root=flutter', '--no-pub', '--template=app', 'testy']);
expect(await command.usageValues,
containsPair(CustomDimensions.commandCreateProjectType, 'app'));
await runner.run(<String>['create', '--flutter-root=flutter', '--no-pub', '--template=package', 'testy']);
expect(await command.usageValues, containsPair(kCommandCreateProjectType, 'package'));
await runner.run(<String>[
'create', '--flutter-root=flutter', '--no-pub', '--template=package', 'testy']);
expect(await command.usageValues,
containsPair(CustomDimensions.commandCreateProjectType, 'package'));
await runner.run(<String>['create', '--flutter-root=flutter', '--no-pub', '--template=plugin', 'testy']);
expect(await command.usageValues, containsPair(kCommandCreateProjectType, 'plugin'));
await runner.run(<String>[
'create', '--flutter-root=flutter', '--no-pub', '--template=plugin', 'testy']);
expect(await command.usageValues,
containsPair(CustomDimensions.commandCreateProjectType, 'plugin'));
}));
test('set iOS host language type as usage value', () => testbed.run(() async {
final CreateCommand command = CreateCommand();
final CommandRunner<void> runner = createTestCommandRunner(command);
await runner.run(<String>['create', '--flutter-root=flutter', '--no-pub', '--template=app', 'testy']);
expect(await command.usageValues, containsPair(kCommandCreateIosLanguage, 'objc'));
await runner.run(<String>[
'create', '--flutter-root=flutter', '--no-pub', '--template=app', 'testy']);
expect(await command.usageValues,
containsPair(CustomDimensions.commandCreateIosLanguage, 'objc'));
await runner.run(<String>[
'create',
......@@ -71,7 +81,8 @@ void main() {
'--ios-language=swift',
'testy',
]);
expect(await command.usageValues, containsPair(kCommandCreateIosLanguage, 'swift'));
expect(await command.usageValues,
containsPair(CustomDimensions.commandCreateIosLanguage, 'swift'));
}));
......@@ -80,7 +91,8 @@ void main() {
final CommandRunner<void> runner = createTestCommandRunner(command);
await runner.run(<String>['create', '--flutter-root=flutter', '--no-pub', '--template=app', 'testy']);
expect(await command.usageValues, containsPair(kCommandCreateAndroidLanguage, 'java'));
expect(await command.usageValues,
containsPair(CustomDimensions.commandCreateAndroidLanguage, 'java'));
await runner.run(<String>[
'create',
......@@ -90,7 +102,8 @@ void main() {
'--android-language=kotlin',
'testy',
]);
expect(await command.usageValues, containsPair(kCommandCreateAndroidLanguage, 'kotlin'));
expect(await command.usageValues,
containsPair(CustomDimensions.commandCreateAndroidLanguage, 'kotlin'));
}));
});
}
......
......@@ -16,9 +16,9 @@ import 'package:flutter_tools/src/base/user_messages.dart';
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/globals.dart';
import 'package:flutter_tools/src/proxy_validator.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/vscode/vscode.dart';
import 'package:flutter_tools/src/vscode/vscode_validator.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import '../../src/common.dart';
import '../../src/context.dart';
......
......@@ -10,7 +10,7 @@ import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/utils.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/packages.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:process/process.dart';
import '../../src/common.dart';
......@@ -226,7 +226,8 @@ void main() {
final PackagesCommand command = await runCommandIn(projectPath, 'get');
final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand;
expect(await getCommand.usageValues, containsPair(kCommandPackagesNumberPlugins, '0'));
expect(await getCommand.usageValues,
containsPair(CustomDimensions.commandPackagesNumberPlugins, '0'));
}, timeout: allowForCreateFlutterProject);
testUsingContext('indicate that the project is not a module in usage value', () async {
......@@ -237,7 +238,8 @@ void main() {
final PackagesCommand command = await runCommandIn(projectPath, 'get');
final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand;
expect(await getCommand.usageValues, containsPair(kCommandPackagesProjectModule, 'false'));
expect(await getCommand.usageValues,
containsPair(CustomDimensions.commandPackagesProjectModule, 'false'));
}, timeout: allowForCreateFlutterProject);
testUsingContext('indicate that the project is a module in usage value', () async {
......@@ -248,7 +250,8 @@ void main() {
final PackagesCommand command = await runCommandIn(projectPath, 'get');
final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand;
expect(await getCommand.usageValues, containsPair(kCommandPackagesProjectModule, 'true'));
expect(await getCommand.usageValues,
containsPair(CustomDimensions.commandPackagesProjectModule, 'true'));
}, timeout: allowForCreateFlutterProject);
testUsingContext('upgrade fetches packages', () async {
......
......@@ -6,9 +6,9 @@ import 'dart:async';
import 'dart:convert';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/terminal.dart';
......
......@@ -8,17 +8,16 @@ import 'dart:convert';
import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:http/http.dart';
import 'package:http/testing.dart';
import 'package:flutter_tools/runner.dart' as tools;
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/reporting/crash_reporting.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:http/http.dart';
import 'package:http/testing.dart';
import 'package:pedantic/pedantic.dart';
import '../src/common.dart';
......
......@@ -129,6 +129,7 @@ void main() {
final MockDevice mockDevice = MockDevice();
when(mockDevice.supportsHotReload).thenReturn(true);
when(mockDevice.supportsHotRestart).thenReturn(false);
when(mockDevice.targetPlatform).thenAnswer((Invocation _) async => TargetPlatform.tester);
// Trigger hot restart.
final List<FlutterDevice> devices = <FlutterDevice>[
FlutterDevice(mockDevice, generator: residentCompiler, trackWidgetCreation: false, buildMode: BuildMode.debug)..devFS = mockDevFs,
......@@ -190,6 +191,7 @@ void main() {
final MockDevice mockDevice = MockDevice();
when(mockDevice.supportsHotReload).thenReturn(true);
when(mockDevice.supportsHotRestart).thenReturn(true);
when(mockDevice.targetPlatform).thenAnswer((Invocation _) async => TargetPlatform.tester);
final List<FlutterDevice> devices = <FlutterDevice>[
FlutterDevice(mockDevice, generator: residentCompiler, trackWidgetCreation: false, buildMode: BuildMode.debug),
];
......@@ -206,6 +208,7 @@ void main() {
final MockDevice mockDevice = MockDevice();
when(mockDevice.supportsHotReload).thenReturn(true);
when(mockDevice.supportsHotRestart).thenReturn(true);
when(mockDevice.targetPlatform).thenAnswer((Invocation _) async => TargetPlatform.tester);
// Trigger hot restart.
final List<FlutterDevice> devices = <FlutterDevice>[
FlutterDevice(mockDevice, generator: residentCompiler, trackWidgetCreation: false, buildMode: BuildMode.debug)..devFS = mockDevFs,
......
......@@ -5,14 +5,14 @@
import 'dart:async';
import 'package:file/file.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart' show ProcessException, ProcessResult;
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/ios/mac.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:process/process.dart';
......@@ -183,9 +183,10 @@ void main() {
);
await diagnoseXcodeBuildFailure(buildResult);
verify(mockUsage.sendEvent('Xcode', 'bitcode-failure', parameters: <String, String>{
'build-commands': buildCommands.toString(),
'build-settings': buildSettings.toString(),
verify(mockUsage.sendEvent('build', 'xcode-bitcode-failure',
parameters: <String, String>{
cdKey(CustomDimensions.buildEventCommand): buildCommands.toString(),
cdKey(CustomDimensions.buildEventSettings): buildSettings.toString(),
})).called(1);
}, overrides: <Type, Generator>{
Usage: () => mockUsage,
......
......@@ -4,17 +4,17 @@
import 'dart:async';
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/flutter_manifest.dart';
import 'package:flutter_tools/src/ios/ios_workflow.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart';
......
......@@ -11,7 +11,7 @@ import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/devfs.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/resident_runner.dart';
import 'package:flutter_tools/src/run_hot.dart';
import 'package:flutter_tools/src/vmservice.dart';
......@@ -53,6 +53,7 @@ void main() {
when(mockDevFS.lastCompiled).thenReturn(DateTime(2000));
when(mockDevFS.sources).thenReturn(<Uri>[]);
when(mockDevFS.destroy()).thenAnswer((Invocation invocation) async { });
when(mockDevFS.assetPathsToEvict).thenReturn(<String>{});
// FlutterDevice Mocks.
when(mockFlutterDevice.updateDevFS(
// Intentionally provide empty list to match above mock.
......@@ -96,6 +97,19 @@ void main() {
mockVMService,
]);
when(mockFlutterDevice.refreshViews()).thenAnswer((Invocation invocation) async { });
when(mockFlutterDevice.reloadSources(any, pause: anyNamed('pause'))).thenReturn(<Future<Map<String, dynamic>>>[
Future<Map<String, dynamic>>.value(<String, dynamic>{
'type': 'ReloadReport',
'success': true,
'details': <String, dynamic>{
'loadedLibraryCount': 1,
'finalLibraryCount': 1,
'receivedLibraryCount': 1,
'receivedClassesCount': 1,
'receivedProceduresCount': 1,
},
}),
]);
// VMService mocks.
when(mockVMService.wsAddress).thenReturn(testUri);
when(mockVMService.done).thenAnswer((Invocation invocation) {
......@@ -108,6 +122,9 @@ void main() {
when(mockIsolate.flutterExit()).thenAnswer((Invocation invocation) {
return Future<Map<String, Object>>.value(null);
});
when(mockIsolate.reload()).thenAnswer((Invocation invocation) {
return Future<ServiceObject>.value(null);
});
});
test('ResidentRunner can attach to device successfully', () => testbed.run(() async {
......@@ -162,15 +179,48 @@ void main() {
expect(result.fatal, true);
expect(result.code, 1);
verify(flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
reloadExceptionTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm),
reloadExceptionSdkName: 'Example',
reloadExceptionEmulator: 'false',
reloadExceptionFullRestart: 'false',
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'false',
})).called(1);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
}));
// Need one for hot restart as well.
test('ResidentRunner can send target platform to analytics from hot reload', () => testbed.run(() async {
when(mockDevice.sdkNameAndVersion).thenAnswer((Invocation invocation) async {
return 'Example';
});
when(mockDevice.targetPlatform).thenAnswer((Invocation invocation) async {
return TargetPlatform.android_arm;
});
when(mockDevice.isLocalEmulator).thenAnswer((Invocation invocation) async {
return false;
});
final Completer<DebugConnectionInfo> onConnectionInfo = Completer<DebugConnectionInfo>.sync();
final Completer<void> onAppStart = Completer<void>.sync();
unawaited(residentRunner.attach(
appStartedCompleter: onAppStart,
connectionInfoCompleter: onConnectionInfo,
));
final OperationResult result = await residentRunner.restart(fullRestart: false);
expect(result.fatal, false);
expect(result.code, 0);
expect(verify(flutterUsage.sendEvent('hot', 'reload',
parameters: captureAnyNamed('parameters'))).captured[0],
containsPair(cdKey(CustomDimensions.hotEventTargetPlatform),
getNameForTargetPlatform(TargetPlatform.android_arm))
);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
}));
test('ResidentRunner Can handle an RPC exception from hot restart', () => testbed.run(() async {
when(mockDevice.sdkNameAndVersion).thenAnswer((Invocation invocation) async {
return 'Example';
......@@ -206,10 +256,11 @@ void main() {
expect(result.fatal, true);
expect(result.code, 1);
verify(flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
reloadExceptionTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm),
reloadExceptionSdkName: 'Example',
reloadExceptionEmulator: 'false',
reloadExceptionFullRestart: 'true',
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'true',
})).called(1);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
......
......@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/base/time.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/time.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/version.dart';
import 'package:mockito/mockito.dart';
......
......@@ -5,7 +5,7 @@
import 'dart:async';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:mockito/mockito.dart';
......
......@@ -5,9 +5,6 @@
import 'dart:async';
import 'package:args/command_runner.dart';
import 'package:test_api/test_api.dart' hide TypeMatcher, isInstanceOf;
import 'package:test_api/test_api.dart' as test_package show TypeMatcher;
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart';
......@@ -15,6 +12,8 @@ import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/commands/create.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/runner/flutter_command_runner.dart';
import 'package:test_api/test_api.dart' as test_package show TypeMatcher;
import 'package:test_api/test_api.dart' hide TypeMatcher, isInstanceOf;
export 'package:test_core/test_core.dart' hide TypeMatcher, isInstanceOf; // Defines a 'package:test' shim.
......
......@@ -13,15 +13,15 @@ import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/base/time.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/context_runner.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/ios/simulators.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/base/time.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/version.dart';
import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart';
......
......@@ -8,17 +8,17 @@ import 'dart:io';
import 'dart:typed_data';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/context_runner.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/reporting/usage.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/version.dart';
import 'context.dart';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment