cocoaPods源码之从入口Pod学起

本文介绍了如何在CocoaPods的Podfile中移除版本校验,并通过debug其源码理解install!函数的工作原理。重点讲解了rubygems、Bundler在CocoaPods中的作用以及ENV['COCOAPODS_NO_BUNDLER']的含义。
摘要由CSDN通过智能技术生成

打开工程的Podfile文件打算学习一下,去除一些cocoapods的版本校验,第一行便是install! 'cocoapods', :deterministic_uuids => false;为了了解install!函数,我debug cocoapods的源码,发现pod Insall命令的的入口是pod文件,下面我们看一下具体的代码,从下面代码我们可以看出,pod命令最后调用Command.rb中的run函数,在该函数中通过super函数调到CLAide::Command,来解析install命令。

#!/usr/bin/env ruby
#1、目的是检测当前的编码是否是UTF-8,如果不是将错误信息输出到stder,用于在命令行中给出提示。
#Encoding.default_external是encoding类的函数返回默认的外部编码
if Encoding.default_external != Encoding::UTF_8

  if ARGV.include? '--no-ansi'
    STDERR.puts <<-DOC
    WARNING: CocoaPods requires your terminal to be using UTF-8 encoding.
    Consider adding the following to ~/.profile:

    export LANG=en_US.UTF-8
    DOC
  else
    STDERR.puts <<-DOC
    \e[33mWARNING: CocoaPods requires your terminal to be using UTF-8 encoding.
    Consider adding the following to ~/.profile:

    export LANG=en_US.UTF-8
    \e[0m
    DOC
  end

end

#下面逻辑是根据不同的条件从不同的地方导入cocoapods库
if $PROGRAM_NAME == __FILE__ && !ENV['COCOAPODS_NO_BUNDLER']
  # 找到 Gemfile 文件,添加到ENV环境变量map中
  ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
  # 导入系统rb库
  require 'rubygems'
  require 'bundler/setup'
   # 将cocoapods源码根目录下的lib目录,添加到$LOAD_PATH记录的加载rb文件的搜索目录集合中
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
elsif ENV['COCOAPODS_NO_BUNDLER']
  require 'rubygems'
  # 从 https://rubygems.org 共有仓库,下载cocoapods库
  gem 'cocoapods'
end

STDOUT.sync = true if ENV['CP_STDOUT_SYNC'] == 'TRUE'
# 导入 cocoapods.rb
require 'cocoapods'

#根据执行pod命令时是否带有COCOAPODS_PROFILE选项,做不同操作
if profile_filename = ENV['COCOAPODS_PROFILE']
	#如果有导入'ruby-prof',分析rb代码执行效率
  require 'ruby-prof'
  reporter =
    case (profile_extname = File.extname(profile_filename))
    when '.txt'
      RubyProf::FlatPrinterWithLineNumbers
    when '.html'
      RubyProf::GraphHtmlPrinter
    when '.callgrind'
      RubyProf::CallTreePrinter
    else
      raise "Unknown profiler format indicated by extension: #{profile_extname}"
    end
  File.open(profile_filename, 'w') do |io|
  	#调用 Pod::Command.run(ARGV) 解析命令行参数
    reporter.new(RubyProf.profile { Pod::Command.run(ARGV) }).print(io)
  end
else
	#没有COCOAPODS_PROFILE选项直接 Pod::Command.run(ARGV) 解析命令行参数
  Pod::Command.run(ARGV)
end

知识点

1、rubygems是什么

RubyGems 是一个统一安装、管理 Ruby 类库、程序的 Ruby 标准工具。在 RubyGems 中,每个单独的库称为 gem。通过 RubyGems,我们可以搜索 gem,显示 gem 相关的信息,安装 / 卸载 gem,升级旧版本的 gem,以及查看 gem 的安装进度一览表,等等。

2、bundle是什么

Bundler 能够跟踪并安装所需的特定版本的 gem,以此来为 Ruby 项目提供一致的运行环境。

Bundler 管理 Ruby 依赖的,能够跟踪并安装所需的特定版本的 gem,以此来为 Ruby 项目提供一致的运行环境,具体可以浏览官网

具体参考这篇文章

3、ENV[‘COCOAPODS_NO_BUNDLER’]

ENV[‘COCOAPODS_NO_BUNDLER’]定义在sandbox-pod.rb中,sandbox-pod.rb文件确保了CocoaPods对沙盒的控制权,沙盒中的文件夹提供了CocoaPods安装需要使用的Pods projects、支持文件以及相关资源。

# Ensure the `pod` bin doesn’t think it needs to use Bundler.(确保 `pod` bin 认为它不需要使用 Bundler)
ENV['COCOAPODS_NO_BUNDLER'] = '1'

一般沙盒中的文件结构如下

   Pods
   |
   +-- Headers
   |   +-- Private
   |   |   +-- [Pod Name]
   |   +-- Public
   |       +-- [Pod Name]
   |
   +-- Local Podspecs
   |   +-- External Sources
   |   +-- Normal Sources
   |
   +-- Target Support Files
   |   +-- [Target Name]
   |       +-- Pods-acknowledgements.markdown
   |       +-- Pods-acknowledgements.plist
   |       +-- Pods-dummy.m
   |       +-- Pods-prefix.pch
   |       +-- Pods.xcconfig
   |
   +-- [Pod Name]
   |
   +-- Manifest.lock
   |
   +-- Pods.xcodeproj
(if installation option 'generate_multiple_pod_projects' is enabled)
   |
   +-- PodTarget1.xcodeproj
   |
  ...
   |
   +-- PodTargetN.xcodeproj

3、Pod::Command.run(ARGV)

Pod::Command.run(ARGV)函数内部调用父类CLAide的run函数,父类run函数如下,解析命令之后,调用到install.rb中的install!函数

   def self.run(argv = [])
      plugin_prefixes.each do |plugin_prefix|
        PluginManager.load_plugins(plugin_prefix)
      end
			#将argv强转位ARGV对象
      argv = ARGV.coerce(argv)
      #解析 argument 生成对应的 command instance,将 run 的类方法转换为实例方法,具体看下面self.parse函数
      command = parse(argv)
      ANSI.disabled = !command.ansi_output?
      unless command.handle_root_options(argv)
        command.validate!
        command.run
      end
    rescue Object => exception
      handle_exception(command, exception)
    end
    
    def self.parse(argv)
      # 通过解析 argv 获取到与 cmd 名称
      argv = ARGV.coerce(argv)
      cmd = argv.arguments.first
      # 如果 cmd 对应的 Command 类,则更新 argv,继续解析命令
      if cmd && subcommand = find_subcommand(cmd)
        argv.shift_argument
        subcommand.parse(argv)
      # 如果 cmd 为抽象命令且指定了默认命令,则返回默认命令继续解析参数
      elsif abstract_command? && default_subcommand
        load_default_subcommand(argv)
      else
      	# 初始化真正的 cmd 实例
        new(argv)
      end
    end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员的修养

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值