Commit ea9b1810 authored by Fabio Pelosin's avatar Fabio Pelosin

WIP Specification refactor.

parent 81d3550d
......@@ -23,7 +23,7 @@ module Pod
# specification information
def spec
@spec ||= @set.specification.part_of_other_pod? ? @set.specification.part_of_specification : @set.specification
@set.specification
end
def authors
......
......@@ -12,7 +12,6 @@ module Pod
def self.for_pod(pod)
spec = pod.specification
spec = spec.part_of_specification if spec.part_of_other_pod?
for_target(pod.root, spec.source.dup)
end
......@@ -26,9 +25,9 @@ module Pod
def clean
# implement in sub-classes
end
private
def self.for_target(target_path, options)
options = options.dup
if url = options.delete(:git)
......
......@@ -145,14 +145,6 @@ module Pod
end
end
unless download_only_specifications.empty?
file.puts
file.puts "DOWNLOAD_ONLY:"
download_only_specifications.map(&:to_s).sort.each do |name|
file.puts " - #{name}"
end
end
file.puts
file.puts "DEPENDENCIES:"
@podfile.dependencies.map(&:to_s).sort.each do |dep|
......@@ -193,7 +185,7 @@ module Pod
result = {}
specs_by_target.each do |target_definition, specs|
result[target_definition] = specs.map do |spec|
LocalPod.new(spec, @sandbox, target_definition.platform) if activated_spec?(spec)
LocalPod.new(spec, @sandbox, target_definition.platform)
end.compact
end
result
......@@ -203,24 +195,15 @@ module Pod
# dependency that is not a download-only
# one.
def activated_specifications
dependency_specifications.select { |spec| activated_spec?(spec) }
dependency_specifications
end
def activated_specifications_for_target(target_definition)
specs_by_target[target_definition].select { |spec| activated_spec?(spec) }
end
def download_only_specifications
dependency_specifications - activated_specifications
specs_by_target[target_definition]
end
private
def activated_spec?(spec)
# Don't activate specs which are only wrappers of subspecs, or share
# source with another pod but aren't activated themselves.
!spec.wrapper? && !@resolver.cached_sets[spec.name].only_part_of_other_pod?
end
def print_title(title, only_verbose = true)
if config.verbose?
......
......@@ -27,13 +27,7 @@ module Pod
targets_and_specs[target_definition] = @specs.values_at(*@loaded_specs).sort_by(&:name)
end
# Specification doesn't need to know more about the context, so we assign
# the other specification, of which this pod is a part, to the spec.
@specs.values.sort_by(&:name).each do |spec|
if spec.part_of_other_pod?
spec.part_of_specification = @cached_sets[spec.part_of.name].specification
end
end
@specs.values.sort_by(&:name)
targets_and_specs
end
......@@ -41,7 +35,8 @@ module Pod
private
def find_cached_set(dependency, platform)
@cached_sets[dependency.name] ||= begin
set_name = dependency.name.split('/').first
@cached_sets[set_name] ||= begin
if dependency.specification
Specification::Set::External.new(dependency.specification)
elsif external_source = dependency.external_source
......@@ -71,6 +66,7 @@ module Pod
if dependency.subspec_dependency?
spec = spec.subspec_by_name(dependency.name)
end
@loaded_specs << spec.name
@specs[spec.name] = spec
......@@ -84,8 +80,8 @@ module Pod
end
def validate_platform!(spec, target)
unless spec.platforms.any? { |platform| target.platform.support?(platform) }
raise Informative, "[!] The platform of the target `#{target.name}' (#{target.platform}) is not compatible with `#{spec}' which has a minimun requirement of #{spec.platforms.join(' - ')}.".red
unless spec.available_platforms.any? { |platform| target.platform.support?(platform) }
raise Informative, "[!] The platform of the target `#{target.name}' (#{target.platform}) is not compatible with `#{spec}' which has a minimun requirement of #{spec.available_platforms.join(' - ')}.".red
end
end
end
......
......@@ -13,18 +13,21 @@ module Pod
autoload :Statistics, 'cocoapods/specification/statistics'
# The file is expected to define and return a Pods::Specification.
def self.from_file(path)
# If name is equals to nil it returns the top level Specification,
# otherwise it returned the specification with the name that matches
def self.from_file(path, subspec_name = nil)
unless path.exist?
raise Informative, "No podspec exists at path `#{path}'."
end
spec = ::Pod._eval_podspec(path)
spec.defined_in_file = path
spec
spec.subspec_by_name(subspec_name)
end
attr_accessor :defined_in_file
attr_accessor :defined_in_file, :parent
def initialize
def initialize(parent = nil, name = nil)
@parent, @name = parent, name if parent
post_initialize
yield self if block_given?
end
......@@ -33,121 +36,110 @@ module Pod
def post_initialize
@define_for_platforms = [:osx, :ios]
@clean_paths, @subspecs = [], []
@dependencies, @source_files, @resources = { :ios => [], :osx => [] }, { :ios => [], :osx => [] }, { :ios => [], :osx => [] }
@deployment_target = {}
@platform = Platform.new(nil)
@xcconfig = { :ios => Xcodeproj::Config.new, :osx => Xcodeproj::Config.new }
@compiler_flags = { :ios => '', :osx => '' }
end
# Attributes **without** multiple platform support
initialized_multiplatform_attributes
attr_accessor :name
attr_accessor :homepage
attr_accessor :description
attr_accessor :source
attr_accessor :documentation
attr_reader :version
def version=(version)
@version = Version.new(version)
# deprecated attributes
@source = {:git => ''}
end
def authors=(*names_and_email_addresses)
list = names_and_email_addresses.flatten
unless list.first.is_a?(Hash)
authors = list.last.is_a?(Hash) ? list.pop : {}
list.each { |name| authors[name] = nil }
end
@authors = authors || list.first
# Deprecated attributes
# TODO: remove once master repo and fixtures are updated
def part_of_dependency=(value)
puts "[!] `part_of_dependency' is deprecated in #{name}"
end
alias_method :author=, :authors=
attr_reader :authors
def summary=(summary)
@summary = summary
def part_of=(value)
puts "[!] `part_of_dependency' is deprecated in #{name}"
end
attr_reader :summary
def license=(license)
if license.kind_of?(Array)
@license = license[1].merge({:type => license[0]})
elsif license.kind_of?(String)
@license = {:type => license}
else
@license = license
end
end
attr_reader :license
# Normal attributes
def description
@description || summary
def name
@parent ? "#{@parent.name}/#{@name}" : @name
end
def part_of=(*name_and_version_requirements)
self.part_of_dependency = *name_and_version_requirements
@part_of.only_part_of_other_pod = true
end
attr_reader :part_of
attr_writer :name
def part_of_dependency=(*name_and_version_requirements)
@part_of = dependency(*name_and_version_requirements)
def summary
@summary || ( @parent.summary if @parent )
end
def prefix_header_file=(file)
@prefix_header_file = Pathname.new(file)
attr_writer :summary
def available_platforms
@platform.nil? ? @define_for_platforms.map { |platform| Platform.new(platform, @deployment_target[platform]) } : [ platform ]
end
attr_reader :prefix_header_file
attr_accessor :prefix_header_contents
attr_accessor :main_subspec
def clean_paths=(patterns)
@clean_paths = pattern_list(patterns)
end
attr_reader :clean_paths
alias_method :clean_path=, :clean_paths=
### Top level attributes. These attributes represent the unique features of pod and can't be specified by subspecs.
def header_dir=(dir)
@header_dir = Pathname.new(dir)
end
def header_dir
@header_dir || pod_destroot_name
end
# Attributes **without** multiple platform support
def platform=(platform)
@platform = Platform.new(*platform)
# Creates a top level attribute reader.
def self.top_attr_reader(attr, block = nil)
define_method(attr) do
ivar = instance_variable_get("@#{attr}")
@parent ? top_level_parent.send(attr) : ( block ? block.call(self, ivar) : ivar )
end
end
attr_reader :platform
def platforms
@platform.nil? ? @define_for_platforms.map { |platfrom| Platform.new(platfrom, @deployment_target[platfrom]) } : [platform]
# Creates a top level attribute writer. A lambda can be passed to initialize the value.
def self.top_attr_writer(attr, block = nil)
raise Informative "Can't set #{attr} for subspecs" if @parent
define_method("#{attr}=") do |value|
instance_variable_set("@#{attr}", block ? block.call(value) : value);
end
end
def requires_arc=(requires_arc)
self.compiler_flags = '-fobjc-arc' if requires_arc
@requires_arc = requires_arc
# Creates a top level attribute accessor. A lambda can be passed to initialize the value in the attribute writer.
def self.top_attr_accessor(attr, block = nil)
top_attr_reader attr
top_attr_writer attr, block
end
attr_reader :requires_arc
def subspec(name, &block)
subspec = Subspec.new(self, name, &block)
@subspecs << subspec
subspec
end
attr_reader :subspecs
top_attr_accessor :homepage
top_attr_accessor :source
top_attr_accessor :documentation
top_attr_accessor :requires_arc
top_attr_accessor :license, lambda { |l| ( l.kind_of? String ) ? { :type => l } : l }
top_attr_accessor :version, lambda { |v| Version.new(v) }
top_attr_accessor :platform, lambda { |p| Platform.new(*p) }
top_attr_accessor :readme_file, lambda { |file| Pathname.new(file) }
top_attr_accessor :authors, lambda { |a| parse_authors(a) }
alias_method :author=, :authors=
def recursive_subspecs
unless @recursive_subspecs
mapper = lambda do |spec|
spec.subspecs.map do |subspec|
[subspec, *mapper.call(subspec)]
end.flatten
end
@recursive_subspecs = mapper.call self
top_attr_reader :description, lambda { |instance, ivar| ivar || instance.summary }
top_attr_writer :description
#TODO: are those top level?
top_attr_accessor :prefix_header_contents
top_attr_accessor :prefix_header_file, lambda { |file| Pathname.new(file) }
top_attr_reader :header_dir, lambda {|instance, ivar| ivar || instance.pod_destroot_name }
top_attr_writer :header_dir, lambda {|dir| Pathname.new(dir) }
#TODO: deprecate and clean all unused files
top_attr_accessor :clean_paths, lambda { |patterns| pattern_list(patterns) }
alias_method :clean_path=, :clean_paths=
def self.parse_authors(*names_and_email_addresses)
list = names_and_email_addresses.flatten
unless list.first.is_a?(Hash)
authors = list.last.is_a?(Hash) ? list.pop : {}
list.each { |name| authors[name] = nil }
end
@recursive_subspecs
authors || list.first
end
# # TODO: move logic to compiler_flags
# def requires_arc=(requires_arc)
# self.compiler_flags = '-fobjc-arc' if requires_arc
# @requires_arc = requires_arc
# end
### Attributes **with** multiple platform support
class PlatformProxy
......@@ -172,52 +164,87 @@ module Pod
PlatformProxy.new(self, :osx)
end
def source_files=(patterns)
@define_for_platforms.each do |platform|
@source_files[platform] = pattern_list(patterns)
end
# It returns the value of the attribute for the current platform. In this way clients do not need to be aware of wich
# attributes are multiplatform
def self.platform_attr_reader(attr)
# TODO: implement
attr_reader attr
end
attr_reader :source_files
def deployment_target=(version)
raise Informative, "The deployment target must be defined per platform like s.ios.deployment_target = '5.0'" unless @define_for_platforms.count == 1
@deployment_target[@define_for_platforms.first] = version
# It returns the value of a pod merged with upstream. The optional lambda can specify how to merge the values
def self.pltf_chained_attr_reader(attr, merge_lambda = nil)
# TODO: chain the value with the upstream
attr_reader attr
end
def resources=(patterns)
@define_for_platforms.each do |platform|
@resources[platform] = pattern_list(patterns)
def self.platform_attr_writer(attr, block = nil)
define_method("#{attr}=") do |value|
current = instance_variable_get("@#{attr}")
@define_for_platforms.each do |platform|
block ? current[platform] = block.call(value, current[platform]) : current[platform] = value
end
end
end
attr_reader :resources
alias_method :resource=, :resources=
def xcconfig=(build_settings)
@define_for_platforms.each do |platform|
@xcconfig[platform].merge!(build_settings)
def initialized_multiplatform_attributes
%w[ source_files resources frameworks libraries dependencies compiler_flags].each do |attr|
instance_variable_set( "@#{attr}", { :ios => [], :osx => [] } )
end
@dependencies = { :ios => [], :osx => [] }
@xcconfig = { :ios => Xcodeproj::Config.new, :osx => Xcodeproj::Config.new }
end
attr_reader :xcconfig
def frameworks=(*frameworks)
frameworks.unshift('')
self.xcconfig = { 'OTHER_LDFLAGS' => frameworks.join(' -framework ').strip }
end
alias_method :framework=, :frameworks=
pltf_chained_attr_reader :source_files
platform_attr_writer :source_files, lambda {|value, current| pattern_list(value) }
pltf_chained_attr_reader :resources
platform_attr_writer :resources, lambda {|value, current| pattern_list(value) }
alias_method :resource=, :resources=
def libraries=(*libraries)
libraries.unshift('')
self.xcconfig = { 'OTHER_LDFLAGS' => libraries.join(' -l').strip }
# frameworks are chained by the xcofing attr_reader
platform_attr_reader :frameworks
platform_attr_writer :frameworks, lambda {|value, current| current << value }
alias_method :framework=, :frameworks=
# libraries are chained by the xcofing attr_reader
platform_attr_reader :libraries
platform_attr_writer :libraries, lambda {|value, current| current << value }
alias_method :library=, :libraries=
def xcconfig
result = {}
@define_for_platforms.each do |platform|
if @parent
chained = @xcconfig[platform].dup.unshift @parent.xcconfig[platform]
else
chained = @xcconfig[platform].dup
end
chained.merge!({ 'OTHER_LDFLAGS' => '-l' << libraries[platform].join(' -l').strip }) unless libraries[platform].empty?
chained.merge!({ 'OTHER_LDFLAGS' => '-framework ' << frameworks[platform].join(' -framework ').strip }) unless frameworks[platform].empty?
result[platform] = chained
end
result
end
alias_method :library=, :libraries=
attr_reader :compiler_flags
def compiler_flags=(flags)
platform_attr_writer :xcconfig, lambda {|value, current| current.tap { |c| c.merge!(value) } }
def compiler_flags
result = {}
@define_for_platforms.each do |platform|
@compiler_flags[platform] << ' ' << flags
if @parent
chained = @compiler_flags[platform].dup.unshift @parent.compiler_flags[platform]
else
chained = @compiler_flags[platform].dup
chained.unshift '-fobjc-arc' if @requires_arc
chained.unshift ''
end
result[platform] = chained.join(' ')
end
result
end
platform_attr_writer :compiler_flags, lambda {|value, current| current << value }
def dependency(*name_and_version_requirements)
name, *version_requirements = name_and_version_requirements.flatten
dep = Dependency.new(name, *version_requirements)
......@@ -226,7 +253,20 @@ module Pod
end
dep
end
attr_reader :dependencies
def dependencies
result = {}
@define_for_platforms.each do |platform|
inherited_subspecs = main_subspec ? [Dependency.new("#{name}/#{main_subspec}", version)] : subspecs.map {|s| Dependency.new(s.name, version) }
result[platform] = @dependencies[platform] + inherited_subspecs
end
result
end
def deployment_target=(version)
raise Informative, "The deployment target must be defined per platform like s.ios.deployment_target = '5.0'" unless @define_for_platforms.count == 1
@deployment_target[@define_for_platforms.first] = version
end
### Not attributes
......@@ -242,30 +282,31 @@ module Pod
include Config::Mixin
def local?
!source.nil? && !source[:local].nil?
def top_level_parent
@parent ? @parent.top_level_parent : self
end
def local_path
Pathname.new(File.expand_path(source[:local]))
def subspec(name, &block)
subspec = Specification.new(self, name, &block)
@subspecs << subspec
subspec
end
attr_reader :subspecs
# This is assigned the other spec, of which this pod's source is a part, by
# a Resolver.
attr_accessor :part_of_specification
def part_of_specification
@part_of_specification || begin
set = Source.search(@part_of)
set.required_by(self)
set.specification
def recursive_subspecs
unless @recursive_subspecs
mapper = lambda do |spec|
spec.subspecs.map do |subspec|
[subspec, *mapper.call(subspec)]
end.flatten
end
@recursive_subspecs = mapper.call self
end
end
def wrapper?
source_files.values.all?(&:empty?) && !subspecs.empty?
@recursive_subspecs
end
def subspec_by_name(name)
return self if name.nil? || name == self.name
# Remove this spec's name from the beginning of the name we’re looking for
# and take the first component from the remainder, which is the spec we need
# to find now.
......@@ -278,28 +319,30 @@ module Pod
remainder.empty? ? subspec : subspec.subspec_by_name(name)
end
def ==(other)
object_id == other.object_id ||
(self.class === other &&
name && name == other.name &&
version && version == other.version)
# Returns if the specification is supported in a given platform
def supports_platform?(plaform)
available_platforms.any? { |p| platform.supports? p }
end
def dependency_by_top_level_spec_name(name)
@dependencies.each do |_, platform_deps|
platform_deps.each do |dep|
return dep if dep.top_level_spec_name == name
end
end
# Defines the active platform for comsumption of the specification.
def activate_for_platform(platform)
raise "[!] #{name} does not support platform".red unless supports_platform?(plaform)
@active_platform = platform
end
def local?
!source.nil? && !source[:local].nil?
end
def local_path
Pathname.new(File.expand_path(source[:local]))
end
def pod_destroot
if part_of_other_pod?
part_of_specification.pod_destroot
elsif local?
if local?
local_path
else
config.project_pods_root + @name
config.project_pods_root + top_level_parent.name
end
end
......@@ -309,15 +352,7 @@ module Pod
end
end
def part_of_other_pod?
!part_of.nil?
end
def podfile?
false
end
def pattern_list(patterns)
def self.pattern_list(patterns)
if patterns.is_a?(Array) && (!defined?(Rake) || !patterns.is_a?(Rake::FileList))
patterns
else
......@@ -332,15 +367,7 @@ module Pod
# namespacing. You can, however, override this method in the podspec, or
# copy_header_mappings for full control.
def copy_header_mapping(from)
from.basename
end
def to_s
"#{name} (#{version})"
end
def inspect
"#<#{self.class.name} for #{to_s}>"
@parent ? top_level_parent.copy_header_mapping(from) : from.basename
end
# This is a convenience method which gets called after all pods have been
......@@ -359,53 +386,32 @@ module Pod
def post_install(target)
end
class Subspec < Specification
attr_reader :parent
def initialize(parent, name)
@parent, @name = parent, name
# TODO a MacRuby bug, the correct super impl `initialize' is not called consistently
#super(&block)
post_initialize
# A subspec is _always_ part of the source of its top level spec.
self.part_of = top_level_parent.name, version
# A subspec has a dependency on the parent if the parent is a subspec too.
dependency(@parent.name, version) if @parent.is_a?(Subspec)
yield self if block_given?
end
undef_method :name=, :version=, :source=
def top_level_parent
top_level_parent = @parent
top_level_parent = top_level_parent.parent while top_level_parent.is_a?(Subspec)
top_level_parent
end
def name
"#{@parent.name}/#{@name}"
end
# TODO manually forwarding the attributes that we have so far needed to forward,
# but need to think if there's a better way to do this.
def podfile?
false
end
def summary
@summary ? @summary : top_level_parent.summary
end
def to_s
"#{name} (#{version})"
end
# Override the getters to always return the value of the top level parent spec.
[:version, :summary, :platform, :license, :authors, :requires_arc, :compiler_flags, :documentation, :homepage].each do |attr|
define_method(attr) { top_level_parent.send(attr) }
end
def inspect
"#<#{self.class.name} for #{to_s}>"
end
def copy_header_mapping(from)
top_level_parent.copy_header_mapping(from)
def dependency_by_top_level_spec_name(name)
dependencies.each do |_, platform_deps|
platform_deps.each do |dep|
return dep if dep.top_level_spec_name == name
end
end
end
def ==(other)
object_id == other.object_id ||
(self.class === other &&
name && name == other.name &&
version && version == other.version)
end
end
Spec = Specification
end
......@@ -27,10 +27,6 @@ module Pod
end
end
def only_part_of_other_pod?
@required_by.all? { |spec| spec.dependency_by_top_level_spec_name(name).only_part_of_other_pod? }
end
def name
@pod_dir.basename.to_s
end
......@@ -88,10 +84,6 @@ module Pod
@specification = before
end
def only_part_of_other_pod?
false
end
def specification_path
raise "specification_path"
end
......
......@@ -81,7 +81,7 @@ module Pod
def github_stats_if_needed(set)
return if get_value(set, :gh_date) && get_value(set, :gh_date) > Time.now - cache_expiration
spec = set.specification.part_of_other_pod? ? set.specification.part_of_specification : set.specification
spec = set.specification
url = spec.source.reject {|k,_| k == :commit || k == :tag }.values.first
repo_id = url[/github.com\/([^\/\.]*\/[^\/\.]*)\.*/, 1]
return unless repo_id
......
......@@ -9,11 +9,9 @@ module SpecHelper
def specs_by_target
@specs_by_target ||= super.tap do |hash|
hash.values.flatten.each do |spec|
unless spec.part_of_other_pod?
source = spec.source
source[:git] = SpecHelper.fixture("integration/#{spec.name}").to_s
spec.source = source
end
source = spec.source
source[:git] = SpecHelper.fixture("integration/#{spec.name}").to_s
spec.source = source
end
end
end
......@@ -113,12 +111,12 @@ else
installer.install!
YAML.load(installer.lock_file.read).should == {
'PODS' => [{ 'Reachability (1.2.3)' => ["ASIHTTPRequest (>= 1.8)"] }],
'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"],
'PODS' => [ 'Reachability (1.2.3)' ],
# 'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"],
'DEPENDENCIES' => ["Reachability (from `#{url}')"]
}
end
it "install a dummy source file" do
create_config!
podfile = Pod::Podfile.new do
......@@ -131,7 +129,7 @@ else
s.source_files = 'JSONKit.*'
end
end
installer = SpecHelper::Installer.new(podfile)
installer.install!
......@@ -254,7 +252,7 @@ else
self.platform platform
xcodeproj 'dummy'
dependency 'Reachability', '> 2.0.5' if platform == :ios
dependency 'ASIWebPageRequest', '>= 1.8.1'
# dependency 'ASIWebPageRequest', '>= 1.8.1'
dependency 'JSONKit', '>= 1.0'
dependency 'SSZipArchive', '< 2'
end
......@@ -264,14 +262,14 @@ else
lock_file_contents = {
'PODS' => [
{ 'ASIHTTPRequest (1.8.1)' => ["Reachability"] },
{ 'ASIWebPageRequest (1.8.1)' => ["ASIHTTPRequest (= 1.8.1)"] },
# { 'ASIHTTPRequest (1.8.1)' => ["Reachability"] },
# { 'ASIWebPageRequest (1.8.1)' => ["ASIHTTPRequest (= 1.8.1)"] },
'JSONKit (1.5pre)',
'Reachability (3.0.0)',
'SSZipArchive (0.1.2)',
],
'DEPENDENCIES' => [
"ASIWebPageRequest (>= 1.8.1)",
# "ASIWebPageRequest (>= 1.8.1)",
"JSONKit (>= 1.0)",
"Reachability (> 2.0.5)",
"SSZipArchive (< 2)",
......@@ -279,9 +277,9 @@ else
}
unless platform == :ios
# No Reachability is required by ASIHTTPRequest on OSX
lock_file_contents['DEPENDENCIES'].delete_at(2)
lock_file_contents['PODS'].delete_at(3)
lock_file_contents['PODS'][0] = 'ASIHTTPRequest (1.8.1)'
lock_file_contents['DEPENDENCIES'].delete_at(1)
lock_file_contents['PODS'].delete_at(1)
# lock_file_contents['PODS'][0] = 'ASIHTTPRequest (1.8.1)'
end
YAML.load(installer.lock_file.read).should == lock_file_contents
......@@ -305,8 +303,9 @@ else
installer.install!
YAML.load(installer.lock_file.read).should == {
'PODS' => [{ 'Reachability (2.0.4)' => ["ASIHTTPRequest (>= 1.8)"] }],
'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"],
# 'PODS' => [{ 'Reachability (2.0.4)' => ["ASIHTTPRequest (>= 1.8)"] }],
'PODS' => [ 'Reachability (2.0.4)' ],
# 'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"],
'DEPENDENCIES' => ["Reachability (= 2.0.4)"]
}
end
......
......@@ -22,11 +22,11 @@ describe Pod::Installer::TargetInstaller do
@specification = fixture_spec('banana-lib/BananaLib.podspec')
@pods = [Pod::LocalPod.new(@specification, @sandbox, Pod::Platform.ios)]
end
def do_install!
@installer.install!(@pods, @sandbox)
end
it 'adds a new static library target to the project' do
do_install!
@project.targets.count.should == 1
......@@ -43,12 +43,12 @@ describe Pod::Installer::TargetInstaller do
@pods[0].expects(:add_to_target).with(instance_of(Xcodeproj::Project::Object::PBXNativeTarget))
do_install!
end
it 'tells each pod to link its headers' do
@pods[0].expects(:link_headers)
do_install!
end
it 'adds the sandbox header search paths to the xcconfig, with quotes' do
do_install!
@installer.xcconfig.to_hash['HEADER_SEARCH_PATHS'].should.include("\"#{@sandbox.header_search_paths.join('" "')}\"")
......@@ -58,7 +58,7 @@ describe Pod::Installer::TargetInstaller do
do_install!
@installer.xcconfig.to_hash['OTHER_LDFLAGS'].split(" ").should.not.include("-fobjc-arc")
end
it 'adds the -fobjc-arc to OTHER_LDFLAGS if any pods require arc (to support non-ARC projects on iOS 4.0)' do
@podfile.stubs(:set_arc_compatibility_flag? => true)
@specification.stubs(:requires_arc).returns(true)
......
......@@ -8,7 +8,8 @@ describe "Pod::Resolver" do
config.repos_dir = fixture('spec-repos')
@podfile = Pod::Podfile.new do
platform :ios
dependency 'ASIWebPageRequest'
dependency 'BlocksKit'
# dependency 'ASIWebPageRequest'
end
@resolver = Pod::Resolver.new(@podfile, stub('sandbox'))
end
......@@ -20,16 +21,15 @@ describe "Pod::Resolver" do
it "holds the context state, such as cached specification sets" do
@resolver.resolve
@resolver.cached_sets.values.sort_by(&:name).should == [
Pod::Spec::Set.new(config.repos_dir + 'master/ASIHTTPRequest'),
Pod::Spec::Set.new(config.repos_dir + 'master/ASIWebPageRequest'),
Pod::Spec::Set.new(config.repos_dir + 'master/Reachability'),
Pod::Spec::Set.new(config.repos_dir + 'master/A2DynamicDelegate'),
Pod::Spec::Set.new(config.repos_dir + 'master/BlocksKit'),
].sort_by(&:name)
end
it "returns all specs needed for the dependency" do
specs = @resolver.resolve.values.flatten
specs.map(&:class).uniq.should == [Pod::Specification]
specs.map(&:name).sort.should == %w{ ASIHTTPRequest ASIWebPageRequest Reachability }
specs.map(&:name).sort.should == %w{ A2DynamicDelegate BlocksKit }
end
it "does not raise if all dependencies match the platform of the root spec (Podfile)" do
......@@ -40,8 +40,8 @@ describe "Pod::Resolver" do
end
it "raises once any of the dependencies does not match the platform of its podfile target" do
set = Pod::Spec::Set.new(config.repos_dir + 'master/ASIHTTPRequest')
@resolver.cached_sets['ASIHTTPRequest'] = set
set = Pod::Spec::Set.new(config.repos_dir + 'master/BlocksKit')
@resolver.cached_sets['BlocksKit'] = set
def set.stub_platform=(platform); @stubbed_platform = platform; end
def set.specification; spec = super; spec.platform = @stubbed_platform; spec; end
......@@ -60,14 +60,14 @@ describe "Pod::Resolver" do
end
it "raises once any of the dependencies does not have a deployment_target compatible with its podfile target" do
set = Pod::Spec::Set.new(config.repos_dir + 'master/ASIHTTPRequest')
@resolver.cached_sets['ASIHTTPRequest'] = set
set = Pod::Spec::Set.new(config.repos_dir + 'master/BlocksKit')
@resolver.cached_sets['BlocksKit'] = set
@podfile.platform :ios, "4.0"
Pod::Specification.any_instance.stubs(:platforms).returns([ Pod::Platform.new(:ios, '4.0'), Pod::Platform.new(:osx, '10.7') ])
Pod::Specification.any_instance.stubs(:available_platforms).returns([ Pod::Platform.new(:ios, '4.0'), Pod::Platform.new(:osx, '10.7') ])
lambda { @resolver.resolve }.should.not.raise
Pod::Specification.any_instance.stubs(:platforms).returns([ Pod::Platform.new(:ios, '5.0'), Pod::Platform.new(:osx, '10.7') ])
Pod::Specification.any_instance.stubs(:available_platforms).returns([ Pod::Platform.new(:ios, '5.0'), Pod::Platform.new(:osx, '10.7') ])
lambda { @resolver.resolve }.should.raise Pod::Informative
end
......@@ -75,20 +75,80 @@ describe "Pod::Resolver" do
@podfile = Pod::Podfile.new do
platform :ios
dependency 'RestKit/Network'
dependency 'RestKit/ObjectMapping'
dependency 'RestKit/ObjectMapping/XML'
end
resolver = Pod::Resolver.new(@podfile, stub('sandbox'))
resolver.resolve.values.flatten.map(&:name).sort.should == %w{
FileMD5Hash
LibComponentLogging-Core
LibComponentLogging-NSLog
RestKit/Network
RestKit/ObjectMapping/XML
SOCKit
XMLReader
cocoa-oauth
}
end
it "includes all the subspecs of a specification node" do
@podfile = Pod::Podfile.new do
platform :ios
dependency 'RestKit'
end
resolver = Pod::Resolver.new(@podfile, stub('sandbox'))
resolver.resolve.values.flatten.map(&:name).sort.should == %w{
FileMD5Hash
ISO8601DateFormatter
JSONKit
LibComponentLogging-Core
LibComponentLogging-NSLog
RestKit
RestKit/Network
RestKit/ObjectMapping
RestKit/ObjectMapping/CoreData
RestKit/ObjectMapping/JSON
RestKit/ObjectMapping/XML
RestKit/UI
SOCKit
UDTableView
XMLReader
cocoa-oauth
}
end
it "if defined it includes only the main subspec of of a specification node" do
@podfile = Pod::Podfile.new do
platform :ios
dependency do |s|
s.main_subspec = 'JSON'
s.name = 'RestKit'
s.version = '0.10.0'
s.subspec 'JSON' do |js|
js.dependency 'RestKit/Network'
js.dependency 'RestKit/UI'
js.dependency 'RestKit/ObjectMapping/JSON'
js.dependency 'RestKit/ObjectMapping/CoreData'
end
s.subspec 'Network'
s.subspec 'UI'
s.subspec 'ObjectMapping' do |os|
os.subspec 'JSON'
os.subspec 'XML'
os.subspec 'CoreData'
end
end
end
resolver = Pod::Resolver.new(@podfile, stub('sandbox'))
resolver.resolve.values.flatten.map(&:name).sort.should == %w{
RestKit
RestKit/JSON
RestKit/Network
RestKit/ObjectMapping/CoreData
RestKit/ObjectMapping/JSON
RestKit/UI
}
end
end
......@@ -29,12 +29,6 @@ describe "Pod::Specification::Set" do
lambda { @set.required_version }.should.raise Pod::Informative
end
it "returns that this set is only part for other pods" do
@set.required_by(Pod::Spec.new { |s| s.part_of = 'CocoaLumberjack' })
@set.required_by(Pod::Spec.new { |s| s.part_of = 'CocoaLumberjack' })
@set.should.be.only_part_of_other_pod
end
before do
@set.required_by(Pod::Spec.new { |s| s.dependency 'CocoaLumberjack', '< 1.2.1' })
end
......@@ -51,11 +45,6 @@ describe "Pod::Specification::Set" do
@set.specification.should == Pod::Spec.new { |s| s.name = 'CocoaLumberjack'; s.version = '1.2' }
end
it "returns that this set is not only part for other pods" do
@set.required_by(Pod::Spec.new { |s| s.part_of = 'CocoaLumberjack' })
@set.should.not.be.only_part_of_other_pod
end
it "ignores dotfiles when getting the version directories" do
`touch #{fixture('spec-repos/master/CocoaLumberjack/.DS_Store')}`
lambda { @set.versions }.should.not.raise
......
......@@ -6,6 +6,10 @@ describe "A Pod::Specification loaded from a podspec" do
@spec = Pod::Specification.from_file(fixture('banana-lib/BananaLib.podspec'))
end
it "has no parent if it is the top level spec" do
@spec.parent.nil?.should == true
end
it "returns that it's not loaded from a podfile" do
@spec.should.not.be.podfile
end
......@@ -60,7 +64,6 @@ describe "A Pod::Specification loaded from a podspec" do
it "returns the pod's dependencies" do
expected = Pod::Dependency.new('monkey', '~> 1.0.1', '< 1.0.9')
@spec.dependencies.should == { :ios => [expected], :osx => [expected] }
@spec.dependency_by_top_level_spec_name('monkey').should == expected
end
it "returns the pod's xcconfig settings" do
......@@ -97,6 +100,7 @@ describe "A Pod::Specification loaded from a podspec" do
end
it "adds compiler flags if ARC is required" do
@spec.parent.should == nil
@spec.requires_arc = true
@spec.compiler_flags.should == { :ios => " -fobjc-arc", :osx => " -fobjc-arc" }
@spec.compiler_flags = "-Wunused-value"
......@@ -104,46 +108,6 @@ describe "A Pod::Specification loaded from a podspec" do
end
end
describe "A Pod::Specification that's part of another pod's source" do
before do
config.repos_dir = fixture('spec-repos')
@spec = Pod::Specification.new
end
after do
config.repos_dir = SpecHelper.tmp_repos_path
end
it "adds a dependency on the other pod's source, but not the library" do
@spec.part_of = 'monkey', '>= 1'
@spec.should.be.part_of_other_pod
dep = Pod::Dependency.new('monkey', '>= 1')
@spec.dependencies.should.not == [dep]
dep.only_part_of_other_pod = true
@spec.dependencies.should == { :ios => [dep], :osx => [dep] }
end
it "adds a dependency on the other pod's source *and* the library" do
@spec.part_of_dependency = 'monkey', '>= 1'
@spec.should.be.part_of_other_pod
@spec.dependencies[:ios].should == [Pod::Dependency.new('monkey', '>= 1')]
end
it "searches the sources for a matching specification if it has not been assigned by the Resolver yet (e.g. the search command)" do
@spec.part_of_dependency = 'SSZipArchive', '0.1.1'
@spec.part_of_specification.to_s.should == 'SSZipArchive (0.1.1)'
end
# TODO
#it "returns the specification of the pod that it's part of" do
# @spec.part_of_specification
#end
#
#it "returns the destroot of the pod that it's part of" do
# @spec.pod_destroot
#end
end
describe "A Pod::Specification, in general," do
before do
@spec = Pod::Spec.new
......@@ -160,11 +124,11 @@ describe "A Pod::Specification, in general," do
@spec.platform.deployment_target.should == Pod::Version.new('4.0')
end
it "returns the platfroms for which the pod is supported" do
it "returns the available platforms for which the pod is supported" do
@spec.platform = :ios, '4.0'
@spec.platforms.count.should == 1
@spec.platforms.first.should == :ios
@spec.platforms.first.deployment_target.should == Pod::Version.new('4.0')
@spec.available_platforms.count.should == 1
@spec.available_platforms.first.should == :ios
@spec.available_platforms.first.deployment_target.should == Pod::Version.new('4.0')
end
it "returns the license of the Pod" do
......@@ -251,11 +215,6 @@ describe "A Pod::Specification subspec" do
end
end
it "makes a parent spec a wrapper if it has no source files of its own" do
@spec.should.be.wrapper
@spec.subspecs.first.should.not.be.wrapper
end
it "returns the top level parent spec" do
@spec.subspecs.first.top_level_parent.should == @spec
@spec.subspecs.first.subspecs.first.top_level_parent.should == @spec
......@@ -266,18 +225,9 @@ describe "A Pod::Specification subspec" do
@spec.subspecs.first.subspecs.first.name.should == 'MainSpec/FirstSubSpec/SecondSubSpec'
end
it "is a `part_of' the top level parent spec" do
dependency = Pod::Dependency.new('MainSpec', '1.2.3').tap { |d| d.only_part_of_other_pod = true }
@spec.subspecs.first.part_of.should == dependency
@spec.subspecs.first.subspecs.first.part_of.should == dependency
end
it "depends on the parent spec, if it is a subspec" do
dependency = Pod::Dependency.new('MainSpec', '1.2.3').tap { |d| d.only_part_of_other_pod = true }
@spec.subspecs.first.dependencies[:ios].should == [dependency]
@spec.subspecs.first.dependencies[:osx].should == [dependency]
@spec.subspecs.first.subspecs.first.dependencies[:ios].should == [dependency, Pod::Dependency.new('MainSpec/FirstSubSpec', '1.2.3')]
@spec.subspecs.first.subspecs.first.dependencies[:osx].should == [dependency, Pod::Dependency.new('MainSpec/FirstSubSpec', '1.2.3')]
it "correctly resolves the inheritance chain" do
@spec.subspecs.first.subspecs.first.parent.should == @spec.subspecs.first
@spec.subspecs.first.parent.should == @spec
end
it "automatically forwards undefined attributes to the top level parent" do
......@@ -288,6 +238,8 @@ describe "A Pod::Specification subspec" do
end
it "returns subspecs by name" do
@spec.subspec_by_name(nil).should == @spec
@spec.subspec_by_name('MainSpec').should == @spec
@spec.subspec_by_name('MainSpec/FirstSubSpec').should == @spec.subspecs.first
@spec.subspec_by_name('MainSpec/FirstSubSpec/SecondSubSpec').should == @spec.subspecs.first.subspecs.first
end
......@@ -337,12 +289,12 @@ describe "A Pod::Specification, concerning its attributes that support different
end
it "returns the same list of xcconfig build settings for each platform" do
build_settings = { 'OTHER_LDFLAGS' => '-lObjC -framework QuartzCore -lz' }
build_settings = { 'OTHER_LDFLAGS' => '-lObjC -lz -framework QuartzCore' }
@spec.xcconfig.should == { :ios => build_settings, :osx => build_settings }
end
it "returns the same list of compiler flags for each platform" do
compiler_flags = ' -Wdeprecated-implementations -fobjc-arc'
compiler_flags = ' -fobjc-arc -Wdeprecated-implementations'
@spec.compiler_flags.should == { :ios => compiler_flags, :osx => compiler_flags }
end
......@@ -392,21 +344,21 @@ describe "A Pod::Specification, concerning its attributes that support different
it "returns a different list of xcconfig build settings for each platform" do
@spec.xcconfig.should == {
:ios => { 'OTHER_LDFLAGS' => '-lObjC -framework QuartzCore -lz' },
:osx => { 'OTHER_LDFLAGS' => '-lObjC -all_load -framework QuartzCore -framework CoreData -lz -lxml' }
:ios => { 'OTHER_LDFLAGS' => '-lObjC -lz -framework QuartzCore' },
:osx => { 'OTHER_LDFLAGS' => '-lObjC -all_load -lz -lxml -framework QuartzCore -framework CoreData' }
}
end
it "returns the list of the supported platfroms and deployment targets" do
@spec.platforms.count.should == 2
@spec.platforms.should.include? Pod::Platform.new(:osx)
@spec.platforms.should.include? Pod::Platform.new(:ios, '4.0')
@spec.available_platforms.count.should == 2
@spec.available_platforms.should.include? Pod::Platform.new(:osx)
@spec.available_platforms.should.include? Pod::Platform.new(:ios, '4.0')
end
it "returns the same list of compiler flags for each platform" do
@spec.compiler_flags.should == {
:ios => ' -Wdeprecated-implementations -fobjc-arc',
:osx => ' -Wfloat-equal -fobjc-arc'
:ios => ' -fobjc-arc -Wdeprecated-implementations',
:osx => ' -fobjc-arc -Wfloat-equal'
}
end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment