mirror of
https://github.com/flutter/flutter
synced 2024-08-27 12:00:58 +00:00
Add readlink -f flag to CocoaPods script to workaround Xcode 14.3 issue (#124062)
This commit is contained in:
parent
d32dc71223
commit
d4934fb6ab
|
@ -13,10 +13,12 @@ import '../base/logger.dart';
|
||||||
import '../base/os.dart';
|
import '../base/os.dart';
|
||||||
import '../base/platform.dart';
|
import '../base/platform.dart';
|
||||||
import '../base/process.dart';
|
import '../base/process.dart';
|
||||||
|
import '../base/project_migrator.dart';
|
||||||
import '../base/version.dart';
|
import '../base/version.dart';
|
||||||
import '../build_info.dart';
|
import '../build_info.dart';
|
||||||
import '../cache.dart';
|
import '../cache.dart';
|
||||||
import '../ios/xcodeproj.dart';
|
import '../ios/xcodeproj.dart';
|
||||||
|
import '../migrations/cocoapods_script_symlink.dart';
|
||||||
import '../reporting/reporting.dart';
|
import '../reporting/reporting.dart';
|
||||||
import '../xcode_project.dart';
|
import '../xcode_project.dart';
|
||||||
|
|
||||||
|
@ -166,6 +168,13 @@ class CocoaPods {
|
||||||
throwToolExit('CocoaPods not installed or not in valid state.');
|
throwToolExit('CocoaPods not installed or not in valid state.');
|
||||||
}
|
}
|
||||||
await _runPodInstall(xcodeProject, buildMode);
|
await _runPodInstall(xcodeProject, buildMode);
|
||||||
|
|
||||||
|
// This migrator works around a CocoaPods bug, and should be run after `pod install` is run.
|
||||||
|
final ProjectMigration postPodMigration = ProjectMigration(<ProjectMigrator>[
|
||||||
|
CocoaPodsScriptReadlink(xcodeProject, _xcodeProjectInterpreter, _logger),
|
||||||
|
]);
|
||||||
|
postPodMigration.run();
|
||||||
|
|
||||||
podsProcessed = true;
|
podsProcessed = true;
|
||||||
}
|
}
|
||||||
return podsProcessed;
|
return podsProcessed;
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import '../base/file_system.dart';
|
||||||
|
import '../base/project_migrator.dart';
|
||||||
|
import '../base/version.dart';
|
||||||
|
import '../ios/xcodeproj.dart';
|
||||||
|
import '../xcode_project.dart';
|
||||||
|
|
||||||
|
// Xcode 14.3 changed the readlink symlink behavior to be relative from the script working directory, instead of the
|
||||||
|
// relative path of the symlink. The -f flag returns the original "--canonicalize" behavior the CocoaPods script relies on.
|
||||||
|
// This has been fixed upstream in CocoaPods, but migrate a copy of their workaround so users don't need to update.
|
||||||
|
//
|
||||||
|
// See https://github.com/flutter/flutter/issues/123890#issuecomment-1494825976.
|
||||||
|
class CocoaPodsScriptReadlink extends ProjectMigrator {
|
||||||
|
CocoaPodsScriptReadlink(
|
||||||
|
XcodeBasedProject project,
|
||||||
|
XcodeProjectInterpreter xcodeProjectInterpreter,
|
||||||
|
super.logger,
|
||||||
|
) : _podRunnerFrameworksScript = project.podRunnerFrameworksScript,
|
||||||
|
_xcodeProjectInterpreter = xcodeProjectInterpreter;
|
||||||
|
|
||||||
|
final File _podRunnerFrameworksScript;
|
||||||
|
final XcodeProjectInterpreter _xcodeProjectInterpreter;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void migrate() {
|
||||||
|
if (!_podRunnerFrameworksScript.existsSync()) {
|
||||||
|
logger.printTrace('CocoaPods Pods-Runner-frameworks.sh script not found, skipping "readlink -f" workaround.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Version? version = _xcodeProjectInterpreter.version;
|
||||||
|
|
||||||
|
// If Xcode not installed or less than 14.3 with readlink behavior change, skip this migration.
|
||||||
|
if (version == null || version < Version(14, 3, 0)) {
|
||||||
|
logger.printTrace('Detected Xcode version is $version, below 14.3, skipping "readlink -f" workaround.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
processFileLines(_podRunnerFrameworksScript);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? migrateLine(String line) {
|
||||||
|
const String originalReadLinkLine = r'source="$(readlink "${source}")"';
|
||||||
|
const String replacementReadLinkLine = r'source="$(readlink -f "${source}")"';
|
||||||
|
|
||||||
|
return line.replaceAll(originalReadLinkLine, replacementReadLinkLine);
|
||||||
|
}
|
||||||
|
}
|
|
@ -89,6 +89,13 @@ abstract class XcodeBasedProject extends FlutterProjectPlatform {
|
||||||
|
|
||||||
/// The CocoaPods 'Manifest.lock'.
|
/// The CocoaPods 'Manifest.lock'.
|
||||||
File get podManifestLock => hostAppRoot.childDirectory('Pods').childFile('Manifest.lock');
|
File get podManifestLock => hostAppRoot.childDirectory('Pods').childFile('Manifest.lock');
|
||||||
|
|
||||||
|
/// The CocoaPods generated 'Pods-Runner-frameworks.sh'.
|
||||||
|
File get podRunnerFrameworksScript => hostAppRoot
|
||||||
|
.childDirectory('Pods')
|
||||||
|
.childDirectory('Target Support Files')
|
||||||
|
.childDirectory('Pods-Runner')
|
||||||
|
.childFile('Pods-Runner-frameworks.sh');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the iOS sub-project of a Flutter project.
|
/// Represents the iOS sub-project of a Flutter project.
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:file/file.dart';
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
import 'package:flutter_tools/src/base/logger.dart';
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
import 'package:flutter_tools/src/base/project_migrator.dart';
|
import 'package:flutter_tools/src/base/project_migrator.dart';
|
||||||
|
import 'package:flutter_tools/src/base/version.dart';
|
||||||
import 'package:flutter_tools/src/ios/migrations/host_app_info_plist_migration.dart';
|
import 'package:flutter_tools/src/ios/migrations/host_app_info_plist_migration.dart';
|
||||||
import 'package:flutter_tools/src/ios/migrations/ios_deployment_target_migration.dart';
|
import 'package:flutter_tools/src/ios/migrations/ios_deployment_target_migration.dart';
|
||||||
import 'package:flutter_tools/src/ios/migrations/project_base_configuration_migration.dart';
|
import 'package:flutter_tools/src/ios/migrations/project_base_configuration_migration.dart';
|
||||||
|
@ -13,6 +14,8 @@ import 'package:flutter_tools/src/ios/migrations/project_build_location_migratio
|
||||||
import 'package:flutter_tools/src/ios/migrations/remove_bitcode_migration.dart';
|
import 'package:flutter_tools/src/ios/migrations/remove_bitcode_migration.dart';
|
||||||
import 'package:flutter_tools/src/ios/migrations/remove_framework_link_and_embedding_migration.dart';
|
import 'package:flutter_tools/src/ios/migrations/remove_framework_link_and_embedding_migration.dart';
|
||||||
import 'package:flutter_tools/src/ios/migrations/xcode_build_system_migration.dart';
|
import 'package:flutter_tools/src/ios/migrations/xcode_build_system_migration.dart';
|
||||||
|
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||||
|
import 'package:flutter_tools/src/migrations/cocoapods_script_symlink.dart';
|
||||||
import 'package:flutter_tools/src/migrations/xcode_project_object_version_migration.dart';
|
import 'package:flutter_tools/src/migrations/xcode_project_object_version_migration.dart';
|
||||||
import 'package:flutter_tools/src/migrations/xcode_script_build_phase_migration.dart';
|
import 'package:flutter_tools/src/migrations/xcode_script_build_phase_migration.dart';
|
||||||
import 'package:flutter_tools/src/migrations/xcode_thin_binary_build_phase_input_paths_migration.dart';
|
import 'package:flutter_tools/src/migrations/xcode_thin_binary_build_phase_input_paths_migration.dart';
|
||||||
|
@ -21,6 +24,7 @@ import 'package:flutter_tools/src/xcode_project.dart';
|
||||||
import 'package:test/fake.dart';
|
import 'package:test/fake.dart';
|
||||||
|
|
||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
|
import '../../src/fake_process_manager.dart';
|
||||||
|
|
||||||
void main () {
|
void main () {
|
||||||
group('iOS migration', () {
|
group('iOS migration', () {
|
||||||
|
@ -901,6 +905,104 @@ platform :ios, '11.0'
|
||||||
expect('Disabling deprecated bitcode Xcode build setting'.allMatches(testLogger.warningText).length, 1);
|
expect('Disabling deprecated bitcode Xcode build setting'.allMatches(testLogger.warningText).length, 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('CocoaPods script readlink', () {
|
||||||
|
late MemoryFileSystem memoryFileSystem;
|
||||||
|
late BufferLogger testLogger;
|
||||||
|
late FakeIosProject project;
|
||||||
|
late File podRunnerFrameworksScript;
|
||||||
|
late ProcessManager processManager;
|
||||||
|
late XcodeProjectInterpreter xcode143ProjectInterpreter;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
memoryFileSystem = MemoryFileSystem();
|
||||||
|
podRunnerFrameworksScript = memoryFileSystem.file('Pods-Runner-frameworks.sh');
|
||||||
|
testLogger = BufferLogger.test();
|
||||||
|
project = FakeIosProject();
|
||||||
|
processManager = FakeProcessManager.any();
|
||||||
|
xcode143ProjectInterpreter = XcodeProjectInterpreter.test(processManager: processManager, version: Version(14, 3, 0));
|
||||||
|
project.podRunnerFrameworksScript = podRunnerFrameworksScript;
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('skipped if files are missing', () {
|
||||||
|
final CocoaPodsScriptReadlink iosProjectMigration = CocoaPodsScriptReadlink(
|
||||||
|
project,
|
||||||
|
xcode143ProjectInterpreter,
|
||||||
|
testLogger,
|
||||||
|
);
|
||||||
|
iosProjectMigration.migrate();
|
||||||
|
expect(podRunnerFrameworksScript.existsSync(), isFalse);
|
||||||
|
|
||||||
|
expect(testLogger.traceText, contains('CocoaPods Pods-Runner-frameworks.sh script not found'));
|
||||||
|
expect(testLogger.statusText, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('skipped if nothing to upgrade', () {
|
||||||
|
const String contents = r'''
|
||||||
|
if [ -L "${source}" ]; then
|
||||||
|
echo "Symlinked..."
|
||||||
|
source="$(readlink -f "${source}")"
|
||||||
|
fi''';
|
||||||
|
podRunnerFrameworksScript.writeAsStringSync(contents);
|
||||||
|
|
||||||
|
final CocoaPodsScriptReadlink iosProjectMigration = CocoaPodsScriptReadlink(
|
||||||
|
project,
|
||||||
|
xcode143ProjectInterpreter,
|
||||||
|
testLogger,
|
||||||
|
);
|
||||||
|
iosProjectMigration.migrate();
|
||||||
|
expect(podRunnerFrameworksScript.existsSync(), isTrue);
|
||||||
|
expect(testLogger.traceText, isEmpty);
|
||||||
|
expect(testLogger.statusText, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('skipped if Xcode version below 14.3', () {
|
||||||
|
const String contents = r'''
|
||||||
|
if [ -L "${source}" ]; then
|
||||||
|
echo "Symlinked..."
|
||||||
|
source="$(readlink "${source}")"
|
||||||
|
fi''';
|
||||||
|
podRunnerFrameworksScript.writeAsStringSync(contents);
|
||||||
|
|
||||||
|
final XcodeProjectInterpreter xcode142ProjectInterpreter = XcodeProjectInterpreter.test(
|
||||||
|
processManager: processManager,
|
||||||
|
version: Version(14, 2, 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
final CocoaPodsScriptReadlink iosProjectMigration = CocoaPodsScriptReadlink(
|
||||||
|
project,
|
||||||
|
xcode142ProjectInterpreter,
|
||||||
|
testLogger,
|
||||||
|
);
|
||||||
|
iosProjectMigration.migrate();
|
||||||
|
expect(podRunnerFrameworksScript.existsSync(), isTrue);
|
||||||
|
expect(testLogger.traceText, contains('Detected Xcode version is 14.2.0, below 14.3, skipping "readlink -f" workaround'));
|
||||||
|
expect(testLogger.statusText, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('Xcode project is migrated', () {
|
||||||
|
const String contents = r'''
|
||||||
|
if [ -L "${source}" ]; then
|
||||||
|
echo "Symlinked..."
|
||||||
|
source="$(readlink "${source}")"
|
||||||
|
fi''';
|
||||||
|
podRunnerFrameworksScript.writeAsStringSync(contents);
|
||||||
|
|
||||||
|
final CocoaPodsScriptReadlink iosProjectMigration = CocoaPodsScriptReadlink(
|
||||||
|
project,
|
||||||
|
xcode143ProjectInterpreter,
|
||||||
|
testLogger,
|
||||||
|
);
|
||||||
|
iosProjectMigration.migrate();
|
||||||
|
expect(podRunnerFrameworksScript.readAsStringSync(), r'''
|
||||||
|
if [ -L "${source}" ]; then
|
||||||
|
echo "Symlinked..."
|
||||||
|
source="$(readlink -f "${source}")"
|
||||||
|
fi
|
||||||
|
''');
|
||||||
|
expect(testLogger.statusText, contains('Upgrading Pods-Runner-frameworks.sh'));
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group('update Xcode script build phase', () {
|
group('update Xcode script build phase', () {
|
||||||
|
@ -1134,6 +1236,9 @@ class FakeIosProject extends Fake implements IosProject {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
File podfile = MemoryFileSystem.test().file('Podfile');
|
File podfile = MemoryFileSystem.test().file('Podfile');
|
||||||
|
|
||||||
|
@override
|
||||||
|
File podRunnerFrameworksScript = MemoryFileSystem.test().file('podRunnerFrameworksScript');
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakeIOSMigrator extends ProjectMigrator {
|
class FakeIOSMigrator extends ProjectMigrator {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:file/file.dart';
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
import 'package:flutter_tools/src/base/logger.dart';
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
import 'package:flutter_tools/src/base/platform.dart';
|
import 'package:flutter_tools/src/base/platform.dart';
|
||||||
|
import 'package:flutter_tools/src/base/version.dart';
|
||||||
import 'package:flutter_tools/src/build_info.dart';
|
import 'package:flutter_tools/src/build_info.dart';
|
||||||
import 'package:flutter_tools/src/cache.dart';
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
import 'package:flutter_tools/src/flutter_plugins.dart';
|
import 'package:flutter_tools/src/flutter_plugins.dart';
|
||||||
|
@ -740,6 +741,55 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
|
||||||
);
|
);
|
||||||
expect(didInstall, isTrue);
|
expect(didInstall, isTrue);
|
||||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
|
expect(logger.traceText, contains('CocoaPods Pods-Runner-frameworks.sh script not found'));
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('runs CocoaPods Pod runner script migrator', () async {
|
||||||
|
final FlutterProject projectUnderTest = setupProjectUnderTest();
|
||||||
|
pretendPodIsInstalled();
|
||||||
|
pretendPodVersionIs('100.0.0');
|
||||||
|
projectUnderTest.ios.podfile
|
||||||
|
..createSync()
|
||||||
|
..writeAsStringSync('Existing Podfile');
|
||||||
|
projectUnderTest.ios.podfileLock
|
||||||
|
..createSync()
|
||||||
|
..writeAsStringSync('Existing lock file.');
|
||||||
|
projectUnderTest.ios.podManifestLock
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync('Existing lock file.');
|
||||||
|
projectUnderTest.ios.podRunnerFrameworksScript
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync(r'source="$(readlink "${source}")"');
|
||||||
|
|
||||||
|
fakeProcessManager.addCommands(const <FakeCommand>[
|
||||||
|
FakeCommand(
|
||||||
|
command: <String>['pod', 'install', '--verbose'],
|
||||||
|
workingDirectory: 'project/ios',
|
||||||
|
environment: <String, String>{'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'},
|
||||||
|
),
|
||||||
|
FakeCommand(
|
||||||
|
command: <String>['touch', 'project/ios/Podfile.lock'],
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
final CocoaPods cocoaPodsUnderTestXcode143 = CocoaPods(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
processManager: fakeProcessManager,
|
||||||
|
logger: logger,
|
||||||
|
platform: FakePlatform(operatingSystem: 'macos'),
|
||||||
|
xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: fakeProcessManager, version: Version(14, 3, 0)),
|
||||||
|
usage: usage,
|
||||||
|
);
|
||||||
|
|
||||||
|
final bool didInstall = await cocoaPodsUnderTestXcode143.processPods(
|
||||||
|
xcodeProject: projectUnderTest.ios,
|
||||||
|
buildMode: BuildMode.debug,
|
||||||
|
);
|
||||||
|
expect(didInstall, isTrue);
|
||||||
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
|
// Now has readlink -f flag.
|
||||||
|
expect(projectUnderTest.ios.podRunnerFrameworksScript.readAsStringSync(), contains(r'source="$(readlink -f "${source}")"'));
|
||||||
|
expect(logger.statusText, contains('Upgrading Pods-Runner-frameworks.sh'));
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('runs pod install, if Podfile.lock is older than Podfile', () async {
|
testUsingContext('runs pod install, if Podfile.lock is older than Podfile', () async {
|
||||||
|
|
Loading…
Reference in a new issue