~aperezdc/webkit-releng-toolbelt

4bc32d1fb0c92fd5d22e7710a102cd71571be8ce — Adrian Perez de Castro 5 years ago 95868a7
Support nested expansions (indirection) in templates

Add support for marking the result of a variable expansion as a template
itself, which will be expanded itself using the same context variables.

Using the "*" sigil in template variable expansions will cause the
result of expanding the variable to be itself considered as a template.
This allows reusing content, as in:

  variables:
    greeting: "Hello %{person}!"
    person: "Peter"

  files:
    greet: "The greeting is: %{*greeting}"

Which will produce "The greeting is: Hello Peter!".
4 files changed, 61 insertions(+), 7 deletions(-)

M README.md
M conf/cog.yml
M conf/defaults.yml
M wkrel/util.py
M README.md => README.md +19 -1
@@ 161,7 161,7 @@ contain any alphanumeric character, dashes (`-`), and underscores (`_`). The
dot (`.`) character can be used to access subelements of variables which
behave like mappings. The following are valid examples:

- `%{date}` expands to a generatd value corresponsing to the current date.
- `%{date}` expands to a generated value corresponding to the current date.
- `%{package}` expands to the value of the `package` configuration value.
- `%{email.sender}` expands to the `sender` configuration item of the
  `email` configuration value (which is a mapping).


@@ 169,6 169,24 @@ behave like mappings. The following are valid examples:
All configuration values are made available as variables, which means that
both `%{name}` and `%{variables.name}` will expand to the same value.

The result of variable expansion can itself be a template, but its expansion
needs to be triggered explicitly by using an asterisk as prefix of the
variable name: `%{*…}`. The main usage of nested template expansion is reusing
variables as template fragments, as in the following example:

```yaml:
variables:
  tar-checksums: |
    md5 %{tar.md5sum} %{tar.filename}
    sha1 %{tar.sha1sum} %{tar.filename}
    sha256 %{tar.sha256sum} %{tar.filename}

files:
  sums: |
    Checksums for %{package} %{version}:
    %{*tar-checksums}
```


#### Variables


M conf/cog.yml => conf/cog.yml +1 -1
@@ 1,5 1,5 @@
pattern: cog-%.tar.xz
package: cog
package: Cog

variables:
  url: https://wpewebkit.org

M conf/defaults.yml => conf/defaults.yml +33 -4
@@ 1,5 1,5 @@
variables:
  -announcement-template: &-announcement-template |
  email-template: &email-template |
    %{package} %{version} is available for download at:

    %{url}/releases/%{tar.filename} (%{tar.humansize})


@@ 49,8 49,8 @@ changelog: NEWS

email:
  sender: "noreply@domain.tld"
  subject: "%{package} %{version} available!"
  template: *-announcement-template
  subject: "%{package} %{version} released"
  template: *email-template

files:
  news: |


@@ 62,4 62,33 @@ files:
       md5sum: %{tar.md5sum}
       sha1sum: %{tar.sha1sum}
       sha256sum: %{tar.sha256sum}
  md: *-announcement-template
  eml: |
    Subject: %{*email.subject}
    From: %{email.sender}
    To: %{email.recipients}

    %{*email-template}
  md: |
    ---
    layout: post
    title: %{package} %{version} released
    tags: [release]
    package: %{package}  # FIXME
    version: %{version}
    permalink: /release/%{package}-%{version}.html
    ---

    %{release-tagline}

    ### What's new in %{package} %{version}?

    %{release-notes}

    #### Checksums

    <pre>
    %{tar.filename} (%{tar.humansize})
       md5sum: %{tar.md5sum}
       sha1sum: %{tar.sha1sum}
       sha256sum: %{tar.sha256sum}
    </pre>

M wkrel/util.py => wkrel/util.py +8 -1
@@ 15,7 15,7 @@ from typing import Iterable, Optional
class Template(BaseTemplate):
    delimiter = "%"
    idpattern = None
    braceidpattern = r"(?a:[_a-z][_a-z0-9-.]*)"
    braceidpattern = r"(?a:\*?[_a-z][_a-z0-9-.]*)"

    def substitute(*arg, **kw):
        if not arg:


@@ 30,9 30,16 @@ class Template(BaseTemplate):
        def value(m):
            named = m.group("braced")
            if named is not None:
                indirection = False
                named = named.strip()
                if named[0] == "*":
                    indirection = True
                    named = named[1:]
                value = self.__resolve(chain, named.strip())
                if value is None:
                    return "%{" + named + "?}"
                if indirection:
                    value = Template(value).substitute(*arg, **kw)
                return str(value)
            if m.group("escaped") is not None:
                return self.delimiter