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,25 +145,10 @@ module Pod ...@@ -145,25 +145,10 @@ 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 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 end
......
...@@ -14,7 +14,10 @@ module Pod ...@@ -14,7 +14,10 @@ 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
...@@ -22,15 +25,15 @@ module Pod ...@@ -22,15 +25,15 @@ module Pod
def initialize(argv) def initialize(argv)
@update = argv.option('--update') @update = argv.option('--update')
@stats = argv.option('--stats')
@new = argv.option('new') @new = argv.option('new')
@presenter = Presenter.new(argv)
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,7 +89,7 @@ module Pod ...@@ -89,7 +89,7 @@ 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
...@@ -103,7 +103,8 @@ module Pod ...@@ -103,7 +103,8 @@ module Pod
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
print_subtitle "Setup completed (#{push? ? "push" : "read-only"} access)" end
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,7 +193,7 @@ module Pod ...@@ -193,7 +193,7 @@ 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)
...@@ -203,6 +203,7 @@ module Pod ...@@ -203,6 +203,7 @@ module Pod
local_pod.downloaded = true local_pod.downloaded = true
end end
end end
end
def description def description
"from `#{@params[:git]}'".tap do |description| "from `#{@params[:git]}'".tap do |description|
...@@ -216,11 +217,12 @@ module Pod ...@@ -216,11 +217,12 @@ 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
"from `#{@params[:podspec]}'" "from `#{@params[:podspec]}'"
......
...@@ -7,14 +7,14 @@ module Pod ...@@ -7,14 +7,14 @@ 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]
...@@ -24,16 +24,16 @@ module Pod ...@@ -24,16 +24,16 @@ module Pod
else else
download_head download_head
end end
Dir.chdir(target_path) { git! "submodule update --init" } if options[:submodules] Dir.chdir(target_path) { git! "submodule update --init" } if options[:submodules]
end
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,15 +74,19 @@ module Pod ...@@ -74,15 +74,19 @@ 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
if git("config core.bare").chomp == "true"
git! "remote update"
else
git! "reset --hard HEAD" git! "reset --hard HEAD"
git! "clean -d -x -f" git! "clean -d -x -f"
git! "pull origin master" git! "pull origin master"
git! "fetch"
git! "fetch --tags" git! "fetch --tags"
end end
end end
end
end
def ref_exists?(ref) def ref_exists?(ref)
Dir.chdir(cache_path) { git "rev-list --max-count=1 #{ref}" } Dir.chdir(cache_path) { git "rev-list --max-count=1 #{ref}" }
...@@ -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,14 +148,16 @@ module Pod ...@@ -144,14 +148,16 @@ 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)
UI.section(" > Cloning to Pods folder",'',1) do
git! %Q|clone "#{from}" "#{to}"| git! %Q|clone "#{from}" "#{to}"|
end end
end end
end
class GitHub < Git class GitHub < Git
def download_head def download_head
......
...@@ -16,10 +16,11 @@ module Pod ...@@ -16,10 +16,11 @@ 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
options[:type] || type_with_url(url) options[:type] || type_with_url(url)
......
...@@ -4,12 +4,14 @@ module Pod ...@@ -4,12 +4,14 @@ module Pod
executable :hg executable :hg
def download def download
UI.section(' > Cloning mercurial repo', '', 3) do
if options[:revision] if options[:revision]
download_revision download_revision
else else
download_head download_head
end end
end end
end
def download_head def download_head
hg! "clone \"#{url}\" \"#{target_path}\"" hg! "clone \"#{url}\" \"#{target_path}\""
......
...@@ -8,12 +8,16 @@ module Pod ...@@ -8,12 +8,16 @@ module Pod
end end
def download def download
UI.section(' > Exporting subversion repo', '', 3) do
svn! %|export "#{reference_url}" "#{target_path}"| svn! %|export "#{reference_url}" "#{target_path}"|
end end
end
def download_head def download_head
UI.section(' > Exporting subversion repo', '', 3) do
svn! %|export "#{trunk_url}" "#{target_path}"| svn! %|export "#{trunk_url}" "#{target_path}"|
end end
end
def reference_url def reference_url
result = url.dup result = url.dup
......
...@@ -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,13 +49,8 @@ module Pod ...@@ -49,13 +49,8 @@ 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
UI.section("Installing #{pod}".green, "-> ".green) do
unless pod.downloaded? unless pod.downloaded?
pod.implode pod.implode
download_pod(pod) download_pod(pod)
...@@ -67,6 +62,9 @@ module Pod ...@@ -67,6 +62,9 @@ module Pod
# pre-downloaded in AbstractExternalSource#specification_from_sandbox. # pre-downloaded in AbstractExternalSource#specification_from_sandbox.
pod.clean! if config.clean? pod.clean! if config.clean?
end end
else
UI.section("Using #{pod}", "-> ".green)
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,49 +98,63 @@ module Pod ...@@ -100,49 +98,63 @@ 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
print_title "Resolving dependencies of: #{@podfile.defined_in_file}"
specs_by_target specs_by_target
end
print_title "Removing deleted dependencies" unless resolver.removed_pods.empty? UI.section "Removing deleted dependencies" do
remove_deleted_dependencies! remove_deleted_dependencies!
end unless resolver.removed_pods.empty?
print_title "Installing dependencies" UI.section "Downloading dependencies" do
install_dependencies! install_dependencies!
end
print_title("Generating support files\n", false) UI.section "Generating support files" do
target_installers.each do |target_installer| UI.message "- Running pre install hooks" do
pods_for_target = pods_by_target[target_installer.target_definition] run_pre_install_hooks
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
puts "- Running post install hooks" if config.verbose? UI.message"- Installing targets" do
generate_target_support_files
end
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
puts "- Writing Xcode project file to `#{@sandbox.project_path}'" if config.verbose? UI.message "- Writing Xcode project file to #{UI.path @sandbox.project_path}" do
project.save_as(@sandbox.project_path) project.save_as(@sandbox.project_path)
end
puts "- Writing lockfile in `#{config.project_lockfile}'\n\n" if config.verbose? UI.message "- Writing lockfile in #{UI.path config.project_lockfile}" do
@lockfile = Lockfile.generate(@podfile, specs_by_target.values.flatten) @lockfile = Lockfile.generate(@podfile, specs_by_target.values.flatten)
@lockfile.write_to_disk(config.project_lockfile) @lockfile.write_to_disk(config.project_lockfile)
end
end
UserProjectIntegrator.new(@podfile).integrate! if config.integrate_targets? UserProjectIntegrator.new(@podfile).integrate! if config.integrate_targets?
end end
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
def run_post_install_hooks def run_post_install_hooks
# we loop over target installers instead of pods, because we yield the target installer # we loop over target installers instead of pods, because we yield the target installer
# to the spec post install hook. # to the spec post install hook.
...@@ -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,21 +97,25 @@ module Pod ...@@ -97,21 +97,25 @@ 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
puts "- Generating BridgeSupport metadata file at `#{bridge_support_metadata_path}'" if config.verbose? UI.message "- Generating BridgeSupport metadata file at #{UI.path bridge_support_metadata_path}" do
bridge_support_generator_for(pods, sandbox).save_as(bridge_support_metadata_path) bridge_support_generator_for(pods, sandbox).save_as(bridge_support_metadata_path)
copy_resources_script_for(pods).resources << @target_definition.bridge_support_name copy_resources_script_for(pods).resources << @target_definition.bridge_support_name
end end if @podfile.generate_bridge_support?
puts "- Generating xcconfig file at `#{sandbox.root + @target_definition.xcconfig_name}'" if config.verbose?
UI.message "- Generating xcconfig file at #{UI.path(sandbox.root + @target_definition.xcconfig_name)}" do
xcconfig.save_as(sandbox.root + @target_definition.xcconfig_name) xcconfig.save_as(sandbox.root + @target_definition.xcconfig_name)
@target_definition.xcconfig = xcconfig @target_definition.xcconfig = xcconfig
end
puts "- Generating prefix header at `#{sandbox.root + @target_definition.prefix_header_name}'" if config.verbose? 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) 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? 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) copy_resources_script_for(pods).save_as(sandbox.root + @target_definition.copy_resources_script_name)
end 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
end
add_xcconfig_base_configuration add_xcconfig_base_configuration
add_pods_library add_pods_library
add_copy_resources_script_phase add_copy_resources_script_phase
user_project.save_as(@target_definition.user_project.path) user_project.save_as(@target_definition.user_project.path)
end 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(' - ')}]"
puts "\n[!] The target `#{name}' overrides the `#{key}' build setting defined in `#{@target_definition.xcconfig_relative_path}'.".yellow actions = [ "Use the `$(inherited)' flag, or", "Remove the build settings from the target." ]
puts " - Use the `$(inherited)' flag, or" UI.warn("The target `#{name}' overrides the `#{key}' build setting defined in `#{@target_definition.xcconfig_relative_path}'.", actions)
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,37 +66,27 @@ module Pod ...@@ -66,37 +66,27 @@ 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)
@specs_by_target @specs_by_target
...@@ -187,14 +177,12 @@ module Pod ...@@ -187,14 +177,12 @@ 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)
...@@ -212,7 +200,7 @@ module Pod ...@@ -212,7 +200,7 @@ module Pod
end end
validate_platform(spec || @cached_specs[dependency.name], target_definition) validate_platform(spec || @cached_specs[dependency.name], target_definition)
end end
@log_indent -= 1 end
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=
# #
...@@ -288,16 +291,12 @@ module Pod ...@@ -288,16 +291,12 @@ 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. platform_attr_writer :header_mappings_dir, lambda { |file, _| Pathname.new(file) }
# pltf_first_defined_attr_reader :header_mappings_dir
# @note If no value is provided it returns an empty {Pathname}.
#
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 compiler_flags def recursive_compiler_flags
if @parent @parent ? @parent.recursive_compiler_flags | @compiler_flags[active_platform] : @compiler_flags[active_platform]
flags = [@parent.compiler_flags]
else
flags = [requires_arc ? ' -fobjc-arc' : '']
end end
(flags + @compiler_flags[active_platform].clone).join(' ')
def compiler_flags
flags = recursive_compiler_flags.dup
flags << '-fobjc-arc' if requires_arc
flags.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