Commit 3ec34b5a authored by Fabio Pelosin's avatar Fabio Pelosin

Merge pull request #512 from CocoaPods/b0.15.0

0.15.0
parents 0cc4fd51 efba29b1
## 0.15.0 (unreleased)
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/master...b0.15.0)
###### Enhancements
- Added a pre install hook to the Podfile and to root specifications.
[#486](https://github.com/CocoaPods/CocoaPods/issues/486)
- Support for `header_mappings_dir` attribute in subspecs.
- Refactored UI.
###### Bug fixes
- Improvements to the git cache that should be more robust.
[#517](https://github.com/CocoaPods/CocoaPods/issues/517)
## Master ## Master
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.14.0...master) [CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.14.0...master)
......
...@@ -7,7 +7,6 @@ require 'rubygems' ...@@ -7,7 +7,6 @@ require 'rubygems'
# #
# E.g. https://github.com/CocoaPods/CocoaPods/issues/398 # E.g. https://github.com/CocoaPods/CocoaPods/issues/398
unless Gem::Version::Requirement.new('>= 1.4.0').satisfied_by?(Gem::Version.new(Gem::VERSION)) unless Gem::Version::Requirement.new('>= 1.4.0').satisfied_by?(Gem::Version.new(Gem::VERSION))
require 'colored'
STDERR.puts "Your RubyGems version (#{Gem::VERSION}) is too old, please update with: `gem update --system`".red STDERR.puts "Your RubyGems version (#{Gem::VERSION}) is too old, please update with: `gem update --system`".red
exit 1 exit 1
end end
...@@ -41,6 +40,7 @@ module Pod ...@@ -41,6 +40,7 @@ module Pod
autoload :Source, 'cocoapods/source' autoload :Source, 'cocoapods/source'
autoload :Spec, 'cocoapods/specification' autoload :Spec, 'cocoapods/specification'
autoload :Specification, 'cocoapods/specification' autoload :Specification, 'cocoapods/specification'
autoload :UI, 'cocoapods/user_interface'
autoload :Version, 'cocoapods/version' autoload :Version, 'cocoapods/version'
autoload :Pathname, 'pathname' autoload :Pathname, 'pathname'
......
...@@ -7,7 +7,6 @@ module Pod ...@@ -7,7 +7,6 @@ module Pod
autoload :List, 'cocoapods/command/list' autoload :List, 'cocoapods/command/list'
autoload :Linter, 'cocoapods/command/linter' autoload :Linter, 'cocoapods/command/linter'
autoload :Outdated, 'cocoapods/command/outdated' autoload :Outdated, 'cocoapods/command/outdated'
autoload :Presenter, 'cocoapods/command/presenter'
autoload :Push, 'cocoapods/command/push' autoload :Push, 'cocoapods/command/push'
autoload :Repo, 'cocoapods/command/repo' autoload :Repo, 'cocoapods/command/repo'
autoload :Search, 'cocoapods/command/search' autoload :Search, 'cocoapods/command/search'
...@@ -74,6 +73,7 @@ module Pod ...@@ -74,6 +73,7 @@ module Pod
Setup.new(ARGV.new).run_if_needed Setup.new(ARGV.new).run_if_needed
end end
sub_command.run sub_command.run
UI.puts
rescue Interrupt rescue Interrupt
puts "[!] Cancelled".red puts "[!] Cancelled".red
...@@ -145,24 +145,9 @@ module Pod ...@@ -145,24 +145,9 @@ module Pod
def update_spec_repos_if_necessary! def update_spec_repos_if_necessary!
if @update_repo if @update_repo
print_title 'Updating Spec Repositories', true UI.section 'Updating Spec Repositories' do
Repo.new(ARGV.new(["update"])).run Repo.new(ARGV.new(["update"])).run
end end
end
def print_title(title, only_verbose = true)
if config.verbose?
puts "\n" + title.yellow
elsif !config.silent? && !only_verbose
puts title
end
end
def print_subtitle(title, only_verbose = false)
if config.verbose?
puts "\n" + title.green
elsif !config.silent? && !only_verbose
puts title
end end
end end
end end
......
...@@ -14,23 +14,26 @@ module Pod ...@@ -14,23 +14,26 @@ module Pod
end end
def self.options def self.options
[["--update", "Run `pod repo update` before listing"]].concat(Presenter.options).concat(super) [[
"--update", "Run `pod repo update` before listing",
"--stats", "Show additional stats (like GitHub watchers and forks)"
]].concat(super)
end end
extend Executable extend Executable
executable :git executable :git
def initialize(argv) def initialize(argv)
@update = argv.option('--update') @update = argv.option('--update')
@new = argv.option('new') @stats = argv.option('--stats')
@presenter = Presenter.new(argv) @new = argv.option('new')
super unless argv.empty? super unless argv.empty?
end end
def list_all def list_all
sets = Source.all_sets sets = Source.all_sets
sets.each {|s| puts @presenter.describe(s)} sets.each { |set| UI.pod(set, :name) }
puts "\n#{sets.count} pods were found" UI.puts "\n#{sets.count} pods were found"
end end
def list_new def list_new
...@@ -53,16 +56,18 @@ module Pod ...@@ -53,16 +56,18 @@ module Pod
days.reverse.each do |d| days.reverse.each do |d|
sets = groups[d] sets = groups[d]
next unless sets next unless sets
puts "\nPods added in the last #{d == 1 ? 'day' : "#{d} days"}".yellow UI.section("\nPods added in the last #{"day".pluralize(d)}".yellow) do
sets.sort_by {|s| creation_dates[s.name]}.each {|s| puts @presenter.describe(s)} sorted = sets.sort_by {|s| creation_dates[s.name]}
sorted.each { |set| UI.pod(set, (@stats ? :stats : :name)) }
end
end end
end end
def run def run
puts "\nUpdating Spec Repositories\n".yellow if @update && config.verbose? UI.section("\nUpdating Spec Repositories\n".yellow) do
Repo.new(ARGV.new(["update"])).run if @update Repo.new(ARGV.new(["update"])).run
end if @update && config.verbose?
@new ? list_new : list_all @new ? list_new : list_all
puts
end end
end end
end end
......
module Pod
class Command
class Presenter
def self.options
[["--stats", "Show additional stats (like GitHub watchers and forks)"]]
end
autoload :CocoaPod, 'cocoapods/command/presenter/cocoa_pod'
def initialize(argv)
@stats = argv.option('--stats')
end
def render(array)
result = "\n"
seats.each {|s| puts describe(s)}
result
end
def describe(set)
pod = CocoaPod.new(set)
result = "\n--> #{pod.name} (#{pod.versions})\n".green
result << wrap_string(pod.summary)
result << detail('Homepage', pod.homepage)
result << detail('Source', pod.source_url)
if @stats
result << detail('Pushed', pod.github_last_activity)
result << detail('Authors', pod.authors) if pod.authors =~ /,/
result << detail('Author', pod.authors) if pod.authors !~ /,/
result << detail('License', pod.license)
result << detail('Platform', pod.platform)
result << detail('Watchers', pod.github_watchers)
result << detail('Forks', pod.github_forks)
end
result << detail('Sub specs', pod.subspecs)
result
end
private
# adapted from http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/
def wrap_string(txt, col = 80, indentation = 4)
indent = ' ' * indentation
txt.strip.gsub(/(.{1,#{col}})( +|$)\n?|(.{#{col}})/, indent + "\\1\\3\n")
end
def detail(title, value)
return '' if !value
''.tap do |t|
t << " - #{title}:".ljust(16)
if value.class == Array
separator = "\n - "
t << separator << value.join(separator)
else
t << value.to_s << "\n"
end
end
end
end
end
end
require 'active_support/core_ext/array/conversions'
module Pod
class Command
class Presenter
class CocoaPod
attr_accessor :set
def initialize(set)
@set = set
end
# set information
def name
@set.name
end
def version
@set.versions.last
end
def versions
@set.versions.reverse.join(", ")
end
# specification information
def spec
@set.specification
end
def authors
spec.authors.keys.to_sentence
end
def homepage
spec.homepage
end
def description
spec.description
end
def summary
spec.summary
end
def source_url
spec.source.reject {|k,_| k == :commit || k == :tag }.values.first
end
def platform
spec.available_platforms.sort { |a,b| a.to_s.downcase <=> b.to_s.downcase }.join(' - ')
end
def license
spec.license[:type] if spec.license
end
# will return array of all subspecs (recursevly) or nil
def subspecs
(spec.recursive_subspecs.any? && spec.recursive_subspecs) || nil
end
# Statistics information
def creation_date
Pod::Specification::Statistics.instance.creation_date(@set)
end
def github_watchers
Pod::Specification::Statistics.instance.github_watchers(@set)
end
def github_forks
Pod::Specification::Statistics.instance.github_forks(@set)
end
def github_last_activity
distance_from_now_in_words(Pod::Specification::Statistics.instance.github_pushed_at(@set))
end
def ==(other)
self.class === other && @set == other.set
end
def eql?(other)
self.class === other && name.eql?(other.name)
end
def hash
name.hash
end
private
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
case distance_in_days
when 0..7
"less than a week ago"
when 8..29
"#{distance_in_days} days ago"
when 30..45
"1 month ago"
when 46..365
"#{(distance_in_days.to_f / 30).round} months ago"
else
"more than a year ago"
end
end
end
end
end
end
...@@ -36,21 +36,20 @@ module Pod ...@@ -36,21 +36,20 @@ module Pod
update_repo update_repo
add_specs_to_repo add_specs_to_repo
push_repo unless @local_only push_repo unless @local_only
puts
end end
private private
def update_repo def update_repo
puts "Updating the `#{@repo}' repo\n".yellow unless config.silent UI.puts "Updating the `#{@repo}' repo\n".yellow unless config.silent
# show the output of git even if not verbose # show the output of git even if not verbose
# TODO: use the `git!' and find a way to show the output in realtime. # TODO: use the `git!' and find a way to show the output in realtime.
Dir.chdir(repo_dir) { puts `git pull 2>&1` } Dir.chdir(repo_dir) { UI.puts `git pull 2>&1` }
end end
def push_repo def push_repo
puts "\nPushing the `#{@repo}' repo\n".yellow unless config.silent UI.puts "\nPushing the `#{@repo}' repo\n".yellow unless config.silent
Dir.chdir(repo_dir) { puts `git push 2>&1` } Dir.chdir(repo_dir) { UI.puts `git push 2>&1` }
end end
def repo_dir def repo_dir
...@@ -72,7 +71,7 @@ module Pod ...@@ -72,7 +71,7 @@ module Pod
end end
def validate_podspec_files def validate_podspec_files
puts "\nValidating specs".yellow unless config.silent UI.puts "\nValidating specs".yellow unless config.silent
lint_argv = ["lint"] lint_argv = ["lint"]
lint_argv << "--only-errors" if @allow_warnings lint_argv << "--only-errors" if @allow_warnings
lint_argv << "--silent" if config.silent lint_argv << "--silent" if config.silent
...@@ -83,7 +82,7 @@ module Pod ...@@ -83,7 +82,7 @@ module Pod
end end
def add_specs_to_repo def add_specs_to_repo
puts "\nAdding the specs to the #{@repo} repo\n".yellow unless config.silent UI.puts "\nAdding the specs to the #{@repo} repo\n".yellow unless config.silent
podspec_files.each do |spec_file| podspec_files.each do |spec_file|
spec = Pod::Specification.from_file(spec_file) spec = Pod::Specification.from_file(spec_file)
output_path = File.join(repo_dir, spec.name, spec.version.to_s) output_path = File.join(repo_dir, spec.name, spec.version.to_s)
...@@ -94,7 +93,7 @@ module Pod ...@@ -94,7 +93,7 @@ module Pod
else else
message = "[Add] #{spec}" message = "[Add] #{spec}"
end end
puts " - #{message}" unless config.silent UI.puts " - #{message}" unless config.silent
FileUtils.mkdir_p(output_path) FileUtils.mkdir_p(output_path)
FileUtils.cp(Pathname.new(spec.name+'.podspec'), output_path) FileUtils.cp(Pathname.new(spec.name+'.podspec'), output_path)
......
...@@ -56,23 +56,25 @@ module Pod ...@@ -56,23 +56,25 @@ module Pod
end end
def add def add
print_subtitle "Cloning spec repo `#{@name}' from `#{@url}'#{" (branch `#{@branch}')" if @branch}" UI.section ("Cloning spec repo `#{@name}' from `#{@url}'#{" (branch `#{@branch}')" if @branch}") do
config.repos_dir.mkpath config.repos_dir.mkpath
Dir.chdir(config.repos_dir) { git!("clone '#{@url}' #{@name}") } Dir.chdir(config.repos_dir) { git!("clone '#{@url}' #{@name}") }
Dir.chdir(dir) { git!("checkout #{@branch}") } if @branch Dir.chdir(dir) { git!("checkout #{@branch}") } if @branch
check_versions(dir) check_versions(dir)
end
end end
def update def update
dirs = @name ? [dir] : config.repos_dir.children.select {|c| c.directory?} dirs = @name ? [dir] : config.repos_dir.children.select {|c| c.directory?}
dirs.each do |dir| dirs.each do |dir|
print_subtitle "Updating spec repo `#{dir.basename}'" UI.section "Updating spec repo `#{dir.basename}'" do
Dir.chdir(dir) do Dir.chdir(dir) do
`git rev-parse >/dev/null 2>&1` `git rev-parse >/dev/null 2>&1`
if $?.exitstatus.zero? if $?.exitstatus.zero?
git!("pull") git!("pull")
else else
puts(" Not a git repository") if config.verbose? UI.message "Not a git repository"
end
end end
end end
check_versions(dir) check_versions(dir)
...@@ -87,7 +89,7 @@ module Pod ...@@ -87,7 +89,7 @@ module Pod
end end
dirs.each do |dir| dirs.each do |dir|
check_versions(dir) check_versions(dir)
puts "\nLinting spec repo `#{dir.realpath.basename}'\n".yellow UI.puts "\nLinting spec repo `#{dir.realpath.basename}'\n".yellow
podspecs = dir.glob('**/*.podspec') podspecs = dir.glob('**/*.podspec')
invalid_count = 0 invalid_count = 0
...@@ -109,19 +111,19 @@ module Pod ...@@ -109,19 +111,19 @@ module Pod
end end
if should_display if should_display
puts " -> ".send(color) << linter.spec_name UI.puts " -> ".send(color) << linter.spec_name
print_messages('ERROR', linter.errors) print_messages('ERROR', linter.errors)
unless @only_errors unless @only_errors
print_messages('WARN', linter.warnings) print_messages('WARN', linter.warnings)
print_messages('NOTE', linter.notes) print_messages('NOTE', linter.notes)
end end
puts unless config.silent? UI.puts unless config.silent?
end end
end end
puts "Analyzed #{podspecs.count} podspecs files.\n\n" unless config.silent? UI.puts "Analyzed #{podspecs.count} podspecs files.\n\n" unless config.silent?
if invalid_count == 0 if invalid_count == 0
puts "All the specs passed validation.".green << "\n\n" unless config.silent? UI.puts "All the specs passed validation.".green << "\n\n" unless config.silent?
else else
raise Informative, "#{invalid_count} podspecs failed validation." raise Informative, "#{invalid_count} podspecs failed validation."
end end
...@@ -130,7 +132,7 @@ module Pod ...@@ -130,7 +132,7 @@ module Pod
def print_messages(type, messages) def print_messages(type, messages)
return if config.silent? return if config.silent?
messages.each {|msg| puts " - #{type.ljust(5)} | #{msg}"} messages.each {|msg| UI.puts " - #{type.ljust(5)} | #{msg}"}
end end
def check_versions(dir) def check_versions(dir)
...@@ -142,7 +144,7 @@ module Pod ...@@ -142,7 +144,7 @@ module Pod
"\n[!] The `#{dir.basename.to_s}' repo requires CocoaPods #{version_msg}\n".red + "\n[!] The `#{dir.basename.to_s}' repo requires CocoaPods #{version_msg}\n".red +
"Update Cocoapods, or checkout the appropriate tag in the repo.\n\n" "Update Cocoapods, or checkout the appropriate tag in the repo.\n\n"
end end
puts "\nCocoapods #{versions['last']} is available.\n".green if has_update(versions) && config.new_version_message? UI.puts "\nCocoapods #{versions['last']} is available.\n".green if has_update(versions) && config.new_version_message?
end end
def self.compatible?(name) def self.compatible?(name)
......
...@@ -12,20 +12,22 @@ module Pod ...@@ -12,20 +12,22 @@ module Pod
end end
def self.options def self.options
[["--full", "Search by name, summary, and description"]].concat(Presenter.options).concat(super) [[
"--full", "Search by name, summary, and description",
"--stats", "Show additional stats (like GitHub watchers and forks)"
]].concat(super)
end end
def initialize(argv) def initialize(argv)
@full_text_search = argv.option('--full') @full_text_search = argv.option('--full')
@presenter = Presenter.new(argv) @stats = argv.option('--stats')
@query = argv.shift_argument @query = argv.shift_argument
super unless argv.empty? && @query super unless argv.empty? && @query
end end
def run def run
sets = Source.search_by_name(@query.strip, @full_text_search) sets = Source.search_by_name(@query.strip, @full_text_search)
sets.each {|s| puts @presenter.describe(s)} sets.each { |set| UI.pod(set, (@stats ? :stats : :normal)) }
puts
end end
end end
end end
......
...@@ -89,21 +89,22 @@ module Pod ...@@ -89,21 +89,22 @@ module Pod
end end
def run def run
print_title "Setting up CocoaPods master repo" UI.section "Setting up CocoaPods master repo" do
if dir.exist? if dir.exist?
set_master_repo_url set_master_repo_url
set_master_repo_branch set_master_repo_branch
update_master_repo update_master_repo
else else
add_master_repo add_master_repo
end end
# Mainly so the specs run with submodule repos # Mainly so the specs run with submodule repos
if (dir + '.git/hooks').exist? if (dir + '.git/hooks').exist?
hook = dir + '.git/hooks/pre-commit' hook = dir + '.git/hooks/pre-commit'
hook.open('w') { |f| f << "#!/bin/sh\nrake lint" } hook.open('w') { |f| f << "#!/bin/sh\nrake lint" }
`chmod +x '#{hook}'` `chmod +x '#{hook}'`
end
end end
print_subtitle "Setup completed (#{push? ? "push" : "read-only"} access)" UI.puts "Setup completed (#{push? ? "push" : "read-only"} access)".green
end end
end end
end end
......
...@@ -59,17 +59,17 @@ module Pod ...@@ -59,17 +59,17 @@ module Pod
repo_id = repo_id_match[1] repo_id = repo_id_match[1]
data = github_data_for_template(repo_id) data = github_data_for_template(repo_id)
data[:name] = @name_or_url if @url data[:name] = @name_or_url if @url
puts semantic_versioning_notice(repo_id, data[:name]) if data[:version] == '0.0.1' UI.puts semantic_versioning_notice(repo_id, data[:name]) if data[:version] == '0.0.1'
else else
data = default_data_for_template(@name_or_url) data = default_data_for_template(@name_or_url)
end end
spec = spec_template(data) spec = spec_template(data)
(Pathname.pwd + "#{data[:name]}.podspec").open('w') { |f| f << spec } (Pathname.pwd + "#{data[:name]}.podspec").open('w') { |f| f << spec }
puts "\nSpecification created at #{data[:name]}.podspec".green UI.puts "\nSpecification created at #{data[:name]}.podspec".green
end end
def lint def lint
puts UI.puts
invalid_count = 0 invalid_count = 0
podspecs_to_lint.each do |podspec| podspecs_to_lint.each do |podspec|
linter = Linter.new(podspec) linter = Linter.new(podspec)
...@@ -93,19 +93,19 @@ module Pod ...@@ -93,19 +93,19 @@ module Pod
end end
# This overwrites the previously printed text # This overwrites the previously printed text
puts " -> ".send(color) << linter.spec_name unless config.silent? UI.puts " -> ".send(color) << linter.spec_name unless config.silent?
print_messages('ERROR', linter.errors) print_messages('ERROR', linter.errors)
print_messages('WARN', linter.warnings) print_messages('WARN', linter.warnings)
print_messages('NOTE', linter.notes) print_messages('NOTE', linter.notes)
puts unless config.silent? UI.puts unless config.silent?
end end
puts "Analyzed #{podspecs_to_lint.count} podspecs files.\n\n" unless config.silent? UI.puts "Analyzed #{podspecs_to_lint.count} podspecs files.\n\n" unless config.silent?
count = podspecs_to_lint.count count = podspecs_to_lint.count
if invalid_count == 0 if invalid_count == 0
lint_passed_message = count == 1 ? "#{podspecs_to_lint.first.basename} passed validation." : "All the specs passed validation." lint_passed_message = count == 1 ? "#{podspecs_to_lint.first.basename} passed validation." : "All the specs passed validation."
puts lint_passed_message.green << "\n\n" unless config.silent? UI.puts lint_passed_message.green << "\n\n" unless config.silent?
else else
raise Informative, count == 1 ? "The spec did not pass validation." : "#{invalid_count} out of #{count} specs failed validation." raise Informative, count == 1 ? "The spec did not pass validation." : "#{invalid_count} out of #{count} specs failed validation."
end end
...@@ -116,7 +116,7 @@ module Pod ...@@ -116,7 +116,7 @@ module Pod
def print_messages(type, messages) def print_messages(type, messages)
return if config.silent? return if config.silent?
messages.each {|msg| puts " - #{type.ljust(5)} | #{msg}"} messages.each {|msg| UI.puts " - #{type.ljust(5)} | #{msg}"}
end end
def podspecs_to_lint def podspecs_to_lint
......
...@@ -193,14 +193,15 @@ module Pod ...@@ -193,14 +193,15 @@ module Pod
class GitSource < AbstractExternalSource class GitSource < AbstractExternalSource
def copy_external_source_into_sandbox(sandbox, platform) def copy_external_source_into_sandbox(sandbox, platform)
puts "-> Pre-downloading: '#{name}'" unless config.silent? UI.info("->".green + " Pre-downloading: '#{name}'") do
target = sandbox.root + name target = sandbox.root + name
target.rmtree if target.exist? target.rmtree if target.exist?
downloader = Downloader.for_target(sandbox.root + name, @params) downloader = Downloader.for_target(sandbox.root + name, @params)
downloader.download downloader.download
store_podspec(sandbox, target + "#{name}.podspec") store_podspec(sandbox, target + "#{name}.podspec")
if local_pod = sandbox.installed_pod_named(name, platform) if local_pod = sandbox.installed_pod_named(name, platform)
local_pod.downloaded = true local_pod.downloaded = true
end
end end
end end
...@@ -216,10 +217,11 @@ module Pod ...@@ -216,10 +217,11 @@ module Pod
# can be http, file, etc # can be http, file, etc
class PodspecSource < AbstractExternalSource class PodspecSource < AbstractExternalSource
def copy_external_source_into_sandbox(sandbox, _) def copy_external_source_into_sandbox(sandbox, _)
puts "-> Fetching podspec for `#{name}' from: #{@params[:podspec]}" unless config.silent? UI.info("->".green + " Fetching podspec for `#{name}' from: #{@params[:podspec]}") do
path = @params[:podspec] path = @params[:podspec]
path = Pathname.new(path).expand_path if path.start_with?("~") path = Pathname.new(path).expand_path if path.start_with?("~")
open(path) { |io| store_podspec(sandbox, io.read) } open(path) { |io| store_podspec(sandbox, io.read) }
end
end end
def description def description
......
...@@ -7,33 +7,33 @@ module Pod ...@@ -7,33 +7,33 @@ module Pod
class Downloader class Downloader
class Git < Downloader class Git < Downloader
include Config::Mixin include Config::Mixin
executable :git executable :git
MAX_CACHE_SIZE = 500 MAX_CACHE_SIZE = 500
def download def download
create_cache unless cache_exist? create_cache unless cache_exist?
puts '-> Cloning git repo' if config.verbose? UI.section(' > Cloning git repo', '', 1) do
if options[:tag]
if options[:tag] download_tag
download_tag elsif options[:branch]
elsif options[:branch] download_branch
download_branch elsif options[:commit]
elsif options[:commit] download_commit
download_commit else
else download_head
download_head end
Dir.chdir(target_path) { git! "submodule update --init" } if options[:submodules]
end end
Dir.chdir(target_path) { git! "submodule update --init" } if options[:submodules]
prune_cache prune_cache
end end
def create_cache def create_cache
puts "-> Creating cache git repo (#{cache_path})" if config.verbose? UI.section(" > Creating cache git repo (#{cache_path})",'',1)
cache_path.rmtree if cache_path.exist? cache_path.rmtree if cache_path.exist?
cache_path.mkpath cache_path.mkpath
clone(url, cache_path) git! %Q|clone --mirror "#{url}" "#{cache_path}"|
end end
def prune_cache def prune_cache
...@@ -42,7 +42,7 @@ module Pod ...@@ -42,7 +42,7 @@ module Pod
repos = Pathname.new(caches_dir).children.select { |c| c.directory? }.sort_by(&:ctime) repos = Pathname.new(caches_dir).children.select { |c| c.directory? }.sort_by(&:ctime)
while caches_size >= MAX_CACHE_SIZE && !repos.empty? while caches_size >= MAX_CACHE_SIZE && !repos.empty?
dir = repos.shift dir = repos.shift
puts '->'.yellow << " Removing git cache for `#{origin_url(dir)}'" if config.verbose? UI.message "#{'->'.yellow} Removing git cache for `#{origin_url(dir)}'"
dir.rmtree dir.rmtree
end end
end end
...@@ -74,13 +74,17 @@ module Pod ...@@ -74,13 +74,17 @@ module Pod
end end
def update_cache def update_cache
puts "-> Updating cache git repo (#{cache_path})" if config.verbose? UI.section(" > Updating cache git repo (#{cache_path})",'',1) do
Dir.chdir(cache_path) do Dir.chdir(cache_path) do
git! "reset --hard HEAD" if git("config core.bare").chomp == "true"
git! "clean -d -x -f" git! "remote update"
git! "pull origin master" else
git! "fetch" git! "reset --hard HEAD"
git! "fetch --tags" git! "clean -d -x -f"
git! "pull origin master"
git! "fetch --tags"
end
end
end end
end end
...@@ -97,7 +101,7 @@ module Pod ...@@ -97,7 +101,7 @@ module Pod
end end
def branch_exists?(branch) def branch_exists?(branch)
Dir.chdir(cache_path) { git "branch -r | grep #{branch}$" } # check for remote branch and do suffix matching ($ anchor) Dir.chdir(cache_path) { git "branch --all | grep #{branch}$" } # check for remote branch and do suffix matching ($ anchor)
$? == 0 $? == 0
end end
...@@ -144,12 +148,14 @@ module Pod ...@@ -144,12 +148,14 @@ module Pod
git! "remote add upstream '#{@url}'" # we need to add the original url, not the cache url git! "remote add upstream '#{@url}'" # we need to add the original url, not the cache url
git! "fetch -q upstream" # refresh the branches git! "fetch -q upstream" # refresh the branches
git! "checkout --track -b activated-pod-commit upstream/#{options[:branch]}" # create a new tracking branch git! "checkout --track -b activated-pod-commit upstream/#{options[:branch]}" # create a new tracking branch
puts "Just downloaded and checked out branch: #{options[:branch]} from upstream #{clone_url}" if config.verbose? UI.message("Just downloaded and checked out branch: #{options[:branch]} from upstream #{clone_url}")
end end
end end
def clone(from, to) def clone(from, to)
git! %Q|clone "#{from}" "#{to}"| UI.section(" > Cloning to Pods folder",'',1) do
git! %Q|clone "#{from}" "#{to}"|
end
end end
end end
......
...@@ -16,9 +16,10 @@ module Pod ...@@ -16,9 +16,10 @@ module Pod
def download def download
@filename = filename_with_type type @filename = filename_with_type type
@download_path = target_path + @filename @download_path = target_path + @filename
UI.section(' > Downloading from HTTP', '', 3) do
download_file @download_path download_file @download_path
extract_with_type @download_path, type extract_with_type @download_path, type
end
end end
def type def type
......
...@@ -4,10 +4,12 @@ module Pod ...@@ -4,10 +4,12 @@ module Pod
executable :hg executable :hg
def download def download
if options[:revision] UI.section(' > Cloning mercurial repo', '', 3) do
download_revision if options[:revision]
else download_revision
download_head else
download_head
end
end end
end end
......
...@@ -8,11 +8,15 @@ module Pod ...@@ -8,11 +8,15 @@ module Pod
end end
def download def download
svn! %|export "#{reference_url}" "#{target_path}"| UI.section(' > Exporting subversion repo', '', 3) do
svn! %|export "#{reference_url}" "#{target_path}"|
end
end end
def download_head def download_head
svn! %|export "#{trunk_url}" "#{target_path}"| UI.section(' > Exporting subversion repo', '', 3) do
svn! %|export "#{trunk_url}" "#{target_path}"|
end
end end
def reference_url def reference_url
......
...@@ -3,12 +3,14 @@ require 'open4' ...@@ -3,12 +3,14 @@ require 'open4'
module Pod module Pod
module Executable module Executable
class Indenter < ::Array class Indenter < ::Array
include Config::Mixin
attr_accessor :indent attr_accessor :indent
attr_accessor :io attr_accessor :io
def initialize(io = nil, indent = ' ') def initialize(io = nil)
@io = io @io = io
@indent = indent @indent = ' ' * UI.indentation_level
end end
def <<(value) def <<(value)
...@@ -27,20 +29,19 @@ module Pod ...@@ -27,20 +29,19 @@ module Pod
end end
full_command = "#{bin} #{command}" full_command = "#{bin} #{command}"
if Config.instance.verbose? if Config.instance.verbose?
puts " $ #{full_command}" UI.message("$ #{full_command}")
stdout, stderr = Indenter.new(STDOUT), Indenter.new(STDERR) stdout, stderr = Indenter.new(STDOUT), Indenter.new(STDERR)
else else
stdout, stderr = Indenter.new, Indenter.new stdout, stderr = Indenter.new, Indenter.new
end end
status = Open4.spawn(full_command, :stdout => stdout, :stderr => stderr, :status => true) status = Open4.spawn(full_command, :stdout => stdout, :stderr => stderr, :status => true)
# TODO not sure that we should be silent in case of a failure.
output = stdout.join("\n") + stderr.join("\n") # TODO will this suffice? output = stdout.join("\n") + stderr.join("\n") # TODO will this suffice?
unless status.success? unless status.success?
if should_raise if should_raise
raise Informative, "#{name} #{command}\n\n#{output}" raise Informative, "#{name} #{command}\n\n#{output}"
else else
puts((Config.instance.verbose? ? ' ' : '') << "[!] Failed: #{full_command}".red) unless Config.instance.silent? UI.message("[!] Failed: #{full_command}".red)
end end
end end
output output
...@@ -54,7 +55,6 @@ module Pod ...@@ -54,7 +55,6 @@ module Pod
send(base_method, command, true) send(base_method, command, true)
end end
private name private name
end end
end end
......
...@@ -49,23 +49,21 @@ module Pod ...@@ -49,23 +49,21 @@ module Pod
def install_dependencies! def install_dependencies!
pods.sort_by { |pod| pod.top_specification.name.downcase }.each do |pod| pods.sort_by { |pod| pod.top_specification.name.downcase }.each do |pod|
should_install = @resolver.should_install?(pod.top_specification.name) || !pod.exists? should_install = @resolver.should_install?(pod.top_specification.name) || !pod.exists?
unless config.silent?
marker = config.verbose ? "\n-> ".green : ''
puts marker << ( should_install ? "Installing #{pod}".green : "Using #{pod}" )
end
if should_install if should_install
unless pod.downloaded? UI.section("Installing #{pod}".green, "-> ".green) do
pod.implode unless pod.downloaded?
download_pod(pod) pod.implode
download_pod(pod)
end
# The docs need to be generated before cleaning because the
# documentation is created for all the subspecs.
generate_docs(pod)
# Here we clean pod's that just have been downloaded or have been
# pre-downloaded in AbstractExternalSource#specification_from_sandbox.
pod.clean! if config.clean?
end end
# The docs need to be generated before cleaning because the else
# documentation is created for all the subspecs. UI.section("Using #{pod}", "-> ".green)
generate_docs(pod)
# Here we clean pod's that just have been downloaded or have been
# pre-downloaded in AbstractExternalSource#specification_from_sandbox.
pod.clean! if config.clean?
end end
end end
end end
...@@ -89,10 +87,10 @@ module Pod ...@@ -89,10 +87,10 @@ module Pod
def generate_docs(pod) def generate_docs(pod)
doc_generator = Generator::Documentation.new(pod) doc_generator = Generator::Documentation.new(pod)
if ( config.generate_docs? && !doc_generator.already_installed? ) if ( config.generate_docs? && !doc_generator.already_installed? )
puts "-> Installing documentation" if config.verbose? UI.section " > Installing documentation"
doc_generator.generate(config.doc_install?) doc_generator.generate(config.doc_install?)
else else
puts "-> Using existing documentation" if config.verbose? UI.section " > Using existing documentation"
end end
end end
...@@ -100,47 +98,61 @@ module Pod ...@@ -100,47 +98,61 @@ module Pod
# #
def remove_deleted_dependencies! def remove_deleted_dependencies!
resolver.removed_pods.each do |pod_name| resolver.removed_pods.each do |pod_name|
marker = config.verbose ? "\n-> ".red : '' UI.section("Removing #{pod_name}", "-> ".red) do
path = sandbox.root + pod_name path = sandbox.root + pod_name
puts marker << "Removing #{pod_name}".red path.rmtree if path.exist?
path.rmtree if path.exist? end
end end
end end
def install! def install!
@sandbox.prepare_for_install @sandbox.prepare_for_install
UI.section "Resolving dependencies of #{UI.path @podfile.defined_in_file}" do
specs_by_target
end
print_title "Resolving dependencies of: #{@podfile.defined_in_file}" UI.section "Removing deleted dependencies" do
specs_by_target remove_deleted_dependencies!
end unless resolver.removed_pods.empty?
print_title "Removing deleted dependencies" unless resolver.removed_pods.empty? UI.section "Downloading dependencies" do
remove_deleted_dependencies! install_dependencies!
end
print_title "Installing dependencies" UI.section "Generating support files" do
install_dependencies! UI.message "- Running pre install hooks" do
run_pre_install_hooks
end
print_title("Generating support files\n", false) UI.message"- Installing targets" do
target_installers.each do |target_installer| generate_target_support_files
pods_for_target = pods_by_target[target_installer.target_definition] end
target_installer.install!(pods_for_target, @sandbox)
acknowledgements_path = target_installer.target_definition.acknowledgements_path
Generator::Acknowledgements.new(target_installer.target_definition,
pods_for_target).save_as(acknowledgements_path)
generate_dummy_source(target_installer)
end
puts "- Running post install hooks" if config.verbose? UI.message "- Running post install hooks" do
# Post install hooks run _before_ saving of project, so that they can alter it before saving. # Post install hooks run _before_ saving of project, so that they can alter it before saving.
run_post_install_hooks run_post_install_hooks
end
UI.message "- Writing Xcode project file to #{UI.path @sandbox.project_path}" do
project.save_as(@sandbox.project_path)
end
puts "- Writing Xcode project file to `#{@sandbox.project_path}'" if config.verbose? UI.message "- Writing lockfile in #{UI.path config.project_lockfile}" do
project.save_as(@sandbox.project_path) @lockfile = Lockfile.generate(@podfile, specs_by_target.values.flatten)
@lockfile.write_to_disk(config.project_lockfile)
end
end
puts "- Writing lockfile in `#{config.project_lockfile}'\n\n" if config.verbose? UserProjectIntegrator.new(@podfile).integrate! if config.integrate_targets?
@lockfile = Lockfile.generate(@podfile, specs_by_target.values.flatten) end
@lockfile.write_to_disk(config.project_lockfile)
UserProjectIntegrator.new(@podfile).integrate! if config.integrate_targets? def run_pre_install_hooks
pods_by_target.each do |target_definition, pods|
pods.each do |pod|
pod.top_specification.pre_install(pod, target_definition)
end
end
@podfile.pre_install!(self)
end end
def run_post_install_hooks def run_post_install_hooks
...@@ -151,10 +163,20 @@ module Pod ...@@ -151,10 +163,20 @@ module Pod
spec.post_install(target_installer) spec.post_install(target_installer)
end end
end end
@podfile.post_install!(self) @podfile.post_install!(self)
end end
def generate_target_support_files
target_installers.each do |target_installer|
pods_for_target = pods_by_target[target_installer.target_definition]
target_installer.install!(pods_for_target, @sandbox)
acknowledgements_path = target_installer.target_definition.acknowledgements_path
Generator::Acknowledgements.new(target_installer.target_definition,
pods_for_target).save_as(acknowledgements_path)
generate_dummy_source(target_installer)
end
end
def generate_dummy_source(target_installer) def generate_dummy_source(target_installer)
class_name_identifier = target_installer.target_definition.label class_name_identifier = target_installer.target_definition.label
dummy_source = Generator::DummySource.new(class_name_identifier) dummy_source = Generator::DummySource.new(class_name_identifier)
...@@ -198,15 +220,5 @@ module Pod ...@@ -198,15 +220,5 @@ module Pod
end end
result result
end end
private
def print_title(title, only_verbose = true)
if config.verbose?
puts "\n" + title.yellow
elsif !config.silent? && !only_verbose
puts title
end
end
end end
end end
...@@ -97,20 +97,24 @@ module Pod ...@@ -97,20 +97,24 @@ module Pod
end end
def create_files(pods, sandbox) def create_files(pods, sandbox)
if @podfile.generate_bridge_support? bridge_support_metadata_path = sandbox.root + @target_definition.bridge_support_name
bridge_support_metadata_path = sandbox.root + @target_definition.bridge_support_name UI.message "- Generating BridgeSupport metadata file at #{UI.path bridge_support_metadata_path}" do
puts "- Generating BridgeSupport metadata file at `#{bridge_support_metadata_path}'" if config.verbose?
bridge_support_generator_for(pods, sandbox).save_as(bridge_support_metadata_path) bridge_support_generator_for(pods, sandbox).save_as(bridge_support_metadata_path)
copy_resources_script_for(pods).resources << @target_definition.bridge_support_name copy_resources_script_for(pods).resources << @target_definition.bridge_support_name
end if @podfile.generate_bridge_support?
UI.message "- Generating xcconfig file at #{UI.path(sandbox.root + @target_definition.xcconfig_name)}" do
xcconfig.save_as(sandbox.root + @target_definition.xcconfig_name)
@target_definition.xcconfig = xcconfig
end
UI.message "- Generating prefix header at #{UI.path(sandbox.root + @target_definition.prefix_header_name)}" do
save_prefix_header_as(sandbox.root + @target_definition.prefix_header_name, pods)
end
UI.message "- Generating copy resources script at #{UI.path(sandbox.root + @target_definition.copy_resources_script_name)}" do
copy_resources_script_for(pods).save_as(sandbox.root + @target_definition.copy_resources_script_name)
end end
puts "- Generating xcconfig file at `#{sandbox.root + @target_definition.xcconfig_name}'" if config.verbose?
xcconfig.save_as(sandbox.root + @target_definition.xcconfig_name)
@target_definition.xcconfig = xcconfig
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?
copy_resources_script_for(pods).save_as(sandbox.root + @target_definition.copy_resources_script_name)
end end
private private
......
...@@ -51,7 +51,7 @@ module Pod ...@@ -51,7 +51,7 @@ module Pod
workspace << project_path unless workspace.include?(project_path) workspace << project_path unless workspace.include?(project_path)
end end
unless workspace_path.exist? || config.silent? unless workspace_path.exist? || config.silent?
puts "[!] From now on use `#{workspace_path.basename}'." UI.notice "From now on use `#{workspace_path.basename}'."
end end
workspace.save_as(workspace_path) workspace.save_as(workspace_path)
end end
...@@ -69,20 +69,30 @@ module Pod ...@@ -69,20 +69,30 @@ module Pod
"#<#{self.class} for target `#{@target_definition.label}'>" "#<#{self.class} for target `#{@target_definition.label}'>"
end end
# Integrates the user project targets. Only the targets that do **not**
# already have the Pods library in their frameworks build phase are
# processed.
#
# @return [void]
#
def integrate! def integrate!
return if targets.empty? return if targets.empty?
unless Config.instance.silent? UI.section ("Integrating `#{@target_definition.lib_name}' into #{'target'.pluralize(targets.size)} " \
puts "-> Integrating `#{@target_definition.lib_name}' into #{'target'.pluralize(targets.size)} " \ "`#{targets.map(&:name).to_sentence}' of Xcode project #{UI.path user_project_path}.") do
"`#{targets.map(&:name).to_sentence}' of Xcode project `#{user_project_path.basename}'.".green add_xcconfig_base_configuration
add_pods_library
add_copy_resources_script_phase
user_project.save_as(@target_definition.user_project.path)
end end
add_xcconfig_base_configuration
add_pods_library
add_copy_resources_script_phase
user_project.save_as(@target_definition.user_project.path)
end end
# @return [Pathname] the path of the user project.
#
# @raises If the path doesn't exits.
#
# @raises If the project is implicit and there are multiple projects.
#
def user_project_path def user_project_path
if path = @target_definition.user_project.path if path = @target_definition.user_project.path
unless path.exist? unless path.exist?
...@@ -96,6 +106,8 @@ module Pod ...@@ -96,6 +106,8 @@ module Pod
end end
end end
# @return [Xcodeproj::Project] Returns the project of the user.
#
def user_project def user_project
@user_project ||= Xcodeproj::Project.new(user_project_path) @user_project ||= Xcodeproj::Project.new(user_project_path)
end end
...@@ -152,13 +164,10 @@ module Pod ...@@ -152,13 +164,10 @@ module Pod
config.base_configuration = xcconfig config.base_configuration = xcconfig
end end
unless config.silent? config_build_names_by_overriden_key.each do |key, config_build_names|
config_build_names_by_overriden_key.each do |key, config_build_names| name = "#{target.attributes["name"]} [#{config_build_names.join(' - ')}]"
name = "#{target.attributes["name"]} [#{config_build_names.join(' - ')}]" actions = [ "Use the `$(inherited)' flag, or", "Remove the build settings from the target." ]
puts "\n[!] The target `#{name}' overrides the `#{key}' build setting defined in `#{@target_definition.xcconfig_relative_path}'.".yellow UI.warn("The target `#{name}' overrides the `#{key}' build setting defined in `#{@target_definition.xcconfig_relative_path}'.", actions)
puts " - Use the `$(inherited)' flag, or"
puts " - Remove the build settings from the target."
end
end end
end end
end end
......
...@@ -432,9 +432,10 @@ module Pod ...@@ -432,9 +432,10 @@ module Pod
mappings = {} mappings = {}
files_by_spec.each do |spec, paths| files_by_spec.each do |spec, paths|
paths = paths - headers_excluded_from_search_paths paths = paths - headers_excluded_from_search_paths
dir = spec.header_dir ? (headers_sandbox + spec.header_dir) : headers_sandbox
paths.each do |from| paths.each do |from|
from_relative = from.relative_path_from(root) from_relative = from.relative_path_from(root)
to = headers_sandbox + (spec.header_dir) + spec.copy_header_mapping(from_relative) to = dir + spec.copy_header_mapping(from_relative)
(mappings[to.dirname] ||= []) << from (mappings[to.dirname] ||= []) << from
end end
end end
......
...@@ -472,6 +472,17 @@ module Pod ...@@ -472,6 +472,17 @@ module Pod
@target_definition = parent @target_definition = parent
end end
# This hook allows you to make any changes to the downloaded Pods and to
# their targets before they are installed.
#
# pre_install do |installer|
# # Do something fancy!
# end
#
def pre_install(&block)
@pre_install_callback = block
end
# This hook allows you to make any last changes to the generated Xcode project # This hook allows you to make any last changes to the generated Xcode project
# before it is written to disk, or any other tasks you might want to perform. # before it is written to disk, or any other tasks you might want to perform.
# #
...@@ -532,6 +543,10 @@ module Pod ...@@ -532,6 +543,10 @@ module Pod
configs_array.inject({}) { |hash, config| hash.merge(config) } configs_array.inject({}) { |hash, config| hash.merge(config) }
end end
def pre_install!(installer)
@pre_install_callback.call(installer) if @pre_install_callback
end
def post_install!(installer) def post_install!(installer)
@post_install_callback.call(installer) if @post_install_callback @post_install_callback.call(installer) if @post_install_callback
end end
......
...@@ -66,36 +66,26 @@ module Pod ...@@ -66,36 +66,26 @@ module Pod
@specs_by_target = {} @specs_by_target = {}
@pods_from_external_sources = [] @pods_from_external_sources = []
@pods_to_lock = [] @pods_to_lock = []
@log_indent = 0
if @lockfile if @lockfile
puts "\nFinding added, modified or removed dependencies:".green if config.verbose?
@pods_by_state = @lockfile.detect_changes_with_podfile(podfile) @pods_by_state = @lockfile.detect_changes_with_podfile(podfile)
if config.verbose? UI.section "Finding added, modified or removed dependencies:" do
marks = {:added => "A".green, :changed => "M".yellow, :removed => "R".red, :unchanged => "-" }
@pods_by_state.each do |symbol, pod_names| @pods_by_state.each do |symbol, pod_names|
case symbol
when :added
mark = "A".green
when :changed
mark = "M".yellow
when :removed
mark = "R".red
when :unchanged
mark = "-"
end
pod_names.each do |pod_name| pod_names.each do |pod_name|
puts " #{mark} " << pod_name UI.message("#{marks[symbol]} #{pod_name}", '',2)
end end
end end
end end if config.verbose?
@pods_to_lock = (lockfile.pods_names - @pods_by_state[:added] - @pods_by_state[:changed] - @pods_by_state[:removed]).uniq @pods_to_lock = (lockfile.pods_names - @pods_by_state[:added] - @pods_by_state[:changed] - @pods_by_state[:removed]).uniq
end end
@podfile.target_definitions.values.each do |target_definition| @podfile.target_definitions.values.each do |target_definition|
puts "\nResolving dependencies for target `#{target_definition.name}' (#{target_definition.platform}):".green if config.verbose? UI.section "Resolving dependencies for target `#{target_definition.name}' (#{target_definition.platform}):" do
@loaded_specs = [] @loaded_specs = []
find_dependency_specs(@podfile, target_definition.dependencies, target_definition) find_dependency_specs(@podfile, target_definition.dependencies, target_definition)
@specs_by_target[target_definition] = @cached_specs.values_at(*@loaded_specs).sort_by(&:name) @specs_by_target[target_definition] = @cached_specs.values_at(*@loaded_specs).sort_by(&:name)
end
end end
@cached_specs.values.sort_by(&:name) @cached_specs.values.sort_by(&:name)
...@@ -187,32 +177,30 @@ module Pod ...@@ -187,32 +177,30 @@ module Pod
# @return [void] # @return [void]
# #
def find_dependency_specs(dependent_specification, dependencies, target_definition) def find_dependency_specs(dependent_specification, dependencies, target_definition)
@log_indent += 1
dependencies.each do |dependency| dependencies.each do |dependency|
# Replace the dependency with a more specific one if the pod is already installed. # Replace the dependency with a more specific one if the pod is already installed.
if !update_mode && @pods_to_lock.include?(dependency.name) if !update_mode && @pods_to_lock.include?(dependency.name)
dependency = lockfile.dependency_for_installed_pod_named(dependency.name) dependency = lockfile.dependency_for_installed_pod_named(dependency.name)
end end
UI.message("- #{dependency}", '', 2) do
puts ' ' * @log_indent + "- #{dependency}" if config.verbose? set = find_cached_set(dependency, target_definition.platform)
set = find_cached_set(dependency, target_definition.platform) set.required_by(dependency, dependent_specification.to_s)
set.required_by(dependency, dependent_specification.to_s)
# Ensure we don't resolve the same spec twice for one target
# Ensure we don't resolve the same spec twice for one target unless @loaded_specs.include?(dependency.name)
unless @loaded_specs.include?(dependency.name) spec = set.specification_by_name(dependency.name)
spec = set.specification_by_name(dependency.name) @pods_from_external_sources << spec.pod_name if dependency.external?
@pods_from_external_sources << spec.pod_name if dependency.external? @loaded_specs << spec.name
@loaded_specs << spec.name @cached_specs[spec.name] = spec
@cached_specs[spec.name] = spec # Configure the specification
# Configure the specification spec.activate_platform(target_definition.platform)
spec.activate_platform(target_definition.platform) spec.version.head = dependency.head?
spec.version.head = dependency.head? # And recursively load the dependencies of the spec.
# And recursively load the dependencies of the spec. find_dependency_specs(spec, spec.dependencies, target_definition) if spec.dependencies
find_dependency_specs(spec, spec.dependencies, target_definition) if spec.dependencies end
validate_platform(spec || @cached_specs[dependency.name], target_definition)
end end
validate_platform(spec || @cached_specs[dependency.name], target_definition)
end end
@log_indent -= 1
end end
# Ensures that a spec is compatible with platform of a target. # Ensures that a spec is compatible with platform of a target.
......
...@@ -54,6 +54,7 @@ module Pod ...@@ -54,6 +54,7 @@ module Pod
@xcconfig = { :ios => Xcodeproj::Config.new, :osx => Xcodeproj::Config.new } @xcconfig = { :ios => Xcodeproj::Config.new, :osx => Xcodeproj::Config.new }
@header_dir = { :ios => nil, :osx => nil } @header_dir = { :ios => nil, :osx => nil }
@requires_arc = { :ios => nil, :osx => nil } @requires_arc = { :ios => nil, :osx => nil }
@header_mappings_dir = { :ios => nil, :osx => nil }
yield self if block_given? yield self if block_given?
end end
...@@ -88,6 +89,7 @@ module Pod ...@@ -88,6 +89,7 @@ module Pod
# Returns the value of the attribute for the active platform # Returns the value of the attribute for the active platform
# chained with the upstream specifications. The ivar must store # chained with the upstream specifications. The ivar must store
# the platform specific values as an array. # the platform specific values as an array.
#
def self.pltf_chained_attr_reader(attr) def self.pltf_chained_attr_reader(attr)
define_method(attr) do define_method(attr) do
active_plaform_check active_plaform_check
...@@ -96,6 +98,17 @@ module Pod ...@@ -96,6 +98,17 @@ module Pod
end end
end end
# Returns the first value defined of the attribute traversing the chain
# upwards.
#
def self.pltf_first_defined_attr_reader(attr)
define_method(attr) do
active_plaform_check
ivar_value = instance_variable_get("@#{attr}")[active_platform]
ivar_value.nil? ? (@parent.send(attr) if @parent) : ivar_value
end
end
def active_plaform_check def active_plaform_check
raise Informative, "#{self.inspect} not activated for a platform before consumption." unless active_platform raise Informative, "#{self.inspect} not activated for a platform before consumption." unless active_platform
end end
...@@ -240,13 +253,11 @@ module Pod ...@@ -240,13 +253,11 @@ module Pod
### Attributes **with** multiple platform support ### Attributes **with** multiple platform support
# @todo allow for subspecs # @todo allow for subspecs?
# #
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_file, lambda { |file| Pathname.new(file) }
top_attr_accessor :prefix_header_contents top_attr_accessor :prefix_header_contents
pltf_chained_attr_accessor :source_files, lambda {|value, current| pattern_list(value) } pltf_chained_attr_accessor :source_files, lambda {|value, current| pattern_list(value) }
pltf_chained_attr_accessor :public_header_files, lambda {|value, current| pattern_list(value) } pltf_chained_attr_accessor :public_header_files, lambda {|value, current| pattern_list(value) }
pltf_chained_attr_accessor :resources, lambda {|value, current| pattern_list(value) } pltf_chained_attr_accessor :resources, lambda {|value, current| pattern_list(value) }
...@@ -262,7 +273,6 @@ module Pod ...@@ -262,7 +273,6 @@ module Pod
alias_method :weak_framework=, :weak_frameworks= alias_method :weak_framework=, :weak_frameworks=
alias_method :library=, :libraries= alias_method :library=, :libraries=
# @!method requires_arc= # @!method requires_arc=
# #
# @abstract Wether the `-fobjc-arc' flag should be added to the compiler # @abstract Wether the `-fobjc-arc' flag should be added to the compiler
...@@ -271,14 +281,7 @@ module Pod ...@@ -271,14 +281,7 @@ module Pod
# @param [Bool] Wether the source files require ARC. # @param [Bool] Wether the source files require ARC.
# #
platform_attr_writer :requires_arc platform_attr_writer :requires_arc
pltf_first_defined_attr_reader :requires_arc
def requires_arc
requires_arc = @requires_arc[active_platform]
if requires_arc.nil?
requires_arc = @parent ? @parent.requires_arc : false
end
requires_arc
end
# @!method header_dir= # @!method header_dir=
# #
...@@ -287,17 +290,13 @@ module Pod ...@@ -287,17 +290,13 @@ module Pod
# #
# @param [String] The headers directory. # @param [String] The headers directory.
# #
platform_attr_writer :header_dir, lambda { |dir, _| Pathname.new(dir) } platform_attr_writer :header_dir, lambda { |dir, _| Pathname.new(dir) }
pltf_first_defined_attr_reader :header_dir
# @abstract (see #header_dir=) # If not provided the headers files are flattened
#
# @return [Pathname] The headers directory.
# #
# @note If no value is provided it returns an empty {Pathname}. platform_attr_writer :header_mappings_dir, lambda { |file, _| Pathname.new(file) }
# pltf_first_defined_attr_reader :header_mappings_dir
def header_dir
@header_dir[active_platform] || (@parent.header_dir if @parent) || Pathname.new('')
end
# @!method xcconfig= # @!method xcconfig=
# #
...@@ -316,13 +315,14 @@ module Pod ...@@ -316,13 +315,14 @@ module Pod
end end
def recursive_compiler_flags
@parent ? @parent.recursive_compiler_flags | @compiler_flags[active_platform] : @compiler_flags[active_platform]
end
def compiler_flags def compiler_flags
if @parent flags = recursive_compiler_flags.dup
flags = [@parent.compiler_flags] flags << '-fobjc-arc' if requires_arc
else flags.join(' ')
flags = [requires_arc ? ' -fobjc-arc' : '']
end
(flags + @compiler_flags[active_platform].clone).join(' ')
end end
platform_attr_writer :compiler_flags, lambda {|value, current| current << value } platform_attr_writer :compiler_flags, lambda {|value, current| current << value }
...@@ -430,20 +430,36 @@ module Pod ...@@ -430,20 +430,36 @@ module Pod
header_mappings_dir ? from.relative_path_from(header_mappings_dir) : from.basename header_mappings_dir ? from.relative_path_from(header_mappings_dir) : from.basename
end end
# This is a convenience method which gets called after all pods have been
# downloaded but before they have been installed, and the Xcode project and
# related files have been generated. (It receives the Pod::LocalPod
# instance generated form the specification and the #
# Pod::Podfile::TargetDefinition instance for the current target.) Override
# this to, for instance, to run any build script:
#
# Pod::Spec.new do |s|
# def pre_install(pod, target_definition)
# Dir.chdir(pod.root){ `sh make.sh` }
# end
# end
def pre_install(pod, target_definition)
end
# This is a convenience method which gets called after all pods have been # This is a convenience method which gets called after all pods have been
# downloaded, installed, and the Xcode project and related files have been # downloaded, installed, and the Xcode project and related files have been
# generated. (It receives the Pod::Installer::Target instance for the current # generated. (It receives the Pod::Installer::TargetInstaller instance for
# target.) Override this to, for instance, add to the prefix header: # the current target.) Override this to, for instance, add to the prefix
# header:
# #
# Pod::Spec.new do |s| # Pod::Spec.new do |s|
# def s.post_install(target) # def s.post_install(target_installer)
# prefix_header = config.project_pods_root + target.prefix_header_filename # prefix_header = config.project_pods_root + target_installer.prefix_header_filename
# prefix_header.open('a') do |file| # prefix_header.open('a') do |file|
# file.puts(%{#ifdef __OBJC__\n#import "SSToolkitDefines.h"\n#endif}) # file.puts(%{#ifdef __OBJC__\n#import "SSToolkitDefines.h"\n#endif})
# end # end
# end # end
# end # end
def post_install(target) def post_install(target_installer)
end end
def podfile? def podfile?
......
module Pod
require 'colored'
class UserInterface
autoload :UIPod, 'cocoapods/user_interface/ui_pod'
@title_colors = %w|yellow green|
@title_level = 0
@indentation_level = 2
@treat_titles_as_messages = false
class << self
include Config::Mixin
attr_accessor :indentation_level, :title_level
# Prints a title taking an optional verbose prefix and
# a relative indentation valid for the UI action in the passed
# block.
#
# In verbose mode titles are printed with a color according
# to their level. In normal mode titles are printed only if
# they have nesting level smaller than 2.
#
# TODO: refactor to title (for always visible titles like search)
# and sections (titles that reppresent collapsible sections).
#
def section(title, verbose_prefix = '', relative_indentation = 0)
if config.verbose?
title(title, verbose_prefix, relative_indentation)
elsif title_level < 2
puts title
end
self.indentation_level += relative_indentation
self.title_level += 1
yield if block_given?
self.indentation_level -= relative_indentation
self.title_level -= 1
end
# A title oposed to a section is always visible
#
def title(title, verbose_prefix = '', relative_indentation = 2)
if(@treat_titles_as_messages)
message(title, verbose_prefix)
else
title = verbose_prefix + title if config.verbose?
title = "\n#{title}" if @title_level < 2
if (color = @title_colors[@title_level])
title = title.send(color)
end
puts "#{title}"
end
self.indentation_level += relative_indentation
self.title_level += 1
yield if block_given?
self.indentation_level -= relative_indentation
self.title_level -= 1
end
# def title(title, verbose_prefix = '', relative_indentation = 2)
# end
# Prints a verbose message taking an optional verbose prefix and
# a relative indentation valid for the UI action in the passed
# block.
#
# TODO: clean interface.
#
def message(message, verbose_prefix = '', relative_indentation = 2)
message = verbose_prefix + message if config.verbose?
puts_indented message if config.verbose?
self.indentation_level += relative_indentation
yield if block_given?
self.indentation_level -= relative_indentation
end
# Prints an info to the user. The info is always displayed.
# It respects the current indentation level only in verbose
# mode.
#
# Any title printed in the optional block is treated as a message.
#
def info(message)
indentation = config.verbose? ? self.indentation_level : 0
indented = wrap_string(message, " " * indentation)
puts(indented)
self.indentation_level += 2
@treat_titles_as_messages = true
yield if block_given?
@treat_titles_as_messages = false
self.indentation_level -= 2
end
# Prints an important message to the user.
#
# @param [String] message The message to print.
#
# return [void]
#
def notice(message)
puts("\n[!] #{message}".green)
end
# Prints an important warning to the user optionally followed by actions
# that the user should take.
#
# @param [String] message The message to print.
# @param [Actions] actions The actions that the user should take.
#
# return [void]
#
def warn(message, actions)
puts("\n[!] #{message}".yellow)
actions.each do |action|
indented = wrap_string(action, " - ")
puts(indented)
end
end
# Returns a string containing relative location of a path from the Podfile.
# The returned path is quoted. If the argument is nit it returns the
# empty string.
#
def path(pathname)
if pathname
"`./#{pathname.relative_path_from(config.project_podfile.dirname || Pathname.pwd)}'"
else
''
end
end
# Prints the textual repprensentation of a given set.
#
def pod(set, mode = :normal)
if mode == :name
puts_indented set.name
else
pod = UIPod.new(set)
title("\n-> #{pod.name} (#{pod.version})".green, '', 3) do
puts_indented pod.summary
labeled('Homepage', pod.homepage)
labeled('Source', pod.source_url)
labeled('Versions', pod.versions) unless set.versions.count == 1
if mode == :stats
labeled('Pushed', pod.github_last_activity)
labeled('Authors', pod.authors) if pod.authors =~ /,/
labeled('Author', pod.authors) if pod.authors !~ /,/
labeled('License', pod.license)
labeled('Platform', pod.platform)
labeled('Watchers', pod.github_watchers)
labeled('Forks', pod.github_forks)
end
labeled('Sub specs', pod.subspecs)
end
end
end
# Prints a message with a label.
#
def labeled(label, value)
if value
''.tap do |t|
t << " - #{label}:".ljust(16)
if value.is_a?(Array)
separator = "\n - "
puts_indented t << separator << value.join(separator)
else
puts_indented t << value.to_s << "\n"
end
end
end
end
# @!group Basic printing
# Prints a message unless config is silent.
#
def puts(message = '')
super(message) unless config.silent?
end
# Prints a message respecting the current indentation level and
# wrapping it to the terminal width if necessary.
#
def puts_indented(message = '')
indented = wrap_string(message, " " * self.indentation_level)
puts(indented)
end
private
# @!group Helpers
# Wraps a string taking into account the width of the terminal and an
# option indent. Adapted from http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/
#
# @param [String] txt The string to wrap
#
# @param [String] indent The string to use to indent the result.
#
# @return [String] The formatted string.
#
def wrap_string(txt, indent = '')
width = `stty size`.split(' ')[1].to_i - indent.length
txt.strip.gsub(/(.{1,#{width}})( +|$)\n?|(.{#{width}})/, indent + "\\1\\3\n")
end
end
end
UI = UserInterface
end
require 'active_support/core_ext/array/conversions'
module Pod
class UserInterface
class UIPod
attr_accessor :set
def initialize(set)
@set = set
end
# set information
def name
@set.name
end
def version
@set.versions.last
end
def versions
@set.versions.reverse.join(", ")
end
# specification information
def spec
@set.specification
end
def authors
spec.authors.keys.to_sentence
end
def homepage
spec.homepage
end
def description
spec.description
end
def summary
spec.summary
end
def source_url
spec.source.reject {|k,_| k == :commit || k == :tag }.values.first
end
def platform
spec.available_platforms.sort { |a,b| a.to_s.downcase <=> b.to_s.downcase }.join(' - ')
end
def license
spec.license[:type] if spec.license
end
# will return array of all subspecs (recursevly) or nil
def subspecs
(spec.recursive_subspecs.any? && spec.recursive_subspecs) || nil
end
# Statistics information
def creation_date
Pod::Specification::Statistics.instance.creation_date(@set)
end
def github_watchers
Pod::Specification::Statistics.instance.github_watchers(@set)
end
def github_forks
Pod::Specification::Statistics.instance.github_forks(@set)
end
def github_last_activity
distance_from_now_in_words(Pod::Specification::Statistics.instance.github_pushed_at(@set))
end
def ==(other)
self.class === other && @set == other.set
end
def eql?(other)
self.class === other && name.eql?(other.name)
end
def hash
name.hash
end
private
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
case distance_in_days
when 0..7
"less than a week ago"
when 8..29
"#{distance_in_days} days ago"
when 30..45
"1 month ago"
when 46..365
"#{(distance_in_days.to_f / 30).round} months ago"
else
"more than a year ago"
end
end
end
end
end
...@@ -31,7 +31,7 @@ describe "Pod::Command::List" do ...@@ -31,7 +31,7 @@ describe "Pod::Command::List" do
/MagicalRecord/, /MagicalRecord/,
/A2DynamicDelegate/, /A2DynamicDelegate/,
/\d+ pods were found/ /\d+ pods were found/
].each { |regex| list.output.should =~ regex } ].each { |regex| Pod::UI.output.should =~ regex }
end end
it "returns the new pods" do it "returns the new pods" do
...@@ -46,7 +46,7 @@ describe "Pod::Command::List" do ...@@ -46,7 +46,7 @@ describe "Pod::Command::List" do
'FileMD5Hash', 'FileMD5Hash',
'cocoa-oauth', 'cocoa-oauth',
'iRate' 'iRate'
].each {|s| list.output.should.include s } ].each {|s| Pod::UI.output.should.include s }
end end
end end
......
...@@ -67,8 +67,8 @@ describe Pod::Command::Push do ...@@ -67,8 +67,8 @@ describe Pod::Command::Push do
cmd.expects(:validate_podspec_files).returns(true) cmd.expects(:validate_podspec_files).returns(true)
Dir.chdir(temporary_directory) { cmd.run } Dir.chdir(temporary_directory) { cmd.run }
cmd.output.should.include('[Add] PushTest (1.4)') Pod::UI.output.should.include('[Add] PushTest (1.4)')
cmd.output.should.include('[Fix] JSONKit (1.4)') Pod::UI.output.should.include('[Fix] JSONKit (1.4)')
git('upstream', 'checkout test') # checkout because test because is it the branch used in the specs. git('upstream', 'checkout test') # checkout because test because is it the branch used in the specs.
(@upstream.dir + 'PushTest/1.4/PushTest.podspec').read.should.include('PushTest') (@upstream.dir + 'PushTest/1.4/PushTest.podspec').read.should.include('PushTest')
......
...@@ -57,7 +57,7 @@ describe "Pod::Command::Repo" do ...@@ -57,7 +57,7 @@ describe "Pod::Command::Repo" do
it "lints a repo" do it "lints a repo" do
cmd = command('repo', 'lint', 'master') cmd = command('repo', 'lint', 'master')
lambda { cmd.run }.should.raise Pod::Informative lambda { cmd.run }.should.raise Pod::Informative
cmd.output.should.include "Missing license type" Pod::UI.output.should.include "Missing license type"
end end
end end
...@@ -104,7 +104,7 @@ describe "Pod::Command::Repo" do ...@@ -104,7 +104,7 @@ describe "Pod::Command::Repo" do
write_version_file({'last' => "999.0.0"}) write_version_file({'last' => "999.0.0"})
cmd = command('repo', 'update') cmd = command('repo', 'update')
cmd.check_versions(versions_file.dirname) cmd.check_versions(versions_file.dirname)
cmd.output.should.include "Cocoapods 999.0.0 is available" Pod::UI.output.should.include "Cocoapods 999.0.0 is available"
end end
it "has a class method that returns if a repo is supported" do it "has a class method that returns if a repo is supported" do
......
...@@ -32,9 +32,9 @@ describe "Pod::Command::Setup" do ...@@ -32,9 +32,9 @@ describe "Pod::Command::Setup" do
it "creates the local spec-repos directory and creates a clone of the `master' repo" do it "creates the local spec-repos directory and creates a clone of the `master' repo" do
output = run_command('setup') output = run_command('setup')
git_config('master', 'remote.origin.url').should == fixture('spec-repos/master').to_s
output.should.include "Setup completed" output.should.include "Setup completed"
output.should.not.include "push" output.should.not.include "push"
git_config('master', 'remote.origin.url').should == fixture('spec-repos/master').to_s
end end
it "preserves push access for the `master' repo" do it "preserves push access for the `master' repo" do
...@@ -47,9 +47,8 @@ describe "Pod::Command::Setup" do ...@@ -47,9 +47,8 @@ describe "Pod::Command::Setup" do
it "can run if needed" do it "can run if needed" do
output = run_command('setup') output = run_command('setup')
output.should.include "Setup completed" output.should.include "Setup completed"
command = command('setup') Pod::UI.output = ''
command.run_if_needed command('setup').run_if_needed
command.output.should == nil Pod::UI.output.should == ''
end end
end end
...@@ -107,7 +107,7 @@ describe "Pod::Command::Spec#lint" do ...@@ -107,7 +107,7 @@ describe "Pod::Command::Spec#lint" do
Dir.chdir(fixture('spec-repos') + 'master/JSONKit/1.4/') do Dir.chdir(fixture('spec-repos') + 'master/JSONKit/1.4/') do
cmd = command('spec', 'lint', '--quick', '--only-errors') cmd = command('spec', 'lint', '--quick', '--only-errors')
cmd.run cmd.run
cmd.output.should.include "passed validation" Pod::UI.output.should.include "passed validation"
end end
end end
...@@ -129,12 +129,12 @@ describe "Pod::Command::Spec#lint" do ...@@ -129,12 +129,12 @@ describe "Pod::Command::Spec#lint" do
it "lints a givent podspec" do it "lints a givent podspec" do
cmd = command('spec', 'lint', '--quick', @spec_path) cmd = command('spec', 'lint', '--quick', @spec_path)
lambda { cmd.run }.should.raise Pod::Informative lambda { cmd.run }.should.raise Pod::Informative
cmd.output.should.include "Missing license type" Pod::UI.output.should.include "Missing license type"
end end
it "respects the -only--errors option" do it "respects the -only--errors option" do
cmd = command('spec', 'lint', '--quick', '--only-errors', @spec_path) cmd = command('spec', 'lint', '--quick', '--only-errors', @spec_path)
lambda { cmd.run }.should.not.raise lambda { cmd.run }.should.not.raise
cmd.output.should.include "Missing license type" Pod::UI.output.should.include "Missing license type"
end end
end end
require File.expand_path('../../../spec_helper', __FILE__) require File.expand_path('../../spec_helper', __FILE__)
require 'net/http' require 'net/http'
describe Pod::Command::Presenter do describe Pod::UI do
extend SpecHelper::Command
Presenter = Pod::Command::Presenter
before do before do
@set = Pod::Spec::Set.new(fixture('spec-repos/master/CocoaLumberjack')) @set = Pod::Spec::Set.new(fixture('spec-repos/master/CocoaLumberjack'))
...@@ -11,8 +10,8 @@ describe Pod::Command::Presenter do ...@@ -11,8 +10,8 @@ describe Pod::Command::Presenter do
end end
it "presents the name, version, description, homepage and source of a specification set" do it "presents the name, version, description, homepage and source of a specification set" do
presenter = Presenter.new(argv()) Pod::UI.pod(@set)
output = presenter.describe(@set) puts output = Pod::UI.output.gsub(/\n */,'')
output.should.include? 'CocoaLumberjack' output.should.include? 'CocoaLumberjack'
output.should.include? '1.0' output.should.include? '1.0'
output.should.include? '1.1' output.should.include? '1.1'
...@@ -24,8 +23,8 @@ describe Pod::Command::Presenter do ...@@ -24,8 +23,8 @@ describe Pod::Command::Presenter do
it "presents the stats of a specification set" do it "presents the stats of a specification set" do
repo = { "forks"=>42, "watchers"=>318, "pushed_at"=>"2011-01-26T19:06:43Z" } repo = { "forks"=>42, "watchers"=>318, "pushed_at"=>"2011-01-26T19:06:43Z" }
Octokit.expects(:repo).with("robbiehanson/CocoaLumberjack").returns(repo) Octokit.expects(:repo).with("robbiehanson/CocoaLumberjack").returns(repo)
presenter = Presenter.new(argv('--stats', '--no-color')) Pod::UI.pod(@set, :stats)
output = presenter.describe(@set) output = Pod::UI.output
output.should.include? 'Author: Robbie Hanson' output.should.include? 'Author: Robbie Hanson'
output.should.include? 'License: BSD' output.should.include? 'License: BSD'
output.should.include? 'Platform: iOS - OS X' output.should.include? 'Platform: iOS - OS X'
...@@ -35,8 +34,9 @@ describe Pod::Command::Presenter do ...@@ -35,8 +34,9 @@ describe Pod::Command::Presenter do
end end
it "should print at least one subspec" do it "should print at least one subspec" do
presenter = Presenter.new(argv()) @set = Pod::Spec::Set.new(fixture('spec-repos/master/RestKit'))
output = presenter.describe(Pod::Spec::Set.new(fixture('spec-repos/master/RestKit'))) Pod::UI.pod(@set)
output = Pod::UI.output
output.should.include? "RestKit/Network" output.should.include? "RestKit/Network"
end end
end end
......
...@@ -249,6 +249,22 @@ else ...@@ -249,6 +249,22 @@ else
FileUtils.cp_r(fixture('integration/.'), config.project_pods_root) FileUtils.cp_r(fixture('integration/.'), config.project_pods_root)
end end
it "runs the optional pre_install callback defined in the Podfile _before_ the targets are integrated but _after_ the pods have been downloaded" do
podfile = Pod::Podfile.new do
self.platform platform
xcodeproj 'dummy'
pod 'SSZipArchive', '0.1.0'
pre_install do |installer|
memo = "PODS:#{installer.pods * ', '} TARGETS:#{installer.project.targets.to_a * ', '}"
File.open(config.project_pods_root + 'memo.txt', 'w') {|f| f.puts memo}
end
end
resolver = Pod::Resolver.new(podfile, nil, Pod::Sandbox.new(config.project_pods_root))
SpecHelper::Installer.new(resolver).install!
File.open(config.project_pods_root + 'memo.txt','rb').read.should == "PODS:SSZipArchive (0.1.0) TARGETS:\n"
end
it "runs the optional post_install callback defined in the Podfile _before_ the project is saved to disk" do it "runs the optional post_install callback defined in the Podfile _before_ the project is saved to disk" do
podfile = Pod::Podfile.new do podfile = Pod::Podfile.new do
self.platform platform self.platform platform
......
...@@ -19,6 +19,7 @@ require 'spec_helper/github' ...@@ -19,6 +19,7 @@ require 'spec_helper/github'
require 'spec_helper/temporary_directory' require 'spec_helper/temporary_directory'
require 'spec_helper/temporary_repos' require 'spec_helper/temporary_repos'
require 'spec_helper/config' require 'spec_helper/config'
require 'spec_helper/user_interface'
module Bacon module Bacon
class Context class Context
......
require 'spec_helper/temporary_directory' require 'spec_helper/temporary_directory'
class Pod::Command
attr_accessor :output
def puts(msg = '') (@output ||= '') << "#{msg}\n" end
end
module SpecHelper module SpecHelper
module Command module Command
def command(*argv) def command(*argv)
...@@ -15,9 +9,21 @@ module SpecHelper ...@@ -15,9 +9,21 @@ module SpecHelper
def run_command(*args) def run_command(*args)
Dir.chdir(SpecHelper.temporary_directory) do Dir.chdir(SpecHelper.temporary_directory) do
command = command(*args) Pod::UI.output = ''
command.run
command.output # TODO: remove this once all cocoapods has
# been converted to use the UI.puts
config_silent = config.silent?
config.silent = false
# Very nasty behaviour where the relative increments are
# not reverted and lead to sections being collapsed and
# not being printed to the output.
Pod::UI.indentation_level = 0
Pod::UI.title_level = 0
command(*args).run
config.silent = config_silent
Pod::UI.output
end end
end end
end end
......
module Pod
class UI
@output = ''
class << self
attr_accessor :output
def puts(message = '')
@output << "#{message}"
end
end
end
end
...@@ -79,6 +79,16 @@ describe "Pod::Podfile" do ...@@ -79,6 +79,16 @@ describe "Pod::Podfile" do
Pod::Podfile.new { set_arc_compatibility_flag! }.should.set_arc_compatibility_flag Pod::Podfile.new { set_arc_compatibility_flag! }.should.set_arc_compatibility_flag
end end
it "stores a block that will be called with the Installer before the target integration" do
yielded = nil
Pod::Podfile.new do
pre_install do |installer|
yielded = installer
end
end.pre_install!(:an_installer)
yielded.should == :an_installer
end
it "stores a block that will be called with the Installer instance once installation is finished (but the project is not written to disk yet)" do it "stores a block that will be called with the Installer instance once installation is finished (but the project is not written to disk yet)" do
yielded = nil yielded = nil
Pod::Podfile.new do Pod::Podfile.new do
......
...@@ -107,11 +107,11 @@ describe "A Pod::Specification loaded from a podspec" do ...@@ -107,11 +107,11 @@ describe "A Pod::Specification loaded from a podspec" do
it "adds compiler flags if ARC is required" do it "adds compiler flags if ARC is required" do
@spec.parent.should == nil @spec.parent.should == nil
@spec.requires_arc = true @spec.requires_arc = true
@spec.activate_platform(:ios).compiler_flags.should == " -fobjc-arc" @spec.activate_platform(:ios).compiler_flags.should == "-fobjc-arc"
@spec.activate_platform(:osx).compiler_flags.should == " -fobjc-arc" @spec.activate_platform(:osx).compiler_flags.should == "-fobjc-arc"
@spec.compiler_flags = "-Wunused-value" @spec.compiler_flags = "-Wunused-value"
@spec.activate_platform(:ios).compiler_flags.should == " -fobjc-arc -Wunused-value" @spec.activate_platform(:ios).compiler_flags.should == "-Wunused-value -fobjc-arc"
@spec.activate_platform(:osx).compiler_flags.should == " -fobjc-arc -Wunused-value" @spec.activate_platform(:osx).compiler_flags.should == "-Wunused-value -fobjc-arc"
end end
end end
...@@ -334,9 +334,9 @@ describe "A Pod::Specification subspec" do ...@@ -334,9 +334,9 @@ describe "A Pod::Specification subspec" do
@spec.subspecs.first.parent.should == @spec @spec.subspecs.first.parent.should == @spec
end end
it "automatically forwards top level attributes to the top level parent" do it "automatically forwards top level attributes to the subspecs" do
@spec.activate_platform(:ios) @spec.activate_platform(:ios)
[:version, :license, :authors, :compiler_flags].each do |attr| [:version, :license, :authors].each do |attr|
@spec.subspecs.first.send(attr).should == @spec.send(attr) @spec.subspecs.first.send(attr).should == @spec.send(attr)
@spec.subspecs.first.subspecs.first.send(attr).should == @spec.send(attr) @spec.subspecs.first.subspecs.first.send(attr).should == @spec.send(attr)
end end
...@@ -350,7 +350,7 @@ describe "A Pod::Specification subspec" do ...@@ -350,7 +350,7 @@ describe "A Pod::Specification subspec" do
@subsubspec.resources.should == %w[ resource ] @subsubspec.resources.should == %w[ resource ]
@subsubspec.compiler_flags = '-Wdeprecated-implementations' @subsubspec.compiler_flags = '-Wdeprecated-implementations'
@subsubspec.compiler_flags.should == ' -fobjc-arc -Wdeprecated-implementations' @subsubspec.compiler_flags.should == '-Wdeprecated-implementations'
end end
it "allows to specify arc settings for subspecs" do it "allows to specify arc settings for subspecs" do
...@@ -523,7 +523,7 @@ describe "A Pod::Specification, concerning its attributes that support different ...@@ -523,7 +523,7 @@ describe "A Pod::Specification, concerning its attributes that support different
end end
it "returns the same list of compiler flags for each platform" do it "returns the same list of compiler flags for each platform" do
compiler_flags = ' -fobjc-arc -Wdeprecated-implementations' compiler_flags = '-Wdeprecated-implementations -fobjc-arc'
@spec.activate_platform(:ios).compiler_flags.should == compiler_flags @spec.activate_platform(:ios).compiler_flags.should == compiler_flags
@spec.activate_platform(:osx).compiler_flags.should == compiler_flags @spec.activate_platform(:osx).compiler_flags.should == compiler_flags
end end
...@@ -587,8 +587,8 @@ describe "A Pod::Specification, concerning its attributes that support different ...@@ -587,8 +587,8 @@ describe "A Pod::Specification, concerning its attributes that support different
end end
it "returns the same list of compiler flags for each platform" do it "returns the same list of compiler flags for each platform" do
@spec.activate_platform(:ios).compiler_flags.should == ' -fobjc-arc -Wdeprecated-implementations' @spec.activate_platform(:ios).compiler_flags.should == '-Wdeprecated-implementations -fobjc-arc'
@spec.activate_platform(:osx).compiler_flags.should == ' -fobjc-arc -Wfloat-equal' @spec.activate_platform(:osx).compiler_flags.should == '-Wfloat-equal -fobjc-arc'
end end
it "returns the same list of dependencies for each platform" do it "returns the same list of dependencies for each platform" do
......
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