首页 > 技术 > 搭建私有的 python 包发布中心 pypi

搭建私有的 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

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

标签:
  1. 2011年1月29日18:43 | #1

    文章很不错,关注!

  2. f
    2011年6月2日20:56 | #2

    你还真是喜欢大蛇啊 🙂

  3. 2011年12月13日12:14 | #3

    我来帮你纪念一下Blog长草一周年。

  4. 2012年10月14日15:49 | #4

    虽然是篇旧文了,但是搜索的时候还是一直靠前。
    现在有了更好的解决方案了。pypiserver 轻量级,使用Bottle可以打包到只有一个文件,又可以快速搭建到SAE上。
    发到这里免得后来人重蹈复辙,
    项目地址 https://github.com/wangeek/pypiserver4sae

  1. 本文目前尚无任何 trackbacks 和 pingbacks.