• cocoaPods源码之从入口Pod学起


    打开工程的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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    知识点

    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'
    
    • 1
    • 2

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

       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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
  • 相关阅读:
    Request和Response
    shiro回话管理
    0分钟!搞懂计算机内存实现原理
    000 我和网安的故事.doc
    10 STL-list
    C++入门——引用|内联函数|auto关键字|基于范围的for循环|指针空值
    安防视频监控平台EasyNVR无法控制云台,该如何解决?
    【编程语言】Python平台化为何比Java差?
    Web自动化-Windows窗口上传文件
    Redis安装和使用(博客)
  • 原文地址:https://blog.csdn.net/u011774517/article/details/126372213