Dank Source Tree Builder

I’ve spent the last ~6 months building a Nix+Node.js framework that is getting prepped for release.

I have a relatively standalone nugget to share though used to create source tree hierarchies from arbitrary inputs. You can feed this bad boy derivations, local paths, anything with an outPath, anything that fetchTree can parse, and any URI recognized by NPM.

I wrote this up for Node.js, but the underlying core is general purpose.

You can feed it custom routines for processing nodes, or use the two defaults which symlink files ( lndir ), or copying.

I think Eelco’s source tree abstraction might make this redundant when it’s eventually released; but since I needed something immediately I cooked up this bad boy.

The README is a good place to dive in, but I’ve got a snippet below.

let
tree = {
  # Just a store path.
  "node_modules/foo" = "/nix/store/XXXX...-foo";
  # `fetchTree' output has an `outPath' field so this works too
  "node_modules/@bar/bar-core" = builtins.fetchTree { ... };

  # Nested deps
  "node_modules/@bar/bar-core/node_modules/@bar/bar-utils" =
    builtins.fetchTree { ... };

  # With bins
  "node_modules/@blub/quux" = {
    outPath = builtins.fetchTree { ... };
    bin.quux        = "./bin/main.js";
    bin.quux-client = "./client/bin/client.js";
  };

  # local path with "normalized" bindir ( encoded as `__DIR__' ).
  # See `libpkginfo' for more info about `__DIR__'.
  "node_modules/@blub/quux-cli-extras" =
    outPath = ( builtins.path {
      path = ./custom-quux-cli;
      filter = name: type: ( baseNameOf name ) != "node_modules";
    } ).outPath;
    # Points to `./custom-quux-cli/bin'. Pay attention to the quotes.
    bin.__DIR__ = "./bin";
  };

  # From a `pkgEnt' ( see `mkNmDirFromWithSet' as well )
  "node_modules/@my-pkgs/my-ent" = myPkgSet."@my-pkgs/my-ent/0.0.1";

  # A nested dependency yanked from a `pkgSet' with an override.
  "node_modules/bar/node_modules/baz" =
    myPkgSet."baz/1.0.0".prepared.override { runScripts = ["my-script"]; };
};
# Let's just dump the tree builder as a shell script. 
# here it's wrapped in a function `installNodeModules`
treeCmd = ( mkNmDirWith { inherit tree; } ) // { __toSting = self: self.cmd; };

in stdenv.mkDerivation {
 ...
 postUnpack = ''
    node_modules_path="$PWD/$sourceRoot/node_modules";
    ${treeCmd}
    installNodeModules;
  '';
 ...
}

In any case, thought this was nifty and wanted to share. :call_me_hand:

3 Likes