Skip to content
mboworksPublic

About

Collection of Bazel support functionality.

Topics

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

1 watching

Forks

Repository files navigation

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, structural normalization, 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.

Collection helpers preserve associated data and compose version ordering with explicit predicates:

semver = versions.with_mode("semver")
releases = ["23.1.0", "23.1.2", "24.0.0-rc1"]
semver.sorted(releases)                                             # Ascending version order.
semver.filter(releases, exclude_requirements=semver.is_prerelease)  # Stable releases, input order.
semver.latest(releases, exclude_requirements=semver.is_prerelease)  # "23.1.2"

See filtering, sorting and picking versions for record/dictionary keys, include/exclude predicates, tie behavior, defaults and caller-controlled prerelease filtering.

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.

Runfiles

bzl/runfiles constructs the same lookup key as Bazel's $(rlocationpath label) expansion from a File inside a rule or aspect:

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

key = runfiles.key(ctx, ctx.executable.tool)

Source, generated and executable files share the same API. Include the file and its dependencies in the launcher's runfiles, then resolve the key with a runtime runfiles library. For build actions, use the tool's FilesToRunProvider instead.

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.8.0")

Dependencies

  • bazel_skylib.

About

Collection of Bazel support functionality.

Topics

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages