bzl 0.7.0

MBO Works bzl, a Bazel support library MBO Works

Release website · Infrastructure and publishing

This library provides Bazel Starlark functionality meant to help in maintaining other libraries.

Test

The following libraries are implemented:

Versions

bzl/versions provides version parsing, precedence comparisons, release-component
selection, compatible-release checks and wildcard matching. Requirement strings support ANDed
clauses and version-function expressions.

load("@mboworks_bzl//bzl/versions:versions.bzl", "versions")

versions.major("23.2.1")                               # 23
versions.prefix("23.2.1", 2)                           # "23.2"
versions.components("23.2", end=4, pad=True)           # "23.2.0.0"
versions.compatible("1.4.8", "1.4.5")                  # True
versions.matches("1.2.3", "1.2.*")                     # True
versions.component_count("1.2.0.0-rc1")               # 4
versions.component("1.2.3.4", -1)                     # 4
versions.prerelease("1.2.3-rc1")                       # "rc1"
versions.is_prerelease("1.2.3-rc1")                    # True
versions.build("1.2.3+001.linux")                     # "001.linux"
versions.local("1.2+Ubuntu-01")                       # "ubuntu.1"
versions.check_all_requirements("23.2.1", "major()==23,minor()>=2", mode="semver")  # True
versions.check_one_requirement("23.2.1", "prefix(2)==23.2", mode="semver")      # True
Mode Behavior
legacy Historical parsing and comparisons: 1.2 < 1.2.0; rc1 and rc.1 normalize alike
semver SemVer suffix precedence with variable-length, zero-padded releases: 1.2 == 1.2.0; rc1 differs from rc.1
pep440 Python version normalization and specifiers, including epochs, pre/post/dev releases and local labels

Existing parsing/comparison APIs default to legacy; component helpers, compatible and matches
default to semver; Python-only local defaults to pep440. Pass a mode explicitly when sharing
parsed values or requirements. In Python
mode, direct version precedence and requirement clauses have different rules: 1.0.post1 sorts
after 1.0, but does not satisfy >1.0.

Requirements use <, <=, >, >=, ==, !=, ~= and the library's !~=, ~~=, !~~=
extensions. ~=1.2 permits compatible 1.x releases from 1.2; ~~=1.2.* selects the 1.2 prefix with
a lower bound at 1.2. ==1.2.* is prefix matching without that extra lower bound. Function calls require parentheses. Bare identifiers read a caller-supplied constants dictionary;
major==23 works when that dictionary binds major, while major()==23 always calls the library
helper. Functions accept an implied candidate, such as components(start=1,end=3)==2.1.
Introspection expressions also support typed results: is_prerelease()==True,
has_prerelease_prefix("rc")==True, and prerelease()=="rc1". Every nested call inherits the
checker's mode, regardless of the standalone helper's default. Python mode treats development
releases as prereleases; prerelease extraction returns only the Python pre segment.

Clients can choose a consistent default for the complete API without changing global state:

semver = versions.with_mode("semver")
semver.eq("1.2", "1.2.0")                             # True
semver.check_one_requirement("1.2.3-rc1", 'prerelease()=="rc1"')  # True
semver.eq("1.2", "1.2.0", mode="legacy")               # False: explicit call override

The returned immutable object preserves every function and option; explicit per-call modes take
precedence, and nested expression calls inherit the checker's effective mode. The original
versions object retains its historical defaults.

candidate = "23.2.1"
versions.check_all_requirements(
    candidate,
    "major==23,minor>=2",
    constants={"major": versions.major(candidate), "minor": versions.minor(candidate)},
    mode="semver",
)  # True

Bindings also work inside calls, such as prefix(width). Parsing retains references; callers can
reuse parsed requirements and supply fresh bindings for each candidate. Unknown names fail when
checked, and a constant never replaces a callable function.

The versions reference documents every API, all three modes, parsing/normalization,
metadata, compatible-release precision, function arguments, errors and prerelease behavior. The
modes use SemVer and the
Python version specification
with the documented differences and extensions.

Paths

bzl/paths provides lexical normalization, parent collapse, joining, absolute-path
tests and trailing-separator helpers. Choose Unix defaults or _windows variants explicitly;
results do not depend on the Bazel host.

load("@mboworks_bzl//bzl/paths:paths.bzl", "paths")

paths.normalize("a/./b/../c")                 # "a/b/../c"
paths.normalize("a/./b/../c", collapse=True)  # "a/c"
paths.join("a/b", "/c")                      # "a/b/c"
paths.join_respect_absolute("a/b", "/c")     # "/c"
paths.normalize_windows("C:/a//b")            # "C:\\a\\b"
paths.ensure_trailing_slash("a//b/")          # "a/b/"

normalize removes redundant separators and . but preserves .. unless collapse is requested.
join keeps earlier components; join_respect_absolute resets at the last absolute part. Windows
mode treats C:foo as C:\foo, so Windows drive-relative semantics are unsupported. These
functions manipulate strings and do not resolve symlinks or inspect the filesystem.

The paths reference documents all generic and Windows APIs, root/UNC handling,
empty values, joining rules, collapse behavior and trailing-separator fallbacks.

Installation

The library is available as a Bazel module (bzlmod) and supports macOS, Ubuntu
and Windows with Bazel versions 7.x, 8.x and 9.x (other systems are not tested).
However, future versions may drop Windows support.

For MODULE.bazel

See mboworks/bzl releases to replace the version number.

bazel_dep(name = "mboworks_bzl", version = "0.5.1")

Dependencies