Commit da6c6e67 authored by Fabio Pelosin's avatar Fabio Pelosin

[Generators] Update for changes in architecture.

parent ae9e56a8
...@@ -4,57 +4,155 @@ require 'active_support/core_ext/array/conversions' ...@@ -4,57 +4,155 @@ require 'active_support/core_ext/array/conversions'
module Pod module Pod
module Generator module Generator
# Generates the documentation for a Pod with the appledoc tool.
#
class Documentation class Documentation
extend Executable
extend Executable
executable :appledoc executable :appledoc
attr_reader :pod, :specification, :target_path, :options
def initialize(pod) attr_reader :sandbox
@pod = pod attr_reader :specification
@specification = pod.top_specification attr_reader :path_list
@target_path = pod.sandbox.root + 'Documentation' + pod.name
@options = @specification.documentation || {} def initialize(sandbox, specification, path_list)
@sandbox = sandbox
@specification = specification.root
@path_list = path_list
end
DOC_SETS_PATH = "~/Library/Developer/Shared/Documentation/DocSets"
# @return [Bool] Whether the documentation for the current Pod is already
# installed in the system.
#
def already_installed?
index = spec_appledoc_options.index('--company-id')
company_id = index ? spec_appledoc_options[index + 1] : docs_id
docset_path = DOC_SETS_PATH + "/#{company_id}.#{name.gsub(/ /,'-')}.docset"
Pathname.new(File.expand_path(docset_path)).exist?
end end
# Generates and optionally installs the documentation for the current
# Pod.
#
# @param [Bool] install_docset
# Whether the documentation should also be installed in Xcode.
#
# @note As the documentation is once per Pod to speed up the
# installation process it is generate for all the specs
# (including those not currently used). For this reason it is
# important that the documentation is generated before cleaning a
# Pod installation.
#
# @todo Passing the files explicitly clutters output and chokes on very
# long list (AWSiOSSDK). It is possible to just pass the dir of
# the pod, however this would include other files like demo
# projects.
#
# @return [void]
#
def generate(install_docset)
if `which appledoc`.strip.empty?
UI.warn "[!] Skipping documentation generation because appledoc can't be found.",
actions = [], verbose_only = true
return
end
target_path.mkpath
Dir.chdir(pod_root) do
appledoc apple_doc_command_line_arguments(install_docset)
end
if $?.exitstatus != 0
UI.warn "[!] Appledoc encountered an error (exitstatus: #{$?.exitstatus}), an update might be available to solve the issue."
end
end
#-----------------------------------------------------------------------#
public
# !@group Docset information.
# @return [String] The name of the docset
#
def name def name
@specification.name + ' ' + @specification.version.to_s specification.name + ' ' + specification.version.to_s
end end
# @return [String] The company of the docset.
#
# @todo Set to CocoaPods?
#
def company def company
if @specification.authors if specification.authors
@specification.authors.keys.sort.to_sentence specification.authors.keys.sort.to_sentence
else else
'no-company' 'no-company'
end end
end end
# @return [String] The copyright of the docset.
#
def copyright def copyright
company company
end end
# @return [String] The description of the docset.
#
def description def description
@specification.description || 'Generated by CocoaPods.' specification.summary || specification.description || 'Generated by CocoaPods.'
end end
# @return [String] The id of the docset.
#
def docs_id def docs_id
'org.cocoapods' 'org.cocoapods'
end end
def files #-----------------------------------------------------------------------#
@pod.documentation_headers.map{ |f| f.relative_path_from(@pod.root).to_s }
public
# !@group Paths.
# @return [Array<String>] the list of the headers to process
# with the appledoc tool.
#
def public_headers
absolute_paths = file_accessors.map(&:public_headers).flatten.uniq
absolute_paths.map { |f| f.relative_path_from(pod_root).to_s }
end end
# @return [String] the path of the file to use ad index of the
# documentation relative to the root of the Pod.
#
def index_file def index_file
@pod.readme_file.relative_path_from(@pod.root).to_s if @pod.readme_file readme_file = file_accessors.first.readme
readme_file.relative_path_from(pod_root).to_s if readme_file
end end
#-----------------------------------------------------------------------#
public
# !@group Appledoc options.
# @return [Array<String>] The list of the appledoc options followed by
# their value as defined in the specification.
#
def spec_appledoc_options def spec_appledoc_options
@options[:appledoc] || [] return unless specification.documentation
specification.documentation[:appledoc]
end end
# @return [Array<String>] The list of the appledoc options followed by
# their value.
#
# @note The appledoc tool terminates with an exits status of 1 if a # @note The appledoc tool terminates with an exits status of 1 if a
# warning was logged # warning was logged (see `--exit-threshold` option).
# #
def appledoc_options def appledoc_options
options = [ options = [
...@@ -73,39 +171,48 @@ module Pod ...@@ -73,39 +171,48 @@ module Pod
options += spec_appledoc_options options += spec_appledoc_options
end end
def already_installed? # @return [String] the arguments to pass to the appledoc command line
index = spec_appledoc_options.index('--company-id') # tool, properly escaped.
company_id = index ? spec_appledoc_options[index + 1] : docs_id #
Pathname.new(File.expand_path("~/Library/Developer/Shared/Documentation/DocSets/#{company_id}.#{name.gsub(/ /,'-')}.docset")).exist? # @param [Bool] install_docset
# Whether the documentation should also be installed in Xcode.
#
def apple_doc_command_line_arguments(install_docset)
arguments = appledoc_options
arguments += ['--output', target_path.to_s]
arguments += install_docset ? ['--create-docset'] : ['--no-create-docset']
arguments += public_headers
Escape.shell_command(arguments)
end end
# @todo passing the files explicitly clutters output and chokes on very #-----------------------------------------------------------------------#
# long list (AWSiOSSDK). It is possible to just pass the dir of
# the pod, however this would include other files like demo
# projects.
#
def generate(install = false)
if `which appledoc`.strip.empty?
UI.warn "[!] Skipping documentation generation because appledoc can't be found.",
actions = [], verbose_only = true
return
end
options = appledoc_options private
options += ['--output', @target_path.to_s]
options += install ? ['--create-docset'] : ['--no-create-docset']
options += files
@target_path.mkpath # !@group Private Helpers
@pod.chdir do
appledoc Escape.shell_command(options)
end
if $?.exitstatus != 0 def target_path
UI.warn "[!] Appledoc encountered an error (exitstatus: #{$?.exitstatus}), an update might be available to solve the issue." sandbox.root + 'Documentation' + specification.name
end end
def pod_root
path_list.root
end
def file_accessors
return @file_accessors if @file_accessors
@file_accessors = []
all_specs = [specification, *specification.subspecs]
all_specs.each do |spec|
spec.available_platforms.each do |platform|
accessor = Sandbox::FileAccessor.new(path_list, spec.consumer(platform))
@file_accessors << accessor
end
end
@file_accessors
end end
end end
end end
end end
...@@ -12,24 +12,25 @@ module Pod ...@@ -12,24 +12,25 @@ module Pod
# @return [Platform] the platform for which the prefix header will be # @return [Platform] the platform for which the prefix header will be
# generated. # generated.
# #
attr_reader :file_accessors
attr_reader :platform attr_reader :platform
# @return [Array<LocalPod>] the LocalPod for the target for which the # @return [Array<LocalPod>] the LocalPod for the target for which the
# prefix header needs to be generated. # prefix header needs to be generated.
# #
attr_reader :pods # attr_reader :consumers
# @return [Array<String>] any header to import (with quotes). # @return [Array<String>] any header to import (with quotes).
# #
attr_reader :imports attr_reader :imports
# @param [Platform] platform @see platform # @param [Platform] platform @see platform
# @param [Array<LocalPod>] pods @see pods # @param [Array<LocalPod>] consumers @see consumers
# #
def initialize(platform, pods) def initialize(file_accessors, platform)
@file_accessors = file_accessors
@platform = platform @platform = platform
@pods = pods @imports = []
@imports = []
end end
# Generates the contents of the prefix header according to the platform # Generates the contents of the prefix header according to the platform
...@@ -52,13 +53,14 @@ module Pod ...@@ -52,13 +53,14 @@ module Pod
result << %|\n#import "#{import}"| result << %|\n#import "#{import}"|
end end
pods.each do |pod| file_accessors.each do |file_accessor|
result << "\n" result << "\n"
if prefix_header_contents = pod.top_specification.consumer(platform).prefix_header_contents if prefix_header_contents = file_accessor.spec_consumer.prefix_header_contents
result << prefix_header_contents result << prefix_header_contents
result << "\n" result << "\n"
elsif prefix_header = pod.prefix_header_file end
result << prefix_header.read if prefix_header = file_accessor.prefix_header
result << Pathname(prefix_header).read
end end
end end
result result
...@@ -74,6 +76,7 @@ module Pod ...@@ -74,6 +76,7 @@ module Pod
def save_as(path) def save_as(path)
path.open('w') { |header| header.write(generate) } path.open('w') { |header| header.write(generate) }
end end
end end
end end
end end
...@@ -10,9 +10,10 @@ module Pod ...@@ -10,9 +10,10 @@ module Pod
# #
attr_reader :sandbox attr_reader :sandbox
# @return [Array<LocalPod>] the list of LocalPods for the library. # @return [Array<Specification::Consumer>] the consumers for the
# specifications of the library which needs the xcconfig.
# #
attr_reader :pods attr_reader :spec_consumers
# @return [String] the relative path of the Pods root respect the user # @return [String] the relative path of the Pods root respect the user
# project that should be integrated by this library. # project that should be integrated by this library.
...@@ -23,9 +24,9 @@ module Pod ...@@ -23,9 +24,9 @@ module Pod
# @param [Array<LocalPod>] pods @see pods # @param [Array<LocalPod>] pods @see pods
# @param [String] relative_pods_root @see relative_pods_root # @param [String] relative_pods_root @see relative_pods_root
# #
def initialize(sandbox, pods, relative_pods_root) def initialize(sandbox, spec_consumers, relative_pods_root)
@sandbox = sandbox @sandbox = sandbox
@pods = pods @spec_consumers = spec_consumers
@relative_pods_root = relative_pods_root @relative_pods_root = relative_pods_root
end end
...@@ -45,7 +46,7 @@ module Pod ...@@ -45,7 +46,7 @@ module Pod
# #
def generate def generate
ld_flags = '-ObjC' ld_flags = '-ObjC'
if set_arc_compatibility_flag && pods.map(&:specifications).flatten.any? { |pod| pod.requires_arc } if set_arc_compatibility_flag && spec_consumers.any? { |consumer| consumer.requires_arc }
ld_flags << ' -fobjc-arc' ld_flags << ' -fobjc-arc'
end end
...@@ -58,7 +59,7 @@ module Pod ...@@ -58,7 +59,7 @@ module Pod
'PODS_BUILD_HEADERS_SEARCH_PATHS' => quote(sandbox.build_headers.search_paths), 'PODS_BUILD_HEADERS_SEARCH_PATHS' => quote(sandbox.build_headers.search_paths),
'PODS_PUBLIC_HEADERS_SEARCH_PATHS' => quote(sandbox.public_headers.search_paths), 'PODS_PUBLIC_HEADERS_SEARCH_PATHS' => quote(sandbox.public_headers.search_paths),
}) })
pods.each { |pod| @xcconfig.merge!(pod.xcconfig) } spec_consumers.each { |consumers| @xcconfig.merge!(consumers.xcconfig) }
@xcconfig @xcconfig
end end
......
require File.expand_path('../../../spec_helper', __FILE__) require File.expand_path('../../../spec_helper', __FILE__)
describe Pod::Generator::Documentation do module Pod
before do describe Generator::Documentation do
@sandbox = temporary_sandbox before do
@pod = Pod::LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), @sandbox, Pod::Platform.ios) sandbox = config.sandbox
copy_fixture_to_pod('banana-lib', @pod) spec = fixture_spec('banana-lib/BananaLib.podspec')
@doc_installer = Pod::Generator::Documentation.new(@pod) root = fixture('banana-lib')
end path_list = Sandbox::PathList.new(root)
@doc_installer = Generator::Documentation.new(sandbox, spec, path_list)
it 'returns reads correctly the Pod documentation' do end
@doc_installer.options.should == {
:html => 'http://banana-corp.local/banana-lib/docs.html',
:appledoc => [
'--project-company', 'Banana Corp',
'--company-id', 'com.banana',
]
}
end
it 'returns the Pod documentation header files' do
@doc_installer.files.sort.should == %w[ Classes/Banana.h ].sort
end
it 'returns the Pod documentation options' do it 'returns the Pod documentation header files' do
@doc_installer.appledoc_options.should == [ @doc_installer.public_headers.sort.should == %w[ Classes/Banana.h ].sort
'--project-name', 'BananaLib 1.0', end
'--docset-desc', 'Full of chunky bananas.',
'--project-company', 'Banana Corp and Monkey Boy',
'--docset-copyright', 'Banana Corp and Monkey Boy',
'--company-id', 'org.cocoapods',
'--ignore', '.m',
'--keep-undocumented-objects',
'--keep-undocumented-members',
'--keep-intermediate-files',
'--exit-threshold', '2',
'--index-desc', 'README',
'--project-company', 'Banana Corp',
'--company-id', 'com.banana'
]
end
if !`which appledoc`.strip.empty? it 'returns the Pod documentation options' do
before do expected = [
@doc_installer.generate '--project-name', 'BananaLib 1.0',
'--docset-desc', 'Chunky bananas!',
'--project-company', 'Banana Corp and Monkey Boy',
'--docset-copyright', 'Banana Corp and Monkey Boy',
'--company-id', 'org.cocoapods',
'--ignore', '.m',
'--keep-undocumented-objects',
'--keep-undocumented-members',
'--keep-intermediate-files',
'--exit-threshold', '2',
'--index-desc', 'README',
'--project-company', 'Banana Corp',
'--company-id', 'com.banana'
]
options = @doc_installer.appledoc_options
expected.each do |expected_option|
options.should.include?(expected_option)
end
end end
after do it "returns the command line arguments to pass to the appledoc tool" do
@sandbox.implode arguments = @doc_installer.apple_doc_command_line_arguments(install_docset=false)
arguments.should.include?("--project-name 'BananaLib 1.0' ")
arguments.should.include?(" --docset-desc 'Chunky bananas!' ")
arguments.should.include?(" --project-company 'Banana Corp and Monkey Boy' ")
arguments.should.include?(" --docset-copyright 'Banana Corp and Monkey Boy' ")
arguments.should.include?(" --company-id org.cocoapods ")
arguments.should.include?(" --ignore .m ")
arguments.should.include?(" --keep-undocumented-objects ")
arguments.should.include?(" --keep-undocumented-members ")
arguments.should.include?(" --keep-intermediate-files ")
arguments.should.include?(" --exit-threshold 2 ")
arguments.should.include?(" --index-desc README ")
arguments.should.include?(" --project-company 'Banana Corp' ")
arguments.should.include?(" --company-id com.banana ")
# arguments.should.include?(" --output tmp/Pods/Documentation/BananaLib ")
arguments.should.include?(" --no-create-docset Classes/Banana.h")
arguments.should.include?(" Classes/Banana.h")
end end
it 'creates the html' do #-------------------------------------------------------------------------#
File.directory?(@sandbox.root + "Documentation/BananaLib/html").should.be.true
index = (@sandbox.root + 'Documentation/BananaLib/html/index.html').read if !`which appledoc`.strip.empty?
index.should.include?('BananaObj')
index = (@sandbox.root + 'Documentation/BananaLib/html/Classes/BananaObj.html').read describe "Appledoc integration" do
index.should.include?('Bananas are cool') before do
@doc_installer.generate(false)
end
it 'creates the html' do
docs_path = config.sandbox.root + "Documentation/BananaLib/html"
docs_path.should.exist
(docs_path + 'index.html').read.should.include?('BananaObj')
(docs_path + 'Classes/BananaObj.html').read.should.include?('Bananas are cool')
end
end
else
puts "[!] Skipping documentation generation specs, because appledoc can't be found."
end end
else
puts "[!] Skipping documentation generation specs, because appledoc can't be found."
end end
end
end
require File.expand_path('../../../spec_helper', __FILE__) require File.expand_path('../../../spec_helper', __FILE__)
describe PrefixHeader = Pod::Generator::PrefixHeader do module Pod
describe PrefixHeader = Generator::PrefixHeader do
before do
platform = Pod::Platform.ios before do
specification = fixture_spec('banana-lib/BananaLib.podspec') file_accessor = fixture_file_accessor('banana-lib/BananaLib.podspec')
@pod = Pod::LocalPod.new(specification, nil, platform) @spec = file_accessor.spec
pods = [ @pod ] @gen = PrefixHeader.new([file_accessor], Platform.ios)
@gen = PrefixHeader.new(platform, pods) end
@pod.stubs(:root).returns(Pathname.new(fixture('banana-lib'))) it "includes the contents of the specification's prefix header" do
end @spec.prefix_header_contents = '#import "BlocksKit.h"'
@spec.prefix_header_file = nil
it "includes the contents of the specification's prefix header" do @gen.generate.should == <<-EOS.strip_heredoc
spec = @pod.top_specification
spec.prefix_header_contents = '#import "BlocksKit.h"'
@gen.generate.should == <<-EOS.strip_heredoc
#ifdef __OBJC__ #ifdef __OBJC__
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#endif #endif
#import "BlocksKit.h" #import "BlocksKit.h"
EOS EOS
end end
it "includes the contents of the specification's prefix header file" do it "includes the contents of the specification's prefix header file" do
@gen.generate.should == <<-EOS.strip_heredoc @gen.generate.should == <<-EOS.strip_heredoc
#ifdef __OBJC__ #ifdef __OBJC__
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#endif #endif
#import <BananaTree/BananaTree.h> #import <BananaTree/BananaTree.h>
EOS EOS
end end
it "includes the imports" do it "includes the imports" do
@gen.imports << "header.h" @gen.imports << "header.h"
@gen.generate.should == <<-EOS.strip_heredoc @gen.generate.should == <<-EOS.strip_heredoc
#ifdef __OBJC__ #ifdef __OBJC__
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#endif #endif
#import "header.h" #import "header.h"
#import <BananaTree/BananaTree.h> #import <BananaTree/BananaTree.h>
EOS EOS
end end
it "prefers the inline specification of the prefix header contents" do it "imports UIKit in iOS platforms" do
spec = @pod.top_specification @gen.stubs(:platform).returns(Pod::Platform.ios)
spec.prefix_header_contents = '#import "BlocksKit.h"' @gen.generate.should.include?('#import <UIKit/UIKit.h>')
@pod.prefix_header_file.should.be.not.nil end
@gen.generate.should == <<-EOS.strip_heredoc
#ifdef __OBJC__ it "imports Cocoa for OS X platforms" do
#import <UIKit/UIKit.h> @gen.stubs(:platform).returns(Pod::Platform.osx)
#endif @gen.generate.should.include?('#import <Cocoa/Cocoa.h>')
end
#import "BlocksKit.h"
EOS it "writes the prefix header file to the disk" do
end path = temporary_directory + 'Test.pch'
@gen.save_as(path)
it "imports UIKit in iOS platforms" do path.read.should == <<-EOS.strip_heredoc
@gen.stubs(:platform).returns(Pod::Platform.ios)
@gen.generate.should.include?('#import <UIKit/UIKit.h>')
end
it "imports Cocoa for OS X platforms" do
@gen.stubs(:platform).returns(Pod::Platform.osx)
@gen.generate.should.include?('#import <Cocoa/Cocoa.h>')
end
it "writes the prefix header file to the disk" do
path = temporary_directory + 'Test.pch'
@gen.save_as(path)
path.read.should == <<-EOS.strip_heredoc
#ifdef __OBJC__ #ifdef __OBJC__
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#endif #endif
#import <BananaTree/BananaTree.h> #import <BananaTree/BananaTree.h>
EOS EOS
end
end end
end end
...@@ -3,9 +3,9 @@ require File.expand_path('../../../spec_helper', __FILE__) ...@@ -3,9 +3,9 @@ require File.expand_path('../../../spec_helper', __FILE__)
module Pod module Pod
describe Generator::XCConfig do describe Generator::XCConfig do
before do before do
specification = fixture_spec('banana-lib/BananaLib.podspec') @spec = fixture_spec('banana-lib/BananaLib.podspec')
@pod = Pod::LocalPod.new(specification, config.sandbox, :ios) @consumer = @spec.consumer(:ios)
@generator = Generator::XCConfig.new(config.sandbox, [@pod], './Pods') @generator = Generator::XCConfig.new(config.sandbox, [@consumer], './Pods')
end end
...@@ -14,7 +14,7 @@ module Pod ...@@ -14,7 +14,7 @@ module Pod
end end
it "returns the pods" do it "returns the pods" do
@generator.pods.should == [@pod] names = @generator.spec_consumers.should == [@consumer]
end end
it "returns the path of the pods root relative to the user project" do it "returns the path of the pods root relative to the user project" do
...@@ -45,7 +45,7 @@ module Pod ...@@ -45,7 +45,7 @@ module Pod
it 'adds the -fobjc-arc to OTHER_LDFLAGS if any pods require arc (to support non-ARC projects on iOS 4.0)' do it 'adds the -fobjc-arc to OTHER_LDFLAGS if any pods require arc (to support non-ARC projects on iOS 4.0)' do
@generator.set_arc_compatibility_flag = true @generator.set_arc_compatibility_flag = true
@pod.top_specification.stubs(:requires_arc).returns(true) @consumer.stubs(:requires_arc).returns(true)
@xcconfig = @generator.generate @xcconfig = @generator.generate
@xcconfig.to_hash['OTHER_LDFLAGS'].split(" ").should.include("-fobjc-arc") @xcconfig.to_hash['OTHER_LDFLAGS'].split(" ").should.include("-fobjc-arc")
end end
...@@ -88,8 +88,6 @@ module Pod ...@@ -88,8 +88,6 @@ module Pod
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
it "saves the xcconfig" do it "saves the xcconfig" do
path = temporary_directory + 'sample.xcconfig' path = temporary_directory + 'sample.xcconfig'
@generator.save_as(path) @generator.save_as(path)
......
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