Commit 76cb703e authored by Fabio Pelosin's avatar Fabio Pelosin

[UI] Adoption in Pod::Command classes.

parent 9aeeb74f
...@@ -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
......
...@@ -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,7 +145,7 @@ module Pod ...@@ -145,7 +145,7 @@ module Pod
def update_spec_repos_if_necessary! def update_spec_repos_if_necessary!
if @update_repo if @update_repo
UI.title 'Updating Spec Repositories' do UI.section 'Updating Spec Repositories' do
Repo.new(ARGV.new(["update"])).run Repo.new(ARGV.new(["update"])).run
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 #{d == 1 ? 'day' : "#{d} days"}".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,20 +36,19 @@ module Pod ...@@ -36,20 +36,19 @@ 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
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
...@@ -71,7 +70,7 @@ module Pod ...@@ -71,7 +70,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
...@@ -82,7 +81,7 @@ module Pod ...@@ -82,7 +81,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)
...@@ -93,7 +92,7 @@ module Pod ...@@ -93,7 +92,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,7 +56,7 @@ module Pod ...@@ -56,7 +56,7 @@ module Pod
end end
def add def add
UI.title ("Cloning spec repo `#{@name}' from `#{@url}'#{" (branch `#{@branch}')" if @branch}") do 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
...@@ -67,7 +67,7 @@ module Pod ...@@ -67,7 +67,7 @@ module Pod
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|
UI.title "Updating spec repo `#{dir.basename}'" do 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?
...@@ -89,7 +89,7 @@ module Pod ...@@ -89,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
...@@ -111,19 +111,19 @@ module Pod ...@@ -111,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
...@@ -132,7 +132,7 @@ module Pod ...@@ -132,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)
...@@ -144,7 +144,7 @@ module Pod ...@@ -144,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
UI.title "Setting up CocoaPods master repo" do 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
...@@ -104,7 +104,7 @@ module Pod ...@@ -104,7 +104,7 @@ module Pod
`chmod +x '#{hook}'` `chmod +x '#{hook}'`
end end
end end
UI.title "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
......
...@@ -14,7 +14,7 @@ module Pod ...@@ -14,7 +14,7 @@ module Pod
def download def download
create_cache unless cache_exist? create_cache unless cache_exist?
UI.title(' > Cloning git repo', '', 3) do UI.section(' > Cloning git repo', '', 3) do
if options[:tag] if options[:tag]
download_tag download_tag
elsif options[:branch] elsif options[:branch]
...@@ -30,7 +30,7 @@ module Pod ...@@ -30,7 +30,7 @@ module Pod
end end
def create_cache def create_cache
UI.title " > Creating cache git repo (#{cache_path})" UI.section " > Creating cache git repo (#{cache_path})"
cache_path.rmtree if cache_path.exist? cache_path.rmtree if cache_path.exist?
cache_path.mkpath cache_path.mkpath
git! %Q|clone --mirror "#{url}" "#{cache_path}"| git! %Q|clone --mirror "#{url}" "#{cache_path}"|
...@@ -74,7 +74,7 @@ module Pod ...@@ -74,7 +74,7 @@ module Pod
end end
def update_cache def update_cache
UI.title " > Updating cache git repo (#{cache_path})" UI.section " > Updating cache git repo (#{cache_path})"
Dir.chdir(cache_path) do Dir.chdir(cache_path) do
if git("config core.bare").chomp == "true" if git("config core.bare").chomp == "true"
git! "remote update" git! "remote update"
......
...@@ -16,7 +16,7 @@ module Pod ...@@ -16,7 +16,7 @@ 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.title(' > Downloading from HTTP', '', 3) do 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
......
...@@ -4,7 +4,7 @@ module Pod ...@@ -4,7 +4,7 @@ module Pod
executable :hg executable :hg
def download def download
UI.title(' > Cloning mercurial repo', '', 3) do UI.section(' > Cloning mercurial repo', '', 3) do
if options[:revision] if options[:revision]
download_revision download_revision
else else
......
...@@ -8,13 +8,13 @@ module Pod ...@@ -8,13 +8,13 @@ module Pod
end end
def download def download
UI.title(' > Exporting subversion repo', '', 3) do UI.section(' > Exporting subversion repo', '', 3) do
svn! %|export "#{reference_url}" "#{target_path}"| svn! %|export "#{reference_url}" "#{target_path}"|
end end
end end
def download_head def download_head
UI.title(' > Exporting subversion repo', '', 3) do UI.section(' > Exporting subversion repo', '', 3) do
svn! %|export "#{trunk_url}" "#{target_path}"| svn! %|export "#{trunk_url}" "#{target_path}"|
end end
end end
......
...@@ -50,7 +50,7 @@ module Pod ...@@ -50,7 +50,7 @@ module Pod
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?
if should_install if should_install
UI.title("Installing #{pod}".green, "-> ".green) do UI.section("Installing #{pod}".green, "-> ".green) do
unless pod.downloaded? unless pod.downloaded?
pod.implode pod.implode
download_pod(pod) download_pod(pod)
...@@ -63,7 +63,7 @@ module Pod ...@@ -63,7 +63,7 @@ module Pod
pod.clean! if config.clean? pod.clean! if config.clean?
end end
else else
UI.title("Using #{pod}", "-> ".green) UI.section("Using #{pod}", "-> ".green)
end end
end end
end end
...@@ -87,10 +87,10 @@ module Pod ...@@ -87,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? )
UI.title " > Installing documentation" UI.section " > Installing documentation"
doc_generator.generate(config.doc_install?) doc_generator.generate(config.doc_install?)
else else
UI.title " > Using existing documentation" UI.section " > Using existing documentation"
end end
end end
...@@ -98,7 +98,7 @@ module Pod ...@@ -98,7 +98,7 @@ module Pod
# #
def remove_deleted_dependencies! def remove_deleted_dependencies!
resolver.removed_pods.each do |pod_name| resolver.removed_pods.each do |pod_name|
UI.title("Removing #{pod_name}", "-> ".red) do UI.section("Removing #{pod_name}", "-> ".red) do
path = sandbox.root + pod_name path = sandbox.root + pod_name
path.rmtree if path.exist? path.rmtree if path.exist?
end end
...@@ -107,19 +107,19 @@ module Pod ...@@ -107,19 +107,19 @@ module Pod
def install! def install!
@sandbox.prepare_for_install @sandbox.prepare_for_install
UI.title "Resolving dependencies of #{UI.path @podfile.defined_in_file}" do UI.section "Resolving dependencies of #{UI.path @podfile.defined_in_file}" do
specs_by_target specs_by_target
end end
UI.title "Removing deleted dependencies" do UI.section "Removing deleted dependencies" do
remove_deleted_dependencies! remove_deleted_dependencies!
end unless resolver.removed_pods.empty? end unless resolver.removed_pods.empty?
UI.title "Downloading dependencies" do UI.section "Downloading dependencies" do
install_dependencies! install_dependencies!
end end
UI.title "Generating support files" do UI.section "Generating support files" do
UI.message "- Running pre install hooks" do UI.message "- Running pre install hooks" do
run_pre_install_hooks run_pre_install_hooks
end end
......
...@@ -69,7 +69,7 @@ module Pod ...@@ -69,7 +69,7 @@ module Pod
if @lockfile if @lockfile
@pods_by_state = @lockfile.detect_changes_with_podfile(podfile) @pods_by_state = @lockfile.detect_changes_with_podfile(podfile)
UI.title "Finding added, modified or removed dependencies:" do UI.section "Finding added, modified or removed dependencies:" do
marks = {:added => "A".green, :changed => "M".yellow, :removed => "R".red, :unchanged => "-" } 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|
pod_names.each do |pod_name| pod_names.each do |pod_name|
...@@ -81,7 +81,7 @@ module Pod ...@@ -81,7 +81,7 @@ module Pod
end end
@podfile.target_definitions.values.each do |target_definition| @podfile.target_definitions.values.each do |target_definition|
UI.title "Resolving dependencies for target `#{target_definition.name}' (#{target_definition.platform}):" do 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)
......
module Pod module Pod
require 'colored'
class UserInterface class UserInterface
autoload :UIPod, 'cocoapods/user_interface/ui_pod'
@indentation_level = 0 @indentation_level = 0
@title_level = 0 @title_level = 0
@title_colors = %w|yellow green| @title_colors = %w|yellow green|
...@@ -9,17 +13,40 @@ module Pod ...@@ -9,17 +13,40 @@ module Pod
attr_accessor :indentation_level, :title_level attr_accessor :indentation_level, :title_level
def title(title, verbose_prefix = '', relative_indentation = 2) # 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 = 2)
if config.verbose? 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)
title = verbose_prefix + title if config.verbose? title = verbose_prefix + title if config.verbose?
title = "\n#{title}" if @title_level < 2 title = "\n#{title}" if @title_level < 2
if (color = @title_colors[@title_level]) if (color = @title_colors[@title_level])
title = title.send(color) title = title.send(color)
end end
puts "#{title}" puts "#{title}"
elsif title_level < 2
puts title
end
self.indentation_level += relative_indentation self.indentation_level += relative_indentation
self.title_level += 1 self.title_level += 1
...@@ -28,6 +55,15 @@ module Pod ...@@ -28,6 +55,15 @@ module Pod
self.title_level -= 1 self.title_level -= 1
end 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) def message(message, verbose_prefix = '', relative_indentation = 2)
message = verbose_prefix + message if config.verbose? message = verbose_prefix + message if config.verbose?
puts_indented message if config.verbose? puts_indented message if config.verbose?
...@@ -37,15 +73,24 @@ module Pod ...@@ -37,15 +73,24 @@ module Pod
self.indentation_level -= relative_indentation self.indentation_level -= relative_indentation
end end
def puts(message) # Prints a message unless config is silent.
#
def puts(message = '')
super(message) unless config.silent? super(message) unless config.silent?
end end
def puts_indented(message) # Prints a message respecting the current indentation level and
indented = wrap_string(message, " " * indentation_level) # wrapping it to the termina width if necessary.
#
def puts_indented(message = '')
indented = wrap_string(message, " " * self.indentation_level)
puts(indented) 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) def path(pathname)
if pathname if pathname
"`./#{pathname.relative_path_from(config.project_podfile.dirname || Pathname.pwd)}'" "`./#{pathname.relative_path_from(config.project_podfile.dirname || Pathname.pwd)}'"
...@@ -54,8 +99,52 @@ module Pod ...@@ -54,8 +99,52 @@ module Pod
end end
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
# Wraps a string with a given indent to the width of the terminal.
# adapted from http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/ # adapted from http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/
def wrap_string(txt, indent) #
def wrap_string(txt, indent = '')
width = `stty size`.split(' ')[1].to_i - indent.length width = `stty size`.split(' ')[1].to_i - indent.length
txt.strip.gsub(/(.{1,#{width}})( +|$)\n?|(.{#{width}})/, indent + "\\1\\3\n") txt.strip.gsub(/(.{1,#{width}})( +|$)\n?|(.{#{width}})/, indent + "\\1\\3\n")
end 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
......
...@@ -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) output = Pod::UI.output
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
......
...@@ -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
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