macOS 包管理工具 Homebrew 不完全指南

说到包管理工具,几乎已经成为现代操作系统或者开发平台不可或缺的工具软件。 如果你有过服务端管理经验的话,你一定会用过诸如 yum 这样的工具,只需要几条命令,就把需要的服务全都安装上。

无论我们平时做开发,或是管理服务器,都免不了用到一些第三方依赖包。即便是架设一个最简单的 web 服务器,你至少也需要安装一个 nginx。

包管理工具的基本功能就是提供一个集中的平台,可以在这里找到大部分流行的组件,而不用费力的到每个软件自己的主页去下载安装。 只需要输入简单的命令,就可以直接安装。 并且包管理工具还会帮助用户管理所有这些包的版本,以及它们之间的依赖关系。 

像刚才说的架设 web 服务器的例子,如果没有包管理工具,我们就需要找到每个组件的下载位置,还要手动管理它们的更新,依赖关系等等,这些事情就需要消耗掉不少的精力。 好在包管理工具已经为我们处理好了这一切,我们要做的只是安装,使用。

macOS 上的包管理

刚才举的是服务端管理的例子,那么包管理在我们自己的开发机上有什么用呢? 下面就逐步给大家介绍。 Homebrew 作为 macOS 包管理工具的后起之秀,在近一两年可谓是风生水起。 相比它的前辈,macports 和 Fink 而言,它的整体设计更加符合现代的开发环境,并且平台的更新速度也更快。

废话不再多说,开始进入正题,无论你是初次接触 Homebrew,又或是已经用过它,但是还没有深入了解,后面的内容我相信都会对你有所帮助。

安装与使用

使用 Homebrew 第一步就是安装它,这个在它的主页 https://brew.sh 上有明确的文档,最简单的方式只需要一行命令:


/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

这是一个 ruby 脚本,执行这个安装脚本就可以完成 Homebrew 所有安装操作。 咱们继续,安装完成后,我们就可以使用 brew 命令安装需要的包了:


brew install node

安装的完整过程如下图所示:

从上面图中的最后一行可以看到,node 被安装到了 /usr/local/Cellar 目录中。 通过 Homebrew 安装的所有包都会被放在这里。 这样做有几个好处,一个是方便集中管理,删除不再使用的软件包,省去了大量软件包散落在各处带来日后清理的头疼问题。另外可以方便更集中的权限管理。 

为了更好的说明这个问题,还是给大家举个具体的例子,比如我们前面命令中安装的 node 软件。 如果不使用 Homebrew, 而用它官网提供的安装程序,那么安装完成后,会创建如下文件:


/usr/local/bin -rwxrwxr-x  1 spring  admin  30994272 10  3 09:55 node lrwxr-xr-x  1 502     staff        38 10 16 09:57 npm -> ../lib/node_modules/npm/bin/npm-cli.js/usr/local/includedrwxrwxr-x  42 spring  admin  1344 10  3 09:55 node /usr/local/libdrwxrwxr-x  3 spring  admin  96 10  3 09:54 node_modules /usr/local/lib/dtrace-rw-rw-r--  1 spring  admin  12324 10  3 09:50 node.d /usr/local/share/doc drwxrwxr-x  5 spring  admin  160 10  3 09:54 node /usr/local/share/man/man1 -rw-rw-r--  1 spring  admin  7849 10  3 09:48 node.1/usr/local/share/systemtap/tapset -rw-rw-r--  1 spring  admin  2361 10  3 09:48 node.stp

这里面路径部分是所在目录,下面的内容是当前目录的内容。大家看到了,一个 nodejs 环境,安装看起来不难,但它却会在这么多的位置创建文件。 当然,如果你一直在同样的环境使用它,没什么问题。 但如果有一天你不需要它了,想删除掉,就比较麻烦了,至少在我写这篇文章的时候,NodeJS 官方也还没提供方便的卸载工具。 也就是说,你必须像我现在这样清楚的列出它所有文件的位置,才能干净的将它删除掉。这个现象存在于大多数我们常用的工具软件中。

再来看看 Homebrew 是如何解决这个问题的,下面是使用 Homebrew 安装 node 后文件的存放位置:


/usr/local/bin lrwxr-xr-x  1 marspro  admin  29 10 16 12:03 node -> ../Cellar/node/8.7.0/bin/nodelrwxr-xr-x  1 marspro  admin  46 10 16 12:03 npm -> /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/include lrwxr-xr-x  1 marspro  admin  33 10 16 12:03 node -> ../Cellar/node/8.7.0/include/node/usr/local/lib drwxr-xr-x  4 marspro  admin  128 10 17 14:01 node_modules /usr/local/lib/dtrace lrwxr-xr-x  1 marspro  admin  41 10 16 12:03 node.d -> ../../Cellar/node/8.7.0/lib/dtrace/node.d/usr/local/share/doc lrwxr-xr-x  1 marspro  admin  38 10 16 12:03 node -> ../../Cellar/node/8.7.0/share/doc/node/usr/local/share/man/man1 lrwxr-xr-x  1 marspro  admin     48 10 16 12:03 node.1 -> ../../../Cellar/node/8.7.0/share/man/man1/node.1/usr/local/share/systemtap/tapset -rw-r--r--  1 marspro  admin  3495 10 11 20:36 node.stp

初步看上去,好像和前面的整体上没有什么区别,但仔细观察你会发现,之前目录中的文件都变成了符号链接,并且指向 Cellar 目录中。 比如之前的:


/usr/local/bin -rwxrwxr-x  1 spring  admin  30994272 10  3 09:55 node

在通过 Homebrew 安装后,变成了:


/usr/local/bin lrwxr-xr-x  1 marspro  admin  29 10 16 12:03 node -> ../Cellar/node/8.7.0/bin/node
也就是说,虽然 node 安装后的目录结构没变,但相应的位置已经变成了符号链接,而 node 实际的文件都存放在了  目录中。 也就是我们前面说的 Homebrew 模块主目录。 当你想删除 nodejs 的时候,只需要运行:/usr/local/Cellar


brew uninstall node

这一条命令就可以完整的删除之前安装的 nodejs 所有内容,这里也包括在 /usr/local/ 中创建的那些符号链接。你甚至还可以用另外一条命令暂时的停用 node:


brew unlink node

使用 unlink,只会删除符号链接,但并不会删除程序本身, /usr/local/Cellar 目录中的程序文件还依然存在。这个功能在某些场景中非常有用,比如你需要某个程序包暂时失效,用于调试你正在进行的开发。

unlink 调试结束后,再运行 link 命令,就可以把相应的程序包恢复回来:


brew link node

包管理的好处是不是体现出来了。 你还可以用 brew info 命令查看当前安装的 node 版本:


brew info

输出:


node: stable 8.7.0 (bottled), HEAD Platform built on V8 to build network applications https://nodejs.org/ /usr/local/Cellar/node/8.7.0 (3,830 files, 45.5MB) *  Poured from bottle on 2017-10-18 at 00:29:19From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/node.rb

这条命令可以列出这个程序包的完整信息,包括它的版本,安装位置,等等。 从这里可以看到,我们当前安装的 node 版本是 8.7.0。 Homebrew 还允许我们指定安装的版本号,比如:


brew install node@6

会安装 6.x 版本的 node。 同样,这个版本的 node 也会被保存到 /usr/local/Cellar 目录中。 这样,我们同时就有了两个 node 版本。 

可定制信息查询

Homebrew 也为我们提供了非常灵活的信息查询能力。 通过 brew info 命令和 jq 模块的结合。 首先我们可以安装 jq 模块:


brew install jq

jq 是一个在命令行中处理 JSON 数据的模块。 而 brew info 命令除了我们刚才展示的方法,还支持原生 JSON 格式的输出, 还是以我们刚才的 node 模块为为例:


brew info --json=v1 node | jq

这里 info 命令多了一个 --json=v1 参数,这表示使用 JSON 格式输出, 随后传递给 jq 做格式化输出,最终的结果如下:

可以看到,这里给出的信息非常全,包括当前版本,安装类型,依赖关系等等。 除了查询单个包的信息之外,还可以利用 jq 的能力做一些条件查询,比如:


brew info --json=v1 node | jq "map(select(.linked_keg != null) | .name)"

jq 命令后面的参数是查询条件。 linked_keg 表示已经建立符号链接的包。 也就是相当于前面提到的没有被 brew unlink的。 后面的 .name 表示我们只需要显示包的 name 属性, 也就是名称。

这只是一个简单的查询例子,通过这个命令,你几乎可以用任何方式访问 Homebrew 的内部数据。 尤其对于只需要数据的程序,比如对于开发一个显示本地 Homebrew 内容的 UI 程序,这些数据可以非常方便的获取到。

Bottles

BottlesHomebrew 中的一个专用名词。 它表示直接用二进制形式发布的包。 我们在使用 brew install 安装程序包的时候有两种方式,一个是下载源代码然后在本地构建,另外一个是直接下载已经编译好的二进制包。 而 Bottles 就是预编译好的二进制包。

如果一个源包含预编译的 Bottle, 我们在使用 brew install 的时候会自动使用它。 如果出于某些原因,你不想使用预编译的包,就可以加上 --build-from-source 选项:


brew install --build-from-source node

这样相应的安装包就会在你的本机上面构建。一般而言,直接在本机构建源代码安装速度会比较慢,这也是为什么 Homebrew 会提供 Bottles 预编译包的原因之一, 但在有些场景下,可能会需要自己来编译,这个选项就有作用了。

Taps

Homebrew 主要是基于 Git 进行包管理的, 之前如果了解过包管理系统的同学应该会知道这个特性,每个包管理工具都会有一个主仓库,和一些可选的功能仓库。 这样做的主要是为了让软件包整理有序。 因为当前所有可用的软件包加在一起会非常庞大,都放到一个仓库中会造成很大的性能损耗,并且这些庞大的包中有相当一部分是比较小众不常用的。 所以一般包管理工具会把那些常用的软件包放到主仓库,其他的软件包根据功能特性组织到可选的功能仓库中。 

HomebrewTaps 就是这个仓库的概念。 我们可以试着输入命令 brew tap, 你应该会看到这样的输出:


homebrew/core

默认情况下,Homebrew 只包含 homebrew/core 这个仓库,也就是它的主仓库。当然 Homebrew 还提供了一些功能仓库,比如:


homebrew/nginx    //包含 nginx 相关模块的仓库
homebrew/php       // php 相关模块的仓库
homebrew/science  // 科学计算工具仓库

如果想加载任何一个仓库,只需要执行 brew tap 命令:


brew tap homebrew/nginx

除了 Homebrew 自身提供的这些仓库之外,还可以加载任何的第三方仓库,只要这些仓库符合 Homebrew 的规范,都可以正常使用。 Homebrew 官网中也列举出了一些有用的 Taps 供大家参考: https://docs.brew.sh/Interesting-Taps-and-Forks.html

用户数据统计

Homebrew 会使用 Google Analytics 记录匿名用户数据, 这点在它的官网上也有明确说明:https://docs.brew.sh/Analytics.html

一个好消息是,你可以控制你的本地客户端是否发送这些匿名数据:


$ brew analytics Analytics is enabled. UUID: D8B7E7E8-2FF5-4110-85F9-3559F1150CCF

brew analytics 命令可以检测当前 Homebrew 是否开启了用户数据上传,如果开启,会向上面那样给出你的 UUID。 如果你不想上传这些行为数据可以运行:


brew analytics off

来关闭数据上传。 同样,你还可以重新生成统计的 UUID


brew analytics regenerate-uuid

那么这个匿名数据用来做什么呢,主要是用来记录整体仓库使用情况的,它不会具体到每一个人,只是用来分析整体趋势,以便 Homebrew 能够更好的完善自身。 并且这些数据对用户也都是开放的:https://brew.sh/analytics/

这个页面里面列出了目前开放的数据统计,比如这个在一段时间内安装量的数据:

从这里就可以看出这些安装包的整体趋势,还是比较有价值的数据。

Homebrew 命名原则

Homebrew 从字面意思上翻译,就是自酿啤酒的意思。 它的一切命名规范都来自于这个主题,比如在安装好一个包的时候,命令行中会出现一个啤酒表情:

知道这个背景,你就应该了解这个表情不是随意放上去的,正好切合了 Homebrew 的主题。 

还记得我们最开始提到的包的安装位置么, /usr/local/CellarCellar 这个词是酒窖的意思。是不是又和主题吻合上了。

这里面是 Homebrew 完整的命名方式含义 https://docs.brew.sh/Formula-Cookbook.html 看完之后相信你会更理解 Homebrew 各种名称的含义了。

总结

这篇文章算是对 Homebrew 给大家做了一个概述,把它的主要功能,能做的事情做了介绍。也希望通过这个介绍,能帮助大家对 Hombrew 的了解更多一些。

相关文章
相关标签/搜索