canva-public/js2nix

Wire things up in a flake

Opened this issue · 11 comments

I've read the TL;DR.

But I'm looking at a wall to climb, now.

As others have pointed out interop is cheap with: https://github.com/edolstra/flake-compat

... wall is in the context of a service provider to divnix/std#165

This comment looks like particularly relevant to your flake TL; DR; → edolstra/flake-compat#39 (comment)

Hi @blaggacao,

This comment looks like particularly relevant to your flake TL; DR; → edolstra/flake-compat#39 (comment)

From my understanding, this comment is about to don't copying the whole repo into the Nix store but this is not about what I have been talking in this comment. I was more talking about the flakes implementation and how they are coupled with git tool and rely on it to infer a diff and what files have been affected by a change set.

In this case, I don't think I grok the issue, yet.

But it also seems like the undesired behaviour is entirely attached to the use of code paths involved in the new flakes commands.

So a forward-compatible flake layout, per se, wouldn't be affected, at all.

There might be actually a couple of additional requirements to weave js2nix into an integration framework, such as not claiming hard coded contracts (on files such as packages.nix and it's output schema). But maybe that's not even actually the case but just implied (in the eye of the reader) by the Readme's posture. I haven't dug deep enough, yet.

Maybe there are some misunderstandings.

I read "Wire things up in a flake" as "Please provide a flake.nix/flake.lock for js2nix".

Together with flake-compat this shouldn't hurt monorepo users
too much, as they can continue to ignore flakes and only have the slight discomfort of having one copy
of the js2nix source code in the store. No "flake code paths", which are not already taken, should be
taken in nix/nix-daemon in this case, I think.

The results produced by js2nix should be easily usable in a flake, if the code generation is used to avoid
import from derivation.

Am I missing something?

Oh, I haven't read this in that way. I am fully on board with having flake.{nix,lock}files along the way! More than happy to review PRs if someone interested in contributing into it. Otherwise, I will try to allocate some time for that, but note, for the @Canva use case it's rather theoretical, ephemeral benefit since we don't use flakes. That is, I most likely I will do it in the blind, without relying on a particular use case, so contribution of those who use flakes in practice is very much appreciated :)

With flake.{nix,lock} and flake-compat, flake.nix would be the source of truth.

So maybe that is not a great idea, if you don't want to look at some flake documentation and doing the occasional nix --extra-experimental-features "flake nix-command" flake update command.

Having separate flake.nix and default.nix/shell.nix (no flake-compat here) would maybe diverge to fast to not be frustrating for everyone.

The only one aspect of flake.{nix,lock} + flake-compat usage I haven't thought about before is the ability to define the dependencies at the call site. The idea of flakes is that you describe dependencies of your Nix package (flake) in the repository so you don't have to deal with its dependencies at the call site, but if you want, it's easy to do with flakes as well.

This is great, however, IIUC flake-compat in default.nix file removes capability of passing dependencies with callPackage function call and will anyways read the flake.lock file to determine the project dependency closure regardless of what you passing in callPackage function call, no?

For example, at the call-site, I would like to have the run time dependency of Node.js to be the 12 version:

with import <nixpkgs> { };

let
  js2nix = callPackage (builtins.fetchGit {
    url = "ssh://git@github.com/canva-public/js2nix.git";
    ref = "main";
  }) {
    nodejs = nodejs_12-x;
  };
  nodeModules = js2nix.makeNodeModules ./package.json {
    tree = js2nix.load ./yarn.lock { };
  };
in nodeModules

But, if we use flake-compat in the default.nix, it won't be possible to override, right?

I that is correct understanding of how the flake-compat work, I would suggest to have the default.nix file as an entry point for both the project flake and for the non-flake consumers.

Meaning, the default.nix file returns a function that expects project dependencies passed thought, like any other package in the nixpkgs repository, and in the flake.nix we do callPackage of the default.nix with the dependencies declared in flake.{nix,lock} but not the other way around; i.e. when we use flake-compat in the default.nix.

This will resolve the issue with dependencies injection for non-flake consumers along with make the project a first-class flake for those who use flakes at call sites. And the most importantly we remove the divergence you have been talking above.

@typetetris, @blaggacao, what do you think?

{inputs, system}:

let
  inherit (inputs) nixpkgs js2nix;
  inherit (nixpkgs.legacyPackages.${system}) callPackage;
  js2nix' = callPackage js2nix {
    nodejs = nodejs_12-x;
  };
  nodeModules = js2nix'.makeNodeModules ./package.json {
    tree = js2nix'.load ./yarn.lock { };
  };
in nodeModules

Should * work with a top __functor outputs that makes a js2nix flake a callPackage-able package function.

* At least the nixpkgs library version of functionArgs (the implementation detail behind callPackage) is aware of functors.

Iirc, I've made a patch to flake-compat a while back to not remove functors from the output.

It removes the __functor property here https://github.com/edolstra/flake-compat/blob/master/default.nix#L193.

I am wondering, would it work if we just do pkgs.callPackage ./default.nix from flake.nix? This should remove the divergence problem and make flake and non-flake folks happy, no?

Oh, I did remove the functor, then. Must have been for another reason in the Nix CLI jungle. 😄

That approach would also work and in most cases people can operate with .overrideAttrs if they need to amend any (package function) inputs.