Commit 5dab3631 authored by Fabio Pelosin's avatar Fabio Pelosin

Merge branch 'lookback-pods-by-config'

* lookback-pods-by-config: (45 commits)
  [UserProjectIntegrator] Warn about xcconfig override after every installation /2
  [UserProjectIntegrator] Warn about xcconfig override after every installation
  [AggregateTarget] Add #user_targets
  [AggregateTarget] Documentation cleanup
  [Bundle] Update
  [PodTarget] Ensure that subspecs are on the same configurations
  add a space to the override warning
  [Docs] Some small fixes.
  [Changelog]
  [Integration] Disable xcproj in Xcodeproj
  [Project] Coherce preprocessor definitions to an array
  [PrivatePodXcconfig] Add inherited to GCC_PREPROCESSOR_DEFINITIONS
  [Project] Add preprocessor definition for build configurations
  [TargetEnvironmentHeader] Refactor
  [AggretateTarget] Expose specs by build configuration
  [PrefixHeader] Style fixes
  [Xcodeproj]: Fix issue for libraries with a space in the name
  [Examples] Update integration
  [Installer] Use downcase to validate configurations
  [XCConfigIntegrator] Downcase the name of the build configurations
  ...

Conflicts:
	CHANGELOG.md
	Gemfile.lock
	lib/cocoapods/installer.rb
	lib/cocoapods/target/aggregate_target.rb
	spec/integration.rb
parents 5870462b bbcf3cee
...@@ -6,6 +6,18 @@ To install or update CocoaPods see this [guide](http://docs.cocoapods.org/guides ...@@ -6,6 +6,18 @@ To install or update CocoaPods see this [guide](http://docs.cocoapods.org/guides
##### Enhancements ##### Enhancements
* Add support to specify dependencies per build configuration.
pod 'PonyDebugger', :configurations => ['Debug']
Currently configurations can only be specified per single Pod.
[Joachim Bengtsson](https://github.com/nevyn)
[Eloy Durán](https://github.com/alloy)
[Fabio Pelosin][irrationalfab]
[#1791](https://github.com/CocoaPods/CocoaPods/pull/1791)
[#1668](https://github.com/CocoaPods/CocoaPods/pull/1668)
[#731](https://github.com/CocoaPods/CocoaPods/pull/731)
* Added hooks for plugins. Currently only the installer hook is supported. * Added hooks for plugins. Currently only the installer hook is supported.
A plugin can register itself to be activated after the installation with the A plugin can register itself to be activated after the installation with the
following syntax: following syntax:
...@@ -27,6 +39,14 @@ To install or update CocoaPods see this [guide](http://docs.cocoapods.org/guides ...@@ -27,6 +39,14 @@ To install or update CocoaPods see this [guide](http://docs.cocoapods.org/guides
[Marius Rackwitz][mrackwitz] [Marius Rackwitz][mrackwitz]
[#2371](https://github.com/CocoaPods/CocoaPods/issues/2371) [#2371](https://github.com/CocoaPods/CocoaPods/issues/2371)
* Include configurations a user explicitly specifies in their Podfile when the
`--no-integrate` option is specified.
[Eloy Durán](https://github.com/alloy)
* Properly quote the `-isystem` values in the xcconfig files.
[Eloy Durán](https://github.com/alloy)
##### Bug Fixes ##### Bug Fixes
* Fixed pod repo push to first check if Specs directory exists and if so push * Fixed pod repo push to first check if Specs directory exists and if so push
......
GIT GIT
remote: https://github.com/CocoaPods/CLAide.git remote: https://github.com/CocoaPods/CLAide.git
revision: e64c76edd9dbc540776772097b78ae27720eccbb revision: 303b96021e0fdd0003a71f1f9bf6823a6262ba12
branch: master branch: master
specs: specs:
claide (0.6.1) claide (0.6.1)
GIT GIT
remote: https://github.com/CocoaPods/Core.git remote: https://github.com/CocoaPods/Core.git
revision: 75028fcea7c8e02cff17ada95bb17f123ac949cc revision: 2e66303717d72b23a98ea5341dc5b627f3eb97e7
branch: master branch: master
specs: specs:
cocoapods-core (0.33.1) cocoapods-core (0.33.1)
...@@ -18,7 +18,7 @@ GIT ...@@ -18,7 +18,7 @@ GIT
GIT GIT
remote: https://github.com/CocoaPods/Xcodeproj.git remote: https://github.com/CocoaPods/Xcodeproj.git
revision: f835e6e1145812ac04ac4b658321c727c2967547 revision: 13733a36b29d2a9698c3e2563b52a0b6339e90df
branch: master branch: master
specs: specs:
xcodeproj (0.18.0) xcodeproj (0.18.0)
...@@ -28,7 +28,7 @@ GIT ...@@ -28,7 +28,7 @@ GIT
GIT GIT
remote: https://github.com/CocoaPods/cocoapods-downloader.git remote: https://github.com/CocoaPods/cocoapods-downloader.git
revision: 27a5c58d7d7aaf8886c47624260d167fa776175c revision: 0e02c9da094a82c5049cbf7266d9eefef2fd5552
branch: master branch: master
specs: specs:
cocoapods-downloader (0.6.1) cocoapods-downloader (0.6.1)
...@@ -43,7 +43,7 @@ GIT ...@@ -43,7 +43,7 @@ GIT
GIT GIT
remote: https://github.com/CocoaPods/cocoapods-trunk.git remote: https://github.com/CocoaPods/cocoapods-trunk.git
revision: c62f86f83bf77faf8baf80359cc511dd1014fcfb revision: 72e02a7ad3f429a6e76e602a238e91eb55c44165
branch: master branch: master
specs: specs:
cocoapods-trunk (0.1.4) cocoapods-trunk (0.1.4)
......
...@@ -19,9 +19,10 @@ ...@@ -19,9 +19,10 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
1489BC7C65DCCDA21BD9C10D /* Pods-AFNetworking Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AFNetworking Example.release.xcconfig"; path = "Pods/Pods-AFNetworking Example.release.xcconfig"; sourceTree = "<group>"; };
206C0CA2FCD1CCE9783CC39F /* Pods-AFNetworking Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AFNetworking Example.debug.xcconfig"; path = "Pods/Pods-AFNetworking Example.debug.xcconfig"; sourceTree = "<group>"; };
6935B1E417A24F0E958977ED /* libPods-AFNetworking Example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AFNetworking Example.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 6935B1E417A24F0E958977ED /* libPods-AFNetworking Example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AFNetworking Example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
B304CCE7177D58DD00F4FC85 /* adn.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = adn.cer; sourceTree = SOURCE_ROOT; }; B304CCE7177D58DD00F4FC85 /* adn.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = adn.cer; sourceTree = SOURCE_ROOT; };
E74E8E7AFD3F4DCF9FEAB5B4 /* Pods-AFNetworking Example.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AFNetworking Example.xcconfig"; path = "Pods/Pods-AFNetworking Example.xcconfig"; sourceTree = "<group>"; };
F8129BFB1591061B009BFE23 /* AFNetworking Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AFNetworking Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; F8129BFB1591061B009BFE23 /* AFNetworking Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AFNetworking Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
F8129BFF1591061B009BFE23 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; F8129BFF1591061B009BFE23 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
F8129C021591061B009BFE23 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; F8129C021591061B009BFE23 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
...@@ -60,7 +61,8 @@ ...@@ -60,7 +61,8 @@
F8129C051591061B009BFE23 /* Classes */, F8129C051591061B009BFE23 /* Classes */,
F8129BFE1591061B009BFE23 /* Frameworks */, F8129BFE1591061B009BFE23 /* Frameworks */,
F8129BFC1591061B009BFE23 /* Products */, F8129BFC1591061B009BFE23 /* Products */,
E74E8E7AFD3F4DCF9FEAB5B4 /* Pods-AFNetworking Example.xcconfig */, 206C0CA2FCD1CCE9783CC39F /* Pods-AFNetworking Example.debug.xcconfig */,
1489BC7C65DCCDA21BD9C10D /* Pods-AFNetworking Example.release.xcconfig */,
); );
indentWidth = 4; indentWidth = 4;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -296,7 +298,7 @@ ...@@ -296,7 +298,7 @@
}; };
F8129C1A1591061B009BFE23 /* Debug */ = { F8129C1A1591061B009BFE23 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = E74E8E7AFD3F4DCF9FEAB5B4 /* Pods-AFNetworking Example.xcconfig */; baseConfigurationReference = 206C0CA2FCD1CCE9783CC39F /* Pods-AFNetworking Example.debug.xcconfig */;
buildSettings = { buildSettings = {
CODE_SIGN_IDENTITY = ""; CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
...@@ -310,7 +312,7 @@ ...@@ -310,7 +312,7 @@
}; };
F8129C1B1591061B009BFE23 /* Release */ = { F8129C1B1591061B009BFE23 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = E74E8E7AFD3F4DCF9FEAB5B4 /* Pods-AFNetworking Example.xcconfig */; baseConfigurationReference = 1489BC7C65DCCDA21BD9C10D /* Pods-AFNetworking Example.release.xcconfig */;
buildSettings = { buildSettings = {
CODE_SIGN_IDENTITY = ""; CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
......
...@@ -33,10 +33,11 @@ ...@@ -33,10 +33,11 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
08ACA902EBEF3347432C3442 /* Pods-AFNetworking iOS Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AFNetworking iOS Example.release.xcconfig"; path = "Pods/Pods-AFNetworking iOS Example.release.xcconfig"; sourceTree = "<group>"; };
17E95B75D4453CE0BA3028FF /* Pods-AFNetworking iOS Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AFNetworking iOS Example.debug.xcconfig"; path = "Pods/Pods-AFNetworking iOS Example.debug.xcconfig"; sourceTree = "<group>"; };
2982AD3117107C0000FFF048 /* adn.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = adn.cer; sourceTree = SOURCE_ROOT; }; 2982AD3117107C0000FFF048 /* adn.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = adn.cer; sourceTree = SOURCE_ROOT; };
50ABD6EC159FC2CE001BE42C /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 50ABD6EC159FC2CE001BE42C /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
9D87F8FEDE4A4313B0D579A3 /* libPods-AFNetworking iOS Example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AFNetworking iOS Example.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 9D87F8FEDE4A4313B0D579A3 /* libPods-AFNetworking iOS Example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AFNetworking iOS Example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
AE3A9F4CC86440AAA3CF5792 /* Pods-AFNetworking iOS Example.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AFNetworking iOS Example.xcconfig"; path = "Pods/Pods-AFNetworking iOS Example.xcconfig"; sourceTree = "<group>"; };
F8129C3815910830009BFE23 /* Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = SOURCE_ROOT; }; F8129C3815910830009BFE23 /* Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = SOURCE_ROOT; };
F8129C7215910C37009BFE23 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; }; F8129C7215910C37009BFE23 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
F8129C7315910C37009BFE23 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; }; F8129C7315910C37009BFE23 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; };
...@@ -130,7 +131,8 @@ ...@@ -130,7 +131,8 @@
F8E469ED1395812A00DB05C8 /* Images */, F8E469ED1395812A00DB05C8 /* Images */,
F8E469631395739D00DB05C8 /* Frameworks */, F8E469631395739D00DB05C8 /* Frameworks */,
F8E469611395739C00DB05C8 /* Products */, F8E469611395739C00DB05C8 /* Products */,
AE3A9F4CC86440AAA3CF5792 /* Pods-AFNetworking iOS Example.xcconfig */, 17E95B75D4453CE0BA3028FF /* Pods-AFNetworking iOS Example.debug.xcconfig */,
08ACA902EBEF3347432C3442 /* Pods-AFNetworking iOS Example.release.xcconfig */,
); );
indentWidth = 4; indentWidth = 4;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -356,7 +358,7 @@ ...@@ -356,7 +358,7 @@
}; };
F8E469821395739D00DB05C8 /* Debug */ = { F8E469821395739D00DB05C8 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = AE3A9F4CC86440AAA3CF5792 /* Pods-AFNetworking iOS Example.xcconfig */; baseConfigurationReference = 17E95B75D4453CE0BA3028FF /* Pods-AFNetworking iOS Example.debug.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
...@@ -378,7 +380,7 @@ ...@@ -378,7 +380,7 @@
}; };
F8E469831395739D00DB05C8 /* Release */ = { F8E469831395739D00DB05C8 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = AE3A9F4CC86440AAA3CF5792 /* Pods-AFNetworking iOS Example.xcconfig */; baseConfigurationReference = 08ACA902EBEF3347432C3442 /* Pods-AFNetworking iOS Example.release.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
......
...@@ -9,18 +9,18 @@ module Pod ...@@ -9,18 +9,18 @@ module Pod
# #
class PrefixHeader class PrefixHeader
# @return [Platform] the platform for which the prefix header will be # @return [Array<FileAccessor>] The file accessors for which to generate
# generated. # the prefix header.
# #
attr_reader :file_accessors attr_reader :file_accessors
attr_reader :platform
# @return [Array<LocalPod>] the LocalPod for the target for which the # @return [Platform] the platform for which the prefix header will be
# prefix header needs to be generated. # generated.
# #
# attr_reader :consumers attr_reader :platform
# @return [Array<String>] any header to import (with quotes). # @return [Array<String>] The list of the headers to import (with
# quotes).
# #
attr_reader :imports attr_reader :imports
...@@ -40,12 +40,14 @@ module Pod ...@@ -40,12 +40,14 @@ module Pod
# added to the top of the prefix header. For OS X `Cocoa/Cocoa.h` # added to the top of the prefix header. For OS X `Cocoa/Cocoa.h`
# is imported. # is imported.
# #
# @note Only unique prefix_header_contents are added to the prefix header. # @note Only unique prefix_header_contents are added to the prefix
# header.
# #
# @return [String] # @return [String]
# #
# @todo Subspecs can specify prefix header information too. # @todo Subspecs can specify prefix header information too.
# @todo Check to see if we have a similar duplication issue with file_accessor.prefix_header. # @todo Check to see if we have a similar duplication issue with
# file_accessor.prefix_header.
# #
def generate def generate
result = "#ifdef __OBJC__\n" result = "#ifdef __OBJC__\n"
......
require 'active_support/core_ext/string/strip'
module Pod module Pod
module Generator module Generator
...@@ -23,14 +25,15 @@ module Pod ...@@ -23,14 +25,15 @@ module Pod
# #
class TargetEnvironmentHeader class TargetEnvironmentHeader
# @return [Array<LocalPod>] the specifications installed for the target. # @return [Hash{String => LocalPod}] the specifications installed for
# the target by build configuration name.
# #
attr_reader :specs attr_reader :specs_by_configuration
# @param [Array<LocalPod>] pods @see pods # @param [Array<Specification>] pods @see pods
# #
def initialize(specs) def initialize(specs_by_configuration)
@specs = specs @specs_by_configuration = specs_by_configuration
end end
# Generates and saves the file. # Generates and saves the file.
...@@ -40,45 +43,131 @@ module Pod ...@@ -40,45 +43,131 @@ module Pod
# #
# @return [void] # @return [void]
# #
def save_as(pathname) def generate
pathname.open('w') do |source| result = "\n#{notice}\n\n"
source.puts common_specs = common_specs(specs_by_configuration)
source.puts "// To check if a library is compiled with CocoaPods you" common_specs.each { |spec| result << spec_defines(spec) }
source.puts "// can use the `COCOAPODS` macro definition which is"
source.puts "// defined in the xcconfigs so it is available in" specs_by_config = specs_scoped_by_configuration(common_specs, specs_by_configuration)
source.puts "// headers also when they are imported in the client" specs_by_config.each do |config, specs|
source.puts "// project." result << "// #{config} build configuration\n"
source.puts result << "#ifdef #{config.gsub(' ', '_').upcase}\n\n"
source.puts specs.each { |spec| result << spec_defines(spec, 1) }
specs.each do |spec| result << "#endif\n"
spec_name = safe_spec_name(spec.name)
source.puts "// #{spec.name}"
source.puts "#define COCOAPODS_POD_AVAILABLE_#{spec_name}"
if spec.version.semantic?
source.puts "#define COCOAPODS_VERSION_MAJOR_#{spec_name} #{spec.version.major}"
source.puts "#define COCOAPODS_VERSION_MINOR_#{spec_name} #{spec.version.minor}"
source.puts "#define COCOAPODS_VERSION_PATCH_#{spec_name} #{spec.version.patch}"
else
source.puts "// This library does not follow semantic-versioning,"
source.puts "// so we were not able to define version macros."
source.puts "// Please contact the author."
source.puts "// Version: #{spec.version}."
end
source.puts
end
end end
result
end end
#-----------------------------------------------------------------------# def save_as(path)
path.open('w') { |header| header.write(generate) }
end
private private
# !@group Private Helpers # !@group Private Helpers
#-----------------------------------------------------------------------#
# @return [Array<Specification>] The list of the specifications present
# in all build configurations sorted by name.
#
# @param [Hash{String => Array<Specification>}] specs_by_configuration
# The specs grouped by build configuration.
#
def common_specs(specs_by_configuration)
result = specs_by_configuration.values.flatten.uniq
specs_by_configuration.values.each do |configuration_specs|
result = result & configuration_specs
end
result.sort_by(&:name)
end
# @return [Hash{String => Array<Specification>}] The list of the
# specifications not present in all build configurations sorted
# by name and grouped by build configuration name.
#
# @param [Hash{String => Array<Specification>}] specs_by_configuration
# The specs grouped by build configuration.
#
def specs_scoped_by_configuration(common_specs, specs_by_configuration)
result = {}
specs_by_configuration.each do |configuration, all_specs|
specs = all_specs.sort_by(&:name) - common_specs
result[configuration] = specs unless specs.empty?
end
result
end
# @return The sanitized name of a specification to make it suitable to be
# used as part of an identifier of a define statement.
#
# @param [String] spec_name
# The name of the spec.
#
def safe_spec_name(spec_name) def safe_spec_name(spec_name)
spec_name.gsub(/[^\w]/,'_') spec_name.gsub(/[^\w]/,'_')
end end
# @return [String]
#
def notice
<<-DOC.strip_heredoc
// To check if a library is compiled with CocoaPods you
// can use the `COCOAPODS` macro definition which is
// defined in the xcconfigs so it is available in
// headers also when they are imported in the client
// project.
DOC
end
# @return [String]
#
def spec_defines(spec, indent_count = 0)
spec_name = safe_spec_name(spec.name)
result = "// #{spec.name}\n"
result << "#define COCOAPODS_POD_AVAILABLE_#{spec_name}\n"
if spec.version.semantic?
result << semantic_version_defines(spec)
else
result << non_semantic_version_notice(spec)
end
result << "\n"
indent(result, indent_count)
end
def indent(string, indent_count)
indent = ' ' * (indent_count * 2)
lines = string.lines.map { |line|
if line == "\n"
line
else
"#{indent}#{line}"
end
}
lines.join
end
# @return [String]
#
def semantic_version_defines(spec)
spec_name = safe_spec_name(spec.name)
<<-DOC.strip_heredoc
#define COCOAPODS_VERSION_MAJOR_#{spec_name} #{spec.version.major}
#define COCOAPODS_VERSION_MINOR_#{spec_name} #{spec.version.minor}
#define COCOAPODS_VERSION_PATCH_#{spec_name} #{spec.version.patch}
DOC
end
# @return [String]
#
def non_semantic_version_notice(spec)
<<-DOC.strip_heredoc
// This library does not follow semantic-versioning,
// so we were not able to define version macros.
// Please contact the author.
// Version: #{spec.version}.
DOC
end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
end end
......
...@@ -12,8 +12,13 @@ module Pod ...@@ -12,8 +12,13 @@ module Pod
# @param [Target] target @see target # @param [Target] target @see target
# #
def initialize(target) # @param [String] configuration_name
# The name of the build configuration to generate this xcconfig
# for.
#
def initialize(target, configuration_name)
@target = target @target = target
@configuration_name = configuration_name
end end
# @return [Xcodeproj::Config] The generated xcconfig. # @return [Xcodeproj::Config] The generated xcconfig.
...@@ -54,6 +59,8 @@ module Pod ...@@ -54,6 +59,8 @@ module Pod
}) })
target.pod_targets.each do |pod_target| target.pod_targets.each do |pod_target|
next unless pod_target.include_in_build_config?(@configuration_name)
pod_target.file_accessors.each do |file_accessor| pod_target.file_accessors.each do |file_accessor|
XCConfigHelper.add_spec_build_settings_to_xcconfig(file_accessor.spec_consumer, @xcconfig) XCConfigHelper.add_spec_build_settings_to_xcconfig(file_accessor.spec_consumer, @xcconfig)
file_accessor.vendored_frameworks.each do |vendored_framework| file_accessor.vendored_frameworks.each do |vendored_framework|
...@@ -63,6 +70,13 @@ module Pod ...@@ -63,6 +70,13 @@ module Pod
XCConfigHelper.add_library_build_settings(vendored_library, @xcconfig, target.sandbox.root) XCConfigHelper.add_library_build_settings(vendored_library, @xcconfig, target.sandbox.root)
end end
end end
# Add pod static lib to list of libraries that are to be linked with
# the user’s project.
@xcconfig.merge!({
'OTHER_LDFLAGS' => %Q(-l "#{pod_target.name}")
})
end end
# TODO Need to decide how we are going to ensure settings like these # TODO Need to decide how we are going to ensure settings like these
......
...@@ -52,7 +52,7 @@ module Pod ...@@ -52,7 +52,7 @@ module Pod
'OTHER_LDFLAGS' => XCConfigHelper.default_ld_flags(target), 'OTHER_LDFLAGS' => XCConfigHelper.default_ld_flags(target),
'PODS_ROOT' => '${SRCROOT}', 'PODS_ROOT' => '${SRCROOT}',
'HEADER_SEARCH_PATHS' => XCConfigHelper.quote(search_paths), 'HEADER_SEARCH_PATHS' => XCConfigHelper.quote(search_paths),
'GCC_PREPROCESSOR_DEFINITIONS' => 'COCOAPODS=1', 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
# 'USE_HEADERMAP' => 'NO' # 'USE_HEADERMAP' => 'NO'
} }
......
...@@ -97,6 +97,7 @@ module Pod ...@@ -97,6 +97,7 @@ module Pod
def resolve_dependencies def resolve_dependencies
UI.section "Analyzing dependencies" do UI.section "Analyzing dependencies" do
analyze analyze
validate_build_configurations
prepare_for_legacy_compatibility prepare_for_legacy_compatibility
clean_sandbox clean_sandbox
end end
...@@ -117,7 +118,6 @@ module Pod ...@@ -117,7 +118,6 @@ module Pod
install_file_references install_file_references
install_libraries install_libraries
set_target_dependencies set_target_dependencies
link_aggregate_target
run_podfile_post_install_hooks run_podfile_post_install_hooks
write_pod_project write_pod_project
write_lockfiles write_lockfiles
...@@ -178,6 +178,23 @@ module Pod ...@@ -178,6 +178,23 @@ module Pod
@aggregate_targets = analyzer.result.targets @aggregate_targets = analyzer.result.targets
end end
# Ensures that the white-listed build configurations are known to prevent
# silent typos.
#
# @raise If a unknown user configuration is found.
#
def validate_build_configurations
whitelisted_configs = pod_targets.map do |target|
target.target_definition.all_whitelisted_configurations.map(&:downcase)
end.flatten.uniq
all_user_configurations = analysis_result.all_user_build_configurations.keys.map(&:downcase)
remainder = whitelisted_configs - all_user_configurations
unless remainder.empty?
raise Informative, "Unknown #{'configuration'.pluralize(remainder.size)} whitelisted: #{remainder.sort.to_sentence}."
end
end
# Prepares the Pods folder in order to be compatible with the most recent # Prepares the Pods folder in order to be compatible with the most recent
# version of CocoaPods. # version of CocoaPods.
# #
...@@ -424,21 +441,6 @@ module Pod ...@@ -424,21 +441,6 @@ module Pod
end end
end end
# Links the aggregate targets with all the dependent libraries.
#
# @note This is run in the integration step to ensure that targets
# have been created for all per spec libraries.
#
def link_aggregate_target
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
native_target.frameworks_build_phase.add_file_reference(product)
end
end
end
# Writes the Pods project to the disk. # Writes the Pods project to the disk.
# #
# @return [void] # @return [void]
......
...@@ -200,7 +200,7 @@ module Pod ...@@ -200,7 +200,7 @@ module Pod
else else
target.client_root = config.installation_root target.client_root = config.installation_root
target.user_target_uuids = [] target.user_target_uuids = []
target.user_build_configurations = {} target.user_build_configurations = target_definition.build_configurations || {}
if target_definition.platform.name == :osx if target_definition.platform.name == :osx
target.archs = '$(ARCHS_STANDARD_64_BIT)' target.archs = '$(ARCHS_STANDARD_64_BIT)'
end end
...@@ -443,9 +443,7 @@ module Pod ...@@ -443,9 +443,7 @@ module Pod
def compute_user_build_configurations(target_definition, user_targets) def compute_user_build_configurations(target_definition, user_targets)
if user_targets if user_targets
user_targets.map { |t| t.build_configurations.map(&:name) }.flatten.inject({}) do |hash, name| user_targets.map { |t| t.build_configurations.map(&:name) }.flatten.inject({}) do |hash, name|
unless name == 'Debug' || name == 'Release' hash[name] = name == 'Debug' ? :debug : :release
hash[name] = :release
end
hash hash
end.merge(target_definition.build_configurations || {}) end.merge(target_definition.build_configurations || {})
else else
......
...@@ -32,15 +32,14 @@ module Pod ...@@ -32,15 +32,14 @@ module Pod
# @return [void] # @return [void]
# #
def create_xcconfig_file def create_xcconfig_file
path = library.xcconfig_path target.build_configurations.each do |configuration|
UI.message "- Generating xcconfig file at #{UI.path(path)}" do path = library.xcconfig_path(configuration.name)
gen = Generator::XCConfig::AggregateXCConfig.new(library) UI.message "- Generating #{configuration.name} xcconfig file at #{UI.path(path)}" do
gen = Generator::XCConfig::AggregateXCConfig.new(library, configuration.name)
gen.save_as(path) gen.save_as(path)
library.xcconfig = gen.xcconfig library.xcconfigs[configuration.name] = gen.xcconfig
xcconfig_file_ref = add_file_to_support_group(path) xcconfig_file_ref = add_file_to_support_group(path)
configuration.base_configuration_reference = xcconfig_file_ref
target.build_configurations.each do |c|
c.base_configuration_reference = xcconfig_file_ref
end end
end end
end end
...@@ -51,7 +50,7 @@ module Pod ...@@ -51,7 +50,7 @@ module Pod
def create_target_environment_header def create_target_environment_header
path = library.target_environment_header_path path = library.target_environment_header_path
UI.message "- Generating target environment header at #{UI.path(path)}" do UI.message "- Generating target environment header at #{UI.path(path)}" do
generator = Generator::TargetEnvironmentHeader.new(library.pod_targets.map { |l| l.specs }.flatten) generator = Generator::TargetEnvironmentHeader.new(library.specs_by_build_configuration)
generator.save_as(path) generator.save_as(path)
add_file_to_support_group(path) add_file_to_support_group(path)
end end
......
...@@ -62,6 +62,7 @@ module Pod ...@@ -62,6 +62,7 @@ module Pod
create_workspace create_workspace
integrate_user_targets integrate_user_targets
warn_about_empty_podfile warn_about_empty_podfile
warn_about_xcconfig_overrides
end end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
...@@ -133,6 +134,28 @@ module Pod ...@@ -133,6 +134,28 @@ module Pod
end end
end end
# Checks whether the settings of the CocoaPods generated xcconfig are
# overridden by the build configuration of a target and prints a
# warning to inform the user if needed.
#
def warn_about_xcconfig_overrides
targets.each do |aggregate_target|
aggregate_target.user_targets.each do |user_target|
user_target.build_configurations.each do |config|
xcconfig = aggregate_target.xcconfigs[config.name]
if xcconfig
xcconfig.to_hash.keys.each do |key|
target_value = config.build_settings[key]
if target_value && !target_value.include?('$(inherited)')
print_override_warning(aggregate_target, user_target, config, key)
end
end
end
end
end
end
end
private private
# @!group Private Helpers # @!group Private Helpers
...@@ -169,11 +192,37 @@ module Pod ...@@ -169,11 +192,37 @@ module Pod
end.compact.uniq end.compact.uniq
end end
def targets_to_integrate def targets_to_integrate
targets.reject { |target| target.target_definition.empty? } targets.reject { |target| target.target_definition.empty? }
end end
# Prints a warning informing the user that a build configuration of
# the integrated target is overriding the CocoaPods build settings.
#
# @param [Target::AggregateTarget] aggregate_target
# The umbrella target.
#
# @param [XcodeProj::PBXNativeTarget] user_target
# The native target.
#
# @param [Xcodeproj::XCBuildConfiguration] config
# The build configuration.
#
# @param [String] key
# The key of the overridden build setting.
#
def print_override_warning(aggregate_target, user_target, config, key)
actions = [
"Use the `$(inherited)` flag, or",
"Remove the build settings from the target."
]
message = "The `#{user_target.name} [#{config.name}]` " \
"target overrides the `#{key}` build setting defined in " \
"`#{aggregate_target.xcconfig_relative_path(config.name)}'. " \
"This can lead to problems with the CocoaPods installation"
UI.warn(message, actions)
end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
end end
......
...@@ -9,6 +9,8 @@ module Pod ...@@ -9,6 +9,8 @@ module Pod
# #
class TargetIntegrator class TargetIntegrator
autoload :XCConfigIntegrator, 'cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator'
# @return [Target] the target that should be integrated. # @return [Target] the target that should be integrated.
# #
attr_reader :target attr_reader :target
...@@ -26,54 +28,15 @@ module Pod ...@@ -26,54 +28,15 @@ module Pod
# @return [void] # @return [void]
# #
def integrate! def integrate!
return if native_targets.empty?
UI.section(integration_message) do UI.section(integration_message) do
add_xcconfig_base_configuration XCConfigIntegrator.integrate(target, native_targets)
unless native_targets_to_integrate.empty?
add_pods_library add_pods_library
add_copy_resources_script_phase add_copy_resources_script_phase
add_check_manifest_lock_script_phase add_check_manifest_lock_script_phase
user_project.save
end
end
# @return [Array<PBXNativeTarget>] the user targets for integration.
#
def native_targets
unless @native_targets
target_uuids = target.user_target_uuids
native_targets = target_uuids.map do |uuid|
native_target = user_project.objects_by_uuid[uuid]
unless native_target
raise Informative, "[Bug] Unable to find the target with " \
"the `#{uuid}` UUID for the `#{target}` integration library"
end
native_target
end
non_integrated = 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 = non_integrated user_project.save
end
@native_targets
end
# Read the project from the disk to ensure that it is up to date as
# other TargetIntegrators might have modified it.
#
def user_project
@user_project ||= Xcodeproj::Project.open(target.user_project_path)
end end
# Read the pods project from the disk to ensure that it is up to date as
# other TargetIntegrators might have modified it.
#
def pods_project
@pods_project ||= Xcodeproj::Project.open(target.sandbox.project_path)
end end
# @return [String] a string representation suitable for debugging. # @return [String] a string representation suitable for debugging.
...@@ -82,41 +45,11 @@ module Pod ...@@ -82,41 +45,11 @@ module Pod
"#<#{self.class} for target `#{target.label}'>" "#<#{self.class} for target `#{target.label}'>"
end end
#---------------------------------------------------------------------#
# @!group Integration steps
private private
# @return [Specification::Consumer] the consumer for the specifications. # @!group Integration steps
# #---------------------------------------------------------------------#
def spec_consumers
@spec_consumers ||= target.pod_targets.map(&:file_accessors).flatten.map(&:spec_consumer)
end
# Adds the `xcconfig` configurations files generated for the current
# {TargetDefinition} to the build configurations of the targets that
# should be integrated.
#
# @note It also checks if any build setting of the build
# configurations overrides the `xcconfig` file and warns the
# user.
#
# @todo If the xcconfig is already set don't override it and inform
# the user.
#
# @return [void]
#
def add_xcconfig_base_configuration
xcconfig = user_project.files.select { |f| f.path == target.xcconfig_relative_path }.first ||
user_project.new_file(target.xcconfig_relative_path)
native_targets.each do |native_target|
check_overridden_build_settings(target.xcconfig, native_target)
native_target.build_configurations.each do |config|
config.base_configuration_reference = xcconfig
end
end
end
# Adds spec libraries to the frameworks build phase of the # Adds spec libraries to the frameworks build phase of the
# {TargetDefinition} integration libraries. Adds a file reference to # {TargetDefinition} integration libraries. Adds a file reference to
...@@ -127,7 +60,7 @@ module Pod ...@@ -127,7 +60,7 @@ module Pod
# #
def add_pods_library def add_pods_library
frameworks = user_project.frameworks_group frameworks = user_project.frameworks_group
native_targets.each do |native_target| native_targets_to_integrate.each do |native_target|
library = frameworks.files.select { |f| f.path == target.product_name }.first || library = frameworks.files.select { |f| f.path == target.product_name }.first ||
frameworks.new_product_ref_for_target(target.name, :static_library) frameworks.new_product_ref_for_target(target.name, :static_library)
unless native_target.frameworks_build_phase.files_references.include?(library) unless native_target.frameworks_build_phase.files_references.include?(library)
...@@ -144,7 +77,7 @@ module Pod ...@@ -144,7 +77,7 @@ module Pod
# #
def add_copy_resources_script_phase def add_copy_resources_script_phase
phase_name = "Copy Pods Resources" phase_name = "Copy Pods Resources"
native_targets.each do |native_target| native_targets_to_integrate.each do |native_target|
phase = native_target.shell_script_build_phases.select { |bp| bp.name == phase_name }.first || phase = native_target.shell_script_build_phases.select { |bp| bp.name == phase_name }.first ||
native_target.new_shell_script_build_phase(phase_name) native_target.new_shell_script_build_phase(phase_name)
path = target.copy_resources_script_relative_path path = target.copy_resources_script_relative_path
...@@ -164,7 +97,7 @@ module Pod ...@@ -164,7 +97,7 @@ module Pod
# #
def add_check_manifest_lock_script_phase def add_check_manifest_lock_script_phase
phase_name = 'Check Pods Manifest.lock' phase_name = 'Check Pods Manifest.lock'
native_targets.each do |native_target| native_targets_to_integrate.each do |native_target|
next if native_target.shell_script_build_phases.any? { |phase| phase.name == phase_name } next if native_target.shell_script_build_phases.any? { |phase| phase.name == phase_name }
phase = native_target.project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) phase = native_target.project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
native_target.build_phases.unshift(phase) native_target.build_phases.unshift(phase)
...@@ -182,42 +115,47 @@ module Pod ...@@ -182,42 +115,47 @@ module Pod
end end
end end
#---------------------------------------------------------------------#
# @!group Private helpers.
private private
# Informs the user about any build setting of the target which might # @!group Private helpers
# override the given xcconfig file. #---------------------------------------------------------------------#
#
# @return [void]
#
def check_overridden_build_settings(xcconfig, native_target)
return unless xcconfig
configs_by_overridden_key = {} # @return [Array<PBXNativeTarget>] The list of all the targets that
native_target.build_configurations.each do |config| # match the given target.
xcconfig.attributes.keys.each do |key| #
target_value = config.build_settings[key] def native_targets
@native_targets ||= target.user_targets(user_project)
end
if target_value && !target_value.include?('$(inherited)') # @return [Array<PBXNativeTarget>] The list of the targets
configs_by_overridden_key[key] ||= [] # that have not been integrated by past installations
configs_by_overridden_key[key] << config.name # 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 end
configs_by_overridden_key.each do |key, config_names|
name = "#{native_target.name} [#{config_names.join(' - ')}]"
actions = [
"Use the `$(inherited)` flag, or",
"Remove the build settings from the target."
]
UI.warn("The target `#{name}` overrides the `#{key}` build " \
"setting defined in `#{target.xcconfig_relative_path}'.",
actions)
end end
@native_targets_to_integrate
end end
# Read the project from the disk to ensure that it is up to date as
# other TargetIntegrators might have modified it.
#
def user_project
@user_project ||= Xcodeproj::Project.open(target.user_project_path)
end
# @return [Specification::Consumer] the consumer for the specifications.
#
def spec_consumers
@spec_consumers ||= target.pod_targets.map(&:file_accessors).flatten.map(&:spec_consumer)
end end
# @return [String] the message that should be displayed for the target # @return [String] the message that should be displayed for the target
...@@ -229,9 +167,6 @@ module Pod ...@@ -229,9 +167,6 @@ module Pod
"into aggregate target #{target.name} " \ "into aggregate target #{target.name} " \
"of project #{UI.path target.user_project_path}." "of project #{UI.path target.user_project_path}."
end end
#---------------------------------------------------------------------#
end end
end end
end end
......
module Pod
class Installer
class UserProjectIntegrator
class TargetIntegrator
# Configures an user target to use the CocoaPods xcconfigs which allow
# lo link against the Pods.
#
class XCConfigIntegrator
# Integrates the user target.
#
# @param [Target::AggregateTarget] pod_bundle
# The Pods bundle.
#
# @param [Array<PBXNativeTarget>] targets
# The native targets associated which should be integrated
# with the Pod bundle.
#
def self.integrate(pod_bundle, targets)
targets.each do |target|
target.build_configurations.each do |config|
update_from_cocoapods_0_33_1(pod_bundle, targets)
set_target_xcconfig(pod_bundle, config)
end
end
end
private
# @!group Integration steps
#-------------------------------------------------------------------#
# Removes the xcconfig used up to CocoaPods 0.33 from the project and
# deletes the file if it exists.
#
# @param [Target::AggregateTarget] pod_bundle
# The Pods bundle.
#
# @param [XcodeProj::PBXNativeTarget] target
# The native targets.
#
# @todo This can be removed for CocoaPods 1.0
#
def self.update_from_cocoapods_0_33_1(pod_bundle, targets)
targets.map(&:project).uniq.each do |project|
path = pod_bundle.xcconfig_relative_path(nil)
file_ref = project.files.find { |f| f.path == path }
if file_ref
UI.message "- Removing (#{path})" do
file_ref.remove_from_project
absolute_path = pod_bundle.xcconfig_path
File.delete(absolute_path) if File.exist?(absolute_path)
end
end
end
end
# Creates a file reference to the xcconfig generated by
# CocoaPods (if needed) and sets it as the base configuration of
# build configuration of the user target.
#
# @param [Target::AggregateTarget] pod_bundle
# The Pods bundle.
#
# @param [[Xcodeproj::XCBuildConfiguration] config
# The build configuration.
#
def self.set_target_xcconfig(pod_bundle, config)
path = pod_bundle.xcconfig_relative_path(config.name)
file_ref = config.project.files.find { |f| f.path == path }
file_ref ||= config.project.new_file(path)
config.base_configuration_reference = file_ref
end
private
# @!group Private helpers
#-------------------------------------------------------------------#
# Prints a warning informing the user that a build configuration of
# the integrated target is overriding the CocoaPods build settings.
#
# @param [Target::AggregateTarget] pod_bundle
# The Pods bundle.
#
# @param [XcodeProj::PBXNativeTarget] target
# The native target.
#
# @param [Xcodeproj::XCBuildConfiguration] config
# The build configuration.
#
# @param [String] key
# The key of the overridden build setting.
#
def self.print_override_warning(pod_bundle, target, config, key)
actions = [
"Use the `$(inherited)` flag, or",
"Remove the build settings from the target."
]
message = "The `#{target.name} [#{config.name}]` " \
"target overrides the `#{key}` build setting defined in " \
"`#{pod_bundle.xcconfig_relative_path(config.name)}'. " \
"This can lead to problems with the CocoaPods installation"
UI.warn(message, actions)
end
end
end
end
end
end
...@@ -193,6 +193,37 @@ module Pod ...@@ -193,6 +193,37 @@ module Pod
podfile_ref podfile_ref
end end
# Adds a new build configuration to the project and populates it with
# default settings according to the provided type.
#
# @note This method extends the original Xcodeproj implementation to
# include a preprocessor definition named after the build
# setting. This is done to support the TargetEnvironmentHeader
# specification of Pods available only on certain build
# configurations.
#
# @param [String] name
# The name of the build configuration.
#
# @param [Symbol] type
# The type of the build configuration used to populate the build
# settings, must be :debug or :release.
#
# @return [XCBuildConfiguration] The new build configuration.
#
def add_build_configuration(name, type)
build_configuration = super
values = ["#{name.gsub(' ', '_').upcase}=1"]
settings = build_configuration.build_settings
definitions = Array(settings['GCC_PREPROCESSOR_DEFINITIONS'])
values.each do |value|
unless definitions.include?(value)
definitions << value
end
end
settings['GCC_PREPROCESSOR_DEFINITIONS'] = definitions
build_configuration
end
private private
......
...@@ -77,11 +77,19 @@ module Pod ...@@ -77,11 +77,19 @@ module Pod
@sandbox.library_support_files_dir(name) @sandbox.library_support_files_dir(name)
end end
# @param [String] variant
# The variant of the xcconfig. Used to differentiate build
# configurations.
#
# @return [Pathname] the absolute path of the xcconfig file. # @return [Pathname] the absolute path of the xcconfig file.
# #
def xcconfig_path def xcconfig_path(variant = nil)
if variant
support_files_root + "#{label}.#{variant.downcase}.xcconfig"
else
support_files_root + "#{label}.xcconfig" support_files_root + "#{label}.xcconfig"
end end
end
# @return [Pathname] the absolute path of the private xcconfig file. # @return [Pathname] the absolute path of the private xcconfig file.
# #
......
...@@ -13,6 +13,7 @@ module Pod ...@@ -13,6 +13,7 @@ module Pod
@sandbox = sandbox @sandbox = sandbox
@pod_targets = [] @pod_targets = []
@file_accessors = [] @file_accessors = []
@xcconfigs = {}
end end
# @return [String] the label for the target. # @return [String] the label for the target.
...@@ -37,20 +38,37 @@ module Pod ...@@ -37,20 +38,37 @@ module Pod
attr_accessor :user_project_path attr_accessor :user_project_path
# @return [Array<String>] the list of the UUIDs of the user targets that # @return [Array<String>] the list of the UUIDs of the user targets that
# will be integrated by this target as identified by the analizer. # will be integrated by this target as identified by the analyzer.
# #
# @note The target instances are not stored to prevent editing different # @note The target instances are not stored to prevent editing different
# instances. # instances.
# #
attr_accessor :user_target_uuids attr_accessor :user_target_uuids
# @return [Xcodeproj::Config] The configuration file of the target. # @return [Array<PBXNativeTarget>] The list of all the user targets that
# will be integrated by this target.
# #
# @note The configuration is generated by the {TargetInstaller} and def user_targets(project = nil)
project ||= Xcodeproj::Project.open(user_project_path)
user_target_uuids.map do |uuid|
native_target = project.objects_by_uuid[uuid]
unless native_target
raise Informative, "[Bug] Unable to find the target with " \
"the `#{uuid}` UUID for the `#{self}` integration library"
end
native_target
end
end
# @return [Hash<String, Xcodeproj::Config>] Map from configuration name to
# configuration file for the target
#
# @note The configurations are generated by the {TargetInstaller} and
# used by {UserProjectIntegrator} to check for any overridden # used by {UserProjectIntegrator} to check for any overridden
# values. # values.
# #
attr_accessor :xcconfig attr_reader :xcconfigs
# @return [Array<PodTarget>] The dependencies for this target. # @return [Array<PodTarget>] The dependencies for this target.
# #
...@@ -62,6 +80,19 @@ module Pod ...@@ -62,6 +80,19 @@ module Pod
pod_targets.map(&:specs).flatten pod_targets.map(&:specs).flatten
end end
# @return [Hash{Symbol => Array<PodTarget>}] The pod targets for each
# build configuration.
#
def specs_by_build_configuration
result = {}
user_build_configurations.keys.each do |build_configuration|
result[build_configuration] = pod_targets.select do |pod_target|
pod_target.include_in_build_config?(build_configuration)
end.map(&:specs).flatten
end
result
end
# @return [Array<Specification::Consumer>] The consumers of the Pod. # @return [Array<Specification::Consumer>] The consumers of the Pod.
# #
def spec_consumers def spec_consumers
...@@ -90,11 +121,12 @@ module Pod ...@@ -90,11 +121,12 @@ module Pod
"${SRCROOT}/#{support_files_root.relative_path_from(client_root)}" "${SRCROOT}/#{support_files_root.relative_path_from(client_root)}"
end end
# @param [String] config_name The build configuration name to get the xcconfig for
# @return [String] The path of the xcconfig file relative to the root of # @return [String] The path of the xcconfig file relative to the root of
# the user project. # the user project.
# #
def xcconfig_relative_path def xcconfig_relative_path(config_name)
relative_to_srcroot(xcconfig_path).to_s relative_to_srcroot(xcconfig_path(config_name)).to_s
end end
# @return [String] The path of the copy resources script relative to the # @return [String] The path of the copy resources script relative to the
......
...@@ -64,5 +64,40 @@ module Pod ...@@ -64,5 +64,40 @@ module Pod
end.flatten end.flatten
end end
# Checks if the target should be included in the build configuration with
# the given name.
#
# @param [String] configuration_name
# The name of the build configuration.
#
def include_in_build_config?(configuration_name)
whitelists = target_definition_dependencies.map do |dependency|
target_definition.pod_whitelisted_for_configuration?(dependency.name, configuration_name)
end.uniq
if whitelists.empty?
return true
elsif whitelists.count == 1
whitelists.first
else
raise Informative, "The subspecs of `#{pod_name}` are linked to " \
"different build configurations for the `#{target_definition}` " \
"target. CocoaPods does not support subspecs across different " \
"build configurations."
end
end
private
# @return [Array<Dependency>] The dependency of the target definition for
# this Pod. Return an empty array if the Pod is not a direct
# dependency of the target definition but the dependency of one or
# more Pods.
#
def target_definition_dependencies
target_definition.dependencies.select do |dependency|
Specification.root_name(dependency.name) == pod_name
end
end
end end
end end
Subproject commit 9ff0ddd87c25f7357a70e8863cef47b0e2557eca Subproject commit 169cd92092a35deaa21330963369b98a1f235264
...@@ -50,7 +50,6 @@ require 'colored' ...@@ -50,7 +50,6 @@ require 'colored'
require "clintegracon" require "clintegracon"
require "integration/xcodeproj_project_yaml" require "integration/xcodeproj_project_yaml"
CLIntegracon.configure do |c| CLIntegracon.configure do |c|
c.spec_path = ROOT + "spec/cocoapods-integration-specs" c.spec_path = ROOT + "spec/cocoapods-integration-specs"
c.temp_path = ROOT + "tmp" c.temp_path = ROOT + "tmp"
...@@ -105,7 +104,8 @@ describe_cli "pod" do ...@@ -105,7 +104,8 @@ describe_cli "pod" do
subject do |s| subject do |s|
s.executable = "ruby #{ROOT + "bin/pod"}" s.executable = "ruby #{ROOT + "bin/pod"}"
s.environment_vars = { s.environment_vars = {
"CP_AGGRESSIVE_CACHE" => "TRUE" "CP_AGGRESSIVE_CACHE" => "TRUE",
"XCODEPROJ_DISABLE_XCPROJ" => "TRUE",
} }
s.default_args = [ s.default_args = [
"--verbose", "--verbose",
......
...@@ -3,8 +3,8 @@ require File.expand_path('../../../spec_helper', __FILE__) ...@@ -3,8 +3,8 @@ require File.expand_path('../../../spec_helper', __FILE__)
describe Pod::Generator::TargetEnvironmentHeader do describe Pod::Generator::TargetEnvironmentHeader do
before do before do
specification = fixture_spec('banana-lib/BananaLib.podspec') spec = fixture_spec('banana-lib/BananaLib.podspec')
@gen = Pod::Generator::TargetEnvironmentHeader.new([specification]) @gen = Pod::Generator::TargetEnvironmentHeader.new({'Debug' => [spec]})
end end
it "generates a header files which include macro definitions for installed Pods" do it "generates a header files which include macro definitions for installed Pods" do
...@@ -32,5 +32,52 @@ describe Pod::Generator::TargetEnvironmentHeader do ...@@ -32,5 +32,52 @@ describe Pod::Generator::TargetEnvironmentHeader do
name = @gen.send(:safe_spec_name, 'AppleCoreAudioUtilityClasses@thehtb') name = @gen.send(:safe_spec_name, 'AppleCoreAudioUtilityClasses@thehtb')
name.should == 'AppleCoreAudioUtilityClasses_thehtb' name.should == 'AppleCoreAudioUtilityClasses_thehtb'
end end
it "includes conditional statements for specifications not present in all build configurations" do
spec = fixture_spec('banana-lib/BananaLib.podspec')
debug_spec = stub(:name => 'DebugPod', :version => Pod::Version.new('1.2.3'))
specs_by_configuration = {
'Debug' => [spec, debug_spec],
'Release' => [spec]
}
@gen = Pod::Generator::TargetEnvironmentHeader.new(specs_by_configuration)
@gen.generate.should == <<-EOS.strip_heredoc
// To check if a library is compiled with CocoaPods you
// can use the `COCOAPODS` macro definition which is
// defined in the xcconfigs so it is available in
// headers also when they are imported in the client
// project.
// BananaLib
#define COCOAPODS_POD_AVAILABLE_BananaLib
#define COCOAPODS_VERSION_MAJOR_BananaLib 1
#define COCOAPODS_VERSION_MINOR_BananaLib 0
#define COCOAPODS_VERSION_PATCH_BananaLib 0
// Debug build configuration
#ifdef DEBUG
// DebugPod
#define COCOAPODS_POD_AVAILABLE_DebugPod
#define COCOAPODS_VERSION_MAJOR_DebugPod 1
#define COCOAPODS_VERSION_MINOR_DebugPod 2
#define COCOAPODS_VERSION_PATCH_DebugPod 3
#endif
EOS
end
it "normalizes the name of the build configuration" do
spec = fixture_spec('banana-lib/BananaLib.podspec')
specs_by_configuration = {
'Debug' => [],
'build configuration copy' => [spec]
}
@gen = Pod::Generator::TargetEnvironmentHeader.new(specs_by_configuration)
@gen.generate.should.include 'BUILD_CONFIGURATION_COPY'
end
end end
...@@ -9,6 +9,7 @@ module Pod ...@@ -9,6 +9,7 @@ module Pod
@spec = fixture_spec('banana-lib/BananaLib.podspec') @spec = fixture_spec('banana-lib/BananaLib.podspec')
@consumer = @spec.consumer(:ios) @consumer = @spec.consumer(:ios)
target_definition = Podfile::TargetDefinition.new('Pods', nil) target_definition = Podfile::TargetDefinition.new('Pods', nil)
target_definition.whitelist_pod_for_configuration("BananaLib", "Release")
@target = AggregateTarget.new(target_definition, config.sandbox) @target = AggregateTarget.new(target_definition, config.sandbox)
@target.client_root = config.sandbox.root.dirname @target.client_root = config.sandbox.root.dirname
@target.stubs(:platform).returns(:ios) @target.stubs(:platform).returns(:ios)
...@@ -16,7 +17,7 @@ module Pod ...@@ -16,7 +17,7 @@ module Pod
@pod_target.stubs(:platform).returns(:ios) @pod_target.stubs(:platform).returns(:ios)
@pod_target.stubs(:spec_consumers).returns([@consumer]) @pod_target.stubs(:spec_consumers).returns([@consumer])
@target.pod_targets = [@pod_target] @target.pod_targets = [@pod_target]
@generator = AggregateXCConfig.new(@target) @generator = AggregateXCConfig.new(@target, "Release")
end end
it "returns the path of the pods root relative to the user project" do it "returns the path of the pods root relative to the user project" do
...@@ -73,6 +74,16 @@ module Pod ...@@ -73,6 +74,16 @@ module Pod
@xcconfig.to_hash['GCC_PREPROCESSOR_DEFINITIONS'].should.include '$(inherited)' @xcconfig.to_hash['GCC_PREPROCESSOR_DEFINITIONS'].should.include '$(inherited)'
end end
it "links the pod targets with the aggregate integration library target" do
@xcconfig.to_hash['OTHER_LDFLAGS'].should.include '-l "Pods-BananaLib"'
end
it "does not links the pod targets with the aggregate integration library target for non-whitelisted configuration" do
@generator = AggregateXCConfig.new(@target, "Debug")
@xcconfig = @generator.generate
@xcconfig.to_hash['OTHER_LDFLAGS'].should.not.include '-lPods-BananaLib'
end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
before do before do
......
...@@ -51,7 +51,8 @@ module Pod ...@@ -51,7 +51,8 @@ module Pod
end end
it 'adds the COCOAPODS macro definition' do it 'adds the COCOAPODS macro definition' do
@xcconfig.to_hash['GCC_PREPROCESSOR_DEFINITIONS'].should.include 'COCOAPODS=1' expected = '$(inherited) COCOAPODS=1'
@xcconfig.to_hash['GCC_PREPROCESSOR_DEFINITIONS'].should == expected
end end
it 'adds the pod namespaced configuration items' do it 'adds the pod namespaced configuration items' do
......
...@@ -36,15 +36,15 @@ module Pod ...@@ -36,15 +36,15 @@ module Pod
end end
it "includes the libraries for the specifications" do it "includes the libraries for the specifications" do
@xcconfig.to_hash["OTHER_LDFLAGS"].should.include('-lxml2') @xcconfig.to_hash["OTHER_LDFLAGS"].should.include(%q(-l "xml2"))
end end
it "includes the frameworks of the specifications" do it "includes the frameworks of the specifications" do
@xcconfig.to_hash["OTHER_LDFLAGS"].should.include('-framework QuartzCore') @xcconfig.to_hash["OTHER_LDFLAGS"].should.include(%q(-framework "QuartzCore"))
end end
it "includes the weak-frameworks of the specifications" do it "includes the weak-frameworks of the specifications" do
@xcconfig.to_hash["OTHER_LDFLAGS"].should.include('-weak_framework iAd') @xcconfig.to_hash["OTHER_LDFLAGS"].should.include(%q(-weak_framework "iAd"))
end end
it "includes the developer frameworks search paths when SenTestingKit is detected" do it "includes the developer frameworks search paths when SenTestingKit is detected" do
......
...@@ -57,7 +57,7 @@ module Pod ...@@ -57,7 +57,7 @@ module Pod
:platform_name => :ios :platform_name => :ios
}) })
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig) @sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-framework SenTestingKit' xcconfig.to_hash['OTHER_LDFLAGS'].should == %q(-framework "SenTestingKit")
end end
it "adds the libraries of the xcconfig" do it "adds the libraries of the xcconfig" do
...@@ -70,7 +70,7 @@ module Pod ...@@ -70,7 +70,7 @@ module Pod
:platform_name => :ios :platform_name => :ios
}) })
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig) @sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-lxml2' xcconfig.to_hash['OTHER_LDFLAGS'].should == %q(-l "xml2")
end end
it "adds the frameworks of the xcconfig" do it "adds the frameworks of the xcconfig" do
...@@ -83,7 +83,7 @@ module Pod ...@@ -83,7 +83,7 @@ module Pod
:platform_name => :ios :platform_name => :ios
}) })
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig) @sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-framework CoreAnimation' xcconfig.to_hash['OTHER_LDFLAGS'].should == %q(-framework "CoreAnimation")
end end
it "adds the weak frameworks of the xcconfig" do it "adds the weak frameworks of the xcconfig" do
...@@ -96,7 +96,7 @@ module Pod ...@@ -96,7 +96,7 @@ module Pod
:platform_name => :ios :platform_name => :ios
}) })
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig) @sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-weak_framework iAd' xcconfig.to_hash['OTHER_LDFLAGS'].should == %q(-weak_framework "iAd")
end end
it "adds the ios developer frameworks search paths if needed" do it "adds the ios developer frameworks search paths if needed" do
...@@ -136,7 +136,7 @@ module Pod ...@@ -136,7 +136,7 @@ module Pod
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_framework_build_settings(framework_path, xcconfig, config.sandbox.root) @sut.add_framework_build_settings(framework_path, xcconfig, config.sandbox.root)
hash_config = xcconfig.to_hash hash_config = xcconfig.to_hash
hash_config['OTHER_LDFLAGS'].should == "-framework Parse" hash_config['OTHER_LDFLAGS'].should == %q(-framework "Parse")
hash_config['FRAMEWORK_SEARCH_PATHS'].should == '"$(PODS_ROOT)/Parse"' hash_config['FRAMEWORK_SEARCH_PATHS'].should == '"$(PODS_ROOT)/Parse"'
end end
...@@ -145,7 +145,7 @@ module Pod ...@@ -145,7 +145,7 @@ module Pod
xcconfig = Xcodeproj::Config.new( { 'OTHER_LDFLAGS' => '-framework CoreAnimation' } ) xcconfig = Xcodeproj::Config.new( { 'OTHER_LDFLAGS' => '-framework CoreAnimation' } )
@sut.add_framework_build_settings(framework_path, xcconfig, config.sandbox.root) @sut.add_framework_build_settings(framework_path, xcconfig, config.sandbox.root)
hash_config = xcconfig.to_hash hash_config = xcconfig.to_hash
hash_config['OTHER_LDFLAGS'].should == "-framework CoreAnimation -framework Parse" hash_config['OTHER_LDFLAGS'].should == %q(-framework "CoreAnimation" -framework "Parse")
end end
it "doesn't ovverides exiting frameworks search paths" do it "doesn't ovverides exiting frameworks search paths" do
...@@ -165,7 +165,7 @@ module Pod ...@@ -165,7 +165,7 @@ module Pod
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_library_build_settings(path, xcconfig, config.sandbox.root) @sut.add_library_build_settings(path, xcconfig, config.sandbox.root)
hash_config = xcconfig.to_hash hash_config = xcconfig.to_hash
hash_config['OTHER_LDFLAGS'].should == "-lProj4" hash_config['OTHER_LDFLAGS'].should == %q(-l "Proj4")
hash_config['LIBRARY_SEARCH_PATHS'].should == '"$(PODS_ROOT)/MapBox/Proj4"' hash_config['LIBRARY_SEARCH_PATHS'].should == '"$(PODS_ROOT)/MapBox/Proj4"'
end end
end end
......
...@@ -89,7 +89,12 @@ module Pod ...@@ -89,7 +89,12 @@ module Pod
target.user_target_uuids.should == ["A346496C14F9BE9A0080D870"] target.user_target_uuids.should == ["A346496C14F9BE9A0080D870"]
user_proj = Xcodeproj::Project.open(target.user_project_path) user_proj = Xcodeproj::Project.open(target.user_project_path)
user_proj.objects_by_uuid[target.user_target_uuids.first].name.should == 'SampleProject' user_proj.objects_by_uuid[target.user_target_uuids.first].name.should == 'SampleProject'
target.user_build_configurations.should == { "Test" => :release, "App Store" => :release } target.user_build_configurations.should == {
"Debug" => :debug,
"Release" => :release,
"Test" => :release,
"App Store" => :release
}
target.platform.to_s.should == 'iOS 6.0' target.platform.to_s.should == 'iOS 6.0'
end end
...@@ -106,7 +111,13 @@ module Pod ...@@ -106,7 +111,13 @@ module Pod
it "returns all the configurations the user has in any of its projects and/or targets" do it "returns all the configurations the user has in any of its projects and/or targets" do
target_definition = @analyzer.podfile.target_definition_list.first target_definition = @analyzer.podfile.target_definition_list.first
target_definition.stubs(:build_configurations).returns("AdHoc" => :test) target_definition.stubs(:build_configurations).returns("AdHoc" => :test)
@analyzer.analyze.all_user_build_configurations.should == { "AdHoc" => :test, "Test" => :release, "App Store" => :release } @analyzer.analyze.all_user_build_configurations.should == {
"Debug" => :debug,
"Release" => :release,
"AdHoc" => :test,
"Test" => :release,
"App Store" => :release
}
end end
#--------------------------------------# #--------------------------------------#
...@@ -315,7 +326,11 @@ module Pod ...@@ -315,7 +326,11 @@ module Pod
user_targets = [target] user_targets = [target]
configurations = @analyzer.send(:compute_user_build_configurations, target_definition, user_targets) configurations = @analyzer.send(:compute_user_build_configurations, target_definition, user_targets)
configurations.should == { 'AppStore' => :release } configurations.should == {
'Debug' => :debug,
'Release' => :release,
'AppStore' => :release
}
end end
it "returns the user build configurations specified in the target definition" do it "returns the user build configurations specified in the target definition" do
......
...@@ -48,7 +48,10 @@ module Pod ...@@ -48,7 +48,10 @@ module Pod
"Pods-dummy.m", "Pods-dummy.m",
"Pods-environment.h", "Pods-environment.h",
"Pods-resources.sh", "Pods-resources.sh",
"Pods.xcconfig" "Pods.appstore.xcconfig",
"Pods.debug.xcconfig",
"Pods.release.xcconfig",
"Pods.test.xcconfig"
] ]
end end
...@@ -114,7 +117,7 @@ module Pod ...@@ -114,7 +117,7 @@ module Pod
it "creates the xcconfig file" do it "creates the xcconfig file" do
@installer.install! @installer.install!
file = config.sandbox.root + @target.xcconfig_path file = config.sandbox.root + @target.xcconfig_path("Release")
xcconfig = Xcodeproj::Config.new(file) xcconfig = Xcodeproj::Config.new(file)
xcconfig.to_hash['PODS_ROOT'].should == '${SRCROOT}/Pods' xcconfig.to_hash['PODS_ROOT'].should == '${SRCROOT}/Pods'
end end
......
require File.expand_path('../../../../../spec_helper', __FILE__)
module Pod
describe XCConfigIntegrator = Installer::UserProjectIntegrator::TargetIntegrator::XCConfigIntegrator do
before do
project_path = SpecHelper.create_sample_app_copy_from_fixture('SampleProject')
@project = Xcodeproj::Project.open(project_path)
Xcodeproj::Project.new(config.sandbox.project_path).save
@target = @project.targets.first
target_definition = Podfile::TargetDefinition.new('Pods', nil)
target_definition.link_with_first_target = true
@pod_bundle = AggregateTarget.new(target_definition, config.sandbox)
@pod_bundle.user_project_path = project_path
@pod_bundle.client_root = project_path.dirname
@pod_bundle.user_target_uuids = [@target.uuid]
configuration = Xcodeproj::Config.new({
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1'
})
@pod_bundle.xcconfigs['Debug'] = configuration
@pod_bundle.xcconfigs['Test'] = configuration
@pod_bundle.xcconfigs['Release'] = configuration
@pod_bundle.xcconfigs['App Store'] = configuration
end
it 'cleans the xcconfig used up to CocoaPods 0.33.1' do
path = @pod_bundle.xcconfig_path
file_ref = @project.new_file(path)
config = @target.build_configuration_list['Release']
config.base_configuration_reference = file_ref
File.expects(:exist?).returns(true)
File.expects(:delete).with(path)
XCConfigIntegrator.integrate(@pod_bundle, [@target])
@project.files.find { |f| f.path == path }.should.be.nil
end
it 'sets the Pods xcconfig as the base config for each build configuration' do
XCConfigIntegrator.integrate(@pod_bundle, [@target])
@target.build_configurations.each do |config|
xcconfig_file = @project.files.find { |f| f.path == @pod_bundle.xcconfig_relative_path(config.name) }
config.base_configuration_reference.should == xcconfig_file
end
end
it 'does not duplicate the file reference to the CocoaPods xcconfig in the user project' do
path = @pod_bundle.xcconfig_relative_path('Release')
existing = @project.new_file(path)
XCConfigIntegrator.integrate(@pod_bundle, [@target])
config = @target.build_configuration_list['Release']
config.base_configuration_reference.should.equal existing
end
end
end
require File.expand_path('../../../../spec_helper', __FILE__) require File.expand_path('../../../../spec_helper', __FILE__)
module Pod module Pod
describe TargetIntegrator = Installer::UserProjectIntegrator::TargetIntegrator do describe TargetIntegrator = Installer::UserProjectIntegrator::TargetIntegrator do
describe "In general" do describe "In general" do
# The project contains a `PBXReferenceProxy` in the build files of the # The project contains a `PBXReferenceProxy` in the build files of the
...@@ -11,83 +9,61 @@ module Pod ...@@ -11,83 +9,61 @@ module Pod
# the detection of the target. # the detection of the target.
# #
before do before do
sample_project_path = SpecHelper.create_sample_app_copy_from_fixture('SampleProject') project_path = SpecHelper.create_sample_app_copy_from_fixture('SampleProject')
@sample_project = Xcodeproj::Project.open(sample_project_path) @project = Xcodeproj::Project.open(project_path)
Xcodeproj::Project.new(config.sandbox.project_path).save Xcodeproj::Project.new(config.sandbox.project_path).save
@target = @sample_project.targets.first @target = @project.targets.first
target_definition = Podfile::TargetDefinition.new('Pods', nil) target_definition = Podfile::TargetDefinition.new('Pods', nil)
target_definition.link_with_first_target = true target_definition.link_with_first_target = true
@lib = AggregateTarget.new(target_definition, config.sandbox) @pod_bundle = AggregateTarget.new(target_definition, config.sandbox)
@lib.user_project_path = sample_project_path @pod_bundle.user_project_path = project_path
@lib.client_root = sample_project_path.dirname @pod_bundle.client_root = project_path.dirname
@lib.user_target_uuids = [@target.uuid] @pod_bundle.user_target_uuids = [@target.uuid]
@target_integrator = TargetIntegrator.new(@lib) configuration = Xcodeproj::Config.new({
end 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1'
})
it 'returns the targets that need to be integrated' do @pod_bundle.xcconfigs['Debug'] = configuration
@target_integrator.native_targets.map(&:name).should == %w[ SampleProject ] @pod_bundle.xcconfigs['Test'] = configuration
end @pod_bundle.xcconfigs['Release'] = configuration
@pod_bundle.xcconfigs['App Store'] = configuration
it 'returns the targets that need to be integrated' do @target_integrator = TargetIntegrator.new(@pod_bundle)
pods_library = @sample_project.frameworks_group.new_product_ref_for_target('Pods', :static_library) end
@target.frameworks_build_phase.add_file_reference(pods_library)
@target_integrator.stubs(:user_project).returns(@sample_project) describe '#integrate!' do
@target_integrator.native_targets.map(&:name).should.be.empty? it 'set the CocoaPods xcconfigs' do
end TargetIntegrator::XCConfigIntegrator.expects(:integrate).with(@pod_bundle, [@target])
it 'is robust against other types of references in the build files of the frameworks build phase' do
build_file = @sample_project.new(Xcodeproj::Project::PBXBuildFile)
build_file.file_ref = @sample_project.new(Xcodeproj::Project::PBXVariantGroup)
@target_integrator.stubs(:user_project).returns(@sample_project)
@target.frameworks_build_phase.files << build_file
@target_integrator.native_targets.map(&:name).should == %w[ SampleProject ]
end
it 'is robust against build files with missing file references' do
build_file = @sample_project.new(Xcodeproj::Project::PBXBuildFile)
build_file.file_ref = nil
@target_integrator.stubs(:user_project).returns(@sample_project)
@target.frameworks_build_phase.files << build_file
@target_integrator.native_targets.map(&:name).should == %w[ SampleProject ]
end
it 'does not perform the integration if there are no targets to integrate' do
@target_integrator.stubs(:native_targets).returns([])
@target_integrator.expects(:add_xcconfig_base_configuration).never
@target_integrator.expects(:add_pods_library).never
@target_integrator.expects(:add_copy_resources_script_phase).never
@target_integrator.expects(:save_user_project).never
@target_integrator.integrate! @target_integrator.integrate!
end end
before do 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! @target_integrator.integrate!
end end
it 'sets the Pods xcconfig as the base config for each build configuration' do
xcconfig_file = @sample_project.files.find { |f| f.path == @lib.xcconfig_relative_path }
@target.build_configurations.each do |config|
config.base_configuration_reference.should == xcconfig_file
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
@target_integrator.user_project["Frameworks/libPods.a"].should.not == nil @target_integrator.integrate!
@target_integrator.send(:user_project)["Frameworks/libPods.a"].should.not == nil
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
target = @target_integrator.native_targets.first @target_integrator.integrate!
target.frameworks_build_phase.files.find { |f| f.file_ref.path == 'libPods.a'}.should.not == nil target = @target_integrator.send(:native_targets).first
phase = target.frameworks_build_phase
ref = phase.files.find { |f| f.file_ref.path == 'libPods.a'}
ref.should.not.be.nil
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
target = @target_integrator.native_targets.first @target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
phase = target.shell_script_build_phases.find { |bp| bp.name == "Copy Pods Resources" } phase = target.shell_script_build_phases.find { |bp| bp.name == "Copy Pods Resources" }
phase.shell_script.strip.should == "\"${SRCROOT}/../Pods/Pods-resources.sh\"" phase.shell_script.strip.should == "\"${SRCROOT}/../Pods/Pods-resources.sh\""
end end
it 'adds a Check Manifest.lock build phase to each target' do it 'adds a Check Manifest.lock build phase to each target' do
target = @target_integrator.native_targets.first @target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
phase = target.shell_script_build_phases.find { |bp| bp.name == "Check Pods Manifest.lock" } phase = target.shell_script_build_phases.find { |bp| bp.name == "Check Pods Manifest.lock" }
phase.shell_script.should == <<-EOS.strip_heredoc phase.shell_script.should == <<-EOS.strip_heredoc
diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null
...@@ -101,11 +77,50 @@ module Pod ...@@ -101,11 +77,50 @@ module Pod
end end
it 'adds the Check Manifest.lock build phase as the first build phase' do it 'adds the Check Manifest.lock build phase as the first build phase' do
target = @target_integrator.native_targets.first @target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
target.build_phases.first
phase = target.build_phases.find { |bp| bp.name == "Check Pods Manifest.lock" } phase = target.build_phases.find { |bp| bp.name == "Check Pods Manifest.lock" }
target.build_phases.first.should.equal? phase target.build_phases.first.should.equal? phase
end end
it 'does not perform the integration if there are no targets to integrate' do
@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.expects(:save_user_project).never
@target_integrator.integrate!
end
end
describe 'Private helpers' do
it 'returns the native targets associated with the Pod bundle' do
@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)
@target_integrator.stubs(:user_project).returns(@project)
@target.frameworks_build_phase.files << build_file
@target_integrator.send(:native_targets).map(&:name).should == %w[ SampleProject ]
end
it 'is robust against build files with missing file references' do
build_file = @project.new(Xcodeproj::Project::PBXBuildFile)
build_file.file_ref = nil
@target_integrator.stubs(:user_project).returns(@project)
@target.frameworks_build_phase.files << build_file
@target_integrator.send(:native_targets).map(&:name).should == %w[ SampleProject ]
end
end
end end
end end
end end
require File.expand_path('../../../spec_helper', __FILE__) require File.expand_path('../../../spec_helper', __FILE__)
module Pod module Pod
describe Installer::UserProjectIntegrator do describe UserProjectIntegrator = Installer::UserProjectIntegrator do
describe "In general" do describe "In general" do
...@@ -23,14 +23,18 @@ module Pod ...@@ -23,14 +23,18 @@ module Pod
@library.user_project_path = sample_project_path @library.user_project_path = sample_project_path
@library.user_target_uuids = ['A346496C14F9BE9A0080D870'] @library.user_target_uuids = ['A346496C14F9BE9A0080D870']
empty_library = AggregateTarget.new(@podfile.target_definitions[:empty], config.sandbox) empty_library = AggregateTarget.new(@podfile.target_definitions[:empty], config.sandbox)
@integrator = Installer::UserProjectIntegrator.new(@podfile, config.sandbox, temporary_directory, [@library, empty_library]) @integrator = UserProjectIntegrator.new(@podfile, config.sandbox, temporary_directory, [@library, empty_library])
end end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
describe "In general" do describe "In general" do
before do
@integrator.stubs(:warn_about_xcconfig_overrides)
end
it "adds the Pods project to the workspace" do it "adds the Pods project to the workspace" do
UserProjectIntegrator::TargetIntegrator.any_instance.stubs(:integrate!)
@integrator.integrate! @integrator.integrate!
workspace_path = @integrator.send(:workspace_path) workspace_path = @integrator.send(:workspace_path)
workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path) workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
...@@ -41,10 +45,8 @@ module Pod ...@@ -41,10 +45,8 @@ module Pod
end end
it "integrates the user targets" do it "integrates the user targets" do
UserProjectIntegrator::TargetIntegrator.any_instance.expects(:integrate!)
@integrator.integrate! @integrator.integrate!
user_project = Xcodeproj::Project.open(@sample_project_path)
target = user_project.objects_by_uuid[@library.user_target_uuids.first]
target.frameworks_build_phase.files.map(&:display_name).should.include('libPods.a')
end end
it "warns if the podfile does not contain any dependency" do it "warns if the podfile does not contain any dependency" do
...@@ -53,6 +55,35 @@ module Pod ...@@ -53,6 +55,35 @@ module Pod
UI.warnings.should.include?('The Podfile does not contain any dependencies') UI.warnings.should.include?('The Podfile does not contain any dependencies')
end end
it 'check that the integrated target does not override the CocoaPods build settings' do
UI.warnings = ''
target_config = stub(:name => 'Release', :build_settings => { 'GCC_PREPROCESSOR_DEFINITIONS' => 'FLAG=1' })
user_target = stub(:name => 'SampleProject', :build_configurations => [target_config])
@library.stubs(:user_targets).returns([user_target])
@library.xcconfigs['Release'] = {'GCC_PREPROCESSOR_DEFINITIONS' => 'COCOAPODS=1'}
@integrator = UserProjectIntegrator.new(@podfile, config.sandbox, temporary_directory, [@library])
@integrator.unstub(:warn_about_xcconfig_overrides)
@integrator.send(:warn_about_xcconfig_overrides)
UI.warnings.should.include 'The `SampleProject [Release]` target ' \
'overrides the `GCC_PREPROCESSOR_DEFINITIONS` build setting'
end
it 'allows build settings which inherit the settings form the CocoaPods xcconfig' do
UI.warnings = ''
target_config = stub(:name => 'Release', :build_settings => { 'GCC_PREPROCESSOR_DEFINITIONS' => 'FLAG=1 $(inherited)' })
user_target = stub(:name => 'SampleProject', :build_configurations => [target_config])
@library.stubs(:user_targets).returns([user_target])
@library.xcconfigs['Release'] = {'GCC_PREPROCESSOR_DEFINITIONS' => 'COCOAPODS=1'}
@integrator = UserProjectIntegrator.new(@podfile, config.sandbox, temporary_directory, [@library])
@integrator.unstub(:warn_about_xcconfig_overrides)
@integrator.send(:warn_about_xcconfig_overrides)
UI.warnings.should.not.include 'GCC_PREPROCESSOR_DEFINITIONS'
end
end end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
......
...@@ -149,6 +149,28 @@ module Pod ...@@ -149,6 +149,28 @@ module Pod
#--------------------------------------# #--------------------------------------#
describe "#validate_whitelisted_configurations" do
it "raises when a whitelisted configuration doesn’t exist in the user's project" do
target_definition = @installer.podfile.target_definitions.values.first
target_definition.whitelist_pod_for_configuration('JSONKit', 'YOLO')
@installer.send(:analyze)
should.raise Informative do
@installer.send(:validate_build_configurations)
end
end
it "does not raise if all whitelisted configurations exist in the user's project" do
target_definition = @installer.podfile.target_definitions.values.first
target_definition.whitelist_pod_for_configuration('JSONKit', 'Test')
@installer.send(:analyze)
should.not.raise do
@installer.send(:validate_build_configurations)
end
end
end
#--------------------------------------#
describe "#clean_sandbox" do describe "#clean_sandbox" do
before do before do
...@@ -444,30 +466,6 @@ module Pod ...@@ -444,30 +466,6 @@ module Pod
describe "Integrating client projects" do describe "Integrating client projects" do
it "links the pod targets with the aggregate integration library target" do
spec = fixture_spec('banana-lib/BananaLib.podspec')
target_definition = Podfile::TargetDefinition.new('Pods', nil)
target = AggregateTarget.new(target_definition, config.sandbox)
lib_definition = Podfile::TargetDefinition.new('BananaLib', nil)
lib_definition.store_pod('BananaLib')
pod_target = PodTarget.new([spec], lib_definition, config.sandbox)
target.pod_targets = [pod_target]
project = Xcodeproj::Project.new('path')
pods_target = project.new_target(:static_library, target.name, :ios)
target.target = pods_target
native_target = project.new_target(:static_library, pod_target.name, :ios)
pod_target.target = pods_target
@installer.stubs(:pods_project).returns(project)
@installer.stubs(:aggregate_targets).returns([target])
@installer.stubs(:pod_targets).returns([pod_target])
@installer.send(:link_aggregate_target)
pods_target.frameworks_build_phase.files.map(&:file_ref).should.include?(pod_target.target.product_reference)
end
it "integrates the client projects" do it "integrates the client projects" do
@installer.stubs(:aggregate_targets).returns([AggregateTarget.new(nil, config.sandbox)]) @installer.stubs(:aggregate_targets).returns([AggregateTarget.new(nil, config.sandbox)])
Installer::UserProjectIntegrator.any_instance.expects(:integrate!) Installer::UserProjectIntegrator.any_instance.expects(:integrate!)
......
...@@ -36,7 +36,7 @@ module Pod ...@@ -36,7 +36,7 @@ module Pod
end end
it "returns the absolute path of the xcconfig file" do it "returns the absolute path of the xcconfig file" do
@lib.xcconfig_path.to_s.should.include?('Pods/Pods.xcconfig') @lib.xcconfig_path("Release").to_s.should.include?('Pods/Pods.release.xcconfig')
end end
it "returns the absolute path of the resources script" do it "returns the absolute path of the resources script" do
...@@ -66,7 +66,7 @@ module Pod ...@@ -66,7 +66,7 @@ module Pod
end end
it "returns the path of the xcconfig file relative to the user project" do it "returns the path of the xcconfig file relative to the user project" do
@lib.xcconfig_relative_path.should == 'Pods/Pods.xcconfig' @lib.xcconfig_relative_path("Release").should == 'Pods/Pods.release.xcconfig'
end end
end end
......
...@@ -225,6 +225,36 @@ module Pod ...@@ -225,6 +225,36 @@ module Pod
f.path.should == '../Podfile' f.path.should == '../Podfile'
end end
#----------------------------------------#
describe "#add_build_configuration" do
it "adds a preprocessor definition for build configurations" do
configuration = @project.add_build_configuration('Release', :release)
settings = configuration.build_settings
settings['GCC_PREPROCESSOR_DEFINITIONS'].should.include('RELEASE=1')
end
it "doesn't duplicate values" do
original = @project.build_configuration_list['Debug']
original_settings = original.build_settings
original_settings['GCC_PREPROCESSOR_DEFINITIONS'].should ==
["DEBUG=1", "$(inherited)"]
configuration = @project.add_build_configuration('Debug', :debug)
settings = configuration.build_settings
settings['GCC_PREPROCESSOR_DEFINITIONS'].should ==
["DEBUG=1", "$(inherited)"]
end
it "normalizes the name of the configuration" do
configuration = @project.add_build_configuration(
'My Awesome Configuration', :release)
settings = configuration.build_settings
settings['GCC_PREPROCESSOR_DEFINITIONS'].should ==
["MY_AWESOME_CONFIGURATION=1"]
end
end
end end
#-------------------------------------------------------------------------# #-------------------------------------------------------------------------#
......
...@@ -24,6 +24,15 @@ module Pod ...@@ -24,6 +24,15 @@ module Pod
it "returns the name of its product" do it "returns the name of its product" do
@target.product_name.should == 'libPods.a' @target.product_name.should == 'libPods.a'
end end
it 'returns the user targets' do
project_path = SpecHelper.fixture('SampleProject/SampleProject.xcodeproj')
@target.user_project_path = project_path
@target.user_target_uuids = ['A346496C14F9BE9A0080D870']
targets = @target.user_targets
targets.count.should == 1
targets.first.class.should == Xcodeproj::Project::PBXNativeTarget
end
end end
describe "Support files" do describe "Support files" do
...@@ -35,7 +44,7 @@ module Pod ...@@ -35,7 +44,7 @@ module Pod
end end
it "returns the absolute path of the xcconfig file" do it "returns the absolute path of the xcconfig file" do
@target.xcconfig_path.to_s.should.include?('Pods/Pods.xcconfig') @target.xcconfig_path("Release").to_s.should.include?('Pods/Pods.release.xcconfig')
end end
it "returns the absolute path of the resources script" do it "returns the absolute path of the resources script" do
...@@ -63,18 +72,38 @@ module Pod ...@@ -63,18 +72,38 @@ module Pod
end end
it "returns the path of the xcconfig file relative to the user project" do it "returns the path of the xcconfig file relative to the user project" do
@target.xcconfig_relative_path.should == 'Pods/Pods.xcconfig' @target.xcconfig_relative_path("Release").should == 'Pods/Pods.release.xcconfig'
end end
end end
describe "Pod targets" do describe "Pod targets" do
before do before do
spec = fixture_spec('banana-lib/BananaLib.podspec') @spec = fixture_spec('banana-lib/BananaLib.podspec')
target_definition = Podfile::TargetDefinition.new('Pods', nil) @target_definition = Podfile::TargetDefinition.new('Pods', nil)
pod_target = PodTarget.new([spec], target_definition, config.sandbox) @pod_target = PodTarget.new([@spec], @target_definition, config.sandbox)
@target = AggregateTarget.new(target_definition, config.sandbox) @target = AggregateTarget.new(@target_definition, config.sandbox)
@target.stubs(:platform).returns(:ios) @target.stubs(:platform).returns(:ios)
@target.pod_targets = [pod_target] @target.pod_targets = [@pod_target]
end
it "returns pod targets by build configuration" do
pod_target_release = PodTarget.new([@spec], @target_definition, config.sandbox)
pod_target_release.expects(:include_in_build_config?).with("Debug").returns(false)
pod_target_release.expects(:include_in_build_config?).with("Release").returns(true)
@target.pod_targets = [@pod_target, pod_target_release]
@target.user_build_configurations = {
"Debug" => :debug,
"Release" => :release
}
expected = {
"Debug" => @pod_target.specs,
"Release" => (@pod_target.specs + pod_target_release.specs)
}
@target.specs_by_build_configuration.should == expected
end
it "returns the specs of the Pods used by this aggregate target" do
@target.specs.map(&:name).should == ["BananaLib"]
end end
it "returns the specs of the Pods used by this aggregate target" do it "returns the specs of the Pods used by this aggregate target" do
......
...@@ -37,11 +37,32 @@ module Pod ...@@ -37,11 +37,32 @@ module Pod
it "returns the name of the Pods on which this target depends" do it "returns the name of the Pods on which this target depends" do
@pod_target.dependencies.should == ["monkey"] @pod_target.dependencies.should == ["monkey"]
end end
it "returns whether it is whitelisted in a build configuration" do
@target_definition.store_pod('BananaLib')
@target_definition.whitelist_pod_for_configuration('BananaLib', 'debug')
@pod_target.include_in_build_config?('Debug').should.be.true
@pod_target.include_in_build_config?('Release').should.be.false
end
it "is whitelisted on all build configurations of it is a dependency of other Pods" do
@pod_target.include_in_build_config?('Debug').should.be.true
@pod_target.include_in_build_config?('Release').should.be.true
end
it "raises if a Pod is whitelisted for different build configurations" do
@target_definition.store_pod('BananaLib')
@target_definition.store_pod('BananaLib/Subspec')
@target_definition.whitelist_pod_for_configuration('BananaLib', 'debug')
should.raise Informative do
@pod_target.include_in_build_config?('release').should.be.true
end.message.should.match /subspecs across different build configurations/
end
end end
describe "Support files" do describe "Support files" do
it "returns the absolute path of the xcconfig file" do it "returns the absolute path of the xcconfig file" do
@pod_target.xcconfig_path.to_s.should.include 'Pods/Pods-BananaLib.xcconfig' @pod_target.xcconfig_path("Release").to_s.should.include 'Pods/Pods-BananaLib.release.xcconfig'
end end
it "returns the absolute path of the target header file" do it "returns the absolute path of the target header file" 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