Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPM: allow podspecs to declare Swift Package Manager dependencies with spm_dependency #11953

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be reverted before merge

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
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be reverted before merge

cp_gem 'cocoapods-deintegrate', 'cocoapods-deintegrate'
cp_gem 'cocoapods-downloader', 'cocoapods-downloader'
cp_gem 'cocoapods-plugins', 'cocoapods-plugins'
Expand Down
32 changes: 16 additions & 16 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
61 changes: 61 additions & 0 deletions lib/cocoapods/installer/xcode/pods_project_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updating this line to get the dependencies on all the specs lets us define spm dependencies at the subspec level 🙂

Suggested change
spm_dependencies = pod_targets.flat_map { |target| target.root_spec.consumer(target.platform).spm_dependencies }
spm_dependencies = pod_targets.flat_map { |target|
target.specs.flat_map{ |spec| 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ 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)
target_installation_results = InstallationResults.new(pod_target_installation_results, aggregate_target_installation_results)

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

Expand Down
8 changes: 8 additions & 0 deletions lib/cocoapods/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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.
#
Expand Down
2 changes: 1 addition & 1 deletion spec/cocoapods-integration-specs
Submodule cocoapods-integration-specs updated 27 files
+12 −0 install_spm_dependency/after/Podfile.lock
+1 −0 install_spm_dependency/after/Pods/Headers/Private/Reachability/Reachability.h
+1 −0 install_spm_dependency/after/Pods/Headers/Public/Reachability/Reachability.h
+36 −0 install_spm_dependency/after/Pods/Local Podspecs/Reachability.podspec.json
+12 −0 install_spm_dependency/after/Pods/Manifest.lock
+251 −0 install_spm_dependency/after/Pods/Pods.xcodeproj/project.pbxproj
+58 −0 ...m_dependency/after/Pods/Pods.xcodeproj/xcuserdata/INTEGRATION.xcuserdatad/xcschemes/Pods-SampleApp.xcscheme
+58 −0 ...spm_dependency/after/Pods/Pods.xcodeproj/xcuserdata/INTEGRATION.xcuserdatad/xcschemes/Reachability.xcscheme
+21 −0 ..._dependency/after/Pods/Pods.xcodeproj/xcuserdata/INTEGRATION.xcuserdatad/xcschemes/xcschememanagement.plist
+48 −0 install_spm_dependency/after/Pods/Reachability/README.md
+116 −0 install_spm_dependency/after/Pods/Reachability/Reachability.h
+512 −0 install_spm_dependency/after/Pods/Reachability/Reachability.m
+3 −0 install_spm_dependency/after/Pods/Target Support Files/Pods-SampleApp/Pods-SampleApp-acknowledgements.markdown
+29 −0 install_spm_dependency/after/Pods/Target Support Files/Pods-SampleApp/Pods-SampleApp-acknowledgements.plist
+5 −0 install_spm_dependency/after/Pods/Target Support Files/Pods-SampleApp/Pods-SampleApp-dummy.m
+11 −0 install_spm_dependency/after/Pods/Target Support Files/Pods-SampleApp/Pods-SampleApp.debug.xcconfig
+11 −0 install_spm_dependency/after/Pods/Target Support Files/Pods-SampleApp/Pods-SampleApp.release.xcconfig
+5 −0 install_spm_dependency/after/Pods/Target Support Files/Reachability/Reachability-dummy.m
+12 −0 install_spm_dependency/after/Pods/Target Support Files/Reachability/Reachability-prefix.pch
+13 −0 install_spm_dependency/after/Pods/Target Support Files/Reachability/Reachability.debug.xcconfig
+13 −0 install_spm_dependency/after/Pods/Target Support Files/Reachability/Reachability.release.xcconfig
+132 −0 install_spm_dependency/after/SampleApp.xcodeproj/project.pbxproj
+10 −0 install_spm_dependency/after/SampleApp.xcworkspace/contents.xcworkspacedata
+57 −0 install_spm_dependency/after/execution_output.txt
+4 −0 install_spm_dependency/before/Podfile
+18 −0 install_spm_dependency/before/Reachability.podspec
+309 −0 install_spm_dependency/before/SampleApp.xcodeproj/project.pbxproj
5 changes: 5 additions & 0 deletions spec/integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
3 changes: 3 additions & 0 deletions spec/integration/xcodeproj_project_yaml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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