diff --git a/.gitmodules b/.gitmodules index 5c6a8f47a6..a1e528562c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,7 +6,8 @@ url = https://github.com/tonymillion/Reachability.git [submodule "spec/cocoapods-integration-specs"] path = spec/cocoapods-integration-specs - url = https://github.com/CocoaPods/cocoapods-integration-specs.git + url = https://github.com/mfazekas/cocoapods-integration-specs.git + branch = podspec-spm [submodule "spec/fixtures/spec-repos/test_repo"] path = spec/fixtures/spec-repos/test_repo url = https://github.com/CocoaPods/cocoapods-test-specs.git diff --git a/Gemfile b/Gemfile index 841ac71cc9..69b0e2025f 100644 --- a/Gemfile +++ b/Gemfile @@ -20,7 +20,8 @@ gemspec group :development do cp_gem 'claide', 'CLAide' - cp_gem 'cocoapods-core', 'Core' + # cp_gem 'cocoapods-core', 'Core' + gem 'cocoapods-core', :git => 'https://github.com/mfazekas/Core', branch: 'podspec-spm' cp_gem 'cocoapods-deintegrate', 'cocoapods-deintegrate' cp_gem 'cocoapods-downloader', 'cocoapods-downloader' cp_gem 'cocoapods-plugins', 'cocoapods-plugins' diff --git a/Gemfile.lock b/Gemfile.lock index 804475fa57..800a6dc048 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,22 +5,6 @@ GIT specs: claide (1.1.0) -GIT - remote: https://github.com/CocoaPods/Core.git - revision: 9320bf557741d7ae80eda4415bc6fb2b0b3a8b9c - branch: master - specs: - cocoapods-core (1.12.1) - activesupport (>= 5.0, < 8) - addressable (~> 2.8) - algoliasearch (~> 1.0) - concurrent-ruby (~> 1.1) - fuzzy_match (~> 2.0.4) - nap (~> 1.0) - netrc (~> 0.11) - public_suffix (~> 4.0) - typhoeus (~> 1.0) - GIT remote: https://github.com/CocoaPods/Molinillo.git revision: 6bc3d6045edadf800ba1b634fef15d3574369e60 @@ -108,6 +92,22 @@ GIT specs: bacon (1.2.0) +GIT + remote: https://github.com/mfazekas/Core + revision: 8524bb4f428992f6ad5f822181c820be2bf4126d + branch: podspec-spm + specs: + cocoapods-core (1.12.1) + activesupport (>= 5.0, < 8) + addressable (~> 2.8) + algoliasearch (~> 1.0) + concurrent-ruby (~> 1.1) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + netrc (~> 0.11) + public_suffix (~> 4.0) + typhoeus (~> 1.0) + GIT remote: https://github.com/mrackwitz/CLIntegracon.git revision: ca88b7b8920b6b6542f9b4ad2b1748855783dbae diff --git a/lib/cocoapods/installer/xcode/pods_project_generator.rb b/lib/cocoapods/installer/xcode/pods_project_generator.rb index f122c7653e..2e7d4ee58b 100644 --- a/lib/cocoapods/installer/xcode/pods_project_generator.rb +++ b/lib/cocoapods/installer/xcode/pods_project_generator.rb @@ -193,6 +193,67 @@ def wire_target_dependencies(target_installation_results) PodTargetDependencyInstaller.new(sandbox, pod_target_installation_results_hash, metadata_cache).install! end + def _merge_spm_requirements(url, requirements) + if requirements.count > 1 + requirements.reduce(requirements.first) do |acc, req| + if acc != req + error "SPM dependencies with different requirements: #{requirements} for #{url} is not yet supported" + end + acc + end + else + requirements.first + end + end + + def install_spm_dedpendecies(project, pod_targets) + spm_dependencies = pod_targets.flat_map { |target| target.root_spec.consumer(target.platform).spm_dependencies } + spm_dependencies_by_url = spm_dependencies.group_by { |dep| dep[:url] } + merged_spm_dependencies = spm_dependencies_by_url.map do |url, deps| + [url, _merge_spm_requirements(url, deps.map { |dep| dep[:requirement] })] + end + + spm_dependencies_by_url = merged_spm_dependencies.map do |url, requirement| + [url, project.add_spm_dependency(url, requirement.to_h)] + end + + spm_dependencies_by_url.to_h + end + + def _spm_deps_workaround_for_swift(native_target) + # Seems to be an XCode issue where subprojects SWITFT_INCLUDE_PATHS doesn't the added SPM dependency's products + # without this Swift code trying to import the SPM dependency's product will fail with "No such module" + search_path = '${SYMROOT}/${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}/' + native_target.build_configurations.each do |config| + build_settings = native_target.build_settings(config.name) + build_settings['SWIFT_INCLUDE_PATHS'] ||= ['$(inherited)'] + unless build_settings['SWIFT_INCLUDE_PATHS'].include?(search_path) + build_settings['SWIFT_INCLUDE_PATHS'].push(search_path) + end + end + end + + def wire_target_spm_dependencies(target_installation_results, spm_dependencies_by_url) + target_installation_results.pod_target_installation_results.each_value do |pod_target_installation_result| + target = pod_target_installation_result.target + spm_deps_to_wire = target.spec_consumers.flat_map(&:spm_dependencies) + spm_deps_to_wire.each do |spm_dep| + native_target = pod_target_installation_result.native_target + project = native_target.project + + spm_dep[:products].each do |product_name| + product_reference = project.new(Xcodeproj::Project::Object::XCSwiftPackageProductDependency) + product_reference.product_name = product_name + product_reference.package = spm_dependencies_by_url[spm_dep[:url]] + + native_target.package_product_dependencies << product_reference + + _spm_deps_workaround_for_swift(native_target) + end + end + end + end + # @param [String] pod The root name of the development pod. # # @return [Boolean] whether the scheme for the given development pod should be diff --git a/lib/cocoapods/installer/xcode/single_pods_project_generator.rb b/lib/cocoapods/installer/xcode/single_pods_project_generator.rb index 1287727a5d..2cac7e8ee8 100644 --- a/lib/cocoapods/installer/xcode/single_pods_project_generator.rb +++ b/lib/cocoapods/installer/xcode/single_pods_project_generator.rb @@ -15,6 +15,7 @@ def generate! platforms, project_object_version, config.podfile_path) project = project_generator.generate! install_file_references(project, pod_targets) + spm_references_by_url = install_spm_dedpendecies(project, pod_targets) pod_target_installation_results = install_all_pod_targets(project, pod_targets) aggregate_target_installation_results = install_aggregate_targets(project, aggregate_targets) @@ -22,6 +23,7 @@ def generate! integrate_targets(target_installation_results.pod_target_installation_results) wire_target_dependencies(target_installation_results) + wire_target_spm_dependencies(target_installation_results, spm_references_by_url) PodsProjectGeneratorResult.new(project, {}, target_installation_results) end diff --git a/lib/cocoapods/project.rb b/lib/cocoapods/project.rb index 3291372337..815f3f0841 100644 --- a/lib/cocoapods/project.rb +++ b/lib/cocoapods/project.rb @@ -392,6 +392,14 @@ def add_build_configuration(name, type) build_configuration end + def add_spm_dependency(url, requirement) + spm_dependency = new(XCRemoteSwiftPackageReference) + spm_dependency.repositoryURL = url + spm_dependency.requirement = requirement + root_object.package_references << spm_dependency + spm_dependency + end + # @param [String] name # The name of the build configuration. # diff --git a/spec/cocoapods-integration-specs b/spec/cocoapods-integration-specs index 5788f5a44f..305d23387e 160000 --- a/spec/cocoapods-integration-specs +++ b/spec/cocoapods-integration-specs @@ -1 +1 @@ -Subproject commit 5788f5a44ff6d742766e86bbdb19b29979bc5311 +Subproject commit 305d23387e087e622044d03165973e1d7236cfa1 diff --git a/spec/integration.rb b/spec/integration.rb index d0e3511164..54db0417a3 100644 --- a/spec/integration.rb +++ b/spec/integration.rb @@ -361,6 +361,11 @@ 'install --no-repo-update' end + describe 'Installs a podspec with SPM dependencies' do + behaves_like cli_spec 'install_spm_dependency', + 'install --no-repo-update' + end + describe 'Integrates a Pod with circular subspec dependencies' do behaves_like cli_spec 'install_circular_subspec_dependency', 'install --no-repo-update' diff --git a/spec/integration/xcodeproj_project_yaml.rb b/spec/integration/xcodeproj_project_yaml.rb index 5dd1844426..f0c160475c 100644 --- a/spec/integration/xcodeproj_project_yaml.rb +++ b/spec/integration/xcodeproj_project_yaml.rb @@ -10,6 +10,9 @@ def to_yaml yaml = { key => pretty_print_output[key] }.to_yaml sections << yaml end + if root_object.package_references.any? + sections << {'Package References' => root_object.package_references.map(&:to_hash)}.to_yaml + end (sections * "\n\n").gsub!('---', '') end end