Suggest Rosetta when x64 binary cannot be run (#114558)
* Suggest Rosetta when x64 binary cannot be run * validator * Adjust error message
This commit is contained in:
parent
458f129b88
commit
49f5980970
@ -581,8 +581,10 @@ Future<T> _run<T>(Future<T> Function() op, {
|
|||||||
} on io.ProcessException catch (e) {
|
} on io.ProcessException catch (e) {
|
||||||
if (platform.isWindows) {
|
if (platform.isWindows) {
|
||||||
_handleWindowsException(e, failureMessage, e.errorCode);
|
_handleWindowsException(e, failureMessage, e.errorCode);
|
||||||
} else if (platform.isLinux || platform.isMacOS) {
|
} else if (platform.isLinux) {
|
||||||
_handlePosixException(e, failureMessage, e.errorCode, posixPermissionSuggestion);
|
_handlePosixException(e, failureMessage, e.errorCode, posixPermissionSuggestion);
|
||||||
|
} if (platform.isMacOS) {
|
||||||
|
_handleMacOSException(e, failureMessage, e.errorCode, posixPermissionSuggestion);
|
||||||
}
|
}
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
@ -611,8 +613,10 @@ T _runSync<T>(T Function() op, {
|
|||||||
} on io.ProcessException catch (e) {
|
} on io.ProcessException catch (e) {
|
||||||
if (platform.isWindows) {
|
if (platform.isWindows) {
|
||||||
_handleWindowsException(e, failureMessage, e.errorCode);
|
_handleWindowsException(e, failureMessage, e.errorCode);
|
||||||
} else if (platform.isLinux || platform.isMacOS) {
|
} else if (platform.isLinux) {
|
||||||
_handlePosixException(e, failureMessage, e.errorCode, posixPermissionSuggestion);
|
_handlePosixException(e, failureMessage, e.errorCode, posixPermissionSuggestion);
|
||||||
|
} if (platform.isMacOS) {
|
||||||
|
_handleMacOSException(e, failureMessage, e.errorCode, posixPermissionSuggestion);
|
||||||
}
|
}
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
@ -762,6 +766,20 @@ void _handlePosixException(Exception e, String? message, int errorCode, String?
|
|||||||
_throwFileSystemException(errorMessage);
|
_throwFileSystemException(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handleMacOSException(Exception e, String? message, int errorCode, String? posixPermissionSuggestion) {
|
||||||
|
// https://github.com/apple/darwin-xnu/blob/master/bsd/dev/dtrace/scripts/errno.d
|
||||||
|
const int ebadarch = 86;
|
||||||
|
if (errorCode == ebadarch) {
|
||||||
|
final StringBuffer errorBuffer = StringBuffer();
|
||||||
|
errorBuffer.writeln(message);
|
||||||
|
errorBuffer.writeln('This binary was built with the incorrect architecture to run on this machine.');
|
||||||
|
errorBuffer.writeln('Flutter requires the Rosetta translation environment. If you are on an ARM Mac, try running:');
|
||||||
|
errorBuffer.writeln(' sudo softwareupdate --install-rosetta --agree-to-license');
|
||||||
|
_throwFileSystemException(errorBuffer.toString());
|
||||||
|
}
|
||||||
|
_handlePosixException(e, message, errorCode, posixPermissionSuggestion);
|
||||||
|
}
|
||||||
|
|
||||||
void _handleWindowsException(Exception e, String? message, int errorCode) {
|
void _handleWindowsException(Exception e, String? message, int errorCode) {
|
||||||
// From:
|
// From:
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes
|
// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes
|
||||||
|
@ -42,7 +42,7 @@ class UserMessages {
|
|||||||
String flutterMirrorURL(String url) => 'Flutter download mirror $url';
|
String flutterMirrorURL(String url) => 'Flutter download mirror $url';
|
||||||
String get flutterBinariesDoNotRun =>
|
String get flutterBinariesDoNotRun =>
|
||||||
'Downloaded executables cannot execute on host.\n'
|
'Downloaded executables cannot execute on host.\n'
|
||||||
'See https://github.com/flutter/flutter/issues/6207 for more information';
|
'See https://github.com/flutter/flutter/issues/6207 for more information.';
|
||||||
String get flutterBinariesLinuxRepairCommands =>
|
String get flutterBinariesLinuxRepairCommands =>
|
||||||
'On Debian/Ubuntu/Mint: sudo apt-get install lib32stdc++6\n'
|
'On Debian/Ubuntu/Mint: sudo apt-get install lib32stdc++6\n'
|
||||||
'On Fedora: dnf install libstdc++.i686\n'
|
'On Fedora: dnf install libstdc++.i686\n'
|
||||||
|
@ -549,6 +549,9 @@ class FlutterValidator extends DoctorValidator {
|
|||||||
buffer.writeln(_userMessages.flutterBinariesDoNotRun);
|
buffer.writeln(_userMessages.flutterBinariesDoNotRun);
|
||||||
if (_platform.isLinux) {
|
if (_platform.isLinux) {
|
||||||
buffer.writeln(_userMessages.flutterBinariesLinuxRepairCommands);
|
buffer.writeln(_userMessages.flutterBinariesLinuxRepairCommands);
|
||||||
|
} else if (_platform.isMacOS && _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm64) {
|
||||||
|
buffer.writeln('Flutter requires the Rosetta translation environment on ARM Macs. Try running:');
|
||||||
|
buffer.writeln(' sudo softwareupdate --install-rosetta --agree-to-license');
|
||||||
}
|
}
|
||||||
messages.add(ValidationMessage.error(buffer.toString()));
|
messages.add(ValidationMessage.error(buffer.toString()));
|
||||||
}
|
}
|
||||||
|
@ -1051,6 +1051,7 @@ void main() {
|
|||||||
group('ProcessManager on macOS throws tool exit', () {
|
group('ProcessManager on macOS throws tool exit', () {
|
||||||
const int enospc = 28;
|
const int enospc = 28;
|
||||||
const int eacces = 13;
|
const int eacces = 13;
|
||||||
|
const int ebadarch = 86;
|
||||||
|
|
||||||
testWithoutContext('when writing to a full device', () {
|
testWithoutContext('when writing to a full device', () {
|
||||||
final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
|
final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
|
||||||
@ -1109,6 +1110,28 @@ void main() {
|
|||||||
|
|
||||||
expect(() async => processManager.canRun('/path/to/dart'), throwsToolExit(message: expectedMessage));
|
expect(() async => processManager.canRun('/path/to/dart'), throwsToolExit(message: expectedMessage));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext('when bad CPU type', () async {
|
||||||
|
final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
|
||||||
|
const FakeCommand(command: <String>['foo'], exception: ProcessException('', <String>[], '', ebadarch)),
|
||||||
|
const FakeCommand(command: <String>['foo'], exception: ProcessException('', <String>[], '', ebadarch)),
|
||||||
|
const FakeCommand(command: <String>['foo'], exception: ProcessException('', <String>[], '', ebadarch)),
|
||||||
|
]);
|
||||||
|
|
||||||
|
final ProcessManager processManager = ErrorHandlingProcessManager(
|
||||||
|
delegate: fakeProcessManager,
|
||||||
|
platform: macOSPlatform,
|
||||||
|
);
|
||||||
|
|
||||||
|
const String expectedMessage = 'Flutter requires the Rosetta translation environment';
|
||||||
|
|
||||||
|
expect(() async => processManager.start(<String>['foo']),
|
||||||
|
throwsToolExit(message: expectedMessage));
|
||||||
|
expect(() async => processManager.run(<String>['foo']),
|
||||||
|
throwsToolExit(message: expectedMessage));
|
||||||
|
expect(() => processManager.runSync(<String>['foo']),
|
||||||
|
throwsToolExit(message: expectedMessage));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('ErrorHandlingProcessManager delegates killPid correctly', () async {
|
testWithoutContext('ErrorHandlingProcessManager delegates killPid correctly', () async {
|
||||||
|
@ -66,7 +66,7 @@ void main() {
|
|||||||
messages: containsAll(const <ValidationMessage>[
|
messages: containsAll(const <ValidationMessage>[
|
||||||
ValidationMessage.error(
|
ValidationMessage.error(
|
||||||
'Downloaded executables cannot execute on host.\n'
|
'Downloaded executables cannot execute on host.\n'
|
||||||
'See https://github.com/flutter/flutter/issues/6207 for more information\n'
|
'See https://github.com/flutter/flutter/issues/6207 for more information.\n'
|
||||||
'On Debian/Ubuntu/Mint: sudo apt-get install lib32stdc++6\n'
|
'On Debian/Ubuntu/Mint: sudo apt-get install lib32stdc++6\n'
|
||||||
'On Fedora: dnf install libstdc++.i686\n'
|
'On Fedora: dnf install libstdc++.i686\n'
|
||||||
'On Arch: pacman -S lib32-gcc-libs\n',
|
'On Arch: pacman -S lib32-gcc-libs\n',
|
||||||
@ -75,6 +75,49 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext('FlutterValidator shows an error message if Rosetta is needed', () async {
|
||||||
|
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(
|
||||||
|
frameworkVersion: '1.0.0',
|
||||||
|
channel: 'beta',
|
||||||
|
);
|
||||||
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final Artifacts artifacts = Artifacts.test();
|
||||||
|
final FlutterValidator flutterValidator = FlutterValidator(
|
||||||
|
platform: FakePlatform(
|
||||||
|
operatingSystem: 'macos',
|
||||||
|
localeName: 'en_US.UTF-8',
|
||||||
|
environment: <String, String>{},
|
||||||
|
),
|
||||||
|
flutterVersion: () => flutterVersion,
|
||||||
|
devToolsVersion: () => '2.8.0',
|
||||||
|
userMessages: UserMessages(),
|
||||||
|
artifacts: artifacts,
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
flutterRoot: () => 'sdk/flutter',
|
||||||
|
operatingSystemUtils: FakeOperatingSystemUtils(name: 'macOS', hostPlatform: HostPlatform.darwin_arm64),
|
||||||
|
processManager: FakeProcessManager.list(<FakeCommand>[
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>['Artifact.genSnapshot'],
|
||||||
|
exitCode: 1,
|
||||||
|
),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
fileSystem.file(artifacts.getArtifactPath(Artifact.genSnapshot)).createSync(recursive: true);
|
||||||
|
|
||||||
|
expect(await flutterValidator.validate(), _matchDoctorValidation(
|
||||||
|
validationType: ValidationType.partial,
|
||||||
|
statusInfo: 'Channel beta, 1.0.0, on macOS, locale en_US.UTF-8',
|
||||||
|
messages: containsAll(const <ValidationMessage>[
|
||||||
|
ValidationMessage.error(
|
||||||
|
'Downloaded executables cannot execute on host.\n'
|
||||||
|
'See https://github.com/flutter/flutter/issues/6207 for more information.\n'
|
||||||
|
'Flutter requires the Rosetta translation environment on ARM Macs. Try running:\n'
|
||||||
|
' sudo softwareupdate --install-rosetta --agree-to-license\n'
|
||||||
|
),
|
||||||
|
])),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
testWithoutContext('FlutterValidator does not run gen_snapshot binary check if it is not already downloaded', () async {
|
testWithoutContext('FlutterValidator does not run gen_snapshot binary check if it is not already downloaded', () async {
|
||||||
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(
|
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(
|
||||||
frameworkVersion: '1.0.0',
|
frameworkVersion: '1.0.0',
|
||||||
@ -569,6 +612,7 @@ void main() {
|
|||||||
class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils {
|
class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils {
|
||||||
FakeOperatingSystemUtils({
|
FakeOperatingSystemUtils({
|
||||||
required this.name,
|
required this.name,
|
||||||
|
this.hostPlatform = HostPlatform.linux_x64,
|
||||||
this.whichLookup,
|
this.whichLookup,
|
||||||
FileSystem? fs,
|
FileSystem? fs,
|
||||||
}) {
|
}) {
|
||||||
@ -587,6 +631,9 @@ class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final HostPlatform hostPlatform;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakeThrowingFlutterVersion extends FakeFlutterVersion {
|
class FakeThrowingFlutterVersion extends FakeFlutterVersion {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user