Commit 0ffb7a6b authored by Samuel Giddins's avatar Samuel Giddins

Ensure all user projects are properly integrated

parent 85ef27f5
GIT
remote: https://github.com/CocoaPods/CLAide.git
revision: b44534d04023fbe82182a8be33d5c728f74c1b9c
revision: 4ded02e52c34d5bbe5f6f031d917394286445aa6
branch: master
specs:
claide (0.9.1)
......@@ -24,7 +24,7 @@ GIT
GIT
remote: https://github.com/CocoaPods/Xcodeproj.git
revision: ad8f6b78e424c274b63ff42ff6ad72840cb307a6
revision: eea8f8d58eef635f2cc9121ee1af6a5478a2841c
branch: master
specs:
xcodeproj (0.28.2)
......@@ -154,7 +154,7 @@ GEM
rb-kqueue (>= 0.2)
metaclass (0.0.4)
method_source (0.8.2)
minitest (5.8.2)
minitest (5.8.3)
mocha (1.1.0)
metaclass (~> 0.0.1)
mocha-on-bacon (0.2.2)
......
......@@ -5,6 +5,8 @@ require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/array/conversions'
module Pod
autoload :Deintegrator, 'cocoapods_deintegrate'
class Installer
# The {UserProjectIntegrator} integrates the libraries generated by
# TargetDefinitions of the {Podfile} with their correspondent user
......@@ -63,6 +65,7 @@ module Pod
integrate_user_targets
warn_about_empty_podfile
warn_about_xcconfig_overrides
save_projects
end
#-----------------------------------------------------------------------#
......@@ -112,8 +115,38 @@ module Pod
# @return [void]
#
def integrate_user_targets
targets_to_integrate.sort_by(&:name).each do |target|
TargetIntegrator.new(target).integrate!
target_integrators = targets_to_integrate.sort_by(&:name).map do |target|
TargetIntegrator.new(target)
end
Config.instance.with_changes(:silent => true) do
deintegrator = Deintegrator.new
all_project_targets = target_integrators.map(&:user_project).flat_map(&:native_targets).uniq
all_native_targets = target_integrators.flat_map(&:native_targets).uniq
targets_to_deintegrate = all_project_targets - all_native_targets
targets_to_deintegrate.each do |target|
deintegrator.deintegrate_target(target)
end
end
target_integrators.each(&:integrate!)
end
def save_projects
user_projects.each do |project|
if project.dirty?
project.save
else
# There is a bug in Xcode where the process of deleting and
# re-creating the xcconfig files used in the build
# configuration cause building the user project to fail until
# Xcode is relaunched.
#
# Touching/saving the project causes Xcode to reload these.
#
# https://github.com/CocoaPods/CocoaPods/issues/2665
FileUtils.touch(project.path + 'project.pbxproj')
end
end
end
......@@ -194,6 +227,10 @@ module Pod
targets.map(&:user_project_path).compact.uniq
end
def user_projects
targets.map(&:user_project).compact.uniq
end
def targets_to_integrate
targets.reject { |target| target.target_definition.empty? }
end
......
......@@ -38,34 +38,15 @@ module Pod
#
def integrate!
UI.section(integration_message) do
# TODO: refactor into Xcodeproj https://github.com/CocoaPods/Xcodeproj/issues/202
project_is_dirty = [
XCConfigIntegrator.integrate(target, native_targets),
update_to_cocoapods_0_34,
update_to_cocoapods_0_37_1,
update_to_cocoapods_0_39,
unless native_targets_to_integrate.empty?
XCConfigIntegrator.integrate(target, native_targets)
update_to_cocoapods_0_34
update_to_cocoapods_0_37_1
update_to_cocoapods_0_39
add_pods_library
add_embed_frameworks_script_phase
add_copy_resources_script_phase
add_check_manifest_lock_script_phase
true
end,
].any?
if project_is_dirty
user_project.save
else
# There is a bug in Xcode where the process of deleting and
# re-creating the xcconfig files used in the build
# configuration cause building the user project to fail until
# Xcode is relaunched.
#
# Touching/saving the project causes Xcode to reload these.
#
# https://github.com/CocoaPods/CocoaPods/issues/2665
FileUtils.touch(user_project.path + 'project.pbxproj')
end
end
end
......@@ -95,14 +76,11 @@ module Pod
script_path = target.copy_resources_script_relative_path
shell_script = %("#{script_path}"\n)
changes = false
phases.each do |phase|
unless phase.shell_script == shell_script
phase.shell_script = shell_script
changes = true
end
end
changes
end
# Removes the embed frameworks phase for target types.
......@@ -122,22 +100,16 @@ module Pod
# Adds the embed frameworks script when integrating as a static library.
#
# @return [Bool] whether any changes to the project were made.
#
# @todo This can be removed for CocoaPods 1.0
#
def update_to_cocoapods_0_39
targets_to_embed = native_targets.select do |target|
EMBED_FRAMEWORK_TARGET_TYPES.include?(target.symbol_type)
end
requires_update = targets_to_embed.any? do |target|
!target.shell_script_build_phases.find { |bp| bp.name == EMBED_FRAMEWORK_PHASE_NAME }
end
if requires_update
targets_to_embed.each do |native_target|
add_embed_frameworks_script_phase_to_target(native_target)
end
end
frameworks = user_project.frameworks_group
native_targets.each do |native_target|
......@@ -151,12 +123,9 @@ module Pod
build_file.settings['ATTRIBUTES'].is_a?(Array) &&
build_file.settings['ATTRIBUTES'].include?('Weak')
build_file.settings = nil
requires_update = true
end
end
end
requires_update
end
# Adds spec product reference to the frameworks build phase of the
......@@ -168,7 +137,7 @@ module Pod
#
def add_pods_library
frameworks = user_project.frameworks_group
native_targets_to_integrate.each do |native_target|
native_targets.each do |native_target|
build_phase = native_target.frameworks_build_phase
# Find and delete possible reference for the other product type
......@@ -209,13 +178,10 @@ module Pod
#
# @param [PBXNativeTarget] native_target
#
# @return [Bool] whether any changes to the project were made.
#
def remove_embed_frameworks_script_phase(native_target)
embed_build_phase = native_target.shell_script_build_phases.find { |bp| bp.name == EMBED_FRAMEWORK_PHASE_NAME }
return false unless embed_build_phase.present?
return unless embed_build_phase.present?
native_target.build_phases.delete(embed_build_phase)
true
end
# Adds a shell script build phase responsible to copy the resources
......@@ -226,7 +192,7 @@ module Pod
#
def add_copy_resources_script_phase
phase_name = 'Copy Pods Resources'
native_targets_to_integrate.each do |native_target|
native_targets.each do |native_target|
phase = create_or_update_build_phase(native_target, phase_name)
script_path = target.copy_resources_script_relative_path
phase.shell_script = %("#{script_path}"\n)
......@@ -244,9 +210,9 @@ module Pod
#
def add_check_manifest_lock_script_phase
phase_name = 'Check Pods Manifest.lock'
native_targets_to_integrate.each do |native_target|
native_targets.each do |native_target|
phase = create_or_update_build_phase(native_target, phase_name)
native_target.build_phases.unshift(phase).uniq!
native_target.build_phases.unshift(phase).uniq! unless native_target.build_phases.first == phase
phase.shell_script = <<-SH.strip_heredoc
diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null
if [[ $? != 0 ]] ; then
......@@ -259,9 +225,9 @@ module Pod
end
end
private
public
# @!group Private helpers
# @!group Helpers
#---------------------------------------------------------------------#
# @return [Array<PBXNativeTarget>] The list of all the targets that
......@@ -276,29 +242,11 @@ module Pod
# directory / product bundle.
#
def native_targets_to_embed_in
native_targets_to_integrate.select do |target|
native_targets.select do |target|
EMBED_FRAMEWORK_TARGET_TYPES.include?(target.symbol_type)
end
end
# @return [Array<PBXNativeTarget>] The list of the targets
# that have not been integrated by past installations
# of
#
def native_targets_to_integrate
unless @native_targets_to_integrate
@native_targets_to_integrate = native_targets.reject do |native_target|
native_target.frameworks_build_phase.files.any? do |build_file|
file_ref = build_file.file_ref
file_ref &&
file_ref.isa == 'PBXFileReference' &&
file_ref.display_name == target.product_name
end
end
end
@native_targets_to_integrate
end
# Read the project from the disk to ensure that it is up to date as
# other TargetIntegrators might have modified it.
#
......@@ -308,6 +256,11 @@ module Pod
target.user_project
end
private
# @!group Private Helpers
#---------------------------------------------------------------------#
# @return [Specification::Consumer] the consumer for the specifications.
#
def spec_consumers
......
......@@ -15,17 +15,13 @@ module Pod
# The native targets associated which should be integrated
# with the Pod bundle.
#
# @return [Bool] whether any changes to the project were made.
#
def self.integrate(pod_bundle, targets)
changes = false
targets.each do |target|
target.build_configurations.each do |config|
changes = true if update_to_cocoapods_0_34(pod_bundle, targets)
changes = true if set_target_xcconfig(pod_bundle, target, config)
update_to_cocoapods_0_34(pod_bundle, targets)
set_target_xcconfig(pod_bundle, target, config)
end
end
changes
end
private
......@@ -42,13 +38,10 @@ module Pod
# @param [Array<XcodeProj::PBXNativeTarget>] targets
# The native targets.
#
# @return [Bool] whether any changes to the project were made.
#
# @todo This can be removed for CocoaPods 1.0
#
def self.update_to_cocoapods_0_34(pod_bundle, targets)
sandbox = pod_bundle.sandbox
changes = false
targets.map(&:project).uniq.each do |project|
file_refs = project.files.select do |file_ref|
path = file_ref.path.to_s
......@@ -64,10 +57,7 @@ module Pod
file_ref.remove_from_project
end
end
changes = true unless file_refs.empty?
end
changes
end
# Creates a file reference to the xcconfig generated by
......@@ -83,15 +73,16 @@ module Pod
# @param [Xcodeproj::XCBuildConfiguration] config
# The build configuration.
#
# @return [Boolean] Indicates whether or not any changes were made.
#
def self.set_target_xcconfig(pod_bundle, target, config)
path = pod_bundle.xcconfig_relative_path(config.name)
group = config.project['Pods'] || config.project.new_group('Pods')
file_ref = group.files.find { |f| f.path == path }
if config.base_configuration_reference &&
config.base_configuration_reference != file_ref
unless xcconfig_includes_target_xcconfig?(config.base_configuration_reference, path)
existing = config.base_configuration_reference
if existing && existing != file_ref
if existing.real_path.to_path.start_with?(pod_bundle.support_files_dir.to_path)
existing.path = path
elsif !xcconfig_includes_target_xcconfig?(config.base_configuration_reference, path)
UI.warn 'CocoaPods did not set the base configuration of your ' \
'project because your project already has a custom ' \
'config set. In order for CocoaPods integration to work at ' \
......@@ -102,9 +93,7 @@ module Pod
elsif config.base_configuration_reference.nil? || file_ref.nil?
file_ref ||= group.new_file(path)
config.base_configuration_reference = file_ref
return true
end
false
end
private
......
......@@ -36,7 +36,6 @@ module Pod
end
it 'allows the xcconfig integrator to edit already integrated targets if needed' do
@target_integrator.stubs(:native_targets_to_integrate).returns([])
TargetIntegrator::XCConfigIntegrator.expects(:integrate).with(@pod_bundle, [@target])
@target_integrator.integrate!
end
......@@ -123,11 +122,10 @@ module Pod
it 'does not perform the integration if there are no targets to integrate' do
Installer::UserProjectIntegrator::TargetIntegrator::XCConfigIntegrator.
integrate(@pod_bundle, @target_integrator.send(:native_targets))
@target_integrator.stubs(:native_targets_to_integrate).returns([])
@target_integrator.expects(:add_pods_library).never
@target_integrator.expects(:add_copy_resources_script_phase).never
@target_integrator.send(:user_project).expects(:save).never
@target_integrator.stubs(:native_targets).returns([])
frameworks = @target_integrator.send(:user_project).frameworks_group.children
@target_integrator.integrate!
@target_integrator.send(:user_project).frameworks_group.children.should == frameworks
end
it 'adds an embed frameworks build phase if frameworks are used' do
......@@ -207,13 +205,6 @@ module Pod
@target_integrator.send(:native_targets).map(&:name).should == %w( SampleProject )
end
it 'returns the targets that need to be integrated' do
pods_library = @project.frameworks_group.new_product_ref_for_target('Pods', :static_library)
@target.frameworks_build_phase.add_file_reference(pods_library)
@project.save
@target_integrator.send(:native_targets_to_integrate).map(&:name).should.be.empty
end
it 'is robust against other types of references in the build files of the frameworks build phase' do
build_file = @project.new(Xcodeproj::Project::PBXBuildFile)
build_file.file_ref = @project.new(Xcodeproj::Project::PBXVariantGroup)
......
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