从模板生成文本文件的Buildout食谱
项目描述
简介
此配方可用于从(文本)模板生成文本文件。
简例
[buildout] parts = message [message] recipe = collective.recipe.template input = templates/message.in output = ${buildout:parts-directory}/etc/message mymessage = Hello, World!
在模板中,你可以使用与在 buildout 配置中相同的变量。例如,一个输入文件可以如下所示
My top level directory is ${buildout:directory} Executables are stored in ${buildout:bin-directory}
作为 buildout 语法的一个扩展,你可以直接引用当前 buildout 部分的变量。例如
My message is: ${mymessage}
功能
从版本 1.3 开始,你也可以指定输出文件的路径,如果路径不存在,则会创建该路径。
从版本 1.5 开始,你可以使用内联模板。
从版本 1.7 开始,你可以使用 genshi 文本模板。
从版本 1.9 开始,你可以使用 URL 来指定模板输入。
从版本 1.12 开始,你可以指定 timeout 作为配置 urllib2 请求的选项。
从版本 2.1 开始,你可以设置 input-encoding 和 output-encoding 来指定字符编码。
Genshi 文本模板
简例
[buildout] parts = message [message] recipe = collective.recipe.template[genshi]:genshi input = templates/message.in output = ${buildout:parts-directory}/etc/message some-option = value mymessage = Hello, World!
在模板中,你可以使用与在 buildout 配置中相同的变量,但分隔符不是冒号,而是属性访问,或者对于带有短横线的选项,是字典语法。全局 buildout 配置可以通过 parts 访问,当前部分通过 options 访问。
例如,一个输入文件可以如下所示
My top level directory is ${parts.buildout.directory} Executables are stored in ${parts.buildout['bin-directory']} Accessing the current part: ${options['some-option']}
为什么还需要另一个模板配方?
iw.recipe.template 和 inquant.recipe.textfile 声称要做同样的事情。我发现它们未提供文档,并且在实际应用中存在太多错误,而且它们都不在公共存储库中,我无法修复它们。此外,此实现利用了 buildout 变量替换代码,使其变得更加简单。
详细描述
从模板简单创建文件
让我们创建一个最小的 buildout.cfg 文件
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = template ... offline = true ... ... [template] ... recipe = collective.recipe.template ... input = template.in ... output = template ... ''')
我们创建一个模板文件
>>> write('template.in', ... '''# ... My templåte knows about buildout path: ... ${buildout:directory} ... ''')
现在我们可以运行 buildout
>>> print(system(join('bin', 'buildout'))) Installing template.
模板确实已创建
>>> cat('template') # My templåte knows about buildout path: .../sample-buildout
变量 buildout:directory 也被替换为路径。
覆盖输出文件
默认情况下,重新执行 buildout,使得输出文件被新输出文件覆盖。但是,如果你想仅在文件不存在时生成此文件,可以使用 overwrite 选项
再次检查输出文件内容
>>> cat('template') # My templåte knows about buildout path: .../sample-buildout
- 让我们更改此文件:
>>> print(system("sed 's/sample-buildout/spam-ham-eggs/g' template > out && mv out template")) <BLANKLINE>
现在让我们检查内容
>>> cat('template') # My templåte knows about buildout path: .../spam-ham-eggs
现在尝试重新执行 buildout,然后再次检查我们的文件
>>> print(system(join('bin', 'buildout'))) Updating template. >>> cat('template') # My templåte knows about buildout path: .../sample-buildout
如你所见,重新执行 buildout 导致覆盖了我们的修改文件。让我们尝试防止这种行为。因此,我们必须修改 buildout.cfg,重新执行 buildout,然后再次修改输出文件
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = template ... offline = true ... ... [template] ... recipe = collective.recipe.template ... input = template.in ... output = template ... overwrite = False ... ''') >>> print(system(join('bin', 'buildout'))) Uninstalling template. Installing template. >>> cat('template') # My templåte knows about buildout path: .../sample-buildout >>> print(system("sed 's/sample-buildout/spam-ham-eggs/g' template > out && mv out template")) <BLANKLINE> >>> cat('template') # My templåte knows about buildout path: .../spam-ham-eggs
再次检查输出文件 - 这次不应该修改
>>> print(system(join('bin', 'buildout'))) Updating template. >>> cat('template') # My templåte knows about buildout path: .../spam-ham-eggs
使用内联输入
对于非常短的脚本,将源代码直接放入 buildout.cfg 中是有意义的
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = template ... offline = true ... ... [template] ... recipe = collective.recipe.template ... input = inline: ... #!/bin/bash ... echo foo ... output = ${buildout:parts-directory}/template ... ''')
现在我们可以运行 buildout
>>> print(system(join('bin', 'buildout'))) Uninstalling template. Installing template.
应该已创建模板
>>> cat('parts', 'template') #!/bin/bash echo foo
通常文件模式会从模板复制,但也可以手动指定,这在这种情况中尤其有意义
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = template ... offline = true ... ... [template] ... recipe = collective.recipe.template ... inline = ... #!/bin/bash ... echo foo ... output = ${buildout:parts-directory}/template ... mode = 755 ... ''')
再次运行 buildout
>>> print(system(join('bin', 'buildout'))) Uninstalling template. Installing template.
模板应该具有指定的文件模式
>>> from os import stat >>> from stat import S_IMODE >>> print('%o' % S_IMODE(stat('parts/template').st_mode)) 755
使用 URL 输入
同样,你可能想从 URL 读取输入,例如
>>> import os >>> tmpfn = os.path.abspath(join('template.in')) >>> write('buildout.cfg', ... ''' ... [buildout] ... parts = template ... ... [template] ... recipe = collective.recipe.template ... url = file://%s ... output = template ... ''' % tmpfn)
为了演示这一点,我们首先创建一个模板文件
>>> write(tmpfn, ... '''# ... My templåte knows about buildout path: ... ${buildout:directory} ... ''')
现在我们可以运行 buildout
>>> lines = system(join('bin', 'buildout')).splitlines() >>> lines = [x for x in lines if not x.startswith('Not found:')] >>> print('\n'.join(lines)) Uninstalling template. Installing template.
应该已创建模板
>>> cat('template') # My templåte knows about buildout path: /sample-buildout
在变量路径中创建模板
让我们创建一个最小的 buildout.cfg 文件。这次输出应该发生在变量路径中
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = template ... offline = true ... ... [template] ... recipe = collective.recipe.template ... input = template.in ... output = ${buildout:parts-directory}/template ... ''')
现在我们可以运行 buildout
>>> print(system(join('bin', 'buildout'))) Uninstalling template. Installing template.
模板确实已创建
>>> cat('parts', 'template') # My templåte knows about buildout path: .../sample-buildout
创建缺失路径
如果需要在尚不存在的路径中创建输出文件,那么缺少的项目将为我们创建
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = template ... offline = true ... ... [template] ... recipe = collective.recipe.template ... input = template.in ... output = ${buildout:parts-directory}/etc/template ... ''') >>> print(system(join('bin', 'buildout'))) Uninstalling template. Installing template.
同时支持创建多个子目录
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = template ... offline = true ... ... [template] ... recipe = collective.recipe.template ... input = template.in ... output = ${buildout:parts-directory}/foo/bar/template ... ''') >>> print(system(join('bin', 'buildout'))) Uninstalling template. Installing template. >>> cat('parts', 'foo', 'bar', 'template') # My templåte knows about buildout path: .../sample-buildout
当输出路径发生变化时,则在卸载时删除旧路径。因此,上面创建的 etc/ 目录现在已消失
>>> ls('parts') d foo
使用其他部分的选项替换变量
当在模板中替换变量时,可能会出现对其他buildout部分的依赖。Buildout将通过确定其他部分选项的值来解决它们。为了看到这一点,我们创建了一个涉及使用变量计算的模板的buildout,而这个变量本不会在其他部分中构建
>>> write('dummy.py', ... ''' ... class Recipe(object): ... ... def __init__(self, buildout, name, options): ... options['foo'] = 'bar' ... ... def install(self): ... return () ... ... def update(self): ... pass ... ''')>>> write('setup.py', ... ''' ... from setuptools import setup ... ... setup(name='dummyrecipe', ... entry_points = {'zc.buildout': ['default = dummy:Recipe']}) ... ''')>>> write('buildout.cfg', ... ''' ... [buildout] ... develop = . ... parts = template ... offline = true ... ... [template] ... recipe = collective.recipe.template ... input = template.in ... output = template ... ... [other] ... recipe = dummyrecipe ... ''')>>> write('template.in', ... '''# ... My templåte knows about another buildout part: ... ${other:foo} ... ''')>>> print(system(join('bin', 'buildout'))) Develop: '/sample-buildout/.' Uninstalling template. Installing other. Installing template.>>> cat('template') # My templåte knows about another buildout part: bar
更新时未更改的输出文件不会被重写
如果输出内容未更改,则更新时不会重写输出文件。优点是文件的修改时间戳不会改变。(例如,systemd会注意到任何单元文件的修改时间戳,并发出有用的“提醒”,提示用户重新运行“systemctl daemon-reload”)
- 注意输出文件的mtime
>>> from os.path import getmtime >>> from time import sleep >>> orig_mtime = getmtime('template')
- 等待直到新文件有不同的mtime
>>> def mtime_tick(): ... write('test.stamp', '') ... return getmtime('test.stamp') > orig_mtime >>> wait_until('mtime_tick', mtime_tick)
- 重新运行buildout
>>> print(system(join('bin', 'buildout'))) Develop: '/sample-buildout/.' Uninstalling other. Installing other. Updating template.
- 文件的mtime没有改变
>>> getmtime('template') == orig_mtime True
- 更改模板
>>> write('template.in', ... '''# ... My template still knows about another buildout part: ... Foo is ${other:foo} ... ''')
- 重新运行buildout
>>> print(system(join('bin', 'buildout'))) Develop: '/sample-buildout/.' Uninstalling other. Installing other. Updating template.
- 文件的mtime已改变
>>> getmtime('template') > orig_mtime True
- 输出已更改
>>> cat('template') # My template still knows about another buildout part: Foo is bar
变更日志
2.2 (2021-12-01)
将端口代码和测试移植到Python 3,而不是使用不再支持的2to3。
添加对Python 3.7、3.8、3.9和3.10的支持。
停止支持Python 3.4。
2.1 (2018-07-14)
支持新的 input-encoding 和 output-encoding 选项。[fschulze]
在更新时,除非其内容已更改,否则不重写输出文件(从而保留其修改时间戳)。[dairiki]
2.0 (2017-01-17)
声称为Python 3.5提供支持,并停止支持Python 2.6。[sallner]
1.13 (2015-10-20)
与zc.buildout 1.7.1兼容。[mstaniszczak]
1.12 - 2015-07-23
添加超时配置选项。[davidjb]
修复python 3中的编码问题。[cedricmessiant]
添加覆盖选项 - 在重新执行buildout后禁用覆盖输出文件。[mstaniszczak]
1.11 - 2014-02-07
为Genshi和doctests添加Python 3支持。[mitchellrj]
在写入之前删除脚本,这样我们就可以避免当当前用户不是脚本所有者时的chmod权限错误。[alecghica]
1.10 - 2012-02-26
使用setup中的2to3标志添加Python 3支持。[mitchellrj]
1.9 - 2011-06-19
添加对URL输入的支持。使用 url =(而不是 input =)来指定URL。[aclark]
1.8 - 2010-06-08
警告!Genshi模板的向后不兼容更改。现在无法访问名称中包含短横线的部分,因此您必须使用 ${parts.partname} 或 ${parts[‘part-name’]}。此外,现在可以使用 options 访问当前部分。[fschulze]
为了防止与zc.buildout的问题,在很晚的时候导入genshi模块。[fschulze]
1.7 - 2010-05-21
添加了对genshi文本模板的支持。使用它们,请将此作为配方: recipe = collective.recipe.template[genshi]:genshi 使用点而不是冒号来分隔部分名称和选项名称。[fschulze]
1.6 - 2010-02-24
输出文件模式现在假设为八进制,如chmod。[elro]
内联模板现在可以使用内联选项指定。[elro]
1.5 - 2010-02-23
添加了明确设置输出文件模式的支持。[witsch]
添加了对内联模板的支持。[witsch]
1.4 - 2009-07-29
修复了模板中变量的替换方式,以允许buildout确定对其他部分的依赖,并正确准备它们。[tlotze]
1.3 - 2009-04-28
添加了对输出路径创建的支持。您可以这样做:
output = /path/to/target
如果中间路径项不存在,将创建它们。[ulif]
添加测试。[ulif]
1.2 - 2008-12-09
(意外的是,1.1版本被标记为1.2。所以实际上它们是相同的。)
1.1 - 2008-12-09
正确处理一行中的多个变量。来自Roman Susi的Bug报告和补丁。[wichert]
1.0 - 2008-10-16
将输入文件的模式复制到输出文件。这使得创建可执行脚本成为可能。[wichert]
在README中添加缺失的链接。[wichert]
1.0rc2 - 2008-07-04
添加一个MANIFEST.in文件,其中包含包含docs/的说明,否则该软件包将无法安装。[wichert]
1.0rc1 - 2008-07-04
初始发布。[wichert]
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解更多关于安装软件包的信息。
源分布
构建分布
集体recipe.template-2.2.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 5e668ac70fd8f5b546c06e1eab1ca143638a23c7d1c05b2040b056ed8e87cadb |
|
MD5 | 01edd899f33ed40e6e6e60b4d2bce27f |
|
BLAKE2b-256 | 501ddafddd45f1586f253b1ea9fbbdfab6fa96b4fa7ecc7b0bf4eed1fa11aaa7 |
集体recipe.template-2.2-py2.py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 9aa53a09a5b6fec56fbb2c2bcf96126a56733155c81d4e20a60d9187aff13fc3 |
|
MD5 | bcc84e91a5c5de8e25a626dc8a6bc033 |
|
BLAKE2b-256 | 04ada5940d7b619a3fca0d08f53a860c1f377938ff475c0e45895832820bcb37 |