Unverified Commit f6a55125 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Add usage event for failed iOS project migration (#51879)

parent 94376395
...@@ -121,7 +121,7 @@ Future<int> _handleToolError( ...@@ -121,7 +121,7 @@ Future<int> _handleToolError(
} }
// Report to both [Usage] and [CrashReportSender]. // Report to both [Usage] and [CrashReportSender].
flutterUsage.sendException(error); globals.flutterUsage.sendException(error);
await CrashReportSender.instance.sendReport( await CrashReportSender.instance.sendReport(
error: error, error: error,
stackTrace: stackTrace, stackTrace: stackTrace,
...@@ -252,13 +252,13 @@ Future<String> _doctorText() async { ...@@ -252,13 +252,13 @@ Future<String> _doctorText() async {
Future<int> _exit(int code) async { Future<int> _exit(int code) async {
// Prints the welcome message if needed. // Prints the welcome message if needed.
flutterUsage.printWelcome(); globals.flutterUsage.printWelcome();
// Send any last analytics calls that are in progress without overly delaying // Send any last analytics calls that are in progress without overly delaying
// the tool's exit (we wait a maximum of 250ms). // the tool's exit (we wait a maximum of 250ms).
if (flutterUsage.enabled) { if (globals.flutterUsage.enabled) {
final Stopwatch stopwatch = Stopwatch()..start(); final Stopwatch stopwatch = Stopwatch()..start();
await flutterUsage.ensureAnalyticsSent(); await globals.flutterUsage.ensureAnalyticsSent();
globals.printTrace('ensureAnalyticsSent: ${stopwatch.elapsedMilliseconds}ms'); globals.printTrace('ensureAnalyticsSent: ${stopwatch.elapsedMilliseconds}ms');
} }
......
...@@ -396,7 +396,7 @@ Future<void> buildGradleApp({ ...@@ -396,7 +396,7 @@ Future<void> buildGradleApp({
status.stop(); status.stop();
} }
flutterUsage.sendTiming('build', 'gradle', sw.elapsed); globals.flutterUsage.sendTiming('build', 'gradle', sw.elapsed);
if (exitCode != 0) { if (exitCode != 0) {
if (detectedGradleError == null) { if (detectedGradleError == null) {
...@@ -589,7 +589,7 @@ Future<void> buildGradleAar({ ...@@ -589,7 +589,7 @@ Future<void> buildGradleAar({
} finally { } finally {
status.stop(); status.stop();
} }
flutterUsage.sendTiming('build', 'gradle-aar', sw.elapsed); globals.flutterUsage.sendTiming('build', 'gradle-aar', sw.elapsed);
if (result.exitCode != 0) { if (result.exitCode != 0) {
globals.printStatus(result.stdout, wrap: false); globals.printStatus(result.stdout, wrap: false);
...@@ -684,11 +684,11 @@ String _calculateSha(File file) { ...@@ -684,11 +684,11 @@ String _calculateSha(File file) {
final Stopwatch sw = Stopwatch()..start(); final Stopwatch sw = Stopwatch()..start();
final List<int> bytes = file.readAsBytesSync(); final List<int> bytes = file.readAsBytesSync();
globals.printTrace('calculateSha: reading file took ${sw.elapsedMilliseconds}us'); globals.printTrace('calculateSha: reading file took ${sw.elapsedMilliseconds}us');
flutterUsage.sendTiming('build', 'apk-sha-read', sw.elapsed); globals.flutterUsage.sendTiming('build', 'apk-sha-read', sw.elapsed);
sw.reset(); sw.reset();
final String sha = _hex(sha1.convert(bytes).bytes); final String sha = _hex(sha1.convert(bytes).bytes);
globals.printTrace('calculateSha: computing sha took ${sw.elapsedMilliseconds}us'); globals.printTrace('calculateSha: computing sha took ${sw.elapsedMilliseconds}us');
flutterUsage.sendTiming('build', 'apk-sha-calc', sw.elapsed); globals.flutterUsage.sendTiming('build', 'apk-sha-calc', sw.elapsed);
return sha; return sha;
} }
......
...@@ -13,7 +13,6 @@ import '../compile.dart'; ...@@ -13,7 +13,6 @@ import '../compile.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../macos/xcode.dart'; import '../macos/xcode.dart';
import '../project.dart'; import '../project.dart';
import '../reporting/reporting.dart';
import 'context.dart'; import 'context.dart';
import 'file_system.dart'; import 'file_system.dart';
...@@ -341,7 +340,7 @@ class AOTSnapshotter { ...@@ -341,7 +340,7 @@ class AOTSnapshotter {
if (reportTimings) { if (reportTimings) {
globals.printStatus('$marker: ${sw.elapsedMilliseconds} ms.'); globals.printStatus('$marker: ${sw.elapsedMilliseconds} ms.');
} }
flutterUsage.sendTiming('build', analyticsVar, Duration(milliseconds: sw.elapsedMilliseconds)); globals.flutterUsage.sendTiming('build', analyticsVar, Duration(milliseconds: sw.elapsedMilliseconds));
return value; return value;
} }
} }
...@@ -538,7 +538,7 @@ class _ResidentWebRunner extends ResidentWebRunner { ...@@ -538,7 +538,7 @@ class _ResidentWebRunner extends ResidentWebRunner {
// Don't track restart times for dart2js builds or web-server devices. // Don't track restart times for dart2js builds or web-server devices.
if (debuggingOptions.buildInfo.isDebug && deviceIsDebuggable) { if (debuggingOptions.buildInfo.isDebug && deviceIsDebuggable) {
flutterUsage.sendTiming('hot', 'web-incremental-restart', timer.elapsed); globals.flutterUsage.sendTiming('hot', 'web-incremental-restart', timer.elapsed);
HotEvent( HotEvent(
'restart', 'restart',
targetPlatform: getNameForTargetPlatform(TargetPlatform.web_javascript), targetPlatform: getNameForTargetPlatform(TargetPlatform.web_javascript),
......
...@@ -89,7 +89,7 @@ class ConfigCommand extends FlutterCommand { ...@@ -89,7 +89,7 @@ class ConfigCommand extends FlutterCommand {
} }
return return
'\nSettings:\n$values\n\n' '\nSettings:\n$values\n\n'
'Analytics reporting is currently ${flutterUsage.enabled ? 'enabled' : 'disabled'}.'; 'Analytics reporting is currently ${globals.flutterUsage.enabled ? 'enabled' : 'disabled'}.';
} }
/// Return null to disable analytics recording of the `config` command. /// Return null to disable analytics recording of the `config` command.
...@@ -117,7 +117,7 @@ class ConfigCommand extends FlutterCommand { ...@@ -117,7 +117,7 @@ class ConfigCommand extends FlutterCommand {
// We send the analytics event *before* toggling the flag intentionally // We send the analytics event *before* toggling the flag intentionally
// to be sure that opt-out events are sent correctly. // to be sure that opt-out events are sent correctly.
AnalyticsConfigEvent(enabled: value).send(); AnalyticsConfigEvent(enabled: value).send();
flutterUsage.enabled = value; globals.flutterUsage.enabled = value;
globals.printStatus('Analytics reporting ${value ? 'enabled' : 'disabled'}.'); globals.printStatus('Analytics reporting ${value ? 'enabled' : 'disabled'}.');
} }
......
...@@ -8,6 +8,7 @@ import '../base/common.dart'; ...@@ -8,6 +8,7 @@ import '../base/common.dart';
import '../base/os.dart'; import '../base/os.dart';
import '../cache.dart'; import '../cache.dart';
import '../dart/pub.dart'; import '../dart/pub.dart';
import '../globals.dart' as globals;
import '../project.dart'; import '../project.dart';
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
...@@ -97,11 +98,11 @@ class PackagesGetCommand extends FlutterCommand { ...@@ -97,11 +98,11 @@ class PackagesGetCommand extends FlutterCommand {
checkLastModified: false, checkLastModified: false,
); );
pubGetTimer.stop(); pubGetTimer.stop();
flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'success'); globals.flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'success');
// Not limiting to catching Exception because the exception is rethrown. // Not limiting to catching Exception because the exception is rethrown.
} catch (_) { // ignore: avoid_catches_without_on_clauses } catch (_) { // ignore: avoid_catches_without_on_clauses
pubGetTimer.stop(); pubGetTimer.stop();
flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'failure'); globals.flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'failure');
rethrow; rethrow;
} }
} }
......
...@@ -20,7 +20,6 @@ import '../convert.dart'; ...@@ -20,7 +20,6 @@ import '../convert.dart';
import '../devfs.dart'; import '../devfs.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../project.dart'; import '../project.dart';
import '../reporting/reporting.dart';
import 'fuchsia_pm.dart'; import 'fuchsia_pm.dart';
import 'fuchsia_sdk.dart'; import 'fuchsia_sdk.dart';
...@@ -29,7 +28,7 @@ Future<void> _timedBuildStep(String name, Future<void> Function() action) async ...@@ -29,7 +28,7 @@ Future<void> _timedBuildStep(String name, Future<void> Function() action) async
final Stopwatch sw = Stopwatch()..start(); final Stopwatch sw = Stopwatch()..start();
await action(); await action();
globals.printTrace('$name: ${sw.elapsedMilliseconds} ms.'); globals.printTrace('$name: ${sw.elapsedMilliseconds} ms.');
flutterUsage.sendTiming('build', name, Duration(milliseconds: sw.elapsedMilliseconds)); globals.flutterUsage.sendTiming('build', name, Duration(milliseconds: sw.elapsedMilliseconds));
} }
Future<void> _validateCmxFile(FuchsiaProject fuchsiaProject) async { Future<void> _validateCmxFile(FuchsiaProject fuchsiaProject) async {
......
...@@ -26,6 +26,7 @@ import 'ios/mac.dart'; ...@@ -26,6 +26,7 @@ import 'ios/mac.dart';
import 'ios/plist_parser.dart'; import 'ios/plist_parser.dart';
import 'macos/xcode.dart'; import 'macos/xcode.dart';
import 'persistent_tool_state.dart'; import 'persistent_tool_state.dart';
import 'reporting/reporting.dart';
import 'version.dart'; import 'version.dart';
import 'web/chrome.dart'; import 'web/chrome.dart';
...@@ -35,6 +36,7 @@ Config get config => context.get<Config>(); ...@@ -35,6 +36,7 @@ Config get config => context.get<Config>();
Logger get logger => context.get<Logger>(); Logger get logger => context.get<Logger>();
OperatingSystemUtils get os => context.get<OperatingSystemUtils>(); OperatingSystemUtils get os => context.get<OperatingSystemUtils>();
PersistentToolState get persistentToolState => PersistentToolState.instance; PersistentToolState get persistentToolState => PersistentToolState.instance;
Usage get flutterUsage => context.get<Usage>();
const FileSystem _kLocalFs = LocalFileSystem(); const FileSystem _kLocalFs = LocalFileSystem();
......
...@@ -9,6 +9,7 @@ import 'package:vm_service/vm_service_io.dart' as vm_service_io; ...@@ -9,6 +9,7 @@ import 'package:vm_service/vm_service_io.dart' as vm_service_io;
import '../base/io.dart'; import '../base/io.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../device.dart'; import '../device.dart';
import '../globals.dart' as globals;
import '../mdns_discovery.dart'; import '../mdns_discovery.dart';
import '../protocol_discovery.dart'; import '../protocol_discovery.dart';
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
...@@ -82,18 +83,18 @@ class FallbackDiscovery { ...@@ -82,18 +83,18 @@ class FallbackDiscovery {
hostVmservicePort: hostVmservicePort, hostVmservicePort: hostVmservicePort,
); );
if (result != null) { if (result != null) {
UsageEvent(_kEventName, 'mdns-success').send(); UsageEvent(_kEventName, 'mdns-success', flutterUsage: globals.flutterUsage).send();
return result; return result;
} }
} on Exception catch (err) { } on Exception catch (err) {
_logger.printTrace(err.toString()); _logger.printTrace(err.toString());
} }
_logger.printTrace('Failed to connect with mDNS, falling back to log scanning'); _logger.printTrace('Failed to connect with mDNS, falling back to log scanning');
UsageEvent(_kEventName, 'mdns-failure').send(); UsageEvent(_kEventName, 'mdns-failure', flutterUsage: globals.flutterUsage).send();
try { try {
final Uri result = await _protocolDiscovery.uri; final Uri result = await _protocolDiscovery.uri;
UsageEvent(_kEventName, 'fallback-success').send(); UsageEvent(_kEventName, 'fallback-success', flutterUsage: globals.flutterUsage).send();
return result; return result;
} on ArgumentError { } on ArgumentError {
// In the event of an invalid InternetAddress, this code attempts to catch // In the event of an invalid InternetAddress, this code attempts to catch
...@@ -102,7 +103,7 @@ class FallbackDiscovery { ...@@ -102,7 +103,7 @@ class FallbackDiscovery {
_logger.printTrace(err.toString()); _logger.printTrace(err.toString());
} }
_logger.printTrace('Failed to connect with log scanning'); _logger.printTrace('Failed to connect with log scanning');
UsageEvent(_kEventName, 'fallback-failure').send(); UsageEvent(_kEventName, 'fallback-failure', flutterUsage: globals.flutterUsage).send();
return null; return null;
} }
...@@ -141,7 +142,7 @@ class FallbackDiscovery { ...@@ -141,7 +142,7 @@ class FallbackDiscovery {
} }
final LibraryRef library = (isolateResponse as Isolate).rootLib; final LibraryRef library = (isolateResponse as Isolate).rootLib;
if (library.uri.startsWith('package:$packageName')) { if (library.uri.startsWith('package:$packageName')) {
UsageEvent(_kEventName, 'success').send(); UsageEvent(_kEventName, 'success', flutterUsage: globals.flutterUsage).send();
return Uri.parse('http://localhost:$hostPort'); return Uri.parse('http://localhost:$hostPort');
} }
} }
...@@ -180,6 +181,7 @@ class FallbackDiscovery { ...@@ -180,6 +181,7 @@ class FallbackDiscovery {
_kEventName, _kEventName,
eventAction, eventAction,
label: eventLabel, label: eventLabel,
flutterUsage: globals.flutterUsage,
).send(); ).send();
} }
} }
...@@ -90,13 +90,12 @@ Future<XcodeBuildResult> buildXcodeProject({ ...@@ -90,13 +90,12 @@ Future<XcodeBuildResult> buildXcodeProject({
} }
final List<IOSMigrator> migrators = <IOSMigrator>[ final List<IOSMigrator> migrators = <IOSMigrator>[
RemoveFrameworkLinkAndEmbeddingMigration(app.project, globals.logger, globals.xcode) RemoveFrameworkLinkAndEmbeddingMigration(app.project, globals.logger, globals.xcode, globals.flutterUsage)
]; ];
for (final IOSMigrator migrator in migrators) { final IOSMigration migration = IOSMigration(migrators);
if (!migrator.migrate()) { if (!migration.run()) {
return XcodeBuildResult(success: false); return XcodeBuildResult(success: false);
}
} }
if (!_checkXcodeVersion()) { if (!_checkXcodeVersion()) {
...@@ -302,7 +301,7 @@ Future<XcodeBuildResult> buildXcodeProject({ ...@@ -302,7 +301,7 @@ Future<XcodeBuildResult> buildXcodeProject({
'Xcode build done.'.padRight(kDefaultStatusPadding + 1) 'Xcode build done.'.padRight(kDefaultStatusPadding + 1)
+ getElapsedAsSeconds(sw.elapsed).padLeft(5), + getElapsedAsSeconds(sw.elapsed).padLeft(5),
); );
flutterUsage.sendTiming('build', 'xcode-ios', Duration(milliseconds: sw.elapsedMilliseconds)); globals.flutterUsage.sendTiming('build', 'xcode-ios', Duration(milliseconds: sw.elapsedMilliseconds));
// Run -showBuildSettings again but with the exact same parameters as the // Run -showBuildSettings again but with the exact same parameters as the
// build. showBuildSettings is reported to ocassionally timeout. Here, we give // build. showBuildSettings is reported to ocassionally timeout. Here, we give
......
...@@ -10,20 +10,20 @@ import '../../base/logger.dart'; ...@@ -10,20 +10,20 @@ import '../../base/logger.dart';
/// iOS project is generated from a template on Flutter project creation. /// iOS project is generated from a template on Flutter project creation.
/// Sometimes (due to behavior changes in Xcode, CocoaPods, etc) these files need to be altered /// Sometimes (due to behavior changes in Xcode, CocoaPods, etc) these files need to be altered
/// from the original template. /// from the original template.
class IOSMigrator { abstract class IOSMigrator {
IOSMigrator(this.logger); IOSMigrator(this.logger);
@protected @protected
final Logger logger; final Logger logger;
/// Returns whether migration was successful or was skipped. /// Returns whether migration was successful or was skipped.
bool migrate() { bool migrate();
return false;
} /// Return null if the line should be deleted.
String migrateLine(String line);
/// [processLine] should return null if the line should be deleted.
@protected @protected
void processFileLines(File file, String Function(String) processLine) { void processFileLines(File file) {
final List<String> lines = file.readAsLinesSync(); final List<String> lines = file.readAsLinesSync();
final StringBuffer newProjectContents = StringBuffer(); final StringBuffer newProjectContents = StringBuffer();
...@@ -31,7 +31,7 @@ class IOSMigrator { ...@@ -31,7 +31,7 @@ class IOSMigrator {
bool migrationRequired = false; bool migrationRequired = false;
for (final String line in lines) { for (final String line in lines) {
final String newProjectLine = processLine(line); final String newProjectLine = migrateLine(line);
if (newProjectLine == null) { if (newProjectLine == null) {
logger.printTrace('Migrating $basename, removing:'); logger.printTrace('Migrating $basename, removing:');
logger.printTrace(' $line'); logger.printTrace(' $line');
...@@ -54,3 +54,21 @@ class IOSMigrator { ...@@ -54,3 +54,21 @@ class IOSMigrator {
} }
} }
} }
class IOSMigration {
IOSMigration(this.migrators);
final List<IOSMigrator> migrators;
bool run() {
for (final IOSMigrator migrator in migrators) {
if (!migrator.migrate()) {
// Migration failures should be more robust, with transactions and fallbacks.
// See https://github.com/flutter/flutter/issues/12573 and
// https://github.com/flutter/flutter/issues/40460
return false;
}
}
return true;
}
}
...@@ -2,10 +2,12 @@ ...@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import '../../base/common.dart';
import '../../base/file_system.dart'; import '../../base/file_system.dart';
import '../../base/logger.dart'; import '../../base/logger.dart';
import '../../macos/xcode.dart'; import '../../macos/xcode.dart';
import '../../project.dart'; import '../../project.dart';
import '../../reporting/reporting.dart';
import 'ios_migrator.dart'; import 'ios_migrator.dart';
/// Xcode 11.4 requires linked and embedded frameworks to contain all targeted architectures before build phases are run. /// Xcode 11.4 requires linked and embedded frameworks to contain all targeted architectures before build phases are run.
...@@ -13,15 +15,18 @@ import 'ios_migrator.dart'; ...@@ -13,15 +15,18 @@ import 'ios_migrator.dart';
/// Remove the linking and embedding logic from the Xcode project to give the tool more control over these. /// Remove the linking and embedding logic from the Xcode project to give the tool more control over these.
class RemoveFrameworkLinkAndEmbeddingMigration extends IOSMigrator { class RemoveFrameworkLinkAndEmbeddingMigration extends IOSMigrator {
RemoveFrameworkLinkAndEmbeddingMigration( RemoveFrameworkLinkAndEmbeddingMigration(
IosProject project, IosProject project,
Logger logger, Logger logger,
Xcode xcode, Xcode xcode,
) : _xcodeProjectInfoFile = project.xcodeProjectInfoFile, Usage usage,
) : _xcodeProjectInfoFile = project.xcodeProjectInfoFile,
_xcode = xcode, _xcode = xcode,
_usage = usage,
super(logger); super(logger);
final File _xcodeProjectInfoFile; final File _xcodeProjectInfoFile;
final Xcode _xcode; final Xcode _xcode;
final Usage _usage;
/// Inspect [project] for necessary migrations and rewrite files as needed. /// Inspect [project] for necessary migrations and rewrite files as needed.
@override @override
...@@ -35,78 +40,76 @@ class RemoveFrameworkLinkAndEmbeddingMigration extends IOSMigrator { ...@@ -35,78 +40,76 @@ class RemoveFrameworkLinkAndEmbeddingMigration extends IOSMigrator {
return true; return true;
} }
bool migrationFailure = false; processFileLines(_xcodeProjectInfoFile);
processFileLines(_xcodeProjectInfoFile, (String line) {
// App.framework Frameworks reference.
// isa = PBXFrameworksBuildPhase;
// files = (
// 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
if (line.contains('3B80C3941E831B6300D905FE')) {
return null;
}
// App.framework Embed Framework reference (build phase to embed framework). return true;
// 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, }
if (line.contains('3B80C3951E831B6300D905FE')
|| line.contains('741F496821356857001E2961')) { // Ephemeral add-to-app variant.
return null;
}
// App.framework project file reference (seen in Xcode navigator pane). @override
// isa = PBXGroup; String migrateLine(String line) {
// children = ( // App.framework Frameworks reference.
// 3B80C3931E831B6300D905FE /* App.framework */, // isa = PBXFrameworksBuildPhase;
if (line.contains('3B80C3931E831B6300D905FE') // files = (
|| line.contains('741F496521356807001E2961')) { // Ephemeral add-to-app variant. // 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
return null; if (line.contains('3B80C3941E831B6300D905FE')) {
} return null;
}
// Flutter.framework Frameworks reference. // App.framework Embed Framework reference (build phase to embed framework).
// isa = PBXFrameworksBuildPhase; // 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
// files = ( if (line.contains('3B80C3951E831B6300D905FE')
// 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, || line.contains('741F496821356857001E2961')) { // Ephemeral add-to-app variant.
if (line.contains('9705A1C61CF904A100538489')) { return null;
return null; }
}
// Flutter.framework Embed Framework reference (build phase to embed framework). // App.framework project file reference (seen in Xcode navigator pane).
// 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, // isa = PBXGroup;
if (line.contains('9705A1C71CF904A300538489') // children = (
|| line.contains('741F496221355F47001E2961')) { // Ephemeral add-to-app variant. // 3B80C3931E831B6300D905FE /* App.framework */,
return null; if (line.contains('3B80C3931E831B6300D905FE')
} || line.contains('741F496521356807001E2961')) { // Ephemeral add-to-app variant.
return null;
}
// Flutter.framework project file reference (seen in Xcode navigator pane). // Flutter.framework Frameworks reference.
// isa = PBXGroup; // isa = PBXFrameworksBuildPhase;
// children = ( // files = (
// 9740EEBA1CF902C7004384FC /* Flutter.framework */, // 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
if (line.contains('9740EEBA1CF902C7004384FC') if (line.contains('9705A1C61CF904A100538489')) {
|| line.contains('741F495E21355F27001E2961')) { // Ephemeral add-to-app variant. return null;
return null; }
}
// Embed and thin frameworks in a script instead of using Xcode's link / embed build phases. // Flutter.framework Embed Framework reference (build phase to embed framework).
const String thinBinaryScript = 'xcode_backend.sh\\" thin'; // 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
if (line.contains(thinBinaryScript) && !line.contains(' embed')) { if (line.contains('9705A1C71CF904A300538489')
return line.replaceFirst(thinBinaryScript, 'xcode_backend.sh\\" embed_and_thin'); || line.contains('741F496221355F47001E2961')) { // Ephemeral add-to-app variant.
} return null;
}
if (line.contains('/* App.framework ') || line.contains('/* Flutter.framework ')) { // Flutter.framework project file reference (seen in Xcode navigator pane).
migrationFailure = true; // isa = PBXGroup;
} // children = (
// 9740EEBA1CF902C7004384FC /* Flutter.framework */,
if (line.contains('9740EEBA1CF902C7004384FC')
|| line.contains('741F495E21355F27001E2961')) { // Ephemeral add-to-app variant.
return null;
}
return line; // Embed and thin frameworks in a script instead of using Xcode's link / embed build phases.
}); const String thinBinaryScript = 'xcode_backend.sh\\" thin';
if (line.contains(thinBinaryScript) && !line.contains(' embed')) {
return line.replaceFirst(thinBinaryScript, 'xcode_backend.sh\\" embed_and_thin');
}
if (migrationFailure) { if (line.contains('/* App.framework ') || line.contains('/* Flutter.framework ')) {
// Print scary message if the user is on Xcode 11.4 or greater, or if Xcode isn't installed. // Print scary message if the user is on Xcode 11.4 or greater, or if Xcode isn't installed.
final bool xcodeIsInstalled = _xcode.isInstalled; final bool xcodeIsInstalled = _xcode.isInstalled;
if(!xcodeIsInstalled || (_xcode.majorVersion > 11 || (_xcode.majorVersion == 11 && _xcode.minorVersion >= 4))) { if(!xcodeIsInstalled || (_xcode.majorVersion > 11 || (_xcode.majorVersion == 11 && _xcode.minorVersion >= 4))) {
logger.printError('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.'); UsageEvent('ios-migration', 'remove-frameworks', label: 'failure', flutterUsage: _usage).send();
return false; throwToolExit('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.');
} }
} }
return true; return line;
} }
} }
...@@ -12,7 +12,6 @@ import '../cache.dart'; ...@@ -12,7 +12,6 @@ import '../cache.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../plugins.dart'; import '../plugins.dart';
import '../project.dart'; import '../project.dart';
import '../reporting/reporting.dart';
/// Builds the Linux project through the Makefile. /// Builds the Linux project through the Makefile.
Future<void> buildLinux(LinuxProject linuxProject, BuildInfo buildInfo, {String target = 'lib/main.dart'}) async { Future<void> buildLinux(LinuxProject linuxProject, BuildInfo buildInfo, {String target = 'lib/main.dart'}) async {
...@@ -88,7 +87,7 @@ export PROJECT_DIR=${linuxProject.project.directory.path} ...@@ -88,7 +87,7 @@ export PROJECT_DIR=${linuxProject.project.directory.path}
if (result != 0) { if (result != 0) {
throwToolExit('Build process failed'); throwToolExit('Build process failed');
} }
flutterUsage.sendTiming('build', 'make-linux', Duration(milliseconds: sw.elapsedMilliseconds)); globals.flutterUsage.sendTiming('build', 'make-linux', Duration(milliseconds: sw.elapsedMilliseconds));
} }
// Checks the template version of [project] against the current template // Checks the template version of [project] against the current template
......
...@@ -10,7 +10,6 @@ import '../build_info.dart'; ...@@ -10,7 +10,6 @@ import '../build_info.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../ios/xcodeproj.dart'; import '../ios/xcodeproj.dart';
import '../project.dart'; import '../project.dart';
import '../reporting/reporting.dart';
import 'cocoapod_utils.dart'; import 'cocoapod_utils.dart';
/// Builds the macOS project through xcodebuild. /// Builds the macOS project through xcodebuild.
...@@ -93,5 +92,5 @@ Future<void> buildMacOS({ ...@@ -93,5 +92,5 @@ Future<void> buildMacOS({
if (result != 0) { if (result != 0) {
throwToolExit('Build process failed'); throwToolExit('Build process failed');
} }
flutterUsage.sendTiming('build', 'xcode-macos', Duration(milliseconds: sw.elapsedMilliseconds)); globals.flutterUsage.sendTiming('build', 'xcode-macos', Duration(milliseconds: sw.elapsedMilliseconds));
} }
...@@ -326,7 +326,7 @@ class XCDevice { ...@@ -326,7 +326,7 @@ class XCDevice {
if (errorProperties != null) { if (errorProperties != null) {
final String errorMessage = _parseErrorMessage(errorProperties); final String errorMessage = _parseErrorMessage(errorProperties);
if (errorMessage.contains('not paired')) { if (errorMessage.contains('not paired')) {
UsageEvent('device', 'ios-trust-failure').send(); UsageEvent('device', 'ios-trust-failure', flutterUsage: globals.flutterUsage).send();
} }
_logger.printTrace(errorMessage); _logger.printTrace(errorMessage);
......
...@@ -189,7 +189,7 @@ class MDnsObservatoryDiscovery { ...@@ -189,7 +189,7 @@ class MDnsObservatoryDiscovery {
final TargetPlatform targetPlatform = await device.targetPlatform; final TargetPlatform targetPlatform = await device.targetPlatform;
switch (targetPlatform) { switch (targetPlatform) {
case TargetPlatform.ios: case TargetPlatform.ios:
UsageEvent('ios-mdns', 'no-ipv4-link-local').send(); UsageEvent('ios-mdns', 'no-ipv4-link-local', flutterUsage: globals.flutterUsage).send();
globals.printError( globals.printError(
'The mDNS query for an attached iOS device failed. It may ' 'The mDNS query for an attached iOS device failed. It may '
'be necessary to disable the "Personal Hotspot" on the device, and ' 'be necessary to disable the "Personal Hotspot" on the device, and '
......
...@@ -53,7 +53,7 @@ class CrashReportSender { ...@@ -53,7 +53,7 @@ class CrashReportSender {
} }
final http.Client _client; final http.Client _client;
final Usage _usage = Usage.instance; final Usage _usage = globals.flutterUsage;
Uri get _baseUrl { Uri get _baseUrl {
final String overrideUrl = globals.platform.environment['FLUTTER_CRASH_SERVER_BASE_URL']; final String overrideUrl = globals.platform.environment['FLUTTER_CRASH_SERVER_BASE_URL'];
......
...@@ -12,12 +12,14 @@ class UsageEvent { ...@@ -12,12 +12,14 @@ class UsageEvent {
UsageEvent(this.category, this.parameter, { UsageEvent(this.category, this.parameter, {
this.label, this.label,
this.value, this.value,
@required this.flutterUsage,
}); });
final String category; final String category;
final String parameter; final String parameter;
final String label; final String label;
final int value; final int value;
final Usage flutterUsage;
void send() { void send() {
flutterUsage.sendEvent(category, parameter, label: label, value: value); flutterUsage.sendEvent(category, parameter, label: label, value: value);
...@@ -46,7 +48,7 @@ class HotEvent extends UsageEvent { ...@@ -46,7 +48,7 @@ class HotEvent extends UsageEvent {
this.invalidatedSourcesCount, this.invalidatedSourcesCount,
this.transferTimeInMs, this.transferTimeInMs,
this.overallTimeInMs, this.overallTimeInMs,
}) : super('hot', parameter); }) : super('hot', parameter, flutterUsage: globals.flutterUsage);
final String reason; final String reason;
final String targetPlatform; final String targetPlatform;
...@@ -101,6 +103,7 @@ class DoctorResultEvent extends UsageEvent { ...@@ -101,6 +103,7 @@ class DoctorResultEvent extends UsageEvent {
'doctor-result', 'doctor-result',
'${validator.runtimeType}', '${validator.runtimeType}',
label: result.typeStr, label: result.typeStr,
flutterUsage: globals.flutterUsage,
); );
final DoctorValidator validator; final DoctorValidator validator;
...@@ -126,7 +129,7 @@ class PubResultEvent extends UsageEvent { ...@@ -126,7 +129,7 @@ class PubResultEvent extends UsageEvent {
PubResultEvent({ PubResultEvent({
@required String context, @required String context,
@required String result, @required String result,
}) : super('pub-result', context, label: result); }) : super('pub-result', context, label: result, flutterUsage: globals.flutterUsage);
} }
/// An event that reports something about a build. /// An event that reports something about a build.
...@@ -143,6 +146,7 @@ class BuildEvent extends UsageEvent { ...@@ -143,6 +146,7 @@ class BuildEvent extends UsageEvent {
? 'unspecified' ? 'unspecified'
: FlutterCommand.current.name, : FlutterCommand.current.name,
label: label, label: label,
flutterUsage: globals.flutterUsage,
); );
final String command; final String command;
...@@ -173,7 +177,7 @@ class CommandResultEvent extends UsageEvent { ...@@ -173,7 +177,7 @@ class CommandResultEvent extends UsageEvent {
CommandResultEvent(String commandPath, FlutterCommandResult result) CommandResultEvent(String commandPath, FlutterCommandResult result)
: assert(commandPath != null), : assert(commandPath != null),
assert(result != null), assert(result != null),
super(commandPath, result.toString()); super(commandPath, result.toString(), flutterUsage: globals.flutterUsage);
@override @override
void send() { void send() {
...@@ -211,5 +215,6 @@ class AnalyticsConfigEvent extends UsageEvent { ...@@ -211,5 +215,6 @@ class AnalyticsConfigEvent extends UsageEvent {
'analytics', 'analytics',
'enabled', 'enabled',
label: enabled ? 'true' : 'false', label: enabled ? 'true' : 'false',
flutterUsage: globals.flutterUsage,
); );
} }
...@@ -10,7 +10,6 @@ import 'package:http/http.dart' as http; ...@@ -10,7 +10,6 @@ import 'package:http/http.dart' as http;
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:usage/usage_io.dart'; import 'package:usage/usage_io.dart';
import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart'; import '../base/io.dart';
import '../base/time.dart'; import '../base/time.dart';
......
...@@ -66,8 +66,6 @@ Map<String, String> _useCdKeys(Map<CustomDimensions, String> parameters) { ...@@ -66,8 +66,6 @@ Map<String, String> _useCdKeys(Map<CustomDimensions, String> parameters) {
MapEntry<String, String>(cdKey(k), v)); MapEntry<String, String>(cdKey(k), v));
} }
Usage get flutterUsage => Usage.instance;
abstract class Usage { abstract class Usage {
/// Create a new Usage instance; [versionOverride], [configDirOverride], and /// Create a new Usage instance; [versionOverride], [configDirOverride], and
/// [logFile] are used for testing. /// [logFile] are used for testing.
...@@ -83,13 +81,10 @@ abstract class Usage { ...@@ -83,13 +81,10 @@ abstract class Usage {
logFile: logFile, logFile: logFile,
runningOnBot: runningOnBot); runningOnBot: runningOnBot);
/// Returns [Usage] active in the current app context.
static Usage get instance => context.get<Usage>();
/// Uses the global [Usage] instance to send a 'command' to analytics. /// Uses the global [Usage] instance to send a 'command' to analytics.
static void command(String command, { static void command(String command, {
Map<CustomDimensions, String> parameters, Map<CustomDimensions, String> parameters,
}) => flutterUsage.sendCommand(command, parameters: _useCdKeys(parameters)); }) => globals.flutterUsage.sendCommand(command, parameters: _useCdKeys(parameters));
/// Whether this is the first run of the tool. /// Whether this is the first run of the tool.
bool get isFirstRun; bool get isFirstRun;
......
...@@ -197,7 +197,7 @@ class HotRunner extends ResidentRunner { ...@@ -197,7 +197,7 @@ class HotRunner extends ResidentRunner {
} }
globals.printStatus('reloadMethod took ${stopwatch.elapsedMilliseconds}'); globals.printStatus('reloadMethod took ${stopwatch.elapsedMilliseconds}');
flutterUsage.sendTiming('hot', 'ui', stopwatch.elapsed); globals.flutterUsage.sendTiming('hot', 'ui', stopwatch.elapsed);
return OperationResult.ok; return OperationResult.ok;
} }
...@@ -550,7 +550,7 @@ class HotRunner extends ResidentRunner { ...@@ -550,7 +550,7 @@ class HotRunner extends ResidentRunner {
restartTimer.elapsed.inMilliseconds); restartTimer.elapsed.inMilliseconds);
// Send timing analytics. // Send timing analytics.
flutterUsage.sendTiming('hot', 'restart', restartTimer.elapsed); globals.flutterUsage.sendTiming('hot', 'restart', restartTimer.elapsed);
// In benchmark mode, make sure all stream notifications have finished. // In benchmark mode, make sure all stream notifications have finished.
if (benchmarkMode) { if (benchmarkMode) {
...@@ -1024,7 +1024,7 @@ class HotRunner extends ResidentRunner { ...@@ -1024,7 +1024,7 @@ class HotRunner extends ResidentRunner {
} }
// Only report timings if we reloaded a single view without any errors. // Only report timings if we reloaded a single view without any errors.
if ((reassembleViews.length == 1) && !failedReassemble && shouldReportReloadTime) { if ((reassembleViews.length == 1) && !failedReassemble && shouldReportReloadTime) {
flutterUsage.sendTiming('hot', 'reload', reloadDuration); globals.flutterUsage.sendTiming('hot', 'reload', reloadDuration);
} }
return OperationResult( return OperationResult(
failedReassemble ? 1 : OperationResult.ok.code, failedReassemble ? 1 : OperationResult.ok.code,
......
...@@ -601,7 +601,7 @@ abstract class FlutterCommand extends Command<void> { ...@@ -601,7 +601,7 @@ abstract class FlutterCommand extends Command<void> {
overrides: <Type, Generator>{FlutterCommand: () => this}, overrides: <Type, Generator>{FlutterCommand: () => this},
body: () async { body: () async {
// Prints the welcome message if needed. // Prints the welcome message if needed.
flutterUsage.printWelcome(); globals.flutterUsage.printWelcome();
final String commandPath = await usagePath; final String commandPath = await usagePath;
_registerSignalHandlers(commandPath, startTime); _registerSignalHandlers(commandPath, startTime);
FlutterCommandResult commandResult = FlutterCommandResult.fail(); FlutterCommandResult commandResult = FlutterCommandResult.fail();
...@@ -657,7 +657,7 @@ abstract class FlutterCommand extends Command<void> { ...@@ -657,7 +657,7 @@ abstract class FlutterCommand extends Command<void> {
final String label = labels final String label = labels
.where((String label) => !isBlank(label)) .where((String label) => !isBlank(label))
.join('-'); .join('-');
flutterUsage.sendTiming( globals.flutterUsage.sendTiming(
'flutter', 'flutter',
name, name,
// If the command provides its own end time, use it. Otherwise report // If the command provides its own end time, use it. Otherwise report
......
...@@ -23,7 +23,6 @@ import '../convert.dart'; ...@@ -23,7 +23,6 @@ import '../convert.dart';
import '../dart/package_map.dart'; import '../dart/package_map.dart';
import '../device.dart'; import '../device.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../reporting/reporting.dart';
import '../tester/flutter_tester.dart'; import '../tester/flutter_tester.dart';
const String kFlutterRootEnvironmentVariableName = 'FLUTTER_ROOT'; // should point to //flutter/ (root of flutter/flutter repo) const String kFlutterRootEnvironmentVariableName = 'FLUTTER_ROOT'; // should point to //flutter/ (root of flutter/flutter repo)
...@@ -298,7 +297,7 @@ class FlutterCommandRunner extends CommandRunner<void> { ...@@ -298,7 +297,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
} }
if (topLevelResults['suppress-analytics'] as bool) { if (topLevelResults['suppress-analytics'] as bool) {
flutterUsage.suppressAnalytics = true; globals.flutterUsage.suppressAnalytics = true;
} }
_checkFlutterCopy(); _checkFlutterCopy();
...@@ -322,7 +321,7 @@ class FlutterCommandRunner extends CommandRunner<void> { ...@@ -322,7 +321,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
deviceManager.specifiedDeviceId = topLevelResults['device-id'] as String; deviceManager.specifiedDeviceId = topLevelResults['device-id'] as String;
if (topLevelResults['version'] as bool) { if (topLevelResults['version'] as bool) {
flutterUsage.sendCommand('version'); globals.flutterUsage.sendCommand('version');
String status; String status;
if (machineFlag) { if (machineFlag) {
status = const JsonEncoder.withIndent(' ').convert(globals.flutterVersion.toJson()); status = const JsonEncoder.withIndent(' ').convert(globals.flutterVersion.toJson());
......
...@@ -18,7 +18,6 @@ import '../globals.dart' as globals; ...@@ -18,7 +18,6 @@ import '../globals.dart' as globals;
import '../platform_plugins.dart'; import '../platform_plugins.dart';
import '../plugins.dart'; import '../plugins.dart';
import '../project.dart'; import '../project.dart';
import '../reporting/reporting.dart';
/// The [WebCompilationProxy] instance. /// The [WebCompilationProxy] instance.
WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>(); WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>();
...@@ -71,7 +70,7 @@ Future<void> buildWeb( ...@@ -71,7 +70,7 @@ Future<void> buildWeb(
} finally { } finally {
status.stop(); status.stop();
} }
flutterUsage.sendTiming('build', 'dart2js', Duration(milliseconds: sw.elapsedMilliseconds)); globals.flutterUsage.sendTiming('build', 'dart2js', Duration(milliseconds: sw.elapsedMilliseconds));
} }
/// An indirection on web compilation. /// An indirection on web compilation.
......
...@@ -12,7 +12,6 @@ import '../cache.dart'; ...@@ -12,7 +12,6 @@ import '../cache.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../plugins.dart'; import '../plugins.dart';
import '../project.dart'; import '../project.dart';
import '../reporting/reporting.dart';
import 'property_sheet.dart'; import 'property_sheet.dart';
import 'visual_studio.dart'; import 'visual_studio.dart';
...@@ -76,7 +75,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {S ...@@ -76,7 +75,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {S
if (result != 0) { if (result != 0) {
throwToolExit('Build process failed. To view the stack trace, please run `flutter run -d windows -v`.'); throwToolExit('Build process failed. To view the stack trace, please run `flutter run -d windows -v`.');
} }
flutterUsage.sendTiming('build', 'vs_build', Duration(milliseconds: sw.elapsedMilliseconds)); globals.flutterUsage.sendTiming('build', 'vs_build', Duration(milliseconds: sw.elapsedMilliseconds));
} }
/// Writes the generatedPropertySheetFile with the configuration for the given build. /// Writes the generatedPropertySheetFile with the configuration for the given build.
......
...@@ -48,18 +48,18 @@ void main() { ...@@ -48,18 +48,18 @@ void main() {
// Ensure we don't send anything when analytics is disabled. // Ensure we don't send anything when analytics is disabled.
testUsingContext("doesn't send when disabled", () async { testUsingContext("doesn't send when disabled", () async {
int count = 0; int count = 0;
flutterUsage.onSend.listen((Map<String, dynamic> data) => count++); globals.flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
flutterUsage.enabled = false; globals.flutterUsage.enabled = false;
await createProject(tempDir); await createProject(tempDir);
expect(count, 0); expect(count, 0);
flutterUsage.enabled = true; globals.flutterUsage.enabled = true;
await createProject(tempDir); await createProject(tempDir);
expect(count, flutterUsage.isFirstRun ? 0 : 4); expect(count, globals.flutterUsage.isFirstRun ? 0 : 4);
count = 0; count = 0;
flutterUsage.enabled = false; globals.flutterUsage.enabled = false;
final DoctorCommand doctorCommand = DoctorCommand(); final DoctorCommand doctorCommand = DoctorCommand();
final CommandRunner<void>runner = createTestCommandRunner(doctorCommand); final CommandRunner<void>runner = createTestCommandRunner(doctorCommand);
await runner.run(<String>['doctor']); await runner.run(<String>['doctor']);
...@@ -76,15 +76,15 @@ void main() { ...@@ -76,15 +76,15 @@ void main() {
// Ensure we don't send for the 'flutter config' command. // Ensure we don't send for the 'flutter config' command.
testUsingContext("config doesn't send", () async { testUsingContext("config doesn't send", () async {
int count = 0; int count = 0;
flutterUsage.onSend.listen((Map<String, dynamic> data) => count++); globals.flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
flutterUsage.enabled = false; globals.flutterUsage.enabled = false;
final ConfigCommand command = ConfigCommand(); final ConfigCommand command = ConfigCommand();
final CommandRunner<void> runner = createTestCommandRunner(command); final CommandRunner<void> runner = createTestCommandRunner(command);
await runner.run(<String>['config']); await runner.run(<String>['config']);
expect(count, 0); expect(count, 0);
flutterUsage.enabled = true; globals.flutterUsage.enabled = true;
await runner.run(<String>['config']); await runner.run(<String>['config']);
expect(count, 0); expect(count, 0);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
...@@ -282,7 +282,7 @@ void main() { ...@@ -282,7 +282,7 @@ void main() {
testUsingContext("don't send on bots with unknown version", () async { testUsingContext("don't send on bots with unknown version", () async {
int count = 0; int count = 0;
flutterUsage.onSend.listen((Map<String, dynamic> data) => count++); globals.flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
await createTestCommandRunner().run(<String>['--version']); await createTestCommandRunner().run(<String>['--version']);
expect(count, 0); expect(count, 0);
...@@ -297,8 +297,8 @@ void main() { ...@@ -297,8 +297,8 @@ void main() {
testUsingContext("don't send on bots even when opted in", () async { testUsingContext("don't send on bots even when opted in", () async {
int count = 0; int count = 0;
flutterUsage.onSend.listen((Map<String, dynamic> data) => count++); globals.flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
flutterUsage.enabled = true; globals.flutterUsage.enabled = true;
await createTestCommandRunner().run(<String>['--version']); await createTestCommandRunner().run(<String>['--version']);
expect(count, 0); expect(count, 0);
......
...@@ -192,7 +192,7 @@ void main() { ...@@ -192,7 +192,7 @@ void main() {
testUsingContext('analytics sent on success', () async { testUsingContext('analytics sent on success', () async {
MockDirectory.findCache = true; MockDirectory.findCache = true;
await pub.get(context: PubContext.flutterTests, checkLastModified: false); await pub.get(context: PubContext.flutterTests, checkLastModified: false);
verify(flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1); verify(globals.flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MockFileSystem(), FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager(0), ProcessManager: () => MockProcessManager(0),
...@@ -212,7 +212,7 @@ void main() { ...@@ -212,7 +212,7 @@ void main() {
} on ToolExit { } on ToolExit {
// Ignore. // Ignore.
} }
verify(flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'failure')).called(1); verify(globals.flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'failure')).called(1);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MockFileSystem(), FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager(1), ProcessManager: () => MockProcessManager(1),
...@@ -232,7 +232,7 @@ void main() { ...@@ -232,7 +232,7 @@ void main() {
} on ToolExit { } on ToolExit {
// Ignore. // Ignore.
} }
verify(flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'version-solving-failed')).called(1); verify(globals.flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'version-solving-failed')).called(1);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MockFileSystem(), FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager( ProcessManager: () => MockProcessManager(
......
...@@ -223,7 +223,7 @@ void main() { ...@@ -223,7 +223,7 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: false); final OperationResult result = await residentRunner.restart(fullRestart: false);
expect(result.fatal, true); expect(result.fatal, true);
expect(result.code, 1); expect(result.code, 1);
verify(flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{ verify(globals.flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform): cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm), getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example', cdKey(CustomDimensions.hotEventSdkName): 'Example',
...@@ -254,7 +254,7 @@ void main() { ...@@ -254,7 +254,7 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: false); final OperationResult result = await residentRunner.restart(fullRestart: false);
expect(result.fatal, false); expect(result.fatal, false);
expect(result.code, 0); expect(result.code, 0);
expect(verify(flutterUsage.sendEvent('hot', 'reload', expect(verify(globals.flutterUsage.sendEvent('hot', 'reload',
parameters: captureAnyNamed('parameters'))).captured[0], parameters: captureAnyNamed('parameters'))).captured[0],
containsPair(cdKey(CustomDimensions.hotEventTargetPlatform), containsPair(cdKey(CustomDimensions.hotEventTargetPlatform),
getNameForTargetPlatform(TargetPlatform.android_arm)), getNameForTargetPlatform(TargetPlatform.android_arm)),
...@@ -284,7 +284,7 @@ void main() { ...@@ -284,7 +284,7 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: true); final OperationResult result = await residentRunner.restart(fullRestart: true);
expect(result.fatal, false); expect(result.fatal, false);
expect(result.code, 0); expect(result.code, 0);
expect(verify(flutterUsage.sendEvent('hot', 'restart', expect(verify(globals.flutterUsage.sendEvent('hot', 'restart',
parameters: captureAnyNamed('parameters'))).captured[0], parameters: captureAnyNamed('parameters'))).captured[0],
containsPair(cdKey(CustomDimensions.hotEventTargetPlatform), containsPair(cdKey(CustomDimensions.hotEventTargetPlatform),
getNameForTargetPlatform(TargetPlatform.android_arm)), getNameForTargetPlatform(TargetPlatform.android_arm)),
...@@ -328,7 +328,7 @@ void main() { ...@@ -328,7 +328,7 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: true); final OperationResult result = await residentRunner.restart(fullRestart: true);
expect(result.fatal, true); expect(result.fatal, true);
expect(result.code, 1); expect(result.code, 1);
verify(flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{ verify(globals.flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform): cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm), getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example', cdKey(CustomDimensions.hotEventSdkName): 'Example',
......
...@@ -324,7 +324,7 @@ void main() { ...@@ -324,7 +324,7 @@ void main() {
expect(result.code, 0); expect(result.code, 0);
verify(mockResidentCompiler.accept()).called(2); verify(mockResidentCompiler.accept()).called(2);
// ensure that analytics are sent. // ensure that analytics are sent.
final Map<String, String> config = verify(Usage.instance.sendEvent('hot', 'restart', final Map<String, String> config = verify(globals.flutterUsage.sendEvent('hot', 'restart',
parameters: captureAnyNamed('parameters'))).captured.first as Map<String, String>; parameters: captureAnyNamed('parameters'))).captured.first as Map<String, String>;
expect(config, allOf(<Matcher>[ expect(config, allOf(<Matcher>[
...@@ -333,7 +333,7 @@ void main() { ...@@ -333,7 +333,7 @@ void main() {
containsPair('cd29', 'false'), containsPair('cd29', 'false'),
containsPair('cd30', 'true'), containsPair('cd30', 'true'),
])); ]));
verify(Usage.instance.sendTiming('hot', 'web-incremental-restart', any)).called(1); verify(globals.flutterUsage.sendTiming('hot', 'web-incremental-restart', any)).called(1);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockFlutterUsage(), Usage: () => MockFlutterUsage(),
})); }));
...@@ -377,7 +377,7 @@ void main() { ...@@ -377,7 +377,7 @@ void main() {
expect(result.code, 0); expect(result.code, 0);
verify(mockResidentCompiler.accept()).called(2); verify(mockResidentCompiler.accept()).called(2);
// ensure that analytics are sent. // ensure that analytics are sent.
final Map<String, String> config = verify(Usage.instance.sendEvent('hot', 'restart', final Map<String, String> config = verify(globals.flutterUsage.sendEvent('hot', 'restart',
parameters: captureAnyNamed('parameters'))).captured.first as Map<String, String>; parameters: captureAnyNamed('parameters'))).captured.first as Map<String, String>;
expect(config, allOf(<Matcher>[ expect(config, allOf(<Matcher>[
...@@ -386,7 +386,7 @@ void main() { ...@@ -386,7 +386,7 @@ void main() {
containsPair('cd29', 'false'), containsPair('cd29', 'false'),
containsPair('cd30', 'true'), containsPair('cd30', 'true'),
])); ]));
verify(Usage.instance.sendTiming('hot', 'web-incremental-restart', any)).called(1); verify(globals.flutterUsage.sendTiming('hot', 'web-incremental-restart', any)).called(1);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockFlutterUsage(), Usage: () => MockFlutterUsage(),
})); }));
...@@ -422,7 +422,7 @@ void main() { ...@@ -422,7 +422,7 @@ void main() {
expect(result.code, 0); expect(result.code, 0);
verify(mockResidentCompiler.accept()).called(2); verify(mockResidentCompiler.accept()).called(2);
// ensure that analytics are sent. // ensure that analytics are sent.
verifyNever(Usage.instance.sendTiming('hot', 'web-incremental-restart', any)); verifyNever(globals.flutterUsage.sendTiming('hot', 'web-incremental-restart', any));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockFlutterUsage(), Usage: () => MockFlutterUsage(),
})); }));
...@@ -455,7 +455,7 @@ void main() { ...@@ -455,7 +455,7 @@ void main() {
)); ));
expect(await residentWebRunner.run(), 1); expect(await residentWebRunner.run(), 1);
verifyNever(Usage.instance.sendTiming('hot', 'web-restart', any)); verifyNever(globals.flutterUsage.sendTiming('hot', 'web-restart', any));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockFlutterUsage(), Usage: () => MockFlutterUsage(),
})); }));
...@@ -488,7 +488,7 @@ void main() { ...@@ -488,7 +488,7 @@ void main() {
expect(result.code, 1); expect(result.code, 1);
expect(result.message, contains('Failed to recompile application.')); expect(result.message, contains('Failed to recompile application.'));
verifyNever(Usage.instance.sendTiming('hot', 'web-restart', any)); verifyNever(globals.flutterUsage.sendTiming('hot', 'web-restart', any));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockFlutterUsage(), Usage: () => MockFlutterUsage(),
})); }));
......
...@@ -10,6 +10,7 @@ import 'package:flutter_tools/src/base/file_system.dart'; ...@@ -10,6 +10,7 @@ import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart' as io; import 'package:flutter_tools/src/base/io.dart' as io;
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/reporting/github_template.dart'; import 'package:flutter_tools/src/reporting/github_template.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart';
...@@ -67,7 +68,7 @@ void main() { ...@@ -67,7 +68,7 @@ void main() {
// exception on the first attempt, the second attempt tries to report the // exception on the first attempt, the second attempt tries to report the
// *original* crash, and not the crash from the first crash report // *original* crash, and not the crash from the first crash report
// attempt. // attempt.
final CrashingUsage crashingUsage = flutterUsage as CrashingUsage; final CrashingUsage crashingUsage = globals.flutterUsage as CrashingUsage;
expect(crashingUsage.sentException, 'an exception % --'); expect(crashingUsage.sentException, 'an exception % --');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => FakePlatform(environment: <String, String>{ Platform: () => FakePlatform(environment: <String, String>{
......
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