Skip to content

Reproducible Builds — fobos.lock

The problem

Without a lock file, two developers running fobis fetch on the same fobos get different results if a dependency's default branch advanced between their fetches. The same fobos file is no longer a reproducible build recipe.

The solution: fobos.lock

After every successful fobis fetch, FoBiS writes fobos.lock next to the fobos file. It records the exact git HEAD commit SHA and a SHA-256 checksum of every fetched dependency:

ini
# fobos.lock — auto-generated by FoBiS.py fetch — do not edit by hand

[PENF]
url    = https://github.com/szaghi/PENF
commit = a1b2c3d4e5f6789012345678901234567890abcd
sha256 = deadbeefdeadbeef...
tag    = v1.5.0

[stdlib]
url      = https://github.com/fortran-lang/stdlib
commit   = 9f8e7d6c5b4a3210fedcba9876543210fedcba98
sha256   = 0102030405060708...
semver   = ^0.5
resolved = v0.5.3

Commit the lock file

bash
git add fobos.lock
git commit -m "chore: lock dependency versions"

Committing fobos.lock guarantees that every checkout — CI, collaborators, release builds — uses the exact same dependency commits.

Frozen builds (--frozen)

The --frozen flag makes fobis fetch refuse to run without a lock file and pins every dependency to the commit recorded in fobos.lock instead of performing a live clone:

bash
fobis fetch --frozen   # abort if fobos.lock is missing

Use --frozen in CI pipelines where the lock file is committed:

yaml
- name: Fetch dependencies (locked)
  run: fobis fetch --frozen

Updating the lock file

bash
# Re-fetch and update fobos.lock to latest commits
fobis fetch --update

# Commit the updated lock
git add fobos.lock && git commit -m "chore: update dependency locks"

Semver version constraints

Instead of pinning to an exact tag=, you can declare a version constraint:

ini
[dependencies]
PENF   = https://github.com/szaghi/PENF :: semver=^1.5
stdlib = https://github.com/fortran-lang/stdlib :: semver=>=0.5,<1.0

fobis fetch queries the remote tags and resolves the highest tag satisfying the constraint:

ConstraintMeaning
^1.5>=1.5.0, <2.0.0 (compatible release)
^1.5.2>=1.5.2, <2.0.0
~1.5.2>=1.5.2, <1.6.0 (patch-level)
>=1.0,<2.0explicit range
=1.5.0exact version
*any version

The resolved tag is written to fobos.lock under resolved. On subsequent non---update runs the locked resolved tag is used without re-querying the remote.

semver= cannot be combined with tag=, branch=, or rev= — they are mutually exclusive.

Lock verification

After cloning, FoBiS compares the current HEAD of each dependency against the lock file. A mismatch emits a warning (non-fatal):

Warning: dependency 'PENF' HEAD (a1b2c3d) does not match
fobos.lock (deadbeef). Run 'fobis fetch --update' to refresh.

This typically means the dependency was updated outside of FoBiS (e.g. a manual git pull inside the dep directory).