Commit 01bc7727 authored by Fabio Pelosin's avatar Fabio Pelosin

[UserInterface] First attempt to extract UI Logic.

parent e9261526
## 0.15.0 (unreleased)
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/master...b0.15.0)
###### Enhancements
- Support for `header_mappings_dir` attribute in subspecs.
- Refactored UI.
## 0.14.0.rc2
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.14.0.rc1...0.14.0.rc2)
......
......@@ -41,6 +41,7 @@ module Pod
autoload :Source, 'cocoapods/source'
autoload :Spec, 'cocoapods/specification'
autoload :Specification, 'cocoapods/specification'
autoload :UserInterface, 'cocoapods/user_interface'
autoload :Version, 'cocoapods/version'
autoload :Pathname, 'pathname'
......
......@@ -7,30 +7,31 @@ module Pod
class Downloader
class Git < Downloader
include Config::Mixin
include UserInterface::Mixin
executable :git
MAX_CACHE_SIZE = 500
def download
create_cache unless cache_exist?
puts '-> Cloning git repo' if config.verbose?
if options[:tag]
download_tag
elsif options[:branch]
download_branch
elsif options[:commit]
download_commit
else
download_head
ui_title(' > Cloning git repo', '', 3) do
if options[:tag]
download_tag
elsif options[:branch]
download_branch
elsif options[:commit]
download_commit
else
download_head
end
Dir.chdir(target_path) { git! "submodule update --init" } if options[:submodules]
end
Dir.chdir(target_path) { git! "submodule update --init" } if options[:submodules]
prune_cache
end
def create_cache
puts "-> Creating cache git repo (#{cache_path})" if config.verbose?
ui_title " > Creating cache git repo (#{cache_path})"
cache_path.rmtree if cache_path.exist?
cache_path.mkpath
clone(url, cache_path)
......@@ -42,7 +43,7 @@ module Pod
repos = Pathname.new(caches_dir).children.select { |c| c.directory? }.sort_by(&:ctime)
while caches_size >= MAX_CACHE_SIZE && !repos.empty?
dir = repos.shift
puts '->'.yellow << " Removing git cache for `#{origin_url(dir)}'" if config.verbose?
ui_message "#{'->'.yellow} Removing git cache for `#{origin_url(dir)}'"
dir.rmtree
end
end
......@@ -74,7 +75,7 @@ module Pod
end
def update_cache
puts "-> Updating cache git repo (#{cache_path})" if config.verbose?
ui_title " > Updating cache git repo (#{cache_path})"
Dir.chdir(cache_path) do
git! "reset --hard HEAD"
git! "clean -d -x -f"
......@@ -138,7 +139,7 @@ module Pod
git! "remote add upstream '#{@url}'" # we need to add the original url, not the cache url
git! "fetch -q upstream" # refresh the branches
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
......
......@@ -16,9 +16,10 @@ module Pod
def download
@filename = filename_with_type type
@download_path = target_path + @filename
download_file @download_path
extract_with_type @download_path, type
ui_title(' > Downloading from HTTP', '', 3) do
download_file @download_path
extract_with_type @download_path, type
end
end
def type
......
......@@ -4,10 +4,12 @@ module Pod
executable :hg
def download
if options[:revision]
download_revision
else
download_head
ui_title(' > Cloning mercurial repo', '', 3) do
if options[:revision]
download_revision
else
download_head
end
end
end
......
......@@ -8,11 +8,15 @@ module Pod
end
def download
svn! %|export "#{reference_url}" "#{target_path}"|
ui_title(' > Exporting subversion repo', '', 3) do
svn! %|export "#{reference_url}" "#{target_path}"|
end
end
def download_head
svn! %|export "#{trunk_url}" "#{target_path}"|
ui_title(' > Exporting subversion repo', '', 3) do
svn! %|export "#{trunk_url}" "#{target_path}"|
end
end
def reference_url
......
......@@ -2,13 +2,17 @@ require 'open4'
module Pod
module Executable
class Indenter < ::Array
include UserInterface::Mixin
include Config::Mixin
attr_accessor :indent
attr_accessor :io
def initialize(io = nil, indent = ' ')
def initialize(io = nil)
@io = io
@indent = indent
@indent = ' ' * UserInterface.instance.indentation_level
end
def <<(value)
......@@ -19,6 +23,7 @@ module Pod
end
def executable(name)
include UserInterface::Mixin
bin = `which #{name}`.strip
base_method = "base_" << name.to_s
define_method(base_method) do |command, should_raise|
......@@ -27,20 +32,19 @@ module Pod
end
full_command = "#{bin} #{command}"
if Config.instance.verbose?
puts " $ #{full_command}"
ui_message("$ #{full_command}")
stdout, stderr = Indenter.new(STDOUT), Indenter.new(STDERR)
else
stdout, stderr = Indenter.new, Indenter.new
end
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?
unless status.success?
if should_raise
raise Informative, "#{name} #{command}\n\n#{output}"
else
puts((Config.instance.verbose? ? ' ' : '') << "[!] Failed: #{full_command}".red) unless Config.instance.silent?
ui_message("[!] Failed: #{full_command}".red)
end
end
output
......
......@@ -6,6 +6,7 @@ module Pod
autoload :UserProjectIntegrator, 'cocoapods/installer/user_project_integrator'
include Config::Mixin
include UserInterface::Mixin
attr_reader :resolver, :sandbox, :lockfile
......@@ -49,23 +50,21 @@ module Pod
def install_dependencies!
pods.sort_by { |pod| pod.top_specification.name.downcase }.each do |pod|
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
unless pod.downloaded?
pod.implode
download_pod(pod)
ui_title("Installing #{pod}".green, "-> ".green) do
unless pod.downloaded?
pod.implode
download_pod(pod)
end
# The docs need to be generated before cleaning because the
# documentation is created for all the subspecs.
generate_docs(pod)
# Here we clean pod's that just have been downloaded or have been
# pre-downloaded in AbstractExternalSource#specification_from_sandbox.
pod.clean! if config.clean?
end
# The docs need to be generated before cleaning because the
# documentation is created for all the subspecs.
generate_docs(pod)
# Here we clean pod's that just have been downloaded or have been
# pre-downloaded in AbstractExternalSource#specification_from_sandbox.
pod.clean! if config.clean?
else
ui_title("Using #{pod}", "-> ".green)
end
end
end
......@@ -89,10 +88,10 @@ module Pod
def generate_docs(pod)
doc_generator = Generator::Documentation.new(pod)
if ( config.generate_docs? && !doc_generator.already_installed? )
puts "-> Installing documentation" if config.verbose?
ui_title " > Installing documentation"
doc_generator.generate(config.doc_install?)
else
puts "-> Using existing documentation" if config.verbose?
ui_title " > Using existing documentation"
end
end
......@@ -100,47 +99,46 @@ module Pod
#
def remove_deleted_dependencies!
resolver.removed_pods.each do |pod_name|
marker = config.verbose ? "\n-> ".red : ''
path = sandbox.root + pod_name
puts marker << "Removing #{pod_name}".red
path.rmtree if path.exist?
ui_title("Removing #{pod_name}", "-> ".red) do
path = sandbox.root + pod_name
path.rmtree if path.exist?
end
end
end
def install!
@sandbox.prepare_for_install
ui_title "Resolving dependencies of `#{@podfile.defined_in_file}'" do
specs_by_target
end
print_title "Resolving dependencies of: #{@podfile.defined_in_file}"
specs_by_target
print_title "Removing deleted dependencies" unless resolver.removed_pods.empty?
remove_deleted_dependencies!
print_title "Installing dependencies"
install_dependencies!
ui_title "Removing deleted dependencies" do
remove_deleted_dependencies!
end unless resolver.removed_pods.empty?
print_title("Generating support files\n", false)
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)
ui_title "Installing dependencies" do
install_dependencies!
end
puts "- Running post install hooks" if config.verbose?
# Post install hooks run _before_ saving of project, so that they can alter it before saving.
run_post_install_hooks
ui_title("Generating support files", '', 2) do
generate_target_support_files
ui_message "- Running post install hooks" do
# Post install hooks run _before_ saving of project, so that they can alter it before saving.
run_post_install_hooks
end
puts "- Writing Xcode project file to `#{@sandbox.project_path}'" if config.verbose?
project.save_as(@sandbox.project_path)
ui_message "- Writing Xcode project file to `#{@sandbox.project_path}'" do
project.save_as(@sandbox.project_path)
end
puts "- Writing lockfile in `#{config.project_lockfile}'\n\n" if config.verbose?
@lockfile = Lockfile.generate(@podfile, specs_by_target.values.flatten)
@lockfile.write_to_disk(config.project_lockfile)
ui_message "- Writing lockfile in `#{config.project_lockfile}'" do
@lockfile = Lockfile.generate(@podfile, specs_by_target.values.flatten)
@lockfile.write_to_disk(config.project_lockfile)
end
UserProjectIntegrator.new(@podfile).integrate! if config.integrate_targets?
UserProjectIntegrator.new(@podfile).integrate! if config.integrate_targets?
end
end
def run_post_install_hooks
......@@ -155,6 +153,17 @@ module Pod
@podfile.post_install!(self)
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)
class_name_identifier = target_installer.target_definition.label
dummy_source = Generator::DummySource.new(class_name_identifier)
......@@ -198,15 +207,5 @@ module Pod
end
result
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
......@@ -2,6 +2,7 @@ module Pod
class Installer
class TargetInstaller
include Config::Mixin
include UserInterface::Mixin
attr_reader :podfile, :project, :target_definition, :target
attr_accessor :requires_arc
......@@ -97,20 +98,24 @@ module Pod
end
def create_files(pods, sandbox)
if @podfile.generate_bridge_support?
bridge_support_metadata_path = sandbox.root + @target_definition.bridge_support_name
puts "- Generating BridgeSupport metadata file at `#{bridge_support_metadata_path}'" if config.verbose?
bridge_support_metadata_path = sandbox.root + @target_definition.bridge_support_name
ui_message "- Generating BridgeSupport metadata file at `#{bridge_support_metadata_path}'" do
bridge_support_generator_for(pods, sandbox).save_as(bridge_support_metadata_path)
copy_resources_script_for(pods).resources << @target_definition.bridge_support_name
end if @podfile.generate_bridge_support?
ui_message "- Generating xcconfig file at `#{sandbox.root + @target_definition.xcconfig_name}'" do
xcconfig.save_as(sandbox.root + @target_definition.xcconfig_name)
@target_definition.xcconfig = xcconfig
end
ui_message "- Generating prefix header at `#{sandbox.root + @target_definition.prefix_header_name}'" do
save_prefix_header_as(sandbox.root + @target_definition.prefix_header_name, pods)
end
ui_message "- Generating copy resources script at `#{sandbox.root + @target_definition.copy_resources_script_name}'" do
copy_resources_script_for(pods).save_as(sandbox.root + @target_definition.copy_resources_script_name)
end
puts "- Generating xcconfig file at `#{sandbox.root + @target_definition.xcconfig_name}'" if config.verbose?
xcconfig.save_as(sandbox.root + @target_definition.xcconfig_name)
@target_definition.xcconfig = xcconfig
puts "- Generating prefix header at `#{sandbox.root + @target_definition.prefix_header_name}'" if config.verbose?
save_prefix_header_as(sandbox.root + @target_definition.prefix_header_name, pods)
puts "- Generating copy resources script at `#{sandbox.root + @target_definition.copy_resources_script_name}'" if config.verbose?
copy_resources_script_for(pods).save_as(sandbox.root + @target_definition.copy_resources_script_name)
end
private
......
......@@ -3,6 +3,7 @@ require 'colored'
module Pod
class Resolver
include Config::Mixin
include UserInterface::Mixin
# @return [Bool] Whether the resolver should find the pods to install or
# the pods to update.
......@@ -66,36 +67,26 @@ module Pod
@specs_by_target = {}
@pods_from_external_sources = []
@pods_to_lock = []
@log_indent = 0
if @lockfile
puts "\nFinding added, modified or removed dependencies:".green if config.verbose?
@pods_by_state = @lockfile.detect_changes_with_podfile(podfile)
if config.verbose?
ui_title "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|
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|
puts " #{mark} " << pod_name
ui_message("#{marks[symbol]} #{pod_name}", '',2)
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
end
@podfile.target_definitions.values.each do |target_definition|
puts "\nResolving dependencies for target `#{target_definition.name}' (#{target_definition.platform}):".green if config.verbose?
@loaded_specs = []
find_dependency_specs(@podfile, target_definition.dependencies, target_definition)
@specs_by_target[target_definition] = @cached_specs.values_at(*@loaded_specs).sort_by(&:name)
ui_title "Resolving dependencies for target `#{target_definition.name}' (#{target_definition.platform}):" do
@loaded_specs = []
find_dependency_specs(@podfile, target_definition.dependencies, target_definition)
@specs_by_target[target_definition] = @cached_specs.values_at(*@loaded_specs).sort_by(&:name)
end
end
@cached_specs.values.sort_by(&:name)
......@@ -187,32 +178,30 @@ module Pod
# @return [void]
#
def find_dependency_specs(dependent_specification, dependencies, target_definition)
@log_indent += 1
dependencies.each do |dependency|
# Replace the dependency with a more specific one if the pod is already installed.
if !update_mode && @pods_to_lock.include?(dependency.name)
dependency = lockfile.dependency_for_installed_pod_named(dependency.name)
end
puts ' ' * @log_indent + "- #{dependency}" if config.verbose?
set = find_cached_set(dependency, target_definition.platform)
set.required_by(dependency, dependent_specification.to_s)
# Ensure we don't resolve the same spec twice for one target
unless @loaded_specs.include?(dependency.name)
spec = set.specification_by_name(dependency.name)
@pods_from_external_sources << spec.pod_name if dependency.external?
@loaded_specs << spec.name
@cached_specs[spec.name] = spec
# Configure the specification
spec.activate_platform(target_definition.platform)
spec.version.head = dependency.head?
# And recursively load the dependencies of the spec.
find_dependency_specs(spec, spec.dependencies, target_definition) if spec.dependencies
ui_message("- #{dependency}", '', 2) do
set = find_cached_set(dependency, target_definition.platform)
set.required_by(dependency, dependent_specification.to_s)
# Ensure we don't resolve the same spec twice for one target
unless @loaded_specs.include?(dependency.name)
spec = set.specification_by_name(dependency.name)
@pods_from_external_sources << spec.pod_name if dependency.external?
@loaded_specs << spec.name
@cached_specs[spec.name] = spec
# Configure the specification
spec.activate_platform(target_definition.platform)
spec.version.head = dependency.head?
# And recursively load the dependencies of the spec.
find_dependency_specs(spec, spec.dependencies, target_definition) if spec.dependencies
end
validate_platform(spec || @cached_specs[dependency.name], target_definition)
end
validate_platform(spec || @cached_specs[dependency.name], target_definition)
end
@log_indent -= 1
end
# Ensures that a spec is compatible with platform of a target.
......
module Pod
class UserInterface
include Config::Mixin
def self.instance
@instance ||= new
end
def initialize
@indentation_level = 0
@title_level = 0
@title_colors = %w|yellow green|
end
attr_accessor :indentation_level, :title_level
def title(title, verbose_prefix = '')
if config.verbose?
title = "\n#{title}" if @title_level < 2
title = verbose_prefix + title if config.verbose?
if (color = @title_colors[@title_level])
title = title.send(color)
end
puts "#{title}"
elsif title_level < 2
puts title
end
end
def message(message, verbose_prefix = '')
message = verbose_prefix + message if config.verbose?
puts_indented message if config.verbose?
end
def puts(message)
super(message) unless config.silent?
end
def puts_indented(message)
indented = wrap_string(message, " " * indentation_level)
puts(indented)
end
# adapted from http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/
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
module Mixin
def ui_title(title, verbose_prefix = '', relative_indentation = 0)
UserInterface.instance.title(title)
UserInterface.instance.indentation_level += relative_indentation
UserInterface.instance.title_level += 1
yield if block_given?
UserInterface.instance.indentation_level -= relative_indentation
UserInterface.instance.title_level -= 1
end
def ui_message(message, verbose_prefix = '', relative_indentation = 0)
UserInterface.instance.indentation_level += relative_indentation
UserInterface.instance.message(message)
yield if block_given?
UserInterface.instance.indentation_level -= relative_indentation
end
def ui_verbose(message)
UserInterface.instance.puts(message)
end
# def ui_progress_start(count)
# end
# def ui_progress_increase(message = nil, ammount = 1)
# end
# def ui_progress_complete()
# 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