Note
Claude Code generated summary of how https://github.com/ekala-project/eka-ci does building of drvs.
This document explains how EkaCI discovers, lists, and builds Nix derivations.
nix-eval-jobs <file.nix>Can also work with flakes:
nix-eval-jobs --flake <flake-ref>#<attr>JSON stream, one derivation per line:
{
"attr": "grpc",
"attrPath": ["grpc"],
"drvPath": "/nix/store/qkgrb8v2...-grpc-1.70.0.drv",
"name": "grpc-1.70.0",
"outputs": {"out": "/nix/store/rn3nlskr54...-grpc-1.70.0"},
"system": "x86_64-linux"
}See: backend/server/src/nix/nix_eval_jobs.rs:52-54
let
pkgs = import <nixpkgs> {};
in
{
inherit (pkgs) stdenv;
}See: examples/simple_job/stdenv.nix
For each drv from nix-eval-jobs:
nix-store --query --requisites <drv-path>Returns all .drv files needed (filters out non-drv inputSrcs).
See: backend/server/src/nix/mod.rs:130-131
nix-store --query --graph <drv-path>Returns graphviz format showing edges between drvs. Parsed to extract (reference, referrer) pairs where referrer depends on reference.
See: backend/server/src/nix/mod.rs:197-198
nix derivation show <drv-path>Returns JSON with system and requiredSystemFeatures.
See: backend/server/src/nix/derivation_show.rs:38-39
All derivations from nix-eval-jobs output + their full dependency graphs.
A drv is buildable only when ALL direct dependencies have successfully built:
deps.into_iter()
.all(|x| x.build_state == DrvBuildState::Completed(DrvBuildResult::Success))See: backend/server/src/db/model/build_event.rs:278-280
-
Initial check (
backend/server/src/scheduler/ingress.rs:76)- Each drv from eval →
IngressService - Checks
is_drv_buildable() - If buildable → send to
BuildQueue - If not → stays in database, waiting
- Each drv from eval →
-
Build execution (
backend/server/src/scheduler/build/builder_thread.rs:105-107)nix-build <drv-path> --builders <builder-config>
- Runs with configured max_jobs in parallel per platform
- Default: 4 parallel builds per local builder
-
After successful build (
backend/server/src/scheduler/recorder.rs:107-111)- Get all downstream drvs (things that depend on this)
- Re-check each one: "are you buildable now?"
- If yes → queue for building
-
After failed build
- Mark as failed in database
- Downstream drvs remain unbuildable (dependency failure)
Builds route to platform-specific queues based on drv's system attribute:
system = "builtin"→ routes to default platform- Otherwise → routes to matching platform queue
See: backend/server/src/scheduler/build/queue.rs:72-76
Round-robin across available builders for that platform.
See: backend/server/src/scheduler/build/system_queue.rs:47-51
Bottom-up, dependency-first, maximally parallel
- Leaf dependencies (no deps) build first
- As each completes, unlocks downstream drvs
- All buildable drvs run concurrently (up to max_jobs limit)
- No drv builds until ALL its dependencies succeed
- If any dependency fails → downstream drvs never build
This is like Hydra's approach - ensures you don't waste time building things that will fail anyway!
nix-instantiate --eval --raw -E "builtins.currentSystem"See: backend/server/src/scheduler/build/queue.rs:92-94
nix config showParse output for system = ... line.
See: backend/server/src/scheduler/build/builder.rs:105-106