2011-03-14

搭建本地pypi服务器

Python中的easy_install很好很强大,后起之秀pip更是青出于蓝。有人说python中的easy_install就像ruby中的gem,perl中的cpan,我一直使用Ubuntu,因此想到的类比是debian系列中的apt。easy_install如此常见以致有不少同学以为easy_install是linux的一个命令。强大的软件包管理工具必然有一个不弱小的软件包仓库。Python的官方软件包仓库就是大名鼎鼎的PyPI。通常情况下我们都是使用easy_install或pip从PyPI仓库下载软件包并安装,很方便。但如果网络状况不好或没有网络的话这就很麻烦。幸好,Python提供了Pypi服务器软件,使得可以在本地搭建一个pypi镜像服务器,然后就可以使用自己的镜像服务器来下载安装了。

Pypi服务器软件有好几个,比如PEP,yopypi,z3c.pypimirror等,还有一种是通过代理来安装的,叫做collective.eggproxy。这其中最常见的就是z3c.pypimirror了。下面讲讲如何使用pypimiror搭建PyPI镜像服务器。

安装pypimirror

首先安装pypimirror。使用easy_install或pip安装:
$ sudo easy_install z3c.pypimirror
$ sudo pip install z3c.pypimirror

配置并下载软件包

安装完毕就要填写配置文件,需要填写的参数主要有:
  • mirror_file_path 下载的包的存放路径
  • base_url 服务器地址,这个注意要和Apache上的一致!
  • create_indexes 布尔类型,用来在下载的每个包目录下创建索引
  • package_matches 这个是用户自定义的,PyPI包无数,使用正则表达式有选择地下载,要不然硬盘要爆了
  • lock_file_name 设置运行时锁状态文件存放位置
  • log_filename 设置日志文件存放位置
填写完毕以后,运行pypimirror来下载软件包,配置文件名可任意,通常是pypimirror.cfg:
$ pypimirror -c -v -I pypimirror.cfg
参数说明:
  • -c 在终端显示日志
  • -v 冗余模式显示
  • -I 初始化PyPi镜像
接下来可以活动活动,因为这个要运行很长时间。

生成索引文件

经过漫长的等待,所有软件下载完毕,然后需要一个索引文件,这个索引文件不同于上面的包目录下的索引文件,而是所有包的索引。
$ pypimirror -c -v -i -U pypimirror.cfg
参数说明:
  • -i 创建索引
  • -U 更新镜像。
为什么要使用-U参数呢?因为在创建索引时必须选择使用-I或者-U。-I用来初始化,-U用来更新。

整合Apache

假设前面设置的下载文件存放路径为/data/pypi/files,下面把它链接到/var/www/目录下:
$ ln -s /data/pypi/files /var/www/pypi
重启Apache,访问http://localhost/pypi/ 应该就可以了。这是最简单的配置,这时的base_url就是 http://localhost/pypi/

使用自己的PyPI服务器

easy_install和pip中使用自己的PyPI服务器安装Pylons:
$ sudo easy_install -i http://localhost/pypi/ Pylons
$ sudo pip install -i http://localhost/pypi/ Pylons
在buildout中使用,在index字段中设置。
[buildout]
parts = instance
index = http://localhost/pypi/

...

使用buildout构建pypimirror

除了使用easy_install或pip安装pymirror以外,也可以通过buildout构建(参考自http://bluedynamics.com/articles/jens/setup-z3c.pypimirror )。 同时使用模板,填写参数,生成对应的配置文件。 buildout配置文件如下:
[buildout]
parts = mirror mirror-cfg

[mirror]
recipe = zc.recipe.egg:scripts
eggs = z3c.pypimirror

[dirs]
recipe = z3c.recipe.mkdir
mirror-base = /PATH/TO/mirror
mirror-files = ${:mirror-base}/files
paths =
    ${:mirror-files}

[mirror-cfg]
recipe = collective.recipe.template
input = ${buildout:directory}/pypimirror.cfg.in
output = ${buildout:directory}/pypimirror.cfg
url = http://pypi.MYDOMAIN.TLD
mirror-path = ${dirs:mirror-files}
lockfile = ${buildout:directory}/mirror.lock
logfile = ${dirs:mirror-base}/mirror.log
配置参数解释:
  • input 配置文件模板,这里是 pypimirror.cfg.in
  • output 生成的配置文件
  • mirror-base,mirror-files,mirror-path 都是用来配置mirror-file-path的
  • url 用来生成base_url
  • lockfile 用来生成lock_file_name
  • logfile 用来生成log_filename
接下来是配置文件模板 pypimirror.cfg.in :
[DEFAULT]
# the root folder of all mirrored packages.
# if necessary it will be created for you
mirror_file_path = ${:mirror-path}

# where's your mirror on the net?
base_url = ${:url}

# lock file to avoid duplicate runs of the mirror script
lock_file_name = ${:lockfile}

# days to fetch in past on update
fetch_since_days = 1

# Pattern for package files, only those matching will be mirrored
filename_matches =
    *.zip
    *.tgz
    *.egg
    *.tar.gz
    *.tar.bz2

# Pattern for package names; only packages having matching names will
# be mirrored
package_matches =
    *

# remove packages not on pypi (or externals) anymore
cleanup = True

# create index.html files
create_indexes = True

# be more verbose
verbose = True

# resolve download_url links on pypi which point to files and download
# the files from there (if they match filename_matches).
# The filename and filesize (from the download header) are used
# to find out if the file is already on the mirror. Not all servers
# support the content-length header, so be prepared to download
# a lot of data on each mirror update.
# This is highly experimental and shouldn't be used right now.
#
# NOTE: This option should only be set to True if package_matches is not
# set to '*' - otherwise you will mirror a huge amount of data. BE CAREFUL
# using this option!!!
external_links = True

# similar to 'external_links' but also follows an index page if no
# download links are available on the referenced download_url page
# of a given package.
#
# NOTE: This option should only be set to True if package_matches is not
# set to '*' - otherwise you will mirror a huge amount of data. BE CAREFUL
# using this option!!!
follow_external_index_pages = False

# logfile
log_filename = ${:logfile}
修改里面的package_matches为自己需要的软件包。然后执行 bin/buildout生成pypimirror脚本和配置文件。 接下来的步骤和前面easy_install的一样,只不过命令改为bin/pypimirror罢了。
blog comments powered by Disqus