Unverified Commit 23a3d101 authored by Zachary Anderson's avatar Zachary Anderson Committed by GitHub

[flutter_tool] Make BotDetector context free (#48605)

parent 6a5964d8
...@@ -9,6 +9,7 @@ import 'package:intl/intl.dart' as intl; ...@@ -9,6 +9,7 @@ import 'package:intl/intl.dart' as intl;
import 'package:intl/intl_standalone.dart' as intl_standalone; import 'package:intl/intl_standalone.dart' as intl_standalone;
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'src/base/bot_detector.dart';
import 'src/base/common.dart'; import 'src/base/common.dart';
import 'src/base/context.dart'; import 'src/base/context.dart';
import 'src/base/file_system.dart'; import 'src/base/file_system.dart';
...@@ -19,7 +20,7 @@ import 'src/base/terminal.dart'; ...@@ -19,7 +20,7 @@ import 'src/base/terminal.dart';
import 'src/base/utils.dart'; import 'src/base/utils.dart';
import 'src/context_runner.dart'; import 'src/context_runner.dart';
import 'src/doctor.dart'; import 'src/doctor.dart';
import 'src/globals.dart'; import 'src/globals.dart' as globals;
import 'src/reporting/github_template.dart'; import 'src/reporting/github_template.dart';
import 'src/reporting/reporting.dart'; import 'src/reporting/reporting.dart';
import 'src/runner/flutter_command.dart'; import 'src/runner/flutter_command.dart';
...@@ -37,7 +38,7 @@ Future<int> run( ...@@ -37,7 +38,7 @@ Future<int> run(
String flutterVersion, String flutterVersion,
Map<Type, Generator> overrides, Map<Type, Generator> overrides,
}) { }) {
reportCrashes ??= !isRunningOnBot; reportCrashes ??= !isRunningOnBot(globals.platform);
if (muteCommandLogging) { if (muteCommandLogging) {
// Remove the verbose option; for help and doctor, users don't need to see // Remove the verbose option; for help and doctor, users don't need to see
...@@ -90,16 +91,16 @@ Future<int> _handleToolError( ...@@ -90,16 +91,16 @@ Future<int> _handleToolError(
String getFlutterVersion(), String getFlutterVersion(),
) async { ) async {
if (error is UsageException) { if (error is UsageException) {
printError('${error.message}\n'); globals.printError('${error.message}\n');
printError("Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and options."); globals.printError("Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and options.");
// Argument error exit code. // Argument error exit code.
return _exit(64); return _exit(64);
} else if (error is ToolExit) { } else if (error is ToolExit) {
if (error.message != null) { if (error.message != null) {
printError(error.message); globals.printError(error.message);
} }
if (verbose) { if (verbose) {
printError('\n$stackTrace\n'); globals.printError('\n$stackTrace\n');
} }
return _exit(error.exitCode ?? 1); return _exit(error.exitCode ?? 1);
} else if (error is ProcessExit) { } else if (error is ProcessExit) {
...@@ -131,7 +132,7 @@ Future<int> _handleToolError( ...@@ -131,7 +132,7 @@ Future<int> _handleToolError(
); );
final String errorString = error.toString(); final String errorString = error.toString();
printError('Oops; flutter has exited unexpectedly: "$errorString".'); globals.printError('Oops; flutter has exited unexpectedly: "$errorString".');
try { try {
await _informUserOfCrash(args, error, stackTrace, errorString); await _informUserOfCrash(args, error, stackTrace, errorString);
...@@ -155,15 +156,15 @@ Future<void> _informUserOfCrash(List<String> args, dynamic error, StackTrace sta ...@@ -155,15 +156,15 @@ Future<void> _informUserOfCrash(List<String> args, dynamic error, StackTrace sta
final String doctorText = await _doctorText(); final String doctorText = await _doctorText();
final File file = await _createLocalCrashReport(args, error, stackTrace, doctorText); final File file = await _createLocalCrashReport(args, error, stackTrace, doctorText);
printError('A crash report has been written to ${file.path}.'); globals.printError('A crash report has been written to ${file.path}.');
printStatus('This crash may already be reported. Check GitHub for similar crashes.', emphasis: true); globals.printStatus('This crash may already be reported. Check GitHub for similar crashes.', emphasis: true);
final GitHubTemplateCreator gitHubTemplateCreator = context.get<GitHubTemplateCreator>() ?? GitHubTemplateCreator(); final GitHubTemplateCreator gitHubTemplateCreator = context.get<GitHubTemplateCreator>() ?? GitHubTemplateCreator();
final String similarIssuesURL = await gitHubTemplateCreator.toolCrashSimilarIssuesGitHubURL(errorString); final String similarIssuesURL = await gitHubTemplateCreator.toolCrashSimilarIssuesGitHubURL(errorString);
printStatus('$similarIssuesURL\n', wrap: false); globals.printStatus('$similarIssuesURL\n', wrap: false);
printStatus('To report your crash to the Flutter team, first read the guide to filing a bug.', emphasis: true); globals.printStatus('To report your crash to the Flutter team, first read the guide to filing a bug.', emphasis: true);
printStatus('https://flutter.dev/docs/resources/bug-reports\n', wrap: false); globals.printStatus('https://flutter.dev/docs/resources/bug-reports\n', wrap: false);
printStatus('Create a new GitHub issue by pasting this link into your browser and completing the issue template. Thank you!', emphasis: true); globals.printStatus('Create a new GitHub issue by pasting this link into your browser and completing the issue template. Thank you!', emphasis: true);
final String command = _crashCommand(args); final String command = _crashCommand(args);
final String gitHubTemplateURL = await gitHubTemplateCreator.toolCrashIssueTemplateGitHubURL( final String gitHubTemplateURL = await gitHubTemplateCreator.toolCrashIssueTemplateGitHubURL(
...@@ -173,7 +174,7 @@ Future<void> _informUserOfCrash(List<String> args, dynamic error, StackTrace sta ...@@ -173,7 +174,7 @@ Future<void> _informUserOfCrash(List<String> args, dynamic error, StackTrace sta
stackTrace, stackTrace,
doctorText doctorText
); );
printStatus('$gitHubTemplateURL\n', wrap: false); globals.printStatus('$gitHubTemplateURL\n', wrap: false);
} }
String _crashCommand(List<String> args) => 'flutter ${args.join(' ')}'; String _crashCommand(List<String> args) => 'flutter ${args.join(' ')}';
...@@ -214,8 +215,8 @@ Future<File> _createLocalCrashReport(List<String> args, dynamic error, StackTrac ...@@ -214,8 +215,8 @@ Future<File> _createLocalCrashReport(List<String> args, dynamic error, StackTrac
try { try {
crashFile.writeAsStringSync(buffer.toString()); crashFile.writeAsStringSync(buffer.toString());
} on FileSystemException catch (e) { } on FileSystemException catch (e) {
printError('Could not write crash report to disk: $e'); globals.printError('Could not write crash report to disk: $e');
printError(buffer.toString()); globals.printError(buffer.toString());
} }
} }
...@@ -225,7 +226,7 @@ Future<File> _createLocalCrashReport(List<String> args, dynamic error, StackTrac ...@@ -225,7 +226,7 @@ Future<File> _createLocalCrashReport(List<String> args, dynamic error, StackTrac
Future<String> _doctorText() async { Future<String> _doctorText() async {
try { try {
final BufferLogger logger = BufferLogger( final BufferLogger logger = BufferLogger(
terminal: terminal, terminal: globals.terminal,
outputPreferences: outputPreferences, outputPreferences: outputPreferences,
); );
...@@ -251,7 +252,7 @@ Future<int> _exit(int code) async { ...@@ -251,7 +252,7 @@ Future<int> _exit(int code) async {
if (flutterUsage.enabled) { if (flutterUsage.enabled) {
final Stopwatch stopwatch = Stopwatch()..start(); final Stopwatch stopwatch = Stopwatch()..start();
await flutterUsage.ensureAnalyticsSent(); await flutterUsage.ensureAnalyticsSent();
printTrace('ensureAnalyticsSent: ${stopwatch.elapsedMilliseconds}ms'); globals.printTrace('ensureAnalyticsSent: ${stopwatch.elapsedMilliseconds}ms');
} }
// Run shutdown hooks before flushing logs // Run shutdown hooks before flushing logs
...@@ -262,7 +263,7 @@ Future<int> _exit(int code) async { ...@@ -262,7 +263,7 @@ Future<int> _exit(int code) async {
// Give the task / timer queue one cycle through before we hard exit. // Give the task / timer queue one cycle through before we hard exit.
Timer.run(() { Timer.run(() {
try { try {
printTrace('exiting with code $code'); globals.printTrace('exiting with code $code');
exit(code); exit(code);
completer.complete(); completer.complete();
} catch (error, stackTrace) { } catch (error, stackTrace) {
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:meta/meta.dart';
import 'package:platform/platform.dart';
import 'context.dart';
class BotDetector {
BotDetector({
@required Platform platform,
}) : _platform = platform;
final Platform _platform;
bool get isRunningOnBot {
if (
// Explicitly stated to not be a bot.
_platform.environment['BOT'] == 'false'
// Set by the IDEs to the IDE name, so a strong signal that this is not a bot.
|| _platform.environment.containsKey('FLUTTER_HOST')
// When set, GA logs to a local file (normally for tests) so we don't need to filter.
|| _platform.environment.containsKey('FLUTTER_ANALYTICS_LOG_FILE')
) {
return false;
}
return _platform.environment['BOT'] == 'true'
// https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
|| _platform.environment['TRAVIS'] == 'true'
|| _platform.environment['CONTINUOUS_INTEGRATION'] == 'true'
|| _platform.environment.containsKey('CI') // Travis and AppVeyor
// https://www.appveyor.com/docs/environment-variables/
|| _platform.environment.containsKey('APPVEYOR')
// https://cirrus-ci.org/guide/writing-tasks/#environment-variables
|| _platform.environment.containsKey('CIRRUS_CI')
// https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
|| (_platform.environment.containsKey('AWS_REGION') &&
_platform.environment.containsKey('CODEBUILD_INITIATOR'))
// https://wiki.jenkins.io/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-belowJenkinsSetEnvironmentVariables
|| _platform.environment.containsKey('JENKINS_URL')
// Properties on Flutter's Chrome Infra bots.
|| _platform.environment['CHROME_HEADLESS'] == '1'
|| _platform.environment.containsKey('BUILDBOT_BUILDERNAME')
|| _platform.environment.containsKey('SWARMING_TASK_ID');
}
}
bool isRunningOnBot(Platform platform) {
final BotDetector botDetector = context.get<BotDetector>() ?? BotDetector(platform: platform);
return botDetector.isRunningOnBot;
}
...@@ -10,61 +10,10 @@ import 'package:meta/meta.dart'; ...@@ -10,61 +10,10 @@ import 'package:meta/meta.dart';
import '../convert.dart'; import '../convert.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import 'context.dart';
import 'file_system.dart'; import 'file_system.dart';
import 'io.dart' as io; import 'io.dart' as io;
import 'terminal.dart'; import 'terminal.dart';
const BotDetector _kBotDetector = BotDetector();
class BotDetector {
const BotDetector();
bool get isRunningOnBot {
if (
// Explicitly stated to not be a bot.
globals.platform.environment['BOT'] == 'false'
// Set by the IDEs to the IDE name, so a strong signal that this is not a bot.
|| globals.platform.environment.containsKey('FLUTTER_HOST')
// When set, GA logs to a local file (normally for tests) so we don't need to filter.
|| globals.platform.environment.containsKey('FLUTTER_ANALYTICS_LOG_FILE')
) {
return false;
}
return globals.platform.environment['BOT'] == 'true'
// https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
|| globals.platform.environment['TRAVIS'] == 'true'
|| globals.platform.environment['CONTINUOUS_INTEGRATION'] == 'true'
|| globals.platform.environment.containsKey('CI') // Travis and AppVeyor
// https://www.appveyor.com/docs/environment-variables/
|| globals.platform.environment.containsKey('APPVEYOR')
// https://cirrus-ci.org/guide/writing-tasks/#environment-variables
|| globals.platform.environment.containsKey('CIRRUS_CI')
// https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
|| (globals.platform.environment.containsKey('AWS_REGION') &&
globals.platform.environment.containsKey('CODEBUILD_INITIATOR'))
// https://wiki.jenkins.io/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-belowJenkinsSetEnvironmentVariables
|| globals.platform.environment.containsKey('JENKINS_URL')
// Properties on Flutter's Chrome Infra bots.
|| globals.platform.environment['CHROME_HEADLESS'] == '1'
|| globals.platform.environment.containsKey('BUILDBOT_BUILDERNAME')
|| globals.platform.environment.containsKey('SWARMING_TASK_ID');
}
}
bool get isRunningOnBot {
final BotDetector botDetector = context.get<BotDetector>() ?? _kBotDetector;
return botDetector.isRunningOnBot;
}
/// Convert `foo_bar` to `fooBar`. /// Convert `foo_bar` to `fooBar`.
String camelCase(String str) { String camelCase(String str) {
int index = str.indexOf('_'); int index = str.indexOf('_');
......
...@@ -22,7 +22,6 @@ import 'base/signals.dart'; ...@@ -22,7 +22,6 @@ import 'base/signals.dart';
import 'base/terminal.dart'; import 'base/terminal.dart';
import 'base/time.dart'; import 'base/time.dart';
import 'base/user_messages.dart'; import 'base/user_messages.dart';
import 'base/utils.dart';
import 'build_system/build_system.dart'; import 'build_system/build_system.dart';
import 'cache.dart'; import 'cache.dart';
import 'compile.dart'; import 'compile.dart';
...@@ -75,7 +74,6 @@ Future<T> runInContext<T>( ...@@ -75,7 +74,6 @@ Future<T> runInContext<T>(
ApplicationPackageFactory: () => ApplicationPackageFactory(), ApplicationPackageFactory: () => ApplicationPackageFactory(),
Artifacts: () => CachedArtifacts(), Artifacts: () => CachedArtifacts(),
AssetBundleFactory: () => AssetBundleFactory.defaultInstance, AssetBundleFactory: () => AssetBundleFactory.defaultInstance,
BotDetector: () => const BotDetector(),
BuildSystem: () => const BuildSystem(), BuildSystem: () => const BuildSystem(),
Cache: () => Cache(), Cache: () => Cache(),
ChromeLauncher: () => const ChromeLauncher(), ChromeLauncher: () => const ChromeLauncher(),
......
...@@ -6,13 +6,13 @@ import 'dart:async'; ...@@ -6,13 +6,13 @@ import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../base/bot_detector.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/context.dart'; import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart' as io; import '../base/io.dart' as io;
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../base/utils.dart';
import '../cache.dart'; import '../cache.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
...@@ -232,7 +232,7 @@ class _DefaultPub implements Pub { ...@@ -232,7 +232,7 @@ class _DefaultPub implements Pub {
@required bool retry, @required bool retry,
bool showTraceForErrors, bool showTraceForErrors,
}) async { }) async {
showTraceForErrors ??= isRunningOnBot; showTraceForErrors ??= isRunningOnBot(globals.platform);
String lastPubMessage = 'no message'; String lastPubMessage = 'no message';
bool versionSolvingFailed = false; bool versionSolvingFailed = false;
...@@ -368,7 +368,7 @@ String _getPubEnvironmentValue(PubContext pubContext) { ...@@ -368,7 +368,7 @@ String _getPubEnvironmentValue(PubContext pubContext) {
final String existing = globals.platform.environment[_pubEnvironmentKey]; final String existing = globals.platform.environment[_pubEnvironmentKey];
final List<String> values = <String>[ final List<String> values = <String>[
if (existing != null && existing.isNotEmpty) existing, if (existing != null && existing.isNotEmpty) existing,
if (isRunningOnBot) 'flutter_bot', if (isRunningOnBot(globals.platform)) 'flutter_bot',
'flutter_cli', 'flutter_cli',
...pubContext._values, ...pubContext._values,
]; ];
......
...@@ -10,12 +10,12 @@ import 'package:http/http.dart' as http; ...@@ -10,12 +10,12 @@ 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/bot_detector.dart';
import '../base/context.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/os.dart'; import '../base/os.dart';
import '../base/time.dart'; import '../base/time.dart';
import '../base/utils.dart';
import '../doctor.dart'; import '../doctor.dart';
import '../features.dart'; import '../features.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
......
...@@ -176,7 +176,7 @@ class _DefaultUsage implements Usage { ...@@ -176,7 +176,7 @@ class _DefaultUsage implements Usage {
// Many CI systems don't do a full git checkout. // Many CI systems don't do a full git checkout.
version.endsWith('/unknown') || version.endsWith('/unknown') ||
// Ignore bots. // Ignore bots.
isRunningOnBot || isRunningOnBot(globals.platform) ||
// Ignore when suppressed by FLUTTER_SUPPRESS_ANALYTICS. // Ignore when suppressed by FLUTTER_SUPPRESS_ANALYTICS.
suppressEnvFlag suppressEnvFlag
)) { )) {
......
...@@ -5,9 +5,9 @@ ...@@ -5,9 +5,9 @@
import 'dart:async'; import 'dart:async';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:flutter_tools/src/base/bot_detector.dart';
import 'package:flutter_tools/src/base/file_system.dart' hide IOSink; import 'package:flutter_tools/src/base/file_system.dart' hide IOSink;
import 'package:flutter_tools/src/base/io.dart'; 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/cache.dart';
import 'package:flutter_tools/src/commands/packages.dart'; import 'package:flutter_tools/src/commands/packages.dart';
import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/dart/pub.dart';
......
...@@ -2,13 +2,10 @@ ...@@ -2,13 +2,10 @@
// 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 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/bot_detector.dart';
import 'package:flutter_tools/src/base/utils.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart'; import '../../src/mocks.dart';
void main() { void main() {
...@@ -20,45 +17,33 @@ void main() { ...@@ -20,45 +17,33 @@ void main() {
setUp(() { setUp(() {
fakePlatform = FakePlatform()..environment = <String, String>{}; fakePlatform = FakePlatform()..environment = <String, String>{};
mockStdio = MockStdio(); mockStdio = MockStdio();
botDetector = const BotDetector(); botDetector = BotDetector(platform: fakePlatform);
}); });
group('isRunningOnBot', () { group('isRunningOnBot', () {
testUsingContext('returns false unconditionally if BOT=false is set', () async { testWithoutContext('returns false unconditionally if BOT=false is set', () async {
fakePlatform.environment['BOT'] = 'false'; fakePlatform.environment['BOT'] = 'false';
fakePlatform.environment['TRAVIS'] = 'true'; fakePlatform.environment['TRAVIS'] = 'true';
expect(botDetector.isRunningOnBot, isFalse); expect(botDetector.isRunningOnBot, isFalse);
}, overrides: <Type, Generator>{
Stdio: () => mockStdio,
Platform: () => fakePlatform,
}); });
testUsingContext('returns false unconditionally if FLUTTER_HOST is set', () async { testWithoutContext('returns false unconditionally if FLUTTER_HOST is set', () async {
fakePlatform.environment['FLUTTER_HOST'] = 'foo'; fakePlatform.environment['FLUTTER_HOST'] = 'foo';
fakePlatform.environment['TRAVIS'] = 'true'; fakePlatform.environment['TRAVIS'] = 'true';
expect(botDetector.isRunningOnBot, isFalse); expect(botDetector.isRunningOnBot, isFalse);
}, overrides: <Type, Generator>{
Stdio: () => mockStdio,
Platform: () => fakePlatform,
}); });
testUsingContext('returns false with and without a terminal attached', () async { testWithoutContext('returns false with and without a terminal attached', () async {
mockStdio.stdout.hasTerminal = true; mockStdio.stdout.hasTerminal = true;
expect(botDetector.isRunningOnBot, isFalse); expect(botDetector.isRunningOnBot, isFalse);
mockStdio.stdout.hasTerminal = false; mockStdio.stdout.hasTerminal = false;
expect(botDetector.isRunningOnBot, isFalse); expect(botDetector.isRunningOnBot, isFalse);
}, overrides: <Type, Generator>{
Stdio: () => mockStdio,
Platform: () => fakePlatform,
}); });
testUsingContext('can test analytics outputs on bots when outputting to a file', () async { testWithoutContext('can test analytics outputs on bots when outputting to a file', () async {
fakePlatform.environment['TRAVIS'] = 'true'; fakePlatform.environment['TRAVIS'] = 'true';
fakePlatform.environment['FLUTTER_ANALYTICS_LOG_FILE'] = '/some/file'; fakePlatform.environment['FLUTTER_ANALYTICS_LOG_FILE'] = '/some/file';
expect(botDetector.isRunningOnBot, isFalse); expect(botDetector.isRunningOnBot, isFalse);
}, overrides: <Type, Generator>{
Stdio: () => mockStdio,
Platform: () => fakePlatform,
}); });
}); });
}); });
......
...@@ -7,11 +7,11 @@ import 'dart:collection'; ...@@ -7,11 +7,11 @@ import 'dart:collection';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/bot_detector.dart';
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/context.dart'; import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart'; 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/cache.dart';
import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/dart/pub.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.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