, and to use pkgs = import (builtins.fetchTarball (import ./nixpkgs.nix)) {}; in shell.nix (works), but it seems like such indirect inputs won’t work in flake.nix with inputs.nixpkgs = (import ./nixpkgs.nix);:
error: expected a set but got a thunk at /nix/store/vl8kinwvl9b4k3k0f707hhkccb6y7nnl-source/flake.nix:2:3
Yeah, the flake input section is technically not written in nix, but a subset of the language. You can basically only specify flake input attrsets, precisely to prevent what you’re trying to accomplish. Flakes are designed not to perform any evaluation as part of their basic commands, otherwise things get slow, especially if you have a large dependency tree.
You should probably go the other way around and use builtins.getFlake, or only use traditional nix.
The other alternative, which I prefer for various reasons, is to circumvent flake inputs altogether and manage remote sources in stable Nix. For example (untested):
# default.nix
{
sources ? import ./npins,
}:
let
/*
Try to import dependencies managed by `npins` the way `flake.nix` would expect them.
This is not strictly required but avoids having to refactor an existing `flake.nix`.
*/
flake-import =
source:
if source ? outPath then
flake-import (import source)
else
let
evil = builtins.tryEval (source.outputs);
in
if evil.success then evil.result else source;
in
{
inputs = builtins.mapAttrs (n: s: flake-import s) sources;
}
Morally this is no loss over flake inputs, since you can still do static dependency analysis on npins/sources.json. And as opposed to flake inputs, it doesn’t flatten recursive dependencies into flake.lock, so you can control how deep you want to go.
And if you for some reason need to go the other way round and want to keep managing dependencies with flake inputs, you can use the lockfile from default.nix with my port for the original flake-compat that exposes lockfile processing as a library function:
@FedericoSchonborn that one particular flake-compat seems to be unmaintained, and isn’t solving a particular problem I ran into and tried to solve with my library: it only exposes the flake outputs baked into flake-compat, but for full control in stable Nix you only want the lockfile contents resolved to metadata and store paths.
The currently-maintained flake-compat is GitHub - edolstra/flake-compat, though it uses the flakehub silliness in the example which would be better served by the github: url.
That’s basically what flake-compat is suggesting, however, you picked the wrong node.
let
nixpkgsAttrs = (builtins.fromJSON (builtins.readFile ./flake.lock)).nodes.nixpkgs.locked;
in
is wrong because it will just pick whatever is the first nixpkgs input it runs into within the lockfile (alphabetically), and you may eventually have multiple in the lockfile due to transitive dependencies and whatnot. What you should use is
let
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
nixpkgsAttrs = lock.nodes.${lock.nodes.root.inputs.nixpkgs}.locked;
in
to ensure to get the direct value of inputs.nixpkgs.