Commit 65221133 authored by Fabio Pelosin's avatar Fabio Pelosin

[LocalPod] Cluster specifications.

parent 3364111c
......@@ -26,7 +26,7 @@ module Pod
return @project if @project
@project = Pod::Project.new
@project.user_build_configurations = @podfile.user_build_configurations
activated_pods.each do |pod|
pods.each do |pod|
# Add all source files to the project grouped by pod
group = @project.add_pod_group(pod.name)
pod.source_files.each do |path|
......@@ -45,24 +45,24 @@ module Pod
end
def install_dependencies!
activated_pods.each do |pod|
marker = config.verbose ? "\n-> ".green : ''
unless should_install = !pod.exists? && !pod.specification.local?
puts marker + "Using #{pod}" unless config.silent?
else
puts marker + "Installing #{pod.specification}".green unless config.silent?
pods.each do |pod|
unless config.silent?
marker = config.verbose ? "\n-> ".green : ''
puts pod.exists? ? "#{marker}Using #{pod}" : "#{marker}Installing #{pod}".green
submarker = " " * marker.length << " - "
puts "#{submarker}#{pod.subspecs.map{ |s| s.name.gsub(pod.specification.name+'/', '') }.join("\n" << submarker)}" unless pod.subspecs.empty?
end
unless pod.exists?
downloader = Downloader.for_pod(pod)
downloader.download
if config.clean
downloader.clean
pod.clean
end
end
if (should_install && config.generate_docs?) || config.force_doc?
if (!pod.exists? && config.generate_docs?) || config.force_doc?
doc_generator = Generator::Documentation.new(pod)
if doc_generator.already_installed?
puts "Using Existing Documentation for #{pod.specification}".green if config.verbose?
......@@ -83,14 +83,13 @@ module Pod
print_title "Installing dependencies"
install_dependencies!
pods = activated_pods
print_title("Generating support files\n", false)
target_installers.each do |target_installer|
pods_for_target = activated_pods_by_target[target_installer.target_definition]
pods_for_target = pods_by_target[target_installer.target_definition]
target_installer.install!(pods_for_target, @sandbox)
end
generate_lock_file!(pods)
generate_lock_file!(specifications)
generate_dummy_source
puts "* Running post install hooks" if config.verbose?
......@@ -107,7 +106,7 @@ module Pod
# we loop over target installers instead of pods, because we yield the target installer
# to the spec post install hook.
target_installers.each do |target_installer|
activated_specifications_for_target(target_installer.target_definition).each do |spec|
specs_by_target[target_installer.target_definition].each do |spec|
spec.post_install(target_installer)
end
end
......@@ -115,28 +114,28 @@ module Pod
@podfile.post_install!(self)
end
def generate_lock_file!(pods)
def generate_lock_file!(specs)
lock_file.open('w') do |file|
file.puts "PODS:"
# Get list of [name, dependencies] pairs.
activated_pods = pods.map do |pod|
[pod.specification.to_s, pod.dependencies.map(&:to_s).sort]
pod_and_deps = specs.map do |spec|
[spec.to_s, spec.dependencies.map(&:to_s).sort]
end.uniq
# Merge dependencies of ios and osx version of the same pod.
tmp = {}
activated_pods.each do |name, deps|
pod_and_deps.each do |name, deps|
if tmp[name]
tmp[name].concat(deps).uniq!
else
tmp[name] = deps
end
end
activated_pods = tmp
pod_and_deps = tmp
# Sort by name and print
activated_pods.sort_by(&:first).each do |name, deps|
pod_and_deps.sort_by(&:first).each do |name, deps|
if deps.empty?
file.puts " - #{name}"
else
......@@ -171,40 +170,36 @@ module Pod
end
# @return [Array<Specification>] All dependencies that have been resolved.
def dependency_specifications
def specifications
specs_by_target.values.flatten
end
# @return [Array<LocalPod>] A list of LocalPod instances for each
# dependency that is not a download-only one.
def activated_pods
activated_pods_by_target.values.flatten
def pods
pods_by_target.values.flatten
end
def activated_pods_by_target
def pods_by_target
@pods_by_spec = {}
result = {}
specs_by_target.each do |target_definition, specs|
@pods_by_spec[target_definition.platform] = {}
result[target_definition] = specs.map do |spec|
LocalPod.new(spec, @sandbox, target_definition.platform)
end.compact
pod = pod_for_spec(spec, target_definition.platform)
pod.add_specification(spec)
pod
end.uniq.compact
end
result
end
# @return [Array<Specification>] A list of specifications for each
# dependency that is not a download-only
# one.
def activated_specifications
dependency_specifications
end
def activated_specifications_for_target(target_definition)
specs_by_target[target_definition]
def pod_for_spec(spec, platform)
@pods_by_spec[platform][spec.top_level_parent.name] ||= LocalPod.new(spec.top_level_parent, @sandbox, platform)
end
private
def print_title(title, only_verbose = true)
if config.verbose?
puts "\n" + title.yellow
......
module Pod
class LocalPod
attr_reader :specification
attr_reader :top_specification, :specifications
# TODO: fix accross the app
alias :specification :top_specification
attr_reader :sandbox
def initialize(specification, sandbox, platform)
@specification, @sandbox = specification, sandbox
@specification.activate_platform(platform)
@top_specification, @sandbox = specification, sandbox
@top_specification.activate_platform(platform)
@specifications = [] << specification
end
def self.from_podspec(podspec, sandbox, platform)
......@@ -13,23 +16,32 @@ module Pod
end
def root
@sandbox.root + specification.name
@sandbox.root + top_specification.name
end
# Adding specifications is idempotent
def add_specification(spec)
raise Informative, "[Local Pod] Attempt to add a specification from another pod" unless spec.top_level_parent == top_specification
spec.activate_platform(platform)
@specifications << spec unless @specifications.include?(spec)
end
def subspecs
specifications.reject{|s| s.parent.nil? }
end
def to_s
if specification.local?
"#{specification} [LOCAL]"
else
specification.to_s
end
result = top_specification.to_s
# result << " [LOCAL]" if top_specification.local?
result
end
def name
specification.name
top_specification.name
end
def platform
specification.active_platform
top_specification.active_platform
end
def create
......@@ -50,29 +62,31 @@ module Pod
end
def clean
clean_paths.each { |path| FileUtils.rm_rf(path) }
# TODO: nuke everything that is not used
# clean_paths.each { |path| FileUtils.rm_rf(path) }
end
def prefix_header_file
if prefix_header = specification.prefix_header_file
@sandbox.root + specification.name + prefix_header
if prefix_header = top_specification.prefix_header_file
@sandbox.root + top_specification.name + prefix_header
end
end
def source_files
expanded_paths(specification.source_files, :glob => '*.{h,m,mm,c,cpp}', :relative_to_sandbox => true)
chained_expanded_paths(:source_files, :glob => '*.{h,m,mm,c,cpp}', :relative_to_sandbox => true)
end
def absolute_source_files
expanded_paths(specification.source_files, :glob => '*.{h,m,mm,c,cpp}')
chained_expanded_paths(:source_files, :glob => '*.{h,m,mm,c,cpp}')
end
def clean_paths
expanded_paths(specification.clean_paths)
# TODO: delete
# chained_expanded_paths(:clean_paths)
end
def resources
expanded_paths(specification.resources, :relative_to_sandbox => true)
chained_expanded_paths(:resources, :relative_to_sandbox => true)
end
def header_files
......@@ -85,6 +99,15 @@ module Pod
end
end
def readme_file
expanded_paths('README.*', options = {})
end
def license
#TODO: merge with the work of will and return the text
expanded_paths(%w[ LICENSE licence.txt ], options = {})
end
def add_to_target(target)
implementation_files.each do |file|
target.add_source_file(file, nil, specification.compiler_flags.strip)
......@@ -120,6 +143,10 @@ module Pod
end
end
def chained_expanded_paths(accessor, options = {})
specifications.map { |s| expanded_paths(s.send(accessor), options) }.compact.reduce(:+).uniq
end
def expanded_paths(patterns, options = {})
patterns.map do |pattern|
pattern = root + pattern
......
......@@ -320,7 +320,7 @@ else
installer = SpecHelper::Installer.new(spec)
target_definition = installer.target_installers.first.target_definition
installer.activated_specifications_for_target(target_definition).first.resources = 'LICEN*', 'Readme.*'
installer.specs_by_target[target_definition].first.resources = 'LICEN*', 'Readme.*'
installer.install!
contents = (config.project_pods_root + 'Pods-resources.sh').read
......
......@@ -42,7 +42,7 @@ describe "Pod::Installer" do
dependency 'ASIHTTPRequest'
end
installer = Pod::Installer.new(podfile)
pods = installer.activated_specifications.map do |spec|
pods = installer.specifications.map do |spec|
Pod::LocalPod.new(spec, installer.sandbox, podfile.target_definitions[:default].platform)
end
expected = pods.map { |pod| pod.header_files }.flatten.map { |header| config.project_pods_root + header }
......
......@@ -3,75 +3,75 @@ require File.expand_path('../../spec_helper', __FILE__)
describe Pod::LocalPod do
# a LocalPod represents a local copy of the dependency, inside the pod root, built from a spec
before do
@sandbox = temporary_sandbox
@pod = Pod::LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), @sandbox, Pod::Platform.new(:ios))
copy_fixture_to_pod('banana-lib', @pod)
end
it 'returns the Pod root directory path' do
@pod.root.should == @sandbox.root + 'BananaLib'
end
it "creates it's own root directory if it doesn't exist" do
@pod.create
File.directory?(@pod.root).should.be.true
end
it "can execute a block within the context of it's root" do
@pod.chdir { FileUtils.touch("foo") }
Pathname(@pod.root + "foo").should.exist
end
it 'can delete itself' do
@pod.create
@pod.implode
@pod.root.should.not.exist
end
it 'returns an expanded list of source files, relative to the sandbox root' do
@pod.source_files.sort.should == [
Pathname.new("BananaLib/Classes/Banana.m"),
Pathname.new("BananaLib/Classes/Banana.h")
].sort
end
it 'returns an expanded list of absolute clean paths' do
xit 'returns an expanded list of absolute clean paths' do
@pod.clean_paths.should == [@sandbox.root + "BananaLib/sub-dir"]
end
it 'returns an expanded list of resources, relative to the sandbox root' do
@pod.resources.should == [Pathname.new("BananaLib/Resources/logo-sidebar.png")]
end
it 'returns a list of header files' do
@pod.header_files.should == [Pathname.new("BananaLib/Classes/Banana.h")]
end
it 'can clean up after itself' do
xit 'can clean up after itself' do
@pod.clean_paths.tap do |paths|
@pod.clean
paths.each do |path|
path.should.not.exist
end
end
end
it "can link it's headers into the sandbox" do
@pod.link_headers
expected_header_path = @sandbox.headers_root + "BananaLib/Banana.h"
expected_header_path.should.be.symlink
File.read(expected_header_path).should == (@sandbox.root + @pod.header_files[0]).read
end
it "can add it's source files to an Xcode project target" do
target = mock('target')
target.expects(:add_source_file).with(Pathname.new("BananaLib/Classes/Banana.m"), anything, anything)
@pod.add_to_target(target)
end
it "can add it's source files to a target with any specially configured compiler flags" do
@pod.specification.compiler_flags = '-d some_flag'
target = mock('target')
......
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