On this page
Versions
A pekit build is almost always about a version of some upstream software. The
recipe declares where source of a given version comes from and how to name the
packages it produces; the invocation decides which versions are in scope. This
page covers the version grammar pekit accepts, the {{...}} variables that carry
version components into your recipe, and how the --version, --latest, and
--all-versions selectors resolve against a source.
Version forms
A version is written as:
MAJOR[.MINOR[.PATCH]][-PRERELEASE][+BUILDMETA]
Only MAJOR is mandatory. Minor and patch are each optional but ordered — you
cannot write a patch without a minor. The optional -PRERELEASE and +BUILDMETA
tails may each contain digits, ASCII letters, dots, and hyphens.
| Written version | major | minor | patch | prerelease | buildmeta |
|---|---|---|---|---|---|
2 |
2 |
||||
2.43 |
2 |
43 |
|||
2.43.1 |
2 |
43 |
1 |
||
1.21.0-rc.1 |
1 |
21 |
0 |
rc.1 |
|
1.21.0+build.5 |
1 |
21 |
0 |
build.5 |
|
1.21.0-rc.1+bld |
1 |
21 |
0 |
rc.1 |
bld |
Anything that does not match this grammar is rejected with an invalid_version
error. Comparison and ordering are numeric on major/minor/patch (a missing
component counts as 0), with the prerelease string compared lexically to break
ties.
Version template variables
Six variables expose the parsed components of the selected version. They render
anywhere pekit expands {{...}} templates in a recipe — most importantly in
source refs and URLs, and in
package version and metadata fields.
| Variable | Expands to |
|---|---|
{{version}} |
the version exactly as written |
{{major}} |
the major component |
{{minor}} |
the minor component |
{{patch}} |
the patch component |
{{prerelease}} |
the prerelease tail, or empty |
{{buildmeta}} |
the build-metadata tail, or empty |
[source.git]
url = "https://github.com/example/tool.git"
ref = "v{{version}}"
Two rules govern rendering:
- Referencing a component the version does not have is an error.
{{version}}fails when no version is selected at all;{{minor}}and{{patch}}fail when the selected version stops short of that component (for example{{patch}}against2.43).{{prerelease}}and{{buildmeta}}are the exception — they render as empty text when absent rather than erroring. - Unknown variables are an error. Any
{{name}}that is not one of the six above (or the multi-package{{multipack}}token) is rejected. There is no silent pass-through.
Version variables do not apply to shell target commands. A
commandin a build/test/install target receives version data through thePEKIT_VERSION,PEKIT_VERSION_MAJOR,PEKIT_VERSION_MINOR,PEKIT_VERSION_PATCH,PEKIT_VERSION_PRERELEASE, andPEKIT_VERSION_BUILDMETAenvironment variables instead — see recipe anatomy.
Selecting versions
Three mutually exclusive flags choose the version set. Supplying more than one is
rejected with --version, --latest, and --all-versions are mutually exclusive.
| Flag | Selects | Needs an enumerable source? |
|---|---|---|
--version <selector> |
exact version(s), or a semver constraint | only for constraints |
--latest |
the single highest available version | yes |
--all-versions |
every available version | yes |
| (none) | an unversioned build (no {{version}} available) |
no |
Enumerable sources are those pekit can list versions for: a [source.git]
source (via git ls-remote --tags) or a [source.url] source (by fetching the
listing directory). --latest, --all-versions, and any constraint require one;
against a non-enumerable source they fail with selected source cannot enumerate versions.
--version as an exact selector
The simplest form is one or more exact versions, comma-separated:
pekit build tool --version 2.43.1
pekit build tool --version 2.43.1,2.42.0
A comma-separated list without spaces is treated as a set of exact versions. When the source is reproducible and enumerable, each written version is matched against the versions the source actually publishes using the trailing-zero ladder described below.
--version as a constraint
A --version value that contains a space or a comparison operator
(<, >, =, <=, >=) is treated as a constraint and takes the
enumeration path. Constraints filter the enumerated set:
pekit build tool --version ">= 2.40"
pekit build tool --version ">= 2.40, < 3.0"
Multiple constraints (comma- or space-separated) are ANDed together. The ~ and
^ operators are not supported and produce
unsupported version constraint operator. A bare * matches everything.
--latest and --all-versions
pekit build tool --latest # highest available version only
pekit package tool --all-versions # every available version
--latest picks the single greatest version after enumeration and filtering.
--all-versions selects the whole set.
The trailing-zero ladder
Upstreams are inconsistent about trailing zeros: one project tags v2.43.0,
another tags v2.43, a third tags v2. So when you ask for an exact version
against a reproducible, enumerable source, pekit does not demand a character-exact
tag. It builds a ladder of candidates from your written version, most specific
first, and picks the first candidate the source actually offers:
| You write | Candidates tried, in order |
|---|---|
2.43.0 |
2.43.0, then 2.43 |
2.0.0 |
2.0.0, then 2.0, then 2 |
2.0 |
2.0, then 2 |
2.43.1 |
2.43.1 only |
Only trailing zero components are dropped — a non-zero patch or minor is never
elided. The ladder is also skipped entirely when the version carries a
prerelease or build-metadata tail: 1.21.0-rc.1 is only ever matched as written.
If no candidate is available (or the source is not reproducible/enumerable), the
version you wrote is used verbatim.
The ladder applies to the exact-selector path only. --latest,
--all-versions, and constraints work on the enumerated set directly and do not
ladder.
Source version caps
A source can declare a hard ceiling (or floor) on the versions a recipe will ever
build, independent of what the invocation asks for. Set versions under the
source table:
[source.git]
url = "https://github.com/example/tool.git"
ref = "v{{version}}"
versions = ">= 1.0, < 3.0"
The cap uses the same constraint grammar as --version. It is applied on both
paths:
- On the enumeration path (
--latest,--all-versions, constraints) the cap filters the available set before the selector runs, so--latestreturns the highest version within the cap. - On the exact-selector path the cap filters the versions you named. If every
named version falls outside the cap the build fails with
selected exact versions were filtered out by source version cap.
An empty result after capping is always an error — a cap that excludes everything is treated as a misconfiguration, not a no-op.
Local builds
When the source resolves to a local directory, there is
nothing to enumerate. Local sources therefore require an exact --version;
--latest, --all-versions, and constraints fail with local sources require an exact --version.
If you build locally without giving a --version at all, pekit stamps the build
with the sentinel version 0.0.0-localdev so that {{version}} and the
PEKIT_VERSION* variables still resolve. This makes local development builds work
without inventing a version number, while keeping them clearly distinguishable
from real releases.
Single-version commands
build, package, and publish are happy to run across many versions — pass
--all-versions and pekit plans one build per version.
test and install are not. They require the selector to resolve to exactly
one version; if it resolves to more, the command fails with test requires a single resolved version (or install requires ...). Use an exact --version or
--latest for these commands.
Where to go next
For where a selected version's source tree comes from, read Sources.
For how version components render into package names and metadata, read Packaging files.
For the full flag surface behind --version, --latest, and --all-versions, read Invocation and flags.