自动生成zcml slugs,buildout:egg和buildout:develop条目。
项目描述
buildout.eggtractor
问题:什么是buildout扩展?
答案:[链接](http://pypi.python.org/pypi/zc.buildout#extensions)
问题
在开发使用 buildout 的 zope/plone eggs 时,每次我在 src 目录或其他开发目录(有时我会有多个)中创建/删除/重命名一个开发 egg,我都必须编辑 buildout 配置文件(3 个地方)。
我必须添加/删除/重命名 egg 至 [buildout] 中的 eggs 选项,然后添加/删除/重命名 egg 路径至 [buildout] 中的 develop 选项,最后添加/删除/重命名 zope [instance] 中的 zcml 选项或我的策略包的 configure.zcml 文件。这太麻烦了,尤其是在开发模式下。我需要一个不那么无聊的开发方式。
解决方案
buildout.eggtractor 是一个 buildout 扩展,它扫描我提供的 src 目录或目录列表中的 eggs,并自动拾取它们。所以不再需要编辑 buildout 的配置文件。
当 buildout.eggtractor 在扫描目录中找到一个 egg 时,它会
1. adds the egg to the ``eggs`` option of all zope instance parts or to a set of given parts 2. adds the egg's path in the ``develop`` option of the ``[buildout]`` 3. If ``tractor-autoload-zcml`` is not given or set to other thing than false, scans the egg folder for ``configure.zcml``, ``meta.zcml`` and ``overrides.zcml`` and adds the appropriate zcml entries to the ``zcml`` option of the zope instance parts or to a set of given parts.
这些步骤在运行 buildout 时即时完成。因此,我可以添加/删除/重命名一个 egg,并且它将被拾取。
注意:该扩展不会写入 buildout 的配置文件。
buildout.eggtractor 选项
- tractor-src-directory
要扫描开发 eggs 的目录集合。默认为 buildout 的 src 目录。
- tractor-target-parts
要更新其 eggs 选项的 parts 集合,其中包含在 tractor-src-directory 中找到的 eggs。如果没有 zope 实例 parts,则默认。
- tractor-autoload-zcml(布尔值)
使用在 tractor-src-directory 中找到的 eggs 更新 tractor-target-parts 的 zcml 选项。默认为 true。
- tractor-zcml-top
要首先加载其 zcml 文件的 eggs 集合。默认为空集合。
如何使用它
使用 buildout.eggtractor 非常简单。如前所述,它是一个 buildout 扩展。我只需要在 extensions 选项中声明它
[buildout] parts = extensions = buildout.eggtractor
这就完了。buildout.eggtractor 将扫描 src 目录,并在每次运行 buildout 命令时执行其工作。
当我想要扫描其他目录时,我只需在 [buildout] 中添加一个 tractor-src-directory 选项,并将我的目录添加到那里
[buildout] parts = extensions = buildout.eggtractor tractor-src-directory = dev-src1 dev-src2 src
在少数情况下,当 zcml 文件的加载优先级很重要时,我在 [buildout] 中的 tractor-zcml-top 选项中添加要首先加载的 egg
[buildout] parts = extensions = buildout.eggtractor tractor-src-directory = dev-src1 dev-src2 src tractor-zcml-top = plone.app.mypackage1
如果我想将开发目录中找到的 eggs 添加到给定集合的 parts 的 eggs 选项中,我添加一个 tractor-target-parts 选项,并将 parts 添加到那里
[buildout] parts = instance1 instance2 instance3 extensions = buildout.eggtractor tractor-target-parts = instance1 instance3
这样,只有 instance1 和 instance3 会被更新。
如果我已经有其他方式包含 zcml 文件(例如:z3c.autoinclude)并且不想让 eggtractor 生成 zcml slugs,我添加一个 tractor-autoload-zcml 选项并将其设置为 false
在大多数情况下,您只需将 buildout.eggtractor 添加到 [buildout] 的 extensions 选项中,而不需要任何额外的配置选项。
限制
该扩展假设 egg 名称反映了其文件系统结构
例如:如果 egg 名称是 com.mustap.www,则扩展假设文件系统结构如下
1. com.mustap.www/src/com/mustap/www 2. com.mustap.www/com/mustap/www
这是扩展寻找 configure.zcml、meta.zcml 和 overrides.zcml 文件的地方。
如果蛋的名称与系统上的结构无关,扩展将忽略它。
XXX:我认为遍历目录比这种假设更好。
在我的情况下,这不是一个限制,因为我就是这样选择我的蛋名称的。
Mustapha
电子邮件:mustap_at_gmail_com
变更历史
0.6 (2008-10-29)
在Windows上修复了安装问题: http://plone.org/support/forums#nabble-f293351
在测试蛋是否已添加之前,将构建配置值拆分。如果蛋的名称是已添加蛋的子串(例如,在plone.app.content之后是plone.app.contentmenu),则使用字符串的“in”不起作用。[csenger]
对os.listdir的输出进行排序(其顺序是未定义的),以便更容易调试。[csenger]
0.5 (2008-04-30)
重构:添加了tractor-target-parts选项,添加了tractor-autoload-zcml选项,更新了文档,更新了测试:需要更多测试[mustapha]
0.4 (2008-04-27)
确保如果找到相同的包中的meta.zcml或overrides.zcml,则将configure.zcml添加到包包含中。[hannosch]
0.3 (2008-04-27)
使用新行作为添加条目的分隔符。空格会让buildout认为它必须处理版本指定符。[hannosch]
0.2 (2008-04-27)
添加了对自动查找多个实例的支持。[hannosch]
最好使用配方名称来查找实例,因为这不太可能发生冲突。[hannosch]
0.1 (2008-04-27)
空白符修复。[hannosch]
使用ZopeSkel创建了配方[mustapha]
详细文档
buildout.eggtractor构建扩展的测试
让我们创建一个buildout配置文件
>>> data = """ ... [buildout] ... parts = zope2 instance1 instance2 ... extensions = buildout.eggtractor ... eggs = ... develop = ... [instance1] ... recipe = plone.recipe.zope2instance ... zope2-location = ${zope2:location} ... user = admin:admin ... [instance2] ... recipe = plone.recipe.zope2instance ... zope2-location = ${zope2:location} ... user = admin:admin ... [zope2] ... recipe = plone.recipe.zope2install ... url = http://www.zope.org/Products/Zope/2.9.8/Zope-2.9.8-final.tgz ... """ >>> rmdir(tempdir, 'buildout.test') >>> cd(tempdir) >>> sh('mkdir buildout.test') mkdir buildout.test <BLANKLINE> >>> cd('buildout.test') >>> touch('buildout.cfg', data=data) >>> ls('.') buildout.cfg
第一次运行buildout,以便wget我们的Zope实例
>>> sh('buildout bootstrap') buildout bootstrap Creating directory '/tmp/buildout.test/bin'. Creating directory '/tmp/buildout.test/parts'. Creating directory '/tmp/buildout.test/develop-eggs'. Generated script '/tmp/buildout.test/bin/buildout'. <BLANKLINE> >>> sh('bin/buildout') bin/buildout ... Installing instance1. Generated script '/tmp/buildout.test/bin/instance1'. Generated script '/tmp/buildout.test/bin/repozo'. Installing instance2. Generated script '/tmp/buildout.test/bin/instance2'. <BLANKLINE> <BLANKLINE>
现在让我们在src目录中创建一个egg
>>> sh("paster create --no-interactive -o src -t plone_app com.mustap.www namespace_package=com namespace_package2=mustap package=www") paster create --no-interactive -o src -t plone_app com.mustap.www namespace_package=com namespace_package2=mustap package=www ... ...setup.py egg_info <BLANKLINE>
好的,现在我们有一个egg,让我们以离线模式运行buildout。我们应该在develop-egg中看到一个链接文件,在parts/instance1/etc/package-includes和parts/instance2/etc/package-includes中的zcml slugs,以及bin/instance1和bin/instance2文件中的我们的egg路径的行。
首先,我们检查没有前面提到的东西
>>> ls('develop-eggs') >>> ls('parts/instance1/etc/package-includes') No directory named parts/instance1/etc/package-includes >>> ls('parts/instance2/etc/package-includes') No directory named parts/instance2/etc/package-includes >>> sh('grep com.mustap.www bin/instance1') grep com.mustap.www bin/instance1 <BLANKLINE> >>> sh('grep com.mustap.www bin/instance2') grep com.mustap.www bin/instance2 <BLANKLINE>
OK,现在以离线模式运行buildout
>>> sh('./bin/buildout -o') ./bin/buildout -o ...
检查我们是否有一个正确创建的buildout。首先检查我们在develop-eggs目录中是否有链接
>>> ls('develop-eggs') com.mustap.www.egg-link
检查我们是否有我们的zcml slugs在package-includes中
>>> ls('parts', 'instance1', 'etc', 'package-includes') 001-com.mustap.www-configure.zcml >>> ls('parts', 'instance2', 'etc', 'package-includes') 001-com.mustap.www-configure.zcml
最后检查在bin/instance1和bin/instance2中是否有包含我们的egg路径的行
>>> cat('bin', 'instance1') #!/usr/bin/python2.4 ... sys.path[0:0] = [ '/tmp/buildout.test/src/com.mustap.www', ... ] ... >>> cat('bin', 'instance2') #!/usr/bin/python2.4 ... sys.path[0:0] = [ '/tmp/buildout.test/src/com.mustap.www', ... ] ...
现在让我们尝试tractor-target-parts选项。我们创建一个新的buildout.cfg文件,其中包含空的tractor-target-parts
>>> data = data.replace('eggs =', 'tractor-target-parts = \neggs = ') >>> touch('buildout.cfg', data=data) >>> sh('./bin/buildout -o') ./bin/buildout -o ...
我们在develop-egg目录中得到了egg链接
>>> ls('develop-eggs') com.mustap.www.egg-link
但在实例1和2中没有zcml slug
>>> ls('parts', 'instance1', 'etc', 'package-includes') No directory named parts/instance1/etc/package-includes >>> ls('parts', 'instance2', 'etc', 'package-includes') No directory named parts/instance2/etc/package-includes
也没有在bin/instance1和bin/instance2中包含我们的egg路径的行
>>> code = cat('bin', 'instance1', returndata=True) >>> code.find('com.mustap.www') == -1 True >>> code = cat('bin', 'instance2', returndata=True) >>> code.find('com.mustap.www') == -1 True
但如果tractor-target-parts选项不为空
>>> data = data.replace('tractor-target-parts =', 'tractor-target-parts = instance1') >>> touch('buildout.cfg', data=data) >>> sh('./bin/buildout -o') ./bin/buildout -o ...
并且我们在指定的目标中只得到zcml slug
>>> ls('parts', 'instance1', 'etc', 'package-includes') 001-com.mustap.www-configure.zcml >>> ls('parts', 'instance2', 'etc', 'package-includes') No directory named parts/instance2/etc/package-includes
并且只更新了指定的目标的控制脚本
>>> code = cat('bin', 'instance1', returndata=True) >>> code.find('com.mustap.www') == -1 False >>> code = cat('bin', 'instance2', returndata=True) >>> code.find('com.mustap.www') == -1 True
贡献者
mustapha,作者
hannosch,小修复