Skip to content

Commit

Permalink
Suggest Rosetta when x64 binary cannot be run (#114558)
Browse files Browse the repository at this point in the history
* Suggest Rosetta when x64 binary cannot be run

* validator

* Adjust error message
  • Loading branch information
jmagman authored Dec 1, 2022
1 parent 458f129 commit 49f5980
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 4 deletions.
22 changes: 20 additions & 2 deletions packages/flutter_tools/lib/src/base/error_handling_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -581,8 +581,10 @@ Future<T> _run<T>(Future<T> Function() op, {
} on io.ProcessException catch (e) {
if (platform.isWindows) {
_handleWindowsException(e, failureMessage, e.errorCode);
} else if (platform.isLinux || platform.isMacOS) {
} else if (platform.isLinux) {
_handlePosixException(e, failureMessage, e.errorCode, posixPermissionSuggestion);
} if (platform.isMacOS) {
_handleMacOSException(e, failureMessage, e.errorCode, posixPermissionSuggestion);
}
rethrow;
}
Expand Down Expand Up @@ -611,8 +613,10 @@ T _runSync<T>(T Function() op, {
} on io.ProcessException catch (e) {
if (platform.isWindows) {
_handleWindowsException(e, failureMessage, e.errorCode);
} else if (platform.isLinux || platform.isMacOS) {
} else if (platform.isLinux) {
_handlePosixException(e, failureMessage, e.errorCode, posixPermissionSuggestion);
} if (platform.isMacOS) {
_handleMacOSException(e, failureMessage, e.errorCode, posixPermissionSuggestion);
}
rethrow;
}
Expand Down Expand Up @@ -762,6 +766,20 @@ void _handlePosixException(Exception e, String? message, int errorCode, String?
_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) {
// From:
// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes
Expand Down
2 changes: 1 addition & 1 deletion packages/flutter_tools/lib/src/base/user_messages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class UserMessages {
String flutterMirrorURL(String url) => 'Flutter download mirror $url';
String get flutterBinariesDoNotRun =>
'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 =>
'On Debian/Ubuntu/Mint: sudo apt-get install lib32stdc++6\n'
'On Fedora: dnf install libstdc++.i686\n'
Expand Down
3 changes: 3 additions & 0 deletions packages/flutter_tools/lib/src/doctor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,9 @@ class FlutterValidator extends DoctorValidator {
buffer.writeln(_userMessages.flutterBinariesDoNotRun);
if (_platform.isLinux) {
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()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,7 @@ void main() {
group('ProcessManager on macOS throws tool exit', () {
const int enospc = 28;
const int eacces = 13;
const int ebadarch = 86;

testWithoutContext('when writing to a full device', () {
final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
Expand Down Expand Up @@ -1109,6 +1110,28 @@ void main() {

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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void main() {
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'
'See https://github.com/flutter/flutter/issues/6207 for more information.\n'
'On Debian/Ubuntu/Mint: sudo apt-get install lib32stdc++6\n'
'On Fedora: dnf install libstdc++.i686\n'
'On Arch: pacman -S lib32-gcc-libs\n',
Expand All @@ -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 {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(
frameworkVersion: '1.0.0',
Expand Down Expand Up @@ -569,6 +612,7 @@ void main() {
class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils {
FakeOperatingSystemUtils({
required this.name,
this.hostPlatform = HostPlatform.linux_x64,
this.whichLookup,
FileSystem? fs,
}) {
Expand All @@ -587,6 +631,9 @@ class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils {

@override
final String name;

@override
final HostPlatform hostPlatform;
}

class FakeThrowingFlutterVersion extends FakeFlutterVersion {
Expand Down

0 comments on commit 49f5980

Please sign in to comment.