mirror of
https://github.com/zhigang1992/CocoaPods.git
synced 2026-06-14 09:29:31 +08:00
470 lines
15 KiB
Ruby
470 lines
15 KiB
Ruby
module Pod
|
||
class Podfile
|
||
class UserProject
|
||
include Config::Mixin
|
||
|
||
DEFAULT_BUILD_CONFIGURATIONS = { 'Debug' => :debug, 'Release' => :release }.freeze
|
||
|
||
def initialize(path = nil, build_configurations = {})
|
||
self.path = path if path
|
||
@build_configurations = build_configurations.merge(DEFAULT_BUILD_CONFIGURATIONS)
|
||
end
|
||
|
||
def path=(path)
|
||
path = path.to_s
|
||
@path = Pathname.new(File.extname(path) == '.xcodeproj' ? path : "#{path}.xcodeproj")
|
||
@path = config.project_root + @path unless @path.absolute?
|
||
@path
|
||
end
|
||
|
||
def path
|
||
if @path
|
||
@path
|
||
else
|
||
xcodeprojs = config.project_root.glob('*.xcodeproj')
|
||
if xcodeprojs.size == 1
|
||
@path = xcodeprojs.first
|
||
end
|
||
end
|
||
end
|
||
|
||
def project
|
||
Xcodeproj::Project.new(path) if path && path.exist?
|
||
end
|
||
|
||
def build_configurations
|
||
if project
|
||
project.build_configurations.map(&:name).inject({}) do |hash, name|
|
||
hash[name] = :release; hash
|
||
end.merge(@build_configurations)
|
||
else
|
||
@build_configurations
|
||
end
|
||
end
|
||
end
|
||
|
||
class TargetDefinition
|
||
include Config::Mixin
|
||
|
||
attr_reader :name, :target_dependencies
|
||
|
||
attr_accessor :user_project, :link_with, :platform, :parent, :exclusive
|
||
|
||
def initialize(name, options = {})
|
||
@name, @target_dependencies = name, []
|
||
@parent, @exclusive = options.values_at(:parent, :exclusive)
|
||
end
|
||
|
||
# A target is automatically `exclusive` if the `platform` does not match
|
||
# the parent's `platform`.
|
||
def exclusive
|
||
if @exclusive.nil?
|
||
if @platform.nil?
|
||
false
|
||
else
|
||
@parent.platform != @platform
|
||
end
|
||
else
|
||
@exclusive
|
||
end
|
||
end
|
||
alias_method :exclusive?, :exclusive
|
||
|
||
def user_project
|
||
@user_project || @parent.user_project
|
||
end
|
||
|
||
def link_with=(targets)
|
||
@link_with = targets.is_a?(Array) ? targets : [targets]
|
||
end
|
||
|
||
def platform
|
||
@platform || (@parent.platform if @parent)
|
||
end
|
||
|
||
def label
|
||
if name == :default
|
||
"Pods"
|
||
elsif exclusive?
|
||
"Pods-#{name}"
|
||
else
|
||
"#{@parent.label}-#{name}"
|
||
end
|
||
end
|
||
|
||
def acknowledgements_path
|
||
config.project_pods_root + "#{label}-Acknowledgements"
|
||
end
|
||
|
||
# Returns a path, which is relative to the project_root, relative to the
|
||
# `$(SRCROOT)` of the user's project.
|
||
def relative_to_srcroot(path)
|
||
if user_project.path.nil?
|
||
# TODO this is not in the right place
|
||
raise Informative, "[!] Unable to find an Xcode project to integrate".red if config.integrate_targets
|
||
path
|
||
else
|
||
(config.project_root + path).relative_path_from(user_project.path.dirname)
|
||
end
|
||
end
|
||
|
||
def relative_pods_root
|
||
"${SRCROOT}/#{relative_to_srcroot "Pods"}"
|
||
end
|
||
|
||
def lib_name
|
||
"lib#{label}.a"
|
||
end
|
||
|
||
def xcconfig_name
|
||
"#{label}.xcconfig"
|
||
end
|
||
|
||
def xcconfig_relative_path
|
||
relative_to_srcroot("Pods/#{xcconfig_name}").to_s
|
||
end
|
||
|
||
def copy_resources_script_name
|
||
"#{label}-resources.sh"
|
||
end
|
||
|
||
def copy_resources_script_relative_path
|
||
"${SRCROOT}/#{relative_to_srcroot("Pods/#{copy_resources_script_name}")}"
|
||
end
|
||
|
||
def prefix_header_name
|
||
"#{label}-prefix.pch"
|
||
end
|
||
|
||
def bridge_support_name
|
||
"#{label}.bridgesupport"
|
||
end
|
||
|
||
# Returns *all* dependencies of this target, not only the target specific
|
||
# ones in `target_dependencies`.
|
||
def dependencies
|
||
@target_dependencies + (exclusive? ? [] : @parent.dependencies)
|
||
end
|
||
|
||
def empty?
|
||
target_dependencies.empty?
|
||
end
|
||
end
|
||
|
||
def self.from_file(path)
|
||
podfile = Podfile.new do
|
||
string = File.open(path, 'r:utf-8') { |f| f.read }
|
||
# TODO: work around for Rubinius incomplete encoding in 1.9 mode
|
||
string.encode!('UTF-8') if string.respond_to?(:encoding) && string.encoding.name != "UTF-8"
|
||
eval(string, nil, path.to_s)
|
||
end
|
||
podfile.defined_in_file = path
|
||
podfile.validate!
|
||
podfile
|
||
end
|
||
|
||
include Config::Mixin
|
||
|
||
def initialize(&block)
|
||
@target_definition = TargetDefinition.new(:default, :exclusive => true)
|
||
@target_definition.user_project = UserProject.new
|
||
@target_definitions = { :default => @target_definition }
|
||
instance_eval(&block)
|
||
end
|
||
|
||
# Specifies the platform for which a static library should be build.
|
||
#
|
||
# This can be either `:osx` for Mac OS X applications, or `:ios` for iOS
|
||
# applications.
|
||
#
|
||
# For iOS applications, you can set the deployment target by passing a :deployment_target
|
||
# option, e.g:
|
||
#
|
||
# platform :ios, :deployment_target => "4.0"
|
||
#
|
||
# If the deployment target requires it (< 4.3), armv6 will be added to ARCHS.
|
||
#
|
||
def platform(platform, options={})
|
||
@target_definition.platform = Platform.new(platform, options)
|
||
end
|
||
|
||
# Specifies the Xcode workspace that should contain all the projects.
|
||
#
|
||
# If no explicit Xcode workspace is specified and only **one** project exists
|
||
# in the same directory as the Podfile, then the name of that project is used
|
||
# as the workspace’s name.
|
||
#
|
||
# @example
|
||
#
|
||
# workspace 'MyWorkspace'
|
||
#
|
||
def workspace(path = nil)
|
||
if path
|
||
@workspace = config.project_root + (File.extname(path) == '.xcworkspace' ? path : "#{path}.xcworkspace")
|
||
elsif @workspace
|
||
@workspace
|
||
else
|
||
projects = @target_definitions.map { |_, td| td.user_project.path }.uniq
|
||
if projects.size == 1 && (xcodeproj = @target_definitions[:default].user_project.path)
|
||
config.project_root + "#{xcodeproj.basename('.xcodeproj')}.xcworkspace"
|
||
end
|
||
end
|
||
end
|
||
|
||
# Specifies the Xcode project that contains the target that the Pods library
|
||
# should be linked with.
|
||
#
|
||
# If no explicit project is specified, it will use the Xcode project of the
|
||
# parent target. If none of the target definitions specify an explicit project
|
||
# and there is only **one** project in the same directory as the Podfile then
|
||
# that project will be used.
|
||
#
|
||
# @example
|
||
#
|
||
# # Look for target to link with in an Xcode project called ‘MyProject.xcodeproj’.
|
||
# xcodeproj 'MyProject'
|
||
#
|
||
# target :test do
|
||
# # This Pods library links with a target in another project.
|
||
# xcodeproj 'TestProject'
|
||
# end
|
||
#
|
||
def xcodeproj(path, build_configurations = {})
|
||
@target_definition.user_project = UserProject.new(path, build_configurations)
|
||
end
|
||
|
||
# Specifies the target(s) in the user’s project that this Pods library
|
||
# should be linked in.
|
||
#
|
||
# If no explicit target is specified, then the Pods target will be linked
|
||
# with the first target in your project. So if you only have one target you
|
||
# do not need to specify the target to link with.
|
||
#
|
||
# @example
|
||
#
|
||
# # Link with a target called ‘MyApp’ (in the user's project).
|
||
# link_with 'MyApp'
|
||
#
|
||
# # Link with the targets in the user’s project called ‘MyApp’ and ‘MyOtherApp’.
|
||
# link_with ['MyApp', 'MyOtherApp']
|
||
#
|
||
def link_with(targets)
|
||
@target_definition.link_with = targets
|
||
end
|
||
|
||
# Specifies a dependency of the project.
|
||
#
|
||
# A dependency requirement is defined by the name of the Pod and _optionally_
|
||
# a list of version requirements.
|
||
#
|
||
#
|
||
# When starting out with a project it is likely that you will want to use the
|
||
# latest version of a Pod. If this is the case, simply omit the version
|
||
# requirements.
|
||
#
|
||
# dependency 'SSZipArchive'
|
||
#
|
||
#
|
||
# Later on in the project you may want to freeze to a specific version of a
|
||
# Pod, in which case you can specify that version number.
|
||
#
|
||
# dependency 'Objection', '0.9'
|
||
#
|
||
#
|
||
# Besides no version, or a specific one, it is also possible to use operators:
|
||
#
|
||
# * `> 0.1` Any version higher than 0.1
|
||
# * `>= 0.1` Version 0.1 and any higher version
|
||
# * `< 0.1` Any version lower than 0.1
|
||
# * `<= 0.1` Version 0.1 and any lower version
|
||
# * `~> 0.1.2` Version 0.1.2 and the versions upto 0.2, not including 0.2
|
||
#
|
||
#
|
||
# Finally, a list of version requirements can be specified for even more fine
|
||
# grained control.
|
||
#
|
||
# For more information, regarding versioning policy, see:
|
||
#
|
||
# * http://semver.org
|
||
# * http://docs.rubygems.org/read/chapter/7
|
||
#
|
||
#
|
||
# ## Dependency on a library, outside those available in a spec repo.
|
||
#
|
||
# ### From a podspec in the root of a library repo.
|
||
#
|
||
# Sometimes you may want to use the bleeding edge version of a Pod. Or a
|
||
# specific revision. If this is the case, you can specify that with your
|
||
# dependency declaration.
|
||
#
|
||
#
|
||
# To use the `master` branch of the repo:
|
||
#
|
||
# dependency 'TTTFormatterKit', :git => 'https://github.com/gowalla/AFNetworking.git'
|
||
#
|
||
#
|
||
# Or specify a commit:
|
||
#
|
||
# dependency 'TTTFormatterKit', :git => 'https://github.com/gowalla/AFNetworking.git', :commit => '082f8319af'
|
||
#
|
||
#
|
||
# It is important to note, though, that this means that the version will
|
||
# have to satisfy any other dependencies on the Pod by other Pods.
|
||
#
|
||
#
|
||
# The `podspec` file is expected to be in the root of the repo, if this
|
||
# library does not have a `podspec` file in its repo yet, you will have to
|
||
# use one of the approaches outlined in the sections below.
|
||
#
|
||
#
|
||
# ### From a podspec outside a spec repo, for a library without podspec.
|
||
#
|
||
# If a podspec is available from another source outside of the library’s
|
||
# repo. Consider, for instance, a podpsec available via HTTP:
|
||
#
|
||
# dependency 'JSONKit', :podspec => 'https://raw.github.com/gist/1346394/1d26570f68ca27377a27430c65841a0880395d72/JSONKit.podspec'
|
||
#
|
||
#
|
||
# ### For a library without any available podspec
|
||
#
|
||
# Finally, if no man alive has created a podspec, for the library you want
|
||
# to use, yet, you will have to specify the library yourself.
|
||
#
|
||
#
|
||
# When you omit arguments and pass a block to `dependency`, an instance of
|
||
# Pod::Specification is yielded to the block. This is the same class which
|
||
# is normally used to specify a Pod.
|
||
#
|
||
# ```
|
||
# dependency do |spec|
|
||
# spec.name = 'JSONKit'
|
||
# spec.version = '1.4'
|
||
# spec.source = { :git => 'https://github.com/johnezang/JSONKit.git', :tag => 'v1.4' }
|
||
# spec.source_files = 'JSONKit.*'
|
||
# end
|
||
# ```
|
||
#
|
||
#
|
||
# For more info on the definition of a Pod::Specification see:
|
||
# https://github.com/CocoaPods/CocoaPods/wiki/A-pod-specification
|
||
def dependency(*name_and_version_requirements, &block)
|
||
@target_definition.target_dependencies << Dependency.new(*name_and_version_requirements, &block)
|
||
end
|
||
|
||
# Specifies that a BridgeSupport metadata document should be generated from
|
||
# the headers of all installed Pods.
|
||
#
|
||
# This is for scripting languages such as MacRuby, Nu, and JSCocoa, which use
|
||
# it to bridge types, functions, etc better.
|
||
def generate_bridge_support!
|
||
@generate_bridge_support = true
|
||
end
|
||
|
||
# Defines a new static library target and scopes dependencies defined from
|
||
# the given block. The target will by default include the dependencies
|
||
# defined outside of the block, unless the `:exclusive => true` option is
|
||
# given.
|
||
#
|
||
# Consider the following Podfile:
|
||
#
|
||
# dependency 'ASIHTTPRequest'
|
||
#
|
||
# target :debug do
|
||
# dependency 'SSZipArchive'
|
||
# end
|
||
#
|
||
# target :test, :exclusive => true do
|
||
# dependency 'JSONKit'
|
||
# end
|
||
#
|
||
# This Podfile defines three targets. The first one is the `:default` target,
|
||
# which produces the `libPods.a` file. The second and third are the `:debug`
|
||
# and `:test` ones, which produce the `libPods-debug.a` and `libPods-test.a`
|
||
# files.
|
||
#
|
||
# The `:default` target has only one dependency (ASIHTTPRequest), whereas the
|
||
# `:debug` target has two (ASIHTTPRequest, SSZipArchive). The `:test` target,
|
||
# however, is an exclusive target which means it will only have one
|
||
# dependency (JSONKit).
|
||
def target(name, options = {})
|
||
parent = @target_definition
|
||
options[:parent] = parent
|
||
@target_definitions[name] = @target_definition = TargetDefinition.new(name, options)
|
||
yield
|
||
ensure
|
||
@target_definition = parent
|
||
end
|
||
|
||
# This hook allows you to make any last changes to the generated Xcode project
|
||
# before it is written to disk, or any other tasks you might want to perform.
|
||
#
|
||
# For instance, say you'd want to customize the `OTHER_LDFLAGS` of all targets:
|
||
#
|
||
# post_install do |installer|
|
||
# installer.project.targets.each do |target|
|
||
# target.build_configurations.each do |config|
|
||
# config.build_settings['GCC_ENABLE_OBJC_GC'] = 'supported'
|
||
# end
|
||
# end
|
||
# end
|
||
def post_install(&block)
|
||
@post_install_callback = block
|
||
end
|
||
|
||
# Specifies that the -fobjc-arc flag should be added to the OTHER_LD_FLAGS.
|
||
#
|
||
# This is used as a workaround for a compiler bug with non-ARC projects.
|
||
# (see https://github.com/CocoaPods/CocoaPods/issues/142)
|
||
#
|
||
# This was originally done automatically but libtool as of Xcode 4.3.2 no
|
||
# longer seems to support the -fobjc-arc flag. Therefore it now has to be
|
||
# enabled explicitly using this method.
|
||
#
|
||
# This may be removed in a future release.
|
||
def set_arc_compatibility_flag!
|
||
@set_arc_compatibility_flag = true
|
||
end
|
||
|
||
# Not attributes
|
||
|
||
def podfile?
|
||
true
|
||
end
|
||
|
||
attr_accessor :defined_in_file
|
||
attr_reader :target_definitions
|
||
|
||
def dependencies
|
||
@target_definitions.values.map(&:target_dependencies).flatten.uniq
|
||
end
|
||
|
||
def dependency_by_top_level_spec_name(name)
|
||
dependencies.find { |d| d.top_level_spec_name == name }
|
||
end
|
||
|
||
def generate_bridge_support?
|
||
@generate_bridge_support
|
||
end
|
||
|
||
def set_arc_compatibility_flag?
|
||
@set_arc_compatibility_flag
|
||
end
|
||
|
||
def user_build_configurations
|
||
configs_array = @target_definitions.values.map { |td| td.user_project.build_configurations }
|
||
configs_array.inject({}) { |hash, config| hash.merge(config) }
|
||
end
|
||
|
||
def post_install!(installer)
|
||
@post_install_callback.call(installer) if @post_install_callback
|
||
end
|
||
|
||
def validate!
|
||
#lines = []
|
||
#lines << "* the `platform` attribute should be either `:osx` or `:ios`" unless @platform && [:osx, :ios].include?(@platform.name)
|
||
#lines << "* no dependencies were specified, which is, well, kinda pointless" if dependencies.empty?
|
||
#raise(Informative, (["The Podfile at `#{@defined_in_file}' is invalid:"] + lines).join("\n")) unless lines.empty?
|
||
end
|
||
end
|
||
end
|