Add custom shell script integration from Podfile

parent fcb21f44
......@@ -8,6 +8,10 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
##### Enhancements
* Add custom shell script integration from Podfile
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#6820](https://github.com/CocoaPods/CocoaPods/pull/6820)
* Show full requirement trees when a version conflict is encountered during
dependency resolution.
[Samuel Giddins](https://github.com/segiddins)
......
......@@ -7,7 +7,7 @@ GIT
GIT
remote: https://github.com/CocoaPods/Core.git
revision: eb21ee8e85201c20aa5d58f0573948204237fd64
revision: bdec7d4861b2b1c669748300da07bf12c51cbf27
branch: master
specs:
cocoapods-core (1.3.1)
......
......@@ -9,10 +9,15 @@ module Pod
class TargetIntegrator
autoload :XCConfigIntegrator, 'cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator'
# @return [String] the PACKAGE emoji to use as prefix for every build phase added to the user project
# @return [String] the string to use as prefix for every build phase added to the user project
#
BUILD_PHASE_PREFIX = '[CP] '.freeze
# @return [String] the string to use as prefix for every build phase declared by the user within a podfile
# or podspec.
#
USER_BUILD_PHASE_PREFIX = '[CP-User] '.freeze
# @return [String] the name of the check manifest phase
#
CHECK_MANIFEST_PHASE_NAME = 'Check Pods Manifest.lock'.freeze
......@@ -67,7 +72,7 @@ module Pod
# @return [void]
#
def add_embed_frameworks_script_phase_to_target(native_target, script_path, input_paths = [], output_paths = [])
phase = TargetIntegrator.create_or_update_build_phase(native_target, EMBED_FRAMEWORK_PHASE_NAME)
phase = TargetIntegrator.create_or_update_build_phase(native_target, BUILD_PHASE_PREFIX + EMBED_FRAMEWORK_PHASE_NAME)
phase.shell_script = %("#{script_path}"\n)
unless input_paths.empty?
phase.input_paths = input_paths
......@@ -108,7 +113,7 @@ module Pod
#
def add_copy_resources_script_phase_to_target(native_target, script_path, input_paths = [], output_paths = [])
phase_name = COPY_PODS_RESOURCES_PHASE_NAME
phase = TargetIntegrator.create_or_update_build_phase(native_target, phase_name)
phase = TargetIntegrator.create_or_update_build_phase(native_target, BUILD_PHASE_PREFIX + phase_name)
phase.shell_script = %("#{script_path}"\n)
unless input_paths.empty?
phase.input_paths = input_paths
......@@ -132,12 +137,11 @@ module Pod
# @return [void]
#
def create_or_update_build_phase(native_target, phase_name, phase_class = Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
prefixed_phase_name = BUILD_PHASE_PREFIX + phase_name
build_phases = native_target.build_phases.grep(phase_class)
build_phases.find { |phase| phase.name && phase.name.end_with?(phase_name) }.tap { |p| p.name = prefixed_phase_name if p } ||
build_phases.find { |phase| phase.name && phase.name.end_with?(phase_name) }.tap { |p| p.name = phase_name if p } ||
native_target.project.new(phase_class).tap do |phase|
UI.message("Adding Build Phase '#{prefixed_phase_name}' to project.") do
phase.name = prefixed_phase_name
UI.message("Adding Build Phase '#{phase_name}' to project.") do
phase.name = phase_name
phase.show_env_vars_in_log = '0'
native_target.build_phases << phase
end
......@@ -160,6 +164,7 @@ module Pod
remove_embed_frameworks_script_phase_from_embedded_targets
add_copy_resources_script_phase
add_check_manifest_lock_script_phase
update_target_script_phases
end
end
......@@ -255,6 +260,46 @@ module Pod
end
end
# Updates all target script phases for the current target, including creating or updating, deleting
# and re-ordering.
#
# @return [void]
#
def update_target_script_phases
target_definition_script_phases = target.target_definition.script_phases
target_definition_script_phase_names = target_definition_script_phases.map { |k| k[:name] }
native_targets.each do |native_target|
# Delete script phases no longer present in the target definition.
native_target_script_phases = native_target.shell_script_build_phases.select { |bp| !bp.name.nil? && bp.name.start_with?(USER_BUILD_PHASE_PREFIX) }
native_target_script_phases.each do |script_phase|
script_phase_name_without_prefix = script_phase.name.sub(USER_BUILD_PHASE_PREFIX, '')
unless target_definition_script_phase_names.include?(script_phase_name_without_prefix)
native_target.build_phases.delete(script_phase)
end
end
# Create or update the ones that are expected to be.
target_definition_script_phases.each do |td_script_phase|
phase = TargetIntegrator.create_or_update_build_phase(native_target, USER_BUILD_PHASE_PREFIX + td_script_phase[:name])
phase.shell_script = td_script_phase[:script]
phase.shell_path = td_script_phase[:shell_path] if td_script_phase.key?(:shell_path)
phase.input_paths = td_script_phase[:input_files] if td_script_phase.key?(:input_files)
phase.output_paths = td_script_phase[:output_files] if td_script_phase.key?(:output_files)
phase.show_env_vars_in_log = td_script_phase[:show_env_vars_in_log] ? '1' : '0' if td_script_phase.key?(:show_env_vars_in_log)
end
# Move script phases to their correct index if the order has changed.
offset = native_target.build_phases.count - target_definition_script_phases.count
target_definition_script_phases.each_with_index do |td_script_phase, index|
current_index = native_target.build_phases.index do |bp|
bp.is_a?(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) && bp.name.sub(USER_BUILD_PHASE_PREFIX, '') == td_script_phase[:name]
end
expected_index = offset + index
native_target.build_phases.insert(expected_index, native_target.build_phases.delete_at(current_index)) if current_index != expected_index
end
end
end
# Adds a shell script build phase responsible for checking if the Pods
# locked in the Pods/Manifest.lock file are in sync with the Pods defined
# in the Podfile.lock.
......@@ -267,7 +312,7 @@ module Pod
def add_check_manifest_lock_script_phase
phase_name = CHECK_MANIFEST_PHASE_NAME
native_targets.each do |native_target|
phase = TargetIntegrator.create_or_update_build_phase(native_target, phase_name)
phase = TargetIntegrator.create_or_update_build_phase(native_target, BUILD_PHASE_PREFIX + phase_name)
native_target.build_phases.unshift(phase).uniq! unless native_target.build_phases.first == phase
phase.shell_script = <<-SH.strip_heredoc
diff "${PODS_PODFILE_DIR_PATH}/Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null
......
......@@ -29,12 +29,14 @@ module Pod
@target_integrator.stubs(method)
end
@phase_prefix = Installer::UserProjectIntegrator::TargetIntegrator::BUILD_PHASE_PREFIX
@user_phase_prefix = Installer::UserProjectIntegrator::TargetIntegrator::USER_BUILD_PHASE_PREFIX
@embed_framework_phase_name = @phase_prefix +
Installer::UserProjectIntegrator::TargetIntegrator::EMBED_FRAMEWORK_PHASE_NAME
@copy_pods_resources_phase_name = @phase_prefix +
Installer::UserProjectIntegrator::TargetIntegrator::COPY_PODS_RESOURCES_PHASE_NAME
@check_manifest_phase_name = @phase_prefix +
Installer::UserProjectIntegrator::TargetIntegrator::CHECK_MANIFEST_PHASE_NAME
@user_script_phase_name = @user_phase_prefix + 'Custom Script'
end
describe '#integrate!' do
......@@ -366,6 +368,105 @@ module Pod
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReleaseVendoredFramework.framework
)
end
it 'adds a custom shell script phase' do
@pod_bundle.target_definition.stubs(:script_phases).returns([:name => 'Custom Script', :script => 'echo "Hello World"'])
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
phase = target.shell_script_build_phases.find { |bp| bp.name == @user_script_phase_name }
phase.name.should == '[CP-User] Custom Script'
phase.shell_script.should == 'echo "Hello World"'
end
it 'removes outdated custom shell script phases' do
@pod_bundle.target_definition.stubs(:script_phases).returns([:name => 'Custom Script', :script => 'echo "Hello World"'])
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
target.shell_script_build_phases.find { |bp| bp.name == @user_script_phase_name }.should.not.be.nil
@pod_bundle.target_definition.stubs(:script_phases).returns([])
@target_integrator.integrate!
target.shell_script_build_phases.find { |bp| bp.name == @user_script_phase_name }.should.be.nil
end
it 'moves custom shell scripts to their correct index' do
shell_script_one = { :name => 'Custom Script', :script => 'echo "Hello World"' }
shell_script_two = { :name => 'Custom Script 2', :script => 'echo "Hello Aliens"' }
@pod_bundle.target_definition.stubs(:script_phases).returns([shell_script_one, shell_script_two])
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
target.shell_script_build_phases.map(&:name).should == [
'[CP] Check Pods Manifest.lock',
'[CP] Embed Pods Frameworks',
'[CP] Copy Pods Resources',
'[CP-User] Custom Script',
'[CP-User] Custom Script 2',
]
shell_script_one_uuid = target.shell_script_build_phases[3].uuid
shell_script_two_uuid = target.shell_script_build_phases[4].uuid
@pod_bundle.target_definition.stubs(:script_phases).returns([shell_script_two, shell_script_one])
@target_integrator.integrate!
target.shell_script_build_phases.map(&:name).should == [
'[CP] Check Pods Manifest.lock',
'[CP] Embed Pods Frameworks',
'[CP] Copy Pods Resources',
'[CP-User] Custom Script 2',
'[CP-User] Custom Script',
]
target.shell_script_build_phases[3].uuid.should == shell_script_two_uuid
target.shell_script_build_phases[4].uuid.should == shell_script_one_uuid
end
it 'adds, removes and moves custom shell script phases' do
shell_script_one = { :name => 'Custom Script', :script => 'echo "Hello World"' }
shell_script_two = { :name => 'Custom Script 2', :script => 'echo "Hello Aliens"' }
shell_script_three = { :name => 'Custom Script 3', :script => 'echo "Hello Universe"' }
shell_script_four = { :name => 'Custom Script 4', :script => 'echo "Ran out of Hellos"' }
@pod_bundle.target_definition.stubs(:script_phases).returns([shell_script_one, shell_script_two, shell_script_three])
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
target.shell_script_build_phases.map(&:name).should == [
'[CP] Check Pods Manifest.lock',
'[CP] Embed Pods Frameworks',
'[CP] Copy Pods Resources',
'[CP-User] Custom Script',
'[CP-User] Custom Script 2',
'[CP-User] Custom Script 3',
]
@pod_bundle.target_definition.stubs(:script_phases).returns([shell_script_two, shell_script_four])
@target_integrator.integrate!
target.shell_script_build_phases.map(&:name).should == [
'[CP] Check Pods Manifest.lock',
'[CP] Embed Pods Frameworks',
'[CP] Copy Pods Resources',
'[CP-User] Custom Script 2',
'[CP-User] Custom Script 4',
]
end
it 'does not touch non cocoapods shell script phases' do
@pod_bundle.target_definition.stubs(:script_phases).returns([:name => 'Custom Script', :script => 'echo "Hello World"'])
target = @target_integrator.send(:native_targets).first
target.new_shell_script_build_phase('User Script Phase 1')
target.new_shell_script_build_phase('User Script Phase 2')
@target_integrator.integrate!
target.shell_script_build_phases.map(&:name).should == [
'[CP] Check Pods Manifest.lock',
'User Script Phase 1',
'User Script Phase 2',
'[CP] Embed Pods Frameworks',
'[CP] Copy Pods Resources',
'[CP-User] Custom Script',
]
@pod_bundle.target_definition.stubs(:script_phases).returns([])
@target_integrator.integrate!
target.shell_script_build_phases.map(&:name).should == [
'[CP] Check Pods Manifest.lock',
'User Script Phase 1',
'User Script Phase 2',
'[CP] Embed Pods Frameworks',
'[CP] Copy Pods Resources',
]
end
end
describe 'Private helpers' do
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment