Commit 12b5bedc authored by Fabio Pelosin's avatar Fabio Pelosin

[PodsProjectGenerator] Major improvements

parent 6d3c2c45
...@@ -4,6 +4,74 @@ module Pod ...@@ -4,6 +4,74 @@ module Pod
# Generates the Pods project according to the targets identified by the # Generates the Pods project according to the targets identified by the
# analyzer. # analyzer.
# #
# # Incremental editing
#
# The generator will edit exiting projects instead of recreating them from
# scratch. This behaviour significantly complicates the logic but leads to
# dramatic performance benefits for the installation times. Another feature
# of the incremental editing is the preservation of the UUIDs in the
# project which allows to easily compare projects, reduce SCM noise (if the
# CocoaPods artifacts are kept under source control), and finally, to
# improve indexing and build time in Xcode.
#
# ## Assumptions
#
# To tame the complexity of the incremental editing, the generator relies
# on the following assumptions:
#
# - The file references of the Pods are all stored in a dedicated group.
# - The support files for a Pod are stored in a group which in turn is
# namespaced per aggregate target.
# - The support files of an aggregate target are stored in its group.
# - The support files generator is incremental and doesn't duplicates file
# references.
#
# ## Logic overview
#
# 1. The pods project is prepared.
# - The Pods project is generated from scratch if needed.
# - Otherwise the project is recreated from scratch and cleaned.
# - Existing native targets are matched to the targets.
# - Unrecognized targets are removed with any reference to them in the
# build phases of their other targets (dependencies build phases and
# frameworks build phases).
# - Unrecognized pod groups are removed.
# 2. All the targets which require it are installed.
# 3. The support files of the targets are generated and the file references
# are created if needed.
# 4. Any missing Pod target is added to the framework build phases of the
# dependent aggregate targets.
# 5. Any missing target is added to the dependencies build phase of the
# dependent target.
#
# ## Caveats & Notes
#
# - Until CocoaPods 1.0 a migrator will not be provided and when the
# structure of the Pods project changes it should be recreated from
# scratch.
# - Although the incremental generation is reasonably robust, if the user
# tampers with the Pods project an generation from scratch might be
# necessary to bring the project to a consistent state.
# - Advanced users might workaround to missing features of CocoaPods
# editing the project. Those customization might persist for a longer
# time than in a system where the project is generated from scratch every
# time.
# - If a Pod changes on any target it needs to be reinstalled from scratch
# as the file references might change according to the platform and the
# file references installer is not incremental.
# - The recreation of the target environment header forces the
# recompilation of the project.
#
#
# TODO: Resource bundle targets are currently removed as they are not
# unrecognized.
# TODO: Rebuild from scratch if the version of CocoaPods is not compatible.
# TODO: The paths of frameworks might not match in different systems.
# TODO: The recreation of the prefix header of the Pods targets forces a
# recompilation.
# TODO: The headers search paths of the Pods xcconfigs should not include
# all the headers.
#
class PodsProjectGenerator class PodsProjectGenerator
autoload :AggregateTargetInstaller, 'cocoapods/installer/pods_project_generator/target_installer/aggregate_target_installer' autoload :AggregateTargetInstaller, 'cocoapods/installer/pods_project_generator/target_installer/aggregate_target_installer'
...@@ -45,27 +113,27 @@ module Pod ...@@ -45,27 +113,27 @@ module Pod
# #
def install def install
prepare_project prepare_project
sync_pod_targets install_targets
sync_aggregate_targets sync_support_files
sync_target_dependencies add_missing_aggregate_targets_libraries
sync_aggregate_targets_libraries add_missing_target_dependencies
end end
# @return [Project] the generated Pods project.
#
attr_reader :project
# Writes the Pods project to the disk. # Writes the Pods project to the disk.
# #
# @return [void] # @return [void]
# #
def write_project def write_project
UI.message "- Writing Xcode project file" do UI.message "- Writing Pods project" do
project.prepare_for_serialization project.prepare_for_serialization
project.save project.save
end end
end end
# @return [Project] the generated Pods project.
#
attr_reader :project
private private
...@@ -85,8 +153,9 @@ module Pod ...@@ -85,8 +153,9 @@ module Pod
else else
UI.message"- Opening existing project" do UI.message"- Opening existing project" do
@project = Pod::Project.open(sandbox.project_path) @project = Pod::Project.open(sandbox.project_path)
remove_groups
detect_native_targets detect_native_targets
clean_groups
clean_native_targets
end end
end end
...@@ -95,211 +164,147 @@ module Pod ...@@ -95,211 +164,147 @@ module Pod
sandbox.project = project sandbox.project = project
end end
def remove_groups # Installs the targets which require an installation.
pod_names = all_pod_targets.map(&:pod_name).uniq.sort #
groups_to_remove = [] # The Pod targets which require an installation (missing, added, or
groups_to_remove << project.pod_groups.reject do |group| # changed) are installed from scratch for all the targets.
pod_names.include?(group.display_name) #
end # Only the missing aggregate targets are installed as any reference to
# any unrecognized target has already be removed, the references in the
groups_to_remove << project.aggregate_groups.map(&:groups).flatten.reject do |group| # build phases will be synchronized later and the support files will be
pod_names.include?(group.display_name) # regenerated and synchronized in any case.
end #
# @return [void]
aggregate_names = aggregate_targets.map(&:label).uniq.sort #
groups_to_remove << project.support_files_group.children.reject do |group| def install_targets
aggregate_names.include?(group.display_name) pods_to_install.each do |name|
UI.message"- Installing `#{name}`" do
add_pod(name)
end
end end
groups_to_remove.flatten.each do |group| aggregate_targets_to_install.each do |target|
p group UI.message"- Installing `#{target.label}`" do
remove_group(group) add_aggregate_target(target)
end
end end
end end
# Removes the given group taking care of removing any referenced target. # Generates the support for files for the targets and adds the file
# references to them if needed.
# #
# @return [void] # @return [void]
# #
def remove_group(group) def sync_support_files
UI.message"- Removing `#{group}` group" do targets = all_pod_targets + aggregate_targets
group.groups.each do |child| targets.reject!(&:skip_installation?)
remove_group(child) targets.each do |target|
UI.message"- Generating support files for target `#{target.label}`" do
gen = SupportFilesGenerator.new(target, sandbox.project)
gen.generate!
end end
end
end
targets = project.targets.select { |target| group.children.include?(target.product_reference) } # Links the aggregate targets with all the dependent pod targets.
targets.each do |target| # Aggregate targets are always created from scratch.
remove_target(target) #
# @return [void]
#
def add_missing_aggregate_targets_libraries
UI.message"- Populating aggregate targets" do
aggregate_targets.each do |aggregate_target|
native_target = aggregate_target.target
aggregate_target.pod_targets.each do |pod_target|
product = pod_target.target.product_reference
unless native_target.frameworks_build_phase.files_references.include?(product)
native_target.frameworks_build_phase.add_file_reference(product)
end
end
end end
group.remove_from_project
end end
end end
# Removes the given target removing any reference to it from any other # Synchronizes the dependencies of the targets.
# target.
# #
# @return [void] # @return [void]
# #
def remove_target(target) def add_missing_target_dependencies
UI.message"- Removing `#{target.display_name}` target" do UI.message"- Setting-up target dependencies" do
target.referrers.each do |ref| aggregate_targets.each do |aggregate_target|
if ref.isa == 'PBXTargetDependency' aggregate_target.pod_targets.each do |dep|
ref.remove_from_project aggregate_target.target.add_dependency(dep.target)
end end
end
target.remove_from_project
target.product_reference.referrers.each do |ref| aggregate_targets.each do |aggregate_target|
if ref.isa == 'PBXBuildFile' aggregate_target.pod_targets.each do |pod_target|
ref.remove_from_project dependencies = pod_target.dependencies.map { |dep_name| aggregate_target.pod_targets.find { |target| target.pod_name == dep_name } }
dependencies.each do |dep|
pod_target.target.add_dependency(dep.target)
end
end
end end
end end
target.product_reference.remove_from_project
end end
end end
private
# @!group Incremental Editing
#-----------------------------------------------------------------------#
# Matches the native targets of the Pods project with the targets # Matches the native targets of the Pods project with the targets
# generated by the analyzer. # generated by the analyzer.
# #
# @return [void] # @return [void]
# #
def detect_native_targets def detect_native_targets
native_targets_by_name = project.targets.group_by(&:name) @native_targets_by_name = project.targets.group_by(&:name)
native_targets_to_remove = native_targets_by_name.keys.dup @unrecognized_targets = native_targets_by_name.keys.dup
cp_targets = aggregate_targets + all_pod_targets cp_targets = aggregate_targets + all_pod_targets
cp_targets.each do |pod_target| cp_targets.each do |pod_target|
native_targets = native_targets_by_name[pod_target.label] native_targets = native_targets_by_name[pod_target.label]
if native_targets if native_targets
pod_target.target = native_targets.first pod_target.target = native_targets.first
native_targets_to_remove.delete(pod_target.label) @unrecognized_targets.delete(pod_target.label)
end
end
native_targets_to_remove.each do |target_name|
remove_target(native_targets_by_name[target_name].first)
end
end
# @return [void]
#
def sync_pod_targets
pods_to_install.each do |name|
add_pod(name)
end
all_pod_targets.each do |target|
UI.message"- Generating support files for target `#{target.label}`" do
gen = SupportFilesGenerator.new(target, sandbox.project)
gen.generate!
end end
end end
end end
# Adds and removes aggregate targets to the # Cleans any unrecognized group in the Pods group and in the support
# files group.
# #
# @return [void] # @return [void]
# #
def sync_aggregate_targets def clean_groups
# TODO: Clean up dependencies and linking pod_names = all_pod_targets.map(&:pod_name).uniq.sort
# TODO: Clean removed targets and their support files groups_to_remove = []
# TODO: Fix sorting of targets groups_to_remove << project.pod_groups.reject do |group|
# TODO: Clean unrecognized targets pod_names.include?(group.display_name)
# TODO: Add integration checks (adding an aggregate target, removing
# one, performing an installation without a project)
# TODO
targets_to_remove = []
targets_to_install.each do |target|
add_aggregate_target(target)
end
aggregate_targets.each do |target|
unless target.target_definition.empty?
UI.message"- Generating support files for target `#{target.label}`" do
gen = SupportFilesGenerator.new(target, sandbox.project)
gen.generate!
end
end
end end
end
# groups_to_remove << project.aggregate_groups.map(&:groups).flatten.reject do |group|
# pod_names.include?(group.display_name)
def add_aggregate_target(target)
UI.message"- Installing `#{target.label}`" do
AggregateTargetInstaller.new(sandbox, target).install!
end end
end
#
#
def add_pod(name)
UI.message"- Installing `#{name}`" do
pod_targets = all_pod_targets.select { |target| target.pod_name == name }
remove_group(project.pod_group(name)) if project.pod_group(name)
UI.message"- Installing file references" do
path = sandbox.pod_dir(name)
local = sandbox.local?(name)
project.add_pod_group(name, path, local)
FileReferencesInstaller.new(sandbox, pod_targets).install!
end
pod_targets.each do |pod_target| aggregate_names = aggregate_targets.map(&:label).uniq.sort
remove_target(pod_target.target) if pod_target.target groups_to_remove << project.support_files_group.children.reject do |group|
UI.message "- Installing target `#{pod_target.name}` #{pod_target.platform}" do aggregate_names.include?(group.display_name)
PodTargetInstaller.new(sandbox, pod_target).install!
end
end
end end
end
# Sets the dependencies of the targets. groups_to_remove.flatten.each do |group|
# remove_group(group)
# @return [void]
#
def sync_target_dependencies
UI.message"- Setting-up dependencies" do
aggregate_targets.each do |aggregate_target|
aggregate_target.pod_targets.each do |dep|
if dep.target
aggregate_target.target.add_dependency(dep.target)
else
puts "[BUG] #{dep}"
end
end
end
aggregate_targets.each do |aggregate_target|
aggregate_target.pod_targets.each do |pod_target|
dependencies = pod_target.dependencies.map { |dep_name| aggregate_target.pod_targets.find { |target| target.pod_name == dep_name } }
dependencies.each do |dep|
pod_target.target.add_dependency(dep.target)
end
end
end
end end
end end
# Links the aggregate targets with all the dependent pod targets. # Cleans the unrecognized native targets.
# #
# @return [void] # @return [void]
# #
def sync_aggregate_targets_libraries def clean_native_targets
UI.message"- Populating aggregate targets" do unrecognized_targets.each do |target_name|
aggregate_targets.each do |aggregate_target| remove_target(native_targets_by_name[target_name].first)
native_target = aggregate_target.target
aggregate_target.pod_targets.each do |pod_target|
product = pod_target.target.product_reference
unless native_target.frameworks_build_phase.files_references.include?(product)
native_target.frameworks_build_phase.add_file_reference(product)
end
end
end
end end
end end
...@@ -312,9 +317,9 @@ module Pod ...@@ -312,9 +317,9 @@ module Pod
# #
# #
def should_create_new_project? def should_create_new_project?
# TODO # TODO version
incompatible = false compatbile_version = '0.24.0'
incompatible || !sandbox.project_path.exist? !sandbox.version_at_least?(compatbile_version) || !sandbox.project_path.exist?
end end
# #
...@@ -343,24 +348,15 @@ module Pod ...@@ -343,24 +348,15 @@ module Pod
# #
# #
def pods_to_remove def aggregate_targets_to_install
return [] if new_project
# TODO: Unrecognized groups
@pods_to_remove ||= (sandbox.state.deleted | sandbox.state.changed).sort
end
def targets_to_install
aggregate_targets.sort_by(&:name).select do |target| aggregate_targets.sort_by(&:name).select do |target|
empty = target.target_definition.empty? target.target.nil? && !target.skip_installation?
if new_project
!empty
else
missing = target.target.nil?
missing && !empty
end
end end
end end
attr_accessor :unrecognized_targets
attr_accessor :native_targets_by_name
# Sets the build configuration of the Pods project according the build # Sets the build configuration of the Pods project according the build
# configurations of the user as detected by the analyzer and other # configurations of the user as detected by the analyzer and other
# default values. # default values.
...@@ -382,6 +378,81 @@ module Pod ...@@ -382,6 +378,81 @@ module Pod
end end
end end
# Removes the given group taking care of removing any referenced target.
#
# @return [void]
#
def remove_group(group)
UI.message"- Removing `#{group}` group" do
group.groups.each do |child|
remove_group(child)
end
targets = project.targets.select { |target| group.children.include?(target.product_reference) }
targets.each do |target|
remove_target(target)
end
group.remove_from_project
end
end
# Removes the given target removing any reference to it from any other
# target.
#
# @return [void]
#
def remove_target(target)
UI.message"- Removing `#{target.display_name}` target" do
target.referrers.each do |ref|
if ref.isa == 'PBXTargetDependency'
ref.remove_from_project
end
end
target.remove_from_project
target.product_reference.referrers.each do |ref|
if ref.isa == 'PBXBuildFile'
ref.remove_from_project
end
end
target.product_reference.remove_from_project
end
end
# Installs all the targets of the Pod with the given name. If the Pod
# already exists it is removed before.
#
# @return [void]
#
def add_pod(name)
pod_targets = all_pod_targets.select { |target| target.pod_name == name }
remove_group(project.pod_group(name)) if project.pod_group(name)
UI.message"- Installing file references" do
path = sandbox.pod_dir(name)
local = sandbox.local?(name)
project.add_pod_group(name, path, local)
FileReferencesInstaller.new(sandbox, pod_targets).install!
end
pod_targets.each do |pod_target|
remove_target(pod_target.target) if pod_target.target
UI.message "- Installing target `#{pod_target.name}` #{pod_target.platform}" do
PodTargetInstaller.new(sandbox, pod_target).install!
end
end
end
# Installs an aggregate target.
#
# @return [void]
#
def add_aggregate_target(target)
AggregateTargetInstaller.new(sandbox, target).install!
end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
end end
......
...@@ -56,12 +56,9 @@ module Pod ...@@ -56,12 +56,9 @@ module Pod
@native_target.add_build_configuration(bc_name, type) @native_target.add_build_configuration(bc_name, type)
end end
target.target = @native_target target.target = @native_target
end end
# @return [PBXNativeTarget] the target generated by the installation # @return [PBXNativeTarget] the target generated by the installation
# process. # process.
# #
......
...@@ -2,21 +2,21 @@ module Pod ...@@ -2,21 +2,21 @@ module Pod
class Installer class Installer
class PodsProjectGenerator class PodsProjectGenerator
# Creates the targets which aggregate the Pods libraries in the Pods # Creates the targets which aggregate the Pods libraries in the Pods
# project and the relative support files. # project and the relative support files.
#
class AggregateTargetInstaller < TargetInstaller
# Creates the target in the Pods project and the relative support files.
#
# @return [void]
# #
def install! class AggregateTargetInstaller < TargetInstaller
UI.message "- Installing target `#{target.name}` #{target.platform}" do
add_target # Creates the target in the Pods project and the relative support files.
#
# @return [void]
#
def install!
UI.message "- Installing target `#{target.name}` #{target.platform}" do
add_target
end
end end
end end
end end
end end
end end
end
...@@ -2,136 +2,136 @@ module Pod ...@@ -2,136 +2,136 @@ module Pod
class Installer class Installer
class PodsProjectGenerator class PodsProjectGenerator
# Creates the target for the Pods libraries in the Pods project and the # Creates the target for the Pods libraries in the Pods project and the
# relative support files. # relative support files.
# #
class PodTargetInstaller < TargetInstaller class PodTargetInstaller < TargetInstaller
# Creates the target in the Pods project and the relative support files. # Creates the target in the Pods project and the relative support files.
# #
# @return [void] # @return [void]
# #
def install! def install!
add_target add_target
add_files_to_build_phases add_files_to_build_phases
add_resources_bundle_targets add_resources_bundle_targets
link_to_system_frameworks link_to_system_frameworks
end end
private
#-----------------------------------------------------------------------#
# Adds the build files of the pods to the target and adds a reference to private
# the frameworks of the Pods.
# #-----------------------------------------------------------------------#
# @note The Frameworks are used only for presentation purposes as the
# xcconfig is the authoritative source about their information. # Adds the build files of the pods to the target and adds a reference to
# # the frameworks of the Pods.
# @return [void] #
# # @note The Frameworks are used only for presentation purposes as the
def add_files_to_build_phases # xcconfig is the authoritative source about their information.
target.file_accessors.each do |file_accessor| #
consumer = file_accessor.spec_consumer # @return [void]
flags = compiler_flags_for_consumer(consumer) #
source_files = file_accessor.source_files def add_files_to_build_phases
file_refs = source_files.map { |sf| project.reference_for_path(sf) } target.file_accessors.each do |file_accessor|
target.target.add_file_references(file_refs, flags) consumer = file_accessor.spec_consumer
flags = compiler_flags_for_consumer(consumer)
source_files = file_accessor.source_files
file_refs = source_files.map { |sf| project.reference_for_path(sf) }
target.target.add_file_references(file_refs, flags)
end
end end
end
# Adds the resources of the Pods to the Pods project. # Adds the resources of the Pods to the Pods project.
# #
# @note The source files are grouped by Pod and in turn by subspec # @note The source files are grouped by Pod and in turn by subspec
# (recursively) in the resources group. # (recursively) in the resources group.
# #
# @return [void] # @return [void]
# #
def add_resources_bundle_targets def add_resources_bundle_targets
target.file_accessors.each do |file_accessor| target.file_accessors.each do |file_accessor|
file_accessor.resource_bundles.each do |bundle_name, paths| file_accessor.resource_bundles.each do |bundle_name, paths|
file_references = paths.map { |sf| project.reference_for_path(sf) } file_references = paths.map { |sf| project.reference_for_path(sf) }
bundle_target = project.new_resources_bundle(bundle_name, file_accessor.spec_consumer.platform_name) bundle_target = project.new_resources_bundle(bundle_name, file_accessor.spec_consumer.platform_name)
bundle_target.add_resources(file_references) bundle_target.add_resources(file_references)
target.user_build_configurations.each do |bc_name, type| target.user_build_configurations.each do |bc_name, type|
bundle_target.add_build_configuration(bc_name, type) bundle_target.add_build_configuration(bc_name, type)
end
target.add_dependency(bundle_target)
end end
target.add_dependency(bundle_target)
end end
end end
end
# Add a file reference to the system frameworks if needed and links the # Add a file reference to the system frameworks if needed and links the
# target to them. # target to them.
# #
# This is done only for informative purposes as the xcconfigs are the # This is done only for informative purposes as the xcconfigs are the
# authoritative source of the build settings. # authoritative source of the build settings.
# #
# @return [void] # @return [void]
# #
def link_to_system_frameworks def link_to_system_frameworks
target.specs.each do |spec| target.specs.each do |spec|
spec.consumer(target.platform).frameworks.each do |framework| spec.consumer(target.platform).frameworks.each do |framework|
project.add_system_framework(framework, target.target) project.add_system_framework(framework, target.target)
end
end end
end end
end
# TODO # TODO
# #
ENABLE_OBJECT_USE_OBJC_FROM = { ENABLE_OBJECT_USE_OBJC_FROM = {
:ios => Version.new('6'), :ios => Version.new('6'),
:osx => Version.new('10.8') :osx => Version.new('10.8')
} }
# Returns the compiler flags for the source files of the given specification. # Returns the compiler flags for the source files of the given specification.
# #
# The following behavior is regarding the `OS_OBJECT_USE_OBJC` flag. When # The following behavior is regarding the `OS_OBJECT_USE_OBJC` flag. When
# set to `0`, it will allow code to use `dispatch_release()` on >= iOS 6.0 # set to `0`, it will allow code to use `dispatch_release()` on >= iOS 6.0
# and OS X 10.8. # and OS X 10.8.
# #
# * New libraries that do *not* require ARC don’t need to care about this # * New libraries that do *not* require ARC don’t need to care about this
# issue at all. # issue at all.
# #
# * New libraries that *do* require ARC _and_ have a deployment target of # * New libraries that *do* require ARC _and_ have a deployment target of
# >= iOS 6.0 or OS X 10.8: # >= iOS 6.0 or OS X 10.8:
# #
# These no longer use `dispatch_release()` and should *not* have the # These no longer use `dispatch_release()` and should *not* have the
# `OS_OBJECT_USE_OBJC` flag set to `0`. # `OS_OBJECT_USE_OBJC` flag set to `0`.
# #
# **Note:** this means that these libraries *have* to specify the # **Note:** this means that these libraries *have* to specify the
# deployment target in order to function well. # deployment target in order to function well.
# #
# * New libraries that *do* require ARC, but have a deployment target of # * New libraries that *do* require ARC, but have a deployment target of
# < iOS 6.0 or OS X 10.8: # < iOS 6.0 or OS X 10.8:
# #
# These contain `dispatch_release()` calls and as such need the # These contain `dispatch_release()` calls and as such need the
# `OS_OBJECT_USE_OBJC` flag set to `1`. # `OS_OBJECT_USE_OBJC` flag set to `1`.
# #
# **Note:** libraries that do *not* specify a platform version are # **Note:** libraries that do *not* specify a platform version are
# assumed to have a deployment target of < iOS 6.0 or OS X 10.8. # assumed to have a deployment target of < iOS 6.0 or OS X 10.8.
# #
# For more information, see: http://opensource.apple.com/source/libdispatch/libdispatch-228.18/os/object.h # For more information, see: http://opensource.apple.com/source/libdispatch/libdispatch-228.18/os/object.h
# #
# @param [Specification::Consumer] consumer # @param [Specification::Consumer] consumer
# The consumer for the specification for which the compiler flags # The consumer for the specification for which the compiler flags
# are needed. # are needed.
# #
# @return [String] The compiler flags. # @return [String] The compiler flags.
# #
def compiler_flags_for_consumer(consumer) def compiler_flags_for_consumer(consumer)
flags = consumer.compiler_flags.dup flags = consumer.compiler_flags.dup
if consumer.requires_arc if consumer.requires_arc
flags << '-fobjc-arc' flags << '-fobjc-arc'
platform_name = consumer.platform_name platform_name = consumer.platform_name
spec_deployment_target = consumer.spec.deployment_target(platform_name) spec_deployment_target = consumer.spec.deployment_target(platform_name)
if spec_deployment_target.nil? || Version.new(spec_deployment_target) < ENABLE_OBJECT_USE_OBJC_FROM[platform_name] if spec_deployment_target.nil? || Version.new(spec_deployment_target) < ENABLE_OBJECT_USE_OBJC_FROM[platform_name]
flags << '-DOS_OBJECT_USE_OBJC=0' flags << '-DOS_OBJECT_USE_OBJC=0'
end end
end end
......
...@@ -78,6 +78,21 @@ module Pod ...@@ -78,6 +78,21 @@ module Pod
Lockfile.from_file(manifest_path) if manifest_path.exist? Lockfile.from_file(manifest_path) if manifest_path.exist?
end end
# Returns whether the version of CocoaPods used to generate the sandbox is
# is major than the given version.
#
# @param [String]
#
# @return [Bool]
#
def version_at_least?(version)
if manifest
manifest.cocoapods_version >= Version.new(version)
else
false
end
end
# @return [Installer::Analyzer::SpecsState] The state of the sandbox # @return [Installer::Analyzer::SpecsState] The state of the sandbox
# (added, deleted, changed and unchanged pods) as computed by the # (added, deleted, changed and unchanged pods) as computed by the
# analyzer. # analyzer.
......
...@@ -35,6 +35,10 @@ module Pod ...@@ -35,6 +35,10 @@ module Pod
label.upcase.gsub(/[^A-Z]/, '_') + '_' label.upcase.gsub(/[^A-Z]/, '_') + '_'
end end
def skip_installation?
false
end
# @return [String] A string suitable for debugging. # @return [String] A string suitable for debugging.
# #
def inspect def inspect
......
...@@ -15,6 +15,10 @@ module Pod ...@@ -15,6 +15,10 @@ module Pod
@file_accessors = [] @file_accessors = []
end end
def skip_installation?
target_definition.empty?
end
# @return [String] the label for the target. # @return [String] the label for the target.
# #
def label def label
......
...@@ -4,6 +4,10 @@ module Pod ...@@ -4,6 +4,10 @@ module Pod
class Installer class Installer
describe PodsProjectGenerator do describe PodsProjectGenerator do
before do
config.sandbox.stubs(:cocoapods_version).returns(Version.new(Pod::VERSION))
end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
describe "In general" do describe "In general" do
...@@ -167,7 +171,30 @@ module Pod ...@@ -167,7 +171,30 @@ module Pod
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
describe "#sync_target_dependencies" do describe "#add_missing_aggregate_targets_libraries" do
before do
project = Pod::Project.new(config.sandbox.project_path)
@aggregate_native_target = project.new_target(:static_library, 'Pods', :ios)
@pod_native_target = project.new_target(:static_library, 'Pods-BananaLib', :ios)
pod_target = PodTarget.new([], nil, config.sandbox)
pod_target.target = @pod_native_target
aggregate_target = AggregateTarget.new(nil, config.sandbox)
aggregate_target.pod_targets = [pod_target]
aggregate_target.target = @aggregate_native_target
@sut = PodsProjectGenerator.new(config.sandbox, [aggregate_target])
end
it "links the aggregate targets to the pod targets" do
@sut.send(:add_missing_aggregate_targets_libraries)
@aggregate_native_target.frameworks_build_phase.files.map(&:file_ref).should.include?(@pod_native_target.product_reference)
end
end
#-----------------------------------------------------------------------#
describe "#add_missing_target_dependencies" do
before do before do
project = Pod::Project.new(config.sandbox.project_path) project = Pod::Project.new(config.sandbox.project_path)
...@@ -188,14 +215,14 @@ module Pod ...@@ -188,14 +215,14 @@ module Pod
it "sets the pod targets as dependencies of the aggregate target" do it "sets the pod targets as dependencies of the aggregate target" do
@sut.send(:sync_target_dependencies) @sut.send(:add_missing_target_dependencies)
dependencies = @aggregate_target.target.dependencies dependencies = @aggregate_target.target.dependencies
dependencies.map { |d| d.target.name}.should == ["Pods-BananaLib", "Pods-monkey"] dependencies.map { |d| d.target.name}.should == ["Pods-BananaLib", "Pods-monkey"]
end end
it "sets the dependencies of the pod targets" do it "sets the dependencies of the pod targets" do
@pod_target_1.stubs(:dependencies).returns(['monkey']) @pod_target_1.stubs(:dependencies).returns(['monkey'])
@sut.send(:sync_target_dependencies) @sut.send(:add_missing_target_dependencies)
dependencies = @pod_target_1.target.dependencies dependencies = @pod_target_1.target.dependencies
dependencies.map { |d| d.target.name}.should == ["Pods-monkey"] dependencies.map { |d| d.target.name}.should == ["Pods-monkey"]
end end
...@@ -204,29 +231,6 @@ module Pod ...@@ -204,29 +231,6 @@ module Pod
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
describe "#sync_aggregate_targets_libraries" do
before do
project = Pod::Project.new(config.sandbox.project_path)
@aggregate_native_target = project.new_target(:static_library, 'Pods', :ios)
@pod_native_target = project.new_target(:static_library, 'Pods-BananaLib', :ios)
pod_target = PodTarget.new([], nil, config.sandbox)
pod_target.target = @pod_native_target
aggregate_target = AggregateTarget.new(nil, config.sandbox)
aggregate_target.pod_targets = [pod_target]
aggregate_target.target = @aggregate_native_target
@sut = PodsProjectGenerator.new(config.sandbox, [aggregate_target])
end
it "links the aggregate targets to the pod targets" do
@sut.send(:sync_aggregate_targets_libraries)
@aggregate_native_target.frameworks_build_phase.files.map(&:file_ref).should.include?(@pod_native_target.product_reference)
end
end
#-----------------------------------------------------------------------#
end end
end end
end end
...@@ -19,6 +19,20 @@ module Pod ...@@ -19,6 +19,20 @@ module Pod
@sandbox.manifest.should == nil @sandbox.manifest.should == nil
end end
describe "#version_at_least?" do
it "returns whether the version of CocoaPods used to generate the sandbox is major to the given one" do
manifest = stub(:cocoapods_version => Version.new('1.0'))
@sandbox.stubs(:manifest).returns(manifest)
@sandbox.version_at_least?('1.0.0').should.be.true
end
it "returns false if the manifest is not available" do
@sandbox.version_at_least?('0.0.1').should.be.false
end
end
it "returns the project" do it "returns the project" do
@sandbox.project.should == nil @sandbox.project.should == nil
end end
......
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