先说点别的。
可能很多人和我一样,最开始习惯使用的是 Windows,后来开始接触 Linux,再后来,接触到 Mac,几周以后,一发不可收拾。
如果说,在 Windows 下面,基本上习惯了便捷友好的图形化界面,以及经历了对 “系统在干什么” 一无所知的恐惧之后,那么接下来 Linux 就带来了另一个极端的体验,知道系统在做什么,但是总是觉得不那么便捷而友好(刚开始很长一段时间都没有接触 Linux 图形界面)。我记得大致有这么一句话,“Linux is user friendly, but it is selective who its friends are.”,Linux 也是对用户朋友友好的,只不过对谁是它的朋友比较挑剔。既霸气,又高傲是不是?于是 Linux 党和 Windows 党见面就掐。
好,Mac 时间到了——既能够体会到便捷和友好(有过之无不及),又能够让我清楚地知道操作系统在干什么,和 Linux 的同源又可以带来系统和应用管理的亲切感。这也是我觉得为什么程序员的开发环境已经从若干年前的 Windows 一统天下到现在大部分被 Mac 蚕食的一个最主要原因。
如果你和我一样,先接触的 Linux,再迁移到 Mac,可能会在第一时间去寻找类似于 Linx 上的包安装管理工具。比如说 rpm(for Redhat,如果是 Debian 那会是 dpkg)。不过和 rpm 相比,Yum 会是更有名的那一个,包仓库、依赖管理等等都被引入(如果是 Debian 的话 apt-get 是类似的)。下图来自这篇文章。
之后就知道了大名鼎鼎的 Homebrew。它是 Mac 上包管理工具毫无疑问的老大。简洁,清晰,使用方便,而且有很多实用的功能。比如 “brew doctor”,帮忙修正一些潜在的问题,比如这样的,连解决方法都给出了:
Warning: The following directories are not writable:
/usr/local/bin
/usr/local/lib
This can happen if you "sudo make install" software that isn't managed
by Homebrew. If a formula tries to write a file to this directory, the
install will fail during the link step.
You should change the ownership of these directories to your account.
sudo chown -R $(whoami) /usr/local/bin /usr/local/lib
还有这样的,连问题单链接都附上了:
Warning: A .pydistutils.cfg file was found in $HOME, which may cause Python
builds to fail. See:
https://bugs.python.org/issue6138
https://bugs.python.org/issue4655
但是,和很多 Linux 版本上的包管理工具不同的是,它是有同级别的竞争对手的——它就是 MacPorts。功能上,二者类似
安装上面,由于 Homebrew 是 Ruby 写的,而 Ruby 已经在 Mac 上预装了,因此安装一行命令就搞定了:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
反观 MacPorts(据说有着最多的包),是用 C 和 TCL 写的,得下载 pkg 包,然后再自行安装(好像更像 Windows 一点)。它和 Homebrew 比起来,把所有的依赖包都重新下载到本地,而不是重用系统中已有的库——这有利有弊,好的一面是不容易发生冲突,也不容易发生一些库本身不可靠带来的乱七八糟的问题,坏的一面是这些库要重下,慢而且占用更多空间。
题外话,偶然看到 Stack Overflow 上面有人支持 MacPorts 的时候,吐槽了一下 Homebrew,哈哈:
Rubists like to rewrite everything in Ruby, because the only thing they are at ease is Ruby itself.
Mac 上的最后一个,我也是才知道的,fink。它对于 Debian 上过来的用户亲和力是最好的,可以下载预编译好的二进制包,也可以在 Mac 上现做现卖,从源代码编译开始。
上面说的都是基于某个操作系统的包安装管理工具,其实还有一些别的维度下的包安装管理工具。比如基于某种编程语言的包安装管理工具。
在 JavaScript 的世界里最常用的是 NPM。事实上,不管是外界的什么工具,在 JavaScript 的世界里,总是能找到相应的一份。后来了解到了它的一个替代工具,叫做 Yarn,。有趣的是,似乎 JavaScript 社区内部要友善得多(跟 “同源” 有关系?),你可以通过 NPM 安装 Yarn,看起来竞争对手其实也不是那么讨厌对吧——错了,你有本事通过 Homebrew 安装 MacPorts 试试?
Java 的话则是 Maven,而如同前面的划分一样,它的前身,也是没有服务端功能的弱化版本是 Ant。印象中还用过一个 Gant,好几年前写过一点点东西。
不过相较于这些,我倒想重点说说 Python 世界里的的 pip。
说这个是因为最近跟 Python 干上了,项目的原因,我也是被迫今年开始学的 Python。
最近知道一个很有意思的事情,Google 的搜索指数上看,Python 已经成功登顶了,可谓最火的语言:
可是去传统的 TIOBE 看看,哪有啊,势头不错,但是距离登顶还远着哪:
其实谁都没有问题,这里恰恰反映了一个有趣的事实,Python 未必是最流行和使用最广泛的,但却是特别需要”use the fucking Google” 的,或者说,有很多人在使用 Python 的时候,Google 一下去寻找某一个 Python 问题的解决方案。
想起来我们的项目也多为 Python 完成,有的项目代码规模还不小了,这里面五味杂陈。既有代码简洁、直接,执行容易,和 Linux 脚本亲和度高的好处,也有从工程上看零零散散,缺乏有效规划、组织、测试等等的问题。发自内心地感受,Python 是如此地便捷,可我依然不觉得 Python 是 “正规军”。随着规模的增大 Python 代码带来的风险和 Java 之类的传统货比起来,还明显让人不放心。
呃,抱歉……好像又扯远了。
现在回到 pip 上面。讲到 pip 必须提一提 easy_install。pip 始于 2008 年,而 easy_install 始于 2004 年,二者的关系就如同 Yum 和 rpm 一样,是后者的替代品,功能更强大,但最重要的一点是有了服务端的支持——对版本库的支持和依赖的解决。下面这张表来自于 PyPA 的这个链接。
在实际项目中,我们把 Python 的包仓库配置到公司内部的服务器,然后在需要的时候根据 requirements.txt 的内容下载依赖包:
pip install -r requirements.txt
一个更全面的执行过程是:
virtualenv venv;
source venv/bin/activate;
pip install --trusted-host=artifactory.xxx.xxx -i https://artifactory.xxx.xxx/api/pypi/global-release-pypi/simple -U xoxo -r requirements.txt;
其实,这些工具对于包的仓库、依赖、冲突解决、依赖树生成、版本比较、状态迁移、本地替换等等功能支持得有强有弱(似乎多数包管理工具指支持到这个列表的仓库和依赖,可能还加上简单的状态迁移,而其它的功能都不支持)。老实说,到现在为止我觉得最强的包管理工具还是 Amazon 内部的 Brazil(而且比其它强很多),很可惜它并不开源。关于这方面的机制,大有文章可做,以后有机会再讲。
文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》