Unverified Commit 9532b91c authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_tools] normalize windows file path cases in flutter validator (#115889)

* normalize windows file path cases in flutter validator

* fix

* make comparison more accurate by checking .startsWith() rather than .contains()

* fix method name

* call path.canonicalize

* fix
parent a9c2f8b9
...@@ -619,7 +619,7 @@ class FlutterValidator extends DoctorValidator { ...@@ -619,7 +619,7 @@ class FlutterValidator extends DoctorValidator {
); );
} }
final String resolvedFlutterPath = flutterBin.resolveSymbolicLinksSync(); final String resolvedFlutterPath = flutterBin.resolveSymbolicLinksSync();
if (!resolvedFlutterPath.contains(flutterRoot)) { if (!_filePathContainsDirPath(flutterRoot, resolvedFlutterPath)) {
final String hint = 'Warning: `$binary` on your path resolves to ' final String hint = 'Warning: `$binary` on your path resolves to '
'$resolvedFlutterPath, which is not inside your current Flutter ' '$resolvedFlutterPath, which is not inside your current Flutter '
'SDK checkout at $flutterRoot. Consider adding $flutterBinDir to ' 'SDK checkout at $flutterRoot. Consider adding $flutterBinDir to '
...@@ -629,6 +629,13 @@ class FlutterValidator extends DoctorValidator { ...@@ -629,6 +629,13 @@ class FlutterValidator extends DoctorValidator {
return null; return null;
} }
bool _filePathContainsDirPath(String directory, String file) {
// calling .canonicalize() will normalize for alphabetic case and path
// separators
return (_fileSystem.path.canonicalize(file))
.startsWith(_fileSystem.path.canonicalize(directory) + _fileSystem.path.separator);
}
ValidationMessage _getFlutterUpstreamMessage(FlutterVersion version) { ValidationMessage _getFlutterUpstreamMessage(FlutterVersion version) {
final String? repositoryUrl = version.repositoryUrl; final String? repositoryUrl = version.repositoryUrl;
final VersionCheckError? upstreamValidationError = VersionUpstreamValidator(version: version, platform: _platform).run(); final VersionCheckError? upstreamValidationError = VersionUpstreamValidator(version: version, platform: _platform).run();
......
...@@ -48,7 +48,7 @@ void main() { ...@@ -48,7 +48,7 @@ void main() {
userMessages: UserMessages(), userMessages: UserMessages(),
artifacts: artifacts, artifacts: artifacts,
fileSystem: fileSystem, fileSystem: fileSystem,
flutterRoot: () => 'sdk/flutter', flutterRoot: () => '/sdk/flutter',
operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'), operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'),
processManager: FakeProcessManager.list(<FakeCommand>[ processManager: FakeProcessManager.list(<FakeCommand>[
const FakeCommand( const FakeCommand(
...@@ -93,7 +93,7 @@ void main() { ...@@ -93,7 +93,7 @@ void main() {
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
operatingSystemUtils: FakeOperatingSystemUtils(name: 'Windows'), operatingSystemUtils: FakeOperatingSystemUtils(name: 'Windows'),
processManager: FakeProcessManager.empty(), processManager: FakeProcessManager.empty(),
flutterRoot: () => 'sdk/flutter', flutterRoot: () => '/sdk/flutter',
); );
// gen_snapshot is downloaded on demand, and the doctor should not // gen_snapshot is downloaded on demand, and the doctor should not
...@@ -115,14 +115,14 @@ void main() { ...@@ -115,14 +115,14 @@ void main() {
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
operatingSystemUtils: FakeOperatingSystemUtils(name: 'Windows'), operatingSystemUtils: FakeOperatingSystemUtils(name: 'Windows'),
processManager: FakeProcessManager.empty(), processManager: FakeProcessManager.empty(),
flutterRoot: () => 'sdk/flutter', flutterRoot: () => '/sdk/flutter',
); );
expect(await flutterValidator.validate(), _matchDoctorValidation( expect(await flutterValidator.validate(), _matchDoctorValidation(
validationType: ValidationType.partial, validationType: ValidationType.partial,
statusInfo: 'Channel beta, 0.0.0, on Windows, locale en_US.UTF-8', statusInfo: 'Channel beta, 0.0.0, on Windows, locale en_US.UTF-8',
messages: containsAll(const <ValidationMessage>[ messages: containsAll(const <ValidationMessage>[
ValidationMessage('Flutter version 0.0.0 on channel beta at sdk/flutter'), ValidationMessage('Flutter version 0.0.0 on channel beta at /sdk/flutter'),
ValidationMessage.error('version error'), ValidationMessage.error('version error'),
]), ]),
)); ));
...@@ -152,7 +152,7 @@ void main() { ...@@ -152,7 +152,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
operatingSystemUtils: FakeOperatingSystemUtils(name: 'Windows'), operatingSystemUtils: FakeOperatingSystemUtils(name: 'Windows'),
flutterRoot: () => 'sdk/flutter' flutterRoot: () => '/sdk/flutter'
); );
expect(await flutterValidator.validate(), _matchDoctorValidation( expect(await flutterValidator.validate(), _matchDoctorValidation(
...@@ -183,7 +183,7 @@ void main() { ...@@ -183,7 +183,7 @@ void main() {
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'), operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'),
flutterRoot: () => 'sdk/flutter', flutterRoot: () => '/sdk/flutter',
); );
expect(await flutterValidator.validate(), _matchDoctorValidation( expect(await flutterValidator.validate(), _matchDoctorValidation(
...@@ -213,7 +213,7 @@ void main() { ...@@ -213,7 +213,7 @@ void main() {
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'), operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'),
flutterRoot: () => 'sdk/flutter', flutterRoot: () => '/sdk/flutter',
); );
expect(await flutterValidator.validate(), _matchDoctorValidation( expect(await flutterValidator.validate(), _matchDoctorValidation(
...@@ -221,7 +221,7 @@ void main() { ...@@ -221,7 +221,7 @@ void main() {
statusInfo: 'Channel unknown, 1.0.0, on Linux, locale en_US.UTF-8', statusInfo: 'Channel unknown, 1.0.0, on Linux, locale en_US.UTF-8',
messages: containsAll(<ValidationMessage>[ messages: containsAll(<ValidationMessage>[
const ValidationMessage.hint( const ValidationMessage.hint(
'Flutter version 1.0.0 on channel unknown at sdk/flutter\n' 'Flutter version 1.0.0 on channel unknown at /sdk/flutter\n'
'Currently on an unknown channel. Run `flutter channel` to switch to an official channel.\n' 'Currently on an unknown channel. Run `flutter channel` to switch to an official channel.\n'
"If that doesn't fix the issue, reinstall Flutter by following instructions at https://flutter.dev/docs/get-started/install." "If that doesn't fix the issue, reinstall Flutter by following instructions at https://flutter.dev/docs/get-started/install."
), ),
...@@ -246,7 +246,7 @@ void main() { ...@@ -246,7 +246,7 @@ void main() {
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'), operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'),
flutterRoot: () => 'sdk/flutter', flutterRoot: () => '/sdk/flutter',
); );
expect(await flutterValidator.validate(), _matchDoctorValidation( expect(await flutterValidator.validate(), _matchDoctorValidation(
...@@ -254,7 +254,7 @@ void main() { ...@@ -254,7 +254,7 @@ void main() {
statusInfo: 'Channel beta, 0.0.0-unknown, on Linux, locale en_US.UTF-8', statusInfo: 'Channel beta, 0.0.0-unknown, on Linux, locale en_US.UTF-8',
messages: containsAll(<ValidationMessage>[ messages: containsAll(<ValidationMessage>[
const ValidationMessage.hint( const ValidationMessage.hint(
'Flutter version 0.0.0-unknown on channel beta at sdk/flutter\n' 'Flutter version 0.0.0-unknown on channel beta at /sdk/flutter\n'
'Cannot resolve current version, possibly due to local changes.\n' 'Cannot resolve current version, possibly due to local changes.\n'
'Reinstall Flutter by following instructions at https://flutter.dev/docs/get-started/install.' 'Reinstall Flutter by following instructions at https://flutter.dev/docs/get-started/install.'
), ),
...@@ -280,7 +280,7 @@ void main() { ...@@ -280,7 +280,7 @@ void main() {
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'), operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'),
flutterRoot: () => 'sdk/flutter', flutterRoot: () => '/sdk/flutter',
); );
expect(await flutterValidator.validate(), _matchDoctorValidation( expect(await flutterValidator.validate(), _matchDoctorValidation(
...@@ -371,7 +371,7 @@ void main() { ...@@ -371,7 +371,7 @@ void main() {
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'), operatingSystemUtils: FakeOperatingSystemUtils(name: 'Linux'),
flutterRoot: () => 'sdk/flutter', flutterRoot: () => '/sdk/flutter',
); );
expect(await flutterValidator.validate(), _matchDoctorValidation( expect(await flutterValidator.validate(), _matchDoctorValidation(
...@@ -387,6 +387,7 @@ void main() { ...@@ -387,6 +387,7 @@ void main() {
}); });
testWithoutContext('detects no flutter and dart on path', () async { testWithoutContext('detects no flutter and dart on path', () async {
const String flutterRoot = 'sdk/flutter';
final FlutterValidator flutterValidator = FlutterValidator( final FlutterValidator flutterValidator = FlutterValidator(
platform: FakePlatform(localeName: 'en_US.UTF-8'), platform: FakePlatform(localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion( flutterVersion: () => FakeFlutterVersion(
...@@ -402,14 +403,96 @@ void main() { ...@@ -402,14 +403,96 @@ void main() {
name: 'Linux', name: 'Linux',
whichLookup: const <String, File>{}, whichLookup: const <String, File>{},
), ),
flutterRoot: () => 'sdk/flutter', flutterRoot: () => flutterRoot,
); );
expect(await flutterValidator.validate(), _matchDoctorValidation( expect(await flutterValidator.validate(), _matchDoctorValidation(
validationType: ValidationType.partial, validationType: ValidationType.partial,
statusInfo: 'Channel beta, 1.0.0, on Linux, locale en_US.UTF-8', statusInfo: 'Channel beta, 1.0.0, on Linux, locale en_US.UTF-8',
messages: contains(const ValidationMessage.hint( messages: contains(const ValidationMessage.hint(
'The flutter binary is not on your path. Consider adding sdk/flutter/bin to your path.', 'The flutter binary is not on your path. Consider adding $flutterRoot/bin to your path.',
)),
));
});
testWithoutContext('allows case differences in paths on Windows', () async {
const String flutterRoot = r'c:\path\to\flutter-sdk';
const String osName = 'Microsoft Windows';
final MemoryFileSystem fs = MemoryFileSystem.test(
style: FileSystemStyle.windows,
);
// The windows' file system is not case sensitive, so changing the case
// here should not matter.
final File flutterBinary = fs.file('${flutterRoot.toUpperCase()}\\bin\\flutter')
..createSync(recursive: true);
final FlutterValidator flutterValidator = FlutterValidator(
platform: FakePlatform(operatingSystem: 'windows', 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.empty(),
operatingSystemUtils: FakeOperatingSystemUtils(
name: osName,
whichLookup: <String, File>{
'flutter': flutterBinary,
},
),
flutterRoot: () => flutterRoot,
);
expect(await flutterValidator.validate(), _matchDoctorValidation(
validationType: ValidationType.partial,
statusInfo: 'Channel beta, 1.0.0, on $osName, locale en_US.UTF-8',
messages: everyElement(isA<ValidationMessage>().having(
(ValidationMessage message) => message.message,
'message',
isNot(contains('Warning: `flutter` on your path resolves to')),
)),
));
});
testWithoutContext('allows different separator types in paths on Windows', () async {
const String flutterRoot = r'c:\path\to\flutter-sdk';
const String osName = 'Microsoft Windows';
final MemoryFileSystem fs = MemoryFileSystem.test(
style: FileSystemStyle.windows,
);
const String filePath = '$flutterRoot\\bin\\flutter';
// force posix style path separators
final File flutterBinary = fs.file(filePath.replaceAll(r'\', '/'))
..createSync(recursive: true);
final FlutterValidator flutterValidator = FlutterValidator(
platform: FakePlatform(operatingSystem: 'windows', 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.empty(),
operatingSystemUtils: FakeOperatingSystemUtils(
name: osName,
whichLookup: <String, File>{
'flutter': flutterBinary,
},
),
flutterRoot: () => flutterRoot,
);
expect(await flutterValidator.validate(), _matchDoctorValidation(
validationType: ValidationType.partial,
statusInfo: 'Channel beta, 1.0.0, on $osName, locale en_US.UTF-8',
messages: everyElement(isA<ValidationMessage>().having(
(ValidationMessage message) => message.message,
'message',
isNot(contains('Warning: `flutter` on your path resolves to')),
)), )),
)); ));
}); });
...@@ -430,20 +513,20 @@ void main() { ...@@ -430,20 +513,20 @@ void main() {
operatingSystemUtils: FakeOperatingSystemUtils( operatingSystemUtils: FakeOperatingSystemUtils(
name: 'Linux', name: 'Linux',
whichLookup: <String, File>{ whichLookup: <String, File>{
'flutter': fs.file('/usr/bin/flutter')..createSync(recursive: true), 'flutter': fs.file('/sdk/flutter-beta')..createSync(recursive: true),
'dart': fs.file('/usr/bin/dart')..createSync(recursive: true), 'dart': fs.file('/sdk/flutter-beta')..createSync(recursive: true),
}, },
), ),
flutterRoot: () => 'sdk/flutter', flutterRoot: () => '/sdk/flutter',
); );
expect(await flutterValidator.validate(), _matchDoctorValidation( expect(await flutterValidator.validate(), _matchDoctorValidation(
validationType: ValidationType.partial, validationType: ValidationType.partial,
statusInfo: 'Channel beta, 1.0.0, on Linux, locale en_US.UTF-8', statusInfo: 'Channel beta, 1.0.0, on Linux, locale en_US.UTF-8',
messages: contains(const ValidationMessage.hint( messages: contains(const ValidationMessage.hint(
'Warning: `flutter` on your path resolves to /usr/bin/flutter, which ' 'Warning: `flutter` on your path resolves to /sdk/flutter-beta, which '
'is not inside your current Flutter SDK checkout at sdk/flutter. ' 'is not inside your current Flutter SDK checkout at /sdk/flutter. '
'Consider adding sdk/flutter/bin to the front of your path.', 'Consider adding /sdk/flutter/bin to the front of your path.',
)), )),
)); ));
}); });
......
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