Unverified Commit c64ace84 authored by Mikkel Nygaard Ravn's avatar Mikkel Nygaard Ravn Committed by GitHub

Recommend upgrading to Cocoapods 1.5.0 (#17210)

parent 7984f6e0
...@@ -52,7 +52,7 @@ Future<T> runInContext<T>( ...@@ -52,7 +52,7 @@ Future<T> runInContext<T>(
BotDetector: () => const BotDetector(), BotDetector: () => const BotDetector(),
Cache: () => new Cache(), Cache: () => new Cache(),
Clock: () => const Clock(), Clock: () => const Clock(),
CocoaPods: () => const CocoaPods(), CocoaPods: () => new CocoaPods(),
Config: () => new Config(), Config: () => new Config(),
DevFSConfig: () => new DevFSConfig(), DevFSConfig: () => new DevFSConfig(),
DeviceManager: () => new DeviceManager(), DeviceManager: () => new DeviceManager(),
......
...@@ -33,25 +33,46 @@ const String cocoaPodsUpgradeInstructions = ''' ...@@ -33,25 +33,46 @@ const String cocoaPodsUpgradeInstructions = '''
CocoaPods get cocoaPods => context[CocoaPods]; CocoaPods get cocoaPods => context[CocoaPods];
class CocoaPods { /// Result of evaluating the CocoaPods installation.
const CocoaPods(); enum CocoaPodsStatus {
/// iOS plugins will not work, installation required.
notInstalled,
/// iOS plugins will not work, upgrade required.
belowMinimumVersion,
/// iOS plugins may not work in certain situations (Swift, static libraries),
/// upgrade recommended.
belowRecommendedVersion,
/// Everything should be fine.
recommended,
}
Future<bool> get hasCocoaPods => exitsHappyAsync(<String>['pod', '--version']); class CocoaPods {
Future<String> _versionText;
// TODO(mravn): Insist on 1.5.0 once build bots have that installed.
// Earlier versions do not work with Swift and static libraries.
String get cocoaPodsMinimumVersion => '1.0.0'; String get cocoaPodsMinimumVersion => '1.0.0';
String get cocoaPodsRecommendedVersion => '1.5.0';
Future<String> get cocoaPodsVersionText async => (await runAsync(<String>['pod', '--version'])).processResult.stdout.trim(); Future<String> get cocoaPodsVersionText {
_versionText ??= runAsync(<String>['pod', '--version']).then<String>((RunResult result) {
return result.exitCode == 0 ? result.stdout.trim() : null;
});
return _versionText;
}
Future<bool> get isCocoaPodsInstalledAndMeetsVersionCheck async { Future<CocoaPodsStatus> get evaluateCocoaPodsInstallation async {
if (!await hasCocoaPods) final String versionText = await cocoaPodsVersionText;
return false; if (versionText == null)
return CocoaPodsStatus.notInstalled;
try { try {
final Version installedVersion = new Version.parse(await cocoaPodsVersionText); final Version installedVersion = new Version.parse(versionText);
return installedVersion >= new Version.parse(cocoaPodsMinimumVersion); if (installedVersion < new Version.parse(cocoaPodsMinimumVersion))
return CocoaPodsStatus.belowMinimumVersion;
else if (installedVersion < new Version.parse(cocoaPodsRecommendedVersion))
return CocoaPodsStatus.belowRecommendedVersion;
else
return CocoaPodsStatus.recommended;
} on FormatException { } on FormatException {
return false; return CocoaPodsStatus.notInstalled;
} }
} }
...@@ -79,16 +100,37 @@ class CocoaPods { ...@@ -79,16 +100,37 @@ class CocoaPods {
/// Make sure the CocoaPods tools are in the right states. /// Make sure the CocoaPods tools are in the right states.
Future<bool> _checkPodCondition() async { Future<bool> _checkPodCondition() async {
if (!await isCocoaPodsInstalledAndMeetsVersionCheck) { final CocoaPodsStatus installation = await evaluateCocoaPodsInstallation;
final String minimumVersion = cocoaPodsMinimumVersion; switch (installation) {
printError( case CocoaPodsStatus.notInstalled:
'Warning: CocoaPods version $minimumVersion or greater not installed. Skipping pod install.\n' printError(
'$noCocoaPodsConsequence\n' 'Warning: CocoaPods not installed. Skipping pod install.\n'
'To install:\n' '$noCocoaPodsConsequence\n'
'$cocoaPodsInstallInstructions\n', 'To install:\n'
emphasis: true, '$cocoaPodsInstallInstructions\n',
); emphasis: true,
return false; );
return false;
case CocoaPodsStatus.belowMinimumVersion:
printError(
'Warning: CocoaPods minimum required version $cocoaPodsMinimumVersion or greater not installed. Skipping pod install.\n'
'$noCocoaPodsConsequence\n'
'To upgrade:\n'
'$cocoaPodsUpgradeInstructions\n',
emphasis: true,
);
return false;
case CocoaPodsStatus.belowRecommendedVersion:
printError(
'Warning: CocoaPods recommended version $cocoaPodsRecommendedVersion or greater not installed.\n'
'Pods handling may fail on some projects involving plugins.\n'
'To upgrade:\n'
'$cocoaPodsUpgradeInstructions\n',
emphasis: true,
);
break;
default:
break;
} }
if (!await isCocoaPodsInitialized) { if (!await isCocoaPodsInitialized) {
printError( printError(
...@@ -155,19 +197,20 @@ class CocoaPods { ...@@ -155,19 +197,20 @@ class CocoaPods {
// Check if you need to run pod install. // Check if you need to run pod install.
// The pod install will run if any of below is true. // The pod install will run if any of below is true.
// 1. The flutter.framework has changed (debug/release/profile) // 1. Flutter dependencies have changed
// 2. The podfile.lock doesn't exist // 2. Podfile.lock doesn't exist or is older than Podfile
// 3. The Pods/Manifest.lock doesn't exist (It is deleted when plugins change) // 3. Pods/Manifest.lock doesn't exist (It is deleted when plugins change)
// 4. The podfile.lock doesn't match Pods/Manifest.lock. // 4. Podfile.lock doesn't match Pods/Manifest.lock.
bool _shouldRunPodInstall(Directory appIosDirectory, bool dependenciesChanged) { bool _shouldRunPodInstall(Directory appIosDirectory, bool dependenciesChanged) {
if (dependenciesChanged) if (dependenciesChanged)
return true; return true;
// Check if podfile.lock and Pods/Manifest.lock exist and match. final File podfileFile = appIosDirectory.childFile('Podfile');
final File podfileLockFile = appIosDirectory.childFile('Podfile.lock'); final File podfileLockFile = appIosDirectory.childFile('Podfile.lock');
final File manifestLockFile = final File manifestLockFile =
appIosDirectory.childFile(fs.path.join('Pods', 'Manifest.lock')); appIosDirectory.childFile(fs.path.join('Pods', 'Manifest.lock'));
return !podfileLockFile.existsSync() return !podfileLockFile.existsSync()
|| !manifestLockFile.existsSync() || !manifestLockFile.existsSync()
|| podfileLockFile.statSync().modified.isBefore(podfileFile.statSync().modified)
|| podfileLockFile.readAsStringSync() != manifestLockFile.readAsStringSync(); || podfileLockFile.readAsStringSync() != manifestLockFile.readAsStringSync();
} }
......
...@@ -171,7 +171,9 @@ class IOSWorkflow extends DoctorValidator implements Workflow { ...@@ -171,7 +171,9 @@ class IOSWorkflow extends DoctorValidator implements Workflow {
} }
} }
if (await cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck) { final CocoaPodsStatus cocoaPodsStatus = await cocoaPods.evaluateCocoaPodsInstallation;
if (cocoaPodsStatus == CocoaPodsStatus.recommended) {
if (await cocoaPods.isCocoaPodsInitialized) { if (await cocoaPods.isCocoaPodsInitialized) {
messages.add(new ValidationMessage('CocoaPods version ${await cocoaPods.cocoaPodsVersionText}')); messages.add(new ValidationMessage('CocoaPods version ${await cocoaPods.cocoaPodsVersionText}'));
} else { } else {
...@@ -186,7 +188,7 @@ class IOSWorkflow extends DoctorValidator implements Workflow { ...@@ -186,7 +188,7 @@ class IOSWorkflow extends DoctorValidator implements Workflow {
} }
} else { } else {
brewStatus = ValidationType.partial; brewStatus = ValidationType.partial;
if (!await cocoaPods.hasCocoaPods) { if (cocoaPodsStatus == CocoaPodsStatus.notInstalled) {
messages.add(new ValidationMessage.error( messages.add(new ValidationMessage.error(
'CocoaPods not installed.\n' 'CocoaPods not installed.\n'
'$noCocoaPodsConsequence\n' '$noCocoaPodsConsequence\n'
...@@ -194,8 +196,8 @@ class IOSWorkflow extends DoctorValidator implements Workflow { ...@@ -194,8 +196,8 @@ class IOSWorkflow extends DoctorValidator implements Workflow {
'$cocoaPodsInstallInstructions' '$cocoaPodsInstallInstructions'
)); ));
} else { } else {
messages.add(new ValidationMessage.error( messages.add(new ValidationMessage.hint(
'CocoaPods out of date ($cocoaPods.cocoaPodsMinimumVersion is required).\n' 'CocoaPods out of date (${cocoaPods.cocoaPodsRecommendedVersion} is recommended).\n'
'$noCocoaPodsConsequence\n' '$noCocoaPodsConsequence\n'
'To upgrade:\n' 'To upgrade:\n'
'$cocoaPodsUpgradeInstructions' '$cocoaPodsUpgradeInstructions'
......
...@@ -238,7 +238,7 @@ void injectPlugins({String directory}) { ...@@ -238,7 +238,7 @@ void injectPlugins({String directory}) {
_writeAndroidPluginRegistrant(directory, plugins); _writeAndroidPluginRegistrant(directory, plugins);
if (fs.isDirectorySync(fs.path.join(directory, 'ios'))) { if (fs.isDirectorySync(fs.path.join(directory, 'ios'))) {
_writeIOSPluginRegistrant(directory, plugins); _writeIOSPluginRegistrant(directory, plugins);
const CocoaPods cocoaPods = const CocoaPods(); final CocoaPods cocoaPods = new CocoaPods();
if (plugins.isNotEmpty) if (plugins.isNotEmpty)
cocoaPods.setupPodfile(directory); cocoaPods.setupPodfile(directory);
if (changed) if (changed)
......
...@@ -29,8 +29,8 @@ end ...@@ -29,8 +29,8 @@ end
target 'Runner' do target 'Runner' do
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines. # referring to absolute paths on developers' machines.
system('rm -rf Pods/.symlinks') system('rm -rf .symlinks')
system('mkdir -p Pods/.symlinks/plugins') system('mkdir -p .symlinks/plugins')
# Flutter Pods # Flutter Pods
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
...@@ -39,7 +39,7 @@ target 'Runner' do ...@@ -39,7 +39,7 @@ target 'Runner' do
end end
generated_xcode_build_settings.map { |p| generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR' if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join('Pods', '.symlinks', 'flutter') symlink = File.join('.symlinks', 'flutter')
File.symlink(File.dirname(p[:path]), symlink) File.symlink(File.dirname(p[:path]), symlink)
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
end end
...@@ -48,7 +48,7 @@ target 'Runner' do ...@@ -48,7 +48,7 @@ target 'Runner' do
# Plugin Pods # Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins') plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p| plugin_pods.map { |p|
symlink = File.join('Pods', '.symlinks', 'plugins', p[:name]) symlink = File.join('.symlinks', 'plugins', p[:name])
File.symlink(p[:path], symlink) File.symlink(p[:path], symlink)
pod p[:name], :path => File.join(symlink, 'ios') pod p[:name], :path => File.join(symlink, 'ios')
} }
......
...@@ -31,8 +31,8 @@ target 'Runner' do ...@@ -31,8 +31,8 @@ target 'Runner' do
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines. # referring to absolute paths on developers' machines.
system('rm -rf Pods/.symlinks') system('rm -rf .symlinks')
system('mkdir -p Pods/.symlinks/plugins') system('mkdir -p .symlinks/plugins')
# Flutter Pods # Flutter Pods
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
...@@ -41,7 +41,7 @@ target 'Runner' do ...@@ -41,7 +41,7 @@ target 'Runner' do
end end
generated_xcode_build_settings.map { |p| generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR' if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join('Pods', '.symlinks', 'flutter') symlink = File.join('.symlinks', 'flutter')
File.symlink(File.dirname(p[:path]), symlink) File.symlink(File.dirname(p[:path]), symlink)
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
end end
...@@ -50,7 +50,7 @@ target 'Runner' do ...@@ -50,7 +50,7 @@ target 'Runner' do
# Plugin Pods # Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins') plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p| plugin_pods.map { |p|
symlink = File.join('Pods', '.symlinks', 'plugins', p[:name]) symlink = File.join('.symlinks', 'plugins', p[:name])
File.symlink(p[:path], symlink) File.symlink(p[:path], symlink)
pod p[:name], :path => File.join(symlink, 'ios') pod p[:name], :path => File.join(symlink, 'ios')
} }
......
...@@ -42,3 +42,4 @@ Icon? ...@@ -42,3 +42,4 @@ Icon?
/ServiceDefinitions.json /ServiceDefinitions.json
Pods/ Pods/
.symlinks/
...@@ -33,10 +33,10 @@ void main() { ...@@ -33,10 +33,10 @@ void main() {
cocoaPods = new MockCocoaPods(); cocoaPods = new MockCocoaPods();
fs = new MemoryFileSystem(); fs = new MemoryFileSystem();
when(cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck) when(cocoaPods.evaluateCocoaPodsInstallation)
.thenAnswer((_) => new Future<bool>.value(true)); .thenAnswer((_) async => CocoaPodsStatus.recommended);
when(cocoaPods.isCocoaPodsInitialized) when(cocoaPods.isCocoaPodsInitialized).thenAnswer((_) async => true);
.thenAnswer((_) => new Future<bool>.value(true)); when(cocoaPods.cocoaPodsVersionText).thenAnswer((_) async => '1.8.0');
}); });
testUsingContext('Emit missing status when nothing is installed', () async { testUsingContext('Emit missing status when nothing is installed', () async {
...@@ -213,9 +213,8 @@ void main() { ...@@ -213,9 +213,8 @@ void main() {
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true); when(xcode.eulaSigned).thenReturn(true);
when(cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck) when(cocoaPods.evaluateCocoaPodsInstallation)
.thenAnswer((_) => new Future<bool>.value(false)); .thenAnswer((_) async => CocoaPodsStatus.notInstalled);
when(cocoaPods.hasCocoaPods).thenAnswer((_) => new Future<bool>.value(false));
when(xcode.isSimctlInstalled).thenReturn(true); when(xcode.isSimctlInstalled).thenReturn(true);
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
final ValidationResult result = await workflow.validate(); final ValidationResult result = await workflow.validate();
...@@ -232,11 +231,8 @@ void main() { ...@@ -232,11 +231,8 @@ void main() {
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true); when(xcode.eulaSigned).thenReturn(true);
when(cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck) when(cocoaPods.evaluateCocoaPodsInstallation)
.thenAnswer((_) => new Future<bool>.value(false)); .thenAnswer((_) async => CocoaPodsStatus.belowRecommendedVersion);
when(cocoaPods.hasCocoaPods).thenAnswer((_) => new Future<bool>.value(true));
when(cocoaPods.cocoaPodsVersionText)
.thenAnswer((_) => new Future<String>.value('0.39.0'));
when(xcode.isSimctlInstalled).thenReturn(true); when(xcode.isSimctlInstalled).thenReturn(true);
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
final ValidationResult result = await workflow.validate(); final ValidationResult result = await workflow.validate();
...@@ -253,8 +249,6 @@ void main() { ...@@ -253,8 +249,6 @@ void main() {
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true); when(xcode.eulaSigned).thenReturn(true);
when(cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck).thenAnswer((_) async => false);
when(cocoaPods.hasCocoaPods).thenAnswer((_) async => true);
when(cocoaPods.isCocoaPodsInitialized).thenAnswer((_) async => false); when(cocoaPods.isCocoaPodsInitialized).thenAnswer((_) async => false);
when(xcode.isSimctlInstalled).thenReturn(true); when(xcode.isSimctlInstalled).thenReturn(true);
......
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