From d41bb3079695c99b5ec28045ec949d31a7d8e71d Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Fri, 30 Sep 2022 15:06:30 -0700 Subject: [PATCH 1/3] wip --- packages/flutter_tools/lib/src/doctor.dart | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart index 28bc421e84ff5..aece92ca8ab33 100644 --- a/packages/flutter_tools/lib/src/doctor.dart +++ b/packages/flutter_tools/lib/src/doctor.dart @@ -512,7 +512,12 @@ class FlutterValidator extends DoctorValidator { versionChannel = version.channel; frameworkVersion = version.frameworkVersion; - messages.add(_getFlutterVersionMessage(frameworkVersion, versionChannel)); + final String flutterRoot = _flutterRoot(); + messages.add(_getFlutterVersionMessage(frameworkVersion, versionChannel, flutterRoot)); + final ValidationMessage? flutterDartPathWarning = _getFlutterDartOnPathMessage(flutterRoot); + if (flutterDartPathWarning != null) { + messages.add(flutterDartPathWarning); + } messages.add(_getFlutterUpstreamMessage(version)); if (gitUrl != null) { messages.add(ValidationMessage(_userMessages.flutterGitUrl(gitUrl))); @@ -575,8 +580,8 @@ class FlutterValidator extends DoctorValidator { ); } - ValidationMessage _getFlutterVersionMessage(String frameworkVersion, String versionChannel) { - String flutterVersionMessage = _userMessages.flutterVersion(frameworkVersion, versionChannel, _flutterRoot()); + ValidationMessage _getFlutterVersionMessage(String frameworkVersion, String versionChannel, String flutterRoot) { + String flutterVersionMessage = _userMessages.flutterVersion(frameworkVersion, versionChannel, flutterRoot); // The tool sets the channel as "unknown", if the current branch is on a // "detached HEAD" state or doesn't have an upstream, and sets the @@ -594,6 +599,15 @@ class FlutterValidator extends DoctorValidator { return ValidationMessage.hint(flutterVersionMessage); } + // This will return null if `flutter` and `dart` on the PATH point to paths + // within the Flutter SDK. + ValidationMessage? _getFlutterDartOnPathMessage(String flutterRoot) { + final File? dartPath = _operatingSystemUtils.which('dart'); + final File? flutterPath = _operatingSystemUtils.which('flutter'); + print(dartPath); + print(flutterPath); + } + ValidationMessage _getFlutterUpstreamMessage(FlutterVersion version) { final String? repositoryUrl = version.repositoryUrl; final VersionCheckError? upstreamValidationError = VersionUpstreamValidator(version: version, platform: _platform).run(); From 23673d6837722cb2108870fcd2ae79a735f04102 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Tue, 4 Oct 2022 12:07:34 -0700 Subject: [PATCH 2/3] wip --- packages/flutter_tools/lib/src/doctor.dart | 37 +++++++++++++++------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart index aece92ca8ab33..7aa8338805e26 100644 --- a/packages/flutter_tools/lib/src/doctor.dart +++ b/packages/flutter_tools/lib/src/doctor.dart @@ -514,10 +514,8 @@ class FlutterValidator extends DoctorValidator { final String flutterRoot = _flutterRoot(); messages.add(_getFlutterVersionMessage(frameworkVersion, versionChannel, flutterRoot)); - final ValidationMessage? flutterDartPathWarning = _getFlutterDartOnPathMessage(flutterRoot); - if (flutterDartPathWarning != null) { - messages.add(flutterDartPathWarning); - } + + _validateRequiredBinaries(flutterRoot).forEach(messages.add); messages.add(_getFlutterUpstreamMessage(version)); if (gitUrl != null) { messages.add(ValidationMessage(_userMessages.flutterGitUrl(gitUrl))); @@ -599,13 +597,30 @@ class FlutterValidator extends DoctorValidator { return ValidationMessage.hint(flutterVersionMessage); } - // This will return null if `flutter` and `dart` on the PATH point to paths - // within the Flutter SDK. - ValidationMessage? _getFlutterDartOnPathMessage(String flutterRoot) { - final File? dartPath = _operatingSystemUtils.which('dart'); - final File? flutterPath = _operatingSystemUtils.which('flutter'); - print(dartPath); - print(flutterPath); + List _validateRequiredBinaries(String flutterRoot) { + final List warnings = []; + + final String flutterBinDir = _fileSystem.path.join(flutterRoot, 'bin'); + + final File? flutterBin = _operatingSystemUtils.which('flutter'); + if (flutterBin == null) { + warnings.add(ValidationMessage.hint( + 'The flutter binary is not on your path. Consider adding ' + '$flutterBinDir to your path.', + )); + } else { + final String resolvedFlutterPath = flutterBin.resolveSymbolicLinksSync(); + if (!resolvedFlutterPath.contains(flutterRoot)) { + final String hint = 'Warning: `flutter` on your path resolves to ' + '$resolvedFlutterPath, which is not inside your current Flutter ' + 'SDK checkout at $flutterRoot. It is recommended to add ' + '$flutterBinDir to the front of your path.'; + warnings.add(ValidationMessage.hint(hint)); + } + } + + final File? dartBin = _operatingSystemUtils.which('dart'); + return warnings; } ValidationMessage _getFlutterUpstreamMessage(FlutterVersion version) { From bfff41960bcae95a968917887adaa30a9e99ccc4 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Fri, 7 Oct 2022 12:59:09 -0700 Subject: [PATCH 3/3] finish and add tests --- packages/flutter_tools/lib/src/doctor.dart | 40 +++--- .../general.shard/flutter_validator_test.dart | 115 +++++++++++++++++- 2 files changed, 137 insertions(+), 18 deletions(-) diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart index 7aa8338805e26..59250eab2ef21 100644 --- a/packages/flutter_tools/lib/src/doctor.dart +++ b/packages/flutter_tools/lib/src/doctor.dart @@ -598,29 +598,35 @@ class FlutterValidator extends DoctorValidator { } List _validateRequiredBinaries(String flutterRoot) { - final List warnings = []; + final ValidationMessage? flutterWarning = _validateSdkBinary('flutter', flutterRoot); + final ValidationMessage? dartWarning = _validateSdkBinary('dart', flutterRoot); + return [ + if (flutterWarning != null) flutterWarning, + if (dartWarning != null) dartWarning, + ]; + } + /// Return a warning if the provided [binary] on the user's path does not + /// resolve within the Flutter SDK. + ValidationMessage? _validateSdkBinary(String binary, String flutterRoot) { final String flutterBinDir = _fileSystem.path.join(flutterRoot, 'bin'); - final File? flutterBin = _operatingSystemUtils.which('flutter'); + final File? flutterBin = _operatingSystemUtils.which(binary); if (flutterBin == null) { - warnings.add(ValidationMessage.hint( - 'The flutter binary is not on your path. Consider adding ' + return ValidationMessage.hint( + 'The $binary binary is not on your path. Consider adding ' '$flutterBinDir to your path.', - )); - } else { - final String resolvedFlutterPath = flutterBin.resolveSymbolicLinksSync(); - if (!resolvedFlutterPath.contains(flutterRoot)) { - final String hint = 'Warning: `flutter` on your path resolves to ' - '$resolvedFlutterPath, which is not inside your current Flutter ' - 'SDK checkout at $flutterRoot. It is recommended to add ' - '$flutterBinDir to the front of your path.'; - warnings.add(ValidationMessage.hint(hint)); - } + ); } - - final File? dartBin = _operatingSystemUtils.which('dart'); - return warnings; + final String resolvedFlutterPath = flutterBin.resolveSymbolicLinksSync(); + if (!resolvedFlutterPath.contains(flutterRoot)) { + final String hint = 'Warning: `$binary` on your path resolves to ' + '$resolvedFlutterPath, which is not inside your current Flutter ' + 'SDK checkout at $flutterRoot. Consider adding $flutterBinDir to ' + 'the front of your path.'; + return ValidationMessage.hint(hint); + } + return null; } ValidationMessage _getFlutterUpstreamMessage(FlutterVersion version) { diff --git a/packages/flutter_tools/test/general.shard/flutter_validator_test.dart b/packages/flutter_tools/test/general.shard/flutter_validator_test.dart index e18ba7cb1521d..e19c0476984cb 100644 --- a/packages/flutter_tools/test/general.shard/flutter_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/flutter_validator_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/os.dart'; @@ -384,10 +385,122 @@ void main() { ), )); }); + + testWithoutContext('detects no flutter and dart on path', () async { + final FlutterValidator flutterValidator = FlutterValidator( + platform: FakePlatform(localeName: 'en_US.UTF-8'), + flutterVersion: () => FakeFlutterVersion( + frameworkVersion: '1.0.0', + channel: 'beta' + ), + devToolsVersion: () => '2.8.0', + userMessages: UserMessages(), + artifacts: Artifacts.test(), + fileSystem: MemoryFileSystem.test(), + processManager: FakeProcessManager.any(), + operatingSystemUtils: FakeOperatingSystemUtils( + name: 'Linux', + whichLookup: const {}, + ), + flutterRoot: () => 'sdk/flutter', + ); + + expect(await flutterValidator.validate(), _matchDoctorValidation( + validationType: ValidationType.partial, + statusInfo: 'Channel beta, 1.0.0, on Linux, locale en_US.UTF-8', + messages: contains(const ValidationMessage.hint( + 'The flutter binary is not on your path. Consider adding sdk/flutter/bin to your path.', + )), + )); + }); + + testWithoutContext('detects flutter and dart from outside flutter sdk', () async { + final FileSystem fs = MemoryFileSystem.test(); + final FlutterValidator flutterValidator = FlutterValidator( + platform: FakePlatform(localeName: 'en_US.UTF-8'), + flutterVersion: () => FakeFlutterVersion( + frameworkVersion: '1.0.0', + channel: 'beta' + ), + devToolsVersion: () => '2.8.0', + userMessages: UserMessages(), + artifacts: Artifacts.test(), + fileSystem: fs, + processManager: FakeProcessManager.any(), + operatingSystemUtils: FakeOperatingSystemUtils( + name: 'Linux', + whichLookup: { + 'flutter': fs.file('/usr/bin/flutter')..createSync(recursive: true), + 'dart': fs.file('/usr/bin/dart')..createSync(recursive: true), + }, + ), + flutterRoot: () => 'sdk/flutter', + ); + + expect(await flutterValidator.validate(), _matchDoctorValidation( + validationType: ValidationType.partial, + statusInfo: 'Channel beta, 1.0.0, on Linux, locale en_US.UTF-8', + messages: contains(const ValidationMessage.hint( + 'Warning: `flutter` on your path resolves to /usr/bin/flutter, which ' + 'is not inside your current Flutter SDK checkout at sdk/flutter. ' + 'Consider adding sdk/flutter/bin to the front of your path.', + )), + )); + }); + + testWithoutContext('no warnings if flutter & dart binaries are inside the Flutter SDK', () async { + final FileSystem fs = MemoryFileSystem.test(); + final FlutterValidator flutterValidator = FlutterValidator( + platform: FakePlatform(localeName: 'en_US.UTF-8'), + flutterVersion: () => FakeFlutterVersion( + frameworkVersion: '1.0.0', + channel: 'beta' + ), + devToolsVersion: () => '2.8.0', + userMessages: UserMessages(), + artifacts: Artifacts.test(), + fileSystem: fs, + processManager: FakeProcessManager.any(), + operatingSystemUtils: FakeOperatingSystemUtils( + name: 'Linux', + whichLookup: { + 'flutter': fs.file('/sdk/flutter/bin/flutter')..createSync(recursive: true), + 'dart': fs.file('/sdk/flutter/bin/dart')..createSync(recursive: true), + }, + ), + flutterRoot: () => '/sdk/flutter', + ); + + expect(await flutterValidator.validate(), _matchDoctorValidation( + validationType: ValidationType.installed, + statusInfo: 'Channel beta, 1.0.0, on Linux, locale en_US.UTF-8', + messages: isNot(contains(isA().having( + (ValidationMessage message) => message.message, + 'message', + contains('Consider adding /sdk/flutter/bin to the front of your path'), + ))), + )); + }); } class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils { - FakeOperatingSystemUtils({required this.name}); + FakeOperatingSystemUtils({ + required this.name, + this.whichLookup, + FileSystem? fs, + }) { + fs ??= MemoryFileSystem.test(); + whichLookup ??= { + 'flutter': fs.file('/sdk/flutter/bin/flutter')..createSync(recursive: true), + 'dart': fs.file('/sdk/flutter/bin/dart')..createSync(recursive: true), + }; + } + + /// A map of [File]s that calls to [which] will return. + Map? whichLookup; + + @override + File? which(String execName) => whichLookup![execName]; @override final String name;