Commit f9e97e7e authored by Eloy Duran's avatar Eloy Duran

Merge branch 'link-with-target'. Related to #3, #63, and #79. Closes #76.

parents fcca63a6 4fe9f58a
......@@ -5,6 +5,8 @@ Kicker::Recipes::Ruby.runner_bin = 'bacon'
process do |files|
specs = files.take_and_map do |file|
case file
when %r{lib/cocoapods/installer.+\.rb$}
['spec/unit/installer_spec.rb', 'spec/unit/target_installer_spec.rb']
when %r{lib/cocoapods/(.+?)\.rb$}
s = Dir.glob("spec/**/#{$1}_spec.rb")
s unless s.empty?
......
......@@ -3,6 +3,43 @@
A full list of all the changes since 0.5.1 can be found [here][6].
### Link with specific targets
CocoaPods can now integrate all the targets specified in your `Podfile`.
To specify which target, in your Xcode project, a Pods target should be linked
with, use the `link_with` method like so:
```ruby
platform :ios
link_with ['MyAppTarget', 'MyOtherAppTarget']
dependency 'JSONKit'
target :test, :exclusive => true do
link_with 'TestRunnerTarget'
dependency 'Kiwi'
end
```
_NOTE: As you can see it can take either one target name, or an array of names._
Alternatively, you can also specify the target to link with in the target
options like so:
```ruby
target :test, :exclusive => true, :link_with => 'TestRunnerTarget' do
dependency 'Kiwi'
end
```
If no explicit target is specified, then the Pods target will be linked with
the first target in your project. So if you only have one target you do not
need to specify the target to link with.
See [#76](https://github.com/CocoaPods/CocoaPods/issues/76) for more info.
### Documentation
CocoaPods will now generate documentation for every library with the
......@@ -22,7 +59,7 @@ s.documentation = { :html => 'http://example.com/docs/index.html' }
```
See [#149](https://github.com/CocoaPods/CocoaPods/issues/149) and
[#151](https://github.com/CocoaPods/CocoaPods/issues/151).
[#151](https://github.com/CocoaPods/CocoaPods/issues/151) for more info.
### Introduced two new classes: LocalPod and Sandbox.
......
......@@ -16,7 +16,6 @@ module Pod
autoload :Platform, 'cocoapods/platform'
autoload :Podfile, 'cocoapods/podfile'
autoload :Project, 'cocoapods/project'
autoload :ProjectIntegration, 'cocoapods/project_integration'
autoload :Resolver, 'cocoapods/resolver'
autoload :Sandbox, 'cocoapods/sandbox'
autoload :Source, 'cocoapods/source'
......
......@@ -42,10 +42,7 @@ module Pod
if @update_repo
Repo.new(ARGV.new(["update"])).run
end
installer = Installer.new(podfile)
installer.install!
ProjectIntegration.integrate_with_project(@projpath) if @projpath
Installer.new(podfile, @projpath).install!
end
end
end
......
......@@ -6,8 +6,8 @@ module Pod
attr_reader :sandbox
def initialize(podfile)
@podfile = podfile
def initialize(podfile, user_project_path = nil)
@podfile, @user_project_path = podfile, user_project_path
# FIXME: pass this into the installer as a parameter
@sandbox = Sandbox.new(config.project_pods_root)
@resolver = Resolver.new(@podfile, @sandbox)
......@@ -87,6 +87,8 @@ module Pod
puts "* Writing Xcode project file to `#{@sandbox.project_path}'" if config.verbose?
project.save_as(@sandbox.project_path)
Project::Integrator.new(@user_project_path, @podfile).integrate! if @user_project_path
end
def run_post_install_hooks
......
......@@ -19,26 +19,19 @@ module Pod
})
end
def xcconfig_filename
"#{@target_definition.lib_name}.xcconfig"
end
def copy_resources_script_for(pods)
@copy_resources_script ||= Generator::CopyResourcesScript.new(pods.map { |p| p.resources }.flatten)
end
def copy_resources_filename
"#{@target_definition.lib_name}-resources.sh"
end
def bridge_support_generator_for(pods, sandbox)
Generator::BridgeSupport.new(pods.map do |pod|
pod.header_files.map { |header| sandbox.root + header }
end.flatten)
end
def bridge_support_filename
"#{@target_definition.lib_name}.bridgesupport"
# TODO This has to be removed, but this means the specs have to be updated if they need a reference to the prefix header.
def prefix_header_filename
@target_definition.prefix_header_name
end
# TODO move out to Generator::PrefixHeader
......@@ -50,12 +43,8 @@ module Pod
end
end
def prefix_header_filename
"#{@target_definition.lib_name}-prefix.pch"
end
def target_support_files
[copy_resources_filename, prefix_header_filename, xcconfig_filename]
[:copy_resources_script_name, :prefix_header_name, :xcconfig_name].map { |file| @target_definition.send(file) }
end
# TODO move xcconfig related code into the xcconfig method, like copy_resources_script and generate_bridge_support.
......@@ -63,7 +52,7 @@ module Pod
self.requires_arc = pods.any? { |pod| pod.requires_arc? }
# First add the target to the project
@target = @project.targets.new_static_library(@target_definition.lib_name)
@target = @project.targets.new_static_library(@target_definition.label)
pods.each do |pod|
xcconfig.merge!(pod.specification.xcconfig)
......@@ -75,10 +64,10 @@ module Pod
xcconfig.merge!('HEADER_SEARCH_PATHS' => quoted(sandbox.header_search_paths).join(" "))
support_files_group = @project.group("Targets Support Files").create_group(@target_definition.lib_name)
support_files_group = @project.group("Targets Support Files").create_group(@target_definition.label)
support_files_group.create_files(target_support_files)
xcconfig_file = support_files_group.files.where(:path => xcconfig_filename)
xcconfig_file = support_files_group.files.where(:path => @target_definition.xcconfig_name)
configure_build_configurations(xcconfig_file)
create_files(pods, sandbox)
......@@ -88,24 +77,24 @@ module Pod
@target.build_configurations.each do |config|
config.base_configuration = xcconfig_file
config.build_settings['OTHER_LDFLAGS'] = ''
config.build_settings['GCC_PREFIX_HEADER'] = prefix_header_filename
config.build_settings['GCC_PREFIX_HEADER'] = @target_definition.prefix_header_name
config.build_settings['PODS_ROOT'] = '$(SRCROOT)'
end
end
def create_files(pods, sandbox)
if @podfile.generate_bridge_support?
bridge_support_metadata_path = sandbox.root + bridge_support_filename
bridge_support_metadata_path = sandbox.root + @target_definition.bridge_support_name
puts "* Generating BridgeSupport metadata file at `#{bridge_support_metadata_path}'" if config.verbose?
bridge_support_generator_for(pods, sandbox).save_as(bridge_support_metadata_path)
copy_resources_script_for(pods).resources << bridge_support_filename
copy_resources_script_for(pods).resources << @target_definition.bridge_support_name
end
puts "* Generating xcconfig file at `#{sandbox.root + xcconfig_filename}'" if config.verbose?
xcconfig.save_as(sandbox.root + xcconfig_filename)
puts "* Generating prefix header at `#{sandbox.root + prefix_header_filename}'" if config.verbose?
save_prefix_header_as(sandbox.root + prefix_header_filename)
puts "* Generating copy resources script at `#{sandbox.root + copy_resources_filename}'" if config.verbose?
copy_resources_script_for(pods).save_as(sandbox.root + copy_resources_filename)
puts "* Generating xcconfig file at `#{sandbox.root + @target_definition.xcconfig_name}'" if config.verbose?
xcconfig.save_as(sandbox.root + @target_definition.xcconfig_name)
puts "* Generating prefix header at `#{sandbox.root + @target_definition.prefix_header_name}'" if config.verbose?
save_prefix_header_as(sandbox.root + @target_definition.prefix_header_name)
puts "* Generating copy resources script at `#{sandbox.root + @target_definition.copy_resources_script_name}'" if config.verbose?
copy_resources_script_for(pods).save_as(sandbox.root + @target_definition.copy_resources_script_name)
end
private
......
module Pod
class Podfile
class TargetDefinition
attr_reader :name, :parent, :target_dependencies
attr_reader :name, :target_dependencies
attr_accessor :link_with, :parent
def initialize(name, parent = nil)
@name, @parent, @target_dependencies = name, parent, []
def initialize(name, options = {})
@name, @target_dependencies = name, []
options.each { |k, v| send("#{k}=", v) }
end
def lib_name
def link_with=(targets)
@link_with = targets.is_a?(Array) ? targets : [targets]
end
def label
if name == :default
"Pods"
elsif @parent
"#{@parent.lib_name}-#{name}"
"#{@parent.label}-#{name}"
else
"Pods-#{name}"
end
end
def lib_name
"lib#{label}.a"
end
def xcconfig_name
"#{label}.xcconfig"
end
def copy_resources_script_name
"#{label}-resources.sh"
end
def prefix_header_name
"#{label}-prefix.pch"
end
def bridge_support_name
"#{label}.bridgesupport"
end
# Returns *all* dependencies of this target, not only the target specific
# ones in `target_dependencies`.
def dependencies
......@@ -59,6 +86,25 @@ module Pod
platform ? @platform = Platform.new(platform, options) : @platform
end
# Specifies the target(s) in the user’s project that this Pods library
# should be linked in.
#
# @example
#
# # Link with a target in the user’s project called ‘MyApp’.
# link_with 'MyApp'
#
# # Link with the targets in the user’s project called ‘MyApp’ and ‘MyOtherApp’.
# link_with ['MyApp', 'MyOtherApp']
#
# # You can also specify this inline when specifying a new Pods target:
# target :test, :exclusive => true, :link_with => 'TestRunner' do
# dependency 'Kiwi'
# end
def link_with(targets)
@target_definition.link_with = targets
end
# Specifies a dependency of the project.
#
# A dependency requirement is defined by the name of the Pod and _optionally_
......@@ -156,8 +202,8 @@ module Pod
@target_definition.target_dependencies << Dependency.new(*name_and_version_requirements, &block)
end
# Specifies that a BridgeSupport metadata should be generated from the
# headers of all installed Pods.
# Specifies that a BridgeSupport metadata document should be generated from
# the headers of all installed Pods.
#
# This is for scripting languages such as MacRuby, Nu, and JSCocoa, which use
# it to bridge types, functions, etc better.
......@@ -193,7 +239,8 @@ module Pod
# dependency (JSONKit).
def target(name, options = {})
parent = @target_definition
@target_definitions[name] = @target_definition = TargetDefinition.new(name, options[:exclusive] ? nil : parent)
options[:parent] = parent unless options.delete(:exclusive)
@target_definitions[name] = @target_definition = TargetDefinition.new(name, options)
yield
ensure
@target_definition = parent
......
......@@ -12,6 +12,8 @@ end
module Pod
class Project < Xcodeproj::Project
autoload :Integrator, 'cocoapods/project/integrator'
# Shortcut access to the `Pods' PBXGroup.
def pods
groups.find { |g| g.name == 'Pods' } || groups.new({ 'name' => 'Pods' })
......
require 'xcodeproj/workspace'
require 'xcodeproj/project'
module Pod
class Project
class Integrator
include Pod::Config::Mixin
attr_reader :user_project_path, :user_project
def initialize(user_project_path, podfile)
@user_project_path = user_project_path
@podfile = podfile
@user_project = Xcodeproj::Project.new(user_project_path)
end
def integrate!
create_workspace!
# Only need to write out the user's project if any of the target
# integrators actually did some work.
if targets.map(&:integrate!).any?
@user_project.save_as(user_project_path)
end
unless config.silent?
# TODO this really shouldn't be here
puts "[!] From now on use `#{xcworkspace_path.basename}' instead of `#{user_project_path.basename}'."
end
end
def workspace_path
config.project_root + "#{user_project_path.basename('.xcodeproj')}.xcworkspace"
end
def pods_project_path
config.project_root + "Pods/Pods.xcodeproj"
end
def targets
@podfile.target_definitions.values.map { |definition| Target.new(self, definition) }
end
def create_workspace!
workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
[user_project_path, pods_project_path].each do |project_path|
project_path = project_path.relative_path_from(config.project_root).to_s
workspace << project_path unless workspace.include?(project_path)
end
workspace.save_as(workspace_path)
end
class Target
attr_reader :integrator, :target_definition
def initialize(integrator, target_definition)
@integrator, @target_definition = integrator, target_definition
end
def integrate!
return false if targets.empty?
add_xcconfig_base_configuration
add_pods_library
add_copy_resources_script_phase
true
end
# This returns a list of the targets from the user’s project to which
# this Pods static library should be linked. If no explicit target was
# specified, then the first encountered target is assumed.
#
# In addition this will only return targets that do **not** already
# have the Pods library in their frameworks build phase.
#
# @return [Array<PBXNativeTarget>] Returns the list of targets that
# the Pods lib should be linked with.
def targets
@targets ||= begin
if link_with = @target_definition.link_with
@integrator.user_project.targets.select do |target|
link_with.include? target.name
end
else
[@integrator.user_project.targets.first]
end.reject do |target|
# reject any target that already has this Pods library in one of its frameworks build phases
target.frameworks_build_phases.any? do |phase|
phase.files.any? { |build_file| build_file.file.name == @target_definition.lib_name }
end
end
end
end
def add_xcconfig_base_configuration
xcconfig = @integrator.user_project.files.new('path' => "Pods/#{@target_definition.xcconfig_name}") # TODO use Sandbox?
targets.each do |target|
target.build_configurations.each do |config|
config.base_configuration = xcconfig
end
end
end
def add_pods_library
pods_library = @integrator.user_project.group("Frameworks").files.new_static_library(@target_definition.label)
targets.each do |target|
target.frameworks_build_phases.each do |build_phase|
build_phase.files << pods_library.build_files.new
end
end
end
def add_copy_resources_script_phase
targets.each do |target|
phase = target.shell_script_build_phases.new
phase.name = 'Copy Pods Resources'
phase.shell_script = %{"${SRCROOT}/Pods/#{@target_definition.copy_resources_script_name}"\n}
end
end
end
end
end
end
require 'xcodeproj/workspace'
require 'xcodeproj/project'
module Pod
class ProjectIntegration
extend Pod::Config::Mixin
# For now this assumes just one pods target, i.e. only libPods.a.
# Not sure yet if we should try to be smart with apps that have multiple
# targets and try to map pod targets to those app targets.
#
# Possible options are:
# 1. Only cater to the most simple setup
# 2. Try to automagically figure it out by name. For example, a pod target
# called `:some_target' could map to an app target called `SomeTarget'.
# (A variation would be to not even camelize the target name, but simply
# let the user specify it with the proper case.)
# 3. Let the user specify the app target name as an extra argument, but this
# seems to be a less good version of the variation on #2.
class << self
def integrate_with_project(projpath)
root = File.dirname(projpath)
name = File.basename(projpath, '.xcodeproj')
xcworkspace = create_workspace(root, name, projpath)
app_project = Xcodeproj::Project.new(projpath)
return if project_already_integrated?(app_project)
xcconfig = app_project.files.new('path' => 'Pods/Pods.xcconfig')
base_project_configurations_on_xcconfig(app_project, xcconfig)
libfile = app_project.files.new_static_library('Pods')
libfile.group = app_project.group("Frameworks")
add_pods_library_to_each_target_in_project(app_project, libfile)
copy_resources = app_project.add_shell_script_build_phase(
'Copy Pods Resources', %{"${SRCROOT}/Pods/Pods-resources.sh"\n})
add_copy_resources_script_phase_to_each_target_in_project(app_project, copy_resources)
app_project.save_as(projpath)
unless config.silent?
# TODO this really shouldn't be here
puts "[!] From now on use `#{File.basename(xcworkspace)}' instead of `#{File.basename(projpath)}'."
end
end
def create_workspace(in_directory, name, project_path)
workspace_path = File.join(in_directory, name + '.xcworkspace')
workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
pods_project_path = File.join(config.project_pods_root, 'Pods.xcodeproj')
root = Pathname.new(in_directory).expand_path
[project_path, pods_project_path].each do |path|
path = Pathname.new(path).expand_path.relative_path_from(root).to_s
workspace << path unless workspace.include?(path)
end
workspace.save_as(workspace_path)
workspace_path
end
def project_already_integrated?(project)
project.files.find { |file| file.path =~ /libPods\.a$/ }
end
def base_project_configurations_on_xcconfig(project, xcconfig_file)
project.targets.each do |target|
target.build_configurations.each do |config|
config.base_configuration = xcconfig_file
end
end
end
def add_pods_library_to_each_target_in_project(project, pods_library)
project.targets.each do |target|
target.frameworks_build_phases.each do |build_phase|
build_phase.files << pods_library.build_files.new
end
end
end
def add_copy_resources_script_phase_to_each_target_in_project(project, copy_resources_script_phase)
project.targets.each { |target| target.build_phases << copy_resources_script_phase }
end
end
end
end
......@@ -7,6 +7,12 @@
objects = {
/* Begin PBXBuildFile section */
51075D4C1521D0C100E39B41 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A346497114F9BE9A0080D870 /* UIKit.framework */; };
51075D4D1521D0C100E39B41 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A346497314F9BE9A0080D870 /* Foundation.framework */; };
51075D4E1521D0C100E39B41 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A346497514F9BE9A0080D870 /* CoreGraphics.framework */; };
51075D541521D0C100E39B41 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 51075D521521D0C100E39B41 /* InfoPlist.strings */; };
51075D561521D0C100E39B41 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 51075D551521D0C100E39B41 /* main.m */; };
51075D5A1521D0C100E39B41 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 51075D591521D0C100E39B41 /* AppDelegate.m */; };
A346497214F9BE9A0080D870 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A346497114F9BE9A0080D870 /* UIKit.framework */; };
A346497414F9BE9A0080D870 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A346497314F9BE9A0080D870 /* Foundation.framework */; };
A346497614F9BE9A0080D870 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A346497514F9BE9A0080D870 /* CoreGraphics.framework */; };
......@@ -16,6 +22,13 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
51075D4A1521D0C100E39B41 /* TestRunner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestRunner.app; sourceTree = BUILT_PRODUCTS_DIR; };
51075D511521D0C100E39B41 /* TestRunner-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TestRunner-Info.plist"; sourceTree = "<group>"; };
51075D531521D0C100E39B41 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
51075D551521D0C100E39B41 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
51075D571521D0C100E39B41 /* TestRunner-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TestRunner-Prefix.pch"; sourceTree = "<group>"; };
51075D581521D0C100E39B41 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
51075D591521D0C100E39B41 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
A346496D14F9BE9A0080D870 /* SampleProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SampleProject.app; sourceTree = BUILT_PRODUCTS_DIR; };
A346497114F9BE9A0080D870 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
A346497314F9BE9A0080D870 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
......@@ -29,6 +42,16 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
51075D471521D0C100E39B41 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
51075D4C1521D0C100E39B41 /* UIKit.framework in Frameworks */,
51075D4D1521D0C100E39B41 /* Foundation.framework in Frameworks */,
51075D4E1521D0C100E39B41 /* CoreGraphics.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A346496A14F9BE9A0080D870 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
......@@ -42,10 +65,32 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
51075D4F1521D0C100E39B41 /* TestRunner */ = {
isa = PBXGroup;
children = (
51075D581521D0C100E39B41 /* AppDelegate.h */,
51075D591521D0C100E39B41 /* AppDelegate.m */,
51075D501521D0C100E39B41 /* Supporting Files */,
);
path = TestRunner;
sourceTree = "<group>";
};
51075D501521D0C100E39B41 /* Supporting Files */ = {
isa = PBXGroup;
children = (
51075D511521D0C100E39B41 /* TestRunner-Info.plist */,
51075D521521D0C100E39B41 /* InfoPlist.strings */,
51075D551521D0C100E39B41 /* main.m */,
51075D571521D0C100E39B41 /* TestRunner-Prefix.pch */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
A346496214F9BE990080D870 = {
isa = PBXGroup;
children = (
A346497714F9BE9A0080D870 /* SampleProject */,
51075D4F1521D0C100E39B41 /* TestRunner */,
A346497014F9BE9A0080D870 /* Frameworks */,
A346496E14F9BE9A0080D870 /* Products */,
);
......@@ -55,6 +100,7 @@
isa = PBXGroup;
children = (
A346496D14F9BE9A0080D870 /* SampleProject.app */,
51075D4A1521D0C100E39B41 /* TestRunner.app */,
);
name = Products;
sourceTree = "<group>";
......@@ -93,6 +139,23 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
51075D491521D0C100E39B41 /* TestRunner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 51075D5B1521D0C100E39B41 /* Build configuration list for PBXNativeTarget "TestRunner" */;
buildPhases = (
51075D461521D0C100E39B41 /* Sources */,
51075D471521D0C100E39B41 /* Frameworks */,
51075D481521D0C100E39B41 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = TestRunner;
productName = TestRunner;
productReference = 51075D4A1521D0C100E39B41 /* TestRunner.app */;
productType = "com.apple.product-type.application";
};
A346496C14F9BE9A0080D870 /* SampleProject */ = {
isa = PBXNativeTarget;
buildConfigurationList = A346498514F9BE9A0080D870 /* Build configuration list for PBXNativeTarget "SampleProject" */;
......@@ -132,11 +195,20 @@
projectRoot = "";
targets = (
A346496C14F9BE9A0080D870 /* SampleProject */,
51075D491521D0C100E39B41 /* TestRunner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
51075D481521D0C100E39B41 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
51075D541521D0C100E39B41 /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A346496B14F9BE9A0080D870 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
......@@ -148,6 +220,15 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
51075D461521D0C100E39B41 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
51075D561521D0C100E39B41 /* main.m in Sources */,
51075D5A1521D0C100E39B41 /* AppDelegate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A346496914F9BE9A0080D870 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
......@@ -160,6 +241,14 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
51075D521521D0C100E39B41 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
51075D531521D0C100E39B41 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
A346497A14F9BE9A0080D870 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
......@@ -171,6 +260,34 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
51075D5C1521D0C100E39B41 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "TestRunner/TestRunner-Prefix.pch";
INFOPLIST_FILE = "TestRunner/TestRunner-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 5.1;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
51075D5D1521D0C100E39B41 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "TestRunner/TestRunner-Prefix.pch";
INFOPLIST_FILE = "TestRunner/TestRunner-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 5.1;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
WRAPPER_EXTENSION = app;
};
name = Release;
};
A346498314F9BE9A0080D870 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
......@@ -241,6 +358,14 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
51075D5B1521D0C100E39B41 /* Build configuration list for PBXNativeTarget "TestRunner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
51075D5C1521D0C100E39B41 /* Debug */,
51075D5D1521D0C100E39B41 /* Release */,
);
defaultConfigurationIsVisible = 0;
};
A346496714F9BE990080D870 /* Build configuration list for PBXProject "SampleProject" */ = {
isa = XCConfigurationList;
buildConfigurations = (
......@@ -257,6 +382,7 @@
A346498714F9BE9A0080D870 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
......
......@@ -9,7 +9,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>co.uk.lukeredpath.${PRODUCT_NAME:rfc1034identifier}</string>
<string>org.cocoapods.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
......
//
// AppDelegate.h
// TestRunner
//
// Created by Eloy Durán on 3/27/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
//
// AppDelegate.m
// TestRunner
//
// Created by Eloy Durán on 3/27/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "AppDelegate.h"
@implementation AppDelegate
@synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>org.cocoapods.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
//
// Prefix header for all source files of the 'TestRunner' target in the 'TestRunner' project
//
#import <Availability.h>
#ifndef __IPHONE_3_0
#warning "This project uses features only available in iOS SDK 3.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif
//
// main.m
// TestRunner
//
// Created by Eloy Durán on 3/27/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
require File.expand_path('../../../spec_helper', __FILE__)
describe Pod::Project::Integrator, 'TODO UNIT SPECS!' do
extend SpecHelper::TemporaryDirectory
before do
@podfile = Pod::Podfile.new do
platform :ios
dependency 'JSONKit'
target :test_runner, :exclusive => true, :link_with => 'TestRunner' do
dependency 'Kiwi'
end
end
@sample_project_path = SpecHelper.create_sample_app_copy_from_fixture('SampleProject')
config.project_root = @sample_project_path.dirname
@integrator = Pod::Project::Integrator.new(@sample_project_path, @podfile)
end
after do
config.project_root = nil
end
it "returns the path to the workspace in the project's root" do
@integrator.workspace_path.should == config.project_root + 'SampleProject.xcworkspace'
end
it "returns the path to the Pods.xcodeproj document" do
@integrator.pods_project_path.should == config.project_root + 'Pods/Pods.xcodeproj'
end
it "returns a Pod::Project::Integrator::Target for each target definition in the Podfile" do
@integrator.targets.map(&:target_definition).should == @podfile.target_definitions.values
end
it "uses the first target in the user's project if no explicit target is specified" do
target_integrator = @integrator.targets.first
target_integrator.target_definition.stubs(:link_with).returns(nil)
target_integrator.targets.should == [Xcodeproj::Project.new(@sample_project_path).targets.first]
end
end
describe Pod::Project::Integrator do
extend SpecHelper::TemporaryDirectory
before do
@podfile = Pod::Podfile.new do
platform :ios
link_with 'SampleProject' # this is an app target!
dependency 'JSONKit'
target :test_runner, :exclusive => true, :link_with => 'TestRunner' do
dependency 'Kiwi'
end
end
@sample_project_path = SpecHelper.create_sample_app_copy_from_fixture('SampleProject')
config.project_root = @sample_project_path.dirname
@integrator = Pod::Project::Integrator.new(@sample_project_path, @podfile)
@integrator.integrate!
@sample_project = Xcodeproj::Project.new(@sample_project_path)
end
after do
config.project_root = nil
end
it 'creates a workspace with a name matching the project' do
workspace_path = @sample_project_path.dirname + "SampleProject.xcworkspace"
workspace_path.should.exist
end
it 'adds the project being integrated to the workspace' do
workspace = Xcodeproj::Workspace.new_from_xcworkspace(@sample_project_path.dirname + "SampleProject.xcworkspace")
workspace.should.include?("SampleProject.xcodeproj")
end
it 'adds the Pods project to the workspace' do
workspace = Xcodeproj::Workspace.new_from_xcworkspace(@sample_project_path.dirname + "SampleProject.xcworkspace")
workspace.projpaths.find { |path| path =~ /Pods.xcodeproj/ }.should.not.be.nil
end
it 'adds the Pods xcconfig file to the project' do
@sample_project.files.where(:path => "Pods/Pods.xcconfig").should.not.be.nil
end
it 'sets the Pods xcconfig as the base config for each build configuration' do
@podfile.target_definitions.each do |_, definition|
target = @sample_project.targets.where(:name => definition.link_with.first)
xcconfig_file = @sample_project.files.where(:path => "Pods/#{definition.xcconfig_name}")
target.build_configurations.each do |config|
config.base_configuration.should == xcconfig_file
end
end
end
it 'adds references to the Pods static libraries' do
@sample_project.files.where(:name => "libPods.a").should.not == nil
@sample_project.files.where(:name => "libPods-test_runner.a").should.not == nil
end
it 'adds the libPods static library to the "Link binary with libraries" build phase of each target' do
@podfile.target_definitions.each do |_, definition|
target = @sample_project.targets.where(:name => definition.link_with.first)
framework_build_phase = target.frameworks_build_phases.first
framework_build_phase.files.where(:file => { :name => definition.lib_name }).should.not == nil
end
end
it 'adds a Copy Pods Resources build phase to each target' do
@podfile.target_definitions.each do |_, definition|
target = @sample_project.targets.where(:name => definition.link_with.first)
phase = target.shell_script_build_phases.where(:name => "Copy Pods Resources")
phase.shell_script.strip.should == "\"${SRCROOT}/Pods/#{definition.copy_resources_script_name}\"".strip
end
end
it "only tries to integrate Pods libraries into user targets that haven't been integrated yet" do
app, test_runner = @integrator.user_project.targets.to_a
test_runner.frameworks_build_phases.first.files.last.destroy
targets = @integrator.targets.sort_by { |target| target.target_definition.label }
@integrator.stubs(:targets).returns(targets)
targets.first.expects(:add_pods_library).never
targets.last.expects(:add_pods_library)
@integrator.integrate!
end
it "does not even try to save the project if none of the target integrators had any work to do" do
@integrator.user_project.expects(:save_as).never
@integrator.integrate!
end
end
require File.expand_path('../../spec_helper', __FILE__)
describe Pod::ProjectIntegration do
before do
@sample_project_path = SpecHelper.create_sample_app_copy_from_fixture('SampleProject')
Pod::ProjectIntegration.integrate_with_project(@sample_project_path)
@sample_project = Xcodeproj::Project.new(@sample_project_path)
end
it 'creates a workspace with a name matching the project' do
workspace_path = @sample_project_path.dirname + "SampleProject.xcworkspace"
workspace_path.should.exist
end
it 'adds the project being integrated to the workspace' do
workspace = Xcodeproj::Workspace.new_from_xcworkspace(@sample_project_path.dirname + "SampleProject.xcworkspace")
workspace.should.include?("SampleProject.xcodeproj")
end
it 'adds the Pods project to the workspace' do
workspace = Xcodeproj::Workspace.new_from_xcworkspace(@sample_project_path.dirname + "SampleProject.xcworkspace")
workspace.projpaths.find { |path| path =~ /Pods.xcodeproj/ }.should.not.be.nil
end
it 'adds the Pods xcconfig file to the project' do
@sample_project.files.where(:path => "Pods/Pods.xcconfig").should.not.be.nil
end
it 'sets the Pods xcconfig as the base config for each build configuration' do
xcconfig_file = @sample_project.files.where(:path => "Pods/Pods.xcconfig")
@sample_project.targets.each do |target|
target.build_configurations.each do |config|
config.base_configuration.should == xcconfig_file
end
end
end
it 'adds a reference to the libPods static library' do
static_lib = @sample_project.files.where(:name => "libPods.a")
static_lib.should.not.be.nil
end
it 'adds the libPods static library to the "Link binary with libraries" build phase of each target' do
@sample_project.targets.each do |target|
framework_build_phase = target.frameworks_build_phases.first
framework_build_phase.files.where(:file => {:name => 'libPods.a'}).should.not.be.nil
end
end
it 'adds a Copy Pods Resources build phase to each target' do
@sample_project.targets.each do |target|
expected_phase = target.shell_script_build_phases.where(:name => "Copy Pods Resources")
expected_phase.shell_script.strip.should == "\"${SRCROOT}/Pods/Pods-resources.sh\"".strip
end
end
end
......@@ -363,27 +363,23 @@ else
self.platform platform
dependency 'SSZipArchive'
end
installer = SpecHelper::Installer.new(spec)
installer = SpecHelper::Installer.new(spec, projpath)
installer.install!
Pod::ProjectIntegration.integrate_with_project(projpath)
xcworkspace = temporary_directory + 'ASIHTTPRequest.xcworkspace'
workspace = Xcodeproj::Workspace.new_from_xcworkspace(xcworkspace)
workspace = Xcodeproj::Workspace.new_from_xcworkspace(temporary_directory + 'ASIHTTPRequest.xcworkspace')
workspace.projpaths.sort.should == ['ASIHTTPRequest.xcodeproj', 'Pods/Pods.xcodeproj']
project = Pod::Project.new(projpath)
libPods = project.files.find { |f| f.name == 'libPods.a' }
project.targets.each do |target|
target.build_configurations.each do |config|
config.base_configuration.path.should == 'Pods/Pods.xcconfig'
end
phase = target.frameworks_build_phases.first
phase.files.map { |build_file| build_file.file }.should.include libPods
# should be the last phase
target.build_phases.last.shell_script.should == %{"${SRCROOT}/Pods/Pods-resources.sh"\n}
target = project.targets.first
target.build_configurations.each do |config|
config.base_configuration.path.should == 'Pods/Pods.xcconfig'
end
phase = target.frameworks_build_phases.first
phase.files.map { |build_file| build_file.file }.should.include libPods
# should be the last phase
target.build_phases.last.shell_script.should == %{"${SRCROOT}/Pods/Pods-resources.sh"\n}
end
it "should prevent duplication cleaning headers symlinks with multiple targets" do
......
......@@ -12,18 +12,23 @@ $:.unshift((ROOT + 'lib').to_s)
require 'cocoapods'
$:.unshift((ROOT + 'spec').to_s)
require 'spec_helper/color_output'
require 'spec_helper/fixture'
require 'spec_helper/git'
require 'spec_helper/temporary_directory'
context_class = defined?(BaconContext) ? BaconContext : Bacon::Context
context_class.class_eval do
include Pod::Config::Mixin
module Bacon
extend ColorOutput
summary_at_exit
include SpecHelper::Fixture
class Context
include Pod::Config::Mixin
def argv(*argv)
Pod::Command::ARGV.new(argv)
include SpecHelper::Fixture
def argv(*argv)
Pod::Command::ARGV.new(argv)
end
end
end
......
# Graciously yanked from https://github.com/zen-cms/Zen-Core
# MIT License
# Thanks, YorickPeterse!
#:nodoc:
module Bacon
#:nodoc:
module ColorOutput
#:nodoc:
def handle_specification(name)
puts spaces + name
yield
puts if Counter[:context_depth] == 1
end
#:nodoc:
def handle_requirement(description)
error = yield
if !error.empty?
puts "#{spaces} \e[31m- #{description} [FAILED]\e[0m"
else
puts "#{spaces} \e[32m- #{description}\e[0m"
end
end
#:nodoc:
def handle_summary
print ErrorLog if Backtraces
puts "%d specifications (%d requirements), %d failures, %d errors" %
Counter.values_at(:specifications, :requirements, :failed, :errors)
end
#:nodoc:
def spaces
if Counter[:context_depth] == 0
Counter[:context_depth] = 1
end
return ' ' * (Counter[:context_depth] - 1)
end
end # ColorOutput
end # Bacon
......@@ -4,10 +4,8 @@ module SpecHelper
end
def self.create_sample_app_copy_from_fixture(fixture_name)
tmp_dir = Pathname.new(Dir.mktmpdir)
fixture_path = ROOT + "spec/fixtures/#{fixture_name}"
fixture_copy_path = tmp_dir + fixture_name
FileUtils.cp_r(fixture_path, tmp_dir)
fixture_copy_path = temporary_directory + fixture_name
FileUtils.cp_r(fixture(fixture_name), temporary_directory)
fixture_copy_path + "#{fixture_name}.xcodeproj"
end
......
......@@ -78,7 +78,7 @@ describe "Pod::Podfile" do
dependency 'SSZipArchive'
end
target :test, :exclusive => true do
target :test, :exclusive => true, :link_with => 'TestRunner' do
dependency 'JSONKit'
target :subtarget do
dependency 'Reachability'
......@@ -95,13 +95,13 @@ describe "Pod::Podfile" do
it "adds dependencies outside of any explicit target block to the default target" do
target = @podfile.target_definitions[:default]
target.lib_name.should == 'Pods'
target.label.should == 'Pods'
target.dependencies.should == [Pod::Dependency.new('ASIHTTPRequest')]
end
it "adds dependencies of the outer target to non-exclusive targets" do
target = @podfile.target_definitions[:debug]
target.lib_name.should == 'Pods-debug'
target.label.should == 'Pods-debug'
target.dependencies.sort_by(&:name).should == [
Pod::Dependency.new('ASIHTTPRequest'),
Pod::Dependency.new('SSZipArchive')
......@@ -110,15 +110,50 @@ describe "Pod::Podfile" do
it "does not add dependencies of the outer target to exclusive targets" do
target = @podfile.target_definitions[:test]
target.lib_name.should == 'Pods-test'
target.label.should == 'Pods-test'
target.dependencies.should == [Pod::Dependency.new('JSONKit')]
end
it "adds dependencies of the outer target to nested targets" do
target = @podfile.target_definitions[:subtarget]
target.lib_name.should == 'Pods-test-subtarget'
target.label.should == 'Pods-test-subtarget'
target.dependencies.should == [Pod::Dependency.new('Reachability'), Pod::Dependency.new('JSONKit')]
end
it "leaves the name of the target, to link with, to be automatically resolved" do
target = @podfile.target_definitions[:default]
target.link_with.should == nil
end
it "returns the names of the explicit targets to link with" do
target = @podfile.target_definitions[:test]
target.link_with.should == ['TestRunner']
end
it "returns the name of the Pods static library" do
@podfile.target_definitions[:default].lib_name.should == 'libPods.a'
@podfile.target_definitions[:test].lib_name.should == 'libPods-test.a'
end
it "returns the name of the xcconfig file for the target" do
@podfile.target_definitions[:default].xcconfig_name.should == 'Pods.xcconfig'
@podfile.target_definitions[:test].xcconfig_name.should == 'Pods-test.xcconfig'
end
it "returns the name of the 'copy resources script' file for the target" do
@podfile.target_definitions[:default].copy_resources_script_name.should == 'Pods-resources.sh'
@podfile.target_definitions[:test].copy_resources_script_name.should == 'Pods-test-resources.sh'
end
it "returns the name of the 'prefix header' file for the target" do
@podfile.target_definitions[:default].prefix_header_name.should == 'Pods-prefix.pch'
@podfile.target_definitions[:test].prefix_header_name.should == 'Pods-test-prefix.pch'
end
it "returns the name of the BridgeSupport file for the target" do
@podfile.target_definitions[:default].bridge_support_name.should == 'Pods.bridgesupport'
@podfile.target_definitions[:test].bridge_support_name.should == 'Pods-test.bridgesupport'
end
end
describe "concerning validations" do
......
......@@ -5,7 +5,7 @@ TMP_POD_ROOT = ROOT + "tmp" + "podroot"
describe Pod::Installer::TargetInstaller do
before do
@target_definition = stub('target', :lib_name => "FooLib")
@target_definition = Pod::Podfile::TargetDefinition.new(:foo)
platform = Pod::Platform.new(:ios)
@podfile = stub('podfile', :platform => platform,
......@@ -29,7 +29,7 @@ describe Pod::Installer::TargetInstaller do
it 'adds a new static library target to the project' do
do_install!
@project.targets.count.should == 1
@project.targets.first.name.should == "FooLib"
@project.targets.first.name.should == @target_definition.label
end
it 'adds each pod to the static library target' 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