Skip to content

Commit

Permalink
Add podspec script_phases DSL
Browse files Browse the repository at this point in the history
  • Loading branch information
dnkoutso committed Sep 29, 2017
1 parent 283ac03 commit 6906c4b
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 14 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

##### Enhancements

* Add podspec `script_phases` DSL
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#413](https://github.com/CocoaPods/Core/pull/413)

* Update commments/docs to indicate prefix_header=false will skip pch generation
[Paul Beusterien](https://github.com/paulb777)
[#412](https://github.com/CocoaPods/Core/pull/412)
Expand Down
12 changes: 3 additions & 9 deletions lib/cocoapods-core/podfile/target_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -585,12 +585,6 @@ def store_podspec(options = nil)

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

SCRIPT_PHASE_REQUIRED_KEYS = [:name, :script].freeze

SCRIPT_PHASE_OPTIONAL_KEYS = [:shell_path, :input_files, :output_files, :show_env_vars_in_log].freeze

ALL_SCRIPT_PHASE_KEYS = (SCRIPT_PHASE_REQUIRED_KEYS + SCRIPT_PHASE_OPTIONAL_KEYS).freeze

# Stores the script phase to add for this target definition.
#
# @param [Hash] options
Expand All @@ -602,12 +596,12 @@ def store_podspec(options = nil)
#
def store_script_phase(options)
option_keys = options.keys
unrecognized_keys = option_keys - ALL_SCRIPT_PHASE_KEYS
unrecognized_keys = option_keys - Specification::ALL_SCRIPT_PHASE_KEYS
unless unrecognized_keys.empty?
raise StandardError, "Unrecognized options `#{unrecognized_keys}` in shell script `#{options}` within `#{name}` target. " \
"Available options are `#{ALL_SCRIPT_PHASE_KEYS}`."
"Available options are `#{Specification::ALL_SCRIPT_PHASE_KEYS}`."
end
missing_required_keys = SCRIPT_PHASE_REQUIRED_KEYS - option_keys
missing_required_keys = Specification::SCRIPT_PHASE_REQUIRED_KEYS - option_keys
unless missing_required_keys.empty?
raise StandardError, "Missing required shell script phase options `#{missing_required_keys.join(', ')}`"
end
Expand Down
8 changes: 7 additions & 1 deletion lib/cocoapods-core/specification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,12 @@ def prefix_header_file
attributes_hash['prefix_header_file']
end

# @return [Hash{String=>String}] The script_phases value.
#
def script_phases
attributes_hash['script_phases']
end

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

public
Expand Down Expand Up @@ -462,7 +468,7 @@ def platform_hash
# @param [Object] value
# the value to store.
#
# @param [Symbol] platform.
# @param [Symbol] platform_name
# If provided the attribute is stored only for the given platform.
#
# @note If the provides value is Hash the keys are converted to a string.
Expand Down
24 changes: 24 additions & 0 deletions lib/cocoapods-core/specification/consumer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ def user_target_xcconfig
#
spec_attr_accessor :resource_bundles

# @return [Array<Hash{Symbol=>String}>] An array of hashes where each hash
# represents a script phase.
#
spec_attr_accessor :script_phases

# @return [Array<String>] A hash where the key represents the
# paths of the resources to copy and the values the paths of
# the resources that should be copied.
Expand Down Expand Up @@ -362,6 +367,25 @@ def _prepare_prefix_header_contents(value)
end
end

# Normalizes script phases value into an array of hashes where each hash represents the entire script phase.
#
# @param [Hash{String=>String}] value.
# The value of the attribute as specified by the user.
#
# @return [Array<Hash{Symbol=>String}>] the normalized script phases array.
#
def _prepare_script_phases(value)
if value
value.map do |name, options|
if options.is_a?(String)
{ :name => name, :script => options }
else
DSL::RootAttributesAccessors.convert_keys_to_symbol(options.dup.merge!(:name => name))
end
end
end
end

# Ensures that the file patterns of the resource bundles are contained in
# an array.
#
Expand Down
43 changes: 42 additions & 1 deletion lib/cocoapods-core/specification/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1134,7 +1134,7 @@ def dependency(*args)

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

# @!method resource_bundles=(*frameworks)
# @!method resource_bundles=(*resource_bundles)
#
# This attribute allows to define the name and the file of the resource
# bundles which should be built for the Pod. They are specified as a
Expand Down Expand Up @@ -1272,6 +1272,47 @@ def dependency(*args)
attribute :module_map,
:root_only => true

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

SCRIPT_PHASE_REQUIRED_KEYS = [:name, :script].freeze

SCRIPT_PHASE_OPTIONAL_KEYS = [:shell_path, :input_files, :output_files, :show_env_vars_in_log].freeze

ALL_SCRIPT_PHASE_KEYS = (SCRIPT_PHASE_REQUIRED_KEYS + SCRIPT_PHASE_OPTIONAL_KEYS).freeze

# @!method script_phases=(*script_phases)
#
# This attribute allows to define a script phase to execute as part of compilation of the Pod.
# Unlike a prepare command, script phases execute as part of `xcodebuild` they can also utilize all environment
# variables that are set during compilation.
#
# A Pod can provide multiple script phases to execute and they will be added in the order they were
# declared.
#
# @example
#
# spec.script_phase = { 'Hello World' => 'echo "Hello World"' }
#
# @example
#
# spec.script_phase = { 'Hello Ruby World' => { :script => 'puts "Hello World"', :shell_path => '/usr/bin/ruby' } }
#
# @example
#
# spec.script_phases = {
# 'Hello World' => 'echo "Hello World"',
# 'Hello Ruby World' => { :script => 'puts "Hello World"', :shell_path => '/usr/bin/ruby' }
# }
#
# @param [Hash{String=>String}] script_phases
# A hash where the keys are the names of the script phases
# and the values represent the content and additional options.
#
attribute :script_phases,
:types => [String, Hash],
:container => Array,
:singularize => true

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

# @!group Subspecs
Expand Down
17 changes: 17 additions & 0 deletions lib/cocoapods-core/specification/linter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,23 @@ def _validate_test_type(t)
end
end

# Performs validations related to the `script_phases` attribute.
#
def _validate_script_phases(s)
s.each do |script_phase|
keys = script_phase.keys
unrecognized_keys = keys - Specification::ALL_SCRIPT_PHASE_KEYS
unless unrecognized_keys.empty?
results.add_error('script_phases', "Unrecognized options `#{unrecognized_keys}` in script phase `#{script_phase[:name]}`. " \
"Available options are `#{Specification::ALL_SCRIPT_PHASE_KEYS}`.")
end
missing_required_keys = Specification::SCRIPT_PHASE_REQUIRED_KEYS - keys
unless missing_required_keys.empty?
results.add_error('script_phases', "Missing required shell script phase options `#{missing_required_keys.join(', ')}` in script phase `#{script_phase[:name]}`.")
end
end
end

# Performs validations related to github sources.
#
def perform_github_source_checks(s)
Expand Down
2 changes: 0 additions & 2 deletions lib/cocoapods-core/specification/root_attribute_accessors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,6 @@ def convert_keys_to_symbol(value)
end
result
end

#---------------------------------------------------------------------#
end
end
end
Expand Down
38 changes: 38 additions & 0 deletions spec/specification/consumer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,44 @@ module Pod
test_consumer = Specification::Consumer.new(test_spec, :ios)
test_consumer.requires_app_host?.should.be.true
end

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

it 'returns the script phases in correct format when using a string for value' do
@spec.script_phases = { 'HelloWorld' => 'echo "Hello World"' }
@consumer.script_phases.should == [{ :name => 'HelloWorld', :script => 'echo "Hello World"' }]
end

it 'returns the script phases in correct format when using a hash for value' do
@spec.script_phases = { 'HelloWorld' => { :script => 'echo "Hello World"', :shell_path => 'usr/bin/ruby' } }
@consumer.script_phases.should == [{ :name => 'HelloWorld', :script => 'echo "Hello World"', :shell_path => 'usr/bin/ruby' }]
end

it 'returns the script phases in correct format when using both string and hash for values' do
@spec.script_phases = { 'HelloWorld' => 'echo "Hello World"', 'HelloWorld2' => { :script => 'echo "Hello World"' } }
@consumer.script_phases.should == [
{ :name => 'HelloWorld', :script => 'echo "Hello World"' },
{ :name => 'HelloWorld2', :script => 'echo "Hello World"' },
]
end

it 'handles multi-platform script phases' do
@spec.ios.script_phases = { 'HelloWorld' => 'echo "Hello World iOS"' }
@consumer.script_phases.should == [{ :name => 'HelloWorld', :script => 'echo "Hello World iOS"' }]
end

it 'merges multi platform script phases if needed' do
@spec.script_phases = { 'HelloWorld' => 'echo "Hello World"' }
@spec.ios.script_phases = { 'HelloWorld-iOS' => 'echo "Hello World iOS"' }
@consumer.script_phases.should == [
{ :name => 'HelloWorld', :script => 'echo "Hello World"' },
{ :name => 'HelloWorld-iOS', :script => 'echo "Hello World iOS"' },
]
end

it 'returns the empty hash if no script phases have been specified' do
@consumer.script_phases.should == []
end
end

#-------------------------------------------------------------------------#
Expand Down
12 changes: 11 additions & 1 deletion spec/specification/dsl_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,16 @@ module Pod
@spec.module_map = 'module.modulemap'
@spec.attributes_hash['module_map'].should == 'module.modulemap'
end

it 'allows to specify the script phases shipped with the Pod' do
@spec.script_phases = { 'HelloWorld' => 'echo "Hello World"' }
@spec.attributes_hash['script_phases'].should == { 'HelloWorld' => 'echo "Hello World"' }
end

it 'allows to specify the script phases shipped with the Pod as a hash' do
@spec.script_phases = { 'HelloWorld' => { :script => 'puts "Hello World"', :shell_path => '/usr/bin/ruby' } }
@spec.attributes_hash['script_phases'].should == { 'HelloWorld' => { 'script' => 'puts "Hello World"', 'shell_path' => '/usr/bin/ruby' } }
end
end

#-----------------------------------------------------------------------------#
Expand Down Expand Up @@ -464,7 +474,7 @@ module Pod
end
singularized.map { |attr| attr.name.to_s }.sort.should == %w(
authors compiler_flags default_subspecs frameworks libraries
preserve_paths resource_bundles resources screenshots
preserve_paths resource_bundles resources screenshots script_phases
vendored_frameworks vendored_libraries weak_frameworks
)
end
Expand Down
29 changes: 29 additions & 0 deletions spec/specification/json_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,18 @@ module Pod
}]
end

it 'writes script phases' do
@spec.script_phases = {
'Hello World' => 'echo "Hello World"',
'Hello Ruby World' => { :script => 'puts "Hello World"', :shell_path => '/usr/bin/ruby' },
}
hash = @spec.to_hash
hash['script_phases'].should == {
'Hello World' => 'echo "Hello World"',
'Hello Ruby World' => { 'script' => 'puts "Hello World"', 'shell_path' => '/usr/bin/ruby' },
}
end

it 'writes test type for test subspec' do
@spec.test_spec {}
hash = @spec.to_hash
Expand Down Expand Up @@ -158,6 +170,23 @@ module Pod
result.test_specs.first.test_type.should.equal :unit
end

it 'can load script phases from hash' do
hash = {
'name' => 'BananaLib',
'version' => '1.0',
'script_phases' => {
'Hello World' => 'echo "Hello World"',
'Hello Ruby World' => { 'script' => 'puts "Hello World"', 'shell_path' => '/usr/bin/ruby' },
},
}
result = Specification.from_hash(hash)
result.script_phases.count.should.equal 2
result.script_phases.should == {
'Hello World' => 'echo "Hello World"',
'Hello Ruby World' => { 'script' => 'puts "Hello World"', 'shell_path' => '/usr/bin/ruby' },
}
end

it 'can load test specification from 1.3.0 hash format' do
hash = {
'name' => 'BananaLib',
Expand Down
12 changes: 12 additions & 0 deletions spec/specification/linter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,18 @@ def result_should_include(*values)

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

it 'checks script phases include the required keys' do
@spec.script_phases = { 'HelloWorld' => {} }
result_should_include('script_phases', 'Missing required shell script phase options `script` in script phase `HelloWorld`')
end

it 'checks script phases include the required keys' do
@spec.script_phases = { 'HelloWorld' => {} }
result_should_include('script_phases', 'Missing required shell script phase options `script` in script phase `HelloWorld`')
end

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

it 'accepts valid frameworks' do
@spec.frameworks = %w(AddressBook Audio-Frameworks)
@linter.lint
Expand Down

0 comments on commit 6906c4b

Please sign in to comment.