@qidiandasheng
2022-01-05T15:36:13.000000Z
字数 3720
阅读 923
Cocoapods
Cocoapods-Downloader
是用于下载源码的小工具,它支持各种类型的版本管理工具,包括 HTTP / SVN / Git / Mercurial
。它可以提供tags
、commites
,revisions
,branches
以及zips
文件的下载和解压缩操作。
我们先通过入口文件 lib/cocoapods-downloader.rb
来一窥cocoapods-downloader
项目的主要文件:
module Pod
module Downloader
require 'cocoapods-downloader/gem_version'
require 'cocoapods-downloader/api'
require 'cocoapods-downloader/api_exposable'
require 'cocoapods-downloader/base'
# 下载方式
autoload :Bazaar, 'cocoapods-downloader/bazaar'
autoload :Git, 'cocoapods-downloader/git'
autoload :Http, 'cocoapods-downloader/http'
autoload :Mercurial, 'cocoapods-downloader/mercurial'
autoload :Scp, 'cocoapods-downloader/scp'
# 下载方式对于的版本,比如tag等
autoload :Subversion, 'cocoapods-downloader/subversion'
# 支持的下载方式
def self.downloader_class_by_key
{
:bzr => Bazaar,
:git => Git,
:hg => Mercurial,
:http => Http,
:scp => Scp,
:svn => Subversion,
}
end
end
# lib/cocoapods/downloader/cache.rb
def download_pod(request)
# 如果缓存中不存在,则进入无缓存下载
cached_pod(request) || uncached_pod(request)
rescue Informative
raise
rescue
UI.puts("\n[!] Error installing #{request.name}".red)
raise
end
# requeset对象包括podname,git地址和tag,以及spec对象
def uncached_pod(request)
in_tmpdir do |target|
# 下载完成之后会返回一个result(response),和对应的podspec对象
result, podspecs = download(request, target)
result.location = nil
podspecs.each do |name, spec|
# 获取对应pod的缓存路径
destination = path_for_pod(request, :name => name, :params => result.checkout_options)
# 从下载目录复制到缓存目录中
copy_and_clean(target, destination, spec)
# podspec转成json类型存入缓存中
write_spec(spec, path_for_spec(request, :name => name, :params => result.checkout_options))
if request.name == name
result.location = destination
end
end
result
end
end
# 准备下载
def download(request, target)
Downloader.download_request(request, target)
end
# lib/cocoapods/downloader.rb
def self.download_request(request, target)
result = Response.new
result.checkout_options = download_source(target, request.params)
result.location = target
if request.released_pod?
result.spec = request.spec
podspecs = { request.name => request.spec }
else
podspecs = Sandbox::PodspecFinder.new(target).podspecs
podspecs[request.name] = request.spec if request.spec
podspecs.each do |name, spec|
if request.name == name
result.spec = spec
end
end
end
[result, podspecs]
end
# target是下载目录,params存的是git地址和tag
def self.download_source(target, params)
FileUtils.rm_rf(target)
# 根据目录和下载地址生成Downloader对象
downloader = Downloader.for_target(target, params)
downloader.download
target.mkpath
if downloader.options_specific?
params
else
downloader.checkout_options
end
end
根据对应的下载类型,会生成对应的下载类型的对象:
def self.for_target(target_path, options)
options = options_to_sym(options)
if target_path.nil?
raise DownloaderError, 'No target path provided.'
end
# 这里的options为{git:'',tag:''},下载类型为git,则这里生成的klass为Pod::Downloader::Git
strategy, klass = class_for_options(options)
url = options[strategy]
sub_options = options.dup
sub_options.delete(strategy)
# Pod::Downloader::Git类初始化
klass.new(target_path, url, sub_options)
end
下载类型git
、mercurial
、remote_file
、bazaar
等的基类是base
,初始化方法会走入基类里面:
# lib/cocoapods-downloader/base.rb
# 初始化对象,保存url,options,创建下载目录
def initialize(target_path, url, options)
require 'pathname'
@target_path = Pathname.new(target_path)
@url = url
@options = options
unrecognized_options = options.keys - self.class.options
unless unrecognized_options.empty?
raise DownloaderError, "Unrecognized options `#{unrecognized_options}`"
end
end
# name就是对应的子类的class名
def download
ui_action("#{name} download") do
target_path.mkpath
download!
end
end
最后进入子类的执行下载的函数:
# lib/cocoapods-downloader/git.rb
module Pod
module Downloader
class Git < Base
def download!
clone
checkout_commit if options[:commit]
end
def clone(force_head = false, shallow_clone = true)
ui_sub_action('Git download') do
begin
git! clone_arguments(force_head, shallow_clone)
update_submodules
rescue DownloaderError => e
if e.message =~ /^fatal:.*does not support (--depth|shallow capabilities)$/im
clone(force_head, false)
else
raise
end
end
end
end
.
.
.
end
end
end