Skip to content

Lockfile (ip.lock) — lockfile.py

The generated, committed record of a resolve: the exact Vlnv chosen for every package, each with an integrity checksum and its source. Committing it gives reproducible, verifiable builds (the Cargo / Orbit / Go model). Pure module.

The ip.lock format

TOML (so it reads like ip.toml), with a schema version and a [[package]] array sorted by VLNV for a stable, diff-friendly file:

# Auto-generated by hdlpkg. Do not edit by hand.
version = 1

[[package]]
vlnv     = "acme:common:fifo:1.0.0"
source   = "path:examples/fifo"
checksum = "sha256:1f3d…"

source records where the core came from (e.g. path:… for a local registry); checksum is the packed-content digest of the core — the same digest the cache keys on. A core on the opaque version scheme also carries a scheme = "opaque" line so its non-SemVer version round-trips on parse. A package may appear at more than one version when the resolve used isolate_namespaces (the [[package]] array simply lists each).

Data model

  • LockedPackagevlnv: Vlnv, source: str, checksum: str.
  • Lockfilepackages: tuple[LockedPackage, ...], lockfile_version: int.
Member Description
Lockfile.from_resolution(resolution, sources=…, checksums=…) Build from a Resolution, attaching known source/checksum by VLNV.
to_toml() -> str Render deterministic TOML (sorted packages).
Lockfile.from_toml(text) / from_path(path) Parse; raises LockfileError.
verify(checksums) Check provided digests against the locked ones — fails closed on a missing or mismatched checksum.
matches_resolution(resolution) -> bool True if the lockfile pins exactly the VLNVs a resolution selected.

from_toml(to_toml(x)) == x round-trips. Parsing rejects an unknown schema version or a malformed [[package]].

Helper: sha256_digest(data: bytes) -> str returns the canonical sha256:<hex> form used everywhere (lockfile, cache, registry).

Errors

LockfileError — malformed TOML, unsupported schema version, bad vlnv, or an integrity failure in verify.

Example

from hdlpkg import Lockfile

lock = Lockfile.from_path("examples/uart/ip.lock")
# Re-fetch the cores, compute their digests, and fail closed on any mismatch:
lock.verify({pkg.vlnv: recompute_digest(pkg.vlnv) for pkg in lock.packages})

hdlpkg resolve writes the lockfile; hdlpkg install writes it and then verifies every fetched core against it. For reproducible builds, hdlpkg install --locked and hdlpkg gen --locked consume the committed lockfile without re-resolving (failing if it is missing). See the CLI page.