Commit c5d13de4 authored by Fabio Pelosin's avatar Fabio Pelosin

Completed support for Xcodeproj refactor.

parent 4fb9ca0a
...@@ -72,14 +72,16 @@ module Pod ...@@ -72,14 +72,16 @@ module Pod
# #
def generate_xcconfig(pods, sandbox) def generate_xcconfig(pods, sandbox)
xcconfig = Xcodeproj::Config.new({ xcconfig = Xcodeproj::Config.new({
'PODS_ROOT' => @target_definition.relative_pods_root, 'ALWAYS_SEARCH_USER_PATHS' => 'YES', # needed to make EmbedReader build
'PODS_HEADERS_SEARCH_PATHS' => '${PODS_PUBLIC_HEADERS_SEARCH_PATHS}', 'OTHER_LDFLAGS' => default_ld_flags,
'ALWAYS_SEARCH_USER_PATHS' => 'YES', # needed to make EmbedReader build 'HEADER_SEARCH_PATHS' => '${PODS_HEADERS_SEARCH_PATHS}',
'OTHER_LDFLAGS' => default_ld_flags # CocoaPods global keys
'PODS_ROOT' => @target_definition.relative_pods_root,
'PODS_BUILD_HEADERS_SEARCH_PATHS' => quoted(sandbox.build_headers.search_paths).join(" "),
'PODS_PUBLIC_HEADERS_SEARCH_PATHS' => quoted(sandbox.public_headers.search_paths).join(" "),
# Pods project specific keys
'PODS_HEADERS_SEARCH_PATHS' => '${PODS_PUBLIC_HEADERS_SEARCH_PATHS}'
}) })
xcconfig.merge!('HEADER_SEARCH_PATHS' => '${PODS_HEADERS_SEARCH_PATHS}')
xcconfig.merge!('PODS_BUILD_HEADERS_SEARCH_PATHS' => quoted(sandbox.build_headers.search_paths).join(" "))
xcconfig.merge!('PODS_PUBLIC_HEADERS_SEARCH_PATHS' => quoted(sandbox.public_headers.search_paths).join(" "))
pods.each { |pod| xcconfig.merge!(pod.xcconfig) } pods.each { |pod| xcconfig.merge!(pod.xcconfig) }
@xcconfig = xcconfig @xcconfig = xcconfig
end end
......
...@@ -387,8 +387,14 @@ module Pod ...@@ -387,8 +387,14 @@ module Pod
result result
end end
# @!group Project integration # @!group Xcodeproj integration
# Adds the file references, to the given `Pods.xcodeproj` project, for the
# source files of the pod. The file references are grouped by specification
# and stored in {#file_references_by_spec}.
#
# @note If the pod is locally sourced the file references are stored in the
# `Local Pods` group otherwise they are stored in the `Pods` group.
# #
# @return [void] # @return [void]
# #
...@@ -406,13 +412,24 @@ module Pod ...@@ -406,13 +412,24 @@ module Pod
end end
end end
# # @return [Hash{Specification => Array<PBXFileReference>}] The file
# references of the pod in the `Pods.xcodeproj` project.
# #
attr_reader :file_references_by_spec attr_reader :file_references_by_spec
# Adds a build file for each file reference to a given target taking into
# account the compiler flags of the corresponding specification.
#
# @raise If the {#add_file_references_to_project} was not called before of
# calling this method.
# #
# @return [void]
# #
def add_build_files_to_target(target) def add_build_files_to_target(target)
unless file_references_by_spec
raise Informative, "Local Pod needs to add the file references to the " \
"project before adding the build files to the target."
end
file_references_by_spec.each do |spec, file_reference| file_references_by_spec.each do |spec, file_reference|
target.add_file_references(file_reference, spec.compiler_flags.strip) target.add_file_references(file_reference, spec.compiler_flags.strip)
end end
...@@ -543,15 +560,27 @@ module Pod ...@@ -543,15 +560,27 @@ module Pod
"\t Options: #{options.inspect}" "\t Options: #{options.inspect}"
end end
patterns = [ patterns ] if patterns.is_a? String return [] if patterns.empty?
patterns.map do |pattern| patterns = [ patterns ] if patterns.is_a?(String)
pattern = root + pattern file_lists = patterns.select { |p| p.is_a?(FileList) }
glob_patterns = patterns - file_lists
result = []
result << file_lists.map do |file_list|
file_list.prepend_patterns(root)
file_list.glob
end
result << glob_patterns.map do |pattern|
pattern = root + pattern
if pattern.directory? && options[:glob] if pattern.directory? && options[:glob]
pattern += options[:glob] pattern += options[:glob]
end end
Pathname.glob(pattern, File::FNM_CASEFOLD) Pathname.glob(pattern, File::FNM_CASEFOLD)
end.flatten end.flatten
result.flatten.compact.uniq
end end
# A {LocalSourcedPod} is a {LocalPod} that interacts with the files of # A {LocalSourcedPod} is a {LocalPod} that interacts with the files of
......
require 'xcodeproj/project' require 'xcodeproj/project'
require 'xcodeproj/project/object/build_phase'
Xcodeproj::Project::Object::PBXCopyFilesBuildPhase.instance_eval do # Xcodeproj::Project::Object::PBXCopyFilesBuildPhase.instance_eval do
def self.new_pod_dir(project, pod_name, path) # def self.new_pod_dir(project, pod_name, path)
new(project, nil, { # new(project, nil, {
"dstPath" => "Pods/#{path}", # "dstPath" => "Pods/#{path}",
"name" => "Copy #{pod_name} Public Headers", # "name" => "Copy #{pod_name} Public Headers",
}) # })
end # end
end # end
module Pod module Pod
class Project < Xcodeproj::Project class Project < Xcodeproj::Project
...@@ -65,6 +64,7 @@ module Pod ...@@ -65,6 +64,7 @@ module Pod
end end
if platform == :ios && platform.deployment_target if platform == :ios && platform.deployment_target
# TODO: add for osx as well
settings['IPHONEOS_DEPLOYMENT_TARGET'] = platform.deployment_target.to_s settings['IPHONEOS_DEPLOYMENT_TARGET'] = platform.deployment_target.to_s
end end
......
...@@ -438,11 +438,12 @@ module Pod ...@@ -438,11 +438,12 @@ module Pod
# this to, for instance, to run any build script: # this to, for instance, to run any build script:
# #
# Pod::Spec.new do |s| # Pod::Spec.new do |s|
# def pre_install(pod, target_definition) # def s.pre_install(pod, target_definition)
# Dir.chdir(pod.root){ `sh make.sh` } # Dir.chdir(pod.root){ `sh make.sh` }
# end # end
# end # end
def pre_install(pod, target_definition) def pre_install(pod, target_definition)
FALSE
end end
# This is a convenience method which gets called after all pods have been # This is a convenience method which gets called after all pods have been
...@@ -460,6 +461,7 @@ module Pod ...@@ -460,6 +461,7 @@ module Pod
# end # end
# end # end
def post_install(target_installer) def post_install(target_installer)
FALSE
end end
def podfile? def podfile?
......
...@@ -32,21 +32,13 @@ describe Pod::Installer::UserProjectIntegrator do ...@@ -32,21 +32,13 @@ describe Pod::Installer::UserProjectIntegrator do
@sample_project = Xcodeproj::Project.new(@sample_project_path) @sample_project = Xcodeproj::Project.new(@sample_project_path)
end end
it 'adds references to the Pods static libraries to the root of the project if the Frameworks group does not exist' do
@sample_project.group('Frameworks').destroy
@sample_project.save_as(@sample_project_path)
integrate!
@sample_project.main_group.files.where(:name => "libPods.a").should.not == nil
@sample_project.main_group.files.where(:name => "libPods-test_runner.a").should.not == nil
end
before do before do
integrate! integrate!
end end
it 'adds references to the Pods static libraries to the Frameworks group' do it 'adds references to the Pods static libraries to the Frameworks group' do
@sample_project.group('Frameworks').files.where(:name => "libPods.a").should.not == nil @sample_project["Frameworks/libPods.a"].should.not == nil
@sample_project.group('Frameworks').files.where(:name => "libPods-test_runner.a").should.not == nil @sample_project["Frameworks/libPods-test_runner.a"].should.not == nil
end end
it 'creates a workspace with a name matching the project' do it 'creates a workspace with a name matching the project' do
...@@ -66,26 +58,25 @@ describe Pod::Installer::UserProjectIntegrator do ...@@ -66,26 +58,25 @@ describe Pod::Installer::UserProjectIntegrator do
it 'sets the Pods xcconfig as the base config for each build configuration' do it 'sets the Pods xcconfig as the base config for each build configuration' do
@podfile.target_definitions.each do |_, definition| @podfile.target_definitions.each do |_, definition|
target = @sample_project.targets.where(:name => definition.link_with.first) target = @sample_project.targets.find { |t| t.name == definition.link_with.first }
xcconfig_file = @sample_project.files.where(:path => "Pods/#{definition.xcconfig_name}") xcconfig_file = @sample_project.files.find { |f| f.path == "Pods/#{definition.xcconfig_name}" }
target.build_configurations.each do |config| target.build_configurations.each do |config|
config.base_configuration.should == xcconfig_file config.base_configuration_reference.should == xcconfig_file
end end
end end
end end
it 'adds the libPods static library to the "Link binary with libraries" build phase of each target' do it 'adds the libPods static library to the "Link binary with libraries" build phase of each target' do
@podfile.target_definitions.each do |_, definition| @podfile.target_definitions.each do |_, definition|
target = @sample_project.targets.where(:name => definition.link_with.first) target = @sample_project.targets.find { |t| t.name == definition.link_with.first }
framework_build_phase = target.frameworks_build_phases.first target.frameworks_build_phase.files.find { |f| f.file_ref.name == definition.lib_name}.should.not == nil
framework_build_phase.files.where(:name => definition.lib_name).should.not == nil
end end
end end
it 'adds a Copy Pods Resources build phase to each target' do it 'adds a Copy Pods Resources build phase to each target' do
@podfile.target_definitions.each do |_, definition| @podfile.target_definitions.each do |_, definition|
target = @sample_project.targets.where(:name => definition.link_with.first) target = @sample_project.targets.find { |t| t.name == definition.link_with.first }
phase = target.shell_script_build_phases.where(:name => "Copy Pods Resources") phase = target.shell_script_build_phases.find { |bp| bp.name == "Copy Pods Resources" }
phase.shell_script.strip.should == "\"${SRCROOT}/Pods/#{definition.copy_resources_script_name}\"" phase.shell_script.strip.should == "\"${SRCROOT}/Pods/#{definition.copy_resources_script_name}\""
end end
end end
...@@ -101,8 +92,8 @@ describe Pod::Installer::UserProjectIntegrator do ...@@ -101,8 +92,8 @@ describe Pod::Installer::UserProjectIntegrator do
# Remove libPods.a from the app target. But don't do it through TargetIntegrator#targets, # Remove libPods.a from the app target. But don't do it through TargetIntegrator#targets,
# as it will return only those that still need integration. # as it will return only those that still need integration.
app_target = app_integrator.user_project.targets.where(:name => 'SampleProject') app_target = app_integrator.user_project.targets.find { |t| t.name == 'SampleProject' }
app_target.frameworks_build_phases.first.build_files.last.destroy app_target.frameworks_build_phase.files.last.remove_from_project
app_integrator.expects(:add_pods_library) app_integrator.expects(:add_pods_library)
test_runner_integrator.expects(:add_pods_library).never test_runner_integrator.expects(:add_pods_library).never
......
...@@ -389,7 +389,9 @@ else ...@@ -389,7 +389,9 @@ else
installer.install! installer.install!
project = Pod::Project.new(config.project_pods_root + 'Pods.xcodeproj') project = Pod::Project.new(config.project_pods_root + 'Pods.xcodeproj')
project.source_files.should == installer.project.source_files disk_source_files = project.files.sort.reject { |f| f.build_files.empty? }
installer_source_files = installer.project.files.sort.reject { |f| f.build_files.empty? }
disk_source_files.should == installer_source_files
end end
it "creates a project with multiple targets" do it "creates a project with multiple targets" do
...@@ -409,7 +411,7 @@ else ...@@ -409,7 +411,7 @@ else
project = Xcodeproj::Project.new(config.project_pods_root + 'Pods.xcodeproj') project = Xcodeproj::Project.new(config.project_pods_root + 'Pods.xcodeproj')
project.targets.each do |target| project.targets.each do |target|
phase = target.build_phases.find { |phase| phase.is_a?(Xcodeproj::Project::Object::PBXSourcesBuildPhase) } phase = target.build_phases.find { |phase| phase.is_a?(Xcodeproj::Project::Object::PBXSourcesBuildPhase) }
files = phase.files.map(&:name) files = phase.files.map { |bf| bf.file_ref.name }
case target.product_name case target.product_name
when 'Pods' when 'Pods'
files.should.include "ASIHTTPRequest.m" files.should.include "ASIHTTPRequest.m"
...@@ -466,9 +468,9 @@ else ...@@ -466,9 +468,9 @@ else
target = project.targets.first target = project.targets.first
target.build_configurations.each do |config| target.build_configurations.each do |config|
config.base_configuration.path.should == 'Pods/Pods.xcconfig' config.base_configuration_reference.path.should == 'Pods/Pods.xcconfig'
end end
target.frameworks_build_phases.first.files.should.include libPods target.frameworks_build_phase.files.should.include libPods.build_files.first
# should be the last phase # should be the last phase
target.build_phases.last.shell_script.should == %{"${SRCROOT}/Pods/Pods-resources.sh"\n} target.build_phases.last.shell_script.should == %{"${SRCROOT}/Pods/Pods-resources.sh"\n}
end end
......
...@@ -13,7 +13,7 @@ describe Pod::Installer::TargetInstaller do ...@@ -13,7 +13,7 @@ describe Pod::Installer::TargetInstaller do
@target_definition = @podfile.target_definitions[:default] @target_definition = @podfile.target_definitions[:default]
@project = Pod::Project.new @project = Pod::Project.new
@project.main_group.groups.new('name' => 'Targets Support Files') @project.new_group('Targets Support Files')
@installer = Pod::Installer::TargetInstaller.new(@podfile, @project, @target_definition) @installer = Pod::Installer::TargetInstaller.new(@podfile, @project, @target_definition)
...@@ -24,6 +24,7 @@ describe Pod::Installer::TargetInstaller do ...@@ -24,6 +24,7 @@ describe Pod::Installer::TargetInstaller do
end end
def do_install! def do_install!
@pods.each { |pod| pod.add_file_references_to_project(@project) }
@installer.install!(@pods, @sandbox) @installer.install!(@pods, @sandbox)
end end
...@@ -40,14 +41,15 @@ describe Pod::Installer::TargetInstaller do ...@@ -40,14 +41,15 @@ describe Pod::Installer::TargetInstaller do
end end
it 'adds each pod to the static library target' do it 'adds each pod to the static library target' do
@pods[0].expects(:source_file_descriptions).returns([]) @pods[0].expects(:add_build_files_to_target)
do_install! do_install!
end end
it 'tells each pod to link its headers' do # TODO: move to project
@pods[0].expects(:link_headers) # it 'tells each pod to link its headers' do
do_install! # @pods[0].expects(:link_headers)
end # do_install!
# end
it 'adds the sandbox header search paths to the xcconfig, with quotes' do it 'adds the sandbox header search paths to the xcconfig, with quotes' do
do_install! do_install!
...@@ -62,7 +64,7 @@ describe Pod::Installer::TargetInstaller do ...@@ -62,7 +64,7 @@ describe Pod::Installer::TargetInstaller do
it 'adds the -fobjc-arc to OTHER_LDFLAGS if any pods require arc (to support non-ARC projects on iOS 4.0)' do it 'adds the -fobjc-arc to OTHER_LDFLAGS if any pods require arc (to support non-ARC projects on iOS 4.0)' do
@podfile.stubs(:set_arc_compatibility_flag? => true) @podfile.stubs(:set_arc_compatibility_flag? => true)
@specification.stubs(:requires_arc).returns(true) @specification.stubs(:requires_arc).returns(true)
@installer.install!(@pods, @sandbox) do_install!
@installer.xcconfig.to_hash['OTHER_LDFLAGS'].split(" ").should.include("-fobjc-arc") @installer.xcconfig.to_hash['OTHER_LDFLAGS'].split(" ").should.include("-fobjc-arc")
end end
......
...@@ -17,7 +17,9 @@ module Pod ...@@ -17,7 +17,9 @@ module Pod
sandbox = Sandbox.new(fixture('integration')) sandbox = Sandbox.new(fixture('integration'))
resolver = Resolver.new(podfile, nil, sandbox) resolver = Resolver.new(podfile, nil, sandbox)
@xcconfig = Installer.new(resolver).target_installers.first.xcconfig.to_hash target_installer = Installer.new(resolver).target_installers.first
target_installer.generate_xcconfig([], sandbox)
@xcconfig = target_installer.xcconfig.to_hash
end end
it "sets the header search paths where installed Pod headers can be found" do it "sets the header search paths where installed Pod headers can be found" do
...@@ -127,7 +129,7 @@ module Pod ...@@ -127,7 +129,7 @@ module Pod
it "adds the files of the pod to the Pods project only once" do it "adds the files of the pod to the Pods project only once" do
@installer.install! @installer.install!
group = @installer.project.pods.groups.where(:name => 'Reachability') group = @installer.project.pods.groups.find { |g| g.name == 'Reachability' }
group.files.map(&:name).should == ["Reachability.h", "Reachability.m"] group.files.map(&:name).should == ["Reachability.h", "Reachability.m"]
end end
...@@ -155,13 +157,13 @@ module Pod ...@@ -155,13 +157,13 @@ module Pod
it "namespaces local pods" do it "namespaces local pods" do
@installer.install! @installer.install!
group = @installer.project.groups.where(:name => 'Local Pods') group = @installer.project['Local Pods']
group.groups.map(&:name).sort.should == %w| Chameleon | group.groups.map(&:name).sort.should == %w| Chameleon |
end end
it "namespaces subspecs" do it "namespaces subspecs" do
@installer.install! @installer.install!
group = @installer.project.groups.where(:name => 'Chameleon') group = @installer.project['Local Pods/Chameleon']
group.groups.map(&:name).sort.should == %w| AVFoundation AssetsLibrary MediaPlayer MessageUI StoreKit UIKit | group.groups.map(&:name).sort.should == %w| AVFoundation AssetsLibrary MediaPlayer MessageUI StoreKit UIKit |
end end
end end
......
...@@ -38,7 +38,7 @@ describe Pod::LocalPod do ...@@ -38,7 +38,7 @@ describe Pod::LocalPod do
].sort ].sort
end end
it "returns the source files groupped by specification" do it "returns the source files grouped by specification" do
files = @pod.source_files_by_spec[@pod.specifications.first].sort files = @pod.source_files_by_spec[@pod.specifications.first].sort
files.should == [ files.should == [
@pod.root + "Classes/Banana.m", @pod.root + "Classes/Banana.m",
...@@ -83,18 +83,26 @@ describe Pod::LocalPod do ...@@ -83,18 +83,26 @@ describe Pod::LocalPod do
end end
it "can add it's source files to an Xcode project target" do it "can add it's source files to an Xcode project target" do
@pod.source_file_descriptions.should == [ project = Pod::Project.new
Xcodeproj::Project::PBXNativeTarget::SourceFileDescription.new(Pathname.new("BananaLib/Classes/Banana.h"), "", nil), @pod.add_file_references_to_project(project)
Xcodeproj::Project::PBXNativeTarget::SourceFileDescription.new(Pathname.new("BananaLib/Classes/Banana.m"), "", nil) project['Pods/BananaLib/Banana.h'].path.should == "BananaLib/Classes/Banana.h"
] project['Pods/BananaLib/Banana.m'].path.should == "BananaLib/Classes/Banana.m"
end end
it "can add it's source files to a target with any specially configured compiler flags" do it "can add it's source files to a target with any specially configured compiler flags" do
project = Pod::Project.new
target = project.new_target(:static, 'Pods', :ios)
@pod.top_specification.compiler_flags = '-d some_flag' @pod.top_specification.compiler_flags = '-d some_flag'
@pod.source_file_descriptions.should == [ @pod.add_file_references_to_project(project)
Xcodeproj::Project::PBXNativeTarget::SourceFileDescription.new(Pathname.new("BananaLib/Classes/Banana.h"), '-d some_flag', nil), @pod.add_build_files_to_target(target)
Xcodeproj::Project::PBXNativeTarget::SourceFileDescription.new(Pathname.new("BananaLib/Classes/Banana.m"), '-d some_flag', nil)
] h_build_file = target.headers_build_phase.files.first
h_build_file.file_ref.path.should == "BananaLib/Classes/Banana.h"
h_build_file.settings.should == {"ATTRIBUTES"=>["Public"]}
m_build_file = target.source_build_phase.files.first
m_build_file.file_ref.path.should == "BananaLib/Classes/Banana.m"
m_build_file.settings.should == {"COMPILER_FLAGS"=>"-d some_flag"}
end end
it "returns the platform" do it "returns the platform" do
......
...@@ -5,44 +5,32 @@ describe 'Pod::Project' do ...@@ -5,44 +5,32 @@ describe 'Pod::Project' do
@project = Pod::Project.new @project = Pod::Project.new
end end
def find_object(conditions)
@project.objects_hash.select do |_, object|
(conditions.keys - object.keys).empty? && object.values_at(*conditions.keys) == conditions.values
end.first
end
it "adds a group to the `Pods' group" do it "adds a group to the `Pods' group" do
group = @project.add_spec_group('JSONKit', @project.pods) group = @project.add_spec_group('JSONKit', @project.pods)
@project.pods.child_references.should.include group.uuid @project.pods.children.should.include?(group)
find_object({ g = @project['Pods/JSONKit']
'isa' => 'PBXGroup', g.name.should == 'JSONKit'
'name' => 'JSONKit', g.children.should.be.empty?
'sourceTree' => '<group>',
'children' => []
}).should.not == nil
end end
it "namespaces subspecs in groups" do it "namespaces subspecs in groups" do
group = @project.add_spec_group('JSONKit/Subspec', @project.pods) group = @project.add_spec_group('JSONKit/Subspec', @project.pods)
@project.pods.groups.find { |g| g.name == 'JSONKit' }.child_references.should.include group.uuid @project.pods.groups.find { |g| g.name == 'JSONKit' }.children.should.include?(group)
find_object({ g = @project['Pods/JSONKit/Subspec']
'isa' => 'PBXGroup', g.name.should == 'Subspec'
'name' => 'Subspec', g.children.should.be.empty?
'sourceTree' => '<group>',
'children' => []
}).should.not == nil
end end
it "creates a copy build header phase which will copy headers to a specified path" do # it "creates a copy build header phase which will copy headers to a specified path" do
@project.targets.new # @project.targets.new
phase = @project.targets.first.copy_files_build_phases.new_pod_dir("SomePod", "Path/To/Source") # phase = @project.targets.first.copy_files_build_phases.new_pod_dir("SomePod", "Path/To/Source")
find_object({ # find_object({
'isa' => 'PBXCopyFilesBuildPhase', # 'isa' => 'PBXCopyFilesBuildPhase',
'dstPath' => 'Pods/Path/To/Source', # 'dstPath' => 'Pods/Path/To/Source',
'name' => 'Copy SomePod Public Headers' # 'name' => 'Copy SomePod Public Headers'
}).should.not == nil # }).should.not == nil
@project.targets.first.build_phases.should.include phase # @project.targets.first.build_phases.should.include phase
end # end
it "adds build configurations named after every configuration across all of the user's projects" do it "adds build configurations named after every configuration across all of the user's projects" do
@project.user_build_configurations = { 'Debug' => :debug, 'Release' => :release, 'Test' => :debug, 'AppStore' => :release } @project.user_build_configurations = { 'Debug' => :debug, 'Release' => :release, 'Test' => :debug, 'AppStore' => :release }
......
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