dream2nix/lib/internal/readDreamLock.nix

194 lines
4.5 KiB
Nix

# This is currently only used for legacy modules ported to v1.
# The dream-lock concept might be deprecated together with this module at some
# point.
{lib, ...}: let
l = builtins // lib;
listDirs = path: l.attrNames (l.filterAttrs (n: v: v == "directory") (builtins.readDir path));
subDreamLockNames = dreamLockFile: let
dir = l.dirOf dreamLockFile;
directories = listDirs dir;
dreamLockDirs =
l.filter
(d: l.pathExists "${dir}/${d}/dream-lock.json")
directories;
in
dreamLockDirs;
/*
Ensures that there is an entry in dependencies for each source.
This allows translators to omit creating dream-locks with empty
dependency graph.
*/
extendWithEmptyGraph = dreamLockDecomp: let
emptyDependencyGraph =
l.mapAttrs
(name: versions:
l.mapAttrs
(version: source: [])
versions)
dreamLockDecomp.sources;
dependencyGraph =
l.recursiveUpdate
emptyDependencyGraph
dreamLockDecomp.dependencies;
lock =
dreamLockDecomp
// {
dependencies = dependencyGraph;
};
in
lock;
decompressDependencyGraph = compGraph:
l.mapAttrs
(name: versions:
l.mapAttrs
(version: deps:
map
(dep: {
name = l.elemAt dep 0;
version = l.elemAt dep 1;
})
deps)
versions)
compGraph;
decompressDreamLock = comp: let
dependencyGraphDecomp =
decompressDependencyGraph (comp.dependencies or {});
cyclicDependencies =
decompressDependencyGraph (comp.cyclicDependencies or {});
in
comp
// {
decompressed = true;
cyclicDependencies = cyclicDependencies;
dependencies = dependencyGraphDecomp;
};
readDreamLock = {dreamLock} @ args: let
isFile =
l.isPath dreamLock
|| l.isString dreamLock
|| l.isDerivation dreamLock;
lockMaybeCompressed =
if isFile
then l.fromJSON (l.readFile dreamLock)
else dreamLock;
lockRaw =
if lockMaybeCompressed.decompressed or false
then lockMaybeCompressed
else decompressDreamLock lockMaybeCompressed;
lock = extendWithEmptyGraph lockRaw;
subDreamLocks =
if ! isFile
then {}
else let
dir = l.dirOf dreamLock;
in
l.genAttrs
(subDreamLockNames dreamLock)
(d:
readDreamLock
{dreamLock = "${dir}/${d}/dream-lock.json";});
packages = lock._generic.packages;
defaultPackageName = lock._generic.defaultPackage;
defaultPackageVersion = packages."${defaultPackageName}";
subsystemAttrs = lock._subsystem;
sources = lock.sources;
dependencyGraph = lock.dependencies;
allDependencies = let
candidatesList =
l.unique
(l.flatten
(l.mapAttrsToList
(name: versions:
l.flatten (l.attrValues versions))
dependencyGraph));
in
l.foldl'
(all: new:
all
// {
"${new.name}" = all.${new.name} or [] ++ [new.version];
})
{}
candidatesList;
allDependants =
l.mapAttrs
(name: versions: l.attrNames versions)
dependencyGraph;
packageVersions =
l.zipAttrsWith
(name: versions: l.unique (l.flatten versions))
[
allDependants
allDependencies
];
cyclicDependencies = lock.cyclicDependencies;
getSourceSpec = pname: version:
sources."${pname}"."${version}"
or (
throw "The source spec for ${pname}#${version} is not defined in lockfile."
);
getDependencies = pname: version:
l.filter
(dep: ! l.elem dep cyclicDependencies."${pname}"."${version}" or [])
dependencyGraph."${pname}"."${version}" or [];
getCyclicDependencies = pname: version:
cyclicDependencies."${pname}"."${version}" or [];
getRoot = pname: version: let
spec = getSourceSpec pname version;
in
if
(pname == defaultPackageName && version == defaultPackageVersion)
|| spec.type != "path"
then {inherit pname version;}
else {
pname = spec.rootName;
version = spec.rootVersion;
};
in {
inherit lock;
interface = {
inherit
defaultPackageName
defaultPackageVersion
subsystemAttrs
getCyclicDependencies
getDependencies
getSourceSpec
getRoot
packages
packageVersions
subDreamLocks
;
};
};
in
readDreamLock