Skip to content

Commit

Permalink
SPM: allow specs to declare Swift Package Manager depenencies with sp…
Browse files Browse the repository at this point in the history
…m_dependency
  • Loading branch information
mfazekas committed Jun 15, 2023
1 parent 8428ea5 commit 0c160f6
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/cocoapods-core/specification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require 'cocoapods-core/specification/root_attribute_accessors'
require 'cocoapods-core/specification/set'
require 'cocoapods-core/specification/json'
require 'cocoapods-core/specification/spm_requirement'

module Pod
# The Specification provides a DSL to describe a Pod. A pod is defined as a
Expand Down
9 changes: 9 additions & 0 deletions lib/cocoapods-core/specification/consumer.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'cocoapods-core/specification/root_attribute_accessors'
require 'cocoapods-core/specification/spm_requirement'

module Pod
class Specification
Expand Down Expand Up @@ -234,6 +235,14 @@ def dependencies
end
end

#-----------------------------------------------------------------------#
def spm_dependencies
value = value_for_attribute(:spm_dependencies)
value.map do |spm_dependency|
{:url => spm_dependency[:url], :requirement => Pod::Specification::SpmRequirement.new(spm_dependency[:requirement]), :products => spm_dependency[:products]}
end
end

# Raw values need to be prepared as soon as they are read so they can be
# safely merged to support multi platform attributes and inheritance
#-----------------------------------------------------------------------#
Expand Down
28 changes: 28 additions & 0 deletions lib/cocoapods-core/specification/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,34 @@ def dependency=(args)

#------------------#

attribute :spm_dependencies,
:container => Array,
:inherited => true

# Dependency on Swift Manager Packages.
#
# ---
#
# Dependencies should specify versions requirements.
#
# @example
# spec.spm_dependency(
# :url => 'https://github.com/apple/swift-atomics.git',
# :requirement' => {:kind => 'upToNextMajor', :minimumVersion => '1.1.0'},
# :products' => ['Atomics']
# )

def spm_dependency(url: , requirement:, products:)
attributes_hash['spm_dependencies'] ||= []
attributes_hash['spm_dependencies'] << {
:url => url,
:requirement => requirement,
:products => products,
}
end

#------------------#

# @!method info_plist=(info_plist)
#
# Key-Value pairs to add to the generated `Info.plist`.
Expand Down
22 changes: 22 additions & 0 deletions lib/cocoapods-core/specification/linter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,28 @@ def _validate_scheme(s)
end
end


# Performs validations related to the `spm_dependencies` attribute.
#
def _validate_spm_dependencies(s)
unless s.empty?
s.each do |spm_dependency|
if spm_dependency[:url].nil?
results.add_error('spm_dependencies', 'SPM dependencies should specify a url.')
end
if spm_dependency[:requirement].nil?
results.add_error('spm_dependencies', 'SPM dependencies should specify a requirement.')
end
if requirement_errors = SpmRequirement.validate(spm_dependency[:requirement])
results.add_error('spm_dependencies', requirement_errors)
end
if spm_dependency[:products].nil?
results.add_error('spm_dependencies', 'SPM dependencies should specify products.')
end
end
end
end

# Performs validations related to github sources.
#
def perform_github_source_checks(s)
Expand Down
51 changes: 51 additions & 0 deletions lib/cocoapods-core/specification/spm_requirement.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module Pod
class Specification
# This class validates and represents swift package manager dependecy requirements
class SpmRequirement
REQUIRED_KEYS = {
:upToNextMajorVersion => [:minimumVersion],
:upToNextMinorVersion => [:minimumVersion],
:exactVersion => [:version],
:range => %i[minimumVersion maximumVersion],
}.freeze

def initialize(requirement_hash)
@requirement = requirement_hash
validate
end

def kind
@requirement[:kind]
end

def ==(other)
@requirement == other.instance_variable_get(:@requirement)
end

def validate
raise 'Kind should be string' unless kind.is_a?(String)
raise "Unknown requirement kind #{kind}" if REQUIRED_KEYS[kind.to_sym].nil?

REQUIRED_KEYS[kind.to_sym].each do |key|
raise "Missing key #{key} for requirement #{@requirement}" unless @requirement[key]
end
end

def to_h
@requirement.map { |k,v| [k.to_s, v.to_s] }.to_h
end

def self.validate(requirement_hash)
if (requirement_hash.is_a? SpmRequirement)
requirement_hash.validate
nil
else
new(requirement_hash)
nil
end
rescue => e
e.message
end
end
end
end
24 changes: 24 additions & 0 deletions spec/specification/consumer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,30 @@ module Pod

#-------------------------------------------------------------------------#

describe 'SPM Dependencies' do
before do
@spec = Spec.new do |s|
s.name = 'Pod'
s.spm_dependency(
:url => "https://github.com/apple/example-package-fisheryates.git",
:requirement => { :kind => "upToNextMajorVersion", :minimumVersion => "1.0.0" },
:products => ["FisherYates"],
)
end
@consumer = Specification::Consumer.new(@spec, :ios)
end

it 'returns the spm_dependencies with SpmRequirement' do
@consumer.spm_dependencies.should == [{
:url => "https://github.com/apple/example-package-fisheryates.git",
:requirement => Specification::SpmRequirement.new({ :kind => "upToNextMajorVersion", :minimumVersion => "1.0.0" }),
:products => ["FisherYates"],
}]
end
end

#-------------------------------------------------------------------------#

describe 'Private helpers' do
before do
@spec = Spec.new do |s|
Expand Down
11 changes: 11 additions & 0 deletions spec/specification/dsl_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,17 @@ module Pod

#------------------#

describe 'spm_dependency' do
it 'allows to specify a single spm_dependency' do
@spec.spm_dependency(:url => "foo", :requirement => {:kind => "upToNextMajorVersion", :minimumVersion => "1.0.0"}, :products => ["Foo"])
@spec.attributes_hash['spm_dependencies'].should == [
{ :url => 'foo', :requirement => {:kind => "upToNextMajorVersion", :minimumVersion => "1.0.0"}, :products => ["Foo"] },
]
end
end

#------------------#

it 'allows to specify whether the specification requires ARC' do
@spec.requires_arc = false
@spec.attributes_hash['requires_arc'].should == false
Expand Down
12 changes: 12 additions & 0 deletions spec/specification/json_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,18 @@ module Pod
result.swift_versions.map(&:to_s).should == %w(3.2 4.0 4.1)
result.swift_version.to_s.should == '4.1'
end

describe 'Swift Package Manger dependencies' do
it 'writes spm dependency' do
@spec.spm_dependency(
:url => 'http://github.com/foo/foo',
:requirement => {:kind => 'upToNextMajor', :minimumVersion => '1.0.0'},
:products => ['Foo'],
)
hash = @spec.to_hash
hash['spm_dependencies'].should == [{:url => 'http://github.com/foo/foo', :requirement => {:kind => 'upToNextMajor', :minimumVersion => '1.0.0'}, :products => ['Foo']}]
end
end
end
end
end
Expand Down
7 changes: 7 additions & 0 deletions spec/specification/linter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,13 @@ def result_should_include(*values)
@spec.compiler_flags = '-some_flag', '-another -Wno_flags'
result_should_include('warnings', 'disabled', 'compiler_flags')
end

#------------------#

it 'check if spm dependency requirement upToNextMinorVersion has a minimumVersion key' do
@spec.spm_dependency(:url => 'https://github.com/foo/foo', :requirement => { :kind => 'upToNextMinorVersion' }, :products => ['Foo'])
result_should_include('missing key minimumVersion')
end
end

#--------------------------------------#
Expand Down

0 comments on commit 0c160f6

Please sign in to comment.