搭建私有的 python 包发布中心 pypi

项目组现在使用Python越来越多,大部分老逻辑都已经迁移到了Python上,相当数量的新逻辑都是Python写的。经过之前的一段时间的分享,团队已经开始使用 virtualenv 和 setuptools 来进行Python代码的开发和打包和发布了。

但是现在的问题是,随着项目规模的变大,以及几个子项目的启动,代码复用开始成为一个问题。有很多代码在多个库当中被使用,应该被抽取出来成为单独的模块。但是这些模块和模块的依赖关系会比较复杂,比如一个应用可能需要依赖pypi上开源的库,同时需要依赖一个内部的库,而内部的库又依赖开源的库。如何解决这种情况下的依赖管理和自动包管理呢?

实际上setuptools 和 easy_install 已经提供了完善的依赖管理,在setup.py当中写上所有依赖的模块名已经在团队内形成了共识,那么内部模块是否可以用同样的方式进行管理呢?

答案是肯定的。easy_install 本质是 pypi 服务的客户端,它依赖的web服务称为 pypi,或者叫Cheese Shop。是 http://pypi.python.org/simple/ 。这个页面下面就是一系列的 index.html 文件,指向各个版本的包文件。这个index.html本身没有严格的格式规定,只是其中应该包含<a>标签,指向每个版本。easy_install 负责抽取出这些标签,形成一个文件列表,比较版本,下载指定版本或者最近版本,并安装到系统上。

而且,easy_install支持一个命令行参数 –index-url,或者短参数 -i ,可以指定兼容于 pypi 的 pypi 索引。这个索引只要满足pypi的规定就是可以的,自然,这个是可以自己搭建的。

但是easy_install有一个限制,就是只能指定一个index URL。对于多个index的问题,PEP381明确说了,这是客户端的问题。easy_install选择不解决这个问题,也是一种解决方案吧……

但是easy_install不解决,我们就要想办法自己解决。去除这个限制有两个方法,一个是让自己的私有pypi在发现私有包里面没有匹配的包名字的时候重定向到pypi.python.org/simple,另一种方法就是使用 easy_install 的替代品 pip。在翻看了众多的部署脚本之后,我们决定,还是使用前面一个策略。

除了常用的easy_install来安装包,pypi还需要一个功能就是支持 distutils 兼容的协议上传包到服务器。对于使用disutils或者setuptools建立的setup.py文件,开发者可以使用 python setup.py register 将项目名注册到 pypi index,也可以通过 python setup.py bdist_egg upload 上传打包好的文件。这个协议很简单,很容易即可实现,只是其中需要的用户管理方面,稍微复杂和体力活一些。

也正是因为简单,搭建私有的pypi服务器的开源程序有很多,PEP 381当中有两个推荐,分别是PloneSoftwareCenter 和 EggBasket。PloneSoftwareCenter是一个恐龙级别的东西,它是一个完整的CMS,pypi只是其中一个小小的功能。为了这样一个简单的功能需要安装一大堆Plone的东西,实在是难以接受,而且它的文档简直是个杯具……,唉。

EggBasket稍好,但是也要安装一堆东西,包括一只小恐龙TurboGears。所幸TurboGears只是一只小恐龙,而且EggBasket本身的文档比较清楚,一步步照着做即可。由于一些安全方面的限制,EggBasket单独的服务器端口在我们的服务器上是不能访问到的,因此我们用apache的mod_proxy做了一个反向代理。

很快,基于EggBasket和apache mod_proxy反向代理的私有pypi就搭建起来,问题随即而来:EggBasket不支持我们上面要求的自动重定向。所幸源代码也不多,简单修改了一下之后,做了一个patch。需要的可以下载下来自己apply。我已经联系了EggBasket的作者,希望能够将这个patch合并进官方代码,但是作者表示,他现在正在休假。【update @2010-12-12 自从这个patch发送过去已经接近半年了,还没有响应,好吧,我放弃了】

经过这些patch,我们的pypi服务器就成功搭建起来了。项目组使用它的方式是:

开发机:

(dev) zhangc@dev-01:pypismpl$ python setup.py register -r http://pypi-server/pypi
We need to know who you are, so please choose either:
1. use your existing login,
2. register as a new user,
3. have the server generate a new password for you (and email it to you), or
4. quit
Your selection [default 1]: 1
Username: zhangc
Password: ********
Server response (200): OK
I can store your PyPI login so future submissions will be faster.
(the login will be stored in /home/zhangc/.pypirc)
Save your login (y/N)? y

这步操作执行一次即可,如果最后一步选择了save login,则后面不再需要每次都register。

在程序新版本稳定了之后,执行:

(dev) zhangc@dev-01:pypismpl$ python setup.py bdist_egg upload -r http://pypi-server/pypi/upload

即可把新版本的程序打包成egg并且上传到服务器。

这时候如果通过浏览器访问pypi服务器,会发现新版本的pypismpl程序已经在页面上列出了。

然后在生产机上:

(dev) zhangc@production-01:~$ sudo -u appuser -E /usr/app/env/bin/python -i http://pypi-server/pypi -U pypismpl

新版本的程序就会自动部署了。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。