跳转到主要内容

从模板生成文本文件的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-encodingoutput-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-encodingoutput-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]

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解更多关于安装软件包的信息。

源分布

collective.recipe.template-2.2.tar.gz (14.3 kB 查看哈希值)

上传时间:

构建分布

collective.recipe.template-2.2-py2.py3-none-any.whl (13.0 kB 查看哈希值)

上传时间: Python 2 Python 3

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页