Templates
OmniPackage renders the RPM .spec file and the DEB debian/ control files from Liquid templates. This page covers what's available in the template context and how to thread per-distro values into a single shared template.
Why template
A working .spec file or debian/control is mostly boilerplate identical across distros in a family — same %build recipe, same Source0, same Description. The parts that genuinely differ are small: package dependency names (qt6-base-common-devel on openSUSE vs. qt6-qtbase-devel on Fedora), optional CMake flags (Qt5 vs. Qt6), occasional tool overrides (a different compiler on an older distro).
Without templating, you'd carry a copy of the spec for every distro and drift between them. With templating, one .spec.liquid and one debian/ directory; everything that varies — names, version, maintainer, deps, custom flags — comes from config.yml per distro.
Where templates live
In config.yml:
- RPM: a single file ending in
.liquid. The rendered output goes into the rpmbuild tree as the spec file. - DEB: a directory. Every file inside ending in
.liquidis rendered (the.liquidsuffix is stripped:control.liquid→control). Files without.liquidare copied verbatim — useful forcompat, license files, scripts, etc.
A typical DEB tree contains control.liquid, changelog.liquid, rules.liquid, and compat.liquid. See the c_makefile example for a complete minimal set.
Built-in variables
Every template renders with these in scope:
| Variable | Type | Source |
|---|---|---|
version |
string | Output of the configured version_extractor |
current_time_rfc2822 |
string | Render-time timestamp; used in debian/changelog |
package_name |
string | From the build entry in config.yml |
maintainer |
string | From the build entry |
homepage |
string | From the build entry |
description |
string | From the build entry |
build_dependencies |
array of strings | From the build entry |
runtime_dependencies |
array of strings | From the build entry |
secrets |
object (string → string) | From the secrets: block; access as {{ secrets.MY_KEY }} |
source_folder_name |
string | RPM only — name of the staged source tarball directory |
Arrays render with the Liquid join filter:
BuildRequires: {{ build_dependencies | join: ' ' }}
Requires: {{ runtime_dependencies | join: ', ' }}
(RPM uses spaces, DEB uses , — the templates choose, not the engine.)
Custom per-distro variables
Any field on a build entry in config.yml beyond the known keys above is passed straight into the template context with the same name. This is the mechanism for per-distro variation.
Example from mpz — same Qt-based project compiled against Qt5 or Qt6 depending on the distro:
debian_qt5: &debian_qt5
build_dependencies: [gcc, make, cmake, qtbase5-dev, qtmultimedia5-dev]
CMAKE_EXTRA_CLI: "-DUSE_QT5=ON"
<<: *deb
debian_qt6: &debian_qt6
build_dependencies: [gcc, make, cmake, qt6-base-dev, qt6-multimedia-dev]
<<: *deb
builds:
- distro: "debian_12"
<<: *debian_qt5
- distro: "debian_13"
<<: *debian_qt6
Then in the shared spec / rules templates:
For Qt5 distros this expands to ... -DUSE_QT5=ON ..; for Qt6 distros it expands to ... .. (the extra space is harmless to cmake). One template, two distro flavors, no fork.
Custom values can be strings, integers, floats, or booleans — whatever YAML produces. They are addressed by the same key used in YAML.
Liquid basics
{{ var }}— substitute a value.{{ var | filter }}— apply a filter (join,upcase,default,size, etc.).{% if cond %}...{% endif %}— conditional block.{% for x in arr %}...{% endfor %}— loop.
Useful patterns:
{% if runtime_dependencies.size > 0 %}
Requires: {{ runtime_dependencies | join: ', ' }}
{% endif %}
Undefined variables render as empty
Referencing a variable that wasn't set anywhere does not error — it renders as an empty string (and evaluates as falsy in {% if %}). This is deliberate, so a custom variable like CMAKE_EXTRA_CLI can be set on some distros and omitted on others without conditional guards in the template.
The flip side: typos render silently. If a value isn't appearing where you expect, double-check the spelling in both config.yml and the template.