Skip to content

Lock Command

The lock command walks every dependency in fastc.toml, fetches it into the shared cache, computes its content sha256, and writes the result into fastc.lock. It's the verifier's source of truth.

Think of it as cargo update with content-hash verification: every dep is anchored against the exact bytes that were fetched, and every subsequent build cross-checks against that anchor.

Usage

fastc lock [OPTIONS]

Options

Option Description
--force Re-hash every dependency and overwrite the recorded sha256, even if no manifest entry changed. Use after an upstream rewrites a rev (force-push) and you've decided the new contents are safe.
-h, --help Print help

Behavior

For each git dep in fastc.toml:

  1. Fetch. No-op if the dep is already in the shared cache.
  2. Hash. Walks the tree (sans .git/) and computes a lowercase hex sha256.
  3. Verify or write. If fastc.lock already has a sha256 for this dep and --force is not set, the computed value is compared to the recorded one. A match prints unchanged: <short-hash> and moves on. A mismatch aborts the whole lock operation with an error pointing at the offending dep — that's the alarm bell for an upstream tree changing under you.
  4. Record. With --force, or when the dep wasn't previously locked, the new sha256 is written into fastc.lock.

Path deps ({ path = "..." }) are skipped — there's no upstream to attest to, and the build verifies them by recompilation instead.

The fastc.lock Schema

# This file is auto-generated by fastc. Do not edit.
# Commit this file to version control for reproducible builds.

[[package]]
name = "fastc-core-cli"
version = "0.1.0"
source = "git+https://github.com/Skelf-Research/fastc-core-cli?rev=<commit-sha>"
resolved = "<commit-sha>"
sha256 = "9b1f3c5e7d2a8b4f6c0e1d2a3b4c5d6e7f8091a2b3c4d5e6f7a8b9c0d1e2f3a4b"

Fields:

Field Description
name Dep name as it appears under [dependencies] in fastc.toml.
version The dep's own [package].version, read from its manifest.
source git+<url>?rev=<commit> form. Stable across invocations.
resolved The resolved git commit (40-char SHA), or the rev string if no commit lookup was possible. Omitted when neither is available.
sha256 Content-tree sha256, lowercase hex, recorded at fetch time.

Entries are sorted alphabetically by name for deterministic output.

The Integrity Story

fastc build walks every entry in fastc.lock before compiling:

  1. Re-hash the cached vendor copy under .fastc/vendor/<name>/ (or the shared cache).
  2. Compare against the recorded sha256.
  3. Refuse to proceed on mismatch.

No silent stale builds. If a dep's tree no longer matches the locked hash, the build fails loudly and points at the offending dep. The user's choices are to either re-lock (if they intended the change) or audit the diff before approving.

The manifest can also carry a sha256 field; when both manifest and lockfile record a hash, both must agree. That's the supply-chain double-check: a malicious actor would need to mutate both files.

Relationship to the Build Cache

The build cache key includes a dep_content_hash field — a sha256 derived from concatenating every locked dep's sha256 in name-sorted order. The implication:

  • Changing a single dep's rev (and re-running fastc lock) flips the whole project's dep_content_hash.
  • A flipped dep_content_hash invalidates every cached C artifact for the project on this machine.
  • Two checkouts of the same source on different machines with the same fastc.lock produce byte-identical C and share cache entries.

See compile.md for the broader build-cache picture.

Worked Example: Green Path

A project with one dep:

# fastc.toml
[package]
name = "my-app"

[dependencies]
fastc-core-cli = { git = "https://github.com/Skelf-Research/fastc-core-cli", rev = "v0.1.0", sha256 = "9b1f3c5e..." }

After fastc lock:

Locking dependency: fastc-core-cli
  unchanged: 9b1f3c5e
Updated fastc.lock

Exit code: 0. fastc.lock already had a matching sha256, so no I/O needed to land. This is the steady-state CI pattern.

Worked Example: Forced Re-anchor

An upstream re-tagged v0.1.0 to a different commit:

fastc lock
Locking dependency: fastc-core-cli
error: dependency 'fastc-core-cli': fetched tree no longer matches the recorded
sha256 (a1b2c3d4 != 9b1f3c5e). Re-run with `--force` if this is intentional.

Exit code: 1. The lock file is now out of sync with the fetched tree — either upstream was rewritten or the local cache is corrupt. After auditing the diff:

fastc lock --force
Locking dependency: fastc-core-cli
  sha256: a1b2c3d4e5f6...
Updated fastc.lock

Exit code: 0. Commit the updated fastc.lock alongside whatever else prompted the version bump.

CI Pattern

There is no --check flag yet. The CI-equivalent recipe is:

fastc lock
git diff --exit-code fastc.lock

If fastc lock leaves fastc.lock unchanged, the working tree stays clean and git diff --exit-code returns 0. If lock state drifted (someone edited fastc.toml without re-running fastc lock), the diff is non-empty and CI fails. A first-class --check is on the v1.x roadmap.

See Also

  • Add — the front door for adding a new dependency. Runs lock for you after appending the entry.
  • Compile — how dep_content_hash feeds into the build cache key.
  • fastc-core — the standard library shipped as individually-locked git deps.