Skip to content

Commit

Permalink
Add Podfile DSL for script_phase
Browse files Browse the repository at this point in the history
  • Loading branch information
dnkoutso committed Aug 22, 2017
1 parent eb21ee8 commit 2ba1e9e
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 0 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 Podfile DSL for `script_phase`
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#389](https://github.com/CocoaPods/Core/pull/389)

* Introduce `static_framework` podspec attribute
[Paul Beusterien](https://github.com/paulb777)
[#386](https://github.com/CocoaPods/Core/pull/386)
Expand Down
42 changes: 42 additions & 0 deletions lib/cocoapods-core/podfile/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,48 @@ def target(name, options = nil)
self.current_target_definition = parent
end

# Adds a script phase to be integrated with this target. A script phase can be used to execute an arbitrary
# script that can use all Xcode environment variables during execution. A target may include multiple script
# phases which they will be added in the order they were declared. Deleting a script phase will effectively remove
# it from the target if it has been added previously.
#
# @example
# script_phase :name => 'HelloWorldScript', :script => 'echo "Hello World"'
#
# @example
# script_phase :name => 'HelloWorldScript', :script => 'puts "Hello World"', :shell_path => '/usr/bin/ruby'
#
# @param [Hash] options
# the options for this script phase.
#
# @option options [String] :name
# the name of the script phase. This option is required.
#
# @option options [String] :script
# the body of the script to execute. This option is required.
#
# @option options [String] :shell_path
# the shell path to use for this script phase, for example `/usr/bin/ruby` to use Ruby for this phase.
#
# @option options [Array<String>] :input_paths
# the input paths to use for script. This is used by Xcode to determine whether to re-execute this
# script phase if the input paths have changed or not.
#
# @option options [Array<String>] :output_paths
# the output paths to use for script. This is used by Xcode to avoid re-executing this script phase if
# none of the output paths have changed.
#
# @option options [Boolean] :show_env_vars_in_log
# whether this script phase should output the environment variables during execution.
#
# @return [void]
#
def script_phase(options)
raise Informative, 'Script phases can only be added within target definitions.' if current_target_definition.root?
raise Informative, 'Script phases cannot be added to abstract targets.' if current_target_definition.abstract?
current_target_definition.store_script_phase(options)
end

# Defines a new abstract target that can be used for convenient
# target dependency inheritance.
#
Expand Down
44 changes: 44 additions & 0 deletions lib/cocoapods-core/podfile/target_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,14 @@ def build_configurations=(hash)

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

# @return [Array<Hash>] The list of the script phases of the target definition.
#
def script_phases
get_hash_value('script_phases') || []
end

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

# @return [Bool] whether the target definition should inhibit warnings
# for a single pod. If inhibit_all_warnings is true, it will
# return true for any asked pod.
Expand Down Expand Up @@ -575,6 +583,41 @@ def store_podspec(options = nil)
end
end

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

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
# The options to use for this script phase. The required keys
# are: `:name`, `:script`, while the optional keys are:
# `:shell_path`, `:input_files`, `:output_files` and `:show_env_vars_in_log`.
#
# @return [void]
#
def store_script_phase(options)
option_keys = options.keys
unrecognized_keys = option_keys - 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}`."
end
missing_required_keys = SCRIPT_PHASE_REQUIRED_KEYS - option_keys
unless missing_required_keys.empty?
raise StandardError, "Missing required shell script phase options `#{missing_required_keys.join(', ')}`"
end
script_phases_hash = get_hash_value('script_phases', [])
if script_phases_hash.map { |script_phase_options| script_phase_options[:name] }.include?(options[:name])
raise StandardError, "Script phase with name `#{options[:name]}` name already present for target `#{name}`."
end
script_phases_hash << options
end

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

public
Expand All @@ -595,6 +638,7 @@ def store_podspec(options = nil)
user_project_path
build_configurations
dependencies
script_phases
children
configuration_pod_whitelist
uses_frameworks
Expand Down
20 changes: 20 additions & 0 deletions spec/podfile/dsl_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,26 @@ module Pod
end
end

describe 'script phases' do
it 'raises when adding a script phase to the root target definition' do
should.raise(Informative) do
Podfile.new do
script_phase :name => 'PhaseName', :script => 'echo "Hello World"'
end
end.message.should == 'Script phases can only be added within target definitions.'
end

it 'raises when adding a script phase to an abstract target' do
should.raise(Informative) do
Podfile.new do
abstract_target 'AbstractTarget' do
script_phase :name => 'PhaseName', :script => 'echo "Hello World"'
end
end
end.message.should == 'Script phases cannot be added to abstract targets.'
end
end

#-------------------------------------------------------------------------#
end
end
35 changes: 35 additions & 0 deletions spec/podfile/target_definition_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,41 @@ module Pod

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

it 'raises if script phase is missing required key' do
e = lambda { @parent.store_script_phase(:name => 'PhaseName') }.should.raise Podfile::StandardError
e.message.should == 'Missing required shell script phase options `script`'
end

it 'raises if script phase includes an unrecognized key' do
e = lambda { @parent.store_script_phase(:name => 'PhaseName', :unknown => 'Unknown') }.should.raise Podfile::StandardError
e.message.should == 'Unrecognized options `[:unknown]` in shell script `{:name=>"PhaseName", :unknown=>"Unknown"}` within `MyApp` target. ' \
'Available options are `[:name, :script, :shell_path, :input_files, :output_files, :show_env_vars_in_log]`.'
end

it 'raises if the same script phase name already exists' do
e = lambda do
@parent.store_script_phase(:name => 'PhaseName', :script => 'echo "Hello World"')
@parent.store_script_phase(:name => 'PhaseName', :script => 'echo "Hello World"')
end.should.raise Podfile::StandardError
e.message.should == 'Script phase with name `PhaseName` name already present for target `MyApp`.'
end

it 'stores a script phase if requirements are provided' do
@parent.store_script_phase(:name => 'PhaseName', :script => 'echo "Hello World"')
@parent.script_phases.should == [
{ :name => 'PhaseName', :script => 'echo "Hello World"' },
]
end

it 'stores a script phase with requirements and optional keys' do
@parent.store_script_phase(:name => 'PhaseName', :script => 'echo "Hello World"', :shell_path => :'/usr/bin/ruby')
@parent.script_phases.should == [
{ :name => 'PhaseName', :script => 'echo "Hello World"', :shell_path => :'/usr/bin/ruby' },
]
end

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

it 'whitelists pods by default' do
@parent.store_pod('ObjectiveSugar')
@parent.should.pod_whitelisted_for_configuration?('ObjectiveSugar', 'Release')
Expand Down

0 comments on commit 2ba1e9e

Please sign in to comment.