Commit 4b4bd467 authored by Will Pragnell's avatar Will Pragnell

Merged branch 'master' into 'acknowledgements'

parents 2837753d 809745bd
...@@ -19,7 +19,7 @@ link_with ['MyAppTarget', 'MyOtherAppTarget'] ...@@ -19,7 +19,7 @@ link_with ['MyAppTarget', 'MyOtherAppTarget']
dependency 'JSONKit' dependency 'JSONKit'
target :test, :exclusive => true do target :test, :exclusive => true do
xcodeproj 'TestProject' xcodeproj 'TestProject', 'Test' => :debug
link_with 'TestRunnerTarget' link_with 'TestRunnerTarget'
dependency 'Kiwi' dependency 'Kiwi'
end end
...@@ -42,6 +42,16 @@ need to specify the target to link with. ...@@ -42,6 +42,16 @@ need to specify the target to link with.
See [#76](https://github.com/CocoaPods/CocoaPods/issues/76) for more info. See [#76](https://github.com/CocoaPods/CocoaPods/issues/76) for more info.
Finally, CocoaPods will add build configurations to the Pods project for all
configurations in the other projects in the workspace. By default the
configurations are based on the `Release` configuration, to base them on the
`Debug` configuration you will have to explicitely specify them as can be seen
above in the following line:
```ruby
xcodeproj 'TestProject', 'Test' => :debug
```
### Documentation ### Documentation
......
...@@ -31,6 +31,7 @@ Gem::Specification.new do |s| ...@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
s.add_runtime_dependency 'xcodeproj', '~> 0.1.0' s.add_runtime_dependency 'xcodeproj', '~> 0.1.0'
s.add_runtime_dependency 'colored', '~> 1.2' s.add_runtime_dependency 'colored', '~> 1.2'
s.add_runtime_dependency 'escape', '~> 0.0.4' s.add_runtime_dependency 'escape', '~> 0.0.4'
s.add_runtime_dependency 'rake', '~> 0.9.0'
s.add_development_dependency 'bacon', '~> 1.1' s.add_development_dependency 'bacon', '~> 1.1'
## Make sure you can build the gem on older versions of RubyGems too: ## Make sure you can build the gem on older versions of RubyGems too:
......
...@@ -4,6 +4,10 @@ module Pod ...@@ -4,6 +4,10 @@ module Pod
VERSION = '0.6.0rc1' VERSION = '0.6.0rc1'
class Informative < StandardError class Informative < StandardError
def message
#TODO: remove formatting from raise calls and remove conditional
super !~ /\[!\]/ ? "[!] #{super}\n".red : super
end
end end
autoload :Command, 'cocoapods/command' autoload :Command, 'cocoapods/command'
......
...@@ -25,9 +25,8 @@ module Pod ...@@ -25,9 +25,8 @@ module Pod
def self.options def self.options
[ [
["--no-clean", "Leave SCM dirs like `.git' and `.svn' in tact after downloading"], ["--no-clean", "Leave SCM dirs like `.git' and `.svn' intact after downloading"],
["--no-doc", "Skip documentation generation with appledoc"], ["--no-doc", "Skip documentation generation with appledoc"],
["--force-doc", "Force the generation of documentation"],
["--no-integrate", "Skip integration of the Pods libraries in the Xcode project(s)"], ["--no-integrate", "Skip integration of the Pods libraries in the Xcode project(s)"],
["--no-update", "Skip running `pod repo update` before install"], ["--no-update", "Skip running `pod repo update` before install"],
].concat(super) ].concat(super)
...@@ -36,7 +35,6 @@ module Pod ...@@ -36,7 +35,6 @@ module Pod
def initialize(argv) def initialize(argv)
config.clean = !argv.option('--no-clean') config.clean = !argv.option('--no-clean')
config.generate_docs = !argv.option('--no-doc') config.generate_docs = !argv.option('--no-doc')
config.force_doc = argv.option('--force-doc')
config.integrate_targets = !argv.option('--no-integrate') config.integrate_targets = !argv.option('--no-integrate')
@update_repo = !argv.option('--no-update') @update_repo = !argv.option('--no-update')
super unless argv.empty? super unless argv.empty?
......
...@@ -23,7 +23,7 @@ module Pod ...@@ -23,7 +23,7 @@ module Pod
# specification information # specification information
def spec def spec
@spec ||= @set.specification.part_of_other_pod? ? @set.specification.part_of_specification : @set.specification @set.specification
end end
def authors def authors
...@@ -47,7 +47,7 @@ module Pod ...@@ -47,7 +47,7 @@ module Pod
end end
def platform def platform
spec.platform.to_s spec.available_platforms.sort { |a,b| a.to_s.downcase <=> b.to_s.downcase }.join(' - ')
end end
def license def license
...@@ -98,6 +98,7 @@ module Pod ...@@ -98,6 +98,7 @@ module Pod
end end
def distance_from_now_in_words(from_time) def distance_from_now_in_words(from_time)
return nil unless from_time
from_time = Time.parse(from_time) from_time = Time.parse(from_time)
to_time = Time.now to_time = Time.now
distance_in_days = (((to_time - from_time).abs)/60/60/24).round distance_in_days = (((to_time - from_time).abs)/60/60/24).round
......
...@@ -92,7 +92,8 @@ module Pod ...@@ -92,7 +92,8 @@ module Pod
FileUtils.cp(Pathname.new(spec.name+'.podspec'), output_path) FileUtils.cp(Pathname.new(spec.name+'.podspec'), output_path)
Dir.chdir(repo_dir) do Dir.chdir(repo_dir) do
git("add #{spec.name}") git("add #{spec.name}")
git("commit -m '#{message}'") # Bypass the pre-commit hook because we already performed validation
git("commit --no-verify -m '#{message}'")
end end
end end
end end
......
...@@ -62,42 +62,39 @@ module Pod ...@@ -62,42 +62,39 @@ module Pod
def lint def lint
puts puts
invalid_count = lint_podspecs invalid_count = lint_podspecs
count = specs_to_lint.count
if invalid_count == 0 if invalid_count == 0
puts lint_passed_message unless config.silent? lint_passed_message = count == 1 ? "#{podspecs_to_lint.first.basename} passed validation" : "All the #{count} specs passed validation"
puts lint_passed_message.green << "\n\n" unless config.silent?
else else
raise Informative, lint_failed_message(invalid_count) raise Informative, count == 1 ? "The spec did not pass validation" : "#{invalid_count} out of #{count} specs failed validation"
end end
end end
private private
def lint_podspecs def lint_podspecs
specs_count, invalid_count = 0, 0 invalid_count = 0
podspecs_to_lint.each do |podspec_file| specs_to_lint.each do |spec|
root_spec = Specification.from_file(podspec_file) # Show immediatly which pod is being processed.
specs = root_spec.recursive_subspecs.any? ? root_spec.recursive_subspecs : [root_spec] print " -> #{spec}\r" unless config.silent? || is_repo?
specs.each do |spec| $stdout.flush
# Show immediatly which pod is being processed.
print " -> #{spec}\r" unless config.silent? || is_repo? linter = Linter.new(spec)
$stdout.flush linter.lenient = @only_errors
linter.quick = @quick || is_repo?
linter = Linter.new(spec, podspec_file) invalid_count += 1 unless linter.lint
linter.lenient = @only_errors
linter.quick = @quick || is_repo? # This overwrites the previously printed text
invalid_count += 1 unless linter.lint puts " -> ".send(lint_result_color(linter)) << spec.to_s unless config.silent? || should_skip?(linter)
print_messages(spec, 'ERROR', linter.errors)
# This overwrites the previously printed text print_messages(spec, 'WARN', linter.warnings)
puts " -> ".send(lint_result_color(linter)) << spec.to_s unless config.silent? || should_skip?(linter) print_messages(spec, 'NOTE', linter.notes)
print_messages(spec, 'ERROR', linter.errors)
print_messages(spec, 'WARN', linter.warnings) puts unless config.silent? || should_skip?(linter)
print_messages(spec, 'NOTE', linter.notes) end
puts "Analyzed #{specs_to_lint.count} specs in #{podspecs_to_lint.count} podspecs files.\n\n" if is_repo? && !config.silent?
puts unless config.silent? || should_skip?(linter) invalid_count
end
specs_count += specs.count
end
puts "Analyzed #{specs_count} specs in #{podspecs_to_lint.count} podspecs files.\n\n" if is_repo? && !config.silent?
invalid_count
end end
def lint_result_color(linter) def lint_result_color(linter)
...@@ -116,55 +113,36 @@ module Pod ...@@ -116,55 +113,36 @@ module Pod
def print_messages(spec, type, messages) def print_messages(spec, type, messages)
return if config.silent? return if config.silent?
if spec.platform.name
messages = clean_platfrom_messages(messages)
else
messages = clean_duplicate_platfrom_messages(messages)
end
messages.each {|msg| puts " - #{type.ljust(5)} | #{msg}"} messages.each {|msg| puts " - #{type.ljust(5)} | #{msg}"}
end end
def clean_platfrom_messages(messages)
messages.map { |l| l.gsub(/ios: /,'').gsub(/osx: /,'') }
end
def clean_duplicate_platfrom_messages(messages)
duplicate_candiates = messages.select {|l| l.include?("ios: ")}
duplicated = duplicate_candiates.select {|l| messages.include?(l.gsub(/ios: /,'osx: ')) }
duplicated.uniq.each do |l|
clean = l.gsub(/ios: /,'')
messages.insert(messages.index(l), clean)
messages.delete(l)
messages.delete('osx: ' + clean)
end
messages
end
def podspecs_to_lint def podspecs_to_lint
@podspecs_to_lint ||= begin @podspecs_to_lint ||= begin
if (is_repo?) if (is_repo?)
files = (config.repos_dir + @repo_or_podspec).glob('**/*.podspec') files = (config.repos_dir + @repo_or_podspec).glob('**/*.podspec')
elsif @repo_or_podspec elsif @repo_or_podspec
files = [Pathname.new(@repo_or_podspec)] files = [Pathname.new(@repo_or_podspec)]
raise Informative, "[!] Unable to find a spec named #{@repo_or_podspec}".red << "\n\n" unless files[0].exist? && @repo_or_podspec.include?('.podspec') raise Informative, "Unable to find a spec named #{@repo_or_podspec}" unless files[0].exist? && @repo_or_podspec.include?('.podspec')
else else
files = Pathname.pwd.glob('*.podspec') files = Pathname.pwd.glob('*.podspec')
raise Informative, "[!] No specs found in the current directory".red << "\n\n" if files.empty? raise Informative, "No specs found in the current directory" if files.empty?
end end
files files
end end
end end
def is_repo? def specs_to_lint
@is_repo ||= @repo_or_podspec && (config.repos_dir + @repo_or_podspec).exist? && !@repo_or_podspec.include?('/') @specs_to_lint ||= begin
end podspecs_to_lint.map do |podspec|
root_spec = Specification.from_file(podspec)
def lint_passed_message # TODO find a way to lint subspecs
( podspecs_to_lint.count == 1 ? "#{podspecs_to_lint.first.basename} passed validation" : "All the specs passed validation" ).green << "\n\n" # root_spec.preferred_dependency ? root_spec.subspec_dependencies : root_spec
end.flatten
end
end end
def lint_failed_message(count) def is_repo?
( podspecs_to_lint.count == 1 ? "[!] The spec did not pass validation" : "[!] #{count} specs failed validation" ).red << "\n\n" @is_repo ||= @repo_or_podspec && (config.repos_dir + @repo_or_podspec).exist? && !@repo_or_podspec.include?('/')
end end
# Linter class # Linter class
...@@ -172,12 +150,15 @@ module Pod ...@@ -172,12 +150,15 @@ module Pod
class Linter class Linter
include Config::Mixin include Config::Mixin
# TODO: Add check to ensure that attributes inherited by subspecs are not duplicated ?
attr_accessor :quick, :lenient attr_accessor :quick, :lenient
attr_reader :spec, :file attr_reader :spec, :file
attr_reader :errors, :warnings, :notes
def initialize(spec, podspec_file) def initialize(spec)
@spec = spec @spec = spec
@file = podspec_file.realpath @file = spec.defined_in_file.realpath
end end
# Takes an array of podspec files and lints them all # Takes an array of podspec files and lints them all
...@@ -185,66 +166,74 @@ module Pod ...@@ -185,66 +166,74 @@ module Pod
# It returns true if the spec passed validation # It returns true if the spec passed validation
# #
def lint def lint
# If the spec doesn't validate it raises and informative @platform_errors, @platform_warnings, @platform_notes = {}, {}, {}
# TODO: consider raising the informative in the clients of Pod::Specification#validate!
# and just report the errors here platforms = @spec.available_platforms
peform_multiplatform_analysis unless quick platforms.each do |platform|
@platform_errors[platform], @platform_warnings[platform], @platform_notes[platform] = [], [], []
# Skip validation if there are errors in the podspec as it would result in a crash
unless podspec_errors.empty? @spec.activate_platform(platform)
@errors, @warnings, @notes = podspec_errors, [], ['[!] Fatal errors found skipping the rest of the validation'] @platform = platform
return false puts "\n\n#{spec} - Analyzing on #{platform} platform.".green.reversed if config.verbose? && !@quick
# Skip validation if there are errors in the podspec as it would result in a crash
if !podspec_errors.empty?
@platform_errors[platform] += podspec_errors
@platform_notes[platform] << "#{platform.name} [!] Fatal errors found skipping the rest of the validation"
else
@platform_warnings[platform] += podspec_warnings + deprecation_warnings
peform_extensive_analysis unless quick
end
end end
valid?
end
def valid? # Get common messages
lenient ? errors.empty? : errors.empty? && warnings.empty? @errors = @platform_errors.values.reduce(:&) || []
end @warnings = @platform_warnings.values.reduce(:&) || []
@notes = @platform_notes.values.reduce(:&) || []
def errors platforms.each do |platform|
@errors ||= file_patterns_errors + build_errors # Mark platform specific messages
end @errors += (@platform_errors[platform] - @errors).map {|m| "[#{platform}] #{m}"}
@warnings += (@platform_warnings[platform] - @warnings).map {|m| "[#{platform}] #{m}"}
@notes += (@platform_notes[platform] - @notes).map {|m| "[#{platform}] #{m}"}
end
def warnings valid?
@warnings ||= podspec_warnings + deprecation_warnings
end end
def notes def valid?
@notes ||= build_warnings lenient ? errors.empty? : ( errors.empty? && warnings.empty? )
end end
# Performs platform specific analysis. # Performs platform specific analysis.
# It requires to download the source at each iteration # It requires to download the source at each iteration
# #
def peform_multiplatform_analysis def peform_extensive_analysis
platform_names.each do |platform_name| set_up_lint_environment
set_up_lint_environment install_pod
puts "\n\n#{spec} - Analyzing on #{Platform.new platform_name} platform.".green.reversed if config.verbose? puts "Building with xcodebuild.\n".yellow if config.verbose?
install_pod(platform_name) # treat xcodebuild warnings as notes because the spec maintainer might not be the author of the library
puts "Building with xcodebuild.\n".yellow if config.verbose? xcodebuild_output.each { |msg| ( msg.include?('error') ? @platform_errors[@platform] : @platform_notes[@platform] ) << msg }
xcodebuild_output.concat(xcodebuild_output_for_platfrom(platform_name)) @platform_errors[@platform] += file_patterns_errors
file_patterns_errors.concat(file_patterns_errors_for_platfrom(platform_name)) @platform_warnings[@platform] += file_patterns_warnings
tear_down_lint_environment tear_down_lint_environment
end end
end
def install_pod
def platform_names podfile = podfile_from_spec
spec.platform.name ? [spec.platform.name] : [:ios, :osx]
end
def install_pod(platform_name)
podfile = podfile_from_spec(platform_name)
config.verbose config.verbose
Installer.new(podfile).install! installer = Installer.new(podfile)
installer.install!
@pod = installer.pods.find { |pod| pod.top_specification == @spec }
config.silent config.silent
end end
def podfile_from_spec(platform_name) def podfile_from_spec
name = spec.name name = spec.name
podspec = file.realpath.to_s podspec = file.realpath.to_s
platform_sym = @platform.to_sym
podfile = Pod::Podfile.new do podfile = Pod::Podfile.new do
platform platform_name platform(platform_sym)
dependency name, :podspec => podspec dependency name, :podspec => podspec
end end
end end
...@@ -276,16 +265,18 @@ module Pod ...@@ -276,16 +265,18 @@ module Pod
# @return [Array<String>] List of the fatal defects detected in a podspec # @return [Array<String>] List of the fatal defects detected in a podspec
def podspec_errors def podspec_errors
messages = [] messages = []
messages << "Missing name" unless spec.name messages << "The name of the spec should match the name of the file" unless names_match?
messages << "Missing version" unless spec.version messages << "Unrecognized platfrom" unless platform_valid?
messages << "Missing summary" unless spec.summary messages << "Missing name" unless spec.name
messages << "Missing homepage" unless spec.homepage messages << "Missing version" unless spec.version
messages << "Missing author(s)" unless spec.authors messages << "Missing summary" unless spec.summary
messages << "Missing source or part_of" unless spec.source || spec.part_of messages << "Missing homepage" unless spec.homepage
messages << "Missing source_files" if spec.source_files.empty? && spec.subspecs.empty? messages << "Missing author(s)" unless spec.authors
messages << "Missing source" unless spec.source
messages << "The name of the spec should match the name of the file" unless names_match?
messages << "Unrecognized platfrom (no value, :ios, :osx)" unless [nil, :ios, :osx].include?(spec.platform.name) # attributes with multiplatform values
return messages unless platform_valid?
messages << "Missing source_files" if spec.source_files.empty? && spec.subspecs.empty? && spec.resources.empty?
messages += paths_starting_with_a_slash_errors messages += paths_starting_with_a_slash_errors
messages messages
end end
...@@ -296,6 +287,10 @@ module Pod ...@@ -296,6 +287,10 @@ module Pod
file.basename.to_s == root_name + '.podspec' file.basename.to_s == root_name + '.podspec'
end end
def platform_valid?
!spec.platform || [:ios, :osx].include?(spec.platform.name)
end
def paths_starting_with_a_slash_errors def paths_starting_with_a_slash_errors
messages = [] messages = []
%w[source_files resources clean_paths].each do |accessor| %w[source_files resources clean_paths].each do |accessor|
...@@ -322,16 +317,15 @@ module Pod ...@@ -322,16 +317,15 @@ module Pod
source = @spec.source || {} source = @spec.source || {}
text = @file.read text = @file.read
messages = [] messages = []
messages << "Missing license[:type]" unless license[:type] messages << "Missing license type" unless license[:type]
messages << "Missing license[:file] or [:text]" unless license[:file] || license[:text] messages << "The summary is not meaningful" if spec.summary =~ /A short description of/
messages << "The summary is not meaningful" if spec.summary =~ /A short description of/ messages << "The description is not meaningful" if spec.description && spec.description =~ /An optional longer description of/
messages << "The description is not meaningful" if spec.description && spec.description =~ /An optional longer description of/ messages << "The summary should end with a dot" if @spec.summary !~ /.*\./
messages << "The summary should end with a dot" if @spec.summary !~ /.*\./ messages << "The description should end with a dot" if @spec.description !~ /.*\./ && @spec.description != @spec.summary
messages << "The description should end with a dot" if @spec.description !~ /.*\./ && @spec.description != @spec.summary messages << "Git sources should specify either a tag or a commit" if source[:git] && !source[:commit] && !source[:tag]
messages << "Git sources should specify either a tag or a commit" if source[:git] && !source[:commit] && !source[:tag] messages << "Github repositories should end in `.git'" if github_source? && source[:git] !~ /.*\.git/
messages << "Github repositories should end in `.git'" if github_source? && source[:git] !~ /.*\.git/ messages << "Github repositories should use `https' link" if github_source? && source[:git] !~ /https:\/\/github.com/
messages << "Github repositories should use `https' link" if github_source? && source[:git] !~ /https:\/\/github.com/ messages << "Comments must be deleted" if text =~ /^\w*#\n\w*#/ # allow a single line comment as it is generally used in subspecs
messages << "Comments must be deleted" if text =~ /^\w*#\n\w*#/ # allow a single line comment as it is generally used in subspecs
messages messages
end end
...@@ -343,36 +337,26 @@ module Pod ...@@ -343,36 +337,26 @@ module Pod
# to features that are or will be deprecated # to features that are or will be deprecated
# #
# @return [Array<String>] # @return [Array<String>]
#
def deprecation_warnings def deprecation_warnings
text = @file.read text = @file.read
deprecations = [] deprecations = []
deprecations << "`config.ios?' and `config.osx?' are deprecated and will be removed in version 0.7" if text. =~ /config\..?os.?/ deprecations << "`config.ios?' and `config.osx?' are deprecated" if text. =~ /config\..?os.?/
deprecations << "The `post_install' hook is reserved for edge cases" if text. =~ /post_install/ deprecations << "clean_paths are deprecated and ignored (use preserve_paths)" if text. =~ /clean_paths/
deprecations << "The `post_install' hook is reserved for edge cases" if text. =~ /post_install/
deprecations deprecations
end end
def build_errors
@build_errors ||= xcodebuild_output.select {|msg| msg.include?('error')}
end
def build_warnings
@build_warnings ||= xcodebuild_output - build_errors
end
def xcodebuild_output
@xcodebuild_output ||= []
end
# It creates a podfile in memory and builds a library containing # It creates a podfile in memory and builds a library containing
# the pod for all available platfroms with xcodebuild. # the pod for all available platfroms with xcodebuild.
# #
# It returns a array of strings # @return [Array<String>]
# #
def xcodebuild_output_for_platfrom(platform_name) def xcodebuild_output
return [] if `which xcodebuild`.strip.empty? return [] if `which xcodebuild`.strip.empty?
messages = [] messages = []
output = Dir.chdir(config.project_pods_root) { `xcodebuild 2>&1` } output = Dir.chdir(config.project_pods_root) { `xcodebuild 2>&1` }
clean_output = process_xcode_build_output(output).map {|l| "#{platform_name}: #{l}"} clean_output = process_xcode_build_output(output)
messages += clean_output messages += clean_output
puts(output) if config.verbose? puts(output) if config.verbose?
messages messages
...@@ -381,48 +365,36 @@ module Pod ...@@ -381,48 +365,36 @@ module Pod
def process_xcode_build_output(output) def process_xcode_build_output(output)
output_by_line = output.split("\n") output_by_line = output.split("\n")
selected_lines = output_by_line.select do |l| selected_lines = output_by_line.select do |l|
l.include?('error') && (l !~ /errors? generated\./) \ l.include?('error:') && (l !~ /errors? generated\./) \
|| l.include?('warning') && (l !~ /warnings? generated\./)\ || l.include?('warning:') && (l !~ /warnings? generated\./)\
|| l.include?('note') || l.include?('note:')
end end
selected_lines.map do |l| selected_lines.map do |l|
new = l.gsub(/\/tmp\/CocoaPods\/Lint\/Pods\//,'') # Remove the unnecessary tmp path new = l.gsub(/\/tmp\/CocoaPods\/Lint\/Pods\//,'') # Remove the unnecessary tmp path
new.gsub!(/^ */,' ') # Remove indentation new.gsub!(/^ */,' ') # Remove indentation
"XCODEBUILD > " << new # Mark "XCODEBUILD > " << new # Mark
end end
end end
def file_patterns_errors
@file_patterns_errors ||= []
end
# It checks that every file pattern specified in a spec yields # It checks that every file pattern specified in a spec yields
# at least one file. It requires the pods to be alredy present # at least one file. It requires the pods to be alredy present
# in the current working directory under Pods/spec.name # in the current working directory under Pods/spec.name.
# #
# It returns a array of messages # @return [Array<String>]
# #
def file_patterns_errors_for_platfrom(platform_name) def file_patterns_errors
Dir.chdir(config.project_pods_root + spec.name ) do messages = []
messages = [] messages << "The sources did not match any file" if !@spec.source_files.empty? && @pod.source_files.empty?
messages += check_spec_files_exists(:source_files, platform_name, '*.{h,m,mm,c,cpp}') messages << "The resources did not match any file" if !@spec.resources.empty? && @pod.resources.empty?
messages += check_spec_files_exists(:resources, platform_name) messages << "The preserve_paths did not match any file" if !@spec.preserve_paths.empty? && @pod.preserve_paths.empty?
messages << "#{platform_name}: license[:file] = '#{spec.license[:file]}' -> did not match any file" if spec.license[:file] && pod_dir.glob(spec.license[:file]).empty? messages << "The exclude_header_search_paths did not match any file" if !@spec.exclude_header_search_paths.empty? && @pod.headers_excluded_from_search_paths.empty?
messages.compact messages
end
end end
def check_spec_files_exists(accessor, platform_name, options = {}) def file_patterns_warnings
result = [] messages = []
patterns = spec.send(accessor)[platform_name] messages << "Unable to find a license file" unless @pod.license_file
patterns.each do |original_pattern| messages
pattern = pod_dir + original_pattern
if pattern.directory? && options[:glob]
pattern += options[:glob]
end
result << "#{platform_name}: [#{accessor} = '#{original_pattern}'] -> did not match any file" if pattern.glob.empty?
end
result
end end
end end
......
...@@ -12,20 +12,20 @@ module Pod ...@@ -12,20 +12,20 @@ module Pod
attr_accessor :repos_dir, :project_root, :project_pods_root attr_accessor :repos_dir, :project_root, :project_pods_root
attr_accessor :clean, :verbose, :silent attr_accessor :clean, :verbose, :silent
attr_accessor :generate_docs, :doc_install, :force_doc attr_accessor :generate_docs, :doc_install
attr_accessor :integrate_targets attr_accessor :integrate_targets
attr_accessor :git_cache_size
alias_method :clean?, :clean alias_method :clean?, :clean
alias_method :verbose?, :verbose alias_method :verbose?, :verbose
alias_method :silent?, :silent alias_method :silent?, :silent
alias_method :generate_docs?, :generate_docs alias_method :generate_docs?, :generate_docs
alias_method :doc_install?, :doc_install alias_method :doc_install?, :doc_install
alias_method :force_doc?, :force_doc
alias_method :integrate_targets?, :integrate_targets alias_method :integrate_targets?, :integrate_targets
def initialize def initialize
@repos_dir = Pathname.new(File.expand_path("~/.cocoapods")) @repos_dir = Pathname.new(File.expand_path("~/.cocoapods"))
@verbose = @silent = @force_doc = false @verbose = @silent = false
@clean = @generate_docs = @doc_install = @integrate_targets = true @clean = @generate_docs = @doc_install = @integrate_targets = true
end end
......
...@@ -5,8 +5,6 @@ require 'open-uri' ...@@ -5,8 +5,6 @@ require 'open-uri'
module Pod module Pod
class Dependency < Gem::Dependency class Dependency < Gem::Dependency
attr_accessor :only_part_of_other_pod
alias_method :only_part_of_other_pod?, :only_part_of_other_pod
attr_reader :external_source attr_reader :external_source
attr_accessor :specification attr_accessor :specification
...@@ -19,7 +17,7 @@ module Pod ...@@ -19,7 +17,7 @@ module Pod
elsif !name_and_version_requirements.empty? && block.nil? elsif !name_and_version_requirements.empty? && block.nil?
if name_and_version_requirements.last.is_a?(Hash) if name_and_version_requirements.last.is_a?(Hash)
@external_source = ExternalSources.from_params(name_and_version_requirements[0], name_and_version_requirements.pop) @external_source = ExternalSources.from_params(name_and_version_requirements[0].split('/').first, name_and_version_requirements.pop)
end end
super(*name_and_version_requirements) super(*name_and_version_requirements)
...@@ -27,23 +25,20 @@ module Pod ...@@ -27,23 +25,20 @@ module Pod
raise Informative, "A dependency needs either a name and version requirements, " \ raise Informative, "A dependency needs either a name and version requirements, " \
"a source hash, or a block which defines a podspec." "a source hash, or a block which defines a podspec."
end end
@only_part_of_other_pod = false
end end
def ==(other) def ==(other)
super && super && (@specification ? @specification == other.specification : @external_source == other.external_source)
@only_part_of_other_pod == other.only_part_of_other_pod &&
(@specification ? @specification == other.specification : @external_source == other.external_source)
end end
def subspec_dependency? def subspec_dependency?
@name.include?('/') @name.include?('/')
end end
def inline? def inline?
@inline_podspec @inline_podspec
end end
def external? def external?
!@external_source.nil? !@external_source.nil?
end end
...@@ -75,7 +70,7 @@ module Pod ...@@ -75,7 +70,7 @@ module Pod
end end
version.empty? ? @name : "#{@name} (#{version})" version.empty? ? @name : "#{@name} (#{version})"
end end
def specification_from_sandbox(sandbox, platform) def specification_from_sandbox(sandbox, platform)
@external_source.specification_from_sandbox(sandbox, platform) @external_source.specification_from_sandbox(sandbox, platform)
end end
...@@ -126,42 +121,41 @@ module Pod ...@@ -126,42 +121,41 @@ module Pod
raise Informative, "Unknown external source parameters for #{name}: #{params}" raise Informative, "Unknown external source parameters for #{name}: #{params}"
end end
end end
class AbstractExternalSource class AbstractExternalSource
include Config::Mixin include Config::Mixin
attr_reader :name, :params attr_reader :name, :params
def initialize(name, params) def initialize(name, params)
@name, @params = name, params @name, @params = name, params
end end
def specification_from_sandbox(sandbox, platform) def specification_from_sandbox(sandbox, platform)
if local_pod = sandbox.installed_pod_named(name, platform) if local_pod = sandbox.installed_pod_named(name, platform)
local_pod.specification local_pod.top_specification
else else
copy_external_source_into_sandbox(sandbox) copy_external_source_into_sandbox(sandbox)
local_pod = sandbox.installed_pod_named(name, platform) local_pod = sandbox.installed_pod_named(name, platform)
local_pod.clean if config.clean? local_pod.clean if config.clean?
local_pod.specification local_pod.top_specification
end end
end end
def ==(other_source) def ==(other_source)
return if other_source.nil? return if other_source.nil?
name == other_source.name && params == other_source.params name == other_source.name && params == other_source.params
end end
end end
class GitSource < AbstractExternalSource class GitSource < AbstractExternalSource
def copy_external_source_into_sandbox(sandbox) def copy_external_source_into_sandbox(sandbox)
puts " * Pre-downloading: '#{name}'" unless config.silent? puts " * Pre-downloading: '#{name}'" unless config.silent?
Downloader.for_target(sandbox.root + name, @params).tap do |downloader| Downloader.for_target(sandbox.root + name, @params).tap do |downloader|
downloader.download downloader.download
downloader.clean if config.clean?
end end
end end
def description def description
"from `#{@params[:git]}'".tap do |description| "from `#{@params[:git]}'".tap do |description|
description << ", commit `#{@params[:commit]}'" if @params[:commit] description << ", commit `#{@params[:commit]}'" if @params[:commit]
...@@ -180,7 +174,7 @@ module Pod ...@@ -180,7 +174,7 @@ module Pod
output_path.open('w') { |f| f << io.read } output_path.open('w') { |f| f << io.read }
end end
end end
def description def description
"from `#{@params[:podspec]}'" "from `#{@params[:podspec]}'"
end end
......
...@@ -11,8 +11,7 @@ module Pod ...@@ -11,8 +11,7 @@ module Pod
extend Executable extend Executable
def self.for_pod(pod) def self.for_pod(pod)
spec = pod.specification spec = pod.top_specification
spec = spec.part_of_specification if spec.part_of_other_pod?
for_target(pod.root, spec.source.dup) for_target(pod.root, spec.source.dup)
end end
...@@ -23,12 +22,8 @@ module Pod ...@@ -23,12 +22,8 @@ module Pod
@target_path.mkpath @target_path.mkpath
end end
def clean
# implement in sub-classes
end
private private
def self.for_target(target_path, options) def self.for_target(target_path, options)
options = options.dup options = options.dup
if url = options.delete(:git) if url = options.delete(:git)
......
require 'open-uri' require 'open-uri'
require 'tempfile' require 'tempfile'
require 'zlib' require 'zlib'
require 'digest/sha1'
module Pod module Pod
class Downloader class Downloader
class Git < Downloader class Git < Downloader
include Config::Mixin
executable :git executable :git
MAX_CACHE_SIZE = 500
def download def download
create_cache unless cache_exist?
puts '-> Cloning git repo' if config.verbose?
if options[:tag] if options[:tag]
download_tag download_tag
elsif options[:commit] elsif options[:commit]
...@@ -15,16 +21,84 @@ module Pod ...@@ -15,16 +21,84 @@ module Pod
else else
download_head download_head
end end
removed_cached_repos_if_needed
end
def create_cache
puts "-> Creating cache git repo (#{cache_path})" if config.verbose?
cache_path.rmtree if cache_path.exist?
cache_path.mkpath
git "clone '#{url}' #{cache_path}"
end
def removed_cached_repos_if_needed
return unless caches_dir.exist?
Dir.chdir(caches_dir) do
repos = Pathname.new(caches_dir).children.select { |c| c.directory? }.sort_by(&:ctime)
while caches_size >= MAX_CACHE_SIZE && !repos.empty?
dir = repos.shift
puts '->'.yellow << " Removing git cache for `#{origin_url(dir)}'" if config.verbose?
dir.rmtree
end
end
end
def cache_path
@cache_path ||= caches_dir + "#{Digest::SHA1.hexdigest(url.to_s)}"
end
def cache_exist?
cache_path.exist? && origin_url(cache_path).to_s == url.to_s
end
def origin_url(dir)
Dir.chdir(dir) { `git config remote.origin.url`.chomp }
end
def caches_dir
Pathname.new(File.expand_path("~/Library/Caches/CocoaPods/Git"))
end
def clone_url
cache_path
end
def caches_size
# expressed in Mb
`du -cm`.split("\n").last.to_i
end
def update_cache
puts "-> Updating cache git repo (#{cache_path})" if config.verbose?
Dir.chdir(cache_path) do
git "reset --hard HEAD"
git "clean -d -x -f"
git "pull"
end
end
def ref_exists?(ref)
Dir.chdir(cache_path) { git "rev-list --max-count=1 #{ref}" }
$? == 0
end
def ensure_ref_exists(ref)
return if ref_exists?(ref)
# Skip pull if not needed
update_cache
raise Informative, "[!] Cache unable to find git reference `#{ref}' for `#{url}'.".red unless ref_exists?(ref)
end end
def download_head def download_head
git "clone '#{url}' '#{target_path}'" update_cache
git "clone '#{clone_url}' '#{target_path}'"
end end
def download_tag def download_tag
ensure_ref_exists(options[:tag])
Dir.chdir(target_path) do Dir.chdir(target_path) do
git "init" git "init"
git "remote add origin '#{url}'" git "remote add origin '#{clone_url}'"
git "fetch origin tags/#{options[:tag]}" git "fetch origin tags/#{options[:tag]}"
git "reset --hard FETCH_HEAD" git "reset --hard FETCH_HEAD"
git "checkout -b activated-pod-commit" git "checkout -b activated-pod-commit"
...@@ -32,16 +106,12 @@ module Pod ...@@ -32,16 +106,12 @@ module Pod
end end
def download_commit def download_commit
git "clone '#{url}' '#{target_path}'" ensure_ref_exists(options[:commit])
git "clone '#{clone_url}' '#{target_path}'"
Dir.chdir(target_path) do Dir.chdir(target_path) do
git "checkout -b activated-pod-commit #{options[:commit]}" git "checkout -b activated-pod-commit #{options[:commit]}"
end end
end end
def clean
(target_path + '.git').rmtree
end
end end
class GitHub < Git class GitHub < Git
...@@ -50,28 +120,18 @@ module Pod ...@@ -50,28 +120,18 @@ module Pod
end end
def download_tag def download_tag
super unless download_only?
download_only? ? download_and_extract_tarball(options[:tag]) : super download_only? ? download_and_extract_tarball(options[:tag]) : super
end end
def download_commit def download_commit
super unless download_only?
download_only? ? download_and_extract_tarball(options[:commit]) : super download_only? ? download_and_extract_tarball(options[:commit]) : super
end end
def clean
if download_only?
FileUtils.rm_f(tmp_path)
else
super
end
end
def tarball_url_for(id) def tarball_url_for(id)
original_url, username, reponame = *(url.match(/[:\/]([\w\-]+)\/([\w\-]+)\.git/).to_a) original_url, username, reponame = *(url.match(/[:\/]([\w\-]+)\/([\w\-]+)\.git/).to_a)
"https://github.com/#{username}/#{reponame}/tarball/#{id}" "https://github.com/#{username}/#{reponame}/tarball/#{id}"
end end
def tmp_path def tmp_path
target_path + "tarball.tar.gz" target_path + "tarball.tar.gz"
end end
......
...@@ -11,7 +11,7 @@ module Pod ...@@ -11,7 +11,7 @@ module Pod
executable :curl executable :curl
executable :unzip executable :unzip
executable :tar executable :tar
attr_accessor :filename, :download_path attr_accessor :filename, :download_path
def download def download
@filename = filename_with_type type @filename = filename_with_type type
...@@ -25,10 +25,6 @@ module Pod ...@@ -25,10 +25,6 @@ module Pod
options[:type] || type_with_url(url) options[:type] || type_with_url(url)
end end
def clean
FileUtils.rm @download_path
end
private private
def type_with_url(url) def type_with_url(url)
if url =~ /.zip$/ if url =~ /.zip$/
...@@ -41,7 +37,7 @@ module Pod ...@@ -41,7 +37,7 @@ module Pod
nil nil
end end
end end
def filename_with_type(type=:zip) def filename_with_type(type=:zip)
case type case type
when :zip when :zip
...@@ -54,7 +50,7 @@ module Pod ...@@ -54,7 +50,7 @@ module Pod
raise UnsupportedFileTypeError.new "Unsupported file type: #{type}" raise UnsupportedFileTypeError.new "Unsupported file type: #{type}"
end end
end end
def download_file(full_filename) def download_file(full_filename)
curl "-L -o '#{full_filename}' '#{url}'" curl "-L -o '#{full_filename}' '#{url}'"
end end
......
...@@ -18,10 +18,6 @@ module Pod ...@@ -18,10 +18,6 @@ module Pod
def download_revision def download_revision
hg "clone '#{url}' --rev '#{options[:revision]}' '#{target_path}'" hg "clone '#{url}' --rev '#{options[:revision]}' '#{target_path}'"
end end
def clean
(target_path + '.hg').rmtree
end
end end
end end
end end
......
...@@ -18,10 +18,6 @@ module Pod ...@@ -18,10 +18,6 @@ module Pod
def download_revision def download_revision
svn "checkout '#{url}' -r '#{options[:revision]}' '#{target_path}'" svn "checkout '#{url}' -r '#{options[:revision]}' '#{target_path}'"
end end
def clean
target_path.glob('**/.svn').each(&:rmtree)
end
end end
end end
end end
...@@ -7,8 +7,14 @@ module Pod ...@@ -7,8 +7,14 @@ module Pod
raise Informative, "Unable to locate the executable `#{name}'" raise Informative, "Unable to locate the executable `#{name}'"
end end
if Config.instance.verbose? if Config.instance.verbose?
puts "-> #{bin} #{command}" print " $ #{name}...\r"
`#{bin} #{command} 1>&2` $stdout.flush
output = `#{bin} #{command} 2>&1`
puts " #{$?.exitstatus.zero? ? '-' : '!'.red} #{name} #{command}"
output = output.gsub(/ */,' ').gsub(/^ */,' ')
puts output unless output.strip.empty?
else else
`#{bin} #{command} 2> /dev/null` `#{bin} #{command} 2> /dev/null`
end end
......
...@@ -7,6 +7,10 @@ module Pod ...@@ -7,6 +7,10 @@ module Pod
install_resource() install_resource()
{ {
case $1 in case $1 in
*\.storyboard)
echo "ibtool --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename $1 .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
ibtool --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename $1 .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
;;
*\.xib) *\.xib)
echo "ibtool --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename $1 .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" echo "ibtool --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename $1 .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
ibtool --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename $1 .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" ibtool --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename $1 .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
......
...@@ -12,9 +12,9 @@ module Pod ...@@ -12,9 +12,9 @@ module Pod
def initialize(pod) def initialize(pod)
@pod = pod @pod = pod
@specification = pod.specification @specification = pod.top_specification
@target_path = pod.sandbox.root + 'Documentation' + pod.name @target_path = pod.sandbox.root + 'Documentation' + pod.name
@options = pod.specification.documentation || {} @options = @specification.documentation || {}
end end
def name def name
...@@ -42,13 +42,11 @@ module Pod ...@@ -42,13 +42,11 @@ module Pod
end end
def files def files
@pod.absolute_source_files.map(&:to_s) @pod.all_specs_public_header_files.map{ |f| f.relative_path_from(@pod.root).to_s }
end end
def index_file def index_file
@pod.chdir do @pod.readme_file.relative_path_from(@pod.root).to_s if @pod.readme_file
Dir.glob('README*', File::FNM_CASEFOLD).first
end
end end
def spec_appledoc_options def spec_appledoc_options
...@@ -66,11 +64,9 @@ module Pod ...@@ -66,11 +64,9 @@ module Pod
'--keep-undocumented-objects', '--keep-undocumented-objects',
'--keep-undocumented-members', '--keep-undocumented-members',
'--keep-intermediate-files', '--keep-intermediate-files',
'--exit-threshold', '2' '--exit-threshold', '2' # appledoc terminates with an exits status of 1 if a warning was logged
# appledoc exits with 1 if a warning was logged
] ]
index = index_file options += ['--index-desc', index_file] if index_file
options += ['--index-desc', index] if index
options += spec_appledoc_options options += spec_appledoc_options
end end
...@@ -82,6 +78,8 @@ module Pod ...@@ -82,6 +78,8 @@ module Pod
options = appledoc_options options = appledoc_options
options += ['--output', @target_path.to_s] options += ['--output', @target_path.to_s]
options += install ? ['--create-docset'] : ['--no-create-docset'] options += install ? ['--create-docset'] : ['--no-create-docset']
# TODO: passing the files explicitly clutters output and chokes on very long list (AWSiOSSDK Spec).
# It is possible to just pass the dir of the pod, however this would include other files like demo projects.
options += files options += files
@target_path.mkpath @target_path.mkpath
......
...@@ -25,7 +25,8 @@ module Pod ...@@ -25,7 +25,8 @@ module Pod
def project def project
return @project if @project return @project if @project
@project = Pod::Project.new @project = Pod::Project.new
activated_pods.each do |pod| @project.user_build_configurations = @podfile.user_build_configurations
pods.each do |pod|
# Add all source files to the project grouped by pod # Add all source files to the project grouped by pod
group = @project.add_pod_group(pod.name) group = @project.add_pod_group(pod.name)
pod.source_files.each do |path| pod.source_files.each do |path|
...@@ -44,32 +45,32 @@ module Pod ...@@ -44,32 +45,32 @@ module Pod
end end
def install_dependencies! def install_dependencies!
activated_pods.each do |pod| pods.each do |pod|
marker = config.verbose ? "\n-> ".green : '' unless config.silent?
marker = config.verbose ? "\n-> ".green : ''
unless should_install = !pod.exists? && !pod.specification.local? name = pod.top_specification.preferred_dependency ? "#{pod.top_specification.name}/#{pod.top_specification.preferred_dependency} (#{pod.top_specification.version})" : pod.to_s
puts marker + "Using #{pod}" unless config.silent? puts marker << ( pod.exists? ? "Using #{name}" : "Installing #{name}".green )
else end
puts marker + "Installing #{pod.specification}".green unless config.silent?
unless pod.exists?
downloader = Downloader.for_pod(pod) downloader = Downloader.for_pod(pod)
downloader.download downloader.download
# The docs need to be generated before cleaning because
if config.clean # the documentation is created for all the subspecs.
downloader.clean generate_docs(pod)
pod.clean pod.clean if config.clean
end
end end
end
end
if (should_install && config.generate_docs?) || config.force_doc? #TODO: move to generator ?
doc_generator = Generator::Documentation.new(pod) def generate_docs(pod)
if doc_generator.already_installed? doc_generator = Generator::Documentation.new(pod)
puts "Using Existing Documentation for #{pod.specification}".green if config.verbose? if ( config.generate_docs? && !doc_generator.already_installed? )
else puts "-> Installing documentation" if config.verbose?
puts "Installing Documentation for #{pod.specification}".green if config.verbose? doc_generator.generate(config.doc_install?)
doc_generator.generate(config.doc_install?) else
end puts "-> Using existing documentation" if config.verbose?
end
end end
end end
...@@ -82,24 +83,23 @@ module Pod ...@@ -82,24 +83,23 @@ module Pod
print_title "Installing dependencies" print_title "Installing dependencies"
install_dependencies! install_dependencies!
pods = activated_pods
print_title("Generating support files\n", false) print_title("Generating support files\n", false)
target_installers.each do |target_installer| target_installers.each do |target_installer|
pods_for_target = activated_pods_by_target[target_installer.target_definition] pods_for_target = pods_by_target[target_installer.target_definition]
target_installer.install!(pods_for_target, @sandbox) target_installer.install!(pods_for_target, @sandbox)
acknowledgements_path = target_installer.target_definition.acknowledgements_path acknowledgements_path = target_installer.target_definition.acknowledgements_path
Generator::Acknowledgements.new(target_installer.target_definition, Generator::Acknowledgements.new(target_installer.target_definition,
pods_for_target).save_as(acknowledgements_path) pods_for_target).save_as(acknowledgements_path)
end end
generate_lock_file!(pods) generate_lock_file!(specifications)
generate_dummy_source generate_dummy_source
puts "* Running post install hooks" if config.verbose? puts "- Running post install hooks" if config.verbose?
# Post install hooks run _before_ saving of project, so that they can alter it before saving. # Post install hooks run _before_ saving of project, so that they can alter it before saving.
run_post_install_hooks run_post_install_hooks
puts "* Writing Xcode project file to `#{@sandbox.project_path}'\n\n" if config.verbose? puts "- Writing Xcode project file to `#{@sandbox.project_path}'\n\n" if config.verbose?
project.save_as(@sandbox.project_path) project.save_as(@sandbox.project_path)
UserProjectIntegrator.new(@podfile).integrate! if config.integrate_targets? UserProjectIntegrator.new(@podfile).integrate! if config.integrate_targets?
...@@ -109,7 +109,7 @@ module Pod ...@@ -109,7 +109,7 @@ module Pod
# we loop over target installers instead of pods, because we yield the target installer # we loop over target installers instead of pods, because we yield the target installer
# to the spec post install hook. # to the spec post install hook.
target_installers.each do |target_installer| target_installers.each do |target_installer|
activated_specifications_for_target(target_installer.target_definition).each do |spec| specs_by_target[target_installer.target_definition].each do |spec|
spec.post_install(target_installer) spec.post_install(target_installer)
end end
end end
...@@ -117,28 +117,28 @@ module Pod ...@@ -117,28 +117,28 @@ module Pod
@podfile.post_install!(self) @podfile.post_install!(self)
end end
def generate_lock_file!(pods) def generate_lock_file!(specs)
lock_file.open('w') do |file| lock_file.open('w') do |file|
file.puts "PODS:" file.puts "PODS:"
# Get list of [name, dependencies] pairs. # Get list of [name, dependencies] pairs.
activated_pods = pods.map do |pod| pod_and_deps = specs.map do |spec|
[pod.specification.to_s, pod.dependencies.map(&:to_s).sort] [spec.to_s, spec.dependencies.map(&:to_s).sort]
end.uniq end.uniq
# Merge dependencies of ios and osx version of the same pod. # Merge dependencies of ios and osx version of the same pod.
tmp = {} tmp = {}
activated_pods.each do |name, deps| pod_and_deps.each do |name, deps|
if tmp[name] if tmp[name]
tmp[name].concat(deps).uniq! tmp[name].concat(deps).uniq!
else else
tmp[name] = deps tmp[name] = deps
end end
end end
activated_pods = tmp pod_and_deps = tmp
# Sort by name and print # Sort by name and print
activated_pods.sort_by(&:first).each do |name, deps| pod_and_deps.sort_by(&:first).each do |name, deps|
if deps.empty? if deps.empty?
file.puts " - #{name}" file.puts " - #{name}"
else else
...@@ -147,14 +147,6 @@ module Pod ...@@ -147,14 +147,6 @@ module Pod
end end
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
file.puts "DEPENDENCIES:" file.puts "DEPENDENCIES:"
@podfile.dependencies.map(&:to_s).sort.each do |dep| @podfile.dependencies.map(&:to_s).sort.each do |dep|
...@@ -181,49 +173,36 @@ module Pod ...@@ -181,49 +173,36 @@ module Pod
end end
# @return [Array<Specification>] All dependencies that have been resolved. # @return [Array<Specification>] All dependencies that have been resolved.
def dependency_specifications def specifications
specs_by_target.values.flatten specs_by_target.values.flatten
end end
# @return [Array<LocalPod>] A list of LocalPod instances for each # @return [Array<LocalPod>] A list of LocalPod instances for each
# dependency that is not a download-only one. # dependency that is not a download-only one.
def activated_pods def pods
activated_pods_by_target.values.flatten pods_by_target.values.flatten
end end
def activated_pods_by_target def pods_by_target
@pods_by_spec = {}
result = {} result = {}
specs_by_target.each do |target_definition, specs| specs_by_target.each do |target_definition, specs|
@pods_by_spec[target_definition.platform] = {}
result[target_definition] = specs.map do |spec| result[target_definition] = specs.map do |spec|
LocalPod.new(spec, @sandbox, target_definition.platform) if activated_spec?(spec) pod = pod_for_spec(spec, target_definition.platform)
end.compact pod.add_specification(spec)
pod
end.uniq.compact
end end
result result
end end
# @return [Array<Specification>] A list of specifications for each def pod_for_spec(spec, platform)
# dependency that is not a download-only @pods_by_spec[platform][spec.top_level_parent.name] ||= LocalPod.new(spec, @sandbox, platform)
# one.
def activated_specifications
dependency_specifications.select { |spec| activated_spec?(spec) }
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
end end
private 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) def print_title(title, only_verbose = true)
if config.verbose? if config.verbose?
puts "\n" + title.yellow puts "\n" + title.yellow
......
...@@ -41,7 +41,7 @@ module Pod ...@@ -41,7 +41,7 @@ module Pod
header.puts "#import #{@target_definition.platform == :ios ? '<UIKit/UIKit.h>' : '<Cocoa/Cocoa.h>'}" header.puts "#import #{@target_definition.platform == :ios ? '<UIKit/UIKit.h>' : '<Cocoa/Cocoa.h>'}"
header.puts "#endif" header.puts "#endif"
pods.each do |pod| pods.each do |pod|
if prefix_header_contents = pod.specification.prefix_header_contents if prefix_header_contents = pod.top_specification.prefix_header_contents
header.puts header.puts
header.puts prefix_header_contents header.puts prefix_header_contents
elsif prefix_header = pod.prefix_header_file elsif prefix_header = pod.prefix_header_file
...@@ -63,19 +63,18 @@ module Pod ...@@ -63,19 +63,18 @@ module Pod
@target = @project.add_pod_target(@target_definition.label, @target_definition.platform) @target = @project.add_pod_target(@target_definition.label, @target_definition.platform)
pods.each do |pod| pods.each do |pod|
# TODO add methods like xcconfig to LocalPod as well? (which returns the correct platform) xcconfig.merge!(pod.xcconfig)
xcconfig.merge!(pod.specification.xcconfig[@target_definition.platform.name])
pod.add_to_target(@target) pod.add_to_target(@target)
# TODO: this doesn't need to be done here, it has nothing to do with the target # TODO: this doesn't need to be done here, it has nothing to do with the target
pod.link_headers pod.link_headers
end end
xcconfig.merge!('HEADER_SEARCH_PATHS' => quoted(sandbox.header_search_paths).join(" ")) xcconfig.merge!('HEADER_SEARCH_PATHS' => quoted(sandbox.header_search_paths).join(" "))
support_files_group = @project.group("Targets Support Files").create_group(@target_definition.label) support_files_group = @project.group("Targets Support Files").create_group(@target_definition.label)
support_files_group.create_files(target_support_files) support_files_group.create_files(target_support_files)
xcconfig_file = support_files_group.files.where(:path => @target_definition.xcconfig_name) xcconfig_file = support_files_group.files.where(:path => @target_definition.xcconfig_name)
configure_build_configurations(xcconfig_file) configure_build_configurations(xcconfig_file)
create_files(pods, sandbox) create_files(pods, sandbox)
...@@ -93,24 +92,24 @@ module Pod ...@@ -93,24 +92,24 @@ module Pod
def create_files(pods, sandbox) def create_files(pods, sandbox)
if @podfile.generate_bridge_support? if @podfile.generate_bridge_support?
bridge_support_metadata_path = sandbox.root + @target_definition.bridge_support_name bridge_support_metadata_path = sandbox.root + @target_definition.bridge_support_name
puts "* Generating BridgeSupport metadata file at `#{bridge_support_metadata_path}'" if config.verbose? 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) bridge_support_generator_for(pods, sandbox).save_as(bridge_support_metadata_path)
copy_resources_script_for(pods).resources << @target_definition.bridge_support_name copy_resources_script_for(pods).resources << @target_definition.bridge_support_name
end end
puts "* Generating xcconfig file at `#{sandbox.root + @target_definition.xcconfig_name}'" if config.verbose? puts "- Generating xcconfig file at `#{sandbox.root + @target_definition.xcconfig_name}'" if config.verbose?
xcconfig.save_as(sandbox.root + @target_definition.xcconfig_name) xcconfig.save_as(sandbox.root + @target_definition.xcconfig_name)
puts "* Generating prefix header at `#{sandbox.root + @target_definition.prefix_header_name}'" if config.verbose? 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, pods) save_prefix_header_as(sandbox.root + @target_definition.prefix_header_name, pods)
puts "* Generating copy resources script at `#{sandbox.root + @target_definition.copy_resources_script_name}'" if config.verbose? 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) copy_resources_script_for(pods).save_as(sandbox.root + @target_definition.copy_resources_script_name)
end end
private private
def quoted(strings) def quoted(strings)
strings.map { |s| "\"#{s}\"" } strings.map { |s| "\"#{s}\"" }
end end
def default_ld_flags def default_ld_flags
flags = %w{-ObjC} flags = %w{-ObjC}
flags << '-fobjc-arc' if @podfile.set_arc_compatibility_flag? && self.requires_arc flags << '-fobjc-arc' if @podfile.set_arc_compatibility_flag? && self.requires_arc
......
...@@ -34,13 +34,17 @@ module Pod ...@@ -34,13 +34,17 @@ module Pod
end.compact end.compact
end end
def user_projects def user_project_paths
@podfile.target_definitions.values.map(&:xcodeproj) @podfile.target_definitions.values.map do |td|
next if td.empty?
td.user_project.path #|| raise(Informative, "Could not resolve the Xcode project in which the " \
# "`#{td.name}' target should be integrated.")
end.compact
end end
def create_workspace! def create_workspace!
workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path) workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
[pods_project_path, *user_projects].each do |project_path| [pods_project_path, *user_project_paths].each do |project_path|
project_path = project_path.relative_path_from(config.project_root).to_s project_path = project_path.relative_path_from(config.project_root).to_s
workspace << project_path unless workspace.include?(project_path) workspace << project_path unless workspace.include?(project_path)
end end
...@@ -74,11 +78,11 @@ module Pod ...@@ -74,11 +78,11 @@ module Pod
add_xcconfig_base_configuration add_xcconfig_base_configuration
add_pods_library add_pods_library
add_copy_resources_script_phase add_copy_resources_script_phase
user_project.save_as(@target_definition.xcodeproj) user_project.save_as(@target_definition.user_project.path)
end end
def user_project_path def user_project_path
if path = @target_definition.xcodeproj if path = @target_definition.user_project.path
unless path.exist? unless path.exist?
raise Informative, "The Xcode project `#{path}' does not exist." raise Informative, "The Xcode project `#{path}' does not exist."
end end
......
module Pod module Pod
class LocalPod class LocalPod
attr_reader :specification attr_reader :top_specification, :specifications
attr_reader :sandbox attr_reader :sandbox
attr_reader :platform
def initialize(specification, sandbox, platform) def initialize(specification, sandbox, platform)
@specification, @sandbox, @platform = specification, sandbox, platform @top_specification, @sandbox = specification.top_level_parent, sandbox
@top_specification.activate_platform(platform)
@specifications = [] << specification
end end
def self.from_podspec(podspec, sandbox, platform) def self.from_podspec(podspec, sandbox, platform)
new(Specification.from_file(podspec), sandbox, platform) new(Specification.from_file(podspec), sandbox, platform)
end end
# Method to add the specifications sharing the same top level
# parent. With this information the local pod can determine the
# paths to clean and avoid duplication in file processing.
# Adding specifications is idempotent.
def add_specification(spec)
raise Informative, "[Local Pod] Attempt to add a specification from another pod" unless spec.top_level_parent == top_specification
spec.activate_platform(platform)
@specifications << spec unless @specifications.include?(spec)
end
def root def root
@sandbox.root + specification.name @sandbox.root + top_specification.name
end
def subspecs
specifications.reject{|s| s.parent.nil? }
end end
def to_s def to_s
if specification.local? result = top_specification.to_s
"#{specification} [LOCAL]" result << " [LOCAL]" if top_specification.local?
else result
specification.to_s
end
end end
def name def name
specification.name top_specification.name
end
def platform
top_specification.active_platform
end end
# Installation methods
def create def create
root.mkpath unless exists? root.mkpath unless exists?
end end
...@@ -45,30 +64,55 @@ module Pod ...@@ -45,30 +64,55 @@ module Pod
root.rmtree if exists? root.rmtree if exists?
end end
# It deletes all the files identified by clean_paths, then it removes
# all the empty folders or symlinks.
def clean def clean
clean_paths.each { |path| FileUtils.rm_rf(path) } clean_paths.each { |path| FileUtils.rm_rf(path) }
Dir.glob("#{root}/**/{*,.*}").
sort_by(&:length).reverse. # Clean the deepest paths first to determine if the containing folders are empty
reject { |d| d =~ /\/\.\.?$/ }. # Remove the `.` and `..` paths
select { |d| File.directory?(d) }. # Get only directories or symlinks to directories
each do |d|
FileUtils.rm_rf(d) if File.symlink?(d) || (Dir.entries(d) == %w[ . .. ]) # Remove the symlink and the empty dirs
end
end end
# File attributes
def prefix_header_file def prefix_header_file
if prefix_header = specification.prefix_header_file if prefix_header = top_specification.prefix_header_file
@sandbox.root + specification.name + prefix_header @sandbox.root + top_specification.name + prefix_header
end end
end end
def source_files def source_files(relative = true)
expanded_paths(specification.source_files, :glob => '*.{h,m,mm,c,cpp}', :relative_to_sandbox => true) chained_expanded_paths(:source_files, :glob => '*.{h,m,mm,c,cpp}', :relative_to_sandbox => relative)
end end
def absolute_source_files def resources(relative = true)
expanded_paths(specification.source_files, :glob => '*.{h,m,mm,c,cpp}') chained_expanded_paths(:resources, :relative_to_sandbox => relative)
end end
def clean_paths def clean_paths
expanded_paths(specification.clean_paths) expanded_paths('**/{*,.*}').reject { |p| p.directory? } - used_files
end
def used_files
source_files(false) + resources(false) + [ readme_file, license_file, prefix_header_file ] + preserve_paths
end
def readme_file
expanded_paths(%w[ README{*,.*} readme{*,.*} ]).first
end
def license_file
file = top_specification.license[:file] if top_specification.license
file || expanded_paths(%w[ LICENSE{*,.*} licence{*,.*} ]).first
end end
def resources # TODO: implement case insensitive search
expanded_paths(specification.resources, :relative_to_sandbox => true) def preserve_paths
chained_expanded_paths(:preserve_paths) + expanded_paths(%w[ *.podspec notice* NOTICE* CREDITS* ])
end end
def header_files def header_files
...@@ -85,6 +129,20 @@ module Pod ...@@ -85,6 +129,20 @@ module Pod
end end
end end
def xcconfig
specifications.map { |s| s.xcconfig }.reduce(:merge)
end
# Method used by documentation generator. It return the source files
# of all the specs.
def all_specs_public_header_files
#TODO: merge with #221
specs = top_specification.recursive_subspecs << top_specification
specs.map { |s| expanded_paths(s.source_files, :glob => '*.{h}') }.compact.flatten.select { |f| f.extname == '.h' }.uniq
end
# Integration methods
def link_headers def link_headers
copy_header_mappings.each do |namespaced_path, files| copy_header_mappings.each do |namespaced_path, files|
@sandbox.add_header_files(namespaced_path, files) @sandbox.add_header_files(namespaced_path, files)
...@@ -92,17 +150,17 @@ module Pod ...@@ -92,17 +150,17 @@ module Pod
end end
def add_to_target(target) def add_to_target(target)
implementation_files.each do |file| sources_files_by_specification.each do | spec, files |
target.add_source_file(file, nil, specification.compiler_flags[@platform.name].strip) files.each do |file|
# TODO: Xcodeproj::Project::Object::PBXNativeTarget#add_source_file is quite slow
# The issus appears to be related to the find call in line 107.
target.add_source_file(file, nil, spec.compiler_flags.strip)
end
end end
end end
def requires_arc? def requires_arc?
specification.requires_arc top_specification.requires_arc
end
def dependencies
specification.dependencies[@platform.name]
end end
private private
...@@ -117,17 +175,46 @@ module Pod ...@@ -117,17 +175,46 @@ module Pod
# TODO this is being overriden in the RestKit 0.9.4 spec, need to do # TODO this is being overriden in the RestKit 0.9.4 spec, need to do
# something with that, and this method also still exists in Specification. # something with that, and this method also still exists in Specification.
#
# This is not overriden anymore in specification refactor and the code
# Pod::Specification#copy_header_mapping can be moved here.
def copy_header_mappings def copy_header_mappings
header_files.inject({}) do |mappings, from| search_path_headers = header_files - headers_excluded_from_search_paths
search_path_headers.inject({}) do |mappings, from|
from_without_prefix = from.relative_path_from(relative_root) from_without_prefix = from.relative_path_from(relative_root)
to = specification.header_dir + specification.copy_header_mapping(from_without_prefix) to = top_specification.header_dir + top_specification.copy_header_mapping(from_without_prefix)
(mappings[to.dirname] ||= []) << from (mappings[to.dirname] ||= []) << from
mappings mappings
end end
end end
def expanded_paths(platforms_with_patterns, options = {}) # returns an hash where the source_files are groupped by specification.
patterns = platforms_with_patterns.is_a?(Hash) ? platforms_with_patterns[@platform.name] : platforms_with_patterns # If the same file is required by two specifications the one at the
# higher level in the inheritance chain wins.
def sources_files_by_specification
files_by_spec = {}
processed_files = []
specifications.sort_by { |s| s.name.length }.each do |spec|
files = []
expanded_paths(spec.source_files, :glob => '*.{h,m,mm,c,cpp}', :relative_to_sandbox => true).each do | file |
files << file unless processed_files.include?(file)
end
files_by_spec[spec] = files
processed_files += files
end
files_by_spec
end
def headers_excluded_from_search_paths
chained_expanded_paths(:exclude_header_search_paths, :relative_to_sandbox => true)
end
def chained_expanded_paths(accessor, options = {})
specifications.map { |s| expanded_paths(s.send(accessor), options) }.compact.flatten.uniq
end
def expanded_paths(patterns, options = {})
patterns = [ patterns ] if patterns.is_a? String
patterns.map do |pattern| patterns.map do |pattern|
pattern = root + pattern pattern = root + pattern
......
...@@ -10,7 +10,7 @@ module Pod ...@@ -10,7 +10,7 @@ module Pod
attr_reader :deployment_target attr_reader :deployment_target
def initialize(symbolic_name, deployment_target = nil) def initialize(symbolic_name = nil, deployment_target = nil)
@symbolic_name = symbolic_name @symbolic_name = symbolic_name
if deployment_target if deployment_target
version = deployment_target.is_a?(Hash) ? deployment_target[:deployment_target] : deployment_target # backwards compatibility from 0.6 version = deployment_target.is_a?(Hash) ? deployment_target[:deployment_target] : deployment_target # backwards compatibility from 0.6
...@@ -34,9 +34,11 @@ module Pod ...@@ -34,9 +34,11 @@ module Pod
end end
end end
def support?(other) def supports?(other)
return true if @symbolic_name.nil? || other.nil? return true if @symbolic_name.nil? || other.nil?
@symbolic_name == other.name && (deployment_target.nil? || other.deployment_target.nil? || deployment_target >= other.deployment_target) os_check = @symbolic_name == other.name
version_check = (deployment_target.nil? || other.deployment_target.nil? || deployment_target >= other.deployment_target)
os_check && version_check
end end
def to_s def to_s
......
module Pod module Pod
class Podfile class Podfile
class UserProject
include Config::Mixin
DEFAULT_BUILD_CONFIGURATIONS = { 'Debug' => :debug, 'Release' => :release }.freeze
def initialize(path = nil, build_configurations = {})
self.path = path if path
@build_configurations = build_configurations.merge(DEFAULT_BUILD_CONFIGURATIONS)
end
def path=(path)
path = path.to_s
@path = Pathname.new(File.extname(path) == '.xcodeproj' ? path : "#{path}.xcodeproj")
@path = config.project_root + @path unless @path.absolute?
@path
end
def path
if @path
@path
else
xcodeprojs = config.project_root.glob('*.xcodeproj')
if xcodeprojs.size == 1
@path = xcodeprojs.first
end
end
end
def project
Xcodeproj::Project.new(path) if path && path.exist?
end
def build_configurations
if project
project.build_configurations.map(&:name).inject({}) do |hash, name|
hash[name] = :release; hash
end.merge(@build_configurations)
else
@build_configurations
end
end
end
class TargetDefinition class TargetDefinition
include Config::Mixin include Config::Mixin
attr_reader :name, :target_dependencies attr_reader :name, :target_dependencies
attr_accessor :xcodeproj, :link_with, :platform, :parent, :exclusive attr_accessor :user_project, :link_with, :platform, :parent, :exclusive
def initialize(name, options = {}) def initialize(name, options = {})
@name, @target_dependencies = name, [] @name, @target_dependencies = name, []
...@@ -27,20 +70,8 @@ module Pod ...@@ -27,20 +70,8 @@ module Pod
end end
alias_method :exclusive?, :exclusive alias_method :exclusive?, :exclusive
def xcodeproj=(path) def user_project
path = path.to_s @user_project || @parent.user_project
@xcodeproj = config.project_root + (File.extname(path) == '.xcodeproj' ? path : "#{path}.xcodeproj")
end
def xcodeproj
if @xcodeproj
@xcodeproj
elsif @parent
@parent.xcodeproj
else
xcodeprojs = config.project_root.glob('*.xcodeproj')
@xcodeproj = xcodeprojs.first if xcodeprojs.size == 1
end
end end
def link_with=(targets) def link_with=(targets)
...@@ -48,16 +79,16 @@ module Pod ...@@ -48,16 +79,16 @@ module Pod
end end
def platform def platform
@platform || @parent.platform @platform || (@parent.platform if @parent)
end end
def label def label
if name == :default if name == :default
"Pods" "Pods"
elsif @parent elsif exclusive?
"#{@parent.label}-#{name}"
else
"Pods-#{name}" "Pods-#{name}"
else
"#{@parent.label}-#{name}"
end end
end end
...@@ -68,8 +99,13 @@ module Pod ...@@ -68,8 +99,13 @@ module Pod
# Returns a path, which is relative to the project_root, relative to the # Returns a path, which is relative to the project_root, relative to the
# `$(SRCROOT)` of the user's project. # `$(SRCROOT)` of the user's project.
def relative_to_srcroot(path) def relative_to_srcroot(path)
raise Informative, "[!] Unable to find an Xcode project to integrate".red unless xcodeproj || !config.integrate_targets if user_project.path.nil?
xcodeproj ? (config.project_root + path).relative_path_from(xcodeproj.dirname) : path # TODO this is not in the right place
raise Informative, "[!] Unable to find an Xcode project to integrate".red if config.integrate_targets
path
else
(config.project_root + path).relative_path_from(user_project.path.dirname)
end
end end
def relative_pods_root def relative_pods_root
...@@ -127,7 +163,9 @@ module Pod ...@@ -127,7 +163,9 @@ module Pod
include Config::Mixin include Config::Mixin
def initialize(&block) def initialize(&block)
@target_definitions = { :default => (@target_definition = TargetDefinition.new(:default, :exclusive => true)) } @target_definition = TargetDefinition.new(:default, :exclusive => true)
@target_definition.user_project = UserProject.new
@target_definitions = { :default => @target_definition }
instance_eval(&block) instance_eval(&block)
end end
...@@ -163,8 +201,8 @@ module Pod ...@@ -163,8 +201,8 @@ module Pod
elsif @workspace elsif @workspace
@workspace @workspace
else else
projects = @target_definitions.map { |_, td| td.xcodeproj }.uniq projects = @target_definitions.map { |_, td| td.user_project.path }.uniq
if projects.size == 1 && (xcodeproj = @target_definitions[:default].xcodeproj) if projects.size == 1 && (xcodeproj = @target_definitions[:default].user_project.path)
config.project_root + "#{xcodeproj.basename('.xcodeproj')}.xcworkspace" config.project_root + "#{xcodeproj.basename('.xcodeproj')}.xcworkspace"
end end
end end
...@@ -188,8 +226,8 @@ module Pod ...@@ -188,8 +226,8 @@ module Pod
# xcodeproj 'TestProject' # xcodeproj 'TestProject'
# end # end
# #
def xcodeproj(path) def xcodeproj(path, build_configurations = {})
@target_definition.xcodeproj = path @target_definition.user_project = UserProject.new(path, build_configurations)
end end
# Specifies the target(s) in the user’s project that this Pods library # Specifies the target(s) in the user’s project that this Pods library
...@@ -407,6 +445,11 @@ module Pod ...@@ -407,6 +445,11 @@ module Pod
@set_arc_compatibility_flag @set_arc_compatibility_flag
end end
def user_build_configurations
configs_array = @target_definitions.values.map { |td| td.user_project.build_configurations }
configs_array.inject({}) { |hash, config| hash.merge(config) }
end
def post_install!(installer) def post_install!(installer)
@post_install_callback.call(installer) if @post_install_callback @post_install_callback.call(installer) if @post_install_callback
end end
......
...@@ -15,6 +15,18 @@ module Pod ...@@ -15,6 +15,18 @@ module Pod
def initialize(*) def initialize(*)
super super
main_group << groups.new('name' => 'Pods') main_group << groups.new('name' => 'Pods')
@user_build_configurations = []
end
def user_build_configurations=(user_build_configurations)
@user_build_configurations = user_build_configurations
# The configurations at the top level only need to exist, they don't hold
# any build settings themselves, that's left to `add_pod_target`.
user_build_configurations.each do |name, _|
unless build_configurations.map(&:name).include?(name)
build_configurations.new('name' => name)
end
end
end end
# Shortcut access to the `Pods' PBXGroup. # Shortcut access to the `Pods' PBXGroup.
...@@ -41,6 +53,14 @@ module Pod ...@@ -41,6 +53,14 @@ module Pod
target.build_settings('Debug').merge!(settings) target.build_settings('Debug').merge!(settings)
target.build_settings('Release').merge!(settings) target.build_settings('Release').merge!(settings)
@user_build_configurations.each do |name, type|
unless target.build_configurations.map(&:name).include?(name)
config = target.build_configurations.new('name' => name)
# Copy the settings from either the Debug or the Release configuration.
config.build_settings = target.build_settings(type.to_s.capitalize).merge(settings)
end
end
target target
end end
end end
......
...@@ -22,26 +22,19 @@ module Pod ...@@ -22,26 +22,19 @@ module Pod
@podfile.target_definitions.values.each do |target_definition| @podfile.target_definitions.values.each do |target_definition|
puts "\nResolving dependencies for target `#{target_definition.name}' (#{target_definition.platform})".green if config.verbose? puts "\nResolving dependencies for target `#{target_definition.name}' (#{target_definition.platform})".green if config.verbose?
@loaded_specs = [] @loaded_specs = []
# TODO @podfile.platform will change to target_definition.platform find_dependency_specs(@podfile, target_definition.dependencies, target_definition)
find_dependency_sets(@podfile, target_definition.dependencies, target_definition)
targets_and_specs[target_definition] = @specs.values_at(*@loaded_specs).sort_by(&:name) targets_and_specs[target_definition] = @specs.values_at(*@loaded_specs).sort_by(&:name)
end end
# Specification doesn't need to know more about the context, so we assign @specs.values.sort_by(&:name)
# 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
targets_and_specs targets_and_specs
end end
private private
def find_cached_set(dependency, platform) 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 if dependency.specification
Specification::Set::External.new(dependency.specification) Specification::Set::External.new(dependency.specification)
elsif external_source = dependency.external_source elsif external_source = dependency.external_source
...@@ -49,14 +42,18 @@ module Pod ...@@ -49,14 +42,18 @@ module Pod
# that's being used behind the scenes, but passing it anyways for # that's being used behind the scenes, but passing it anyways for
# completeness sake. # completeness sake.
specification = external_source.specification_from_sandbox(@sandbox, platform) specification = external_source.specification_from_sandbox(@sandbox, platform)
Specification::Set::External.new(specification) set = Specification::Set::External.new(specification)
if dependency.subspec_dependency?
@cached_sets[dependency.top_level_spec_name] ||= set
end
set
else else
@cached_sources.search(dependency) @cached_sources.search(dependency)
end end
end end
end end
def find_dependency_sets(dependent_specification, dependencies, target_definition) def find_dependency_specs(dependent_specification, dependencies, target_definition)
@log_indent += 1 @log_indent += 1
dependencies.each do |dependency| dependencies.each do |dependency|
puts ' ' * @log_indent + "- #{dependency}" if config.verbose? puts ' ' * @log_indent + "- #{dependency}" if config.verbose?
...@@ -64,19 +61,12 @@ module Pod ...@@ -64,19 +61,12 @@ module Pod
set.required_by(dependent_specification) set.required_by(dependent_specification)
# Ensure we don't resolve the same spec twice for one target # Ensure we don't resolve the same spec twice for one target
unless @loaded_specs.include?(dependency.name) unless @loaded_specs.include?(dependency.name)
# Get a reference to the spec that’s actually being loaded. spec = set.specification_by_name(dependency.name)
# If it’s a subspec dependency, e.g. 'RestKit/Network', then
# find that subspec.
spec = set.specification
if dependency.subspec_dependency?
spec = spec.subspec_by_name(dependency.name)
end
@loaded_specs << spec.name @loaded_specs << spec.name
@specs[spec.name] = spec @specs[spec.name] = spec
spec.activate_platform(target_definition.platform)
# And recursively load the dependencies of the spec. # And recursively load the dependencies of the spec.
# TODO fix the need to return an empty arrayf if there are no deps for the given platform find_dependency_specs(spec, spec.dependencies, target_definition) if spec.dependencies
find_dependency_sets(spec, (spec.dependencies[target_definition.platform.to_sym] || []), target_definition)
end end
validate_platform!(spec || @specs[dependency.name], target_definition) validate_platform!(spec || @specs[dependency.name], target_definition)
end end
...@@ -84,8 +74,8 @@ module Pod ...@@ -84,8 +74,8 @@ module Pod
end end
def validate_platform!(spec, target) def validate_platform!(spec, target)
unless spec.platforms.any? { |platform| target.platform.support?(platform) } unless spec.available_platforms.any? { |platform| target.platform.supports?(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 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 end
end end
......
...@@ -68,7 +68,7 @@ module Pod ...@@ -68,7 +68,7 @@ module Pod
set.name == dependency.top_level_spec_name && set.name == dependency.top_level_spec_name &&
# Now either check if it's a dependency on the top level spec, or if it's not # Now either check if it's a dependency on the top level spec, or if it's not
# check if the requested subspec exists in the top level spec. # check if the requested subspec exists in the top level spec.
(!dependency.subspec_dependency? || !set.specification.subspec_by_name(dependency.name).nil?) set.specification.subspec_by_name(dependency.name)
end end
end end
......
require 'xcodeproj/config' require 'xcodeproj/config'
require 'colored'
module Pod module Pod
extend Config::Mixin extend Config::Mixin
...@@ -12,144 +11,97 @@ module Pod ...@@ -12,144 +11,97 @@ module Pod
autoload :Set, 'cocoapods/specification/set' autoload :Set, 'cocoapods/specification/set'
autoload :Statistics, 'cocoapods/specification/statistics' autoload :Statistics, 'cocoapods/specification/statistics'
### Initalization
# The file is expected to define and return a Pods::Specification. # 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? unless path.exist?
raise Informative, "No podspec exists at path `#{path}'." raise Informative, "No podspec exists at path `#{path}'."
end end
spec = ::Pod._eval_podspec(path) spec = ::Pod._eval_podspec(path)
spec.defined_in_file = path spec.defined_in_file = path
spec spec.subspec_by_name(subspec_name)
end
attr_accessor :defined_in_file
def initialize
post_initialize
yield self if block_given?
end end
# TODO This is just to work around a MacRuby bug def initialize(parent = nil, name = nil)
def post_initialize @parent, @name = parent, name
@define_for_platforms = [:osx, :ios] @define_for_platforms = [:osx, :ios]
@clean_paths, @subspecs = [], [] @clean_paths, @subspecs = [], []
@dependencies, @source_files, @resources = { :ios => [], :osx => [] }, { :ios => [], :osx => [] }, { :ios => [], :osx => [] }
@deployment_target = {} @deployment_target = {}
@platform = Platform.new(nil) unless parent
@xcconfig = { :ios => Xcodeproj::Config.new, :osx => Xcodeproj::Config.new } @source = {:git => ''}
@compiler_flags = { :ios => '', :osx => '' }
end
# Attributes **without** multiple platform support
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)
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 end
@authors = authors || list.first
end
alias_method :author=, :authors=
attr_reader :authors
def summary=(summary)
@summary = summary
end
attr_reader :summary
def license=(license) # multi-platform attributes
if license.kind_of?(Array) %w[ source_files resources preserve_paths exclude_header_search_paths frameworks libraries dependencies compiler_flags].each do |attr|
@license = license[1].merge({:type => license[0]}) instance_variable_set( "@#{attr}", { :ios => [], :osx => [] } )
elsif license.kind_of?(String)
@license = {:type => license}
else
@license = license
end end
end @xcconfig = { :ios => Xcodeproj::Config.new, :osx => Xcodeproj::Config.new }
attr_reader :license
def description
@description || summary
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
def part_of_dependency=(*name_and_version_requirements)
@part_of = dependency(*name_and_version_requirements)
end
def prefix_header_file=(file) yield self if block_given?
@prefix_header_file = Pathname.new(file)
end end
attr_reader :prefix_header_file
attr_accessor :prefix_header_contents
def clean_paths=(patterns) ### Meta programming
@clean_paths = pattern_list(patterns)
end
attr_reader :clean_paths
alias_method :clean_path=, :clean_paths=
def header_dir=(dir) # Creates a top level attribute reader. A lambda can
@header_dir = Pathname.new(dir) # be passed to process the ivar before returning it
end def self.top_attr_reader(attr, read_lambda = nil)
def header_dir define_method(attr) do
@header_dir || pod_destroot_name ivar = instance_variable_get("@#{attr}")
@parent ? top_level_parent.send(attr) : ( read_lambda ? read_lambda.call(self, ivar) : ivar )
end
end end
def platform=(platform) # Creates a top level attribute writer. A lambda can
@platform = Platform.new(*platform) # be passed to initalize the value
def self.top_attr_writer(attr, init_lambda = nil)
define_method("#{attr}=") do |value|
raise Informative, "Can't set `#{attr}' for subspecs." if @parent
instance_variable_set("@#{attr}", init_lambda ? init_lambda.call(value) : value);
end
end end
attr_reader :platform
def platforms # Creates a top level attribute accessor. A lambda can
@platform.nil? ? @define_for_platforms.map { |platfrom| Platform.new(platfrom, @deployment_target[platfrom]) } : [platform] # be passed to initialize the value in the attribute writer.
def self.top_attr_accessor(attr, writer_labmda = nil)
top_attr_reader attr
top_attr_writer attr, writer_labmda
end end
def requires_arc=(requires_arc) # Returns the value of the attribute for the active platform
self.compiler_flags = '-fobjc-arc' if requires_arc # chained with the upstream specifications. The ivar must store
@requires_arc = requires_arc # the platform specific values as an array.
def self.pltf_chained_attr_reader(attr)
define_method(attr) do
active_plaform_check
ivar_value = instance_variable_get("@#{attr}")[active_platform]
@parent ? @parent.send(attr) + ivar_value : ( ivar_value )
end
end end
attr_reader :requires_arc
def subspec(name, &block) def active_plaform_check
subspec = Subspec.new(self, name, &block) raise Informative, "#{self.inspect} not activated for a platform before consumption." unless active_platform
@subspecs << subspec
subspec
end end
attr_reader :subspecs
def recursive_subspecs # Attribute writer that works in conjuction with the PlatformProxy.
unless @recursive_subspecs def self.platform_attr_writer(attr, block = nil)
mapper = lambda do |spec| define_method("#{attr}=") do |value|
spec.subspecs.map do |subspec| current = instance_variable_get("@#{attr}")
[subspec, *mapper.call(subspec)] @define_for_platforms.each do |platform|
end.flatten block ? current[platform] = block.call(value, current[platform]) : current[platform] = value
end end
@recursive_subspecs = mapper.call self
end end
@recursive_subspecs
end end
### Attributes **with** multiple platform support def self.pltf_chained_attr_accessor(attr, block = nil)
pltf_chained_attr_reader(attr)
platform_attr_writer(attr, block)
end
# The PlatformProxy works in conjuction with Specification#_on_platform.
# It allows a syntax like `spec.ios.source_files = file`
class PlatformProxy class PlatformProxy
def initialize(specification, platform) def initialize(specification, platform)
@specification, @platform = specification, platform @specification, @platform = specification, platform
...@@ -172,100 +124,200 @@ module Pod ...@@ -172,100 +124,200 @@ module Pod
PlatformProxy.new(self, :osx) PlatformProxy.new(self, :osx)
end end
def source_files=(patterns) ### Deprecated attributes - TODO: remove once master repo and fixtures have been updated
@define_for_platforms.each do |platform|
@source_files[platform] = pattern_list(patterns) attr_writer :part_of_dependency
end attr_writer :part_of
top_attr_accessor :clean_paths, lambda { |patterns| pattern_list(patterns) }
alias_method :clean_path=, :clean_paths=
### Regular attributes
attr_accessor :parent
attr_accessor :preferred_dependency
def name
@parent ? "#{@parent.name}/#{@name}" : @name
end end
attr_reader :source_files attr_writer :name
def deployment_target=(version) ### Attributes that return the first value defined in the chain
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 def platform
@platform || ( @parent ? @parent.platform : nil )
end end
def resources=(patterns) def platform=(platform)
@define_for_platforms.each do |platform| @platform = Platform.new(*platform)
@resources[platform] = pattern_list(patterns)
end
end end
attr_reader :resources
alias_method :resource=, :resources=
def xcconfig=(build_settings) # If not platform is specified all the platforms are returned.
@define_for_platforms.each do |platform| def available_platforms
@xcconfig[platform].merge!(build_settings) platform.nil? ? @define_for_platforms.map { |platform| Platform.new(platform, deployment_target(platform)) } : [ platform ]
end
### Top level attributes. These attributes represent the unique features of pod and can't be specified by subspecs.
top_attr_accessor :defined_in_file
top_attr_accessor :source
top_attr_accessor :homepage
top_attr_accessor :summary
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 :authors, lambda { |a| parse_authors(a) }
top_attr_accessor :header_mappings_dir, lambda { |file| Pathname.new(file) } # If not provided the headers files are flattened
top_attr_accessor :prefix_header_file, lambda { |file| Pathname.new(file) }
top_attr_accessor :prefix_header_contents
top_attr_reader :description, lambda {|instance, ivar| ivar || instance.summary }
top_attr_writer :description
top_attr_reader :header_dir, lambda {|instance, ivar| ivar || instance.pod_destroot_name }
top_attr_writer :header_dir, lambda {|dir| Pathname.new(dir) }
alias_method :author=, :authors=
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 end
authors || list.first
end end
attr_reader :xcconfig
def frameworks=(*frameworks) ### Attributes **with** multiple platform support
frameworks.unshift('')
self.xcconfig = { 'OTHER_LDFLAGS' => frameworks.join(' -framework ').strip } pltf_chained_attr_accessor :source_files, lambda {|value, current| pattern_list(value) }
pltf_chained_attr_accessor :resources, lambda {|value, current| pattern_list(value) }
pltf_chained_attr_accessor :preserve_paths, lambda {|value, current| pattern_list(value) } # Paths that should not be cleaned
pltf_chained_attr_accessor :exclude_header_search_paths, lambda {|value, current| pattern_list(value) } # Headers to be excluded from being added to search paths (RestKit)
pltf_chained_attr_accessor :frameworks, lambda {|value, current| current << value }
pltf_chained_attr_accessor :libraries, lambda {|value, current| current << value }
alias_method :resource=, :resources=
alias_method :framework=, :frameworks=
alias_method :library=, :libraries=
def xcconfig
raw_xconfig.dup.
tap { |x| x.add_libraries(libraries) }.
tap { |x| x.add_frameworks(frameworks) }
end
# TODO: move to Xcodeproj
class ::Xcodeproj::Config
# BUG: old implementation would lose keys specified in self
# but not specified in the passed xcconfig.
def merge!(xcconfig)
@attributes.merge!(xcconfig.to_hash) { |key, v1, v2| "#{v1} #{v2}" }
end
def merge(config)
self.dup.tap { |x|x.merge!(config) }
end
def add_libraries(libraries)
return if libraries.nil? || libraries.empty?
flags = [ @attributes['OTHER_LDFLAGS'] ] || []
flags << "-l#{ libraries.join(' -l') }"
@attributes['OTHER_LDFLAGS'] = flags.compact.map(&:strip).join(' ')
end
def add_frameworks(frameworks)
return if frameworks.nil? || frameworks.empty?
flags = [ @attributes['OTHER_LDFLAGS'] ] || []
flags << "-framework #{ frameworks.join(' -framework ') }"
@attributes['OTHER_LDFLAGS'] = flags.compact.map(&:strip).join(' ')
end
def dup
Xcodeproj::Config.new(self.to_hash.dup)
end
end end
alias_method :framework=, :frameworks=
def libraries=(*libraries) def raw_xconfig
libraries.unshift('') @parent ? @parent.raw_xconfig.merge(@xcconfig[active_platform]) : @xcconfig[active_platform]
self.xcconfig = { 'OTHER_LDFLAGS' => libraries.join(' -l').strip }
end end
alias_method :library=, :libraries=
attr_reader :compiler_flags platform_attr_writer :xcconfig, lambda {|value, current| current.tap { |c| c.merge!(value) } }
def compiler_flags=(flags)
@define_for_platforms.each do |platform| def compiler_flags
@compiler_flags[platform] << ' ' << flags if @parent
chained = @compiler_flags[active_platform].clone.unshift @parent.compiler_flags[active_platform]
else
chained = @compiler_flags[active_platform].clone
chained.unshift '-fobjc-arc' if @requires_arc
chained.unshift ''
end end
chained.join(' ')
end end
platform_attr_writer :compiler_flags, lambda {|value, current| current << value }
def dependency(*name_and_version_requirements) def dependency(*name_and_version_requirements)
name, *version_requirements = name_and_version_requirements.flatten name, *version_requirements = name_and_version_requirements.flatten
raise Informative, "A specification can't require self as a subspec" if name == self.name
raise Informative, "A subspec can't require one of its parents specifications" if @parent && @parent.name.include?(name)
dep = Dependency.new(name, *version_requirements) dep = Dependency.new(name, *version_requirements)
@define_for_platforms.each do |platform| @define_for_platforms.each do |platform|
@dependencies[platform] << dep @dependencies[platform] << dep
end end
dep dep
end end
attr_reader :dependencies
### Not attributes # External dependencies are inherited by subspecs
def external_dependencies(all_platforms = false)
active_plaform_check unless all_platforms
result = all_platforms ? @dependencies.values.flatten : @dependencies[active_platform]
result += parent.external_dependencies if parent
result
end
# @visibility private # A specification inherits the preferred_dependency or
# # all the compatible subspecs as dependencies
# This is used by PlatformProxy to assign attributes for the scoped platform. def subspec_dependencies
def _on_platform(platform) active_plaform_check
before, @define_for_platforms = @define_for_platforms, [platform] specs = preferred_dependency ? [subspec_by_name("#{name}/#{preferred_dependency}")] : subspecs
yield specs.compact \
ensure .select { |s| s.supports_platform?(active_platform) } \
@define_for_platforms = before .map { |s| Dependency.new(s.name, version) }
end
def dependencies
external_dependencies + subspec_dependencies
end end
include Config::Mixin include Config::Mixin
def local? def top_level_parent
!source.nil? && !source[:local].nil? @parent ? @parent.top_level_parent : self
end end
def local_path def subspec(name, &block)
Pathname.new(File.expand_path(source[:local])) subspec = Specification.new(self, name, &block)
@subspecs << subspec
subspec
end end
attr_reader :subspecs
# This is assigned the other spec, of which this pod's source is a part, by def recursive_subspecs
# a Resolver. unless @recursive_subspecs
attr_accessor :part_of_specification mapper = lambda do |spec|
def part_of_specification spec.subspecs.map do |subspec|
@part_of_specification || begin [subspec, *mapper.call(subspec)]
set = Source.search(@part_of) end.flatten
set.required_by(self) end
set.specification @recursive_subspecs = mapper.call self
end end
end @recursive_subspecs
def wrapper?
source_files.values.all?(&:empty?) && !subspecs.empty?
end end
def subspec_by_name(name) 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 # 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 # and take the first component from the remainder, which is the spec we need
# to find now. # to find now.
...@@ -275,31 +327,24 @@ module Pod ...@@ -275,31 +327,24 @@ module Pod
# If this was the last component in the name, then return the subspec, # If this was the last component in the name, then return the subspec,
# otherwise we recursively keep calling subspec_by_name until we reach the # otherwise we recursively keep calling subspec_by_name until we reach the
# last one and return that # last one and return that
raise Informative, "Unable to find a subspec named `#{name}'." unless subspec
remainder.empty? ? subspec : subspec.subspec_by_name(name) remainder.empty? ? subspec : subspec.subspec_by_name(name)
end end
def ==(other) def local?
object_id == other.object_id || !source.nil? && !source[:local].nil?
(self.class === other &&
name && name == other.name &&
version && version == other.version)
end end
def dependency_by_top_level_spec_name(name) def local_path
@dependencies.each do |_, platform_deps| Pathname.new(File.expand_path(source[:local]))
platform_deps.each do |dep|
return dep if dep.top_level_spec_name == name
end
end
end end
def pod_destroot def pod_destroot
if part_of_other_pod? if local?
part_of_specification.pod_destroot
elsif local?
local_path local_path
else else
config.project_pods_root + @name config.project_pods_root + top_level_parent.name
end end
end end
...@@ -309,15 +354,7 @@ module Pod ...@@ -309,15 +354,7 @@ module Pod
end end
end end
def part_of_other_pod? def self.pattern_list(patterns)
!part_of.nil?
end
def podfile?
false
end
def pattern_list(patterns)
if patterns.is_a?(Array) && (!defined?(Rake) || !patterns.is_a?(Rake::FileList)) if patterns.is_a?(Array) && (!defined?(Rake) || !patterns.is_a?(Rake::FileList))
patterns patterns
else else
...@@ -329,18 +366,10 @@ module Pod ...@@ -329,18 +366,10 @@ module Pod
# in the pod's header dir. # in the pod's header dir.
# #
# By default all headers are copied to the pod's header dir without any # By default all headers are copied to the pod's header dir without any
# namespacing. You can, however, override this method in the podspec, or # namespacing. However if the top level attribute accessor header_mappings_dir
# copy_header_mappings for full control. # is specified the namespacing will be preserved from that directory.
def copy_header_mapping(from) def copy_header_mapping(from)
from.basename header_mappings_dir ? from.relative_path_from(header_mappings_dir) : from.basename
end
def to_s
"#{name} (#{version})"
end
def inspect
"#<#{self.class.name} for #{to_s}>"
end end
# This is a convenience method which gets called after all pods have been # This is a convenience method which gets called after all pods have been
...@@ -359,53 +388,76 @@ module Pod ...@@ -359,53 +388,76 @@ module Pod
def post_install(target) def post_install(target)
end end
class Subspec < Specification def podfile?
attr_reader :parent false
end
def initialize(parent, name) # This is used by the specification set
@parent, @name = parent, name def dependency_by_top_level_spec_name(name)
# TODO a MacRuby bug, the correct super impl `initialize' is not called consistently external_dependencies(true).each do |dep|
#super(&block) return dep if dep.top_level_spec_name == name
post_initialize end
end
# A subspec is _always_ part of the source of its top level spec. def to_s
self.part_of = top_level_parent.name, version "#{name} (#{version})"
# A subspec has a dependency on the parent if the parent is a subspec too. end
dependency(@parent.name, version) if @parent.is_a?(Subspec)
yield self if block_given? def inspect
end "#<#{self.class.name} for #{to_s}>"
end
undef_method :name=, :version=, :source= def ==(other)
object_id == other.object_id ||
(self.class === other &&
name && name == other.name &&
version && version == other.version)
end
def top_level_parent # Returns whether the specification is supported in a given platform
top_level_parent = @parent def supports_platform?(*platform)
top_level_parent = top_level_parent.parent while top_level_parent.is_a?(Subspec) platform = platform[0].is_a?(Platform) ? platform[0] : Platform.new(*platform)
top_level_parent available_platforms.any? { |p| platform.supports?(p) }
end end
def name # Defines the active platform for comsumption of the specification and
"#{@parent.name}/#{@name}" # returns self for method chainability.
end # The active platform must the the same accross the chain so attributes
# that are inherited can be correctly resolved.
def activate_platform(*platform)
platform = platform[0].is_a?(Platform) ? platform[0] : Platform.new(*platform)
raise Informative, "#{to_s} is not compatible with #{platform}." unless supports_platform?(platform)
top_level_parent.active_platform = platform.to_sym
self
end
# TODO manually forwarding the attributes that we have so far needed to forward, top_attr_accessor :active_platform
# but need to think if there's a better way to do this.
def summary ### Not attributes
@summary ? @summary : top_level_parent.summary
end
# Override the getters to always return the value of the top level parent spec. # @visibility private
[:version, :summary, :platform, :license, :authors, :requires_arc, :compiler_flags, :documentation, :homepage].each do |attr| #
define_method(attr) { top_level_parent.send(attr) } # This is used by PlatformProxy to assign attributes for the scoped platform.
end def _on_platform(platform)
before, @define_for_platforms = @define_for_platforms, [platform]
yield
ensure
@define_for_platforms = before
end
def copy_header_mapping(from) # @visibility private
top_level_parent.copy_header_mapping(from) #
end # This is multi-platform and to support
# subspecs with different platforms is is resolved as the
# first non nil value accross the chain.
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 end
def deployment_target(platform)
@deployment_target[platform] || ( @parent ? @parent.deployment_target(platform) : nil )
end
end end
Spec = Specification Spec = Specification
end end
...@@ -9,6 +9,9 @@ module Pod ...@@ -9,6 +9,9 @@ module Pod
end end
def required_by(specification) def required_by(specification)
# Skip subspecs because the can't require a different version of the top level parent
return if !specification.podfile? && specification.top_level_parent.name == name
dependency = specification.dependency_by_top_level_spec_name(name) dependency = specification.dependency_by_top_level_spec_name(name)
# TODO we don’t actually do anything in our Version subclass. Maybe we should just remove that. # TODO we don’t actually do anything in our Version subclass. Maybe we should just remove that.
unless @required_by.empty? || dependency.requirement.satisfied_by?(Gem::Version.new(required_version.to_s)) unless @required_by.empty? || dependency.requirement.satisfied_by?(Gem::Version.new(required_version.to_s))
...@@ -21,16 +24,16 @@ module Pod ...@@ -21,16 +24,16 @@ module Pod
@required_by << specification @required_by << specification
end end
def specification_by_name(name)
specification.top_level_parent.subspec_by_name(name)
end
def dependency def dependency
@required_by.inject(Dependency.new(name)) do |previous, spec| @required_by.inject(Dependency.new(name)) do |previous, spec|
previous.merge(spec.dependency_by_top_level_spec_name(name).to_top_level_spec_dependency) previous.merge(spec.dependency_by_top_level_spec_name(name).to_top_level_spec_dependency)
end end
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 def name
@pod_dir.basename.to_s @pod_dir.basename.to_s
end end
...@@ -74,7 +77,7 @@ module Pod ...@@ -74,7 +77,7 @@ module Pod
end end
def name def name
@specification.name @specification.top_level_parent.name
end end
def ==(other) def ==(other)
...@@ -88,10 +91,6 @@ module Pod ...@@ -88,10 +91,6 @@ module Pod
@specification = before @specification = before
end end
def only_part_of_other_pod?
false
end
def specification_path def specification_path
raise "specification_path" raise "specification_path"
end end
......
...@@ -81,7 +81,7 @@ module Pod ...@@ -81,7 +81,7 @@ module Pod
def github_stats_if_needed(set) def github_stats_if_needed(set)
return if get_value(set, :gh_date) && get_value(set, :gh_date) > Time.now - cache_expiration 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 url = spec.source.reject {|k,_| k == :commit || k == :tag }.values.first
repo_id = url[/github.com\/([^\/\.]*\/[^\/\.]*)\.*/, 1] repo_id = url[/github.com\/([^\/\.]*\/[^\/\.]*)\.*/, 1]
return unless repo_id return unless repo_id
......
...@@ -288,6 +288,101 @@ ...@@ -288,6 +288,101 @@
}; };
name = Release; name = Release;
}; };
517F031C154C379000D46FE2 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
CLANG_ENABLE_OBJC_ARC = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
SDKROOT = iphoneos;
};
name = Test;
};
517F031D154C379000D46FE2 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "SampleProject/SampleProject-Prefix.pch";
INFOPLIST_FILE = "SampleProject/SampleProject-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
name = Test;
};
517F031E154C379000D46FE2 /* Test */ = {
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 = Test;
};
517F0320154C379700D46FE2 /* App Store */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
CLANG_ENABLE_OBJC_ARC = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = "App Store";
};
517F0321154C379700D46FE2 /* App Store */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "SampleProject/SampleProject-Prefix.pch";
INFOPLIST_FILE = "SampleProject/SampleProject-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
name = "App Store";
};
517F0322154C379700D46FE2 /* App Store */ = {
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 = "App Store";
};
A346498314F9BE9A0080D870 /* Debug */ = { A346498314F9BE9A0080D870 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
...@@ -362,15 +457,20 @@ ...@@ -362,15 +457,20 @@
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
51075D5C1521D0C100E39B41 /* Debug */, 51075D5C1521D0C100E39B41 /* Debug */,
517F031E154C379000D46FE2 /* Test */,
51075D5D1521D0C100E39B41 /* Release */, 51075D5D1521D0C100E39B41 /* Release */,
517F0322154C379700D46FE2 /* App Store */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
}; };
A346496714F9BE990080D870 /* Build configuration list for PBXProject "SampleProject" */ = { A346496714F9BE990080D870 /* Build configuration list for PBXProject "SampleProject" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
A346498314F9BE9A0080D870 /* Debug */, A346498314F9BE9A0080D870 /* Debug */,
517F031C154C379000D46FE2 /* Test */,
A346498414F9BE9A0080D870 /* Release */, A346498414F9BE9A0080D870 /* Release */,
517F0320154C379700D46FE2 /* App Store */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
...@@ -379,7 +479,9 @@ ...@@ -379,7 +479,9 @@
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
A346498614F9BE9A0080D870 /* Debug */, A346498614F9BE9A0080D870 /* Debug */,
517F031D154C379000D46FE2 /* Test */,
A346498714F9BE9A0080D870 /* Release */, A346498714F9BE9A0080D870 /* Release */,
517F0321154C379700D46FE2 /* App Store */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
......
Subproject commit 7e96b1af54872aba6e474ea5860e84f1ce534fb1 Subproject commit 5f39221d0bf69ebc0a2dc5879deae271f208877b
require File.expand_path('../../../spec_helper', __FILE__) require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::Install" do describe "Pod::Command::Install" do
extend SpecHelper::Command
extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
it "should include instructions on how to reference the xcode project" do it "should include instructions on how to reference the xcode project" do
Pod::Command::Install.banner.should.match %r{xcodeproj 'path/to/XcodeProject'} Pod::Command::Install.banner.should.match %r{xcodeproj 'path/to/XcodeProject'}
end end
end
it "tells the user that no Podfile or podspec was found in the current working dir" do
exception = lambda { run_command('install','--no-update') }.should.raise Pod::Informative
exception.message.should.include "No `Podfile' found in the current working directory."
end
end
require File.expand_path('../../../spec_helper', __FILE__) require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::List" do describe "Pod::Command::List" do
extend SpecHelper::Git extend SpecHelper::TemporaryRepos
before do before do
config.repos_dir = fixture('spec-repos') config.repos_dir = fixture('spec-repos')
end end
after do
config.repos_dir = tmp_repos_path
end
def command(arguments = argv) def command(arguments = argv)
command = Pod::Command::List.new(arguments) command = Pod::Command::List.new(arguments)
end end
......
...@@ -2,8 +2,12 @@ require File.expand_path('../../../spec_helper', __FILE__) ...@@ -2,8 +2,12 @@ require File.expand_path('../../../spec_helper', __FILE__)
describe Pod::Command::Push do describe Pod::Command::Push do
extend SpecHelper::Command extend SpecHelper::Command
extend SpecHelper::Git
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
def master_repo
fixture('spec-repos/master')
end
it "complains for wrong parameters" do it "complains for wrong parameters" do
lambda { run_command('push') }.should.raise Pod::Command::Help lambda { run_command('push') }.should.raise Pod::Command::Help
...@@ -12,19 +16,19 @@ describe Pod::Command::Push do ...@@ -12,19 +16,19 @@ describe Pod::Command::Push do
end end
it "complains if it can't find the repo" do it "complains if it can't find the repo" do
repo1 = add_repo('repo1', fixture('spec-repos/master')) repo1 = add_repo('repo1', master_repo)
Dir.chdir(fixture('banana-lib')) do Dir.chdir(fixture('banana-lib')) do
lambda { run_command('push', 'repo2') }.should.raise Pod::Informative lambda { run_command('push', 'repo2') }.should.raise Pod::Informative
end end
end end
it "complains if it can't find a spec" do it "complains if it can't find a spec" do
repo1 = add_repo('repo1', fixture('spec-repos/master')) repo1 = add_repo('repo1', master_repo)
lambda { run_command('push', 'repo1') }.should.raise Pod::Informative lambda { run_command('push', 'repo1') }.should.raise Pod::Informative
end end
it "it raises if the pod is not validated" do it "it raises if the pod is not validated" do
repo1 = add_repo('repo1', fixture('spec-repos/master')) repo1 = add_repo('repo1', master_repo)
git('repo1', 'checkout master') # checkout master, because the fixture is a submodule git('repo1', 'checkout master') # checkout master, because the fixture is a submodule
repo2 = add_repo('repo2', repo1.dir) repo2 = add_repo('repo2', repo1.dir)
git_config('repo2', 'remote.origin.url').should == (tmp_repos_path + 'repo1').to_s git_config('repo2', 'remote.origin.url').should == (tmp_repos_path + 'repo1').to_s
...@@ -36,7 +40,7 @@ describe Pod::Command::Push do ...@@ -36,7 +40,7 @@ describe Pod::Command::Push do
before do before do
# prepare the repos # prepare the repos
@upstream = add_repo('upstream', fixture('spec-repos/master')) @upstream = add_repo('upstream', master_repo)
git('upstream', 'checkout -b master') # checkout master, because the fixture is a submodule git('upstream', 'checkout -b master') # checkout master, because the fixture is a submodule
@local_repo = add_repo('local_repo', @upstream.dir) @local_repo = add_repo('local_repo', @upstream.dir)
git_config('local_repo', 'remote.origin.url').should == (tmp_repos_path + 'upstream').to_s git_config('local_repo', 'remote.origin.url').should == (tmp_repos_path + 'upstream').to_s
......
...@@ -2,8 +2,8 @@ require File.expand_path('../../../spec_helper', __FILE__) ...@@ -2,8 +2,8 @@ require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::Repo" do describe "Pod::Command::Repo" do
extend SpecHelper::Command extend SpecHelper::Command
extend SpecHelper::Git
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
it "runs with correct parameters" do it "runs with correct parameters" do
lambda { run_command('repo', 'add', 'NAME', 'URL') }.should.not.raise lambda { run_command('repo', 'add', 'NAME', 'URL') }.should.not.raise
...@@ -42,6 +42,7 @@ describe "Pod::Command::Repo" do ...@@ -42,6 +42,7 @@ describe "Pod::Command::Repo" do
before do before do
add_repo('repo1', fixture('spec-repos/master')) add_repo('repo1', fixture('spec-repos/master'))
FileUtils.rm_rf(versions_file)
versions_file.should.not.exist? versions_file.should.not.exist?
end end
......
...@@ -2,18 +2,13 @@ require File.expand_path('../../../spec_helper', __FILE__) ...@@ -2,18 +2,13 @@ require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::Search" do describe "Pod::Command::Search" do
extend SpecHelper::Command extend SpecHelper::Command
extend SpecHelper::Git
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
before do before do
config.repos_dir = fixture('spec-repos') config.repos_dir = fixture('spec-repos')
end end
after do
config.repos_dir = tmp_repos_path
end
it "runs with correct parameters" do it "runs with correct parameters" do
lambda { run_command('search', 'table') }.should.not.raise lambda { run_command('search', 'table') }.should.not.raise
lambda { run_command('search', 'table', '--full') }.should.not.raise lambda { run_command('search', 'table', '--full') }.should.not.raise
......
...@@ -3,8 +3,8 @@ require File.expand_path('../../../spec_helper', __FILE__) ...@@ -3,8 +3,8 @@ require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::Setup" do describe "Pod::Command::Setup" do
extend SpecHelper::Command extend SpecHelper::Command
extend SpecHelper::Git
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
it "runs with correct parameters" do it "runs with correct parameters" do
lambda { run_command('setup') }.should.not.raise lambda { run_command('setup') }.should.not.raise
......
...@@ -18,21 +18,22 @@ describe "Pod::Command::Spec#create" do ...@@ -18,21 +18,22 @@ describe "Pod::Command::Spec#create" do
extend SpecHelper::Command extend SpecHelper::Command
extend SpecHelper::Github extend SpecHelper::Github
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
extend SpecHelper::Git extend SpecHelper::TemporaryRepos
it "creates a new podspec stub file" do it "creates a new podspec stub file" do
run_command('spec', 'create', 'Bananas') run_command('spec', 'create', 'Bananas')
path = temporary_directory + 'Bananas.podspec' path = temporary_directory + 'Bananas.podspec'
spec = Pod::Specification.from_file(path) spec = Pod::Specification.from_file(path).activate_platform(:ios)
spec.name.should == 'Bananas'
spec.license.should == { :type => "MIT", :file => "LICENSE" } spec.name.should == 'Bananas'
spec.version.should == Pod::Version.new('0.0.1') spec.license.should == { :type => "MIT", :file => "LICENSE" }
spec.summary.should == 'A short description of Bananas.' spec.version.should == Pod::Version.new('0.0.1')
spec.homepage.should == 'http://EXAMPLE/Bananas' spec.summary.should == 'A short description of Bananas.'
spec.authors.should == { `git config --get user.name`.strip => `git config --get user.email`.strip} spec.homepage.should == 'http://EXAMPLE/Bananas'
spec.source.should == { :git => 'http://EXAMPLE/Bananas.git', :tag => '0.0.1' } spec.authors.should == { `git config --get user.name`.strip => `git config --get user.email`.strip}
spec.description.should == 'An optional longer description of Bananas.' spec.source.should == { :git => 'http://EXAMPLE/Bananas.git', :tag => '0.0.1' }
spec.source_files[:ios].should == ['Classes', 'Classes/**/*.{h,m}'] spec.description.should == 'An optional longer description of Bananas.'
spec.source_files.should == ['Classes', 'Classes/**/*.{h,m}']
end end
it "correctly creates a podspec from github" do it "correctly creates a podspec from github" do
...@@ -93,21 +94,16 @@ end ...@@ -93,21 +94,16 @@ end
describe "Pod::Command::Spec#lint" do describe "Pod::Command::Spec#lint" do
extend SpecHelper::Command extend SpecHelper::Command
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
extend SpecHelper::Git extend SpecHelper::TemporaryRepos
before do before do
config.repos_dir = fixture('spec-repos') config.repos_dir = fixture('spec-repos')
end end
after do
config.repos_dir = tmp_repos_path
end
it "lints a repo" do it "lints a repo" do
# The fixture has an error due to a name mismatch # The fixture has warnings so it raises
cmd = command('spec', 'lint', 'master') cmd = command('spec', 'lint', 'master')
lambda { cmd.run }.should.raise Pod::Informative lambda { cmd.run }.should.raise Pod::Informative
cmd.output.should.include "InAppSettingKit (0.0.1)\n - ERROR | The name of the spec should match the name of the file"
cmd.output.should.include "WARN" cmd.output.should.include "WARN"
end end
...@@ -124,17 +120,23 @@ describe "Pod::Command::Spec#lint" do ...@@ -124,17 +120,23 @@ describe "Pod::Command::Spec#lint" do
end end
end end
before do
text = (fixture('spec-repos') + 'master/JSONKit/1.4/JSONKit.podspec').read
text.gsub!(/.*license.*/, "")
file = temporary_directory + 'JSONKit.podspec'
File.open(file, 'w') {|f| f.write(text) }
@spec_path = file.to_s
end
it "lints a givent podspec" do it "lints a givent podspec" do
spec_file = fixture('spec-repos') + 'master/JSONKit/1.4/JSONKit.podspec' cmd = command('spec', 'lint', '--quick', @spec_path)
cmd = command('spec', 'lint', '--quick', spec_file.to_s)
lambda { cmd.run }.should.raise Pod::Informative lambda { cmd.run }.should.raise Pod::Informative
cmd.output.should.include "Missing license[:file] or [:text]" cmd.output.should.include "Missing license type"
end end
it "respects the -only--errors option" do it "respects the -only--errors option" do
spec_file = fixture('spec-repos') + 'master/JSONKit/1.4/JSONKit.podspec' cmd = command('spec', 'lint', '--quick', '--only-errors', @spec_path)
cmd = command('spec', 'lint', '--quick', '--only-errors', spec_file.to_s)
lambda { cmd.run }.should.not.raise lambda { cmd.run }.should.not.raise
cmd.output.should.include "Missing license[:file] or [:text]" cmd.output.should.include "Missing license type"
end end
end end
...@@ -2,8 +2,8 @@ require File.expand_path('../../spec_helper', __FILE__) ...@@ -2,8 +2,8 @@ require File.expand_path('../../spec_helper', __FILE__)
# describe "Pod::Command" do # describe "Pod::Command" do
# extend SpecHelper::Command # extend SpecHelper::Command
# extend SpecHelper::Git
# extend SpecHelper::TemporaryDirectory # extend SpecHelper::TemporaryDirectory
# extend SpecHelper::TemporaryRepos
# #
# TODO: # TODO:
# it "raises help informative if an unknown parameter is passed" # it "raises help informative if an unknown parameter is passed"
......
...@@ -7,156 +7,218 @@ describe "Pod::Downloader" do ...@@ -7,156 +7,218 @@ describe "Pod::Downloader" do
describe "for Git" do describe "for Git" do
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
it "check's out a specific commit" do it "check's out a specific commit" do
@pod.specification.stubs(:source).returns( @pod.top_specification.stubs(:source).returns(
:git => fixture('banana-lib'), :commit => 'fd56054' :git => fixture('banana-lib'), :commit => 'fd56054'
) )
downloader = Pod::Downloader.for_pod(@pod) downloader = Pod::Downloader.for_pod(@pod)
downloader.download downloader.download
(@pod.root + 'README').read.strip.should == 'first commit' (@pod.root + 'README').read.strip.should == 'first commit'
end end
it "check's out a specific tag" do it "check's out a specific tag" do
@pod.specification.stubs(:source).returns( @pod.top_specification.stubs(:source).returns(
:git => fixture('banana-lib'), :tag => 'v1.0' :git => fixture('banana-lib'), :tag => 'v1.0'
) )
downloader = Pod::Downloader.for_pod(@pod) downloader = Pod::Downloader.for_pod(@pod)
downloader.download downloader.download
(@pod.root + 'README').read.strip.should == 'v1.0' (@pod.root + 'README').read.strip.should == 'v1.0'
end end
it "removes the .git directory when cleaning" do it "prepares the cache if it does not exits" do
@pod.specification.stubs(:source).returns( @pod.top_specification.stubs(:source).returns(
:git => fixture('banana-lib'), :commit => 'fd56054'
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.cache_path.rmtree if downloader.cache_path.exist?
downloader.expects(:create_cache).once
downloader.stubs(:download_commit)
downloader.download
end
it "removes the oldest repo if the caches is too big" do
@pod.top_specification.stubs(:source).returns(
:git => fixture('banana-lib'), :commit => 'fd56054'
)
original_chace_size = Pod::Downloader::Git::MAX_CACHE_SIZE
Pod::Downloader::Git.__send__(:remove_const,'MAX_CACHE_SIZE')
Pod::Downloader::Git::MAX_CACHE_SIZE = 0
downloader = Pod::Downloader.for_pod(@pod)
downloader.stubs(:cache_dir).returns(temporary_directory)
downloader.download
downloader.cache_path.should.not.exist?
Pod::Downloader::Git.__send__(:remove_const,'MAX_CACHE_SIZE')
Pod::Downloader::Git::MAX_CACHE_SIZE = original_chace_size
end
xit "raises if it can't find the url" do
@pod.top_specification.stubs(:source).returns(
:git => 'find_me_if_you_can'
)
downloader = Pod::Downloader.for_pod(@pod)
lambda { downloader.download }.should.raise Pod::Informative
end
it "raises if it can't find a commit" do
@pod.top_specification.stubs(:source).returns(
:git => fixture('banana-lib'), :commit => 'aaaaaa'
)
downloader = Pod::Downloader.for_pod(@pod)
lambda { downloader.download }.should.raise Pod::Informative
end
it "raises if it can't find a tag" do
@pod.top_specification.stubs(:source).returns(
:git => fixture('banana-lib'), :tag => 'aaaaaa'
)
downloader = Pod::Downloader.for_pod(@pod)
lambda { downloader.download }.should.raise Pod::Informative
end
it "does not raise if it can find the reference" do
@pod.top_specification.stubs(:source).returns(
:git => fixture('banana-lib'), :commit => 'fd56054'
)
downloader = Pod::Downloader.for_pod(@pod)
lambda { downloader.download }.should.not.raise
end
it "returns the cache directory as the clone url" do
@pod.top_specification.stubs(:source).returns(
:git => fixture('banana-lib'), :commit => 'fd56054'
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.clone_url.to_s.should.match /Library\/Caches\/CocoaPods\/Git/
end
it "updates the cache if the HEAD is requested" do
@pod.top_specification.stubs(:source).returns(
:git => fixture('banana-lib') :git => fixture('banana-lib')
) )
downloader = Pod::Downloader.for_pod(@pod) downloader = Pod::Downloader.for_pod(@pod)
downloader.expects(:update_cache).once
downloader.download
end
it "updates the cache if the ref is not available" do
# create the origin repo and the cache
tmp_repo_path = temporary_directory + 'banana-lib-source'
`git clone #{fixture('banana-lib')} #{tmp_repo_path}`
@pod.top_specification.stubs(:source).returns(
:git => tmp_repo_path, :commit => 'fd56054'
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.download
# make a new commit in the origin
commit = ''
Dir.chdir(tmp_repo_path) do
`touch test.txt`
`git add test.txt`
`git commit -m 'test'`
commit = `git rev-parse HEAD`.chomp
end
# require the new commit
pod = Pod::LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), temporary_sandbox, Pod::Platform.ios)
pod.top_specification.stubs(:source).returns(
:git => tmp_repo_path, :commit => commit
)
downloader = Pod::Downloader.for_pod(pod)
downloader.download
(pod.root + 'test.txt').should.exist?
end
it "doesn't updates cache the if the ref is available" do
@pod.top_specification.stubs(:source).returns(
:git => fixture('banana-lib'), :commit => 'fd56054'
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.download
downloader.expects(:update_cache).never
downloader.download downloader.download
downloader.clean
(@pod.root + '.git').should.not.exist
end end
end end
describe "for Github repositories, with :download_only set to true" do describe "for GitHub repositories, with :download_only set to true" do
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
it "downloads HEAD with no other options specified" do it "downloads HEAD with no other options specified" do
@pod.specification.stubs(:source).returns( @pod.top_specification.stubs(:source).returns(
:git => "git://github.com/lukeredpath/libPusher.git", :download_only => true :git => "git://github.com/lukeredpath/libPusher.git", :download_only => true
) )
downloader = Pod::Downloader.for_pod(@pod) downloader = Pod::Downloader.for_pod(@pod)
VCR.use_cassette('tarballs', :record => :new_episodes) { downloader.download } VCR.use_cassette('tarballs', :record => :new_episodes) { downloader.download }
# deliberately keep this assertion as loose as possible for now # deliberately keep this assertion as loose as possible for now
(@pod.root + 'README.md').readlines[0].should =~ /libPusher/ (@pod.root + 'README.md').readlines[0].should =~ /libPusher/
end end
it "downloads a specific tag when specified" do it "downloads a specific tag when specified" do
@pod.specification.stubs(:source).returns( @pod.top_specification.stubs(:source).returns(
:git => "git://github.com/lukeredpath/libPusher.git", :tag => 'v1.1', :download_only => true :git => "git://github.com/lukeredpath/libPusher.git", :tag => 'v1.1', :download_only => true
) )
downloader = Pod::Downloader.for_pod(@pod) downloader = Pod::Downloader.for_pod(@pod)
VCR.use_cassette('tarballs', :record => :new_episodes) { downloader.download } VCR.use_cassette('tarballs', :record => :new_episodes) { downloader.download }
# deliberately keep this assertion as loose as possible for now # deliberately keep this assertion as loose as possible for now
(@pod.root + 'libPusher.podspec').readlines.grep(/1.1/).should.not.be.empty (@pod.root + 'libPusher.podspec').readlines.grep(/1.1/).should.not.be.empty
end end
it "downloads a specific commit when specified" do it "downloads a specific commit when specified" do
@pod.specification.stubs(:source).returns( @pod.top_specification.stubs(:source).returns(
:git => "git://github.com/lukeredpath/libPusher.git", :commit => 'eca89998d5', :download_only => true :git => "git://github.com/lukeredpath/libPusher.git", :commit => 'eca89998d5', :download_only => true
) )
downloader = Pod::Downloader.for_pod(@pod) downloader = Pod::Downloader.for_pod(@pod)
VCR.use_cassette('tarballs', :record => :new_episodes) { downloader.download } VCR.use_cassette('tarballs', :record => :new_episodes) { downloader.download }
# deliberately keep this assertion as loose as possible for now # deliberately keep this assertion as loose as possible for now
(@pod.root + 'README.md').readlines[0].should =~ /PusherTouch/ (@pod.root + 'README.md').readlines[0].should =~ /PusherTouch/
end end
it 'deletes the downloaded tarball after unpacking it' do
@pod.specification.stubs(:source).returns(
:git => "git://github.com/lukeredpath/libPusher.git", :download_only => true
)
downloader = Pod::Downloader.for_pod(@pod)
VCR.use_cassette('tarballs', :record => :new_episodes) { downloader.download }
downloader.clean
(@pod.root + 'tarball.tar.gz').should.not.exist
end
it "removes the .git directory when cleaning" do
@pod.specification.stubs(:source).returns(
:git => "git://github.com/lukeredpath/libPusher.git", :download_only => false
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.download
downloader.clean
(@pod.root + '.git').should.not.exist
end
end end
describe "for Mercurial" do describe "for Mercurial" do
it "check's out a specific revision" do it "check's out a specific revision" do
@pod.specification.stubs(:source).returns( @pod.top_specification.stubs(:source).returns(
:hg => fixture('mercurial-repo'), :revision => '46198bb3af96' :hg => fixture('mercurial-repo'), :revision => '46198bb3af96'
) )
downloader = Pod::Downloader.for_pod(@pod) downloader = Pod::Downloader.for_pod(@pod)
downloader.download downloader.download
(@pod.root + 'README').read.strip.should == 'first commit' (@pod.root + 'README').read.strip.should == 'first commit'
end end
it "removes the .hg directory when cleaning" do
@pod.specification.stubs(:source).returns(
:hg => fixture('mercurial-repo')
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.download
downloader.clean
(@pod.root + '.hg').should.not.exist
end
end end
describe "for Subversion" do describe "for Subversion" do
it "check's out a specific revision" do it "check's out a specific revision" do
@pod.specification.stubs(:source).returns( @pod.top_specification.stubs(:source).returns(
:svn => "file://#{fixture('subversion-repo')}", :revision => '1' :svn => "file://#{fixture('subversion-repo')}", :revision => '1'
) )
downloader = Pod::Downloader.for_pod(@pod) downloader = Pod::Downloader.for_pod(@pod)
downloader.download downloader.download
(@pod.root + 'README').read.strip.should == 'first commit' (@pod.root + 'README').read.strip.should == 'first commit'
end end
it "check's out a specific tag" do it "check's out a specific tag" do
@pod.specification.stubs(:source).returns( @pod.top_specification.stubs(:source).returns(
:svn => "file://#{fixture('subversion-repo')}/tags/tag-1" :svn => "file://#{fixture('subversion-repo')}/tags/tag-1"
) )
downloader = Pod::Downloader.for_pod(@pod) downloader = Pod::Downloader.for_pod(@pod)
downloader.download downloader.download
(@pod.root + 'README').read.strip.should == 'tag 1' (@pod.root + 'README').read.strip.should == 'tag 1'
end end
it "removes the .svn directories when cleaning" do
@pod.specification.stubs(:source).returns(
:svn => "file://#{fixture('subversion-repo')}/trunk"
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.download
downloader.clean
(@pod.root + '.svn').should.not.exist
end
end end
describe "for Http" do describe "for Http" do
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
it "download file and unzip it" do it "download file and unzip it" do
@pod.specification.stubs(:source).returns( @pod.top_specification.stubs(:source).returns(
:http => 'http://dl.google.com/googleadmobadssdk/googleadmobsearchadssdkios.zip' :http => 'http://dl.google.com/googleadmobadssdk/googleadmobsearchadssdkios.zip'
) )
downloader = Pod::Downloader.for_pod(@pod) downloader = Pod::Downloader.for_pod(@pod)
...@@ -165,18 +227,5 @@ describe "Pod::Downloader" do ...@@ -165,18 +227,5 @@ describe "Pod::Downloader" do
(@pod.root + 'GoogleAdMobSearchAdsSDK/GADSearchRequest.h').should.exist (@pod.root + 'GoogleAdMobSearchAdsSDK/GADSearchRequest.h').should.exist
(@pod.root + 'GoogleAdMobSearchAdsSDK/GADSearchRequest.h').read.strip.should =~ /Google Search Ads iOS SDK/ (@pod.root + 'GoogleAdMobSearchAdsSDK/GADSearchRequest.h').read.strip.should =~ /Google Search Ads iOS SDK/
end end
it "removes the .zip when cleaning" do
@pod.specification.stubs(:source).returns(
:http => 'http://dl.google.com/googleadmobadssdk/googleadmobsearchadssdkios.zip'
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.download
downloader.clean
(@pod.root + 'file.zip').should.not.exist
end
end end
end end
...@@ -4,6 +4,7 @@ describe Pod::Installer::UserProjectIntegrator do ...@@ -4,6 +4,7 @@ describe Pod::Installer::UserProjectIntegrator do
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
before do before do
config.silent = true
@sample_project_path = SpecHelper.create_sample_app_copy_from_fixture('SampleProject') @sample_project_path = SpecHelper.create_sample_app_copy_from_fixture('SampleProject')
config.project_root = @sample_project_path.dirname config.project_root = @sample_project_path.dirname
...@@ -11,7 +12,7 @@ describe Pod::Installer::UserProjectIntegrator do ...@@ -11,7 +12,7 @@ describe Pod::Installer::UserProjectIntegrator do
@podfile = Pod::Podfile.new do @podfile = Pod::Podfile.new do
platform :ios platform :ios
xcodeproj sample_project_path xcodeproj sample_project_path, 'Test' => :debug
link_with 'SampleProject' # this is an app target! link_with 'SampleProject' # this is an app target!
dependency 'JSONKit' dependency 'JSONKit'
...@@ -28,10 +29,6 @@ describe Pod::Installer::UserProjectIntegrator do ...@@ -28,10 +29,6 @@ describe Pod::Installer::UserProjectIntegrator do
@sample_project = Xcodeproj::Project.new(@sample_project_path) @sample_project = Xcodeproj::Project.new(@sample_project_path)
end end
after do
config.project_root = nil
end
it 'creates a workspace with a name matching the project' do it 'creates a workspace with a name matching the project' do
workspace_path = @sample_project_path.dirname + "SampleProject.xcworkspace" workspace_path = @sample_project_path.dirname + "SampleProject.xcworkspace"
workspace_path.should.exist workspace_path.should.exist
...@@ -41,12 +38,12 @@ describe Pod::Installer::UserProjectIntegrator do ...@@ -41,12 +38,12 @@ describe Pod::Installer::UserProjectIntegrator do
workspace = Xcodeproj::Workspace.new_from_xcworkspace(@sample_project_path.dirname + "SampleProject.xcworkspace") workspace = Xcodeproj::Workspace.new_from_xcworkspace(@sample_project_path.dirname + "SampleProject.xcworkspace")
workspace.projpaths.sort.should == %w{ Pods/Pods.xcodeproj SampleProject.xcodeproj } workspace.projpaths.sort.should == %w{ Pods/Pods.xcodeproj SampleProject.xcodeproj }
end end
it 'adds the Pods project to the workspace' do it 'adds the Pods project to the workspace' do
workspace = Xcodeproj::Workspace.new_from_xcworkspace(@sample_project_path.dirname + "SampleProject.xcworkspace") workspace = Xcodeproj::Workspace.new_from_xcworkspace(@sample_project_path.dirname + "SampleProject.xcworkspace")
workspace.projpaths.find { |path| path =~ /Pods.xcodeproj/ }.should.not.be.nil workspace.projpaths.find { |path| path =~ /Pods.xcodeproj/ }.should.not.be.nil
end end
it 'sets the Pods xcconfig as the base config for each build configuration' do it 'sets the Pods xcconfig as the base config for each build configuration' do
@podfile.target_definitions.each do |_, definition| @podfile.target_definitions.each do |_, definition|
target = @sample_project.targets.where(:name => definition.link_with.first) target = @sample_project.targets.where(:name => definition.link_with.first)
...@@ -69,7 +66,7 @@ describe Pod::Installer::UserProjectIntegrator do ...@@ -69,7 +66,7 @@ describe Pod::Installer::UserProjectIntegrator do
framework_build_phase.files.where(:name => definition.lib_name).should.not == nil framework_build_phase.files.where(:name => definition.lib_name).should.not == nil
end end
end end
it 'adds a Copy Pods Resources build phase to each target' do it 'adds a Copy Pods Resources build phase to each target' do
@podfile.target_definitions.each do |_, definition| @podfile.target_definitions.each do |_, definition|
target = @sample_project.targets.where(:name => definition.link_with.first) target = @sample_project.targets.where(:name => definition.link_with.first)
......
...@@ -9,11 +9,9 @@ module SpecHelper ...@@ -9,11 +9,9 @@ module SpecHelper
def specs_by_target def specs_by_target
@specs_by_target ||= super.tap do |hash| @specs_by_target ||= super.tap do |hash|
hash.values.flatten.each do |spec| hash.values.flatten.each do |spec|
unless spec.part_of_other_pod? source = spec.source
source = spec.source source[:git] = SpecHelper.fixture("integration/#{spec.name}").to_s
source[:git] = SpecHelper.fixture("integration/#{spec.name}").to_s spec.source = source
spec.source = source
end
end end
end end
end end
...@@ -28,37 +26,14 @@ else ...@@ -28,37 +26,14 @@ else
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
def create_config! def create_config!
Pod::Config.instance = nil
if ENV['VERBOSE_SPECS']
config.verbose = true
else
config.silent = true
end
config.repos_dir = fixture('spec-repos') config.repos_dir = fixture('spec-repos')
config.project_root = temporary_directory config.project_root = temporary_directory
config.doc_install = false
config.integrate_targets = false config.integrate_targets = false
end end
before do before do
fixture('spec-repos/master') # ensure the archive is unpacked fixture('spec-repos/master') # ensure the archive is unpacked
@config_before = config
create_config! create_config!
config.generate_docs = false
end
after do
Pod::Config.instance = @config_before
end
# This is so we can run at least the specs that don't use xcodebuild on Travis.
def with_xcodebuild_available
unless `which xcodebuild`.strip.empty?
yield
else
puts "\n[!] Skipping xcodebuild, because it can't be found."
end
end end
def should_successfully_perform(command) def should_successfully_perform(command)
...@@ -67,11 +42,14 @@ else ...@@ -67,11 +42,14 @@ else
$?.should.be.success $?.should.be.success
end end
puts " ! ".red << "Skipping xcodebuild based checks, because it can't be found." if `which xcodebuild`.strip.empty?
def should_xcodebuild(target_definition) def should_xcodebuild(target_definition)
return if `which xcodebuilda`.strip.empty?
target = target_definition target = target_definition
with_xcodebuild_available do with_xcodebuild_available do
Dir.chdir(config.project_pods_root) do Dir.chdir(config.project_pods_root) do
puts "\n[!] Compiling #{target.label} static library..." print "[!] Compiling #{target.label}...\r"
should_successfully_perform "xcodebuild -target '#{target.label}'" should_successfully_perform "xcodebuild -target '#{target.label}'"
lib_path = config.project_pods_root + "build/Release#{'-iphoneos' if target.platform == :ios}" + target.lib_name lib_path = config.project_pods_root + "build/Release#{'-iphoneos' if target.platform == :ios}" + target.lib_name
`lipo -info '#{lib_path}'`.should.include "architecture: #{target.platform == :ios ? 'armv7' : 'x86_64'}" `lipo -info '#{lib_path}'`.should.include "architecture: #{target.platform == :ios ? 'armv7' : 'x86_64'}"
...@@ -113,13 +91,13 @@ else ...@@ -113,13 +91,13 @@ else
installer.install! installer.install!
YAML.load(installer.lock_file.read).should == { YAML.load(installer.lock_file.read).should == {
'PODS' => [{ 'Reachability (1.2.3)' => ["ASIHTTPRequest (>= 1.8)"] }], 'PODS' => [ 'Reachability (1.2.3)' ],
'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"], # 'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"],
'DEPENDENCIES' => ["Reachability (from `#{url}')"] 'DEPENDENCIES' => ["Reachability (from `#{url}')"]
} }
end end
it "install a dummy source file" do it "installs a dummy source file" do
create_config! create_config!
podfile = Pod::Podfile.new do podfile = Pod::Podfile.new do
self.platform :ios self.platform :ios
...@@ -131,7 +109,7 @@ else ...@@ -131,7 +109,7 @@ else
s.source_files = 'JSONKit.*' s.source_files = 'JSONKit.*'
end end
end end
installer = SpecHelper::Installer.new(podfile) installer = SpecHelper::Installer.new(podfile)
installer.install! installer.install!
...@@ -157,6 +135,7 @@ else ...@@ -157,6 +135,7 @@ else
end end
end end
Pod::Specification.any_instance.stubs(:preserve_paths).returns(['CHANGELOG.md'])
installer = SpecHelper::Installer.new(podfile) installer = SpecHelper::Installer.new(podfile)
installer.install! installer.install!
...@@ -199,7 +178,16 @@ else ...@@ -199,7 +178,16 @@ else
unless `which appledoc`.strip.empty? unless `which appledoc`.strip.empty?
it "generates documentation of all pods by default" do it "generates documentation of all pods by default" do
create_config! ::Pod::Config.instance = nil
::Pod::Config.instance.tap do |c|
ENV['VERBOSE_SPECS'] ? c.verbose = true : c.silent = true
c.doc_install = false
c.repos_dir = fixture('spec-repos')
c.project_root = temporary_directory
c.integrate_targets = false
end
Pod::Generator::Documentation.any_instance.stubs(:already_installed?).returns(false)
podfile = Pod::Podfile.new do podfile = Pod::Podfile.new do
self.platform :ios self.platform :ios
...@@ -207,19 +195,16 @@ else ...@@ -207,19 +195,16 @@ else
dependency 'JSONKit', '1.4' dependency 'JSONKit', '1.4'
dependency 'SSToolkit' dependency 'SSToolkit'
end end
Pod::Generator::Documentation.any_instance.stubs(:already_installed?).returns(false)
installer = SpecHelper::Installer.new(podfile) installer = SpecHelper::Installer.new(podfile)
installer.install! installer.install!
doc = (config.project_pods_root + 'Documentation/JSONKit/html/index.html').read doc = (config.project_pods_root + 'Documentation/JSONKit/html/index.html').read
doc.should.include?('<title>JSONKit 1.4 Reference</title>') doc.should.include?('<title>JSONKit 1.4 Reference</title>')
doc = (config.project_pods_root + 'Documentation/SSToolkit/html/index.html').read doc = (config.project_pods_root + 'Documentation/SSToolkit/html/index.html').read
doc.should.include?('<title>SSToolkit 0.1.2 Reference</title>') doc.should.include?('<title>SSToolkit 1.0.0 Reference</title>')
end end
else else
puts "[!] Skipping documentation generation specs, because appledoc can't be found." puts " ! ".red << "Skipping documentation generation specs, because appledoc can't be found."
end end
end end
...@@ -249,12 +234,13 @@ else ...@@ -249,12 +234,13 @@ else
end end
# TODO add a simple source file which uses the compiled lib to check that it really really works # TODO add a simple source file which uses the compiled lib to check that it really really works
# TODO update for specification refactor
it "activates required pods and create a working static library xcode project" do it "activates required pods and create a working static library xcode project" do
podfile = Pod::Podfile.new do podfile = Pod::Podfile.new do
self.platform platform self.platform platform
xcodeproj 'dummy' xcodeproj 'dummy'
dependency 'Reachability', '> 2.0.5' if platform == :ios dependency 'Reachability', '> 2.0.5' if platform == :ios
dependency 'ASIWebPageRequest', '>= 1.8.1' # dependency 'ASIWebPageRequest', '>= 1.8.1'
dependency 'JSONKit', '>= 1.0' dependency 'JSONKit', '>= 1.0'
dependency 'SSZipArchive', '< 2' dependency 'SSZipArchive', '< 2'
end end
...@@ -264,14 +250,14 @@ else ...@@ -264,14 +250,14 @@ else
lock_file_contents = { lock_file_contents = {
'PODS' => [ 'PODS' => [
{ 'ASIHTTPRequest (1.8.1)' => ["Reachability"] }, # { 'ASIHTTPRequest (1.8.1)' => ["Reachability"] },
{ 'ASIWebPageRequest (1.8.1)' => ["ASIHTTPRequest (= 1.8.1)"] }, # { 'ASIWebPageRequest (1.8.1)' => ["ASIHTTPRequest (= 1.8.1)"] },
'JSONKit (1.5pre)', 'JSONKit (1.5pre)',
'Reachability (3.0.0)', 'Reachability (3.0.0)',
'SSZipArchive (0.1.2)', 'SSZipArchive (0.2.1)',
], ],
'DEPENDENCIES' => [ 'DEPENDENCIES' => [
"ASIWebPageRequest (>= 1.8.1)", # "ASIWebPageRequest (>= 1.8.1)",
"JSONKit (>= 1.0)", "JSONKit (>= 1.0)",
"Reachability (> 2.0.5)", "Reachability (> 2.0.5)",
"SSZipArchive (< 2)", "SSZipArchive (< 2)",
...@@ -279,9 +265,9 @@ else ...@@ -279,9 +265,9 @@ else
} }
unless platform == :ios unless platform == :ios
# No Reachability is required by ASIHTTPRequest on OSX # No Reachability is required by ASIHTTPRequest on OSX
lock_file_contents['DEPENDENCIES'].delete_at(2) lock_file_contents['DEPENDENCIES'].delete_at(1)
lock_file_contents['PODS'].delete_at(3) lock_file_contents['PODS'].delete_at(1)
lock_file_contents['PODS'][0] = 'ASIHTTPRequest (1.8.1)' # lock_file_contents['PODS'][0] = 'ASIHTTPRequest (1.8.1)'
end end
YAML.load(installer.lock_file.read).should == lock_file_contents YAML.load(installer.lock_file.read).should == lock_file_contents
...@@ -294,6 +280,7 @@ else ...@@ -294,6 +280,7 @@ else
end end
if platform == :ios if platform == :ios
# TODO: update for Specification Refactor
it "does not activate pods that are only part of other pods" do it "does not activate pods that are only part of other pods" do
spec = Pod::Podfile.new do spec = Pod::Podfile.new do
self.platform platform self.platform platform
...@@ -305,8 +292,9 @@ else ...@@ -305,8 +292,9 @@ else
installer.install! installer.install!
YAML.load(installer.lock_file.read).should == { YAML.load(installer.lock_file.read).should == {
'PODS' => [{ 'Reachability (2.0.4)' => ["ASIHTTPRequest (>= 1.8)"] }], # 'PODS' => [{ 'Reachability (2.0.4)' => ["ASIHTTPRequest (>= 1.8)"] }],
'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"], 'PODS' => [ 'Reachability (2.0.4)' ],
# 'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"],
'DEPENDENCIES' => ["Reachability (= 2.0.4)"] 'DEPENDENCIES' => ["Reachability (= 2.0.4)"]
} }
end end
...@@ -321,7 +309,7 @@ else ...@@ -321,7 +309,7 @@ else
installer = SpecHelper::Installer.new(spec) installer = SpecHelper::Installer.new(spec)
target_definition = installer.target_installers.first.target_definition target_definition = installer.target_installers.first.target_definition
installer.activated_specifications_for_target(target_definition).first.resources = 'LICEN*', 'Readme.*' installer.specs_by_target[target_definition].first.resources = 'LICEN*', 'Readme.*'
installer.install! installer.install!
contents = (config.project_pods_root + 'Pods-resources.sh').read contents = (config.project_pods_root + 'Pods-resources.sh').read
......
...@@ -12,47 +12,30 @@ $:.unshift((ROOT + 'lib').to_s) ...@@ -12,47 +12,30 @@ $:.unshift((ROOT + 'lib').to_s)
require 'cocoapods' require 'cocoapods'
$:.unshift((ROOT + 'spec').to_s) $:.unshift((ROOT + 'spec').to_s)
require 'spec_helper/color_output' require 'spec_helper/bacon'
require 'spec_helper/command' require 'spec_helper/command'
require 'spec_helper/fixture' require 'spec_helper/fixture'
require 'spec_helper/git'
require 'spec_helper/github' require 'spec_helper/github'
require 'spec_helper/temporary_directory' require 'spec_helper/temporary_directory'
require 'spec_helper/temporary_repos'
require 'spec_helper/config'
module Bacon module Bacon
extend ColorOutput
summary_at_exit
module FilterBacktraces
def handle_summary
ErrorLog.replace(ErrorLog.split("\n").reject do |line|
line =~ %r{(gems/mocha|spec_helper)}
end.join("\n").lstrip << "\n\n")
super
end
end
extend FilterBacktraces
class Context class Context
include Pod::Config::Mixin include Pod::Config::Mixin
include SpecHelper::Fixture include SpecHelper::Fixture
def argv(*argv) def argv(*argv)
Pod::Command::ARGV.new(argv) Pod::Command::ARGV.new(argv)
end end
require 'colored'
def xit(description, *args)
puts "- #{description} [DISABLED]".yellow
ErrorLog << "[DISABLED] #{self.name} #{description}\n\n"
end
end end
end end
config = Pod::Config.instance config = Pod::Config.instance
config.silent = true config.silent = true
config.repos_dir = SpecHelper.tmp_repos_path config.repos_dir = SpecHelper.tmp_repos_path
config.project_root = SpecHelper.temporary_directory
Pod::Specification::Statistics.instance.cache_file = nil
require 'tmpdir' require 'tmpdir'
...@@ -85,5 +68,3 @@ VCR.configure do |c| ...@@ -85,5 +68,3 @@ VCR.configure do |c|
c.allow_http_connections_when_no_cassette = true c.allow_http_connections_when_no_cassette = true
end end
Pod::Specification::Statistics.instance.cache_file = nil
module Bacon
summary_at_exit
@needs_first_put = true
module ColorOutput
# Graciously yanked from https://github.com/zen-cms/Zen-Core and subsequently modified
# MIT License
# Thanks, YorickPeterse! #:nodoc:
def handle_specification(name)
if @needs_first_put
@needs_first_put = false
puts
end
@specs_depth = @specs_depth || 0
puts spaces + name
@specs_depth += 1
yield
@specs_depth -= 1
puts if @specs_depth.zero?
end
#:nodoc:
def handle_requirement(description, disabled = false)
error = yield
if !error.empty?
puts "#{spaces}\e[31m- #{description} [FAILED]\e[0m"
elsif disabled
puts "#{spaces}\e[33m- #{description} [DISABLED]\e[0m"
else
puts "#{spaces}\e[32m- #{description}\e[0m"
end
end
#:nodoc:
def handle_summary
print ErrorLog if Backtraces
puts "\e[33m#{Counter[:disabled]} disabled specifications\n\e[0m" unless Counter[:disabled].zero?
puts "%d specifications (%d requirements), %d failures, %d errors" %
Counter.values_at(:specifications, :requirements, :failed, :errors)
end
#:nodoc:
def spaces
return ' ' * @specs_depth
end
end
extend ColorOutput
module FilterBacktraces
def handle_summary
ErrorLog.replace(ErrorLog.split("\n").reject do |line|
line =~ %r{(gems/mocha|spec_helper)}
end.join("\n").lstrip << "\n\n")
super
end
end
extend FilterBacktraces
class Context
def xit(description, *args)
Counter[:disabled] += 1
Bacon.handle_requirement(description, true) {[]}
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
# Restores the config to the default state before each requirement
module Bacon
class Context
old_run_requirement = instance_method(:run_requirement)
define_method(:run_requirement) do |description, spec|
::Pod::Config.instance = nil
::Pod::Config.instance.tap do |c|
ENV['VERBOSE_SPECS'] ? c.verbose = true : c.silent = true
c.repos_dir = SpecHelper.tmp_repos_path
c.project_root = SpecHelper.temporary_directory
c.doc_install = false
c.generate_docs = false
end
old_run_requirement.bind(self).call(description, spec)
end
end
end
...@@ -2,22 +2,18 @@ require 'spec_helper/temporary_directory' ...@@ -2,22 +2,18 @@ require 'spec_helper/temporary_directory'
module SpecHelper module SpecHelper
def self.tmp_repos_path def self.tmp_repos_path
Git.tmp_repos_path TemporaryRepos.tmp_repos_path
end end
module Git module TemporaryRepos
extend Pod::Executable
executable :git
def tmp_repos_path def tmp_repos_path
SpecHelper.temporary_directory + 'cocoapods' SpecHelper.temporary_directory + 'cocoapods'
end end
module_function :tmp_repos_path module_function :tmp_repos_path
def tmp_master_repo_path
tmp_repos_path + 'master'
end
extend Pod::Executable
executable :git
alias_method :git_super, :git alias_method :git_super, :git
def git(repo, command) def git(repo, command)
Dir.chdir(tmp_repos_path + repo) do Dir.chdir(tmp_repos_path + repo) do
...@@ -42,5 +38,12 @@ module SpecHelper ...@@ -42,5 +38,12 @@ module SpecHelper
git(name, 'add README') git(name, 'add README')
git(name, 'commit -m "changed"') git(name, 'commit -m "changed"')
end end
def self.extended(base)
base.before do
tmp_repos_path.mkpath
end
end
end end
end end
...@@ -19,7 +19,7 @@ describe "Pod::Command::Spec::Linter" do ...@@ -19,7 +19,7 @@ describe "Pod::Command::Spec::Linter" do
it "fails a specifications that does not contain the minimum required attributes" do it "fails a specifications that does not contain the minimum required attributes" do
spec, file = write_podspec('Pod::Spec.new do |s| end') spec, file = write_podspec('Pod::Spec.new do |s| end')
linter = Pod::Command::Spec::Linter.new(spec, file) linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = true, true linter.lenient, linter.quick = true, true
linter.lint.should == false linter.lint.should == false
linter.errors.join(' | ') =~ /name.*version.*summary.*homepage.*authors.*(source.*part_of).*source_files/ linter.errors.join(' | ') =~ /name.*version.*summary.*homepage.*authors.*(source.*part_of).*source_files/
...@@ -27,7 +27,7 @@ describe "Pod::Command::Spec::Linter" do ...@@ -27,7 +27,7 @@ describe "Pod::Command::Spec::Linter" do
it "fails specifications if the name does not match the name of the file" do it "fails specifications if the name does not match the name of the file" do
spec, file = write_podspec(stub_podspec(/s.name *= 'JSONKit'/, "s.name = 'JSONKitAAA'")) spec, file = write_podspec(stub_podspec(/s.name *= 'JSONKit'/, "s.name = 'JSONKitAAA'"))
linter = Pod::Command::Spec::Linter.new(spec, file) linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = true, true linter.lenient, linter.quick = true, true
linter.lint.should == false linter.lint.should == false
linter.errors.count.should == 1 linter.errors.count.should == 1
...@@ -36,16 +36,16 @@ describe "Pod::Command::Spec::Linter" do ...@@ -36,16 +36,16 @@ describe "Pod::Command::Spec::Linter" do
it "fails a specification if a path starts with a slash" do it "fails a specification if a path starts with a slash" do
spec, file = write_podspec(stub_podspec(/s.source_files = 'JSONKit\.\*'/, "s.source_files = '/JSONKit.*'")) spec, file = write_podspec(stub_podspec(/s.source_files = 'JSONKit\.\*'/, "s.source_files = '/JSONKit.*'"))
linter = Pod::Command::Spec::Linter.new(spec, file) linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = true, true linter.lenient, linter.quick = true, true
linter.lint.should == false linter.lint.should == false
linter.errors.count.should == 1 linter.errors.count.should == 1
linter.errors[0].should =~ /Paths cannot start with a slash/ linter.errors[0].should =~ /Paths cannot start with a slash/
end end
it "fails a specification if the plafrom is unrecognized" do it "fails a specification if the platform is unrecognized" do
spec, file = write_podspec(stub_podspec(/s.name *= 'JSONKit'/, "s.name = 'JSONKit'\ns.platform = :iososx\n")) spec, file = write_podspec(stub_podspec(/s.name *= 'JSONKit'/, "s.name = 'JSONKit'\ns.platform = :iososx\n"))
linter = Pod::Command::Spec::Linter.new(spec, file) linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = true, true linter.lenient, linter.quick = true, true
linter.lint.should == false linter.lint.should == false
linter.errors.count.should == 1 linter.errors.count.should == 1
...@@ -53,8 +53,8 @@ describe "Pod::Command::Spec::Linter" do ...@@ -53,8 +53,8 @@ describe "Pod::Command::Spec::Linter" do
end end
it "fails validation if the specification contains warnings" do it "fails validation if the specification contains warnings" do
spec, file = write_podspec(stub_podspec) spec, file = write_podspec(stub_podspec(/.*license.*/, ""))
linter = Pod::Command::Spec::Linter.new(spec, file) linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = false, true linter.lenient, linter.quick = false, true
linter.lint.should == false linter.lint.should == false
linter.errors.should.be.empty linter.errors.should.be.empty
...@@ -62,8 +62,8 @@ describe "Pod::Command::Spec::Linter" do ...@@ -62,8 +62,8 @@ describe "Pod::Command::Spec::Linter" do
end end
it "validates in lenient mode if there are no erros but there are warnings" do it "validates in lenient mode if there are no erros but there are warnings" do
spec, file = write_podspec(stub_podspec) spec, file = write_podspec(stub_podspec(/.*license.*/, ""))
linter = Pod::Command::Spec::Linter.new(spec, file) linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = true, true linter.lenient, linter.quick = true, true
linter.lint.should == true linter.lint.should == true
linter.errors.should.be.empty linter.errors.should.be.empty
...@@ -72,7 +72,7 @@ describe "Pod::Command::Spec::Linter" do ...@@ -72,7 +72,7 @@ describe "Pod::Command::Spec::Linter" do
it "respects quick mode" do it "respects quick mode" do
spec, file = write_podspec(stub_podspec) spec, file = write_podspec(stub_podspec)
linter = Pod::Command::Spec::Linter.new(spec, file) linter = Pod::Command::Spec::Linter.new(spec)
linter.expects(:peform_multiplatform_analysis).never linter.expects(:peform_multiplatform_analysis).never
linter.expects(:install_pod).never linter.expects(:install_pod).never
linter.expects(:xcodebuild_output_for_platfrom).never linter.expects(:xcodebuild_output_for_platfrom).never
...@@ -83,16 +83,16 @@ describe "Pod::Command::Spec::Linter" do ...@@ -83,16 +83,16 @@ describe "Pod::Command::Spec::Linter" do
it "produces deprecation notices" do it "produces deprecation notices" do
spec, file = write_podspec(stub_podspec(/s\.source_files = 'JSONKit\.\*'/, "s.source_files = 'JSONKit.*'\n if config.ios?\nend")) spec, file = write_podspec(stub_podspec(/s\.source_files = 'JSONKit\.\*'/, "s.source_files = 'JSONKit.*'\n if config.ios?\nend"))
linter = Pod::Command::Spec::Linter.new(spec, file) linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = false, true linter.lenient, linter.quick = false, true
linter.lint.should == false linter.lint.should == false
linter.errors.should.be.empty linter.errors.should.be.empty
linter.warnings.join(' | ').should =~ /`config.ios\?' and `config.osx\?' are deprecated and will be removed in version 0.7/ linter.warnings.join(' | ').should =~ /`config.ios\?' and `config.osx\?' are deprecated/
end end
it "uses xcodebuild to generate notes and warnings" do it "uses xcodebuild to generate notes and warnings" do
spec, file = write_podspec(stub_podspec) spec, file = write_podspec(stub_podspec)
linter = Pod::Command::Spec::Linter.new(spec, file) linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = false, false linter.lenient, linter.quick = false, false
linter.lint.should == false linter.lint.should == false
linter.notes.join(' | ').should.include "JSONKit/JSONKit.m:1640:27: warning: equality comparison with extraneous parentheses" unless `which xcodebuild`.strip.empty? linter.notes.join(' | ').should.include "JSONKit/JSONKit.m:1640:27: warning: equality comparison with extraneous parentheses" unless `which xcodebuild`.strip.empty?
...@@ -100,10 +100,10 @@ describe "Pod::Command::Spec::Linter" do ...@@ -100,10 +100,10 @@ describe "Pod::Command::Spec::Linter" do
it "checks for file patterns" do it "checks for file patterns" do
spec, file = write_podspec(stub_podspec(/s\.source_files = 'JSONKit\.\*'/, "s.source_files = 'JSONKit.*'\ns.resources = 'WRONG_FOLDER'")) spec, file = write_podspec(stub_podspec(/s\.source_files = 'JSONKit\.\*'/, "s.source_files = 'JSONKit.*'\ns.resources = 'WRONG_FOLDER'"))
linter = Pod::Command::Spec::Linter.new(spec, file) linter = Pod::Command::Spec::Linter.new(spec)
linter.stubs(:xcodebuild_output_for_platfrom).returns([]) linter.stubs(:xcodebuild_output).returns([])
linter.lenient, linter.quick = false, false linter.lenient, linter.quick = false, false
linter.lint.should == false linter.lint.should == false
linter.errors.join(' | ').should.include "[resources = 'WRONG_FOLDER'] -> did not match any file" linter.errors.join(' | ').should.include "The resources did not match any file"
end end
end end
...@@ -15,12 +15,3 @@ describe "Pod::Command::Repo" do ...@@ -15,12 +15,3 @@ describe "Pod::Command::Repo" do
end end
end end
describe "Pod::Command::Install" do
it "tells the user that no Podfile or podspec was found in the current working dir" do
command = Pod::Command::Install.new(argv)
exception = lambda {
command.run
}.should.raise Pod::Informative
exception.message.should.include "No `Podfile' found in the current working directory."
end
end
...@@ -2,14 +2,9 @@ require File.expand_path('../../spec_helper', __FILE__) ...@@ -2,14 +2,9 @@ require File.expand_path('../../spec_helper', __FILE__)
describe "Pod::Config" do describe "Pod::Config" do
before do before do
@original_config = config
Pod::Config.instance = nil Pod::Config.instance = nil
end end
after do
Pod::Config.instance = @original_config
end
it "returns the singleton config instance" do it "returns the singleton config instance" do
config.should.be.instance_of Pod::Config config.should.be.instance_of Pod::Config
end end
...@@ -22,7 +17,9 @@ describe "Pod::Config" do ...@@ -22,7 +17,9 @@ describe "Pod::Config" do
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
it "returns the path to the project root" do it "returns the path to the project root" do
config.project_root = nil
config.project_root.should == Pathname.pwd config.project_root.should == Pathname.pwd
config.project_root = temporary_directory
end end
it "returns the path to the project Podfile if it exists" do it "returns the path to the project Podfile if it exists" do
......
...@@ -7,15 +7,6 @@ describe "Pod::Dependency" do ...@@ -7,15 +7,6 @@ describe "Pod::Dependency" do
dep1.merge(dep2).should == Pod::Dependency.new('bananas', '>= 1.8', '1.9') dep1.merge(dep2).should == Pod::Dependency.new('bananas', '>= 1.8', '1.9')
end end
it "is equal to another dependency if `part_of_other_pod' is the same" do
dep1 = Pod::Dependency.new('bananas', '>= 1')
dep1.only_part_of_other_pod = true
dep2 = Pod::Dependency.new('bananas', '>= 1')
dep1.should.not == dep2
dep2.only_part_of_other_pod = true
dep1.should == dep2
end
it "returns the name of the dependency, or the name of the pod of which this is a subspec" do it "returns the name of the dependency, or the name of the pod of which this is a subspec" do
dep = Pod::Dependency.new('RestKit') dep = Pod::Dependency.new('RestKit')
dep.top_level_spec_name.should == 'RestKit' dep.top_level_spec_name.should == 'RestKit'
......
...@@ -2,12 +2,11 @@ require File.expand_path('../../spec_helper', __FILE__) ...@@ -2,12 +2,11 @@ require File.expand_path('../../spec_helper', __FILE__)
def stub_pod_with_source(source_options) def stub_pod_with_source(source_options)
specification = stub( specification = stub(
:part_of_other_pod? => false,
:source => source_options :source => source_options
) )
stub('pod') do stub('pod') do
stubs(:root).returns(temporary_sandbox.root) stubs(:root).returns(temporary_sandbox.root)
stubs(:specification).returns(specification) stubs(:top_specification).returns(specification)
end end
end end
...@@ -19,10 +18,10 @@ describe "Pod::Downloader" do ...@@ -19,10 +18,10 @@ describe "Pod::Downloader" do
downloader.url.should == 'http://banana-corp.local/banana-lib.git' downloader.url.should == 'http://banana-corp.local/banana-lib.git'
downloader.options.should == { :tag => 'v1.0' } downloader.options.should == { :tag => 'v1.0' }
end end
it 'returns a github downloader when the :git URL is on github' do it 'returns a github downloader when the :git URL is on github' do
pod = Pod::LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), temporary_sandbox, Pod::Platform.ios) pod = Pod::LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), temporary_sandbox, Pod::Platform.ios)
pod.specification.stubs(:source).returns(:git => "git://github.com/CocoaPods/CocoaPods") pod.top_specification.stubs(:source).returns(:git => "git://github.com/CocoaPods/CocoaPods")
downloader = Pod::Downloader.for_pod(pod) downloader = Pod::Downloader.for_pod(pod)
downloader.should.be.instance_of Pod::Downloader::GitHub downloader.should.be.instance_of Pod::Downloader::GitHub
end end
...@@ -36,21 +35,21 @@ describe Pod::Downloader::GitHub do ...@@ -36,21 +35,21 @@ describe Pod::Downloader::GitHub do
)) ))
downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master" downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master"
end end
it 'can convert private HTTP repository URLs to the tarball URL' do it 'can convert private HTTP repository URLs to the tarball URL' do
downloader = Pod::Downloader.for_pod(stub_pod_with_source( downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:git => "https://lukeredpath@github.com/CocoaPods/CocoaPods.git" :git => "https://lukeredpath@github.com/CocoaPods/CocoaPods.git"
)) ))
downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master" downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master"
end end
it 'can convert private SSH repository URLs to the tarball URL' do it 'can convert private SSH repository URLs to the tarball URL' do
downloader = Pod::Downloader.for_pod(stub_pod_with_source( downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:git => "git@github.com:CocoaPods/CocoaPods.git" :git => "git@github.com:CocoaPods/CocoaPods.git"
)) ))
downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master" downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master"
end end
it 'can convert public git protocol repository URLs to the tarball URL' do it 'can convert public git protocol repository URLs to the tarball URL' do
downloader = Pod::Downloader.for_pod(stub_pod_with_source( downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:git => "git://github.com/CocoaPods/CocoaPods.git" :git => "git://github.com/CocoaPods/CocoaPods.git"
......
...@@ -18,11 +18,8 @@ describe Pod::Generator::Documentation do ...@@ -18,11 +18,8 @@ describe Pod::Generator::Documentation do
} }
end end
it 'returns the Pod documentation documentation files' do it 'returns the Pod documentation header files' do
@doc_installer.files.sort.should == [ @doc_installer.files.sort.should == %w[ Classes/Banana.h ].sort
(@pod.root + "Classes/Banana.m").to_s,
(@pod.root + "Classes/Banana.h").to_s,
].sort
end end
it 'returns the Pod documentation options' do it 'returns the Pod documentation options' do
......
...@@ -6,7 +6,7 @@ describe Pod::Generator::DummySource do ...@@ -6,7 +6,7 @@ describe Pod::Generator::DummySource do
before do before do
setup_temporary_directory setup_temporary_directory
end end
after do after do
teardown_temporary_directory teardown_temporary_directory
end end
...@@ -21,5 +21,5 @@ describe Pod::Generator::DummySource do ...@@ -21,5 +21,5 @@ describe Pod::Generator::DummySource do
@implementation PodsDummy @implementation PodsDummy
@end @end
EOS EOS
end end
end end
...@@ -2,12 +2,11 @@ require File.expand_path('../../spec_helper', __FILE__) ...@@ -2,12 +2,11 @@ require File.expand_path('../../spec_helper', __FILE__)
def stub_pod_with_source(source_options) def stub_pod_with_source(source_options)
specification = stub( specification = stub(
:part_of_other_pod? => false,
:source => source_options :source => source_options
) )
stub('pod') do stub('pod') do
stubs(:root).returns(temporary_sandbox.root) stubs(:root).returns(temporary_sandbox.root)
stubs(:specification).returns(specification) stubs(:top_specification).returns(specification)
end end
end end
...@@ -19,20 +18,20 @@ describe Pod::Downloader::Http do ...@@ -19,20 +18,20 @@ describe Pod::Downloader::Http do
)) ))
downloader.should.be.instance_of Pod::Downloader::Http downloader.should.be.instance_of Pod::Downloader::Http
downloader.type.should == :zip downloader.type.should == :zip
downloader = Pod::Downloader.for_pod(stub_pod_with_source( downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.tar' :http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.tar'
)) ))
downloader.should.be.instance_of Pod::Downloader::Http downloader.should.be.instance_of Pod::Downloader::Http
downloader.type.should == :tar downloader.type.should == :tar
downloader = Pod::Downloader.for_pod(stub_pod_with_source( downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.tgz' :http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.tgz'
)) ))
downloader.should.be.instance_of Pod::Downloader::Http downloader.should.be.instance_of Pod::Downloader::Http
downloader.type.should == :tgz downloader.type.should == :tgz
downloader = Pod::Downloader.for_pod(stub_pod_with_source( downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0', :http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0',
:type => :zip :type => :zip
...@@ -40,7 +39,7 @@ describe Pod::Downloader::Http do ...@@ -40,7 +39,7 @@ describe Pod::Downloader::Http do
downloader.should.be.instance_of Pod::Downloader::Http downloader.should.be.instance_of Pod::Downloader::Http
downloader.type.should == :zip downloader.type.should == :zip
end end
it 'should download file and extract it with proper type' do it 'should download file and extract it with proper type' do
downloader = Pod::Downloader.for_pod(stub_pod_with_source( downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.zip' :http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.zip'
...@@ -48,28 +47,28 @@ describe Pod::Downloader::Http do ...@@ -48,28 +47,28 @@ describe Pod::Downloader::Http do
downloader.expects(:download_file).with(anything()) downloader.expects(:download_file).with(anything())
downloader.expects(:extract_with_type).with(anything(), :zip).at_least_once downloader.expects(:extract_with_type).with(anything(), :zip).at_least_once
downloader.download downloader.download
downloader = Pod::Downloader.for_pod(stub_pod_with_source( downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.tgz' :http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.tgz'
)) ))
downloader.expects(:download_file).with(anything()) downloader.expects(:download_file).with(anything())
downloader.expects(:extract_with_type).with(anything(), :tgz).at_least_once downloader.expects(:extract_with_type).with(anything(), :tgz).at_least_once
downloader.download downloader.download
end end
it 'should raise error when unsupported filetype is pass' do it 'should raise error when unsupported filetype is pass' do
downloader = Pod::Downloader.for_pod(stub_pod_with_source( downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.rar' :http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.rar'
)) ))
downloader.expects(:download).raises(Pod::Downloader::Http::UnsupportedFileTypeError) downloader.expects(:download).raises(Pod::Downloader::Http::UnsupportedFileTypeError)
downloader.download rescue nil downloader.download rescue nil
downloader = Pod::Downloader.for_pod(stub_pod_with_source( downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0', :http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0',
:type => :rar :type => :rar
)) ))
downloader.expects(:download).raises(Pod::Downloader::Http::UnsupportedFileTypeError) downloader.expects(:download).raises(Pod::Downloader::Http::UnsupportedFileTypeError)
downloader.download rescue nil downloader.download rescue nil
end end
end end
...@@ -22,38 +22,43 @@ describe Pod::Installer::TargetInstaller do ...@@ -22,38 +22,43 @@ describe Pod::Installer::TargetInstaller do
@specification = fixture_spec('banana-lib/BananaLib.podspec') @specification = fixture_spec('banana-lib/BananaLib.podspec')
@pods = [Pod::LocalPod.new(@specification, @sandbox, Pod::Platform.ios)] @pods = [Pod::LocalPod.new(@specification, @sandbox, Pod::Platform.ios)]
end end
def do_install! def do_install!
@installer.install!(@pods, @sandbox) @installer.install!(@pods, @sandbox)
end end
it 'adds a new static library target to the project' do it 'adds a new static library target to the project' do
do_install! do_install!
@project.targets.count.should == 1 @project.targets.count.should == 1
@project.targets.first.name.should == @target_definition.label @project.targets.first.name.should == @target_definition.label
end end
it "adds the user's build configurations to the target" do
@project.user_build_configurations = { 'Debug' => :debug, 'Release' => :release, 'AppStore' => :release, 'Test' => :debug }
do_install!
@project.targets.first.build_configurations.map(&:name).sort.should == %w{ AppStore Debug Release Test }
end
it 'adds each pod to the static library target' do it 'adds each pod to the static library target' do
@pods[0].expects(:add_to_target).with(instance_of(Xcodeproj::Project::Object::PBXNativeTarget)) @pods[0].expects(:add_to_target).with(instance_of(Xcodeproj::Project::Object::PBXNativeTarget))
do_install! do_install!
end end
it 'tells each pod to link its headers' do it 'tells each pod to link its headers' do
@pods[0].expects(:link_headers) @pods[0].expects(:link_headers)
do_install! do_install!
end end
it 'adds the sandbox header search paths to the xcconfig, with quotes' do it 'adds the sandbox header search paths to the xcconfig, with quotes' do
do_install! do_install!
@installer.xcconfig.to_hash['HEADER_SEARCH_PATHS'].should.include("\"#{@sandbox.header_search_paths.join('" "')}\"") @installer.xcconfig.to_hash['HEADER_SEARCH_PATHS'].should.include("\"#{@sandbox.header_search_paths.join('" "')}\"")
end end
it 'does not add the -fobjc-arc to OTHER_LDFLAGS by default as Xcode 4.3.2 does not support it' do it 'does not add the -fobjc-arc to OTHER_LDFLAGS by default as Xcode 4.3.2 does not support it' do
do_install! do_install!
@installer.xcconfig.to_hash['OTHER_LDFLAGS'].split(" ").should.not.include("-fobjc-arc") @installer.xcconfig.to_hash['OTHER_LDFLAGS'].split(" ").should.not.include("-fobjc-arc")
end end
it 'adds the -fobjc-arc to OTHER_LDFLAGS if any pods require arc (to support non-ARC projects on iOS 4.0)' do it 'adds the -fobjc-arc to OTHER_LDFLAGS if any pods require arc (to support non-ARC projects on iOS 4.0)' do
@podfile.stubs(:set_arc_compatibility_flag? => true) @podfile.stubs(:set_arc_compatibility_flag? => true)
@specification.stubs(:requires_arc).returns(true) @specification.stubs(:requires_arc).returns(true)
......
...@@ -21,10 +21,6 @@ describe Pod::Installer::UserProjectIntegrator do ...@@ -21,10 +21,6 @@ describe Pod::Installer::UserProjectIntegrator do
@integrator = Pod::Installer::UserProjectIntegrator.new(@podfile) @integrator = Pod::Installer::UserProjectIntegrator.new(@podfile)
end end
after do
config.project_root = nil
end
it "returns the path to the workspace from the Podfile" do it "returns the path to the workspace from the Podfile" do
@integrator.workspace_path.should == config.project_root + 'SampleProject.xcworkspace' @integrator.workspace_path.should == config.project_root + 'SampleProject.xcworkspace'
end end
...@@ -52,12 +48,12 @@ describe Pod::Installer::UserProjectIntegrator do ...@@ -52,12 +48,12 @@ describe Pod::Installer::UserProjectIntegrator do
end end
it "raises if no project could be selected" do it "raises if no project could be selected" do
@target_integrator.target_definition.stubs(:xcodeproj).returns(nil) @target_integrator.target_definition.user_project.stubs(:path).returns(nil)
lambda { @target_integrator.user_project_path }.should.raise Pod::Informative lambda { @target_integrator.user_project_path }.should.raise Pod::Informative
end end
it "raises if the project path doesn't exist" do it "raises if the project path doesn't exist" do
@target_integrator.target_definition.xcodeproj.stubs(:exist?).returns(false) @target_integrator.target_definition.user_project.path.stubs(:exist?).returns(false)
lambda { @target_integrator.user_project_path }.should.raise Pod::Informative lambda { @target_integrator.user_project_path }.should.raise Pod::Informative
end end
......
...@@ -2,24 +2,18 @@ require File.expand_path('../../spec_helper', __FILE__) ...@@ -2,24 +2,18 @@ require File.expand_path('../../spec_helper', __FILE__)
describe "Pod::Installer" do describe "Pod::Installer" do
before do before do
@config_before = config
Pod::Config.instance = nil
config.silent = true
config.repos_dir = fixture('spec-repos') config.repos_dir = fixture('spec-repos')
config.project_pods_root = fixture('integration') config.project_pods_root = fixture('integration')
end end
after do describe "by default" do
Pod::Config.instance = @config_before
end
describe ", by default," do
before do before do
@xcconfig = Pod::Installer.new(Pod::Podfile.new do podfile = Pod::Podfile.new do
platform :ios platform :ios
xcodeproj 'MyProject' xcodeproj 'MyProject'
dependency 'JSONKit' dependency 'JSONKit'
end).target_installers.first.xcconfig.to_hash end
@xcconfig = Pod::Installer.new(podfile).target_installers.first.xcconfig.to_hash
end end
it "sets the header search paths where installed Pod headers can be found" do it "sets the header search paths where installed Pod headers can be found" do
...@@ -41,7 +35,7 @@ describe "Pod::Installer" do ...@@ -41,7 +35,7 @@ describe "Pod::Installer" do
dependency 'ASIHTTPRequest' dependency 'ASIHTTPRequest'
end end
installer = Pod::Installer.new(podfile) installer = Pod::Installer.new(podfile)
pods = installer.activated_specifications.map do |spec| pods = installer.specifications.map do |spec|
Pod::LocalPod.new(spec, installer.sandbox, podfile.target_definitions[:default].platform) Pod::LocalPod.new(spec, installer.sandbox, podfile.target_definitions[:default].platform)
end end
expected = pods.map { |pod| pod.header_files }.flatten.map { |header| config.project_pods_root + header } expected = pods.map { |pod| pod.header_files }.flatten.map { |header| config.project_pods_root + header }
...@@ -59,4 +53,14 @@ describe "Pod::Installer" do ...@@ -59,4 +53,14 @@ describe "Pod::Installer" do
installer = Pod::Installer.new(podfile) installer = Pod::Installer.new(podfile)
installer.target_installers.map(&:target_definition).map(&:name).should == [:not_empty] installer.target_installers.map(&:target_definition).map(&:name).should == [:not_empty]
end end
it "adds the user's build configurations" do
path = fixture('SampleProject/SampleProject.xcodeproj')
podfile = Pod::Podfile.new do
platform :ios
xcodeproj path, 'App Store' => :release
end
installer = Pod::Installer.new(podfile)
installer.project.build_configurations.map(&:name).sort.should == ['App Store', 'Debug', 'Release', 'Test']
end
end end
...@@ -3,178 +3,245 @@ require File.expand_path('../../spec_helper', __FILE__) ...@@ -3,178 +3,245 @@ require File.expand_path('../../spec_helper', __FILE__)
describe Pod::LocalPod do describe Pod::LocalPod do
# a LocalPod represents a local copy of the dependency, inside the pod root, built from a spec # a LocalPod represents a local copy of the dependency, inside the pod root, built from a spec
describe "in general" do
before do before do
@sandbox = temporary_sandbox @sandbox = temporary_sandbox
@pod = Pod::LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), @sandbox, Pod::Platform.new(:ios)) @pod = Pod::LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), @sandbox, Pod::Platform.new(:ios))
copy_fixture_to_pod('banana-lib', @pod) copy_fixture_to_pod('banana-lib', @pod)
end end
it 'returns the Pod root directory path' do
@pod.root.should == @sandbox.root + 'BananaLib'
end
it "creates it's own root directory if it doesn't exist" do
@pod.create
File.directory?(@pod.root).should.be.true
end
it "can execute a block within the context of it's root" do
@pod.chdir { FileUtils.touch("foo") }
Pathname(@pod.root + "foo").should.exist
end
it 'can delete itself' do
@pod.create
@pod.implode
@pod.root.should.not.exist
end
it 'returns an expanded list of source files, relative to the sandbox root' do
@pod.source_files.sort.should == [
Pathname.new("BananaLib/Classes/Banana.m"),
Pathname.new("BananaLib/Classes/Banana.h")
].sort
end
it 'returns an expanded list of absolute clean paths' do
@pod.clean_paths.should == [@sandbox.root + "BananaLib/sub-dir"]
end
it 'returns an expanded list of resources, relative to the sandbox root' do
@pod.resources.should == [Pathname.new("BananaLib/Resources/logo-sidebar.png")]
end
it 'returns a list of header files' do
@pod.header_files.should == [Pathname.new("BananaLib/Classes/Banana.h")]
end
it 'returns some license text' do
@pod.license_text.should == "Permission is hereby granted ..."
end
it 'can clean up after itself' do it 'returns the Pod root directory path' do
@pod.clean_paths.tap do |paths| @pod.root.should == @sandbox.root + 'BananaLib'
@pod.clean end
paths.each do |path| it "creates it's own root directory if it doesn't exist" do
path.should.not.exist @pod.create
end File.directory?(@pod.root).should.be.true
end
it "can execute a block within the context of it's root" do
@pod.chdir { FileUtils.touch("foo") }
Pathname(@pod.root + "foo").should.exist
end
it 'can delete itself' do
@pod.create
@pod.implode
@pod.root.should.not.exist
end
it 'returns an expanded list of source files, relative to the sandbox root' do
@pod.source_files.sort.should == [
Pathname.new("BananaLib/Classes/Banana.m"),
Pathname.new("BananaLib/Classes/Banana.h")
].sort
end
it 'returns an expanded list of absolute clean paths' do
#TODO: there are some temporary files that prevent a complete check
@pod.clean_paths.map { |p| p.relative_path_from(@sandbox.root).to_s }.should.include 'BananaLib/sub-dir/sub-dir-2/somefile.txt'
end
it 'returns an expanded list of resources, relative to the sandbox root' do
@pod.resources.should == [Pathname.new("BananaLib/Resources/logo-sidebar.png")]
end
it 'returns a list of header files' do
@pod.header_files.should == [Pathname.new("BananaLib/Classes/Banana.h")]
end
it "can link it's headers into the sandbox" do
@pod.link_headers
expected_header_path = @sandbox.headers_root + "BananaLib/Banana.h"
expected_header_path.should.be.symlink
File.read(expected_header_path).should == (@sandbox.root + @pod.header_files[0]).read
end
it "can add it's source files to an Xcode project target" do
target = mock('target')
target.expects(:add_source_file).with(Pathname.new("BananaLib/Classes/Banana.h"), anything, anything)
target.expects(:add_source_file).with(Pathname.new("BananaLib/Classes/Banana.m"), anything, anything)
@pod.add_to_target(target)
end
it "can add it's source files to a target with any specially configured compiler flags" do
@pod.top_specification.compiler_flags = '-d some_flag'
target = mock('target')
target.expects(:add_source_file).twice.with(anything, anything, "-d some_flag")
@pod.add_to_target(target)
end
it "returns the platform" do
@pod.platform.should == :ios
end end
end end
it "can link it's headers into the sandbox" do
@pod.link_headers
expected_header_path = @sandbox.headers_root + "BananaLib/Banana.h"
expected_header_path.should.be.symlink
File.read(expected_header_path).should == (@sandbox.root + @pod.header_files[0]).read
end
it "can add it's source files to an Xcode project target" do
target = mock('target')
target.expects(:add_source_file).with(Pathname.new("BananaLib/Classes/Banana.m"), anything, anything)
@pod.add_to_target(target)
end
it "can add it's source files to a target with any specially configured compiler flags" do
@pod.specification.compiler_flags = '-d some_flag'
target = mock('target')
target.expects(:add_source_file).with(anything, anything, "-d some_flag")
@pod.add_to_target(target)
end
end
describe "A Pod::LocalPod, with installed source," do describe "with installed source," do
#before do #before do
#config.project_pods_root = fixture('integration') #config.project_pods_root = fixture('integration')
#podspec = fixture('spec-repos/master/SSZipArchive/0.1.0/SSZipArchive.podspec') #podspec = fixture('spec-repos/master/SSZipArchive/0.1.0/SSZipArchive.podspec')
#@spec = Pod::Specification.from_file(podspec) #@spec = Pod::Specification.from_file(podspec)
#@destroot = fixture('integration/SSZipArchive') #@destroot = fixture('integration/SSZipArchive')
#end #end
#after do xit "returns the list of files that the source_files pattern expand to" do
#config.project_pods_root = nil files = @destroot.glob('**/*.{h,c,m}')
#end files = files.map { |file| file.relative_path_from(config.project_pods_root) }
@spec.expanded_source_files[:ios].sort.should == files.sort
xit "returns the list of files that the source_files pattern expand to" do end
files = @destroot.glob('**/*.{h,c,m}')
files = files.map { |file| file.relative_path_from(config.project_pods_root) }
@spec.expanded_source_files[:ios].sort.should == files.sort
end
xit "returns the list of headers" do xit "returns the list of headers" do
files = @destroot.glob('**/*.h') files = @destroot.glob('**/*.h')
files = files.map { |file| file.relative_path_from(config.project_pods_root) } files = files.map { |file| file.relative_path_from(config.project_pods_root) }
@spec.header_files[:ios].sort.should == files.sort @spec.header_files[:ios].sort.should == files.sort
end end
xit "returns a hash of mappings from the pod's destroot to its header dirs, which by default is just the pod's header dir" do xit "returns a hash of mappings from the pod's destroot to its header dirs, which by default is just the pod's header dir" do
@spec.copy_header_mappings[:ios].size.should == 1 @spec.copy_header_mappings[:ios].size.should == 1
@spec.copy_header_mappings[:ios][Pathname.new('SSZipArchive')].sort.should == %w{ @spec.copy_header_mappings[:ios][Pathname.new('SSZipArchive')].sort.should == %w{
SSZipArchive.h SSZipArchive.h
minizip/crypt.h minizip/crypt.h
minizip/ioapi.h minizip/ioapi.h
minizip/mztools.h minizip/mztools.h
minizip/unzip.h minizip/unzip.h
minizip/zip.h minizip/zip.h
}.map { |f| Pathname.new("SSZipArchive/#{f}") }.sort }.map { |f| Pathname.new("SSZipArchive/#{f}") }.sort
end
xit "allows for customization of header mappings by overriding copy_header_mapping" do
def @spec.copy_header_mapping(from)
Pathname.new('ns') + from.basename
end end
@spec.copy_header_mappings[:ios].size.should == 1
@spec.copy_header_mappings[:ios][Pathname.new('SSZipArchive/ns')].sort.should == %w{ xit "allows for customization of header mappings by overriding copy_header_mapping" do
def @spec.copy_header_mapping(from)
Pathname.new('ns') + from.basename
end
@spec.copy_header_mappings[:ios].size.should == 1
@spec.copy_header_mappings[:ios][Pathname.new('SSZipArchive/ns')].sort.should == %w{
SSZipArchive.h SSZipArchive.h
minizip/crypt.h minizip/crypt.h
minizip/ioapi.h minizip/ioapi.h
minizip/mztools.h minizip/mztools.h
minizip/unzip.h minizip/unzip.h
minizip/zip.h minizip/zip.h
}.map { |f| Pathname.new("SSZipArchive/#{f}") }.sort }.map { |f| Pathname.new("SSZipArchive/#{f}") }.sort
end end
xit "returns a hash of mappings with a custom header dir prefix" do xit "returns a hash of mappings with a custom header dir prefix" do
@spec.header_dir = 'AnotherRoot' @spec.header_dir = 'AnotherRoot'
@spec.copy_header_mappings[:ios][Pathname.new('AnotherRoot')].sort.should == %w{ @spec.copy_header_mappings[:ios][Pathname.new('AnotherRoot')].sort.should == %w{
SSZipArchive.h SSZipArchive.h
minizip/crypt.h minizip/crypt.h
minizip/ioapi.h minizip/ioapi.h
minizip/mztools.h minizip/mztools.h
minizip/unzip.h minizip/unzip.h
minizip/zip.h minizip/zip.h
}.map { |f| Pathname.new("SSZipArchive/#{f}") }.sort }.map { |f| Pathname.new("SSZipArchive/#{f}") }.sort
end
xit "returns the user header search paths" do
def @spec.copy_header_mapping(from)
Pathname.new('ns') + from.basename
end end
@spec.header_search_paths.should == %w{
xit "returns the user header search paths" do
def @spec.copy_header_mapping(from)
Pathname.new('ns') + from.basename
end
@spec.header_search_paths.should == %w{
"$(PODS_ROOT)/Headers/SSZipArchive" "$(PODS_ROOT)/Headers/SSZipArchive"
"$(PODS_ROOT)/Headers/SSZipArchive/ns" "$(PODS_ROOT)/Headers/SSZipArchive/ns"
} }
end
xit "returns the user header search paths with a custom header dir prefix" do
@spec.header_dir = 'AnotherRoot'
def @spec.copy_header_mapping(from)
Pathname.new('ns') + from.basename
end end
@spec.header_search_paths.should == %w{
xit "returns the user header search paths with a custom header dir prefix" do
@spec.header_dir = 'AnotherRoot'
def @spec.copy_header_mapping(from)
Pathname.new('ns') + from.basename
end
@spec.header_search_paths.should == %w{
"$(PODS_ROOT)/Headers/AnotherRoot" "$(PODS_ROOT)/Headers/AnotherRoot"
"$(PODS_ROOT)/Headers/AnotherRoot/ns" "$(PODS_ROOT)/Headers/AnotherRoot/ns"
} }
end
xit "returns the list of files that the resources pattern expand to" do
@spec.expanded_resources.should == {}
@spec.resource = 'LICEN*'
@spec.expanded_resources[:ios].map(&:to_s).should == %w{ SSZipArchive/LICENSE }
@spec.expanded_resources[:osx].map(&:to_s).should == %w{ SSZipArchive/LICENSE }
@spec.resources = 'LICEN*', 'Readme.*'
@spec.expanded_resources[:ios].map(&:to_s).should == %w{ SSZipArchive/LICENSE SSZipArchive/Readme.markdown }
@spec.expanded_resources[:osx].map(&:to_s).should == %w{ SSZipArchive/LICENSE SSZipArchive/Readme.markdown }
end
end end
xit "returns the list of files that the resources pattern expand to" do describe "regarding multiple subspecs" do
@spec.expanded_resources.should == {}
@spec.resource = 'LICEN*' before do
@spec.expanded_resources[:ios].map(&:to_s).should == %w{ SSZipArchive/LICENSE } # specification with only some subspecs activated
@spec.expanded_resources[:osx].map(&:to_s).should == %w{ SSZipArchive/LICENSE } # to check that only the needed files are being activated
@spec.resources = 'LICEN*', 'Readme.*' # A fixture is needed.
@spec.expanded_resources[:ios].map(&:to_s).should == %w{ SSZipArchive/LICENSE SSZipArchive/Readme.markdown } #
@spec.expanded_resources[:osx].map(&:to_s).should == %w{ SSZipArchive/LICENSE SSZipArchive/Readme.markdown } # specification = Pod::Spec.new do |s|
# ...
# s.xcconfig = ...
# s.compiler_flags = ...
# s.subspec 's1' do |s1|
# s1.xcconfig = ...
# s1.compiler_flags = ...
# s1.ns.source_files = 's1.{h,m}'
# end
#
# s.subspec 's2' do |s2|
# s2.ns.source_files = 's2.{h,m}'
# end
#
# Add only s1 to the localPod
# s1 = specification.subspec_by_name(s1)
# @pod = Pod::LocalPod.new(s1, @sandbox, Pod::Platform.new(:ios))
# @pod.add_specification(specification)
end
xit "returns the subspecs" do
@pod.subspecs.map{ |s| name }.should == %w[ s1 ]
end
xit "resolve the source files" do
@pod.source_files.should == %w[ s1.h s1.m ]
end
xit "resolve the resources" do
end
xit "resolve the clean paths" do
@pod.clean_paths.should == %w[ s2.h s2.m ]
end
xit "resolves the used files" do
@pod.used_files.should == %w[ s1.h s1.m README.md ]
end
xit "resolved the header files" do
@pod.header_files.should == %w[ s1.h ]
end
xit "resolves the header files of every subspec" do
@pod.all_specs_public_header_files.should == %w[ s1.h s2.h ]
end
xit "merges the xcconfigs" do
end
xit "adds each file to a target with the compiler flags of its specification" do
# @pod.add_to_target(target)
end
xit "can provide the source files of all the subspecs" do
sources = @pod.all_specs_source_files.map { |p| p.relative_path_from(@sandbox.root).to_s }
sources.should == %w[ s1.h s1.m s2.h s2.m ]
end
xit 'can clean the unused files' do
# copy fixture to another folder
@pod.clean
@pod.clean_paths.tap do |paths|
paths.each do |path|
path.should.not.exist
end
end
end
end end
end end
require File.expand_path('../../spec_helper', __FILE__) require File.expand_path('../../spec_helper', __FILE__)
describe Pod::Platform do describe Pod::Platform do
it "returns a new Platform instance" do describe "by default" do
Pod::Platform.ios.should == Pod::Platform.new(:ios) it "returns a new Platform instance" do
Pod::Platform.osx.should == Pod::Platform.new(:osx) Pod::Platform.ios.should == Pod::Platform.new(:ios)
end Pod::Platform.osx.should == Pod::Platform.new(:osx)
end
before do
@platform = Pod::Platform.ios before do
end @platform = Pod::Platform.ios
end
it "exposes it's symbolic name" do
@platform.name.should == :ios it "exposes it's symbolic name" do
end @platform.name.should == :ios
end
it "can be compared for equality with another platform with the same symbolic name" do
@platform.should == Pod::Platform.new(:ios) it "can be compared for equality with another platform with the same symbolic name" do
end @platform.should == Pod::Platform.new(:ios)
end
it "can be compared for equality with another platform with the same symbolic name and the same deployment target" do
@platform.should.not == Pod::Platform.new(:ios, '4.0') it "can be compared for equality with another platform with the same symbolic name and the same deployment target" do
Pod::Platform.new(:ios, '4.0').should == Pod::Platform.new(:ios, '4.0') @platform.should.not == Pod::Platform.new(:ios, '4.0')
end Pod::Platform.new(:ios, '4.0').should == Pod::Platform.new(:ios, '4.0')
end
it "can be compared for equality with a matching symbolic name (backwards compatibility reasons)" do
@platform.should == :ios it "can be compared for equality with a matching symbolic name (backwards compatibility reasons)" do
end @platform.should == :ios
end
it "presents an accurate string representation" do
@platform.to_s.should == "iOS" it "presents an accurate string representation" do
Pod::Platform.new(:osx).to_s.should == 'OS X' @platform.to_s.should == "iOS"
Pod::Platform.new(nil).to_s.should == "iOS - OS X" Pod::Platform.new(:osx).to_s.should == 'OS X'
Pod::Platform.new(:ios, '5.0.0').to_s.should == 'iOS 5.0.0' Pod::Platform.new(nil).to_s.should == "iOS - OS X"
Pod::Platform.new(:osx, '10.7').to_s.should == 'OS X 10.7' Pod::Platform.new(:ios, '5.0.0').to_s.should == 'iOS 5.0.0'
end Pod::Platform.new(:osx, '10.7').to_s.should == 'OS X 10.7'
end
it "uses it's name as it's symbold version" do
@platform.to_sym.should == :ios it "uses it's name as it's symbold version" do
end @platform.to_sym.should == :ios
end
it "allows to specify the deployment target on initialization" do
p = Pod::Platform.new(:ios, '4.0.0') it "allows to specify the deployment target on initialization" do
p.deployment_target.should == Pod::Version.new('4.0.0') p = Pod::Platform.new(:ios, '4.0.0')
end p.deployment_target.should == Pod::Version.new('4.0.0')
end
it "allows to specify the deployment target in a hash on initialization (backwards compatibility from 0.6)" do
p = Pod::Platform.new(:ios, { :deployment_target => '4.0.0' }) it "allows to specify the deployment target in a hash on initialization (backwards compatibility from 0.6)" do
p.deployment_target.should == Pod::Version.new('4.0.0') p = Pod::Platform.new(:ios, { :deployment_target => '4.0.0' })
end p.deployment_target.should == Pod::Version.new('4.0.0')
end
it "allows to specify the deployment target after initialization" do
p = Pod::Platform.new(:ios, '4.0.0') it "allows to specify the deployment target after initialization" do
p.deployment_target = '4.0.0' p = Pod::Platform.new(:ios, '4.0.0')
p.deployment_target.should == Pod::Version.new('4.0.0') p.deployment_target = '4.0.0'
p.deployment_target = Pod::Version.new('4.0.0') p.deployment_target.should == Pod::Version.new('4.0.0')
p.deployment_target.should == Pod::Version.new('4.0.0') p.deployment_target = Pod::Version.new('4.0.0')
end p.deployment_target.should == Pod::Version.new('4.0.0')
end end
end
describe "Pod::Platform with a nil value" do
before do describe "with a nil value" do
@platform = Pod::Platform.new(nil) before do
end @platform = Pod::Platform.new(nil)
end
it "behaves like a nil object" do
@platform.should.be.nil it "behaves like a nil object" do
end @platform.should.be.nil
end end
end
describe "Pod::Platform#support?" do
it "supports another platform is with the same operating system" do describe "regarding supporting platforms" do
p1 = Pod::Platform.new(:ios) it "supports platforms with the same operating system" do
p2 = Pod::Platform.new(:ios) p1 = Pod::Platform.new(:ios)
p1.should.support?(p2) p2 = Pod::Platform.new(:ios)
p1.should.supports?(p2)
p1 = Pod::Platform.new(:osx)
p2 = Pod::Platform.new(:osx) p1 = Pod::Platform.new(:osx)
p1.should.support?(p2) p2 = Pod::Platform.new(:osx)
end p1.should.supports?(p2)
end
it "supports a nil platform" do
p1 = Pod::Platform.new(:ios) it "supports a nil platform" do
p1.should.support?(nil) p1 = Pod::Platform.new(:ios)
end p1.should.supports?(nil)
end
it "supports a platform with a lower or equal deployment_target" do
p1 = Pod::Platform.new(:ios, '5.0') it "supports a platform with a lower or equal deployment_target" do
p2 = Pod::Platform.new(:ios, '4.0') p1 = Pod::Platform.new(:ios, '5.0')
p1.should.support?(p1) p2 = Pod::Platform.new(:ios, '4.0')
p1.should.support?(p2) p1.should.supports?(p1)
p2.should.not.support?(p1) p1.should.supports?(p2)
end p2.should.not.supports?(p1)
end
it "supports a platform regardless of the deployment_target if one of the two does not specify it" do
p1 = Pod::Platform.new(:ios) it "supports a platform regardless of the deployment_target if one of the two does not specify it" do
p2 = Pod::Platform.new(:ios, '4.0') p1 = Pod::Platform.new(:ios)
p1.should.support?(p2) p2 = Pod::Platform.new(:ios, '4.0')
p2.should.support?(p1) p1.should.supports?(p2)
p2.should.supports?(p1)
end
it "doesn't supports a platform with a different operating system" do
p1 = Pod::Platform.new(:ios)
p2 = Pod::Platform.new(:osx)
p1.should.not.supports?(p2)
end
end end
end end
...@@ -26,6 +26,14 @@ describe "Pod::Podfile" do ...@@ -26,6 +26,14 @@ describe "Pod::Podfile" do
dep.external_source.params.should == { :git => 'GIT-URL', :commit => '1234' } dep.external_source.params.should == { :git => 'GIT-URL', :commit => '1234' }
end end
it "adds a subspec dependency on a Pod repo outside of a spec repo (the repo is expected to contain a podspec)" do
podfile = Pod::Podfile.new do
dependency 'MainSpec/FirstSubSpec', :git => 'GIT-URL', :commit => '1234'
end
dep = podfile.dependency_by_top_level_spec_name('MainSpec')
dep.external_source.name.should == 'MainSpec'
end
it "adds a dependency on a library outside of a spec repo (the repo does not need to contain a podspec)" do it "adds a dependency on a library outside of a spec repo (the repo does not need to contain a podspec)" do
podfile = Pod::Podfile.new do podfile = Pod::Podfile.new do
dependency 'SomeExternalPod', :podspec => 'http://gist/SomeExternalPod.podspec' dependency 'SomeExternalPod', :podspec => 'http://gist/SomeExternalPod.podspec'
...@@ -71,8 +79,8 @@ describe "Pod::Podfile" do ...@@ -71,8 +79,8 @@ describe "Pod::Podfile" do
path = config.project_root + 'MyProject.xcodeproj' path = config.project_root + 'MyProject.xcodeproj'
config.project_root.expects(:glob).with('*.xcodeproj').returns([path]) config.project_root.expects(:glob).with('*.xcodeproj').returns([path])
podfile.target_definitions[:default].xcodeproj.should == path podfile.target_definitions[:default].user_project.path.should == path
podfile.target_definitions[:another_target].xcodeproj.should == path podfile.target_definitions[:another_target].user_project.path.should == path
end end
it "assumes the basename of the workspace is the same as the default target's project basename" do it "assumes the basename of the workspace is the same as the default target's project basename" do
...@@ -117,7 +125,7 @@ describe "Pod::Podfile" do ...@@ -117,7 +125,7 @@ describe "Pod::Podfile" do
before do before do
@podfile = Pod::Podfile.new do @podfile = Pod::Podfile.new do
platform :ios platform :ios
xcodeproj 'iOS Project' xcodeproj 'iOS Project', 'iOS App Store' => :release, 'Test' => :debug
target :debug do target :debug do
dependency 'SSZipArchive' dependency 'SSZipArchive'
...@@ -133,7 +141,7 @@ describe "Pod::Podfile" do ...@@ -133,7 +141,7 @@ describe "Pod::Podfile" do
target :osx_target do target :osx_target do
platform :osx platform :osx
xcodeproj 'OSX Project.xcodeproj' xcodeproj 'OSX Project.xcodeproj', 'Mac App Store' => :release, 'Test' => :debug
link_with 'OSXTarget' link_with 'OSXTarget'
dependency 'ASIHTTPRequest' dependency 'ASIHTTPRequest'
target :nested_osx_target do target :nested_osx_target do
...@@ -178,26 +186,24 @@ describe "Pod::Podfile" do ...@@ -178,26 +186,24 @@ describe "Pod::Podfile" do
it "returns the Xcode project that contains the target to link with" do it "returns the Xcode project that contains the target to link with" do
[:default, :debug, :test, :subtarget].each do |target_name| [:default, :debug, :test, :subtarget].each do |target_name|
target = @podfile.target_definitions[target_name] target = @podfile.target_definitions[target_name]
target.xcodeproj.should == config.project_root + 'iOS Project.xcodeproj' target.user_project.path.should == config.project_root + 'iOS Project.xcodeproj'
end end
[:osx_target, :nested_osx_target].each do |target_name| [:osx_target, :nested_osx_target].each do |target_name|
target = @podfile.target_definitions[target_name] target = @podfile.target_definitions[target_name]
target.xcodeproj.should == config.project_root + 'OSX Project.xcodeproj' target.user_project.path.should == config.project_root + 'OSX Project.xcodeproj'
end end
end end
it "returns a Xcode project found in the working dir when no explicit project is specified" do it "returns a Xcode project found in the working dir when no explicit project is specified" do
xcodeproj1 = config.project_root + '1.xcodeproj' xcodeproj1 = config.project_root + '1.xcodeproj'
target = Pod::Podfile::TargetDefinition.new(:implicit)
config.project_root.expects(:glob).with('*.xcodeproj').returns([xcodeproj1]) config.project_root.expects(:glob).with('*.xcodeproj').returns([xcodeproj1])
target.xcodeproj.should == xcodeproj1 Pod::Podfile::UserProject.new.path.should == xcodeproj1
end end
it "returns `nil' if more than one Xcode project was found in the working when no explicit project is specified" do it "returns `nil' if more than one Xcode project was found in the working when no explicit project is specified" do
xcodeproj1, xcodeproj2 = config.project_root + '1.xcodeproj', config.project_root + '2.xcodeproj' xcodeproj1, xcodeproj2 = config.project_root + '1.xcodeproj', config.project_root + '2.xcodeproj'
target = Pod::Podfile::TargetDefinition.new(:implicit)
config.project_root.expects(:glob).with('*.xcodeproj').returns([xcodeproj1, xcodeproj2]) config.project_root.expects(:glob).with('*.xcodeproj').returns([xcodeproj1, xcodeproj2])
target.xcodeproj.should == nil Pod::Podfile::UserProject.new.path.should == nil
end end
it "leaves the name of the target, to link with, to be automatically resolved" do it "leaves the name of the target, to link with, to be automatically resolved" do
...@@ -250,10 +256,25 @@ describe "Pod::Podfile" do ...@@ -250,10 +256,25 @@ describe "Pod::Podfile" do
@podfile.target_definitions[:nested_osx_target].should.not.be.exclusive @podfile.target_definitions[:nested_osx_target].should.not.be.exclusive
end end
it "returns the specified configurations and wether it should be based on a debug or a release build" do
Pod::Podfile::UserProject.any_instance.stubs(:project)
all = { 'Release' => :release, 'Debug' => :debug, 'Test' => :debug }
@podfile.target_definitions[:default].user_project.build_configurations.should == all.merge('iOS App Store' => :release)
@podfile.target_definitions[:test].user_project.build_configurations.should == all.merge('iOS App Store' => :release)
@podfile.target_definitions[:osx_target].user_project.build_configurations.should == all.merge('Mac App Store' => :release)
@podfile.target_definitions[:nested_osx_target].user_project.build_configurations.should == all.merge('Mac App Store' => :release)
@podfile.user_build_configurations.should == all.merge('iOS App Store' => :release, 'Mac App Store' => :release)
end
it "defaults, for unspecified configurations, to a release build" do
project = Pod::Podfile::UserProject.new(fixture('SampleProject/SampleProject.xcodeproj'), 'Test' => :debug)
project.build_configurations.should == { 'Release' => :release, 'Debug' => :debug, 'Test' => :debug, 'App Store' => :release }
end
describe "with an Xcode project that's not in the project_root" do describe "with an Xcode project that's not in the project_root" do
before do before do
@target_definition = @podfile.target_definitions[:default] @target_definition = @podfile.target_definitions[:default]
@target_definition.stubs(:xcodeproj).returns(config.project_root + 'subdir/iOS Project.xcodeproj') @target_definition.user_project.stubs(:path).returns(config.project_root + 'subdir/iOS Project.xcodeproj')
end end
it "returns the $(PODS_ROOT) relative to the project's $(SRCROOT)" do it "returns the $(PODS_ROOT) relative to the project's $(SRCROOT)" do
...@@ -264,7 +285,7 @@ describe "Pod::Podfile" do ...@@ -264,7 +285,7 @@ describe "Pod::Podfile" do
config.integrate_targets.should.equal true config.integrate_targets.should.equal true
config.integrate_targets = false config.integrate_targets = false
@target_definition.relative_pods_root.should == '${SRCROOT}/../Pods' @target_definition.relative_pods_root.should == '${SRCROOT}/../Pods'
@target_definition.stubs(:xcodeproj).returns(nil) @target_definition.user_project.stubs(:path).returns(nil)
@target_definition.relative_pods_root.should == '${SRCROOT}/Pods' @target_definition.relative_pods_root.should == '${SRCROOT}/Pods'
config.integrate_targets = true config.integrate_targets = true
end end
...@@ -282,9 +303,9 @@ describe "Pod::Podfile" do ...@@ -282,9 +303,9 @@ describe "Pod::Podfile" do
describe "concerning validations" do describe "concerning validations" do
it "raises if it should integrate and can't find an xcodeproj" do it "raises if it should integrate and can't find an xcodeproj" do
config.integrate_targets.should.equal true config.integrate_targets = true
target_definition = Pod::Podfile.new {}.target_definitions[:default] target_definition = Pod::Podfile.new {}.target_definitions[:default]
target_definition.stubs(:xcodeproj).returns(nil) target_definition.user_project.stubs(:path).returns(nil)
exception = lambda { exception = lambda {
target_definition.relative_pods_root target_definition.relative_pods_root
}.should.raise Pod::Informative }.should.raise Pod::Informative
......
...@@ -33,6 +33,18 @@ describe 'Pod::Project' do ...@@ -33,6 +33,18 @@ describe 'Pod::Project' do
@project.targets.first.build_phases.should.include phase @project.targets.first.build_phases.should.include phase
end end
it "adds build configurations named after every configuration across all of the user's projects" do
@project.user_build_configurations = { 'Debug' => :debug, 'Release' => :release, 'Test' => :debug, 'AppStore' => :release }
@project.build_configurations.map(&:name).sort.should == %w{ AppStore Debug Release Test }
end
it "adds build configurations named after every configuration across all of the user's projects to a target" do
@project.user_build_configurations = { 'Debug' => :debug, 'Release' => :release, 'Test' => :debug, 'AppStore' => :release }
target = @project.add_pod_target('SomeTarget', Pod::Platform.ios)
target.build_settings('Test')["VALIDATE_PRODUCT"].should == nil
target.build_settings('AppStore')["VALIDATE_PRODUCT"].should == "YES"
end
describe "concerning its :ios targets" do describe "concerning its :ios targets" do
it "sets VALIDATE_PRODUCT to YES for the Release configuration" do it "sets VALIDATE_PRODUCT to YES for the Release configuration" do
target = Pod::Project.new.add_pod_target('Pods', Pod::Platform.ios) target = Pod::Project.new.add_pod_target('Pods', Pod::Platform.ios)
......
...@@ -2,34 +2,28 @@ require File.expand_path('../../spec_helper', __FILE__) ...@@ -2,34 +2,28 @@ require File.expand_path('../../spec_helper', __FILE__)
describe "Pod::Resolver" do describe "Pod::Resolver" do
before do before do
@config_before = config
Pod::Config.instance = nil
config.silent = true
config.repos_dir = fixture('spec-repos') config.repos_dir = fixture('spec-repos')
@podfile = Pod::Podfile.new do @podfile = Pod::Podfile.new do
platform :ios platform :ios
dependency 'ASIWebPageRequest' dependency 'BlocksKit'
# dependency 'ASIWebPageRequest'
end end
@resolver = Pod::Resolver.new(@podfile, stub('sandbox')) @resolver = Pod::Resolver.new(@podfile, stub('sandbox'))
end end
after do
Pod::Config.instance = @config_before
end
it "holds the context state, such as cached specification sets" do it "holds the context state, such as cached specification sets" do
@resolver.resolve @resolver.resolve
@resolver.cached_sets.values.sort_by(&:name).should == [ @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/A2DynamicDelegate'),
Pod::Spec::Set.new(config.repos_dir + 'master/ASIWebPageRequest'), Pod::Spec::Set.new(config.repos_dir + 'master/BlocksKit'),
Pod::Spec::Set.new(config.repos_dir + 'master/Reachability'),
].sort_by(&:name) ].sort_by(&:name)
end end
it "returns all specs needed for the dependency" do it "returns all specs needed for the dependency" do
specs = @resolver.resolve.values.flatten specs = @resolver.resolve.values.flatten
specs.map(&:class).uniq.should == [Pod::Specification] 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 end
it "does not raise if all dependencies match the platform of the root spec (Podfile)" do it "does not raise if all dependencies match the platform of the root spec (Podfile)" do
...@@ -40,8 +34,8 @@ describe "Pod::Resolver" do ...@@ -40,8 +34,8 @@ describe "Pod::Resolver" do
end end
it "raises once any of the dependencies does not match the platform of its podfile target" do 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') set = Pod::Spec::Set.new(config.repos_dir + 'master/BlocksKit')
@resolver.cached_sets['ASIHTTPRequest'] = set @resolver.cached_sets['BlocksKit'] = set
def set.stub_platform=(platform); @stubbed_platform = platform; end def set.stub_platform=(platform); @stubbed_platform = platform; end
def set.specification; spec = super; spec.platform = @stubbed_platform; spec; end def set.specification; spec = super; spec.platform = @stubbed_platform; spec; end
...@@ -60,14 +54,14 @@ describe "Pod::Resolver" do ...@@ -60,14 +54,14 @@ describe "Pod::Resolver" do
end end
it "raises once any of the dependencies does not have a deployment_target compatible with its podfile target" do 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') set = Pod::Spec::Set.new(config.repos_dir + 'master/BlocksKit')
@resolver.cached_sets['ASIHTTPRequest'] = set @resolver.cached_sets['BlocksKit'] = set
@podfile.platform :ios, "4.0" @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 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 lambda { @resolver.resolve }.should.raise Pod::Informative
end end
...@@ -75,20 +69,111 @@ describe "Pod::Resolver" do ...@@ -75,20 +69,111 @@ describe "Pod::Resolver" do
@podfile = Pod::Podfile.new do @podfile = Pod::Podfile.new do
platform :ios platform :ios
dependency 'RestKit/Network' 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
ISO8601DateFormatter
LibComponentLogging-Core
LibComponentLogging-NSLog
NSData+Base64
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 end
resolver = Pod::Resolver.new(@podfile, stub('sandbox')) resolver = Pod::Resolver.new(@podfile, stub('sandbox'))
resolver.resolve.values.flatten.map(&:name).sort.should == %w{ resolver.resolve.values.flatten.map(&:name).sort.should == %w{
FileMD5Hash FileMD5Hash
ISO8601DateFormatter ISO8601DateFormatter
JSONKit
LibComponentLogging-Core LibComponentLogging-Core
LibComponentLogging-NSLog LibComponentLogging-NSLog
NSData+Base64
RestKit RestKit
RestKit/JSON
RestKit/Network RestKit/Network
RestKit/ObjectMapping RestKit/ObjectMapping/CoreData
RestKit/ObjectMapping/JSON
RestKit/UI
SOCKit SOCKit
UDTableView
cocoa-oauth cocoa-oauth
} }
end 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.name = 'RestKit'
s.version = '0.10.0'
s.preferred_dependency = 'JSON'
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' do |ns|
ns.dependency 'LibComponentLogging-NSLog', '>= 1.0.4'
end
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{
LibComponentLogging-Core
LibComponentLogging-NSLog
RestKit
RestKit/JSON
RestKit/Network
RestKit/ObjectMapping/CoreData
RestKit/ObjectMapping/JSON
RestKit/UI
}
it "resolves subspecs with external constraints" do
@podfile = Pod::Podfile.new do
platform :ios
dependency 'MainSpec/FirstSubSpec', :git => 'GIT-URL'
end
spec = Pod::Spec.new do |s|
s.name = 'MainSpec'
s.version = '1.2.3'
s.platform = :ios
s.license = 'MIT'
s.author = 'Joe the Plumber'
s.summary = 'A spec with subspecs'
s.source = { :git => '/some/url' }
s.requires_arc = true
s.subspec 'FirstSubSpec' do |fss|
fss.source_files = 'some/file'
fss.subspec 'SecondSubSpec'
end
end
@podfile.dependencies.first.external_source.stubs(:specification_from_sandbox).returns(spec)
resolver = Pod::Resolver.new(@podfile, stub('sandbox'))
resolver.resolve.values.flatten.map(&:name).sort.should == %w{ MainSpec/FirstSubSpec MainSpec/FirstSubSpec/SecondSubSpec }
end
end
end end
require File.expand_path('../../spec_helper', __FILE__) require File.expand_path('../../spec_helper', __FILE__)
require 'tmpdir' require 'tmpdir'
TMP_POD_ROOT = ROOT + "tmp" + "podroot" TMP_POD_ROOT = ROOT + "tmp" + "podroot" unless defined? TMP_POD_ROOT
describe Pod::Sandbox do describe Pod::Sandbox do
before do before do
@sandbox = Pod::Sandbox.new(TMP_POD_ROOT) @sandbox = Pod::Sandbox.new(TMP_POD_ROOT)
end end
after do after do
@sandbox.implode @sandbox.implode
end end
it "automatically creates the TMP_POD_ROOT if it doesn't exist" do it "automatically creates the TMP_POD_ROOT if it doesn't exist" do
File.directory?(TMP_POD_ROOT).should.be.true File.directory?(TMP_POD_ROOT).should.be.true
end end
it "deletes the entire root directory on implode" do it "deletes the entire root directory on implode" do
@sandbox.implode @sandbox.implode
File.directory?(TMP_POD_ROOT).should.be.false File.directory?(TMP_POD_ROOT).should.be.false
FileUtils.mkdir(TMP_POD_ROOT) # put it back again FileUtils.mkdir(TMP_POD_ROOT) # put it back again
end end
it "returns it's headers root" do it "returns it's headers root" do
@sandbox.headers_root.should == Pathname.new(File.join(TMP_POD_ROOT, "Headers")) @sandbox.headers_root.should == Pathname.new(File.join(TMP_POD_ROOT, "Headers"))
end end
it "can add namespaced headers to it's header path using symlinks and return the relative path" do it "can add namespaced headers to it's header path using symlinks and return the relative path" do
FileUtils.mkdir_p(@sandbox.root + "ExampleLib/Headers") FileUtils.mkdir_p(@sandbox.root + "ExampleLib/Headers")
namespace_path = Pathname.new("ExampleLib") namespace_path = Pathname.new("ExampleLib")
...@@ -36,7 +36,7 @@ describe Pod::Sandbox do ...@@ -36,7 +36,7 @@ describe Pod::Sandbox do
symlink_path.should.be.symlink symlink_path.should.be.symlink
File.read(symlink_path).should == 'hello' File.read(symlink_path).should == 'hello'
end end
it 'can add multiple headers at once and return the relative symlink paths' do it 'can add multiple headers at once and return the relative symlink paths' do
FileUtils.mkdir_p(@sandbox.root + "ExampleLib/Headers") FileUtils.mkdir_p(@sandbox.root + "ExampleLib/Headers")
namespace_path = Pathname.new("ExampleLib") namespace_path = Pathname.new("ExampleLib")
...@@ -53,7 +53,7 @@ describe Pod::Sandbox do ...@@ -53,7 +53,7 @@ describe Pod::Sandbox do
File.read(path).should == "hello" File.read(path).should == "hello"
end end
end end
it 'keeps a list of unique header search paths when headers are added' do it 'keeps a list of unique header search paths when headers are added' do
FileUtils.mkdir_p(@sandbox.root + "ExampleLib/Headers") FileUtils.mkdir_p(@sandbox.root + "ExampleLib/Headers")
namespace_path = Pathname.new("ExampleLib") namespace_path = Pathname.new("ExampleLib")
...@@ -67,11 +67,11 @@ describe Pod::Sandbox do ...@@ -67,11 +67,11 @@ describe Pod::Sandbox do
@sandbox.add_header_files(namespace_path, relative_header_paths) @sandbox.add_header_files(namespace_path, relative_header_paths)
@sandbox.header_search_paths.should.include("${PODS_ROOT}/Headers/ExampleLib") @sandbox.header_search_paths.should.include("${PODS_ROOT}/Headers/ExampleLib")
end end
it 'always adds the Headers root to the header search paths' do it 'always adds the Headers root to the header search paths' do
@sandbox.header_search_paths.should.include("${PODS_ROOT}/Headers") @sandbox.header_search_paths.should.include("${PODS_ROOT}/Headers")
end end
it 'clears out its headers root when preparing for install' do it 'clears out its headers root when preparing for install' do
@sandbox.prepare_for_install @sandbox.prepare_for_install
@sandbox.headers_root.should.not.exist @sandbox.headers_root.should.not.exist
......
require File.expand_path('../../spec_helper', __FILE__) require File.expand_path('../../spec_helper', __FILE__)
describe "Pod::Source" do describe "Pod::Source" do
extend SpecHelper::Git
extend SpecHelper::Command extend SpecHelper::Command
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
before do before do
add_repo('repo1', fixture('spec-repos/master')) add_repo('repo1', fixture('spec-repos/master'))
......
...@@ -10,7 +10,7 @@ describe "Pod::Specification::Set" do ...@@ -10,7 +10,7 @@ describe "Pod::Specification::Set" do
end end
it "returns the versions available for this pod ordered from highest to lowest" do it "returns the versions available for this pod ordered from highest to lowest" do
@set.versions.should == %w[1.3.2 1.3.1 1.3 1.2.3 1.2.2 1.2.1 1.2 1.1 1.0].map { |v| Pod::Version.new(v) } @set.versions.should == %w[1.3.3 1.3.2 1.3.1 1.3 1.2.3 1.2.2 1.2.1 1.2 1.1 1.0].map { |v| Pod::Version.new(v) }
end end
it "checks if the dependency of the specification is compatible with existing requirements" do it "checks if the dependency of the specification is compatible with existing requirements" do
...@@ -29,12 +29,6 @@ describe "Pod::Specification::Set" do ...@@ -29,12 +29,6 @@ describe "Pod::Specification::Set" do
lambda { @set.required_version }.should.raise Pod::Informative lambda { @set.required_version }.should.raise Pod::Informative
end 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 before do
@set.required_by(Pod::Spec.new { |s| s.dependency 'CocoaLumberjack', '< 1.2.1' }) @set.required_by(Pod::Spec.new { |s| s.dependency 'CocoaLumberjack', '< 1.2.1' })
end end
...@@ -51,11 +45,6 @@ describe "Pod::Specification::Set" do ...@@ -51,11 +45,6 @@ describe "Pod::Specification::Set" do
@set.specification.should == Pod::Spec.new { |s| s.name = 'CocoaLumberjack'; s.version = '1.2' } @set.specification.should == Pod::Spec.new { |s| s.name = 'CocoaLumberjack'; s.version = '1.2' }
end 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 it "ignores dotfiles when getting the version directories" do
`touch #{fixture('spec-repos/master/CocoaLumberjack/.DS_Store')}` `touch #{fixture('spec-repos/master/CocoaLumberjack/.DS_Store')}`
lambda { @set.versions }.should.not.raise lambda { @set.versions }.should.not.raise
......
...@@ -6,6 +6,10 @@ describe "A Pod::Specification loaded from a podspec" do ...@@ -6,6 +6,10 @@ describe "A Pod::Specification loaded from a podspec" do
@spec = Pod::Specification.from_file(fixture('banana-lib/BananaLib.podspec')) @spec = Pod::Specification.from_file(fixture('banana-lib/BananaLib.podspec'))
end 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 it "returns that it's not loaded from a podfile" do
@spec.should.not.be.podfile @spec.should.not.be.podfile
end end
...@@ -53,25 +57,23 @@ describe "A Pod::Specification loaded from a podspec" do ...@@ -53,25 +57,23 @@ describe "A Pod::Specification loaded from a podspec" do
end end
it "returns the pod's source files" do it "returns the pod's source files" do
@spec.source_files[:ios].should == ['Classes/*.{h,m}', 'Vendor'] @spec.activate_platform(:ios).source_files.should == ['Classes/*.{h,m}', 'Vendor']
@spec.source_files[:osx].should == ['Classes/*.{h,m}', 'Vendor'] @spec.activate_platform(:osx).source_files.should == ['Classes/*.{h,m}', 'Vendor']
end end
it "returns the pod's dependencies" do it "returns the pod's dependencies" do
expected = Pod::Dependency.new('monkey', '~> 1.0.1', '< 1.0.9') expected = Pod::Dependency.new('monkey', '~> 1.0.1', '< 1.0.9')
@spec.dependencies.should == { :ios => [expected], :osx => [expected] } @spec.activate_platform(:ios).dependencies.should == [expected]
@spec.dependency_by_top_level_spec_name('monkey').should == expected @spec.activate_platform(:osx).dependencies.should == [expected]
end end
it "returns the pod's xcconfig settings" do it "returns the pod's xcconfig settings" do
@spec.xcconfig[:ios].should == { @spec.activate_platform(:ios).xcconfig.should == { 'OTHER_LDFLAGS' => '-framework SystemConfiguration' }
'OTHER_LDFLAGS' => '-framework SystemConfiguration'
}
end end
it "has a shortcut to add frameworks to the xcconfig" do it "has a shortcut to add frameworks to the xcconfig" do
@spec.frameworks = 'CFNetwork', 'CoreText' @spec.frameworks = 'CFNetwork', 'CoreText'
@spec.xcconfig[:ios].should == { @spec.activate_platform(:ios).xcconfig.should == {
'OTHER_LDFLAGS' => '-framework SystemConfiguration ' \ 'OTHER_LDFLAGS' => '-framework SystemConfiguration ' \
'-framework CFNetwork ' \ '-framework CFNetwork ' \
'-framework CoreText' '-framework CoreText'
...@@ -80,7 +82,7 @@ describe "A Pod::Specification loaded from a podspec" do ...@@ -80,7 +82,7 @@ describe "A Pod::Specification loaded from a podspec" do
it "has a shortcut to add libraries to the xcconfig" do it "has a shortcut to add libraries to the xcconfig" do
@spec.libraries = 'z', 'xml2' @spec.libraries = 'z', 'xml2'
@spec.xcconfig[:ios].should == { @spec.activate_platform(:ios).xcconfig.should == {
'OTHER_LDFLAGS' => '-framework SystemConfiguration -lz -lxml2' 'OTHER_LDFLAGS' => '-framework SystemConfiguration -lz -lxml2'
} }
end end
...@@ -97,53 +99,16 @@ describe "A Pod::Specification loaded from a podspec" do ...@@ -97,53 +99,16 @@ describe "A Pod::Specification loaded from a podspec" do
end end
it "adds compiler flags if ARC is required" do it "adds compiler flags if ARC is required" do
@spec.parent.should == nil
@spec.requires_arc = true @spec.requires_arc = true
@spec.compiler_flags.should == { :ios => " -fobjc-arc", :osx => " -fobjc-arc" } @spec.activate_platform(:ios).compiler_flags.should == " -fobjc-arc"
@spec.activate_platform(:osx).compiler_flags.should == " -fobjc-arc"
@spec.compiler_flags = "-Wunused-value" @spec.compiler_flags = "-Wunused-value"
@spec.compiler_flags.should == { :ios => " -fobjc-arc -Wunused-value", :osx => " -fobjc-arc -Wunused-value" } @spec.activate_platform(:ios).compiler_flags.should == " -fobjc-arc -Wunused-value"
@spec.activate_platform(:osx).compiler_flags.should == " -fobjc-arc -Wunused-value"
end end
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 describe "A Pod::Specification, in general," do
before do before do
@spec = Pod::Spec.new @spec = Pod::Spec.new
...@@ -160,11 +125,11 @@ describe "A Pod::Specification, in general," do ...@@ -160,11 +125,11 @@ describe "A Pod::Specification, in general," do
@spec.platform.deployment_target.should == Pod::Version.new('4.0') @spec.platform.deployment_target.should == Pod::Version.new('4.0')
end 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.platform = :ios, '4.0'
@spec.platforms.count.should == 1 @spec.available_platforms.count.should == 1
@spec.platforms.first.should == :ios @spec.available_platforms.first.should == :ios
@spec.platforms.first.deployment_target.should == Pod::Version.new('4.0') @spec.available_platforms.first.deployment_target.should == Pod::Version.new('4.0')
end end
it "returns the license of the Pod" do it "returns the license of the Pod" do
...@@ -200,7 +165,7 @@ describe "A Pod::Specification, in general," do ...@@ -200,7 +165,7 @@ describe "A Pod::Specification, in general," do
@spec.documentation[:appledoc].should == ['--project-name', '#{@name}', @spec.documentation[:appledoc].should == ['--project-name', '#{@name}',
'--project-company', '"Company Name"', '--project-company', '"Company Name"',
'--company-id', 'com.company', '--company-id', 'com.company',
'--ignore', 'Common', '--ignore', 'Common',
'--ignore', '.m'] '--ignore', '.m']
end end
...@@ -215,6 +180,18 @@ describe "A Pod::Specification, in general," do ...@@ -215,6 +180,18 @@ describe "A Pod::Specification, in general," do
list.glob.should == Pod::FileList[(ROOT + '*').to_s].exclude('Rakefile').map { |path| Pathname.new(path) } list.glob.should == Pod::FileList[(ROOT + '*').to_s].exclude('Rakefile').map { |path| Pathname.new(path) }
end end
it "takes a list of paths to preserve" do
@spec.preserve_paths = 'script.sh'
@spec.activate_platform(:ios).preserve_paths.should == %w{ script.sh }
end
it "takes any object for source_files as long as it responds to #glob (we provide this for Rake::FileList)" do
@spec.source_files = Pod::FileList['*'].exclude('Rakefile')
@spec.activate_platform(:ios)
list = ROOT + @spec.source_files.first
list.glob.should == Pod::FileList[(ROOT + '*').to_s].exclude('Rakefile').map { |path| Pathname.new(path) }
end
it "takes a prefix header path which will be appended to the Pods pch file" do it "takes a prefix header path which will be appended to the Pods pch file" do
@spec.prefix_header_file.should == nil @spec.prefix_header_file.should == nil
@spec.prefix_header_file = 'Classes/Demo.pch' @spec.prefix_header_file = 'Classes/Demo.pch'
...@@ -226,32 +203,106 @@ describe "A Pod::Specification, in general," do ...@@ -226,32 +203,106 @@ describe "A Pod::Specification, in general," do
@spec.prefix_header_contents = '#import "BlocksKit.h"' @spec.prefix_header_contents = '#import "BlocksKit.h"'
@spec.prefix_header_contents.should == '#import "BlocksKit.h"' @spec.prefix_header_contents.should == '#import "BlocksKit.h"'
end end
it "can be activated for a supported platorm" do
@spec.platform = :ios
lambda {@spec.activate_platform(:ios)}.should.not.raise Pod::Informative
end
it "raised if attempted to be activated for an unsupported platform" do
@spec.platform = :osx, '10.7'
lambda {@spec.activate_platform(:ios)}.should.raise Pod::Informative
lambda {@spec.activate_platform(:ios, '10.6')}.should.raise Pod::Informative
end
it "raises if not activated for a platform before accessing a multiplatform value" do
@spec.platform = :ios
lambda {@spec.source_files}.should.raise Pod::Informative
end
it "returns self on activation for method chainablity" do
@spec.platform = :ios
@spec.activate_platform(:ios).should == @spec
end
end
describe "A Pod::Specification, hierarchy" do
before do
@spec = Pod::Spec.new do |s|
s.name = 'MainSpec'
s.version = '0.999'
s.dependency 'awesome_lib'
s.subspec 'SubSpec.0' do |fss|
fss.platform = :ios
fss.subspec 'SubSpec.0.0' do |sss|
end
end
s.subspec 'SubSpec.1'
end
@subspec = @spec.subspecs.first
@spec.activate_platform(:ios)
end
it "automatically includes all the compatible subspecs as a dependencis if not preference is given" do
@spec.dependencies.map { |s| s.name }.should == %w[ awesome_lib MainSpec/SubSpec.0 MainSpec/SubSpec.1 ]
@spec.activate_platform(:osx).dependencies.map { |s| s.name }.should == %w[ awesome_lib MainSpec/SubSpec.1 ]
end
it "uses the spec version for the dependencies" do
@spec.dependencies.
select { |d| d.name =~ /MainSpec/ }.
all? { |d| d.requirement === Pod::Version.new('0.999') }.
should.be.true
end
it "respecs the preferred dependency for subspecs, if specified" do
@spec.preferred_dependency = 'SubSpec.0'
@spec.dependencies.map { |s| s.name }.should == %w[ awesome_lib MainSpec/SubSpec.0 ]
end
it "raises if it has dependecy on a self or on an upstream subspec" do
lambda { @subspec.dependency('MainSpec/SubSpec.0') }.should.raise Pod::Informative
lambda { @subspec.dependency('MainSpec') }.should.raise Pod::Informative
end
it "inherits external dependecies from the parent" do
@subspec.dependencies.map { |s| s.name }.should == %w[ awesome_lib MainSpec/SubSpec.0/SubSpec.0.0 ]
end
it "it accepts a dependency on a subspec that is in the same level of the hierarchy" do
@subspec.dependency('MainSpec/SubSpec.1')
@subspec.dependencies.map { |s| s.name }.should == %w[ MainSpec/SubSpec.1 awesome_lib MainSpec/SubSpec.0/SubSpec.0.0 ]
end
end end
describe "A Pod::Specification subspec" do describe "A Pod::Specification subspec" do
before do before do
@spec = Pod::Spec.new do |s| @spec = Pod::Spec.new do |s|
s.name = 'MainSpec' s.name = 'MainSpec'
s.version = '1.2.3' s.version = '1.2.3'
s.platform = :ios s.license = 'MIT'
s.license = 'MIT' s.author = 'Joe the Plumber'
s.author = 'Joe the Plumber' s.source = { :git => '/some/url' }
s.summary = 'A spec with subspecs'
s.source = { :git => '/some/url' }
s.requires_arc = true s.requires_arc = true
s.source_files = 'spec.m'
s.resource = 'resource'
s.platform = :ios
s.library = 'xml'
s.framework = 'CoreData'
s.subspec 'FirstSubSpec' do |fss| s.subspec 'FirstSubSpec' do |fss|
fss.source_files = 'some/file' fss.ios.source_files = 'subspec_ios.m'
fss.osx.source_files = 'subspec_osx.m'
fss.framework = 'CoreGraphics'
fss.library = 'z'
fss.subspec 'SecondSubSpec' do |sss| fss.subspec 'SecondSubSpec' do |sss|
sss.source_files = 'subsubspec.m'
end end
end end
end end
end @subspec = @spec.subspecs.first
@subsubspec = @subspec.subspecs.first
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 end
it "returns the top level parent spec" do it "returns the top level parent spec" do
...@@ -264,30 +315,130 @@ describe "A Pod::Specification subspec" do ...@@ -264,30 +315,130 @@ describe "A Pod::Specification subspec" do
@spec.subspecs.first.subspecs.first.name.should == 'MainSpec/FirstSubSpec/SecondSubSpec' @spec.subspecs.first.subspecs.first.name.should == 'MainSpec/FirstSubSpec/SecondSubSpec'
end end
it "is a `part_of' the top level parent spec" do it "correctly resolves the inheritance chain" do
dependency = Pod::Dependency.new('MainSpec', '1.2.3').tap { |d| d.only_part_of_other_pod = true } @spec.subspecs.first.subspecs.first.parent.should == @spec.subspecs.first
@spec.subspecs.first.part_of.should == dependency @spec.subspecs.first.parent.should == @spec
@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')]
end end
it "automatically forwards undefined attributes to the top level parent" do it "automatically forwards top level attributes to the top level parent" do
[:version, :summary, :platform, :license, :authors, :requires_arc, :compiler_flags].each do |attr| @spec.activate_platform(:ios)
[:version, :license, :authors, :requires_arc].each do |attr|
@spec.subspecs.first.send(attr).should == @spec.send(attr) @spec.subspecs.first.send(attr).should == @spec.send(attr)
@spec.subspecs.first.subspecs.first.send(attr).should == @spec.send(attr) @spec.subspecs.first.subspecs.first.send(attr).should == @spec.send(attr)
end end
end end
it "resolves correctly chained attributes" do
@spec.activate_platform(:ios)
@spec.source_files.map { |f| f.to_s }.should == %w[ spec.m ]
@subspec.source_files.map { |f| f.to_s }.should == %w[ spec.m subspec_ios.m ]
@subsubspec.source_files.map { |f| f.to_s }.should == %w[ spec.m subspec_ios.m subsubspec.m ]
@subsubspec.resources.should == %w[ resource ]
end
it "returns empty arrays for chained attributes with no value in the chain" do
@spec = Pod::Spec.new do |s|
s.name = 'MainSpec'
s.platform = :ios
s.subspec 'FirstSubSpec' do |fss|
fss.subspec 'SecondSubSpec' do |sss|
sss.source_files = 'subsubspec.m'
end
end
end
@spec.activate_platform(:ios).source_files.should == []
@spec.subspecs.first.source_files.should == []
@spec.subspecs.first.subspecs.first.source_files.should == %w[ subsubspec.m ]
end
it "does not cache platform attributes and can activate another platform" do
@spec.platform = nil
@spec.activate_platform(:ios)
@subsubspec.source_files.map { |f| f.to_s }.should == %w[ spec.m subspec_ios.m subsubspec.m ]
@spec.activate_platform(:osx)
@subsubspec.source_files.map { |f| f.to_s }.should == %w[ spec.m subspec_osx.m subsubspec.m ]
end
it "resolves correctly the available platforms" do
@spec.platform = nil
@subspec.platform = :ios, '4.0'
@spec.available_platforms.map{ |p| p.to_sym }.should == [ :osx, :ios ]
@subspec.available_platforms.first.to_sym.should == :ios
@subsubspec.available_platforms.first.to_sym.should == :ios
@subsubspec.platform = :ios, '5.0'
@subspec.available_platforms.first.deployment_target.to_s.should == '4.0'
@subsubspec.available_platforms.first.deployment_target.to_s.should == '5.0'
end
it "resolves reports correctly the supported platforms" do
@spec.platform = nil
@subspec.platform = :ios, '4.0'
@subsubspec.platform = :ios, '5.0'
@spec.supports_platform?(:ios).should.be.true
@spec.supports_platform?(:osx).should.be.true
@subspec.supports_platform?(:ios).should.be.true
@subspec.supports_platform?(:osx).should.be.false
@subspec.supports_platform?(:ios, '4.0').should.be.true
@subspec.supports_platform?(:ios, '5.0').should.be.true
@subsubspec.supports_platform?(:ios).should.be.true
@subsubspec.supports_platform?(:osx).should.be.false
@subsubspec.supports_platform?(:ios, '4.0').should.be.false
@subsubspec.supports_platform?(:ios, '5.0').should.be.true
@subsubspec.supports_platform?(Pod::Platform.new(:ios, '4.0')).should.be.false
@subsubspec.supports_platform?(Pod::Platform.new(:ios, '5.0')).should.be.true
end
it "raises a top level attribute is assigned to a spec with a parent" do
lambda { @subspec.version = '0.0.1' }.should.raise Pod::Informative
end
it "returns subspecs by name" do it "returns subspecs by name" do
@spec.subspec_by_name('MainSpec/FirstSubSpec').should == @spec.subspecs.first @spec.subspec_by_name(nil).should == @spec
@spec.subspec_by_name('MainSpec/FirstSubSpec/SecondSubSpec').should == @spec.subspecs.first.subspecs.first @spec.subspec_by_name('MainSpec').should == @spec
@spec.subspec_by_name('MainSpec/FirstSubSpec').should == @subspec
@spec.subspec_by_name('MainSpec/FirstSubSpec/SecondSubSpec').should == @subsubspec
end
it "has the same active platform accross the chain attributes" do
@spec.activate_platform(:ios)
@subspec.active_platform.should == :ios
@subsubspec.active_platform.should == :ios
@spec.platform = nil
@subsubspec.activate_platform(:osx)
@subspec.active_platform.should == :osx
@spec.active_platform.should == :osx
end
it "resolves the libraries correctly" do
@spec.activate_platform(:ios)
@spec.libraries.should == %w[ xml ]
@subspec.libraries.should == %w[ xml z ]
@subsubspec.libraries.should == %w[ xml z ]
end
it "resolves the frameworks correctly" do
@spec.activate_platform(:ios)
@spec.frameworks.should == %w[ CoreData ]
@subspec.frameworks.should == %w[ CoreData CoreGraphics ]
@subsubspec.frameworks.should == %w[ CoreData CoreGraphics ]
end
it "resolves the xcconfig" do
@spec.activate_platform(:ios)
@spec.xcconfig = { 'OTHER_LDFLAGS' => "-Wl,-no_compact_unwind" }
@spec.xcconfig.should == {"OTHER_LDFLAGS"=>"-Wl,-no_compact_unwind -lxml -framework CoreData"}
@subspec.xcconfig.should == {"OTHER_LDFLAGS"=>"-Wl,-no_compact_unwind -lxml -lz -framework CoreData -framework CoreGraphics"}
@subsubspec.xcconfig.should == {"OTHER_LDFLAGS"=>"-Wl,-no_compact_unwind -lxml -lz -framework CoreData -framework CoreGraphics"}
@subsubspec.xcconfig = { 'HEADER_SEARCH_PATHS' => '$(SDKROOT)/usr/include/libxml2' }
@spec.xcconfig.should == {"OTHER_LDFLAGS"=>"-Wl,-no_compact_unwind -lxml -framework CoreData"}
@subsubspec.xcconfig.should == {"OTHER_LDFLAGS"=>"-Wl,-no_compact_unwind -lxml -lz -framework CoreData -framework CoreGraphics", "HEADER_SEARCH_PATHS"=>"$(SDKROOT)/usr/include/libxml2"}
end end
end end
...@@ -327,26 +478,31 @@ describe "A Pod::Specification, concerning its attributes that support different ...@@ -327,26 +478,31 @@ describe "A Pod::Specification, concerning its attributes that support different
end end
it "returns the same list of source files for each platform" do it "returns the same list of source files for each platform" do
@spec.source_files.should == { :ios => %w{ file1 file2 }, :osx => %w{ file1 file2 } } @spec.activate_platform(:ios).source_files.should == %w{ file1 file2 }
@spec.activate_platform(:osx).source_files.should == %w{ file1 file2 }
end end
it "returns the same list of resources for each platform" do it "returns the same list of resources for each platform" do
@spec.resources.should == { :ios => %w{ file1 file2 }, :osx => %w{ file1 file2 } } @spec.activate_platform(:ios).resources.should == %w{ file1 file2 }
@spec.activate_platform(:osx).resources.should == %w{ file1 file2 }
end end
it "returns the same list of xcconfig build settings for each platform" do 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 } @spec.activate_platform(:ios).xcconfig.should == build_settings
@spec.activate_platform(:osx).xcconfig.should == build_settings
end end
it "returns the same list of compiler flags for each platform" do 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 } @spec.activate_platform(:ios).compiler_flags.should == compiler_flags
@spec.activate_platform(:osx).compiler_flags.should == compiler_flags
end end
it "returns the same list of dependencies for each platform" do it "returns the same list of dependencies for each platform" do
dependencies = %w{ JSONKit SSZipArchive }.map { |name| Pod::Dependency.new(name) } dependencies = %w{ JSONKit SSZipArchive }.map { |name| Pod::Dependency.new(name) }
@spec.dependencies.should == { :ios => dependencies, :osx => dependencies } @spec.activate_platform(:ios).dependencies.should == dependencies
@spec.activate_platform(:osx).dependencies.should == dependencies
end end
end end
...@@ -381,38 +537,34 @@ describe "A Pod::Specification, concerning its attributes that support different ...@@ -381,38 +537,34 @@ describe "A Pod::Specification, concerning its attributes that support different
end end
it "returns a different list of source files for each platform" do it "returns a different list of source files for each platform" do
@spec.source_files.should == { :ios => %w{ file1 }, :osx => %w{ file1 file2 } } @spec.activate_platform(:ios).source_files.should == %w{ file1 }
@spec.activate_platform(:osx).source_files.should == %w{ file1 file2 }
end end
it "returns a different list of resources for each platform" do it "returns a different list of resources for each platform" do
@spec.resources.should == { :ios => %w{ file1 }, :osx => %w{ file1 file2 } } @spec.activate_platform(:ios).resources.should == %w{ file1 }
@spec.activate_platform(:osx).resources.should == %w{ file1 file2 }
end end
it "returns a different list of xcconfig build settings for each platform" do it "returns a different list of xcconfig build settings for each platform" do
@spec.xcconfig.should == { @spec.activate_platform(:ios).xcconfig.should == { 'OTHER_LDFLAGS' => '-lObjC -lz -framework QuartzCore' }
:ios => { 'OTHER_LDFLAGS' => '-lObjC -framework QuartzCore -lz' }, @spec.activate_platform(:osx).xcconfig.should == { 'OTHER_LDFLAGS' => '-lObjC -all_load -lz -lxml -framework QuartzCore -framework CoreData' }
:osx => { 'OTHER_LDFLAGS' => '-lObjC -all_load -framework QuartzCore -framework CoreData -lz -lxml' }
}
end end
it "returns the list of the supported platfroms and deployment targets" do it "returns the list of the supported platfroms and deployment targets" do
@spec.platforms.count.should == 2 @spec.available_platforms.count.should == 2
@spec.platforms.should.include? Pod::Platform.new(:osx) @spec.available_platforms.should.include? Pod::Platform.new(:osx)
@spec.platforms.should.include? Pod::Platform.new(:ios, '4.0') @spec.available_platforms.should.include? Pod::Platform.new(:ios, '4.0')
end end
it "returns the same list of compiler flags for each platform" do it "returns the same list of compiler flags for each platform" do
@spec.compiler_flags.should == { @spec.activate_platform(:ios).compiler_flags.should == ' -fobjc-arc -Wdeprecated-implementations'
:ios => ' -Wdeprecated-implementations -fobjc-arc', @spec.activate_platform(:osx).compiler_flags.should == ' -fobjc-arc -Wfloat-equal'
:osx => ' -Wfloat-equal -fobjc-arc'
}
end end
it "returns the same list of dependencies for each platform" do it "returns the same list of dependencies for each platform" do
@spec.dependencies.should == { @spec.activate_platform(:ios).dependencies.should == [Pod::Dependency.new('JSONKit')]
:ios => [Pod::Dependency.new('JSONKit')], @spec.activate_platform(:osx).dependencies.should == [Pod::Dependency.new('SSZipArchive')]
:osx => [Pod::Dependency.new('SSZipArchive')]
}
end end
end end
end end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment