simplify graph methods & add more tests for fileSystem

This commit is contained in:
Johannes Kirschbauer 2024-01-19 12:47:18 +01:00 committed by mergify[bot]
parent 4f2a64a66f
commit df26fb319f
6 changed files with 365 additions and 75 deletions

View File

@ -11,7 +11,15 @@ A collection of tools needed to interact with graphs (i.e. A dependencyTree)
# Params
- graph :: { ${path} :: [ [ string ] ] }
- Graph :: {
${name}.${version} :: {
dependencies = {
${dep.name}.version = String;
};
dev :: Bool;
};
};
GenericGraph; An AttrSet of nodeIds, pointing to neighboring nodes. (could be cyclic).
- roots :: [ String ]
@ -102,46 +110,60 @@ A collection of tools needed to interact with graphs (i.e. A dependencyTree)
}
}
*/
getFileSystem = pdefs: pdefs':
getFileSystem = graph: sanitizedGraph:
l.foldl' (
/*
set :: {
sanitziedGraphEntry :: {
name ::
version ::
dev ::
isRoot ? :: true;
key :: [];
}
*/
res: set: let
filteredSet = l.filterAttrs (_: value: value.info.initialState == "dist") pdefs.${set.name};
res: sanitizedGraphEntry: let
/*
filteredSet :: graph
Example:
All versions of "next" that are in the dist state.
*/
distVersions = l.filterAttrs (_version: e: e.info.initialState == "dist") graph.${sanitizedGraphEntry.name};
in
res
// l.foldl' (
acc: version: let
entry = filteredSet.${version};
// l.foldlAttrs (
acc: version: entry: let
pdef = graph.${sanitizedGraphEntry.name}.${version};
in
acc
// l.foldl' (res: path:
if entry.info.allPaths.${path}
// l.foldlAttrs (fileSystem: path: pathInfo:
if pathInfo
then
res
// {
${path} = {
source = entry.dist;
bins =
l.mapAttrs' (name: target: {
name = (builtins.dirOf path) + "/.bin/" + name;
value = path + "/" + target;
})
pdefs.${set.name}.${version}.bins;
};
}
else res) {} (l.attrNames (entry.info.allPaths))
) {} (l.attrNames filteredSet)
fileSystem
// getFileSystemInfo path pdef entry
else fileSystem) {} (entry.info.allPaths)
) {}
distVersions
) {}
pdefs';
sanitizedGraph;
getFileSystemInfo = path: pdef: entry: let
info = {
${path} = {
source = entry.dist;
bins =
l.mapAttrs' (name: target: {
name = (builtins.dirOf path) + "/.bin/" + name;
value = path + "/" + target;
})
pdef.bins;
};
};
in
info;
in {
inherit
sanitizeGraph

View File

@ -152,20 +152,12 @@
rinfo = info // {inherit fileSystem;};
name = plent.name or lock.name;
fileSystem = graphUtils.getFileSystem pdefs (info.pdefs' {
graph = pdefs;
root = {
inherit name;
inherit (plent) version;
};
fileSystem = graphUtils.getFileSystem pdefs (utils.getSanitizedGraph {
inherit plent pdefs;
});
fileSystemProd = graphUtils.getFileSystem pdefs (info.pdefs' {
graph = pdefs;
root = {
inherit name;
inherit (plent) version;
};
opt = {
fileSystemProd = graphUtils.getFileSystem pdefs (utils.getSanitizedGraph {
inherit pdefs plent;
filterTree = {
dev = false;
};
});

View File

@ -66,7 +66,6 @@ in {
specialArgs
;
})
fileSystem
pdefs
;
};

View File

@ -72,12 +72,42 @@
# One source drv must potentially be installed in multiple other (nested) locations
options.info.allPaths = l.mkOption {
type = t.attrsOf t.bool;
};
options.info.pdefs' = l.mkOption {
type = t.raw;
description = ''
In case of conflicting versions a dependency must be installed in multiple nested locations.
In this example: Because the root "node_modules/ansi-regex" is a different version.
The current version must be installed privately if anyone depdends on it.
{
"node_modules/cliui/node_modules/ansi-regex" = true;
"node_modules/wrap-ansi/node_modules/ansi-regex" = true;
"node_modules/yargs/node_modules/ansi-regex" = true;
};
npm usually already resolved this, can be manually adjusted via this option.
'';
};
options.info.fileSystem = l.mkOption {
type = t.raw;
type = t.nullOr t.raw;
default = null;
description = ''
A json serializable attribute-set.
Holds all directories and bin symlinks realized the build script.
Example:
```nix
{
"node_modules/tap-dot" = {
bins = {
"node_modules/.bin/tap-dot" = "node_modules/tap-dot/bin/dot";
};
source = «derivation tap-dot.drv»;
};
# ..
}
```
'';
};
/*
@ -135,6 +165,16 @@ in {
*/
pdefs = {
type = t.attrsOf (t.attrsOf (t.submodule pdefEntryOptions));
description = ''
Also known as 'graph'.
Holds all information, including cyclic references.
Use this structure to access meta information from the lockfile.
Such as bins, path etc.
Can be JSON serialized.
'';
};
/*
@ -143,24 +183,24 @@ in {
${nodePath} :: Derivation
}
*/
fileSystem = {
type = t.nullOr (t.attrsOf (t.submodule {
options.source = l.mkOption {
type = t.nullOr dreamTypes.drvPartOrPackage;
};
options.bins = optBins;
}));
# options.bins = l.mkOption {
# type = t.attrsOf (t.submodule {
# options.name = l.mkOption {
# type = t.str;
# };
# options.target = l.mkOption {
# type = t.str;
# };
# });
# };
# }));
# default = null;
};
# TODO: Make lazy enough. then replace info.fileSystem with this
# fileSystem = {
# type = t.nullOr (t.attrsOf (t.submodule {
# options.source = l.mkOption {
# type = t.nullOr dreamTypes.drvPartOrPackage;
# };
# options.bins = optBins;
# }));
# options.bins = l.mkOption {
# type = t.attrsOf (t.submodule {
# options.name = l.mkOption {
# type = t.str;
# };
# options.target = l.mkOption {
# type = t.str;
# };
# });
# };
# }));
# };
}

View File

@ -1,6 +1,5 @@
{lib}: let
l = lib // builtins;
# cfg = config.WIP-nodejs-builder-v3;
nodejsLockUtils = import ../../../lib/internal/nodejsLockUtils.nix {inherit lib;};
graphUtils = import ../../../lib/internal/graphUtils.nix {inherit lib;};
@ -19,15 +18,42 @@
path == ""
then "source"
else "dist";
};
pdefs' = {
graph,
root ? {
name = plent.name or "nixpkgs-docs-example";
version = plent.version;
},
opt ? {},
/**
A Convinient wrapper around sanitizeGraph
which allows to pass options such as { dev=false; }
*/
getSanitizedGraph = {
# The lockfile entry; One depdency used as a root.
plent,
# The dependency 'graph'. See: sanitizeGraph
pdefs,
/**
Drops dependencies including their subtree connection by filter attribute.
for example:
```
filterTree = {
dev = false;
};
```
Will filter out all dev dependencies including all children below dev-dependencies.
Which will result in a prod only tree.
*/
filterTree ? {},
}:
let
root = {
name = plent.name;
version = plent.version;
};
graph = pdefs;
in
graphUtils.sanitizeGraph {
inherit root graph;
pred = (
@ -39,10 +65,9 @@
else value == e.${name}
)
true
opt
filterTree
);
};
};
in {
inherit getInfo;
inherit getInfo getSanitizedGraph;
}

View File

@ -0,0 +1,212 @@
{lib ? import <nixpkgs/lib>, ...}: let
utils = import ../../../lib/internal/graphUtils.nix {inherit lib;};
in {
test_simple = let
graph = {
"a"."1" = {
dist = "<Dist Derivation>";
dependencies = {};
dev = false;
bins = {
};
info = {
initialState = "dist";
allPaths = {
"node_modules/a" = true;
};
};
};
};
sanitizedGraph = utils.sanitizeGraph {
inherit graph;
root = {
name = "a";
version = "1";
};
};
fileSystem = utils.getFileSystem graph sanitizedGraph;
in {
expr = fileSystem;
expected = {
"node_modules/a" = {
bins = {};
source = "<Dist Derivation>";
};
};
};
test_cyclic_dependency = let
graph = {
"a"."1" = {
dist = "<A Derivation>";
dependencies = {
b.version = "1";
};
dev = false;
bins = {};
info = {
initialState = "dist";
allPaths = {
"node_modules/a" = true;
};
};
};
"b"."1" = {
dist = "<B Derivation>";
dependencies = {
a.version = "1";
};
dev = false;
bins = {};
info = {
initialState = "dist";
allPaths = {
"node_modules/b" = true;
};
};
};
};
sanitizedGraph = utils.sanitizeGraph {
inherit graph;
root = {
name = "a";
version = "1";
};
};
fileSystem = utils.getFileSystem graph sanitizedGraph;
in {
expr = fileSystem;
expected = {
"node_modules/a" = {
bins = {};
source = "<A Derivation>";
};
"node_modules/b" = {
bins = {};
source = "<B Derivation>";
};
};
};
test_bin_conflict = let
graph = {
"a"."1" = {
dist = "<A Derivation>";
dependencies = {
b.version = "1";
c.version = "1";
};
dev = false;
bins = {
};
info = {
initialState = "dist";
allPaths = {
"node_modules/a" = true;
};
};
};
"b"."1" = {
dist = "<B Derivation>";
dependencies = {
c.version = "2";
d.version = "1";
};
dev = false;
bins = {
};
info = {
initialState = "dist";
allPaths = {
"node_modules/b" = true;
};
};
};
"d"."1" = {
dist = "<D Derivation>";
dependencies = {
c.version = "2";
};
dev = false;
bins = {
};
info = {
initialState = "dist";
allPaths = {
"node_modules/d" = true;
};
};
};
"c"."1" = {
dist = "<C1 Derivation>";
dependencies = {
};
dev = false;
bins = {
c-cli = "cli.js";
};
info = {
initialState = "dist";
allPaths = {
"node_modules/c" = true;
};
};
};
"c"."2" = {
dist = "<C2 Derivation>";
dependencies = {
};
dev = false;
bins = {
c-cli = "cli.js";
};
info = {
initialState = "dist";
allPaths = {
"node_modules/b/node_modules/c" = true;
"node_modules/d/node_modules/c" = true;
};
};
};
};
sanitizedGraph = utils.sanitizeGraph {
inherit graph;
root = {
name = "a";
version = "1";
};
};
fileSystem = utils.getFileSystem graph sanitizedGraph;
in {
expr = fileSystem;
expected = {
"node_modules/a" = {
bins = {};
source = "<A Derivation>";
};
"node_modules/b" = {
bins = {};
source = "<B Derivation>";
};
"node_modules/b/node_modules/c" = {
bins = {"node_modules/b/node_modules/.bin/c-cli" = "node_modules/b/node_modules/c/cli.js";};
source = "<C2 Derivation>";
};
"node_modules/c" = {
bins = {"node_modules/.bin/c-cli" = "node_modules/c/cli.js";};
source = "<C1 Derivation>";
};
"node_modules/d" = {
bins = {};
source = "<D Derivation>";
};
"node_modules/d/node_modules/c" = {
bins = {"node_modules/d/node_modules/.bin/c-cli" = "node_modules/d/node_modules/c/cli.js";};
source = "<C2 Derivation>";
};
};
};
}