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 Jul 14, 2017
1 parent 4a2de57 commit 165c45a
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 1 deletion.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

##### Enhancements

* None.
* Add Podfile DSL for `script_phase`
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#389](https://github.com/CocoaPods/Core/pull/389)

##### Bug Fixes

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
43 changes: 43 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,40 @@ 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
unless option_keys.all? { |key| ALL_SCRIPT_PHASE_KEYS.include?(key) }
raise StandardError, 'Unrecognized options for the shell script ' \
"method `#{options}`"
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 +637,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
34 changes: 34 additions & 0 deletions spec/podfile/target_definition_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,40 @@ 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 unknown key' do
e = lambda { @parent.store_script_phase(:name => 'PhaseName', :unknown => 'Unknown') }.should.raise Podfile::StandardError
e.message.should == 'Unrecognized options for the shell script method `{:name=>"PhaseName", :unknown=>"Unknown"}`'
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 165c45a

Please sign in to comment.