@qidiandasheng
2022-08-07T20:53:28.000000Z
字数 4963
阅读 654
Cocoapods
我们下载Cocoapods的源码,然后能看到Gemfile文件,通过这个文件我们能看到cocoapods
的gem依赖,这其中就包括了Cocoapods的核心组件依赖。
SKIP_UNRELEASED_VERSIONS = false
# Declares a dependency to the git repo of CocoaPods gem. This declaration is
# compatible with the local git repos feature of Bundler.
#
def cp_gem(name, repo_name, branch = 'master', path: false)
return gem name if SKIP_UNRELEASED_VERSIONS
opts = if path
{ :path => "../#{repo_name}" }
else
url = "https://github.com/CocoaPods/#{repo_name}.git"
{ :git => url, :branch => branch }
end
gem name, opts
end
source 'https://rubygems.org'
gemspec
group :development do
cp_gem 'claide', 'CLAide'
cp_gem 'cocoapods-core', 'Core', '1-11-stable'
cp_gem 'cocoapods-deintegrate', 'cocoapods-deintegrate'
cp_gem 'cocoapods-downloader', 'cocoapods-downloader'
cp_gem 'cocoapods-plugins', 'cocoapods-plugins'
cp_gem 'cocoapods-search', 'cocoapods-search'
cp_gem 'cocoapods-trunk', 'cocoapods-trunk'
cp_gem 'cocoapods-try', 'cocoapods-try'
cp_gem 'molinillo', 'Molinillo'
cp_gem 'nanaimo', 'Nanaimo'
cp_gem 'xcodeproj', 'Xcodeproj'
gem 'cocoapods-dependencies', '~> 1.0.beta.1'
gem 'activesupport', '> 5', '< 6' # Pinned < 6 because 6 requires Ruby 2.5.0
gem 'bacon', :git => 'https://github.com/leahneukirchen/bacon.git'
gem 'mocha', '< 1.5'
gem 'mocha-on-bacon'
gem 'netrc'
gem 'prettybacon'
gem 'typhoeus'
gem 'webmock'
gem 'bigdecimal', '~> 1.3.0'
gem 'public_suffix'
gem 'ruby-graphviz', '< 1.2.5'
# Integration tests
gem 'diffy'
gem 'clintegracon', :git => 'https://github.com/mrackwitz/CLIntegracon.git'
# Code Quality
gem 'inch_by_inch'
gem 'rubocop', '0.50.0'
gem 'simplecov', '< 0.18'
gem 'danger', '~> 5.3'
end
group :debugging do
gem 'cocoapods_debug'
gem 'rb-fsevent'
gem 'kicker'
gem 'awesome_print'
gem 'ruby-prof', :platforms => [:ruby]
end
我们在命令行里输入pod命令,最先来到的就是CLAide
,通过调用 Pod::Command.run(ARGV)
,实例化了一个 CLAide::Command
对象,开始我们的 CLAide 命令解析阶段。
CLAide中最核心的部分就是command.rb
里的Command
类,我们之后的一些pod命令的起点都是继承自Command
。我们在Cocoapods
源码下面的command
文件夹能看到这些命令,比如Command::Install
类对应的命令为pod install
:
其中运行部分就是其中的run函数:
module Pod
class Command
class Install < Command
# ...
def run
# 判断是否存在 Podfile 文件
verify_podfile_exists!
# 从 Config 中获取一个 Instraller 实例
installer = installer_for_config
# 默认是不执行 update
installer.repo_update = repo_update?(:default => false)
installer.update = false
installer.deployment = @deployment
# 忽略工程中的缓存,直接全量编译,默认为false
installer.clean_install = @clean_install
# install 的真正过程
installer.install!
end
end
end
end
CocoaPods-Core 用于 CocoaPods 中配置文件的解析,包括 Podfile、Podspec以及解析后的依赖锁存文件,如 Podfile.lock 等。
我们先通过入口文件 lib/cocoapods-core.rb
来一窥 Core 项目的主要文件:
module Pod
require 'cocoapods-core/gem_version'
class PlainInformative < StandardError; end
class Informative < PlainInformative; end
require 'pathname'
require 'cocoapods-core/vendor'
# 用于存储 PodSpec 中的版本号
autoload :Version, 'cocoapods-core/version'
# pod 的版本限制
autoload :Requirement, 'cocoapods-core/requirement'
# 配置 Podfile 或 PodSpec 中的 pod 依赖
autoload :Dependency, 'cocoapods-core/dependency'
# 获取 Github 仓库信息
autoload :GitHub, 'cocoapods-core/github'
# 处理 HTTP 请求
autoload :HTTP, 'cocoapods-core/http'
# 记录最终 pod 的依赖信息
autoload :Lockfile, 'cocoapods-core/lockfile'
# 记录 SDK 的名称和 target 版本
autoload :Platform, 'cocoapods-core/platform'
# 对应 Podfile 文件的 class
autoload :Podfile, 'cocoapods-core/podfile'
# 管理 PodSpec 的集合
autoload :Source, 'cocoapods-core/source'
# 管理基于 CDN 来源的 PodSpec 集合
autoload :CDNSource, 'cocoapods-core/cdn_source'
# 管理基于 Trunk 来源的 PodSpec 集合
autoload :TrunkSource, 'cocoapods-core/trunk_source'
# 对应 PodSpec 文件的 class
autoload :Specification, 'cocoapods-core/specification'
# 将 pod 信息转为 .yml 文件,用于 lockfile 的序列化
autoload :YAMLHelper, 'cocoapods-core/yaml_helper'
# 记录 pod 依赖类型,是静态库/动态库
autoload :BuildType, 'cocoapods-core/build_type'
...
Spec = Specification
end
pod install
命令执行后的 verify_podfile_exists!
中读取podfile:
def verify_podfile_exists!
unless config.podfile
raise Informative, "No `Podfile' found in the project directory."
end
end
Podfile
文件的读取就是config.podfile
里触发的,代码在 CocoaPods
的 config.rb
文件中:
def podfile_path_in_dir(dir)
PODFILE_NAMES.each do |filename|
candidate = dir + filename
if candidate.file?
return candidate
end
end
nil
end
def podfile_path
@podfile_path ||= podfile_path_in_dir(installation_root)
end
def podfile
@podfile ||= Podfile.from_file(podfile_path) if podfile_path
end
最后 Core 里的podfile.rb
的from_file
函数将依据目录下的 Podfile
文件类型选择调用 from_yaml
或者 from_ruby
:
def self.from_file(path)
path = Pathname.new(path)
unless path.exist?
raise Informative, "No Podfile exists at path `#{path}`."
end
case path.extname
when '', '.podfile', '.rb'
Podfile.from_ruby(path)
when '.yaml'
Podfile.from_yaml(path)
else
raise Informative, "Unsupported Podfile format `#{path}`."
end
end
读取到文件之后我们需要对Podfile内容进行解析,这里主要看Core
下面的podfile.rb文件下的from_ruby
函数:
def self.from_ruby(path, contents = nil)
contents ||= File.open(path, 'r:utf-8', &:read)
...
# 生成podfile对象,eval执行自己定义的dsl语句
podfile = Podfile.new(path) do
# rubocop:disable Lint/RescueException
begin
# rubocop:disable Security/Eval
eval(contents, nil, path.to_s)
# rubocop:enable Security/Eval
rescue Exception => e
message = "Invalid `#{path.basename}` file: #{e.message}"
raise DSLError.new(message, path, e, contents)
end
# rubocop:enable Lint/RescueException
end
podfile
end
Cocoapods-Downloader
是用于下载源码的小工具,它支持各种类型的版本管理工具,包括 HTTP / SVN / Git / Mercurial。它可以提供 tags、commites,revisions,branches 以及 zips 文件的下载和解压缩操作。