[关闭]
@qidiandasheng 2022-01-02T21:02:31.000000Z 字数 3645 阅读 897

Cocoapods核心组件:CLAide

Cocoapods


介绍

CLAide 是一个简单的命令行解释器,它提供了功能齐全的命令行界面和 API。它不仅负责解析我们使用到的 Pods 命令,例如:pod install, pod update等,还可用于封装常用的一些脚本,将其打包成简单的命令行小工具。

CLAide 功能概览

我们先通过 pod --help 来查看 CLAide 的真实输出效果:

  1. $ pod
  2. Usage:
  3. $ pod COMMAND
  4. CocoaPods, the Cocoa library package manager.
  5. Commands:
  6. + cache Manipulate the CocoaPods cache
  7. + deintegrate Deintegrate CocoaPods from your project
  8. + env Display pod environment
  9. + init Generate a Podfile for the current directory
  10. ...
  11. Options:
  12. --allow-root Allows CocoaPods to run as root
  13. --silent Show nothing
  14. --version Show the version of the tool
  15. ...

👆所展示的UsageCommandsOptions 及其内容均是由 CALide 的输出模版Banner 来完成的。CALide 提供了 Command 基类帮助我们快速定义出标准且美观的命令。除了 pod 命令之外,例如:Xcodeproj 所提供的命令也是由 CALide 来实现的。

CALide 的目录结构

首先来看 CALide 项目的文件入口 lib/calide.rb

  1. module CLAide
  2. VERSION = '1.0.3'.freeze
  3. require 'claide/ansi'
  4. require 'claide/argument'
  5. require 'claide/argv'
  6. require 'claide/command'
  7. require 'claide/help'
  8. require 'claide/informative_error'
  9. end

Command 抽象类

Command 是用于构建命令行界面的基础抽象类。所有我们添加的命令都需要继承自Command,这些子类可以嵌套组合成更加精细的命令。

pod 命令正是由多个 Pod::Command < CLAide::Command 的子类组合而成的 Abstract command。当然 pod 的 subcommand 同样也能声明为 abstact command,通过这样的方式我们就能达到多级嵌套命令的效果。有抽象命令当然也需要有具体执行任务的 normal command

对于任何命令类型都可以设置以下几个属性和方法:

guardia1598855030376-84980ad9-7ff0-4c97-bee8-266bc77772e9.jpeg-143.3kB

Abstract Command

Abstract command为不提供具体命令实现的抽象容器命令类,不过它可以包含一个或多个的subcommands

比如我们最简单的pod命令为Abstract Command,就是继承自CLAide::Command:

  1. module Pod
  2. class Command < CLAide::Command
  3. require 'cocoapods/command/options/repo_update'
  4. require 'cocoapods/command/options/project_directory'
  5. include Options
  6. require 'cocoapods/command/cache'
  7. require 'cocoapods/command/env'
  8. require 'cocoapods/command/init'
  9. require 'cocoapods/command/install'
  10. require 'cocoapods/command/ipc'
  11. require 'cocoapods/command/lib'
  12. require 'cocoapods/command/list'
  13. require 'cocoapods/command/outdated'
  14. require 'cocoapods/command/repo'
  15. require 'cocoapods/command/setup'
  16. require 'cocoapods/command/spec'
  17. require 'cocoapods/command/update'
  18. # 表示为Abstract Command
  19. self.abstract_command = true
  20. self.command = 'pod'
  21. self.version = VERSION
  22. self.description = 'CocoaPods, the Cocoa library package manager.'
  23. self.plugin_prefixes = %w(claide cocoapods)
  24. .
  25. .
  26. .
  27. .
  28. end
  29. end

Normal Command

相对于抽象命令,普通命令就需要设置传递实参的名称和描述,以及重载 run 方法。

比如继承自Command的pod子命令pod update

  1. module Pod
  2. class Command
  3. class Update < Command
  4. self.arguments = [
  5. CLAide::Argument.new('POD_NAMES', false, true),
  6. ]
  7. self.description = <<-DESC
  8. Updates the Pods identified by the specified `POD_NAMES`.
  9. DESC
  10. def self.options
  11. [
  12. ["--sources", 'The sources from which to update dependent pods'],
  13. ['--exclude-pods', 'Pods to exclude during update'],
  14. ['--clean-install', 'Ignore the contents of the project cache and force a full pod installation']
  15. ].concat(super)
  16. end
  17. end
  18. end
  19. end

guardia1599005020049-ddaee5cf-5280-4586-b5ab-0a3587f0d245.png-825.2kB

Run方法实际运行命令

Command 类中定义了两个run方法:

  1. def self.run(argv = [])
  2. # 根据文件前缀来匹配对应的插件
  3. plugin_prefixes.each do |plugin_prefix|
  4. PluginManager.load_plugins(plugin_prefix)
  5. end
  6. argv = ARGV.coerce(argv)
  7. # 解析 argument 生成对应的 command instance
  8. command = parse(argv)
  9. ANSI.disabled = !command.ansi_output?
  10. unless command.handle_root_options(argv)
  11. command.validate!
  12. command.run
  13. end
  14. rescue Object => exception
  15. handle_exception(command, exception)
  16. end
  17. def run
  18. raise 'A subclass should override the `CLAide::Command#run` method to ' \
  19. 'actually perform some work.'
  20. end

作为Command类的核心方法,类方法 self.run 将终端传入的参数解析成对应的 commandargv,并最终调用 command 的实例方法 run 来触发真正的命令逻辑。因此子类需要通过重载 run 方法来完成对应命令的实现。

比如pod install的run方法:

  1. module Pod
  2. class Command
  3. class Install < Command
  4. # ...
  5. def run
  6. # 判断是否存在 Podfile 文件
  7. verify_podfile_exists!
  8. # 从 Config 中获取一个 Instraller 实例
  9. installer = installer_for_config
  10. # 默认是不执行 update
  11. installer.repo_update = repo_update?(:default => false)
  12. installer.update = false
  13. installer.deployment = @deployment
  14. # 忽略工程中的缓存,直接全量编译,默认为false
  15. installer.clean_install = @clean_install
  16. # install 的真正过程
  17. installer.install!
  18. end
  19. end
  20. end
  21. end

参考

CocoaPods 命令解析 - CLAide

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注