Commit 1801ce2d authored by Fabio Pelosin's avatar Fabio Pelosin

Merge pull request #253 from CocoaPods/spec-refactor

Specification refactor
parents 2f9a5fad 9511cc44
......@@ -4,6 +4,10 @@ module Pod
VERSION = '0.6.0rc1'
class Informative < StandardError
def message
#TODO: remove formatting from raise calls and remove conditional
super !~ /\[!\]/ ? "[!] #{super}\n".red : super
end
end
autoload :Command, 'cocoapods/command'
......
......@@ -27,7 +27,6 @@ module Pod
[
["--no-clean", "Leave SCM dirs like `.git' and `.svn' intact after downloading"],
["--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-update", "Skip running `pod repo update` before install"],
].concat(super)
......@@ -36,7 +35,6 @@ module Pod
def initialize(argv)
config.clean = !argv.option('--no-clean')
config.generate_docs = !argv.option('--no-doc')
config.force_doc = argv.option('--force-doc')
config.integrate_targets = !argv.option('--no-integrate')
@update_repo = !argv.option('--no-update')
super unless argv.empty?
......
......@@ -23,7 +23,7 @@ module Pod
# specification information
def spec
@spec ||= @set.specification.part_of_other_pod? ? @set.specification.part_of_specification : @set.specification
@set.specification
end
def authors
......@@ -47,7 +47,7 @@ module Pod
end
def platform
spec.platform.to_s
spec.available_platforms.sort { |a,b| a.to_s.downcase <=> b.to_s.downcase }.join(' - ')
end
def license
......@@ -98,6 +98,7 @@ module Pod
end
def distance_from_now_in_words(from_time)
return nil unless from_time
from_time = Time.parse(from_time)
to_time = Time.now
distance_in_days = (((to_time - from_time).abs)/60/60/24).round
......
......@@ -62,42 +62,39 @@ module Pod
def lint
puts
invalid_count = lint_podspecs
count = specs_to_lint.count
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
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
private
def lint_podspecs
specs_count, invalid_count = 0, 0
podspecs_to_lint.each do |podspec_file|
root_spec = Specification.from_file(podspec_file)
specs = root_spec.recursive_subspecs.any? ? root_spec.recursive_subspecs : [root_spec]
specs.each do |spec|
# Show immediatly which pod is being processed.
print " -> #{spec}\r" unless config.silent? || is_repo?
$stdout.flush
linter = Linter.new(spec, podspec_file)
linter.lenient = @only_errors
linter.quick = @quick || is_repo?
invalid_count += 1 unless linter.lint
# This overwrites the previously printed text
puts " -> ".send(lint_result_color(linter)) << spec.to_s unless config.silent? || should_skip?(linter)
print_messages(spec, 'ERROR', linter.errors)
print_messages(spec, 'WARN', linter.warnings)
print_messages(spec, 'NOTE', linter.notes)
puts unless config.silent? || should_skip?(linter)
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
invalid_count = 0
specs_to_lint.each do |spec|
# Show immediatly which pod is being processed.
print " -> #{spec}\r" unless config.silent? || is_repo?
$stdout.flush
linter = Linter.new(spec)
linter.lenient = @only_errors
linter.quick = @quick || is_repo?
invalid_count += 1 unless linter.lint
# This overwrites the previously printed text
puts " -> ".send(lint_result_color(linter)) << spec.to_s unless config.silent? || should_skip?(linter)
print_messages(spec, 'ERROR', linter.errors)
print_messages(spec, 'WARN', linter.warnings)
print_messages(spec, 'NOTE', linter.notes)
puts unless config.silent? || should_skip?(linter)
end
puts "Analyzed #{specs_to_lint.count} specs in #{podspecs_to_lint.count} podspecs files.\n\n" if is_repo? && !config.silent?
invalid_count
end
def lint_result_color(linter)
......@@ -116,55 +113,36 @@ module Pod
def print_messages(spec, type, messages)
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}"}
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
@podspecs_to_lint ||= begin
if (is_repo?)
files = (config.repos_dir + @repo_or_podspec).glob('**/*.podspec')
elsif @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
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
files
end
end
def is_repo?
@is_repo ||= @repo_or_podspec && (config.repos_dir + @repo_or_podspec).exist? && !@repo_or_podspec.include?('/')
end
def lint_passed_message
( podspecs_to_lint.count == 1 ? "#{podspecs_to_lint.first.basename} passed validation" : "All the specs passed validation" ).green << "\n\n"
def specs_to_lint
@specs_to_lint ||= begin
podspecs_to_lint.map do |podspec|
root_spec = Specification.from_file(podspec)
# TODO find a way to lint subspecs
# root_spec.preferred_dependency ? root_spec.subspec_dependencies : root_spec
end.flatten
end
end
def lint_failed_message(count)
( podspecs_to_lint.count == 1 ? "[!] The spec did not pass validation" : "[!] #{count} specs failed validation" ).red << "\n\n"
def is_repo?
@is_repo ||= @repo_or_podspec && (config.repos_dir + @repo_or_podspec).exist? && !@repo_or_podspec.include?('/')
end
# Linter class
......@@ -172,12 +150,15 @@ module Pod
class Linter
include Config::Mixin
# TODO: Add check to ensure that attributes inherited by subspecs are not duplicated ?
attr_accessor :quick, :lenient
attr_reader :spec, :file
attr_reader :errors, :warnings, :notes
def initialize(spec, podspec_file)
def initialize(spec)
@spec = spec
@file = podspec_file.realpath
@file = spec.defined_in_file.realpath
end
# Takes an array of podspec files and lints them all
......@@ -185,66 +166,74 @@ module Pod
# It returns true if the spec passed validation
#
def lint
# If the spec doesn't validate it raises and informative
# TODO: consider raising the informative in the clients of Pod::Specification#validate!
# and just report the errors here
peform_multiplatform_analysis unless quick
# Skip validation if there are errors in the podspec as it would result in a crash
unless podspec_errors.empty?
@errors, @warnings, @notes = podspec_errors, [], ['[!] Fatal errors found skipping the rest of the validation']
return false
@platform_errors, @platform_warnings, @platform_notes = {}, {}, {}
platforms = @spec.available_platforms
platforms.each do |platform|
@platform_errors[platform], @platform_warnings[platform], @platform_notes[platform] = [], [], []
@spec.activate_platform(platform)
@platform = platform
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
valid?
end
def valid?
lenient ? errors.empty? : errors.empty? && warnings.empty?
end
# Get common messages
@errors = @platform_errors.values.reduce(:&) || []
@warnings = @platform_warnings.values.reduce(:&) || []
@notes = @platform_notes.values.reduce(:&) || []
def errors
@errors ||= file_patterns_errors + build_errors
end
platforms.each do |platform|
# Mark platform specific messages
@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
@warnings ||= podspec_warnings + deprecation_warnings
valid?
end
def notes
@notes ||= build_warnings
def valid?
lenient ? errors.empty? : ( errors.empty? && warnings.empty? )
end
# Performs platform specific analysis.
# It requires to download the source at each iteration
#
def peform_multiplatform_analysis
platform_names.each do |platform_name|
set_up_lint_environment
puts "\n\n#{spec} - Analyzing on #{Platform.new platform_name} platform.".green.reversed if config.verbose?
install_pod(platform_name)
puts "Building with xcodebuild.\n".yellow if config.verbose?
xcodebuild_output.concat(xcodebuild_output_for_platfrom(platform_name))
file_patterns_errors.concat(file_patterns_errors_for_platfrom(platform_name))
tear_down_lint_environment
end
end
def platform_names
spec.platform.name ? [spec.platform.name] : [:ios, :osx]
end
def install_pod(platform_name)
podfile = podfile_from_spec(platform_name)
def peform_extensive_analysis
set_up_lint_environment
install_pod
puts "Building with xcodebuild.\n".yellow if config.verbose?
# treat xcodebuild warnings as notes because the spec maintainer might not be the author of the library
xcodebuild_output.each { |msg| ( msg.include?('error') ? @platform_errors[@platform] : @platform_notes[@platform] ) << msg }
@platform_errors[@platform] += file_patterns_errors
@platform_warnings[@platform] += file_patterns_warnings
tear_down_lint_environment
end
def install_pod
podfile = podfile_from_spec
config.verbose
Installer.new(podfile).install!
installer = Installer.new(podfile)
installer.install!
@pod = installer.pods.find { |pod| pod.top_specification == @spec }
config.silent
end
def podfile_from_spec(platform_name)
name = spec.name
podspec = file.realpath.to_s
def podfile_from_spec
name = spec.name
podspec = file.realpath.to_s
platform_sym = @platform.to_sym
podfile = Pod::Podfile.new do
platform platform_name
platform(platform_sym)
dependency name, :podspec => podspec
end
end
......@@ -276,16 +265,18 @@ module Pod
# @return [Array<String>] List of the fatal defects detected in a podspec
def podspec_errors
messages = []
messages << "Missing name" unless spec.name
messages << "Missing version" unless spec.version
messages << "Missing summary" unless spec.summary
messages << "Missing homepage" unless spec.homepage
messages << "Missing author(s)" unless spec.authors
messages << "Missing source or part_of" unless spec.source || spec.part_of
messages << "Missing source_files" if spec.source_files.empty? && spec.subspecs.empty?
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)
messages << "The name of the spec should match the name of the file" unless names_match?
messages << "Unrecognized platfrom" unless platform_valid?
messages << "Missing name" unless spec.name
messages << "Missing version" unless spec.version
messages << "Missing summary" unless spec.summary
messages << "Missing homepage" unless spec.homepage
messages << "Missing author(s)" unless spec.authors
messages << "Missing source" unless spec.source
# 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
end
......@@ -296,6 +287,10 @@ module Pod
file.basename.to_s == root_name + '.podspec'
end
def platform_valid?
!spec.platform || [:ios, :osx].include?(spec.platform.name)
end
def paths_starting_with_a_slash_errors
messages = []
%w[source_files resources clean_paths].each do |accessor|
......@@ -322,16 +317,15 @@ module Pod
source = @spec.source || {}
text = @file.read
messages = []
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 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 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 << "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 << "Comments must be deleted" if text =~ /^\w*#\n\w*#/ # allow a single line comment as it is generally used in subspecs
messages << "Missing license type" unless license[:type]
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 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 << "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 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
end
......@@ -343,36 +337,26 @@ module Pod
# to features that are or will be deprecated
#
# @return [Array<String>]
#
def deprecation_warnings
text = @file.read
deprecations = []
deprecations << "`config.ios?' and `config.osx?' are deprecated and will be removed in version 0.7" if text. =~ /config\..?os.?/
deprecations << "The `post_install' hook is reserved for edge cases" if text. =~ /post_install/
deprecations << "`config.ios?' and `config.osx?' are deprecated" if text. =~ /config\..?os.?/
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
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
# 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?
messages = []
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
puts(output) if config.verbose?
messages
......@@ -381,48 +365,36 @@ module Pod
def process_xcode_build_output(output)
output_by_line = output.split("\n")
selected_lines = output_by_line.select do |l|
l.include?('error') && (l !~ /errors? generated\./) \
|| l.include?('warning') && (l !~ /warnings? generated\./)\
|| l.include?('note')
l.include?('error:') && (l !~ /errors? generated\./) \
|| l.include?('warning:') && (l !~ /warnings? generated\./)\
|| l.include?('note:')
end
selected_lines.map do |l|
new = l.gsub(/\/tmp\/CocoaPods\/Lint\/Pods\//,'') # Remove the unnecessary tmp path
new.gsub!(/^ */,' ') # Remove indentation
"XCODEBUILD > " << new # Mark
new.gsub!(/^ */,' ') # Remove indentation
"XCODEBUILD > " << new # Mark
end
end
def file_patterns_errors
@file_patterns_errors ||= []
end
# It checks that every file pattern specified in a spec yields
# 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)
Dir.chdir(config.project_pods_root + spec.name ) do
messages = []
messages += check_spec_files_exists(:source_files, platform_name, '*.{h,m,mm,c,cpp}')
messages += check_spec_files_exists(:resources, platform_name)
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.compact
end
def file_patterns_errors
messages = []
messages << "The sources did not match any file" if !@spec.source_files.empty? && @pod.source_files.empty?
messages << "The resources did not match any file" if !@spec.resources.empty? && @pod.resources.empty?
messages << "The preserve_paths did not match any file" if !@spec.preserve_paths.empty? && @pod.preserve_paths.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
end
def check_spec_files_exists(accessor, platform_name, options = {})
result = []
patterns = spec.send(accessor)[platform_name]
patterns.each do |original_pattern|
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
def file_patterns_warnings
messages = []
messages << "Unable to find a license file" unless @pod.license_file
messages
end
end
......
......@@ -12,7 +12,7 @@ module Pod
attr_accessor :repos_dir, :project_root, :project_pods_root
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 :git_cache_size
......@@ -21,12 +21,11 @@ module Pod
alias_method :silent?, :silent
alias_method :generate_docs?, :generate_docs
alias_method :doc_install?, :doc_install
alias_method :force_doc?, :force_doc
alias_method :integrate_targets?, :integrate_targets
def initialize
@repos_dir = Pathname.new(File.expand_path("~/.cocoapods"))
@verbose = @silent = @force_doc = false
@verbose = @silent = false
@clean = @generate_docs = @doc_install = @integrate_targets = true
end
......
......@@ -5,8 +5,6 @@ require 'open-uri'
module Pod
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_accessor :specification
......@@ -27,23 +25,20 @@ module Pod
raise Informative, "A dependency needs either a name and version requirements, " \
"a source hash, or a block which defines a podspec."
end
@only_part_of_other_pod = false
end
def ==(other)
super &&
@only_part_of_other_pod == other.only_part_of_other_pod &&
(@specification ? @specification == other.specification : @external_source == other.external_source)
super && (@specification ? @specification == other.specification : @external_source == other.external_source)
end
def subspec_dependency?
@name.include?('/')
end
def inline?
@inline_podspec
end
def external?
!@external_source.nil?
end
......@@ -75,7 +70,7 @@ module Pod
end
version.empty? ? @name : "#{@name} (#{version})"
end
def specification_from_sandbox(sandbox, platform)
@external_source.specification_from_sandbox(sandbox, platform)
end
......@@ -126,33 +121,33 @@ module Pod
raise Informative, "Unknown external source parameters for #{name}: #{params}"
end
end
class AbstractExternalSource
include Config::Mixin
attr_reader :name, :params
def initialize(name, params)
@name, @params = name, params
end
def specification_from_sandbox(sandbox, platform)
if local_pod = sandbox.installed_pod_named(name, platform)
local_pod.specification
local_pod.top_specification
else
copy_external_source_into_sandbox(sandbox)
local_pod = sandbox.installed_pod_named(name, platform)
local_pod.clean if config.clean?
local_pod.specification
local_pod.top_specification
end
end
def ==(other_source)
return if other_source.nil?
name == other_source.name && params == other_source.params
end
end
class GitSource < AbstractExternalSource
def copy_external_source_into_sandbox(sandbox)
puts " * Pre-downloading: '#{name}'" unless config.silent?
......@@ -161,7 +156,7 @@ module Pod
downloader.clean if config.clean?
end
end
def description
"from `#{@params[:git]}'".tap do |description|
description << ", commit `#{@params[:commit]}'" if @params[:commit]
......@@ -180,7 +175,7 @@ module Pod
output_path.open('w') { |f| f << io.read }
end
end
def description
"from `#{@params[:podspec]}'"
end
......
......@@ -11,8 +11,7 @@ module Pod
extend Executable
def self.for_pod(pod)
spec = pod.specification
spec = spec.part_of_specification if spec.part_of_other_pod?
spec = pod.top_specification
for_target(pod.root, spec.source.dup)
end
......
......@@ -13,7 +13,7 @@ module Pod
def download
prepare_cache
puts '->'.green << ' Cloning git repo' if config.verbose?
puts '-> Cloning git repo' if config.verbose?
if options[:tag]
download_tag
elsif options[:commit]
......@@ -26,7 +26,7 @@ module Pod
def prepare_cache
unless cache_exist?
puts '->'.green << " Creating cache git repo (#{cache_path})" if config.verbose?
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}"
......@@ -71,7 +71,7 @@ module Pod
end
def update_cache
puts '->'.green << " Updating cache git repo (#{cache_path})" if config.verbose?
puts "-> Updating cache git repo (#{cache_path})" if config.verbose?
Dir.chdir(cache_path) do
git "reset --hard HEAD"
git "clean -d -x -f"
......
......@@ -11,7 +11,7 @@ module Pod
executable :curl
executable :unzip
executable :tar
attr_accessor :filename, :download_path
def download
@filename = filename_with_type type
......@@ -41,7 +41,7 @@ module Pod
nil
end
end
def filename_with_type(type=:zip)
case type
when :zip
......@@ -54,7 +54,7 @@ module Pod
raise UnsupportedFileTypeError.new "Unsupported file type: #{type}"
end
end
def download_file(full_filename)
curl "-L -o '#{full_filename}' '#{url}'"
end
......
......@@ -7,8 +7,14 @@ module Pod
raise Informative, "Unable to locate the executable `#{name}'"
end
if Config.instance.verbose?
puts "-> #{bin} #{command}"
`#{bin} #{command} 1>&2`
print " $ #{name}...\r"
$stdout.flush
output = `#{bin} #{command} 2>&1`
puts " #{$?.exitstatus.zero? ? '-' : '!'.red} #{name} #{command}"
output = output.gsub(/ */,' ').gsub(/^ */,' ')
puts output unless output.strip.empty?
else
`#{bin} #{command} 2> /dev/null`
end
......
......@@ -12,9 +12,9 @@ module Pod
def initialize(pod)
@pod = pod
@specification = pod.specification
@specification = pod.top_specification
@target_path = pod.sandbox.root + 'Documentation' + pod.name
@options = pod.specification.documentation || {}
@options = @specification.documentation || {}
end
def name
......@@ -42,13 +42,11 @@ module Pod
end
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
def index_file
@pod.chdir do
Dir.glob('README*', File::FNM_CASEFOLD).first
end
@pod.readme_file.relative_path_from(@pod.root).to_s if @pod.readme_file
end
def spec_appledoc_options
......@@ -66,11 +64,9 @@ module Pod
'--keep-undocumented-objects',
'--keep-undocumented-members',
'--keep-intermediate-files',
'--exit-threshold', '2'
# appledoc exits with 1 if a warning was logged
'--exit-threshold', '2' # appledoc terminates with an exits status of 1 if a warning was logged
]
index = index_file
options += ['--index-desc', index] if index
options += ['--index-desc', index_file] if index_file
options += spec_appledoc_options
end
......@@ -82,6 +78,8 @@ module Pod
options = appledoc_options
options += ['--output', @target_path.to_s]
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
@target_path.mkpath
......
......@@ -26,7 +26,7 @@ module Pod
return @project if @project
@project = Pod::Project.new
@project.user_build_configurations = @podfile.user_build_configurations
activated_pods.each do |pod|
pods.each do |pod|
# Add all source files to the project grouped by pod
group = @project.add_pod_group(pod.name)
pod.source_files.each do |path|
......@@ -45,32 +45,32 @@ module Pod
end
def install_dependencies!
activated_pods.each do |pod|
marker = config.verbose ? "\n-> ".green : ''
unless should_install = !pod.exists? && !pod.specification.local?
puts marker + "Using #{pod}" unless config.silent?
else
puts marker + "Installing #{pod.specification}".green unless config.silent?
pods.each do |pod|
unless config.silent?
marker = config.verbose ? "\n-> ".green : ''
name = pod.top_specification.preferred_dependency ? "#{pod.top_specification.name}/#{pod.top_specification.preferred_dependency} (#{pod.top_specification.version})" : pod.to_s
puts marker << ( pod.exists? ? "Using #{name}" : "Installing #{name}".green )
end
unless pod.exists?
downloader = Downloader.for_pod(pod)
downloader.download
if config.clean
downloader.clean
pod.clean
end
# The docs need to be generated before cleaning because
# the documentation is created for all the subspecs.
generate_docs(pod)
pod.clean if config.clean
end
end
end
if (should_install && config.generate_docs?) || config.force_doc?
doc_generator = Generator::Documentation.new(pod)
if doc_generator.already_installed?
puts "Using Existing Documentation for #{pod.specification}".green if config.verbose?
else
puts "Installing Documentation for #{pod.specification}".green if config.verbose?
doc_generator.generate(config.doc_install?)
end
end
#TODO: move to generator ?
def generate_docs(pod)
doc_generator = Generator::Documentation.new(pod)
if ( config.generate_docs? && !doc_generator.already_installed? )
puts "-> Installing documentation" if config.verbose?
doc_generator.generate(config.doc_install?)
else
puts "-> Using existing documentation" if config.verbose?
end
end
......@@ -83,21 +83,20 @@ module Pod
print_title "Installing dependencies"
install_dependencies!
pods = activated_pods
print_title("Generating support files\n", false)
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)
end
generate_lock_file!(pods)
generate_lock_file!(specifications)
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.
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)
UserProjectIntegrator.new(@podfile).integrate! if config.integrate_targets?
......@@ -107,7 +106,7 @@ module Pod
# we loop over target installers instead of pods, because we yield the target installer
# to the spec post install hook.
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)
end
end
......@@ -115,28 +114,28 @@ module Pod
@podfile.post_install!(self)
end
def generate_lock_file!(pods)
def generate_lock_file!(specs)
lock_file.open('w') do |file|
file.puts "PODS:"
# Get list of [name, dependencies] pairs.
activated_pods = pods.map do |pod|
[pod.specification.to_s, pod.dependencies.map(&:to_s).sort]
pod_and_deps = specs.map do |spec|
[spec.to_s, spec.dependencies.map(&:to_s).sort]
end.uniq
# Merge dependencies of ios and osx version of the same pod.
tmp = {}
activated_pods.each do |name, deps|
pod_and_deps.each do |name, deps|
if tmp[name]
tmp[name].concat(deps).uniq!
else
tmp[name] = deps
end
end
activated_pods = tmp
pod_and_deps = tmp
# 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?
file.puts " - #{name}"
else
......@@ -145,14 +144,6 @@ module Pod
end
end
unless download_only_specifications.empty?
file.puts
file.puts "DOWNLOAD_ONLY:"
download_only_specifications.map(&:to_s).sort.each do |name|
file.puts " - #{name}"
end
end
file.puts
file.puts "DEPENDENCIES:"
@podfile.dependencies.map(&:to_s).sort.each do |dep|
......@@ -179,49 +170,36 @@ module Pod
end
# @return [Array<Specification>] All dependencies that have been resolved.
def dependency_specifications
def specifications
specs_by_target.values.flatten
end
# @return [Array<LocalPod>] A list of LocalPod instances for each
# dependency that is not a download-only one.
def activated_pods
activated_pods_by_target.values.flatten
def pods
pods_by_target.values.flatten
end
def activated_pods_by_target
def pods_by_target
@pods_by_spec = {}
result = {}
specs_by_target.each do |target_definition, specs|
@pods_by_spec[target_definition.platform] = {}
result[target_definition] = specs.map do |spec|
LocalPod.new(spec, @sandbox, target_definition.platform) if activated_spec?(spec)
end.compact
pod = pod_for_spec(spec, target_definition.platform)
pod.add_specification(spec)
pod
end.uniq.compact
end
result
end
# @return [Array<Specification>] A list of specifications for each
# dependency that is not a download-only
# 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
def pod_for_spec(spec, platform)
@pods_by_spec[platform][spec.top_level_parent.name] ||= LocalPod.new(spec, @sandbox, platform)
end
private
def activated_spec?(spec)
# Don't activate specs which are only wrappers of subspecs, or share
# source with another pod but aren't activated themselves.
!spec.wrapper? && !@resolver.cached_sets[spec.name].only_part_of_other_pod?
end
def print_title(title, only_verbose = true)
if config.verbose?
puts "\n" + title.yellow
......
......@@ -41,7 +41,7 @@ module Pod
header.puts "#import #{@target_definition.platform == :ios ? '<UIKit/UIKit.h>' : '<Cocoa/Cocoa.h>'}"
header.puts "#endif"
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 prefix_header_contents
elsif prefix_header = pod.prefix_header_file
......@@ -63,19 +63,18 @@ module Pod
@target = @project.add_pod_target(@target_definition.label, @target_definition.platform)
pods.each do |pod|
# TODO add methods like xcconfig to LocalPod as well? (which returns the correct platform)
xcconfig.merge!(pod.specification.xcconfig[@target_definition.platform.name])
xcconfig.merge!(pod.xcconfig)
pod.add_to_target(@target)
# TODO: this doesn't need to be done here, it has nothing to do with the target
pod.link_headers
end
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.create_files(target_support_files)
xcconfig_file = support_files_group.files.where(:path => @target_definition.xcconfig_name)
configure_build_configurations(xcconfig_file)
create_files(pods, sandbox)
......@@ -93,24 +92,24 @@ module Pod
def create_files(pods, sandbox)
if @podfile.generate_bridge_support?
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)
copy_resources_script_for(pods).resources << @target_definition.bridge_support_name
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)
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)
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)
end
private
def quoted(strings)
strings.map { |s| "\"#{s}\"" }
end
def default_ld_flags
flags = %w{-ObjC}
flags << '-fobjc-arc' if @podfile.set_arc_compatibility_flag? && self.requires_arc
......
module Pod
class LocalPod
attr_reader :specification
attr_reader :top_specification, :specifications
attr_reader :sandbox
attr_reader :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
def self.from_podspec(podspec, sandbox, platform)
new(Specification.from_file(podspec), sandbox, platform)
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
@sandbox.root + specification.name
@sandbox.root + top_specification.name
end
def subspecs
specifications.reject{|s| s.parent.nil? }
end
def to_s
if specification.local?
"#{specification} [LOCAL]"
else
specification.to_s
end
result = top_specification.to_s
result << " [LOCAL]" if top_specification.local?
result
end
def name
specification.name
top_specification.name
end
def platform
top_specification.active_platform
end
# Installation methods
def create
root.mkpath unless exists?
end
......@@ -45,36 +64,75 @@ module Pod
root.rmtree if exists?
end
# It deletes all the files identified by clean_paths, then it removes
# all the empty folders or symlinks.
def clean
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
# File attributes
def prefix_header_file
if prefix_header = specification.prefix_header_file
@sandbox.root + specification.name + prefix_header
if prefix_header = top_specification.prefix_header_file
@sandbox.root + top_specification.name + prefix_header
end
end
def source_files
expanded_paths(specification.source_files, :glob => '*.{h,m,mm,c,cpp}', :relative_to_sandbox => true)
def source_files(relative = true)
chained_expanded_paths(:source_files, :glob => '*.{h,m,mm,c,cpp}', :relative_to_sandbox => relative)
end
def absolute_source_files
expanded_paths(specification.source_files, :glob => '*.{h,m,mm,c,cpp}')
def resources(relative = true)
chained_expanded_paths(:resources, :relative_to_sandbox => relative)
end
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
def resources
expanded_paths(specification.resources, :relative_to_sandbox => true)
# TODO: implement case insensitive search
def preserve_paths
chained_expanded_paths(:preserve_paths) + expanded_paths(%w[ *.podspec notice* NOTICE* CREDITS* ])
end
def header_files
source_files.select { |f| f.extname == '.h' }
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
copy_header_mappings.each do |namespaced_path, files|
@sandbox.add_header_files(namespaced_path, files)
......@@ -82,17 +140,17 @@ module Pod
end
def add_to_target(target)
implementation_files.each do |file|
target.add_source_file(file, nil, specification.compiler_flags[@platform.name].strip)
sources_files_by_specification.each do | spec, files |
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
def requires_arc?
specification.requires_arc
end
def dependencies
specification.dependencies[@platform.name]
top_specification.requires_arc
end
private
......@@ -107,17 +165,46 @@ module Pod
# 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.
#
# This is not overriden anymore in specification refactor and the code
# Pod::Specification#copy_header_mapping can be moved here.
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)
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
end
end
def expanded_paths(platforms_with_patterns, options = {})
patterns = platforms_with_patterns.is_a?(Hash) ? platforms_with_patterns[@platform.name] : platforms_with_patterns
# returns an hash where the source_files are groupped by specification.
# 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|
pattern = root + pattern
......
......@@ -10,7 +10,7 @@ module Pod
attr_reader :deployment_target
def initialize(symbolic_name, deployment_target = nil)
def initialize(symbolic_name = nil, deployment_target = nil)
@symbolic_name = symbolic_name
if deployment_target
version = deployment_target.is_a?(Hash) ? deployment_target[:deployment_target] : deployment_target # backwards compatibility from 0.6
......@@ -34,9 +34,11 @@ module Pod
end
end
def support?(other)
def supports?(other)
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
def to_s
......
......@@ -22,26 +22,19 @@ module Pod
@podfile.target_definitions.values.each do |target_definition|
puts "\nResolving dependencies for target `#{target_definition.name}' (#{target_definition.platform})".green if config.verbose?
@loaded_specs = []
# TODO @podfile.platform will change to target_definition.platform
find_dependency_sets(@podfile, target_definition.dependencies, target_definition)
find_dependency_specs(@podfile, target_definition.dependencies, target_definition)
targets_and_specs[target_definition] = @specs.values_at(*@loaded_specs).sort_by(&:name)
end
# Specification doesn't need to know more about the context, so we assign
# the other specification, of which this pod is a part, to the spec.
@specs.values.sort_by(&:name).each do |spec|
if spec.part_of_other_pod?
spec.part_of_specification = @cached_sets[spec.part_of.name].specification
end
end
@specs.values.sort_by(&:name)
targets_and_specs
end
private
def find_cached_set(dependency, platform)
@cached_sets[dependency.name] ||= begin
set_name = dependency.name.split('/').first
@cached_sets[set_name] ||= begin
if dependency.specification
Specification::Set::External.new(dependency.specification)
elsif external_source = dependency.external_source
......@@ -60,7 +53,7 @@ module Pod
end
end
def find_dependency_sets(dependent_specification, dependencies, target_definition)
def find_dependency_specs(dependent_specification, dependencies, target_definition)
@log_indent += 1
dependencies.each do |dependency|
puts ' ' * @log_indent + "- #{dependency}" if config.verbose?
......@@ -68,19 +61,12 @@ module Pod
set.required_by(dependent_specification)
# Ensure we don't resolve the same spec twice for one target
unless @loaded_specs.include?(dependency.name)
# Get a reference to the spec that’s actually being loaded.
# 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
spec = set.specification_by_name(dependency.name)
@loaded_specs << spec.name
@specs[spec.name] = spec
spec.activate_platform(target_definition.platform)
# 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_sets(spec, (spec.dependencies[target_definition.platform.to_sym] || []), target_definition)
find_dependency_specs(spec, spec.dependencies, target_definition) if spec.dependencies
end
validate_platform!(spec || @specs[dependency.name], target_definition)
end
......@@ -88,8 +74,8 @@ module Pod
end
def validate_platform!(spec, target)
unless spec.platforms.any? { |platform| target.platform.support?(platform) }
raise Informative, "[!] The platform of the target `#{target.name}' (#{target.platform}) is not compatible with `#{spec}' which has a minimun requirement of #{spec.platforms.join(' - ')}.".red
unless spec.available_platforms.any? { |platform| target.platform.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.available_platforms.join(' - ')}.".red
end
end
end
......
......@@ -68,7 +68,7 @@ module Pod
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
# 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
......
require 'xcodeproj/config'
require 'colored'
module Pod
extend Config::Mixin
......@@ -12,144 +11,97 @@ module Pod
autoload :Set, 'cocoapods/specification/set'
autoload :Statistics, 'cocoapods/specification/statistics'
### Initalization
# The file is expected to define and return a Pods::Specification.
def self.from_file(path)
# If name is equals to nil it returns the top level Specification,
# otherwise it returned the specification with the name that matches
def self.from_file(path, subspec_name = nil)
unless path.exist?
raise Informative, "No podspec exists at path `#{path}'."
end
spec = ::Pod._eval_podspec(path)
spec.defined_in_file = path
spec
spec.subspec_by_name(subspec_name)
end
attr_accessor :defined_in_file
def initialize
post_initialize
yield self if block_given?
end
# TODO This is just to work around a MacRuby bug
def post_initialize
def initialize(parent = nil, name = nil)
@parent, @name = parent, name
@define_for_platforms = [:osx, :ios]
@clean_paths, @subspecs = [], []
@dependencies, @source_files, @resources = { :ios => [], :osx => [] }, { :ios => [], :osx => [] }, { :ios => [], :osx => [] }
@deployment_target = {}
@platform = Platform.new(nil)
@xcconfig = { :ios => Xcodeproj::Config.new, :osx => Xcodeproj::Config.new }
@compiler_flags = { :ios => '', :osx => '' }
end
# Attributes **without** multiple platform support
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 }
unless parent
@source = {:git => ''}
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)
if license.kind_of?(Array)
@license = license[1].merge({:type => license[0]})
elsif license.kind_of?(String)
@license = {:type => license}
else
@license = license
# multi-platform attributes
%w[ source_files resources preserve_paths exclude_header_search_paths frameworks libraries dependencies compiler_flags].each do |attr|
instance_variable_set( "@#{attr}", { :ios => [], :osx => [] } )
end
end
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
@xcconfig = { :ios => Xcodeproj::Config.new, :osx => Xcodeproj::Config.new }
def prefix_header_file=(file)
@prefix_header_file = Pathname.new(file)
yield self if block_given?
end
attr_reader :prefix_header_file
attr_accessor :prefix_header_contents
### Meta programming
def clean_paths=(patterns)
@clean_paths = pattern_list(patterns)
end
attr_reader :clean_paths
alias_method :clean_path=, :clean_paths=
def header_dir=(dir)
@header_dir = Pathname.new(dir)
end
def header_dir
@header_dir || pod_destroot_name
# Creates a top level attribute reader. A lambda can
# be passed to process the ivar before returning it
def self.top_attr_reader(attr, read_lambda = nil)
define_method(attr) do
ivar = instance_variable_get("@#{attr}")
@parent ? top_level_parent.send(attr) : ( read_lambda ? read_lambda.call(self, ivar) : ivar )
end
end
def platform=(platform)
@platform = Platform.new(*platform)
# Creates a top level attribute writer. A lambda can
# 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
attr_reader :platform
def platforms
@platform.nil? ? @define_for_platforms.map { |platfrom| Platform.new(platfrom, @deployment_target[platfrom]) } : [platform]
# Creates a top level attribute accessor. A lambda can
# be passed to initialize the value in the attribute writer.
def self.top_attr_accessor(attr, writer_labmda = nil)
top_attr_reader attr
top_attr_writer attr, writer_labmda
end
def requires_arc=(requires_arc)
self.compiler_flags = '-fobjc-arc' if requires_arc
@requires_arc = requires_arc
# Returns the value of the attribute for the active platform
# chained with the upstream specifications. The ivar must store
# 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
attr_reader :requires_arc
def subspec(name, &block)
subspec = Subspec.new(self, name, &block)
@subspecs << subspec
subspec
def active_plaform_check
raise Informative, "#{self.inspect} not activated for a platform before consumption." unless active_platform
end
attr_reader :subspecs
def recursive_subspecs
unless @recursive_subspecs
mapper = lambda do |spec|
spec.subspecs.map do |subspec|
[subspec, *mapper.call(subspec)]
end.flatten
end
@recursive_subspecs = mapper.call self
# Attribute writer that works in conjuction with the PlatformProxy.
def self.platform_attr_writer(attr, block = nil)
define_method("#{attr}=") do |value|
current = instance_variable_get("@#{attr}")
@define_for_platforms.each do |platform|
block ? current[platform] = block.call(value, current[platform]) : current[platform] = value
end
end
@recursive_subspecs
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
def initialize(specification, platform)
@specification, @platform = specification, platform
......@@ -172,100 +124,208 @@ module Pod
PlatformProxy.new(self, :osx)
end
def source_files=(patterns)
@define_for_platforms.each do |platform|
@source_files[platform] = pattern_list(patterns)
end
### Deprecated attributes - TODO: remove once master repo and fixtures have been updated
attr_writer :part_of_dependency
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
attr_accessor :summary
def name
@parent ? "#{@parent.name}/#{@name}" : @name
end
attr_reader :source_files
def deployment_target=(version)
raise Informative, "The deployment target must be defined per platform like s.ios.deployment_target = '5.0'" unless @define_for_platforms.count == 1
@deployment_target[@define_for_platforms.first] = version
attr_writer :name
def description
@description || summary
end
def resources=(patterns)
@define_for_platforms.each do |platform|
@resources[platform] = pattern_list(patterns)
end
# TODO: consider converting the following to top level attributes
# A subspec should have a summary instead of a description.
# Some subspecs contain a homepage but we never use this information.
attr_writer :description
attr_accessor :homepage
### Attributes that return the first value defined in the chain
def platform
@platform || ( @parent ? @parent.platform : nil )
end
attr_reader :resources
alias_method :resource=, :resources=
def xcconfig=(build_settings)
@define_for_platforms.each do |platform|
@xcconfig[platform].merge!(build_settings)
def platform=(platform)
@platform = Platform.new(*platform)
end
# If not platform is specified all the platforms are returned.
def available_platforms
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 :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 :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
authors || list.first
end
attr_reader :xcconfig
def frameworks=(*frameworks)
frameworks.unshift('')
self.xcconfig = { 'OTHER_LDFLAGS' => frameworks.join(' -framework ').strip }
### Attributes **with** multiple platform support
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
alias_method :framework=, :frameworks=
def libraries=(*libraries)
libraries.unshift('')
self.xcconfig = { 'OTHER_LDFLAGS' => libraries.join(' -l').strip }
def raw_xconfig
@parent ? @parent.raw_xconfig.merge(@xcconfig[active_platform]) : @xcconfig[active_platform]
end
alias_method :library=, :libraries=
attr_reader :compiler_flags
def compiler_flags=(flags)
@define_for_platforms.each do |platform|
@compiler_flags[platform] << ' ' << flags
platform_attr_writer :xcconfig, lambda {|value, current| current.tap { |c| c.merge!(value) } }
def compiler_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
chained.join(' ')
end
platform_attr_writer :compiler_flags, lambda {|value, current| current << value }
def dependency(*name_and_version_requirements)
name, *version_requirements = name_and_version_requirements.flatten
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)
@define_for_platforms.each do |platform|
@dependencies[platform] << dep
end
dep
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
#
# This is used by PlatformProxy to assign attributes for the scoped platform.
def _on_platform(platform)
before, @define_for_platforms = @define_for_platforms, [platform]
yield
ensure
@define_for_platforms = before
# A specification inherits the preferred_dependency or
# all the compatible subspecs as dependencies
def subspec_dependencies
active_plaform_check
specs = preferred_dependency ? [subspec_by_name("#{name}/#{preferred_dependency}")] : subspecs
specs.compact \
.select { |s| s.supports_platform?(active_platform) } \
.map { |s| Dependency.new(s.name, version) }
end
def dependencies
external_dependencies + subspec_dependencies
end
include Config::Mixin
def local?
!source.nil? && !source[:local].nil?
def top_level_parent
@parent ? @parent.top_level_parent : self
end
def local_path
Pathname.new(File.expand_path(source[:local]))
def subspec(name, &block)
subspec = Specification.new(self, name, &block)
@subspecs << subspec
subspec
end
attr_reader :subspecs
# This is assigned the other spec, of which this pod's source is a part, by
# a Resolver.
attr_accessor :part_of_specification
def part_of_specification
@part_of_specification || begin
set = Source.search(@part_of)
set.required_by(self)
set.specification
def recursive_subspecs
unless @recursive_subspecs
mapper = lambda do |spec|
spec.subspecs.map do |subspec|
[subspec, *mapper.call(subspec)]
end.flatten
end
@recursive_subspecs = mapper.call self
end
end
def wrapper?
source_files.values.all?(&:empty?) && !subspecs.empty?
@recursive_subspecs
end
def subspec_by_name(name)
return self if name.nil? || name == self.name
# Remove this spec's name from the beginning of the name we’re looking for
# and take the first component from the remainder, which is the spec we need
# to find now.
......@@ -278,28 +338,19 @@ module Pod
remainder.empty? ? subspec : subspec.subspec_by_name(name)
end
def ==(other)
object_id == other.object_id ||
(self.class === other &&
name && name == other.name &&
version && version == other.version)
def local?
!source.nil? && !source[:local].nil?
end
def dependency_by_top_level_spec_name(name)
@dependencies.each do |_, platform_deps|
platform_deps.each do |dep|
return dep if dep.top_level_spec_name == name
end
end
def local_path
Pathname.new(File.expand_path(source[:local]))
end
def pod_destroot
if part_of_other_pod?
part_of_specification.pod_destroot
elsif local?
if local?
local_path
else
config.project_pods_root + @name
config.project_pods_root + top_level_parent.name
end
end
......@@ -309,15 +360,7 @@ module Pod
end
end
def part_of_other_pod?
!part_of.nil?
end
def podfile?
false
end
def pattern_list(patterns)
def self.pattern_list(patterns)
if patterns.is_a?(Array) && (!defined?(Rake) || !patterns.is_a?(Rake::FileList))
patterns
else
......@@ -329,18 +372,10 @@ module Pod
# in the pod's header dir.
#
# 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
# copy_header_mappings for full control.
# namespacing. However if the top level attribute accessor header_mappings_dir
# is specified the namespacing will be preserved from that directory.
def copy_header_mapping(from)
from.basename
end
def to_s
"#{name} (#{version})"
end
def inspect
"#<#{self.class.name} for #{to_s}>"
header_mappings_dir ? from.relative_path_from(header_mappings_dir) : from.basename
end
# This is a convenience method which gets called after all pods have been
......@@ -359,53 +394,76 @@ module Pod
def post_install(target)
end
class Subspec < Specification
attr_reader :parent
def podfile?
false
end
def initialize(parent, name)
@parent, @name = parent, name
# TODO a MacRuby bug, the correct super impl `initialize' is not called consistently
#super(&block)
post_initialize
# This is used by the specification set
def dependency_by_top_level_spec_name(name)
external_dependencies(true).each do |dep|
return dep if dep.top_level_spec_name == name
end
end
# A subspec is _always_ part of the source of its top level spec.
self.part_of = top_level_parent.name, version
# A subspec has a dependency on the parent if the parent is a subspec too.
dependency(@parent.name, version) if @parent.is_a?(Subspec)
def to_s
"#{name} (#{version})"
end
yield self if block_given?
end
def inspect
"#<#{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
top_level_parent = @parent
top_level_parent = top_level_parent.parent while top_level_parent.is_a?(Subspec)
top_level_parent
end
# Returns whether the specification is supported in a given platform
def supports_platform?(*platform)
platform = platform[0].is_a?(Platform) ? platform[0] : Platform.new(*platform)
available_platforms.any? { |p| platform.supports?(p) }
end
def name
"#{@parent.name}/#{@name}"
end
# Defines the active platform for comsumption of the specification and
# returns self for method chainability.
# 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,
# but need to think if there's a better way to do this.
top_attr_accessor :active_platform
def summary
@summary ? @summary : top_level_parent.summary
end
### Not attributes
# Override the getters to always return the value of the top level parent spec.
[:version, :summary, :platform, :license, :authors, :requires_arc, :compiler_flags, :documentation, :homepage].each do |attr|
define_method(attr) { top_level_parent.send(attr) }
end
# @visibility private
#
# This is used by PlatformProxy to assign attributes for the scoped platform.
def _on_platform(platform)
before, @define_for_platforms = @define_for_platforms, [platform]
yield
ensure
@define_for_platforms = before
end
def copy_header_mapping(from)
top_level_parent.copy_header_mapping(from)
end
# @visibility private
#
# 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
def deployment_target(platform)
@deployment_target[platform] || ( @parent ? @parent.deployment_target(platform) : nil )
end
end
Spec = Specification
end
......@@ -9,6 +9,9 @@ module Pod
end
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)
# 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))
......@@ -21,16 +24,16 @@ module Pod
@required_by << specification
end
def specification_by_name(name)
specification.top_level_parent.subspec_by_name(name)
end
def dependency
@required_by.inject(Dependency.new(name)) do |previous, spec|
previous.merge(spec.dependency_by_top_level_spec_name(name).to_top_level_spec_dependency)
end
end
def only_part_of_other_pod?
@required_by.all? { |spec| spec.dependency_by_top_level_spec_name(name).only_part_of_other_pod? }
end
def name
@pod_dir.basename.to_s
end
......@@ -74,7 +77,7 @@ module Pod
end
def name
@specification.name
@specification.top_level_parent.name
end
def ==(other)
......@@ -88,10 +91,6 @@ module Pod
@specification = before
end
def only_part_of_other_pod?
false
end
def specification_path
raise "specification_path"
end
......
......@@ -81,7 +81,7 @@ module Pod
def github_stats_if_needed(set)
return if get_value(set, :gh_date) && get_value(set, :gh_date) > Time.now - cache_expiration
spec = set.specification.part_of_other_pod? ? set.specification.part_of_specification : set.specification
spec = set.specification
url = spec.source.reject {|k,_| k == :commit || k == :tag }.values.first
repo_id = url[/github.com\/([^\/\.]*\/[^\/\.]*)\.*/, 1]
return unless repo_id
......
Subproject commit 7e96b1af54872aba6e474ea5860e84f1ce534fb1
Subproject commit 7aec148979834c795a0c7f3108b4d48a9f1c0f5c
require File.expand_path('../../../spec_helper', __FILE__)
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
Pod::Command::Install.banner.should.match %r{xcodeproj 'path/to/XcodeProject'}
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__)
describe "Pod::Command::List" do
extend SpecHelper::Git
extend SpecHelper::TemporaryRepos
before do
config.repos_dir = fixture('spec-repos')
end
after do
config.repos_dir = tmp_repos_path
end
def command(arguments = argv)
command = Pod::Command::List.new(arguments)
end
......
......@@ -2,8 +2,12 @@ require File.expand_path('../../../spec_helper', __FILE__)
describe Pod::Command::Push do
extend SpecHelper::Command
extend SpecHelper::Git
extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
def master_repo
fixture('spec-repos/master')
end
it "complains for wrong parameters" do
lambda { run_command('push') }.should.raise Pod::Command::Help
......@@ -12,19 +16,19 @@ describe Pod::Command::Push do
end
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
lambda { run_command('push', 'repo2') }.should.raise Pod::Informative
end
end
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
end
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
repo2 = add_repo('repo2', repo1.dir)
git_config('repo2', 'remote.origin.url').should == (tmp_repos_path + 'repo1').to_s
......@@ -36,7 +40,7 @@ describe Pod::Command::Push do
before do
# 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
@local_repo = add_repo('local_repo', @upstream.dir)
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__)
describe "Pod::Command::Repo" do
extend SpecHelper::Command
extend SpecHelper::Git
extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
it "runs with correct parameters" do
lambda { run_command('repo', 'add', 'NAME', 'URL') }.should.not.raise
......@@ -42,6 +42,7 @@ describe "Pod::Command::Repo" do
before do
add_repo('repo1', fixture('spec-repos/master'))
FileUtils.rm_rf(versions_file)
versions_file.should.not.exist?
end
......
......@@ -2,18 +2,13 @@ require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::Search" do
extend SpecHelper::Command
extend SpecHelper::Git
extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
before do
config.repos_dir = fixture('spec-repos')
end
after do
config.repos_dir = tmp_repos_path
end
it "runs with correct parameters" do
lambda { run_command('search', 'table') }.should.not.raise
lambda { run_command('search', 'table', '--full') }.should.not.raise
......
......@@ -3,8 +3,8 @@ require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::Setup" do
extend SpecHelper::Command
extend SpecHelper::Git
extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
it "runs with correct parameters" do
lambda { run_command('setup') }.should.not.raise
......
......@@ -18,21 +18,22 @@ describe "Pod::Command::Spec#create" do
extend SpecHelper::Command
extend SpecHelper::Github
extend SpecHelper::TemporaryDirectory
extend SpecHelper::Git
extend SpecHelper::TemporaryRepos
it "creates a new podspec stub file" do
run_command('spec', 'create', 'Bananas')
path = temporary_directory + 'Bananas.podspec'
spec = Pod::Specification.from_file(path)
spec.name.should == 'Bananas'
spec.license.should == { :type => "MIT", :file => "LICENSE" }
spec.version.should == Pod::Version.new('0.0.1')
spec.summary.should == 'A short description of Bananas.'
spec.homepage.should == 'http://EXAMPLE/Bananas'
spec.authors.should == { `git config --get user.name`.strip => `git config --get user.email`.strip}
spec.source.should == { :git => 'http://EXAMPLE/Bananas.git', :tag => '0.0.1' }
spec.description.should == 'An optional longer description of Bananas.'
spec.source_files[:ios].should == ['Classes', 'Classes/**/*.{h,m}']
spec = Pod::Specification.from_file(path).activate_platform(:ios)
spec.name.should == 'Bananas'
spec.license.should == { :type => "MIT", :file => "LICENSE" }
spec.version.should == Pod::Version.new('0.0.1')
spec.summary.should == 'A short description of Bananas.'
spec.homepage.should == 'http://EXAMPLE/Bananas'
spec.authors.should == { `git config --get user.name`.strip => `git config --get user.email`.strip}
spec.source.should == { :git => 'http://EXAMPLE/Bananas.git', :tag => '0.0.1' }
spec.description.should == 'An optional longer description of Bananas.'
spec.source_files.should == ['Classes', 'Classes/**/*.{h,m}']
end
it "correctly creates a podspec from github" do
......@@ -93,16 +94,12 @@ end
describe "Pod::Command::Spec#lint" do
extend SpecHelper::Command
extend SpecHelper::TemporaryDirectory
extend SpecHelper::Git
extend SpecHelper::TemporaryRepos
before do
config.repos_dir = fixture('spec-repos')
end
after do
config.repos_dir = tmp_repos_path
end
it "lints a repo" do
# The fixture has an error due to a name mismatch
cmd = command('spec', 'lint', 'master')
......@@ -124,17 +121,23 @@ describe "Pod::Command::Spec#lint" do
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
spec_file = fixture('spec-repos') + 'master/JSONKit/1.4/JSONKit.podspec'
cmd = command('spec', 'lint', '--quick', spec_file.to_s)
cmd = command('spec', 'lint', '--quick', @spec_path)
lambda { cmd.run }.should.raise Pod::Informative
cmd.output.should.include "Missing license[:file] or [:text]"
cmd.output.should.include "Missing license type"
end
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_file.to_s)
cmd = command('spec', 'lint', '--quick', '--only-errors', @spec_path)
lambda { cmd.run }.should.not.raise
cmd.output.should.include "Missing license[:file] or [:text]"
cmd.output.should.include "Missing license type"
end
end
......@@ -2,8 +2,8 @@ require File.expand_path('../../spec_helper', __FILE__)
# describe "Pod::Command" do
# extend SpecHelper::Command
# extend SpecHelper::Git
# extend SpecHelper::TemporaryDirectory
# extend SpecHelper::TemporaryRepos
#
# TODO:
# it "raises help informative if an unknown parameter is passed"
......
......@@ -7,28 +7,28 @@ describe "Pod::Downloader" do
describe "for Git" do
extend SpecHelper::TemporaryDirectory
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'
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.download
(@pod.root + 'README').read.strip.should == 'first commit'
end
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'
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.download
(@pod.root + 'README').read.strip.should == 'v1.0'
end
it "removes the .git directory when cleaning" do
@pod.specification.stubs(:source).returns(
@pod.top_specification.stubs(:source).returns(
:git => fixture('banana-lib')
)
downloader = Pod::Downloader.for_pod(@pod)
......@@ -37,60 +37,60 @@ describe "Pod::Downloader" do
(@pod.root + '.git').should.not.exist
end
end
describe "for Github repositories, with :download_only set to true" do
extend SpecHelper::TemporaryDirectory
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
)
downloader = Pod::Downloader.for_pod(@pod)
VCR.use_cassette('tarballs', :record => :new_episodes) { downloader.download }
# deliberately keep this assertion as loose as possible for now
(@pod.root + 'README.md').readlines[0].should =~ /libPusher/
end
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
)
downloader = Pod::Downloader.for_pod(@pod)
VCR.use_cassette('tarballs', :record => :new_episodes) { downloader.download }
# deliberately keep this assertion as loose as possible for now
(@pod.root + 'libPusher.podspec').readlines.grep(/1.1/).should.not.be.empty
end
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
)
downloader = Pod::Downloader.for_pod(@pod)
VCR.use_cassette('tarballs', :record => :new_episodes) { downloader.download }
# deliberately keep this assertion as loose as possible for now
(@pod.root + 'README.md').readlines[0].should =~ /PusherTouch/
end
it 'deletes the downloaded tarball after unpacking it' do
@pod.specification.stubs(:source).returns(
@pod.top_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(
@pod.top_specification.stubs(:source).returns(
:git => "git://github.com/lukeredpath/libPusher.git", :download_only => false
)
downloader = Pod::Downloader.for_pod(@pod)
......@@ -98,21 +98,21 @@ describe "Pod::Downloader" do
downloader.clean
(@pod.root + '.git').should.not.exist
end
end
describe "for Mercurial" 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'
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.download
(@pod.root + 'README').read.strip.should == 'first commit'
end
it "removes the .hg directory when cleaning" do
@pod.specification.stubs(:source).returns(
@pod.top_specification.stubs(:source).returns(
:hg => fixture('mercurial-repo')
)
downloader = Pod::Downloader.for_pod(@pod)
......@@ -121,28 +121,28 @@ describe "Pod::Downloader" do
(@pod.root + '.hg').should.not.exist
end
end
describe "for Subversion" 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'
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.download
(@pod.root + 'README').read.strip.should == 'first commit'
end
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"
)
downloader = Pod::Downloader.for_pod(@pod)
downloader.download
(@pod.root + 'README').read.strip.should == 'tag 1'
end
it "removes the .svn directories when cleaning" do
@pod.specification.stubs(:source).returns(
@pod.top_specification.stubs(:source).returns(
:svn => "file://#{fixture('subversion-repo')}/trunk"
)
downloader = Pod::Downloader.for_pod(@pod)
......@@ -156,7 +156,7 @@ describe "Pod::Downloader" do
extend SpecHelper::TemporaryDirectory
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'
)
downloader = Pod::Downloader.for_pod(@pod)
......@@ -167,7 +167,7 @@ describe "Pod::Downloader" do
end
it "removes the .zip when cleaning" do
@pod.specification.stubs(:source).returns(
@pod.top_specification.stubs(:source).returns(
:http => 'http://dl.google.com/googleadmobadssdk/googleadmobsearchadssdkios.zip'
)
downloader = Pod::Downloader.for_pod(@pod)
......@@ -176,7 +176,7 @@ describe "Pod::Downloader" do
(@pod.root + 'file.zip').should.not.exist
end
end
end
......@@ -29,10 +29,6 @@ describe Pod::Installer::UserProjectIntegrator do
@sample_project = Xcodeproj::Project.new(@sample_project_path)
end
after do
config.project_root = nil
end
it 'creates a workspace with a name matching the project' do
workspace_path = @sample_project_path.dirname + "SampleProject.xcworkspace"
workspace_path.should.exist
......@@ -42,12 +38,12 @@ describe Pod::Installer::UserProjectIntegrator do
workspace = Xcodeproj::Workspace.new_from_xcworkspace(@sample_project_path.dirname + "SampleProject.xcworkspace")
workspace.projpaths.sort.should == %w{ Pods/Pods.xcodeproj SampleProject.xcodeproj }
end
it 'adds the Pods project to the workspace' do
workspace = Xcodeproj::Workspace.new_from_xcworkspace(@sample_project_path.dirname + "SampleProject.xcworkspace")
workspace.projpaths.find { |path| path =~ /Pods.xcodeproj/ }.should.not.be.nil
end
it 'sets the Pods xcconfig as the base config for each build configuration' do
@podfile.target_definitions.each do |_, definition|
target = @sample_project.targets.where(:name => definition.link_with.first)
......@@ -70,7 +66,7 @@ describe Pod::Installer::UserProjectIntegrator do
framework_build_phase.files.where(:name => definition.lib_name).should.not == nil
end
end
it 'adds a Copy Pods Resources build phase to each target' do
@podfile.target_definitions.each do |_, definition|
target = @sample_project.targets.where(:name => definition.link_with.first)
......
......@@ -9,11 +9,9 @@ module SpecHelper
def specs_by_target
@specs_by_target ||= super.tap do |hash|
hash.values.flatten.each do |spec|
unless spec.part_of_other_pod?
source = spec.source
source[:git] = SpecHelper.fixture("integration/#{spec.name}").to_s
spec.source = source
end
source = spec.source
source[:git] = SpecHelper.fixture("integration/#{spec.name}").to_s
spec.source = source
end
end
end
......@@ -28,37 +26,14 @@ else
extend SpecHelper::TemporaryDirectory
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.project_root = temporary_directory
config.doc_install = false
config.integrate_targets = false
end
before do
fixture('spec-repos/master') # ensure the archive is unpacked
@config_before = 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
def should_successfully_perform(command)
......@@ -67,11 +42,14 @@ else
$?.should.be.success
end
puts " ! ".red << "Skipping xcodebuild based checks, because it can't be found." if `which xcodebuild`.strip.empty?
def should_xcodebuild(target_definition)
return if `which xcodebuilda`.strip.empty?
target = target_definition
with_xcodebuild_available 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}'"
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'}"
......@@ -113,13 +91,13 @@ else
installer.install!
YAML.load(installer.lock_file.read).should == {
'PODS' => [{ 'Reachability (1.2.3)' => ["ASIHTTPRequest (>= 1.8)"] }],
'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"],
'PODS' => [ 'Reachability (1.2.3)' ],
# 'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"],
'DEPENDENCIES' => ["Reachability (from `#{url}')"]
}
end
it "install a dummy source file" do
it "installs a dummy source file" do
create_config!
podfile = Pod::Podfile.new do
self.platform :ios
......@@ -131,7 +109,7 @@ else
s.source_files = 'JSONKit.*'
end
end
installer = SpecHelper::Installer.new(podfile)
installer.install!
......@@ -157,6 +135,7 @@ else
end
end
Pod::Specification.any_instance.stubs(:preserve_paths).returns(['CHANGELOG.md'])
installer = SpecHelper::Installer.new(podfile)
installer.install!
......@@ -199,7 +178,16 @@ else
unless `which appledoc`.strip.empty?
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
self.platform :ios
......@@ -207,9 +195,6 @@ else
dependency 'JSONKit', '1.4'
dependency 'SSToolkit'
end
Pod::Generator::Documentation.any_instance.stubs(:already_installed?).returns(false)
installer = SpecHelper::Installer.new(podfile)
installer.install!
......@@ -219,7 +204,7 @@ else
doc.should.include?('<title>SSToolkit 0.1.2 Reference</title>')
end
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
......@@ -249,12 +234,13 @@ else
end
# 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
podfile = Pod::Podfile.new do
self.platform platform
xcodeproj 'dummy'
dependency 'Reachability', '> 2.0.5' if platform == :ios
dependency 'ASIWebPageRequest', '>= 1.8.1'
# dependency 'ASIWebPageRequest', '>= 1.8.1'
dependency 'JSONKit', '>= 1.0'
dependency 'SSZipArchive', '< 2'
end
......@@ -264,14 +250,14 @@ else
lock_file_contents = {
'PODS' => [
{ 'ASIHTTPRequest (1.8.1)' => ["Reachability"] },
{ 'ASIWebPageRequest (1.8.1)' => ["ASIHTTPRequest (= 1.8.1)"] },
# { 'ASIHTTPRequest (1.8.1)' => ["Reachability"] },
# { 'ASIWebPageRequest (1.8.1)' => ["ASIHTTPRequest (= 1.8.1)"] },
'JSONKit (1.5pre)',
'Reachability (3.0.0)',
'SSZipArchive (0.1.2)',
],
'DEPENDENCIES' => [
"ASIWebPageRequest (>= 1.8.1)",
# "ASIWebPageRequest (>= 1.8.1)",
"JSONKit (>= 1.0)",
"Reachability (> 2.0.5)",
"SSZipArchive (< 2)",
......@@ -279,9 +265,9 @@ else
}
unless platform == :ios
# No Reachability is required by ASIHTTPRequest on OSX
lock_file_contents['DEPENDENCIES'].delete_at(2)
lock_file_contents['PODS'].delete_at(3)
lock_file_contents['PODS'][0] = 'ASIHTTPRequest (1.8.1)'
lock_file_contents['DEPENDENCIES'].delete_at(1)
lock_file_contents['PODS'].delete_at(1)
# lock_file_contents['PODS'][0] = 'ASIHTTPRequest (1.8.1)'
end
YAML.load(installer.lock_file.read).should == lock_file_contents
......@@ -294,6 +280,7 @@ else
end
if platform == :ios
# TODO: update for Specification Refactor
it "does not activate pods that are only part of other pods" do
spec = Pod::Podfile.new do
self.platform platform
......@@ -305,8 +292,9 @@ else
installer.install!
YAML.load(installer.lock_file.read).should == {
'PODS' => [{ 'Reachability (2.0.4)' => ["ASIHTTPRequest (>= 1.8)"] }],
'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"],
# 'PODS' => [{ 'Reachability (2.0.4)' => ["ASIHTTPRequest (>= 1.8)"] }],
'PODS' => [ 'Reachability (2.0.4)' ],
# 'DOWNLOAD_ONLY' => ["ASIHTTPRequest (1.8.1)"],
'DEPENDENCIES' => ["Reachability (= 2.0.4)"]
}
end
......@@ -321,7 +309,7 @@ else
installer = SpecHelper::Installer.new(spec)
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!
contents = (config.project_pods_root + 'Pods-resources.sh').read
......
......@@ -12,47 +12,30 @@ $:.unshift((ROOT + 'lib').to_s)
require 'cocoapods'
$:.unshift((ROOT + 'spec').to_s)
require 'spec_helper/color_output'
require 'spec_helper/bacon'
require 'spec_helper/command'
require 'spec_helper/fixture'
require 'spec_helper/git'
require 'spec_helper/github'
require 'spec_helper/temporary_directory'
require 'spec_helper/temporary_repos'
require 'spec_helper/config'
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
include Pod::Config::Mixin
include SpecHelper::Fixture
def argv(*argv)
Pod::Command::ARGV.new(argv)
end
require 'colored'
def xit(description, *args)
puts "- #{description} [DISABLED]".yellow
ErrorLog << "[DISABLED] #{self.name} #{description}\n\n"
end
end
end
config = Pod::Config.instance
config.silent = true
config.repos_dir = SpecHelper.tmp_repos_path
config.silent = true
config.repos_dir = SpecHelper.tmp_repos_path
config.project_root = SpecHelper.temporary_directory
Pod::Specification::Statistics.instance.cache_file = nil
require 'tmpdir'
......@@ -85,5 +68,3 @@ VCR.configure do |c|
c.allow_http_connections_when_no_cassette = true
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'
module SpecHelper
def self.tmp_repos_path
Git.tmp_repos_path
TemporaryRepos.tmp_repos_path
end
module Git
module TemporaryRepos
extend Pod::Executable
executable :git
def tmp_repos_path
SpecHelper.temporary_directory + 'cocoapods'
end
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
def git(repo, command)
Dir.chdir(tmp_repos_path + repo) do
......@@ -42,5 +38,12 @@ module SpecHelper
git(name, 'add README')
git(name, 'commit -m "changed"')
end
def self.extended(base)
base.before do
tmp_repos_path.mkpath
end
end
end
end
......@@ -19,7 +19,7 @@ describe "Pod::Command::Spec::Linter" do
it "fails a specifications that does not contain the minimum required attributes" do
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.lint.should == false
linter.errors.join(' | ') =~ /name.*version.*summary.*homepage.*authors.*(source.*part_of).*source_files/
......@@ -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
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.lint.should == false
linter.errors.count.should == 1
......@@ -36,16 +36,16 @@ describe "Pod::Command::Spec::Linter" 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.*'"))
linter = Pod::Command::Spec::Linter.new(spec, file)
linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = true, true
linter.lint.should == false
linter.errors.count.should == 1
linter.errors[0].should =~ /Paths cannot start with a slash/
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"))
linter = Pod::Command::Spec::Linter.new(spec, file)
linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = true, true
linter.lint.should == false
linter.errors.count.should == 1
......@@ -53,8 +53,8 @@ describe "Pod::Command::Spec::Linter" do
end
it "fails validation if the specification contains warnings" do
spec, file = write_podspec(stub_podspec)
linter = Pod::Command::Spec::Linter.new(spec, file)
spec, file = write_podspec(stub_podspec(/.*license.*/, ""))
linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = false, true
linter.lint.should == false
linter.errors.should.be.empty
......@@ -62,8 +62,8 @@ describe "Pod::Command::Spec::Linter" do
end
it "validates in lenient mode if there are no erros but there are warnings" do
spec, file = write_podspec(stub_podspec)
linter = Pod::Command::Spec::Linter.new(spec, file)
spec, file = write_podspec(stub_podspec(/.*license.*/, ""))
linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = true, true
linter.lint.should == true
linter.errors.should.be.empty
......@@ -72,7 +72,7 @@ describe "Pod::Command::Spec::Linter" do
it "respects quick mode" do
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(:install_pod).never
linter.expects(:xcodebuild_output_for_platfrom).never
......@@ -83,16 +83,16 @@ describe "Pod::Command::Spec::Linter" 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"))
linter = Pod::Command::Spec::Linter.new(spec, file)
linter = Pod::Command::Spec::Linter.new(spec)
linter.lenient, linter.quick = false, true
linter.lint.should == false
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
it "uses xcodebuild to generate notes and warnings" do
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.lint.should == false
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
it "checks for file patterns" do
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.stubs(:xcodebuild_output_for_platfrom).returns([])
linter = Pod::Command::Spec::Linter.new(spec)
linter.stubs(:xcodebuild_output).returns([])
linter.lenient, linter.quick = false, 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
......@@ -15,12 +15,3 @@ describe "Pod::Command::Repo" do
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__)
describe "Pod::Config" do
before do
@original_config = config
Pod::Config.instance = nil
end
after do
Pod::Config.instance = @original_config
end
it "returns the singleton config instance" do
config.should.be.instance_of Pod::Config
end
......@@ -22,7 +17,9 @@ describe "Pod::Config" do
extend SpecHelper::TemporaryDirectory
it "returns the path to the project root" do
config.project_root = nil
config.project_root.should == Pathname.pwd
config.project_root = temporary_directory
end
it "returns the path to the project Podfile if it exists" do
......
......@@ -7,15 +7,6 @@ describe "Pod::Dependency" do
dep1.merge(dep2).should == Pod::Dependency.new('bananas', '>= 1.8', '1.9')
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
dep = Pod::Dependency.new('RestKit')
dep.top_level_spec_name.should == 'RestKit'
......
......@@ -2,12 +2,11 @@ require File.expand_path('../../spec_helper', __FILE__)
def stub_pod_with_source(source_options)
specification = stub(
:part_of_other_pod? => false,
:source => source_options
)
stub('pod') do
stubs(:root).returns(temporary_sandbox.root)
stubs(:specification).returns(specification)
stubs(:top_specification).returns(specification)
end
end
......@@ -22,7 +21,7 @@ describe "Pod::Downloader" 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.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.should.be.instance_of Pod::Downloader::GitHub
end
......
......@@ -18,11 +18,8 @@ describe Pod::Generator::Documentation do
}
end
it 'returns the Pod documentation documentation files' do
@doc_installer.files.sort.should == [
(@pod.root + "Classes/Banana.m").to_s,
(@pod.root + "Classes/Banana.h").to_s,
].sort
it 'returns the Pod documentation header files' do
@doc_installer.files.sort.should == %w[ Classes/Banana.h ].sort
end
it 'returns the Pod documentation options' do
......
......@@ -6,7 +6,7 @@ describe Pod::Generator::DummySource do
before do
setup_temporary_directory
end
after do
teardown_temporary_directory
end
......@@ -21,5 +21,5 @@ describe Pod::Generator::DummySource do
@implementation PodsDummy
@end
EOS
end
end
end
......@@ -2,12 +2,11 @@ require File.expand_path('../../spec_helper', __FILE__)
def stub_pod_with_source(source_options)
specification = stub(
:part_of_other_pod? => false,
:source => source_options
)
stub('pod') do
stubs(:root).returns(temporary_sandbox.root)
stubs(:specification).returns(specification)
stubs(:top_specification).returns(specification)
end
end
......@@ -19,20 +18,20 @@ describe Pod::Downloader::Http do
))
downloader.should.be.instance_of Pod::Downloader::Http
downloader.type.should == :zip
downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.tar'
))
downloader.should.be.instance_of Pod::Downloader::Http
downloader.type.should == :tar
downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.tgz'
))
downloader.should.be.instance_of Pod::Downloader::Http
downloader.type.should == :tgz
downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0',
:type => :zip
......@@ -40,7 +39,7 @@ describe Pod::Downloader::Http do
downloader.should.be.instance_of Pod::Downloader::Http
downloader.type.should == :zip
end
it 'should download file and extract it with proper type' do
downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.zip'
......@@ -48,28 +47,28 @@ describe Pod::Downloader::Http do
downloader.expects(:download_file).with(anything())
downloader.expects(:extract_with_type).with(anything(), :zip).at_least_once
downloader.download
downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.tgz'
))
downloader.expects(:download_file).with(anything())
downloader.expects(:extract_with_type).with(anything(), :tgz).at_least_once
downloader.download
downloader.download
end
it 'should raise error when unsupported filetype is pass' do
downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0.rar'
))
downloader.expects(:download).raises(Pod::Downloader::Http::UnsupportedFileTypeError)
downloader.download rescue nil
downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:http => 'https://testflightapp.com/media/sdk-downloads/TestFlightSDK1.0',
:type => :rar
))
downloader.expects(:download).raises(Pod::Downloader::Http::UnsupportedFileTypeError)
downloader.download rescue nil
end
end
......@@ -22,11 +22,11 @@ describe Pod::Installer::TargetInstaller do
@specification = fixture_spec('banana-lib/BananaLib.podspec')
@pods = [Pod::LocalPod.new(@specification, @sandbox, Pod::Platform.ios)]
end
def do_install!
@installer.install!(@pods, @sandbox)
end
it 'adds a new static library target to the project' do
do_install!
@project.targets.count.should == 1
......@@ -43,12 +43,12 @@ describe Pod::Installer::TargetInstaller do
@pods[0].expects(:add_to_target).with(instance_of(Xcodeproj::Project::Object::PBXNativeTarget))
do_install!
end
it 'tells each pod to link its headers' do
@pods[0].expects(:link_headers)
do_install!
end
it 'adds the sandbox header search paths to the xcconfig, with quotes' do
do_install!
@installer.xcconfig.to_hash['HEADER_SEARCH_PATHS'].should.include("\"#{@sandbox.header_search_paths.join('" "')}\"")
......@@ -58,7 +58,7 @@ describe Pod::Installer::TargetInstaller do
do_install!
@installer.xcconfig.to_hash['OTHER_LDFLAGS'].split(" ").should.not.include("-fobjc-arc")
end
it 'adds the -fobjc-arc to OTHER_LDFLAGS if any pods require arc (to support non-ARC projects on iOS 4.0)' do
@podfile.stubs(:set_arc_compatibility_flag? => true)
@specification.stubs(:requires_arc).returns(true)
......
......@@ -21,10 +21,6 @@ describe Pod::Installer::UserProjectIntegrator do
@integrator = Pod::Installer::UserProjectIntegrator.new(@podfile)
end
after do
config.project_root = nil
end
it "returns the path to the workspace from the Podfile" do
@integrator.workspace_path.should == config.project_root + 'SampleProject.xcworkspace'
end
......
......@@ -2,18 +2,11 @@ require File.expand_path('../../spec_helper', __FILE__)
describe "Pod::Installer" do
before do
@config_before = config
Pod::Config.instance = nil
config.silent = true
config.repos_dir = fixture('spec-repos')
config.project_pods_root = fixture('integration')
end
after do
Pod::Config.instance = @config_before
end
describe ", by default," do
describe "by default" do
before do
podfile = Pod::Podfile.new do
platform :ios
......@@ -42,7 +35,7 @@ describe "Pod::Installer" do
dependency 'ASIHTTPRequest'
end
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)
end
expected = pods.map { |pod| pod.header_files }.flatten.map { |header| config.project_pods_root + header }
......
......@@ -3,174 +3,245 @@ require File.expand_path('../../spec_helper', __FILE__)
describe Pod::LocalPod do
# a LocalPod represents a local copy of the dependency, inside the pod root, built from a spec
before do
@sandbox = temporary_sandbox
@pod = Pod::LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), @sandbox, Pod::Platform.new(:ios))
copy_fixture_to_pod('banana-lib', @pod)
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 'can clean up after itself' do
@pod.clean_paths.tap do |paths|
@pod.clean
paths.each do |path|
path.should.not.exist
end
describe "in general" do
before do
@sandbox = temporary_sandbox
@pod = Pod::LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), @sandbox, Pod::Platform.new(:ios))
copy_fixture_to_pod('banana-lib', @pod)
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
#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
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
#before do
describe "with installed source," do
#before do
#config.project_pods_root = fixture('integration')
#podspec = fixture('spec-repos/master/SSZipArchive/0.1.0/SSZipArchive.podspec')
#@spec = Pod::Specification.from_file(podspec)
#@destroot = fixture('integration/SSZipArchive')
#end
#end
#after do
#config.project_pods_root = nil
#end
xit "returns the list of files that the source_files pattern expand to" do
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 files that the source_files pattern expand to" do
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
files = @destroot.glob('**/*.h')
files = files.map { |file| file.relative_path_from(config.project_pods_root) }
@spec.header_files[:ios].sort.should == files.sort
end
xit "returns the list of headers" do
files = @destroot.glob('**/*.h')
files = files.map { |file| file.relative_path_from(config.project_pods_root) }
@spec.header_files[:ios].sort.should == files.sort
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
@spec.copy_header_mappings[:ios].size.should == 1
@spec.copy_header_mappings[:ios][Pathname.new('SSZipArchive')].sort.should == %w{
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][Pathname.new('SSZipArchive')].sort.should == %w{
SSZipArchive.h
minizip/crypt.h
minizip/ioapi.h
minizip/mztools.h
minizip/unzip.h
minizip/zip.h
}.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
}.map { |f| Pathname.new("SSZipArchive/#{f}") }.sort
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
minizip/crypt.h
minizip/ioapi.h
minizip/mztools.h
minizip/unzip.h
minizip/zip.h
}.map { |f| Pathname.new("SSZipArchive/#{f}") }.sort
end
}.map { |f| Pathname.new("SSZipArchive/#{f}") }.sort
end
xit "returns a hash of mappings with a custom header dir prefix" do
@spec.header_dir = 'AnotherRoot'
@spec.copy_header_mappings[:ios][Pathname.new('AnotherRoot')].sort.should == %w{
xit "returns a hash of mappings with a custom header dir prefix" do
@spec.header_dir = 'AnotherRoot'
@spec.copy_header_mappings[:ios][Pathname.new('AnotherRoot')].sort.should == %w{
SSZipArchive.h
minizip/crypt.h
minizip/ioapi.h
minizip/mztools.h
minizip/unzip.h
minizip/zip.h
}.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
}.map { |f| Pathname.new("SSZipArchive/#{f}") }.sort
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/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
@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/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
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 }
describe "regarding multiple subspecs" do
before do
# specification with only some subspecs activated
# to check that only the needed files are being activated
# A fixture is needed.
#
# 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
require File.expand_path('../../spec_helper', __FILE__)
describe Pod::Platform do
it "returns a new Platform instance" do
Pod::Platform.ios.should == Pod::Platform.new(:ios)
Pod::Platform.osx.should == Pod::Platform.new(:osx)
end
before do
@platform = Pod::Platform.ios
end
it "exposes it's symbolic name" do
@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)
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')
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
end
it "presents an accurate string representation" do
@platform.to_s.should == "iOS"
Pod::Platform.new(:osx).to_s.should == 'OS X'
Pod::Platform.new(nil).to_s.should == "iOS - OS X"
Pod::Platform.new(:ios, '5.0.0').to_s.should == 'iOS 5.0.0'
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
end
it "allows to specify the deployment target on initialization" do
p = Pod::Platform.new(:ios, '4.0.0')
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' })
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')
p.deployment_target = '4.0.0'
p.deployment_target.should == Pod::Version.new('4.0.0')
p.deployment_target = Pod::Version.new('4.0.0')
p.deployment_target.should == Pod::Version.new('4.0.0')
end
end
describe "Pod::Platform with a nil value" do
before do
@platform = Pod::Platform.new(nil)
end
it "behaves like a nil object" do
@platform.should.be.nil
end
end
describe "Pod::Platform#support?" do
it "supports another platform is with the same operating system" do
p1 = Pod::Platform.new(:ios)
p2 = Pod::Platform.new(:ios)
p1.should.support?(p2)
p1 = Pod::Platform.new(:osx)
p2 = Pod::Platform.new(:osx)
p1.should.support?(p2)
end
it "supports a nil platform" do
p1 = Pod::Platform.new(:ios)
p1.should.support?(nil)
end
it "supports a platform with a lower or equal deployment_target" do
p1 = Pod::Platform.new(:ios, '5.0')
p2 = Pod::Platform.new(:ios, '4.0')
p1.should.support?(p1)
p1.should.support?(p2)
p2.should.not.support?(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)
p2 = Pod::Platform.new(:ios, '4.0')
p1.should.support?(p2)
p2.should.support?(p1)
describe "by default" do
it "returns a new Platform instance" do
Pod::Platform.ios.should == Pod::Platform.new(:ios)
Pod::Platform.osx.should == Pod::Platform.new(:osx)
end
before do
@platform = Pod::Platform.ios
end
it "exposes it's symbolic name" do
@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)
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')
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
end
it "presents an accurate string representation" do
@platform.to_s.should == "iOS"
Pod::Platform.new(:osx).to_s.should == 'OS X'
Pod::Platform.new(nil).to_s.should == "iOS - OS X"
Pod::Platform.new(:ios, '5.0.0').to_s.should == 'iOS 5.0.0'
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
end
it "allows to specify the deployment target on initialization" do
p = Pod::Platform.new(:ios, '4.0.0')
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' })
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')
p.deployment_target = '4.0.0'
p.deployment_target.should == Pod::Version.new('4.0.0')
p.deployment_target = Pod::Version.new('4.0.0')
p.deployment_target.should == Pod::Version.new('4.0.0')
end
end
describe "with a nil value" do
before do
@platform = Pod::Platform.new(nil)
end
it "behaves like a nil object" do
@platform.should.be.nil
end
end
describe "regarding supporting platforms" do
it "supports platforms with the same operating system" do
p1 = Pod::Platform.new(:ios)
p2 = Pod::Platform.new(:ios)
p1.should.supports?(p2)
p1 = Pod::Platform.new(:osx)
p2 = Pod::Platform.new(:osx)
p1.should.supports?(p2)
end
it "supports a nil platform" do
p1 = Pod::Platform.new(:ios)
p1.should.supports?(nil)
end
it "supports a platform with a lower or equal deployment_target" do
p1 = Pod::Platform.new(:ios, '5.0')
p2 = Pod::Platform.new(:ios, '4.0')
p1.should.supports?(p1)
p1.should.supports?(p2)
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)
p2 = Pod::Platform.new(:ios, '4.0')
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
......@@ -25,7 +25,7 @@ describe "Pod::Podfile" do
dep = podfile.dependency_by_top_level_spec_name('SomeExternalPod')
dep.external_source.params.should == { :git => 'GIT-URL', :commit => '1234' }
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'
......
......@@ -2,34 +2,28 @@ require File.expand_path('../../spec_helper', __FILE__)
describe "Pod::Resolver" do
before do
@config_before = config
Pod::Config.instance = nil
config.silent = true
config.repos_dir = fixture('spec-repos')
@podfile = Pod::Podfile.new do
platform :ios
dependency 'ASIWebPageRequest'
dependency 'BlocksKit'
# dependency 'ASIWebPageRequest'
end
@resolver = Pod::Resolver.new(@podfile, stub('sandbox'))
end
after do
Pod::Config.instance = @config_before
end
it "holds the context state, such as cached specification sets" do
@resolver.resolve
@resolver.cached_sets.values.sort_by(&:name).should == [
Pod::Spec::Set.new(config.repos_dir + 'master/ASIHTTPRequest'),
Pod::Spec::Set.new(config.repos_dir + 'master/ASIWebPageRequest'),
Pod::Spec::Set.new(config.repos_dir + 'master/Reachability'),
Pod::Spec::Set.new(config.repos_dir + 'master/A2DynamicDelegate'),
Pod::Spec::Set.new(config.repos_dir + 'master/BlocksKit'),
].sort_by(&:name)
end
it "returns all specs needed for the dependency" do
specs = @resolver.resolve.values.flatten
specs.map(&:class).uniq.should == [Pod::Specification]
specs.map(&:name).sort.should == %w{ ASIHTTPRequest ASIWebPageRequest Reachability }
specs.map(&:name).sort.should == %w{ A2DynamicDelegate BlocksKit }
end
it "does not raise if all dependencies match the platform of the root spec (Podfile)" do
......@@ -40,8 +34,8 @@ describe "Pod::Resolver" do
end
it "raises once any of the dependencies does not match the platform of its podfile target" do
set = Pod::Spec::Set.new(config.repos_dir + 'master/ASIHTTPRequest')
@resolver.cached_sets['ASIHTTPRequest'] = set
set = Pod::Spec::Set.new(config.repos_dir + 'master/BlocksKit')
@resolver.cached_sets['BlocksKit'] = set
def set.stub_platform=(platform); @stubbed_platform = platform; end
def set.specification; spec = super; spec.platform = @stubbed_platform; spec; end
......@@ -60,14 +54,14 @@ describe "Pod::Resolver" do
end
it "raises once any of the dependencies does not have a deployment_target compatible with its podfile target" do
set = Pod::Spec::Set.new(config.repos_dir + 'master/ASIHTTPRequest')
@resolver.cached_sets['ASIHTTPRequest'] = set
set = Pod::Spec::Set.new(config.repos_dir + 'master/BlocksKit')
@resolver.cached_sets['BlocksKit'] = set
@podfile.platform :ios, "4.0"
Pod::Specification.any_instance.stubs(:platforms).returns([ Pod::Platform.new(:ios, '4.0'), Pod::Platform.new(:osx, '10.7') ])
Pod::Specification.any_instance.stubs(:available_platforms).returns([ Pod::Platform.new(:ios, '4.0'), Pod::Platform.new(:osx, '10.7') ])
lambda { @resolver.resolve }.should.not.raise
Pod::Specification.any_instance.stubs(:platforms).returns([ Pod::Platform.new(:ios, '5.0'), Pod::Platform.new(:osx, '10.7') ])
Pod::Specification.any_instance.stubs(:available_platforms).returns([ Pod::Platform.new(:ios, '5.0'), Pod::Platform.new(:osx, '10.7') ])
lambda { @resolver.resolve }.should.raise Pod::Informative
end
......@@ -75,7 +69,7 @@ describe "Pod::Resolver" do
@podfile = Pod::Podfile.new do
platform :ios
dependency 'RestKit/Network'
dependency 'RestKit/ObjectMapping'
dependency 'RestKit/ObjectMapping/XML'
end
resolver = Pod::Resolver.new(@podfile, stub('sandbox'))
resolver.resolve.values.flatten.map(&:name).sort.should == %w{
......@@ -83,42 +77,103 @@ describe "Pod::Resolver" do
ISO8601DateFormatter
LibComponentLogging-Core
LibComponentLogging-NSLog
RestKit
NSData+Base64
RestKit/Network
RestKit/ObjectMapping
RestKit/ObjectMapping/XML
SOCKit
XMLReader
cocoa-oauth
}
end
it "resolves subspecs with external constraints" do
it "includes all the subspecs of a specification node" do
@podfile = Pod::Podfile.new do
platform :ios
dependency 'MainSpec/FirstSubSpec', :git => 'GIT-URL'
dependency 'RestKit'
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' do |sss|
resolver = Pod::Resolver.new(@podfile, stub('sandbox'))
resolver.resolve.values.flatten.map(&:name).sort.should == %w{
FileMD5Hash
ISO8601DateFormatter
JSONKit
LibComponentLogging-Core
LibComponentLogging-NSLog
NSData+Base64
RestKit
RestKit/JSON
RestKit/Network
RestKit/ObjectMapping/CoreData
RestKit/ObjectMapping/JSON
RestKit/UI
SOCKit
UDTableView
cocoa-oauth
}
end
it "if defined it includes only the main subspec of of a specification node" do
@podfile = Pod::Podfile.new do
platform :ios
dependency do |s|
s.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
@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
MainSpec/FirstSubSpec
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
require File.expand_path('../../spec_helper', __FILE__)
require 'tmpdir'
TMP_POD_ROOT = ROOT + "tmp" + "podroot"
TMP_POD_ROOT = ROOT + "tmp" + "podroot" unless defined? TMP_POD_ROOT
describe Pod::Sandbox do
before do
before do
@sandbox = Pod::Sandbox.new(TMP_POD_ROOT)
end
after do
@sandbox.implode
end
it "automatically creates the TMP_POD_ROOT if it doesn't exist" do
File.directory?(TMP_POD_ROOT).should.be.true
end
it "deletes the entire root directory on implode" do
@sandbox.implode
File.directory?(TMP_POD_ROOT).should.be.false
FileUtils.mkdir(TMP_POD_ROOT) # put it back again
end
it "returns it's headers root" do
@sandbox.headers_root.should == Pathname.new(File.join(TMP_POD_ROOT, "Headers"))
end
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")
namespace_path = Pathname.new("ExampleLib")
......@@ -36,7 +36,7 @@ describe Pod::Sandbox do
symlink_path.should.be.symlink
File.read(symlink_path).should == 'hello'
end
it 'can add multiple headers at once and return the relative symlink paths' do
FileUtils.mkdir_p(@sandbox.root + "ExampleLib/Headers")
namespace_path = Pathname.new("ExampleLib")
......@@ -53,7 +53,7 @@ describe Pod::Sandbox do
File.read(path).should == "hello"
end
end
it 'keeps a list of unique header search paths when headers are added' do
FileUtils.mkdir_p(@sandbox.root + "ExampleLib/Headers")
namespace_path = Pathname.new("ExampleLib")
......@@ -67,11 +67,11 @@ describe Pod::Sandbox do
@sandbox.add_header_files(namespace_path, relative_header_paths)
@sandbox.header_search_paths.should.include("${PODS_ROOT}/Headers/ExampleLib")
end
it 'always adds the Headers root to the header search paths' do
@sandbox.header_search_paths.should.include("${PODS_ROOT}/Headers")
end
it 'clears out its headers root when preparing for install' do
@sandbox.prepare_for_install
@sandbox.headers_root.should.not.exist
......
require File.expand_path('../../spec_helper', __FILE__)
describe "Pod::Source" do
extend SpecHelper::Git
extend SpecHelper::Command
extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
before do
add_repo('repo1', fixture('spec-repos/master'))
......
......@@ -29,12 +29,6 @@ describe "Pod::Specification::Set" do
lambda { @set.required_version }.should.raise Pod::Informative
end
it "returns that this set is only part for other pods" do
@set.required_by(Pod::Spec.new { |s| s.part_of = 'CocoaLumberjack' })
@set.required_by(Pod::Spec.new { |s| s.part_of = 'CocoaLumberjack' })
@set.should.be.only_part_of_other_pod
end
before do
@set.required_by(Pod::Spec.new { |s| s.dependency 'CocoaLumberjack', '< 1.2.1' })
end
......@@ -51,11 +45,6 @@ describe "Pod::Specification::Set" do
@set.specification.should == Pod::Spec.new { |s| s.name = 'CocoaLumberjack'; s.version = '1.2' }
end
it "returns that this set is not only part for other pods" do
@set.required_by(Pod::Spec.new { |s| s.part_of = 'CocoaLumberjack' })
@set.should.not.be.only_part_of_other_pod
end
it "ignores dotfiles when getting the version directories" do
`touch #{fixture('spec-repos/master/CocoaLumberjack/.DS_Store')}`
lambda { @set.versions }.should.not.raise
......
......@@ -6,6 +6,10 @@ describe "A Pod::Specification loaded from a podspec" do
@spec = Pod::Specification.from_file(fixture('banana-lib/BananaLib.podspec'))
end
it "has no parent if it is the top level spec" do
@spec.parent.nil?.should == true
end
it "returns that it's not loaded from a podfile" do
@spec.should.not.be.podfile
end
......@@ -53,25 +57,23 @@ describe "A Pod::Specification loaded from a podspec" do
end
it "returns the pod's source files" do
@spec.source_files[:ios].should == ['Classes/*.{h,m}', 'Vendor']
@spec.source_files[:osx].should == ['Classes/*.{h,m}', 'Vendor']
@spec.activate_platform(:ios).source_files.should == ['Classes/*.{h,m}', 'Vendor']
@spec.activate_platform(:osx).source_files.should == ['Classes/*.{h,m}', 'Vendor']
end
it "returns the pod's dependencies" do
expected = Pod::Dependency.new('monkey', '~> 1.0.1', '< 1.0.9')
@spec.dependencies.should == { :ios => [expected], :osx => [expected] }
@spec.dependency_by_top_level_spec_name('monkey').should == expected
@spec.activate_platform(:ios).dependencies.should == [expected]
@spec.activate_platform(:osx).dependencies.should == [expected]
end
it "returns the pod's xcconfig settings" do
@spec.xcconfig[:ios].should == {
'OTHER_LDFLAGS' => '-framework SystemConfiguration'
}
@spec.activate_platform(:ios).xcconfig.should == { 'OTHER_LDFLAGS' => '-framework SystemConfiguration' }
end
it "has a shortcut to add frameworks to the xcconfig" do
@spec.frameworks = 'CFNetwork', 'CoreText'
@spec.xcconfig[:ios].should == {
@spec.activate_platform(:ios).xcconfig.should == {
'OTHER_LDFLAGS' => '-framework SystemConfiguration ' \
'-framework CFNetwork ' \
'-framework CoreText'
......@@ -80,7 +82,7 @@ describe "A Pod::Specification loaded from a podspec" do
it "has a shortcut to add libraries to the xcconfig" do
@spec.libraries = 'z', 'xml2'
@spec.xcconfig[:ios].should == {
@spec.activate_platform(:ios).xcconfig.should == {
'OTHER_LDFLAGS' => '-framework SystemConfiguration -lz -lxml2'
}
end
......@@ -97,53 +99,16 @@ describe "A Pod::Specification loaded from a podspec" do
end
it "adds compiler flags if ARC is required" do
@spec.parent.should == nil
@spec.requires_arc = true
@spec.compiler_flags.should == { :ios => " -fobjc-arc", :osx => " -fobjc-arc" }
@spec.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.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
describe "A Pod::Specification that's part of another pod's source" do
before do
config.repos_dir = fixture('spec-repos')
@spec = Pod::Specification.new
end
after do
config.repos_dir = SpecHelper.tmp_repos_path
end
it "adds a dependency on the other pod's source, but not the library" do
@spec.part_of = 'monkey', '>= 1'
@spec.should.be.part_of_other_pod
dep = Pod::Dependency.new('monkey', '>= 1')
@spec.dependencies.should.not == [dep]
dep.only_part_of_other_pod = true
@spec.dependencies.should == { :ios => [dep], :osx => [dep] }
end
it "adds a dependency on the other pod's source *and* the library" do
@spec.part_of_dependency = 'monkey', '>= 1'
@spec.should.be.part_of_other_pod
@spec.dependencies[:ios].should == [Pod::Dependency.new('monkey', '>= 1')]
end
it "searches the sources for a matching specification if it has not been assigned by the Resolver yet (e.g. the search command)" do
@spec.part_of_dependency = 'SSZipArchive', '0.1.1'
@spec.part_of_specification.to_s.should == 'SSZipArchive (0.1.1)'
end
# TODO
#it "returns the specification of the pod that it's part of" do
# @spec.part_of_specification
#end
#
#it "returns the destroot of the pod that it's part of" do
# @spec.pod_destroot
#end
end
describe "A Pod::Specification, in general," do
before do
@spec = Pod::Spec.new
......@@ -160,11 +125,11 @@ describe "A Pod::Specification, in general," do
@spec.platform.deployment_target.should == Pod::Version.new('4.0')
end
it "returns the platfroms for which the pod is supported" do
it "returns the available platforms for which the pod is supported" do
@spec.platform = :ios, '4.0'
@spec.platforms.count.should == 1
@spec.platforms.first.should == :ios
@spec.platforms.first.deployment_target.should == Pod::Version.new('4.0')
@spec.available_platforms.count.should == 1
@spec.available_platforms.first.should == :ios
@spec.available_platforms.first.deployment_target.should == Pod::Version.new('4.0')
end
it "returns the license of the Pod" do
......@@ -202,7 +167,7 @@ describe "A Pod::Specification, in general," do
@spec.documentation[:appledoc].should == ['--project-name', '#{@name}',
'--project-company', '"Company Name"',
'--company-id', 'com.company',
'--ignore', 'Common',
'--ignore', 'Common',
'--ignore', '.m']
end
......@@ -217,6 +182,18 @@ describe "A Pod::Specification, in general," do
list.glob.should == Pod::FileList[(ROOT + '*').to_s].exclude('Rakefile').map { |path| Pathname.new(path) }
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
@spec.prefix_header_file.should == nil
@spec.prefix_header_file = 'Classes/Demo.pch'
......@@ -228,32 +205,106 @@ describe "A Pod::Specification, in general," do
@spec.prefix_header_contents = '#import "BlocksKit.h"'
@spec.prefix_header_contents.should == '#import "BlocksKit.h"'
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
describe "A Pod::Specification subspec" do
before do
@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.name = 'MainSpec'
s.version = '1.2.3'
s.license = 'MIT'
s.author = 'Joe the Plumber'
s.source = { :git => '/some/url' }
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|
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|
sss.source_files = 'subsubspec.m'
end
end
end
end
it "makes a parent spec a wrapper if it has no source files of its own" do
@spec.should.be.wrapper
@spec.subspecs.first.should.not.be.wrapper
@subspec = @spec.subspecs.first
@subsubspec = @subspec.subspecs.first
end
it "returns the top level parent spec" do
......@@ -266,30 +317,130 @@ describe "A Pod::Specification subspec" do
@spec.subspecs.first.subspecs.first.name.should == 'MainSpec/FirstSubSpec/SecondSubSpec'
end
it "is a `part_of' the top level parent spec" do
dependency = Pod::Dependency.new('MainSpec', '1.2.3').tap { |d| d.only_part_of_other_pod = true }
@spec.subspecs.first.part_of.should == dependency
@spec.subspecs.first.subspecs.first.part_of.should == dependency
end
it "depends on the parent spec, if it is a subspec" do
dependency = Pod::Dependency.new('MainSpec', '1.2.3').tap { |d| d.only_part_of_other_pod = true }
@spec.subspecs.first.dependencies[:ios].should == [dependency]
@spec.subspecs.first.dependencies[:osx].should == [dependency]
@spec.subspecs.first.subspecs.first.dependencies[:ios].should == [dependency, Pod::Dependency.new('MainSpec/FirstSubSpec', '1.2.3')]
@spec.subspecs.first.subspecs.first.dependencies[:osx].should == [dependency, Pod::Dependency.new('MainSpec/FirstSubSpec', '1.2.3')]
it "correctly resolves the inheritance chain" do
@spec.subspecs.first.subspecs.first.parent.should == @spec.subspecs.first
@spec.subspecs.first.parent.should == @spec
end
it "automatically forwards undefined attributes to the top level parent" do
[:version, :summary, :platform, :license, :authors, :requires_arc, :compiler_flags].each do |attr|
it "automatically forwards top level attributes to the top level parent" do
@spec.activate_platform(:ios)
[:version, :license, :authors, :requires_arc].each do |attr|
@spec.subspecs.first.send(attr).should == @spec.send(attr)
@spec.subspecs.first.subspecs.first.send(attr).should == @spec.send(attr)
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
@spec.subspec_by_name('MainSpec/FirstSubSpec').should == @spec.subspecs.first
@spec.subspec_by_name('MainSpec/FirstSubSpec/SecondSubSpec').should == @spec.subspecs.first.subspecs.first
@spec.subspec_by_name(nil).should == @spec
@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
......@@ -329,26 +480,31 @@ describe "A Pod::Specification, concerning its attributes that support different
end
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
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
it "returns the same list of xcconfig build settings for each platform" do
build_settings = { 'OTHER_LDFLAGS' => '-lObjC -framework QuartzCore -lz' }
@spec.xcconfig.should == { :ios => build_settings, :osx => build_settings }
build_settings = { 'OTHER_LDFLAGS' => '-lObjC -lz -framework QuartzCore' }
@spec.activate_platform(:ios).xcconfig.should == build_settings
@spec.activate_platform(:osx).xcconfig.should == build_settings
end
it "returns the same list of compiler flags for each platform" do
compiler_flags = ' -Wdeprecated-implementations -fobjc-arc'
@spec.compiler_flags.should == { :ios => compiler_flags, :osx => compiler_flags }
compiler_flags = ' -fobjc-arc -Wdeprecated-implementations'
@spec.activate_platform(:ios).compiler_flags.should == compiler_flags
@spec.activate_platform(:osx).compiler_flags.should == compiler_flags
end
it "returns the same list of dependencies for each platform" do
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
......@@ -383,38 +539,34 @@ describe "A Pod::Specification, concerning its attributes that support different
end
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
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
it "returns a different list of xcconfig build settings for each platform" do
@spec.xcconfig.should == {
:ios => { 'OTHER_LDFLAGS' => '-lObjC -framework QuartzCore -lz' },
:osx => { 'OTHER_LDFLAGS' => '-lObjC -all_load -framework QuartzCore -framework CoreData -lz -lxml' }
}
@spec.activate_platform(:ios).xcconfig.should == { 'OTHER_LDFLAGS' => '-lObjC -lz -framework QuartzCore' }
@spec.activate_platform(:osx).xcconfig.should == { 'OTHER_LDFLAGS' => '-lObjC -all_load -lz -lxml -framework QuartzCore -framework CoreData' }
end
it "returns the list of the supported platfroms and deployment targets" do
@spec.platforms.count.should == 2
@spec.platforms.should.include? Pod::Platform.new(:osx)
@spec.platforms.should.include? Pod::Platform.new(:ios, '4.0')
@spec.available_platforms.count.should == 2
@spec.available_platforms.should.include? Pod::Platform.new(:osx)
@spec.available_platforms.should.include? Pod::Platform.new(:ios, '4.0')
end
it "returns the same list of compiler flags for each platform" do
@spec.compiler_flags.should == {
:ios => ' -Wdeprecated-implementations -fobjc-arc',
:osx => ' -Wfloat-equal -fobjc-arc'
}
@spec.activate_platform(:ios).compiler_flags.should == ' -fobjc-arc -Wdeprecated-implementations'
@spec.activate_platform(:osx).compiler_flags.should == ' -fobjc-arc -Wfloat-equal'
end
it "returns the same list of dependencies for each platform" do
@spec.dependencies.should == {
:ios => [Pod::Dependency.new('JSONKit')],
:osx => [Pod::Dependency.new('SSZipArchive')]
}
@spec.activate_platform(:ios).dependencies.should == [Pod::Dependency.new('JSONKit')]
@spec.activate_platform(:osx).dependencies.should == [Pod::Dependency.new('SSZipArchive')]
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