Unverified Commit 37f4f1f2 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Detect ARM ffi CocoaPods error, suggest gem install (#70801)

parent ef474154
......@@ -135,6 +135,7 @@ Future<T> runInContext<T>(
platform: globals.platform,
xcodeProjectInterpreter: globals.xcodeProjectInterpreter,
artifacts: globals.artifacts,
usage: globals.flutterUsage,
),
CocoaPodsValidator: () => CocoaPodsValidator(
globals.cocoaPods,
......
......@@ -12,6 +12,7 @@ import '../base/error_handling_io.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/logger.dart';
import '../base/os.dart';
import '../base/platform.dart';
import '../base/process.dart';
import '../base/version.dart';
......@@ -19,6 +20,7 @@ import '../build_info.dart';
import '../cache.dart';
import '../ios/xcodeproj.dart';
import '../project.dart';
import '../reporting/reporting.dart';
const String noCocoaPodsConsequence = '''
CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin usage on the Dart side.
......@@ -82,23 +84,33 @@ class CocoaPods {
@required Logger logger,
@required Platform platform,
@required Artifacts artifacts,
@required Usage usage,
}) : _fileSystem = fileSystem,
_processManager = processManager,
_xcodeProjectInterpreter = xcodeProjectInterpreter,
_logger = logger,
_platform = platform,
_artifacts = artifacts,
_usage = usage,
_processUtils = ProcessUtils(processManager: processManager, logger: logger),
_fileSystemUtils = FileSystemUtils(fileSystem: fileSystem, platform: platform);
_fileSystemUtils = FileSystemUtils(fileSystem: fileSystem, platform: platform),
_operatingSystemUtils = OperatingSystemUtils(
fileSystem: fileSystem,
logger: logger,
platform: platform,
processManager: processManager,
);
final FileSystem _fileSystem;
final ProcessManager _processManager;
final FileSystemUtils _fileSystemUtils;
final ProcessUtils _processUtils;
final OperatingSystemUtils _operatingSystemUtils;
final XcodeProjectInterpreter _xcodeProjectInterpreter;
final Logger _logger;
final Platform _platform;
final Artifacts _artifacts;
final Usage _usage;
Future<String> _versionText;
......@@ -370,14 +382,31 @@ class CocoaPods {
}
void _diagnosePodInstallFailure(ProcessResult result) {
final dynamic stdout = result.stdout;
if (stdout is String && stdout.contains('out-of-date source repos')) {
if (result.stdout is! String) {
return;
}
final String stdout = result.stdout as String;
if (stdout.contains('out-of-date source repos')) {
_logger.printError(
"Error: CocoaPods's specs repository is too out-of-date to satisfy dependencies.\n"
'To update the CocoaPods specs, run:\n'
' pod repo update\n',
emphasis: true,
);
} else if (stdout.contains('Init_ffi_c') &&
stdout.contains('symbol not found') &&
_operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm) {
// https://github.com/flutter/flutter/issues/70796
UsageEvent(
'pod-install-failure',
'arm-ffi',
flutterUsage: _usage,
).send();
_logger.printError(
'Error: To set up CocoaPods for ARM macOS, run:\n'
' arch -x86_64 sudo gem install ffi\n',
emphasis: true,
);
}
}
......
......@@ -16,6 +16,7 @@ import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/macos/cocoapods.dart';
import 'package:flutter_tools/src/plugins.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
......@@ -32,6 +33,7 @@ void main() {
CocoaPods cocoaPodsUnderTest;
InvokeProcess resultOfPodVersion;
BufferLogger logger;
Usage usage;
void pretendPodVersionFails() {
resultOfPodVersion = () async => exitsWithError();
......@@ -68,15 +70,17 @@ void main() {
projectUnderTest = FlutterProject.fromDirectory(fileSystem.directory('project'));
projectUnderTest.ios.xcodeProject.createSync(recursive: true);
projectUnderTest.macos.xcodeProject.createSync(recursive: true);
usage = Usage.test();
cocoaPodsUnderTest = CocoaPods(
fileSystem: fileSystem,
processManager: mockProcessManager,
logger: logger,
platform: FakePlatform(),
platform: FakePlatform(operatingSystem: 'macos'),
artifacts: Artifacts.test(),
xcodeProjectInterpreter: mockXcodeProjectInterpreter,
usage: usage,
);
pretendPodVersionIs('1.8.0');
pretendPodVersionIs('1.9.0');
fileSystem.file(fileSystem.path.join(
Cache.flutterRoot, 'packages', 'flutter_tools', 'templates', 'cocoapods', 'Podfile-ios-objc',
))
......@@ -450,6 +454,79 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
}
});
testWithoutContext('ffi failure on ARM macOS prompts gem install', () async {
pretendPodIsInstalled();
fileSystem.file(fileSystem.path.join('project', 'ios', 'Podfile'))
..createSync()
..writeAsStringSync('Existing Podfile');
when(mockProcessManager.runSync(<String>['sysctl', 'hw.optional.arm64']))
.thenReturn(ProcessResult(0, 0, 'hw.optional.arm64: 1', ''));
when(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: <String, String>{
'COCOAPODS_DISABLE_STATS': 'true',
'LANG': 'en_US.UTF-8',
},
)).thenAnswer((_) async => exitsWithError(
'LoadError - dlsym(0x7fbbeb6837d0, Init_ffi_c): symbol not found - /Library/Ruby/Gems/2.6.0/gems/ffi-1.13.1/lib/ffi_c.bundle',
));
// Capture Usage.test() events.
final StringBuffer buffer =
await capturedConsolePrint(() => expectToolExitLater(
cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
buildMode: BuildMode.debug,
),
equals('Error running pod install'),
));
expect(
logger.errorText,
contains('set up CocoaPods for ARM macOS'),
);
expect(buffer.toString(),
contains('event {category: pod-install-failure, action: arm-ffi'));
});
testWithoutContext('ffi failure on x86 macOS does not prompt gem install', () async {
pretendPodIsInstalled();
fileSystem.file(fileSystem.path.join('project', 'ios', 'Podfile'))
..createSync()
..writeAsStringSync('Existing Podfile');
when(mockProcessManager.runSync(<String>['sysctl', 'hw.optional.arm64']))
.thenReturn(ProcessResult(0, 1, '', ''));
when(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: <String, String>{
'COCOAPODS_DISABLE_STATS': 'true',
'LANG': 'en_US.UTF-8',
},
)).thenAnswer((_) async => exitsWithError(
'LoadError - dlsym(0x7fbbeb6837d0, Init_ffi_c): symbol not found - /Library/Ruby/Gems/2.6.0/gems/ffi-1.13.1/lib/ffi_c.bundle',
));
// Capture Usage.test() events.
final StringBuffer buffer =
await capturedConsolePrint(() => expectToolExitLater(
cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
buildMode: BuildMode.debug,
),
equals('Error running pod install'),
));
expect(
logger.errorText,
isNot(contains('ARM macOS')),
);
expect(buffer.isEmpty, true);
});
testWithoutContext('run pod install, if Podfile.lock is missing', () async {
pretendPodIsInstalled();
projectUnderTest.ios.podfile
......
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