openlang

tryEval passed a package I had broken on purpose

Wrote a small sweep over an overlay that wraps each package in builtins.tryEval and lists the ones that fail. It reported everything as fine, including one I had broken on purpose with a throw in its dependency list.

The manual is clear about it once you read the whole entry. tryEval evaluates shallowly. A package is an attribute set, so reaching that form is enough to succeed, and nothing inside it gets forced.

let
  pkg = { name = "demo"; deps = throw "broken on purpose"; };
in {
  shallow = (builtins.tryEval pkg).success;
  deep = (builtins.tryEval (builtins.deepSeq pkg pkg)).success;
}

With --strict that gives shallow = true and deep = false. The rest of the entry matters as well. It only catches throw and assert, so an abort or a type error from a builtin stops the whole sweep instead of marking one package. The sweep as written answered a narrower question than its name suggests, and I'm not yet sure what the right thing to force is for real packages.

The conversation continues 4

Follow the reasoning
  1. Permalink

    Would deepSeq on a real package even be a good idea? A derivation's attribute set points at its dependencies, which are derivations with attribute sets of their own, and so on through a big part of the package set. Forcing all of that to check one package sounds like it checks far more than you asked, and then fails for reasons that belong to some other package.

  2. Permalink

    It would, which is why I've moved to forcing drvPath instead. (builtins.tryEval pkg.drvPath).success makes the evaluator instantiate the derivation, which needs what its inputs need for their own instantiation and nothing that only lives in other attributes. My broken package now shows up as failing. One qualification. This forces only what instantiation reads, so a throw hiding in something that never reaches the derivation, a passthru attribute for example, still passes.

  3. Permalink

    Settle what the sweep reports first. "Every listed package can be instantiated" needs drvPath. "Every name in the overlay evaluates to something" is answered by the shallow version, and the two reports look identical in a list.

  4. Permalink

    A successful drvPath means the .drv files can be written, not that the builder succeeds when the derivation is realised. A sweep that reports "broken packages" should say which of the two it checked.

Other sides of the same question

  1. for_each keys are addresses, not labels

    A for_each key isn't a label. It's half of the resource address, terraform_data.queue["prod-orders"], and the state tracks th…

    Replies 6hcl
  2. A stopped shell job is not a finished one

    Got a question about a supervisor rule that treats a stopped process as a finished one, and a tiny repro makes the problem ob…

    Replies 17bashpython
  3. Keep loops and conditions out of build.gradle

    Ran into a build.gradle where half the logic lived in closures that had their delegate reassigned at runtime. Took a while to…

    Replies 6groovy