Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow a flake output to re-evaluate the flake with sourceInfo preserved #12388

Open
plietar opened this issue Jan 31, 2025 · 0 comments
Open
Labels
feature Feature request or proposal

Comments

@plietar
Copy link

plietar commented Jan 31, 2025

I have a flake where one output embeds self.sourceInfo (writeJSON behaves in a surprising way if outPath is present, hence the removeAttrs call):

packages.x86_64-linux.sourceInfo = pkgs.writers.writeJSON "sourceInfo.json" (builtins.removeAttrs self.sourceInfo [ "outPath" ]);

If I build and print this output, I get all the metadata I expected

$ nix build .#sourceInfo
$ cat result
{
  "dirtyRev": "c8bec8697f5dda3eb27a8703ea1004ba6bac1c8a-dirty",
  "dirtyShortRev": "c8bec86-dirty",
  "lastModified": 1738331265,
  "lastModifiedDate": "20250131134745",
  "narHash": "sha256-MIrEQ686AL6QdvsU+guE3Zh5UnL9V7mu0MZAu413R38=",
  "submodules": false
}

I now want to have a second output of my flake that is a script which when run, evaluates and builds the first attribute.
I can get a basic version of this by doing nix build .#sourceInfo

packages.x86_64-linux.print-sourceinfo = pkgs.writeShellScriptBin "print-sourceinfo" ''
  cat $(nix build --no-link --print-out-paths .#sourceInfo)
'';

The above works, but only if the current working directory is the actual flake that I want to run. I would like to be able to run this script from any source, using something as nix run github:org/repo#print-sourceinfo.

I can get pretty close to this by using self as the flake ref in the script:

outputs = { self, nixpkgs }:
  let pkgs = nixpkgs.legacyPackages.x86_64-linux; in {
    packages.x86_64-linux.sourceInfo =
      pkgs.writers.writeJSON "sourceInfo.json" (builtins.removeAttrs self.sourceInfo [ "outPath" ]);
    packages.x86_64-linux.print-sourceinfo = pkgs.writeShellScriptBin "print-metadata" ''
      cat $(nix build --no-link --print-out-paths ${self}#sourceInfo)
    '';
  };

Unfortunately, because ${self} is just a store path, this setup loses any of the Git metadata that is associated with the flake.

$ nix run .#print-sourceinfo
{
  "lastModified": 0,
  "lastModifiedDate": "19700101000000",
  "narHash": "sha256-Ze0b5N+a3RklxbLX7bEFVCOv+PSo2rr2Zq83Yd1bbhM="
}

I'd like a way to replicate this setup, but while preserving the sourceInfo metadata.

Proposed solution

Effectively I need to be able to get a reference to the current flake as a string that can be embedded into a script.
There should be a function that can get take a sourceInfo and produce a flake ref that is locked to that source, including all the associated metadata.

The CLI has the nix flake metadata command that prints a "locked URL". If this URL was exposed inside the flake, then my script could embed it and be certain to be re-evaluating itself with the same source and metadata by using nix build ${self.lockedUrl}. It's worth noting that even in the CLI, the "Locked URL" is not printed if the local Git tree is dirty.

Alternative solutions

I can actually get some of the way there by using path:${self}?rev=${self.sourceInfo.rev} as the flake reference in my script. Somehow the path flake scheme allows a ref to be specified. It does not however allow a dirtyRev to be used, which means that I cannot use this solution in the case where the Git tree has local modifications.

Additional context

My use case of having a flake output evaluate the flake itself might seemed a bit contrived. In pratice this script is used to deploy a NixOS configuration from the flake to a machine. It accepts a hostname as an argument, and when run evalutes ${self}#nixosConfigurations.$hostname and deploys it to the machine.

The overall workflow should be to run nix run github:org/repo#deploy <hostname>, which would use the deploy script and NixOS configuration found in the flake.

I do not want to embed the built system configuration into the deploy script, since we have many machines and they should be all be evaluated and built lazily when needed by the script, and not eagerly when the script is being built.


Add 👍 to issues you find important.

@plietar plietar added the feature Feature request or proposal label Jan 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Feature request or proposal
Projects
None yet
Development

No branches or pull requests

1 participant