feat: module system improvements

- add documentation to the subsystem-loading interface
- expose evaled modules publicly via `framework`
- add option config.modules to allow users to include their own modules
- update examples for extending dream2nix
This commit is contained in:
DavHau 2022-08-15 15:34:24 +02:00
parent debe2e9152
commit e654ffaa10
11 changed files with 95 additions and 56 deletions

View File

@ -3,6 +3,11 @@
`dream2nix` can be extended while you are `init`ializing it. This can be done in a few ways. `dream2nix` can be extended while you are `init`ializing it. This can be done in a few ways.
For extending, you need to utilize the `config.extra` option of the dream2nix config. For extending, you need to utilize the `config.extra` option of the dream2nix config.
## Module System Transition
The dream2nix architecture is currently in the process of being refactored into nixos modules. The actual APIs can deviate from what is described in this document.
For up-to-date examples see `/examples/_d2n-extended` and `/examples/_d2n-extended-new-subsystem`
Once the transition is completed we will update this document and remove this notice.
## Declare `extra`s from a nix file ## Declare `extra`s from a nix file
```nix ```nix

View File

@ -11,28 +11,6 @@
}) })
]; ];
}; };
translators.dummy = {...}: {
type = "pure";
translate = {hello, ...}: {...}: {
result = {
_generic = {
subsystem = "hello";
defaultPackage = "hello";
location = "";
sourcesAggregatedHash = null;
packages = {${hello.pname} = hello.version;};
};
_subsystem = {};
cyclicDependencies = {};
dependencies.${hello.pname}.${hello.version} = [];
sources.${hello.pname}.${hello.version} = {
type = "http";
url = hello.src.url;
hash = hello.src.outputHash;
};
};
};
};
builders.dummy = {...}: { builders.dummy = {...}: {
type = "pure"; type = "pure";
build = {hello, ...}: {...}: { build = {hello, ...}: {...}: {

View File

@ -11,6 +11,9 @@
systems = ["x86_64-linux"]; systems = ["x86_64-linux"];
config.projectRoot = ./.; config.projectRoot = ./.;
config.extra = ./extra.nix; config.extra = ./extra.nix;
config.modules = [
./translators.nix
];
source = ./.; source = ./.;
settings = [ settings = [
{ {

View File

@ -0,0 +1,26 @@
{
translators.dummy = {...}: {
type = "pure";
name = "dummy";
subsystem = "hello";
translate = {hello, ...}: {...}: {
result = {
_generic = {
subsystem = "hello";
defaultPackage = "hello";
location = "";
sourcesAggregatedHash = null;
packages = {${hello.pname} = hello.version;};
};
_subsystem = {};
cyclicDependencies = {};
dependencies.${hello.pname}.${hello.version} = [];
sources.${hello.pname}.${hello.version} = {
type = "http";
url = hello.src.url;
hash = hello.src.outputHash;
};
};
};
};
}

View File

@ -13,10 +13,20 @@
(dream2nix.lib.makeFlakeOutputs { (dream2nix.lib.makeFlakeOutputs {
systems = ["x86_64-linux"]; systems = ["x86_64-linux"];
config.projectRoot = ./.; config.projectRoot = ./.;
config.modules = [
(builtins.toFile "cargo-toml-new.nix" ''
{
translators.cargo-toml-new = {
imports = ["${inp.dream2nix}/src/subsystems/rust/translators/cargo-toml"];
name = "cargo-toml-new";
subsystem = "rust";
};
}
'')
];
config.extra = { config.extra = {
subsystems.rust = { subsystems.rust = {
builders.brp-new = "${inp.dream2nix}/src/subsystems/rust/builders/build-rust-package"; builders.brp-new = "${inp.dream2nix}/src/subsystems/rust/builders/build-rust-package";
translators.cargo-toml-new = "${inp.dream2nix}/src/subsystems/rust/translators/cargo-toml";
discoverers.default = "${inp.dream2nix}/src/subsystems/rust/discoverers/default"; discoverers.default = "${inp.dream2nix}/src/subsystems/rust/discoverers/default";
}; };
fetchers.crates-io = "${inp.dream2nix}/src/fetchers/crates-io"; fetchers.crates-io = "${inp.dream2nix}/src/fetchers/crates-io";

View File

@ -49,17 +49,22 @@ in let
configFile = pkgs.writeText "dream2nix-config.json" (b.toJSON config); configFile = pkgs.writeText "dream2nix-config.json" (b.toJSON config);
# pass spacialArgs itself in specialArgs in order to forward it to submodules.
specialModuleArgs = l.fix (self: {
specialArgs = self;
inherit
callPackageDream
dlib
;
});
evaledModules = lib.evalModules { evaledModules = lib.evalModules {
modules = [ modules =
./modules/top-level.nix [./modules/top-level.nix]
]; ++ (config.modules or []);
# TODO: remove specialArgs once all functionality is moved to /src/modules # TODO: remove specialArgs once all functionality is moved to /src/modules
specialArgs = { specialArgs = specialModuleArgs;
inherit
callPackageDream
dlib
;
};
}; };
framework = evaledModules.config; framework = evaledModules.config;
@ -709,6 +714,7 @@ in {
callPackageDream callPackageDream
dream2nixWithExternals dream2nixWithExternals
fetchers fetchers
framework
indexers indexers
fetchSources fetchSources
realizeProjects realizeProjects

View File

@ -17,10 +17,6 @@ modules:
subsystemsDir = lib.toString ../../subsystems; subsystemsDir = lib.toString ../../subsystems;
subsystems = dlib.dirNames subsystemsDir; subsystems = dlib.dirNames subsystemsDir;
/*
Discover modules in:
/src/subsystems/{subsystem}/{module-type}/{module-name}
*/
collect = moduleDirName: collect = moduleDirName:
lib.concatMap lib.concatMap
(subsystem: let (subsystem: let
@ -43,10 +39,6 @@ modules:
names) names)
subsystems; subsystems;
/*
Imports discovered module files.
Adds name and subsystem attributes to each module derived from the path.
*/
import_ = collectedModules: import_ = collectedModules:
lib.mapAttrs lib.mapAttrs
(name: description: (name: description:
@ -54,12 +46,6 @@ modules:
// {inherit (description) name subsystem;}) // {inherit (description) name subsystem;})
(lib.listToAttrs collectedModules); (lib.listToAttrs collectedModules);
/*
To keep module implementations simpler, additional generic logic is added
by a loader.
The loader is subsytem specific and needs to be passed as an argument.
*/
instantiate = importedModules: loader: instantiate = importedModules: loader:
lib.mapAttrs lib.mapAttrs
(name: module: (name: module:
@ -67,10 +53,6 @@ modules:
// {inherit (module) name subsystem;}) // {inherit (module) name subsystem;})
importedModules; importedModules;
/*
re-structures the instantiated instances into a deeper attrset like:
{subsytem}.{module-name} = ...
*/
structureBySubsystem = instances: structureBySubsystem = instances:
lib.foldl lib.foldl
lib.recursiveUpdate lib.recursiveUpdate

View File

@ -3,9 +3,33 @@
t = lib.types; t = lib.types;
in { in {
options.functions.subsystem-loading = { options.functions.subsystem-loading = {
collect = lib.mkOption {type = t.functionTo t.anything;}; collect = lib.mkOption {
import_ = lib.mkOption {type = t.functionTo t.anything;}; type = t.functionTo t.anything;
instantiate = lib.mkOption {type = t.functionTo t.anything;}; description = ''
structureBySubsystem = lib.mkOption {type = t.functionTo t.anything;}; Discover modules in /src/subsystems/{subsystem}/{module-type}/{module-name}
'';
};
import_ = lib.mkOption {
type = t.functionTo t.anything;
description = ''
Imports discovered module files.
Adds name and subsystem attributes to each module derived from the path.
'';
};
instantiate = lib.mkOption {
type = t.functionTo t.anything;
description = ''
To keep module implementations simpler, additional generic logic is added
by a loader.
The loader is subsytem specific and needs to be passed as an argument.
'';
};
structureBySubsystem = lib.mkOption {
type = t.functionTo t.anything;
description = ''
re-structures the instantiated instances into a deeper attrset like:
{subsytem}.{module-name} = ...
'';
};
}; };
} }

View File

@ -44,6 +44,7 @@ in {
default = null; default = null;
}; };
extraArgs = lib.mkOption { extraArgs = lib.mkOption {
default = {};
type = t.attrsOf (t.submodule { type = t.attrsOf (t.submodule {
options = { options = {
description = lib.mkOption { description = lib.mkOption {

View File

@ -1,13 +1,17 @@
{ {
config, config,
lib, lib,
specialArgs,
... ...
}: let }: let
t = lib.types; t = lib.types;
in { in {
options = { options = {
translators = lib.mkOption { translators = lib.mkOption {
type = t.attrsOf (t.submodule ./interface-translator.nix); type = t.attrsOf (t.submoduleWith {
modules = [./interface-translator.nix];
inherit specialArgs;
});
description = '' description = ''
Translator module definitions Translator module definitions
''; '';

View File

@ -29,7 +29,7 @@
cp -r ${examples}/$dir/* . cp -r ${examples}/$dir/* .
chmod -R +w . chmod -R +w .
nix flake lock --override-input dream2nix ${../../.} nix flake lock --override-input dream2nix ${../../.}
nix run .#resolveImpure nix run .#resolveImpure --show-trace
# disable --read-only check for these because they do IFD so they will # disable --read-only check for these because they do IFD so they will
# write to store at eval time # write to store at eval time
evalBlockList=("haskell_cabal-plan" "haskell_stack-lock") evalBlockList=("haskell_cabal-plan" "haskell_stack-lock")