系统理解 Ruby 工具链
source link: http://chuquan.me/2021/01/20/understand-ruby-tool-chain/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
一直以来,我对 Ruby 工具链环境都没有一个系统的认识,这使得我在 iOS 开发时遇到的 Ruby 环境问题都难以把握其本质原因。最近开始学习 Ruby 开发,借此机会深入学习了一下 Ruby 工具链,并整理出本文以供后续的学习。
版本管理系统
在软件工程中,版本管理系统(Version Control System,简称 VCS)是用于管理团队协作开发重要的工具,能够为后续的持续继承提供保障。源码管理器(Source Code Manager,简称 SCM)就是 VCS 的一种,常见的工具如:git
、svn
。包管理器(Package Manager,简称 PM)也是 VCS 的一种,常见的工具如:cocoapods
、swift package manager
、npm
、git submodule
。
源码管理器一般是针对单个文件进行版本控制;包管理器则是针对单个 package 进行版本控制。
通常在一个项目中,会同时使用源码管理器和包管理器,由于包管理器能够限定包的版本范围,所以通常不会将包加入源码管理中。举个例子:对于 iOS 项目,我们会使用 git
进行源码管理,使用 cocoapods
进行包管理,在 Pods
目录下存放项目所依赖的包,并在 .ignore
中忽略 Pods
目录。
包管理工具通常具备语义化版本检查,依赖递归查找,依赖冲突解决,构建具体依赖等能力。这些能力则主要围绕以下两个文件来实现:
- 描述文件:声明了项目的依赖及其版本限制。
- 锁存文件:记录了依赖更新后的全版本列表。
除了上述两个文件之外,中心化的包管理器一般会提供依赖包的托管服务,比如:npm 提供的 npmjs.com 可以集中查找和下载 npm 包;去中心化的包管理器一般会通过 git 仓库的地址查找和下载依赖包,比如:iOS 的 carthage
和 spm
中所声明的依赖都会有各自的 git
仓库地址。
下面我们对常见的几种包管理器进行简要的对比:
Key File Git Submodule CocoaPods SPM npm 描述文件 .gitmodule Podfile Package.swift Package.json 锁存文件 .git/modules Podfile.lock Package.resolved Package-lock.json下面我们来介绍这里提到的两种包管理器:git submodule
和 cocoapods
。
Git Submodule
Git submodule 是一种原始的包管理器,它不具备常见包管理器工具所特有的语义化管理功能,无法处理依赖共享和冲突。Git submodule 将单独的 git
仓库以子目录的形式嵌入在项目中,保存每个依赖仓库的文件状态。
.gitmodules
Git submodule 以 .gitmodules
文件作为描述文件,其描述了模块的基本信息,如:path
、url
、branch
。如下所示是一个 .gitmodule
文件的实例:
[submodule "flutter"]
path = flutter
url = https://github.com/flutter/flutter.git
branch = stable
.git/modules
Git submodule
以 .git/modules
目录作为锁存文件,其中 HEAD
文件记录了项目所依赖的子仓库的 commit 信息。
CocoaPods
CocoaPods 是 iOS 开发中常用的一个第三方库的依赖管理工具。
Podfile
CocoaPods 以 Podfile
文件作为描述文件,使用基于 Ruby 的 DSL 来描述依赖关系,用于描述项目所依赖的第三方库。
Podfile.lock
CocoaPods 以 Podfile.lock
文件作为锁存文件,其记录了每个已安装 Pod 的版本。项目中,一般会把 Podfile.lock
加入到版本控制中,有助于保持团队的一致性。
Manifest.lock
CocoaPods 使用未加入版本控制的 Manifest.lock
,对比已加入版本控制的 Podfile.lock
,从而判断是否需要更新本地的依赖。我们常见的 The sandbox is not in sync with the Podfile.lock
报错就是由于 Manifest.lock
与 Podfile.lock
不一致所引起的。每次执行完 pod install
命令时会重新生成 Podfile.lock
及其副本 Manifest.lock
。
Ruby 环境版本控制
我们都知道 CocoaPods 是通过 Ruby 实现的,是一个 gem
包。在 iOS 开发中,我们经常会遇到由于 Ruby 环境变化而导致 CocoaPods 出错。一旦我们理解了 Ruby 的依赖管理,那么有助于我们更好的管理不同版本的 CocoaPods 和其他 gem
,从而顺利解决开发过程中遇到的各种环境问题。
RVM & rbenv
RVM 和 rbenv 都是管理多个 Ruby 环境的工具,它们都能够提供不同版本的 Ruby 环境管理和切换。
关于 RVM 和 rbenv 孰好孰坏,各有各的说法,我选择 RVM 作为 Ruby 版本管理工具主要是因为工作中团队使用的是 RVM。
RubyGems
RubyGems 是 Ruby 的一个包管理器,它所管理的包或者依赖,我们称之为 gem。
上述介绍的包管理器,一般都是围绕着 描述文件 和 锁存文件 来工作的。这种情况只是针对项目而言,因为不同的项目有着不同的环境。然而,RubyGems 作为系统的包管理器,它的工作环境只有一个,因此无需描述文件和锁存文件。
作为一个中心化的包管理器,RubyGems 提供了 Ruby 组件的托管服务,可以集中式的查找和安装工具和依赖。当我们使用 gem install xxx
时,会通过 rubygems.org
来查询对应的 gem。iOS 开发中常用的工具都可以通过 RubyGems 进行安装,如:bundler
、fastlane
、cocoapods
等。
默认情况下,RubyGems 总是下载 gem 的最新版本,这无法确保所安装的 gem 符合我们的预期。因此我们还缺一个工具。
Bundler
Bundler 是管理 gem 依赖的工具,它能够隔离不同项目中 gem 的版本。本质上,Bundler 是一个包管理器,也是一个 gem。
Gemfile
Bundler 以 Gemfile
文件作为描述文件,从而确定各个 gem 的版本号或范围,从而提供稳定的应用环境。
在 iOS 开发中,为了让团队的工作环境保持一致性,通常使用 Bundler,结合项目中的 Gemfile
来指定项目所使用工具的具体版本。如下所示是 Gemfile
配置的示例:
source 'https://gems.ruby-china.com'
gem 'cocoapods', '~> 1.10.0'
gem 'fastlane', '~> 2.153.1'
当我们执行 bundle exec pod install
时,bundler 会读取 Gemfile 选择指定版本的 cocoapods 来执行 pod install
命令,从而让团队的工作环境保持一致。
Gemfile.lock
Bundler 以 Gemfile.lock
文件作为锁存文件,将各个 gem 的具体安装版本写入其中。
当团队中的其他人通过 bundle install
来安装 gem 时,会读取 Gemfile.lock
中的 gem 名称及其版本信息,从而安装对应的 gem 版本。
Ruby 工具链
如下所示为 Ruby 工具链的关系图,我们可以使用 homebrew
+ rvm
+ RubyGems
+ Bundler
组成的 Ruby 工具链来管理一个项目中 Ruby 工具的版本依赖,具体管理流程如下:
- 使用
homebrew
安装 Ruby 版本管理工具rbenv
或rvm
(rvm
目前不支持通过homebrew
进行安装) - 使用
rbenv
或rvm
安装并指定一个系统默认的 Ruby 版本,每个版本的 Ruby 都有一个对应的RubyGems
包管理器 - 使用
RubyGems
安装 gem 包,如:cocoapods
、bundler
、fastlane
- 使用
bundler
管理单个项目中所依赖 gem 包的版本
对于项目而言,可以使用 bundler
管理其所依赖的 gem 包的版本。具体操作是在项目中新增一个 Gemfile
描述文件,从而锁定项目中依赖 gem
包的版本。
在 Gemfile
所在目录下执行 bundle install
,能够安装 Bundler
环境下的 gem
依赖。通过如下命令可以分别查看系统环境下和 Bundler
环境下的 gem 列表。
# 系统环境下的 gem 列表
$ gem list
# Bundler 环境下的 gem 列表
$ bundle exec gem list
本文,我们从版本管理系统出发,分别介绍了源码管理器和包管理器。然后,重点介绍了包管理器中几种常见的工具:git submodule
、cocoapods
。包管理器一般围绕着 描述文件、锁存文件 实现,cocoapods
、bundler
、npm
都是如此。
最后,我们梳理了一下 Ruby 工具链中各种工具之间的关系,并绘制了两个关系图。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK