Improve flutter test startup time (#29404)
diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart index 3fa235f..85b40e8 100644 --- a/packages/flutter_tools/lib/src/commands/test.dart +++ b/packages/flutter_tools/lib/src/commands/test.dart
@@ -10,6 +10,7 @@ import '../base/platform.dart'; import '../cache.dart'; import '../codegen.dart'; +import '../dart/pub.dart'; import '../project.dart'; import '../runner/flutter_command.dart'; import '../test/coverage_collector.dart'; @@ -17,7 +18,7 @@ import '../test/runner.dart'; import '../test/watcher.dart'; -class TestCommand extends FlutterCommand { +class TestCommand extends FastFlutterCommand { TestCommand({ bool verboseHelp = false }) { requiresPubspecYaml(); usesPubOption(); @@ -91,8 +92,7 @@ String get description => 'Run Flutter unit tests for the current project.'; @override - Future<void> validateCommand() async { - await super.validateCommand(); + Future<FlutterCommandResult> runCommand() async { if (!fs.isFileSync('pubspec.yaml')) { throwToolExit( 'Error: No pubspec.yaml file found in the current working directory.\n' @@ -100,10 +100,9 @@ 'called *_test.dart and must reside in the package\'s \'test\' ' 'directory (or one of its subdirectories).'); } - } - - @override - Future<FlutterCommandResult> runCommand() async { + if (shouldRunPub) { + await pubGet(context: PubContext.getVerifyContext(name), skipPubspecYamlCheck: true); + } final List<String> names = argResults['name']; final List<String> plainNames = argResults['plain-name']; final FlutterProject flutterProject = await FlutterProject.current();
diff --git a/packages/flutter_tools/lib/src/dart/pub.dart b/packages/flutter_tools/lib/src/dart/pub.dart index 2f1957b..60bcc8e 100644 --- a/packages/flutter_tools/lib/src/dart/pub.dart +++ b/packages/flutter_tools/lib/src/dart/pub.dart
@@ -76,13 +76,14 @@ bool upgrade = false, bool offline = false, bool checkLastModified = true, + bool skipPubspecYamlCheck = false }) async { directory ??= fs.currentDirectory.path; final File pubSpecYaml = fs.file(fs.path.join(directory, 'pubspec.yaml')); final File dotPackages = fs.file(fs.path.join(directory, '.packages')); - if (!pubSpecYaml.existsSync()) { + if (!skipPubspecYamlCheck && !pubSpecYaml.existsSync()) { if (!skipIfAbsent) throwToolExit('$directory: no pubspec.yaml found'); return;
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 2d93bfb..4c80af5 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -662,3 +662,15 @@ ApplicationPackageStore applicationPackages; } + +/// A command which runs less analytics and checks to speed up startup time. +abstract class FastFlutterCommand extends FlutterCommand { + @override + Future<void> run() { + return context.run<void>( + name: 'command', + overrides: <Type, Generator>{FlutterCommand: () => this}, + body: runCommand, + ); + } +}
diff --git a/packages/flutter_tools/lib/src/test/flutter_platform.dart b/packages/flutter_tools/lib/src/test/flutter_platform.dart index 22aa734..d265aac 100644 --- a/packages/flutter_tools/lib/src/test/flutter_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_platform.dart
@@ -275,6 +275,7 @@ flutterProject: flutterProject, trackWidgetCreation: trackWidgetCreation, compilerMessageConsumer: reportCompilerMessage, + initializeFromDill: testFilePath, // We already ran codegen once at the start, we only need to // configure builders. runCold: true,
diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart index e1b9923..3df1df0 100644 --- a/packages/flutter_tools/lib/src/version.dart +++ b/packages/flutter_tools/lib/src/version.dart
@@ -20,28 +20,17 @@ class FlutterVersion { @visibleForTesting FlutterVersion([this._clock = const SystemClock()]) { - _channel = _runGit('git rev-parse --abbrev-ref --symbolic @{u}'); - final String branch = _runGit('git rev-parse --abbrev-ref HEAD'); - _branch = branch == 'HEAD' ? _channel : branch; - - final int slash = _channel.indexOf('/'); - if (slash != -1) { - final String remote = _channel.substring(0, slash); - _repositoryUrl = _runGit('git ls-remote --get-url $remote'); - _channel = _channel.substring(slash + 1); - } else if (_channel.isEmpty) { - _channel = 'unknown'; - } - _frameworkRevision = _runGit('git log -n 1 --pretty=format:%H'); - _frameworkAge = _runGit('git log -n 1 --pretty=format:%ar'); _frameworkVersion = GitTagVersion.determine().frameworkVersionFor(_frameworkRevision); } final SystemClock _clock; String _repositoryUrl; - String get repositoryUrl => _repositoryUrl; + String get repositoryUrl { + final String _ = channel; + return _repositoryUrl; + } static const Set<String> officialChannels = <String>{ 'master', @@ -64,7 +53,22 @@ String _channel; /// The channel is the upstream branch. /// `master`, `dev`, `beta`, `stable`; or old ones, like `alpha`, `hackathon`, ... - String get channel => _channel; + String get channel { + if (_channel == null) { + final String channel = _runGit('git rev-parse --abbrev-ref --symbolic @{u}'); + final int slash = channel.indexOf('/'); + if (slash != -1) { + final String remote = channel.substring(0, slash); + _repositoryUrl = _runGit('git ls-remote --get-url $remote'); + _channel = channel.substring(slash + 1); + } else if (channel.isEmpty) { + _channel = 'unknown'; + } else { + _channel = channel; + } + } + return _channel; + } /// The name of the local branch. /// Use getBranchName() to read this. @@ -75,7 +79,9 @@ String get frameworkRevisionShort => _shortGitRevision(frameworkRevision); String _frameworkAge; - String get frameworkAge => _frameworkAge; + String get frameworkAge { + return _frameworkAge ??= _runGit('git log -n 1 --pretty=format:%ar'); + } String _frameworkVersion; String get frameworkVersion => _frameworkVersion; @@ -182,6 +188,10 @@ /// If [redactUnknownBranches] is true and the branch is unknown, /// the branch name will be returned as `'[user-branch]'`. String getBranchName({ bool redactUnknownBranches = false }) { + _branch ??= () { + final String branch = _runGit('git rev-parse --abbrev-ref HEAD'); + return branch == 'HEAD' ? channel : branch; + }(); if (redactUnknownBranches || _branch.isEmpty) { // Only return the branch names we know about; arbitrary branch names might contain PII. if (!officialChannels.contains(_branch) && !obsoleteBranches.containsKey(_branch)) @@ -266,7 +276,7 @@ /// writes shared cache files. Future<void> checkFlutterVersionFreshness() async { // Don't perform update checks if we're not on an official channel. - if (!officialChannels.contains(_channel)) { + if (!officialChannels.contains(channel)) { return; } @@ -359,7 +369,7 @@ // Cache is empty or it's been a while since the last server ping. Ping the server. try { - final DateTime remoteFrameworkCommitDate = DateTime.parse(await FlutterVersion.fetchRemoteFrameworkCommitDate(_channel)); + final DateTime remoteFrameworkCommitDate = DateTime.parse(await FlutterVersion.fetchRemoteFrameworkCommitDate(channel)); await versionCheckStamp.store( newTimeVersionWasChecked: _clock.now(), newKnownRemoteVersion: remoteFrameworkCommitDate,