mirror of
https://github.com/nix-community/dream2nix.git
synced 2024-12-23 06:21:30 +03:00
refactor: move dream2nix interface to modules
This commit is contained in:
parent
4b4e82cb14
commit
f44016a2d4
@ -20,7 +20,7 @@
|
||||
};
|
||||
|
||||
makeOutputs = pkgs: let
|
||||
outputs = (initD2N pkgs).makeOutputs {
|
||||
outputs = (initD2N pkgs).dream2nixInterface.makeOutputs {
|
||||
source = inp.src;
|
||||
settings = [
|
||||
{
|
||||
|
356
flake.nix
356
flake.nix
@ -77,7 +77,6 @@
|
||||
ghc-utils,
|
||||
...
|
||||
} @ inp: let
|
||||
b = builtins;
|
||||
l = lib // builtins;
|
||||
|
||||
lib = nixpkgs.lib;
|
||||
@ -133,9 +132,6 @@
|
||||
];
|
||||
};
|
||||
|
||||
# create a directory containing the files listed in externalPaths
|
||||
makeExternalDir = import ./src/utils/external-dir.nix;
|
||||
|
||||
# An interface to access files of external projects.
|
||||
# This implementation accesses the flake inputs directly,
|
||||
# but if dream2nix is used without flakes, it defaults
|
||||
@ -168,212 +164,156 @@
|
||||
system,
|
||||
...
|
||||
}: let
|
||||
externalDir = makeExternalDir {
|
||||
inherit externalPaths externalSources pkgs;
|
||||
};
|
||||
d2n = import ./src {
|
||||
inherit externalDir externalPaths externalSources inputs lib pkgs;
|
||||
config = {inherit overridesDirs;};
|
||||
inherit externalPaths externalSources inputs lib pkgs;
|
||||
dream2nixConfig = {inherit overridesDirs;};
|
||||
};
|
||||
docsCli = pkgs.callPackage ./src/utils/view-docs {
|
||||
dream2nixDocsSrc = "${self}/docs/src";
|
||||
};
|
||||
in {
|
||||
# all apps including cli, install, etc.
|
||||
apps =
|
||||
d2n.framework.flakeApps
|
||||
// {
|
||||
tests-unit.type = "app";
|
||||
tests-unit.program =
|
||||
b.toString
|
||||
(d2n.callPackageDream ./tests/unit {
|
||||
inherit self;
|
||||
});
|
||||
options = {
|
||||
d2n = l.mkOption {
|
||||
type = l.types.raw;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
inherit d2n;
|
||||
|
||||
tests-integration.type = "app";
|
||||
tests-integration.program =
|
||||
b.toString
|
||||
(d2n.callPackageDream ./tests/integration {
|
||||
inherit self;
|
||||
});
|
||||
# all apps including cli, install, etc.
|
||||
apps =
|
||||
d2n.flakeApps
|
||||
// {
|
||||
# passes through extra flags to treefmt
|
||||
format.type = "app";
|
||||
format.program =
|
||||
l.toString
|
||||
(pkgs.writeScript "format" ''
|
||||
export PATH="${alejandra.defaultPackage.${system}}/bin"
|
||||
${pkgs.treefmt}/bin/treefmt --clear-cache "$@"
|
||||
'');
|
||||
|
||||
tests-integration-d2n-flakes.type = "app";
|
||||
tests-integration-d2n-flakes.program =
|
||||
b.toString
|
||||
(d2n.callPackageDream ./tests/integration-d2n-flakes {
|
||||
inherit self;
|
||||
});
|
||||
docs.type = "app";
|
||||
docs.program = "${docsCli}/bin/d2n-docs";
|
||||
};
|
||||
|
||||
tests-examples.type = "app";
|
||||
tests-examples.program =
|
||||
b.toString
|
||||
(d2n.callPackageDream ./tests/examples {
|
||||
inherit self;
|
||||
});
|
||||
# a dev shell for working on dream2nix
|
||||
# use via 'nix develop . -c $SHELL'
|
||||
devShells = let
|
||||
makeDevshell = import "${inp.devshell}/modules" pkgs;
|
||||
mkShell = config:
|
||||
(makeDevshell {
|
||||
configuration = {
|
||||
inherit config;
|
||||
imports = [];
|
||||
};
|
||||
})
|
||||
.shell;
|
||||
in rec {
|
||||
default = dream2nix-shell;
|
||||
dream2nix-shell = mkShell {
|
||||
devshell.name = "dream2nix-devshell";
|
||||
|
||||
tests-all.type = "app";
|
||||
tests-all.program =
|
||||
l.toString
|
||||
(d2n.framework.utils.writePureShellScript
|
||||
commands =
|
||||
[
|
||||
alejandra.defaultPackage.${system}
|
||||
pkgs.coreutils
|
||||
pkgs.gitMinimal
|
||||
pkgs.nix
|
||||
{package = pkgs.nix;}
|
||||
{
|
||||
package = pkgs.mdbook;
|
||||
category = "documentation";
|
||||
}
|
||||
{
|
||||
package = docsCli;
|
||||
category = "documentation";
|
||||
help = "CLI for listing and viewing dream2nix documentation";
|
||||
}
|
||||
{
|
||||
package = pkgs.treefmt;
|
||||
category = "formatting";
|
||||
}
|
||||
{
|
||||
package = alejandra.defaultPackage.${system};
|
||||
category = "formatting";
|
||||
}
|
||||
]
|
||||
''
|
||||
echo "check for correct formatting"
|
||||
WORKDIR=$(realpath ./.)
|
||||
cd $TMPDIR
|
||||
cp -r $WORKDIR ./repo
|
||||
cd ./repo
|
||||
${config.apps.format.program} --fail-on-change
|
||||
cd -
|
||||
# using linux is highly recommended as cntr is amazing for debugging builds
|
||||
++ lib.optional pkgs.stdenv.isLinux {
|
||||
package = pkgs.cntr;
|
||||
category = "debugging";
|
||||
};
|
||||
|
||||
echo "running unit tests"
|
||||
${config.apps.tests-unit.program}
|
||||
devshell.startup = {
|
||||
preCommitHooks.text = self.checks.${system}.pre-commit-check.shellHook;
|
||||
dream2nixEnv.text = ''
|
||||
export NIX_PATH=nixpkgs=${nixpkgs}
|
||||
export d2nExternalDir=${d2n.externalDir}
|
||||
export dream2nixWithExternals=${d2n.dream2nixWithExternals}
|
||||
|
||||
echo "running integration tests"
|
||||
${config.apps.tests-integration.program}
|
||||
|
||||
echo "checking flakes under ./examples"
|
||||
${config.apps.tests-examples.program}
|
||||
|
||||
echo "running nix flake check"
|
||||
cd $WORKDIR
|
||||
nix flake show >/dev/null
|
||||
nix flake check
|
||||
'');
|
||||
|
||||
# passes through extra flags to treefmt
|
||||
format.type = "app";
|
||||
format.program =
|
||||
l.toString
|
||||
(pkgs.writeScript "format" ''
|
||||
export PATH="${alejandra.defaultPackage.${system}}/bin"
|
||||
${pkgs.treefmt}/bin/treefmt --clear-cache "$@"
|
||||
'');
|
||||
|
||||
docs.type = "app";
|
||||
docs.program = "${docsCli}/bin/d2n-docs";
|
||||
};
|
||||
|
||||
# a dev shell for working on dream2nix
|
||||
# use via 'nix develop . -c $SHELL'
|
||||
devShells = let
|
||||
makeDevshell = import "${inp.devshell}/modules" pkgs;
|
||||
mkShell = config:
|
||||
(makeDevshell {
|
||||
configuration = {
|
||||
inherit config;
|
||||
imports = [];
|
||||
};
|
||||
})
|
||||
.shell;
|
||||
in rec {
|
||||
default = dream2nix-shell;
|
||||
dream2nix-shell = mkShell {
|
||||
devshell.name = "dream2nix-devshell";
|
||||
|
||||
commands =
|
||||
[
|
||||
{package = pkgs.nix;}
|
||||
{
|
||||
package = pkgs.mdbook;
|
||||
category = "documentation";
|
||||
}
|
||||
{
|
||||
package = docsCli;
|
||||
category = "documentation";
|
||||
help = "CLI for listing and viewing dream2nix documentation";
|
||||
}
|
||||
{
|
||||
package = pkgs.treefmt;
|
||||
category = "formatting";
|
||||
}
|
||||
{
|
||||
package = alejandra.defaultPackage.${system};
|
||||
category = "formatting";
|
||||
}
|
||||
]
|
||||
# using linux is highly recommended as cntr is amazing for debugging builds
|
||||
++ lib.optional pkgs.stdenv.isLinux {
|
||||
package = pkgs.cntr;
|
||||
category = "debugging";
|
||||
};
|
||||
|
||||
devshell.startup = {
|
||||
preCommitHooks.text = self.checks.${system}.pre-commit-check.shellHook;
|
||||
dream2nixEnv.text = ''
|
||||
export NIX_PATH=nixpkgs=${nixpkgs}
|
||||
export d2nExternalDir=${externalDir}
|
||||
export dream2nixWithExternals=${d2n.dream2nixWithExternals}
|
||||
|
||||
if [ -e ./overrides ]; then
|
||||
export d2nOverridesDir=$(realpath ./overrides)
|
||||
else
|
||||
export d2nOverridesDir=${./overrides}
|
||||
echo -e "\nManually execute 'export d2nOverridesDir={path to your dream2nix overrides dir}'"
|
||||
fi
|
||||
|
||||
if [ -e ../dream2nix ]; then
|
||||
export dream2nixWithExternals=$(realpath ./src)
|
||||
else
|
||||
export dream2nixWithExternals=${./src}
|
||||
echo -e "\nManually execute 'export dream2nixWithExternals={path to your dream2nix checkout}'"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
checks = {
|
||||
pre-commit-check = pre-commit-hooks.lib.${system}.run {
|
||||
src = ./.;
|
||||
hooks = {
|
||||
treefmt = {
|
||||
enable = true;
|
||||
name = "treefmt";
|
||||
pass_filenames = false;
|
||||
entry = l.toString (pkgs.writeScript "treefmt" ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
export PATH="$PATH:${alejandra.defaultPackage.${system}}/bin"
|
||||
${pkgs.treefmt}/bin/treefmt --clear-cache --fail-on-change
|
||||
'');
|
||||
};
|
||||
cleanup = {
|
||||
enable = true;
|
||||
name = "cleaned";
|
||||
entry = l.toString (pkgs.writeScript "cleaned" ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
for badFile in $(find ./examples | grep 'flake.lock\|dream2nix-packages'); do
|
||||
rm -rf $badFile
|
||||
git add $badFile || :
|
||||
done
|
||||
'');
|
||||
};
|
||||
is-cleaned = {
|
||||
enable = true;
|
||||
name = "is-cleaned";
|
||||
entry = l.toString (pkgs.writeScript "is-cleaned" ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
if find ./examples | grep -q 'flake.lock\|dream2nix-packages'; then
|
||||
echo "./examples should not contain any flake.lock files or dream2nix-packages directories" >&2
|
||||
exit 1
|
||||
if [ -e ./overrides ]; then
|
||||
export d2nOverridesDir=$(realpath ./overrides)
|
||||
else
|
||||
export d2nOverridesDir=${./overrides}
|
||||
echo -e "\nManually execute 'export d2nOverridesDir={path to your dream2nix overrides dir}'"
|
||||
fi
|
||||
'');
|
||||
|
||||
if [ -e ../dream2nix ]; then
|
||||
export dream2nixWithExternals=$(realpath ./src)
|
||||
else
|
||||
export dream2nixWithExternals=${./src}
|
||||
echo -e "\nManually execute 'export dream2nixWithExternals={path to your dream2nix checkout}'"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
packages = {
|
||||
docs =
|
||||
pkgs.runCommand
|
||||
"dream2nix-docs"
|
||||
{nativeBuildInputs = [pkgs.mdbook];}
|
||||
''
|
||||
mdbook build -d $out ${./.}/docs
|
||||
'';
|
||||
|
||||
checks = {
|
||||
pre-commit-check = pre-commit-hooks.lib.${system}.run {
|
||||
src = ./.;
|
||||
hooks = {
|
||||
treefmt = {
|
||||
enable = true;
|
||||
name = "treefmt";
|
||||
pass_filenames = false;
|
||||
entry = l.toString (pkgs.writeScript "treefmt" ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
export PATH="$PATH:${alejandra.defaultPackage.${system}}/bin"
|
||||
${pkgs.treefmt}/bin/treefmt --clear-cache --fail-on-change
|
||||
'');
|
||||
};
|
||||
cleanup = {
|
||||
enable = true;
|
||||
name = "cleaned";
|
||||
entry = l.toString (pkgs.writeScript "cleaned" ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
for badFile in $(find ./examples | grep 'flake.lock\|dream2nix-packages'); do
|
||||
rm -rf $badFile
|
||||
git add $badFile || :
|
||||
done
|
||||
'');
|
||||
};
|
||||
is-cleaned = {
|
||||
enable = true;
|
||||
name = "is-cleaned";
|
||||
entry = l.toString (pkgs.writeScript "is-cleaned" ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
if find ./examples | grep -q 'flake.lock\|dream2nix-packages'; then
|
||||
echo "./examples should not contain any flake.lock files or dream2nix-packages directories" >&2
|
||||
exit 1
|
||||
fi
|
||||
'');
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
packages = {
|
||||
docs =
|
||||
pkgs.runCommand
|
||||
"dream2nix-docs"
|
||||
{nativeBuildInputs = [pkgs.mdbook];}
|
||||
''
|
||||
mdbook build -d $out ${./.}/docs
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@ -386,37 +326,13 @@
|
||||
imports = [./src/modules/flake-parts];
|
||||
dream2nix.lib = d2n-lib;
|
||||
};
|
||||
templates =
|
||||
{
|
||||
default = self.templates.simple;
|
||||
simple = {
|
||||
description = "Simple dream2nix flake";
|
||||
path = ./templates/simple;
|
||||
welcomeText = ''
|
||||
You just created a simple dream2nix package!
|
||||
|
||||
start with typing `nix flake show` to discover the projects attributes.
|
||||
|
||||
commands:
|
||||
|
||||
- `nix develop` <-- enters the devShell
|
||||
- `nix build .#` <-- builds the default package (`.#default`)
|
||||
|
||||
|
||||
Start hacking and -_- have some fun!
|
||||
|
||||
> dont forget to add nix `result` folder to your `.gitignore`
|
||||
|
||||
'';
|
||||
};
|
||||
}
|
||||
// (b.mapAttrs (name: value: {
|
||||
description = "Example: ${name} template";
|
||||
path = ./examples/${name};
|
||||
}) (l.filterAttrs (n: v: v == "directory") (b.readDir ./examples)));
|
||||
};
|
||||
in
|
||||
flake-parts.lib.mkFlake {inherit self;} {
|
||||
imports = [
|
||||
./tests
|
||||
./templates
|
||||
];
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
|
@ -14,7 +14,7 @@ utils.writePureShellScript
|
||||
nixpkgs = <nixpkgs>;
|
||||
l = (import \"\''${nixpkgs}/lib\") // builtins;
|
||||
dream2nix = import ${dream2nixWithExternals} {
|
||||
config = ''${dream2nixConfig:-"${dream2nixConfigFile}"};
|
||||
dream2nixConfig = ''${dream2nixConfig:-"${dream2nixConfigFile}"};
|
||||
};
|
||||
in ''${@:$#}
|
||||
"
|
||||
|
@ -30,7 +30,7 @@ utils.writePureShellScriptBin
|
||||
resultBin="$TMPDIR/result"
|
||||
|
||||
${apps.callNixWithD2N} build -L --keep-failed --show-trace --out-link $resultBin \
|
||||
"dream2nix.framework.indexers.$name.indexBin"
|
||||
"dream2nix.indexers.$name.indexBin"
|
||||
|
||||
$resultBin $inputFile
|
||||
''
|
||||
|
@ -60,7 +60,7 @@ in
|
||||
if [ ! -e "$bin" ]; then
|
||||
echo "building executable for translator $translator"
|
||||
${apps.callNixWithD2N} build -o "$bin" "
|
||||
dream2nix.framework.translators.$translator.finalTranslateBin
|
||||
dream2nix.translators.$translator.finalTranslateBin
|
||||
"
|
||||
fi
|
||||
done
|
||||
|
@ -45,7 +45,7 @@ utils.writePureShellScriptBin
|
||||
translateBin="$TRANSLATOR_DIR/$translator"
|
||||
else
|
||||
translateBin=$(${apps.callNixWithD2N} build --print-out-paths --no-link "
|
||||
dream2nix.framework.translators.$translator.finalTranslateBin
|
||||
dream2nix.translators.$translator.finalTranslateBin
|
||||
")
|
||||
fi
|
||||
|
||||
|
@ -19,7 +19,7 @@ pkgs.writers.writeBash
|
||||
pkgs = import ${pkgs.path} {inherit system;};
|
||||
d2n = import ${dream2nixWithExternals} {
|
||||
inherit pkgs;
|
||||
config = ''${dream2nixConfig:-"{}"};
|
||||
dream2nixConfig = ''${dream2nixConfig:-"{}"};
|
||||
};
|
||||
src = d2n.fetchers.fetchSource {
|
||||
source = b.fromJSON (b.readFile \"''${flakeSrcInfoPath:?"error: set source info path"}\");
|
||||
|
748
src/default.nix
748
src/default.nix
@ -1,747 +1 @@
|
||||
# This is the system specific api for dream2nix.
|
||||
# It requires passing one specific pkgs.
|
||||
# If the intention is to generate output for several systems,
|
||||
# use ./lib.nix instead.
|
||||
{
|
||||
pkgs ? import <nixpkgs> {},
|
||||
lib ? pkgs.lib,
|
||||
nix ? pkgs.nix,
|
||||
# already validated config.
|
||||
# this is mainly used by src/lib.nix since it loads the config beforehand.
|
||||
loadedConfig ? null,
|
||||
# default to empty dream2nix config. This is assumed to be not loaded.
|
||||
config ?
|
||||
if builtins ? getEnv && builtins.getEnv "dream2nixConfig" != ""
|
||||
# if called via CLI, load config via env
|
||||
then builtins.toPath (builtins.getEnv "dream2nixConfig")
|
||||
# load from default directory
|
||||
else {},
|
||||
/*
|
||||
Inputs that are not required for building, and therefore not need to be
|
||||
copied alongside a dream2nix installation.
|
||||
*/
|
||||
inputs ?
|
||||
(import ../flake-compat.nix {
|
||||
src = ../.;
|
||||
inherit (pkgs) system;
|
||||
})
|
||||
.inputs,
|
||||
# dependencies of dream2nix builders
|
||||
externalSources ?
|
||||
lib.genAttrs
|
||||
(lib.attrNames (builtins.readDir externalDir))
|
||||
(inputName: "${/. + externalDir}/${inputName}"),
|
||||
# will be defined if called via flake
|
||||
externalPaths ? null,
|
||||
# required for non-flake mode
|
||||
externalDir ?
|
||||
# if flake is used, construct external dir from flake inputs
|
||||
if externalPaths != null
|
||||
then
|
||||
(import ./utils/external-dir.nix {
|
||||
inherit externalPaths externalSources pkgs;
|
||||
})
|
||||
# if called via CLI, load externals via env
|
||||
else if builtins ? getEnv && builtins.getEnv "d2nExternalDir" != ""
|
||||
then /. + (builtins.getEnv "d2nExternalDir")
|
||||
# load from default directory
|
||||
else ./external,
|
||||
} @ args: let
|
||||
argsConfig = config;
|
||||
in let
|
||||
b = builtins;
|
||||
|
||||
l = lib // builtins;
|
||||
|
||||
config =
|
||||
if loadedConfig != null
|
||||
then loadedConfig
|
||||
else
|
||||
import ./modules/config.nix {
|
||||
inherit lib;
|
||||
rawConfig = argsConfig;
|
||||
};
|
||||
|
||||
configFile = pkgs.writeText "dream2nix-config.json" (b.toJSON config);
|
||||
|
||||
framework = import ./modules/framework.nix {
|
||||
inherit
|
||||
inputs
|
||||
lib
|
||||
pkgs
|
||||
externals
|
||||
externalSources
|
||||
dream2nixWithExternals
|
||||
;
|
||||
dream2nixConfigFile = configFile;
|
||||
dream2nixConfig = config;
|
||||
dream2nixInterface = {
|
||||
inherit
|
||||
makeOutputsForDreamLock
|
||||
;
|
||||
};
|
||||
};
|
||||
|
||||
inherit (framework) dlib;
|
||||
|
||||
/*
|
||||
The nixos module system seems to break pkgs.callPackage.
|
||||
Therefore we always need to pass all of pkgs with callPackageDream.
|
||||
callPackageDream should also be deprecated once all functionality is moved to
|
||||
the module system.
|
||||
*/
|
||||
callPackageDreamArgs =
|
||||
pkgs
|
||||
// {
|
||||
inherit callPackageDream;
|
||||
inherit config;
|
||||
inherit configFile;
|
||||
inherit externals;
|
||||
inherit externalSources;
|
||||
inherit inputs;
|
||||
inherit framework;
|
||||
inherit dream2nixWithExternals;
|
||||
inherit nix;
|
||||
};
|
||||
|
||||
# like pkgs.callPackage, but includes all the dream2nix modules
|
||||
callPackageDream = f: fargs:
|
||||
(
|
||||
if l.isFunction f
|
||||
then f
|
||||
else import f
|
||||
) (callPackageDreamArgs // fargs);
|
||||
|
||||
inherit (framework) utils;
|
||||
|
||||
# updater modules to find newest package versions
|
||||
updaters = callPackageDream ./updaters {};
|
||||
|
||||
externals = {
|
||||
devshell = {
|
||||
makeShell = import "${externalSources.devshell}/modules" pkgs;
|
||||
imports.c = "${externalSources.devshell}/extra/language/c.nix";
|
||||
};
|
||||
crane = let
|
||||
importLibFile = name: import "${externalSources.crane}/lib/${name}.nix";
|
||||
|
||||
makeHook = attrs: name:
|
||||
pkgs.makeSetupHook
|
||||
({inherit name;} // attrs)
|
||||
"${externalSources.crane}/pkgs/${name}.sh";
|
||||
genHooks = names: attrs: lib.genAttrs names (makeHook attrs);
|
||||
in
|
||||
{
|
||||
cargoHostTarget,
|
||||
cargoBuildBuild,
|
||||
}: rec {
|
||||
otherHooks =
|
||||
genHooks [
|
||||
"cargoHelperFunctions"
|
||||
"configureCargoCommonVarsHook"
|
||||
"configureCargoVendoredDepsHook"
|
||||
]
|
||||
{};
|
||||
installHooks =
|
||||
genHooks [
|
||||
"inheritCargoArtifactsHook"
|
||||
"installCargoArtifactsHook"
|
||||
]
|
||||
{
|
||||
substitutions = {
|
||||
zstd = "${pkgs.pkgsBuildBuild.zstd}/bin/zstd";
|
||||
};
|
||||
};
|
||||
installLogHook = genHooks ["installFromCargoBuildLogHook"] {
|
||||
substitutions = {
|
||||
cargo = "${cargoBuildBuild}/bin/cargo";
|
||||
jq = "${pkgs.pkgsBuildBuild.jq}/bin/jq";
|
||||
};
|
||||
};
|
||||
|
||||
# These aren't used by dream2nix
|
||||
crateNameFromCargoToml = null;
|
||||
vendorCargoDeps = null;
|
||||
|
||||
writeTOML = importLibFile "writeTOML" {
|
||||
inherit (pkgs) runCommand pkgsBuildBuild;
|
||||
};
|
||||
cleanCargoToml = importLibFile "cleanCargoToml" {};
|
||||
findCargoFiles = importLibFile "findCargoFiles" {
|
||||
inherit (pkgs) lib;
|
||||
};
|
||||
mkDummySrc = importLibFile "mkDummySrc" {
|
||||
inherit (pkgs) writeText runCommandLocal lib;
|
||||
inherit writeTOML cleanCargoToml findCargoFiles;
|
||||
};
|
||||
|
||||
mkCargoDerivation = importLibFile "mkCargoDerivation" {
|
||||
cargo = cargoHostTarget;
|
||||
inherit (pkgs) stdenv lib;
|
||||
inherit
|
||||
(installHooks)
|
||||
inheritCargoArtifactsHook
|
||||
installCargoArtifactsHook
|
||||
;
|
||||
inherit
|
||||
(otherHooks)
|
||||
configureCargoCommonVarsHook
|
||||
configureCargoVendoredDepsHook
|
||||
;
|
||||
cargoHelperFunctionsHook = otherHooks.cargoHelperFunctions;
|
||||
};
|
||||
buildDepsOnly = importLibFile "buildDepsOnly" {
|
||||
inherit
|
||||
mkCargoDerivation
|
||||
crateNameFromCargoToml
|
||||
vendorCargoDeps
|
||||
mkDummySrc
|
||||
;
|
||||
};
|
||||
cargoBuild = importLibFile "cargoBuild" {
|
||||
inherit
|
||||
mkCargoDerivation
|
||||
buildDepsOnly
|
||||
crateNameFromCargoToml
|
||||
vendorCargoDeps
|
||||
;
|
||||
};
|
||||
buildPackage = importLibFile "buildPackage" {
|
||||
inherit (pkgs) removeReferencesTo lib;
|
||||
inherit (installLogHook) installFromCargoBuildLogHook;
|
||||
inherit cargoBuild;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dreamOverrides = let
|
||||
overridesDirs =
|
||||
config.overridesDirs
|
||||
++ (lib.optionals (b ? getEnv && b.getEnv "d2nOverridesDir" != "") [
|
||||
(b.getEnv "d2nOverridesDir")
|
||||
]);
|
||||
in
|
||||
utils.loadOverridesDirs overridesDirs pkgs;
|
||||
|
||||
# the location of the dream2nix framework for self references (update scripts, etc.)
|
||||
dream2nixWithExternals =
|
||||
if b.pathExists (./. + "/external")
|
||||
then ./.
|
||||
else
|
||||
pkgs.runCommandLocal "dream2nix-full-src" {} ''
|
||||
cp -r ${./.} $out
|
||||
chmod +w $out
|
||||
mkdir $out/external
|
||||
cp -r ${externalDir}/* $out/external/
|
||||
'';
|
||||
|
||||
# automatically find a suitable builder for a given dream lock
|
||||
findBuilder = dreamLock: let
|
||||
subsystem = dreamLock._generic.subsystem;
|
||||
in
|
||||
if ! framework.buildersBySubsystem ? ${subsystem}
|
||||
then throw "Could not find any builder for subsystem '${subsystem}'"
|
||||
else framework.buildersBySubsystem.${subsystem}.default;
|
||||
|
||||
# detect if granular or combined fetching must be used
|
||||
findFetcher = dreamLock:
|
||||
if null != dreamLock._generic.sourcesAggregatedHash or null
|
||||
then framework.functions.combinedFetcher
|
||||
else framework.functions.defaultFetcher;
|
||||
|
||||
# fetch only sources and do not build
|
||||
fetchSources = {
|
||||
dreamLock,
|
||||
sourceRoot ? null,
|
||||
fetcher ? null,
|
||||
extract ? false,
|
||||
sourceOverrides ? oldSources: {},
|
||||
} @ args: let
|
||||
# if dream lock is a file, read and parse it
|
||||
dreamLock' = (utils.dream-lock.readDreamLock {inherit dreamLock;}).lock;
|
||||
|
||||
fetcher =
|
||||
if args.fetcher or null == null
|
||||
then findFetcher dreamLock'
|
||||
else args.fetcher;
|
||||
|
||||
fetched = fetcher rec {
|
||||
inherit sourceOverrides sourceRoot;
|
||||
defaultPackage = dreamLock._generic.defaultPackage;
|
||||
defaultPackageVersion = dreamLock._generic.packages."${defaultPackage}";
|
||||
sources = dreamLock'.sources;
|
||||
sourcesAggregatedHash = dreamLock'._generic.sourcesAggregatedHash;
|
||||
};
|
||||
|
||||
fetchedSources = fetched.fetchedSources;
|
||||
in
|
||||
fetched
|
||||
// {
|
||||
fetchedSources =
|
||||
if extract
|
||||
then
|
||||
lib.mapAttrs
|
||||
(key: source: utils.extractSource {inherit source;})
|
||||
fetchedSources
|
||||
else fetchedSources;
|
||||
};
|
||||
|
||||
# build a dream lock via a specific builder
|
||||
callBuilder = {
|
||||
builder,
|
||||
builderArgs,
|
||||
fetchedSources,
|
||||
sourceRoot,
|
||||
dreamLock,
|
||||
inject,
|
||||
sourceOverrides,
|
||||
packageOverrides,
|
||||
allOutputs,
|
||||
} @ args: let
|
||||
# inject dependencies
|
||||
dreamLock = utils.dream-lock.injectDependencies args.dreamLock inject;
|
||||
|
||||
dreamLockInterface = (utils.dream-lock.readDreamLock {inherit dreamLock;}).interface;
|
||||
|
||||
produceDerivation = name: pkg:
|
||||
utils.applyOverridesToPackage {
|
||||
inherit pkg;
|
||||
outputs = allOutputs;
|
||||
pname = name;
|
||||
conditionalOverrides = packageOverrides;
|
||||
};
|
||||
|
||||
outputs = builder.build (builderArgs
|
||||
// {
|
||||
inherit
|
||||
produceDerivation
|
||||
dreamLock
|
||||
sourceRoot
|
||||
;
|
||||
|
||||
inherit
|
||||
(dreamLockInterface)
|
||||
subsystemAttrs
|
||||
getSourceSpec
|
||||
getRoot
|
||||
getDependencies
|
||||
getCyclicDependencies
|
||||
defaultPackageName
|
||||
defaultPackageVersion
|
||||
packages
|
||||
packageVersions
|
||||
;
|
||||
|
||||
getSource = utils.dream-lock.getSource fetchedSources;
|
||||
});
|
||||
|
||||
# Makes the packages tree compatible with flakes schema.
|
||||
# For each package the attr `{pname}` will link to the latest release.
|
||||
# Other package versions will be inside: `{pname}.versions`
|
||||
# Adds a `default` package by using `defaultPackageName` and `defaultPackageVersion`.
|
||||
formattedOutputs =
|
||||
outputs
|
||||
// {
|
||||
packages = let
|
||||
allPackages = outputs.packages or {};
|
||||
|
||||
latestPackages =
|
||||
lib.mapAttrs'
|
||||
(pname: releases: let
|
||||
latest =
|
||||
releases."${dlib.latestVersion (b.attrNames releases)}";
|
||||
in (lib.nameValuePair
|
||||
"${pname}"
|
||||
(latest
|
||||
// {
|
||||
versions = releases;
|
||||
})))
|
||||
allPackages;
|
||||
|
||||
defaultPackage =
|
||||
allPackages
|
||||
."${dreamLockInterface.defaultPackageName}"
|
||||
."${dreamLockInterface.defaultPackageVersion}";
|
||||
in
|
||||
latestPackages // {default = defaultPackage;};
|
||||
};
|
||||
in
|
||||
formattedOutputs;
|
||||
|
||||
riseAndShine = throw ''
|
||||
`riseAndShine` is deprecated. See usage in readme.md.
|
||||
'';
|
||||
|
||||
makeOutputsForDreamLock = {
|
||||
dreamLock,
|
||||
sourceRoot ? null,
|
||||
fetcher ? null,
|
||||
builder ? null,
|
||||
builderArgs ? {},
|
||||
inject ? {},
|
||||
sourceOverrides ? oldSources: {},
|
||||
packageOverrides ? {},
|
||||
} @ args: let
|
||||
# parse dreamLock
|
||||
dreamLockLoaded = utils.dream-lock.readDreamLock {inherit (args) dreamLock;};
|
||||
dreamLock = dreamLockLoaded.lock;
|
||||
dreamLockInterface = dreamLockLoaded.interface;
|
||||
|
||||
builder' =
|
||||
if builder == null
|
||||
then findBuilder dreamLock
|
||||
else if l.isString builder
|
||||
then framework.buildersBySubsystem.${dreamLock._generic.subsystem}.${builder}
|
||||
else builder;
|
||||
|
||||
fetcher' =
|
||||
if fetcher == null
|
||||
then findFetcher dreamLock
|
||||
else fetcher;
|
||||
|
||||
fetchedSources =
|
||||
(fetchSources {
|
||||
inherit dreamLock sourceOverrides sourceRoot;
|
||||
fetcher = fetcher';
|
||||
})
|
||||
.fetchedSources;
|
||||
|
||||
builderOutputs = callBuilder {
|
||||
inherit
|
||||
dreamLock
|
||||
fetchedSources
|
||||
allOutputs
|
||||
sourceOverrides
|
||||
sourceRoot
|
||||
;
|
||||
|
||||
builder = builder';
|
||||
|
||||
inherit builderArgs;
|
||||
|
||||
packageOverrides =
|
||||
lib.recursiveUpdate
|
||||
(dreamOverrides."${dreamLock._generic.subsystem}" or {})
|
||||
(args.packageOverrides or {});
|
||||
|
||||
inject = args.inject or {};
|
||||
};
|
||||
|
||||
allOutputs = builderOutputs;
|
||||
in
|
||||
allOutputs;
|
||||
|
||||
translateProjects = {
|
||||
discoveredProjects ?
|
||||
framework.functions.discoverers.discoverProjects
|
||||
{inherit settings tree;},
|
||||
projects ? {},
|
||||
source ? throw "Pass either `source` or `tree` to translateProjects",
|
||||
tree ? dlib.prepareSourceTree {inherit source;},
|
||||
pname,
|
||||
settings ? [],
|
||||
} @ args: let
|
||||
getTranslator = translatorName:
|
||||
framework.translators.${translatorName};
|
||||
|
||||
isImpure = project: translatorName:
|
||||
(getTranslator translatorName).type == "impure";
|
||||
|
||||
getInvalidationHash = project:
|
||||
dlib.calcInvalidationHash {
|
||||
inherit project source;
|
||||
# TODO: add translatorArgs
|
||||
translatorArgs = {};
|
||||
translator = project.translator;
|
||||
inherit config;
|
||||
};
|
||||
|
||||
isResolved = project: let
|
||||
dreamLockExists =
|
||||
l.pathExists "${toString config.projectRoot}/${project.dreamLockPath}";
|
||||
|
||||
dreamLockValid =
|
||||
project.dreamLock._generic.invalidationHash
|
||||
or ""
|
||||
== project.invalidationHash;
|
||||
in
|
||||
dreamLockExists && dreamLockValid;
|
||||
|
||||
getProjectKey = project: "${project.name}_|_${project.subsystem}_|_${project.relPath}";
|
||||
|
||||
# list of projects extended with some information requried for processing
|
||||
projectsList =
|
||||
l.map
|
||||
(project: (let
|
||||
self =
|
||||
project
|
||||
// rec {
|
||||
dreamLock =
|
||||
(utils.dream-lock.readDreamLock {
|
||||
dreamLock = "${toString config.projectRoot}/${project.dreamLockPath}";
|
||||
})
|
||||
.lock;
|
||||
impure = isImpure project translator;
|
||||
invalidationHash = getInvalidationHash project;
|
||||
key = getProjectKey project;
|
||||
resolved = isResolved self;
|
||||
translator = project.translator or (l.head project.translators);
|
||||
};
|
||||
in
|
||||
self))
|
||||
discoveredProjects;
|
||||
|
||||
# projects without existing valid dream-lock.json
|
||||
projectsPureUnresolved =
|
||||
l.filter
|
||||
(project: ! project.resolved && ! project.impure)
|
||||
projectsList;
|
||||
|
||||
# already resolved projects
|
||||
projectsResolved =
|
||||
l.filter
|
||||
(project: project.resolved)
|
||||
projectsList;
|
||||
|
||||
# list of pure projects extended with 'dreamLock' attribute
|
||||
projectsResolvedOnTheFly =
|
||||
l.forEach projectsPureUnresolved
|
||||
(proj: let
|
||||
translator = getTranslator proj.translator;
|
||||
dreamLock'' = translator.finalTranslate {
|
||||
inherit source tree discoveredProjects;
|
||||
project = proj;
|
||||
};
|
||||
|
||||
/*
|
||||
simpleTranslate2 exposes result via `.result` in order to allow for
|
||||
unit testing via `.inputs`.
|
||||
*/
|
||||
dreamLock' = dreamLock''.result or dreamLock'';
|
||||
|
||||
dreamLock =
|
||||
dreamLock'
|
||||
// {
|
||||
_generic =
|
||||
dreamLock'._generic
|
||||
// {
|
||||
invalidationHash = proj.invalidationHash;
|
||||
};
|
||||
};
|
||||
in
|
||||
proj
|
||||
// {
|
||||
inherit dreamLock;
|
||||
});
|
||||
|
||||
resolvedProjects = projectsResolved ++ projectsResolvedOnTheFly;
|
||||
in
|
||||
resolvedProjects;
|
||||
|
||||
# transform a list of resolved projects to buildable outputs
|
||||
realizeProjects = {
|
||||
inject ? {},
|
||||
translatedProjects ? translateProjects {inherit pname settings source;},
|
||||
# alternative way of calling (for debugging)
|
||||
pname ? null,
|
||||
source ? null,
|
||||
packageOverrides ? {},
|
||||
sourceOverrides ? oldSources: {},
|
||||
settings ? [],
|
||||
}: let
|
||||
dreamLocks = l.forEach translatedProjects (proj: proj.dreamLock);
|
||||
|
||||
defaultSourceOverride = dreamLock:
|
||||
if source == null
|
||||
then {}
|
||||
else let
|
||||
defaultPackage = dreamLock._generic.defaultPackage;
|
||||
defaultPackageVersion =
|
||||
dreamLock._generic.packages."${defaultPackage}";
|
||||
in {
|
||||
"${defaultPackage}"."${defaultPackageVersion}" = "${source}/${dreamLock._generic.location}";
|
||||
};
|
||||
|
||||
# extends each package with a `.resolve` attribute
|
||||
# and applies sourceOverrides
|
||||
outputsForProject = proj: let
|
||||
outputs = makeOutputsForDreamLock {
|
||||
inherit inject packageOverrides;
|
||||
sourceRoot = source;
|
||||
builder = proj.builder or null;
|
||||
dreamLock = proj.dreamLock;
|
||||
sourceOverrides = oldSources:
|
||||
dlib.recursiveUpdateUntilDepth
|
||||
1
|
||||
(defaultSourceOverride proj.dreamLock)
|
||||
(sourceOverrides oldSources);
|
||||
};
|
||||
in
|
||||
outputs
|
||||
// {
|
||||
packages =
|
||||
l.mapAttrs
|
||||
(pname: pkg:
|
||||
pkg.overrideAttrs (old: {
|
||||
passthru =
|
||||
old.passthru
|
||||
or {}
|
||||
// {
|
||||
resolve = utils.makeTranslateScript {
|
||||
inherit source;
|
||||
invalidationHash = proj.invalidationHash;
|
||||
project = proj;
|
||||
};
|
||||
};
|
||||
}))
|
||||
(outputs.packages or {});
|
||||
};
|
||||
|
||||
projectOutputs = l.map outputsForProject translatedProjects;
|
||||
in
|
||||
dlib.mergeFlakes projectOutputs;
|
||||
|
||||
generateImpureResolveScript = {
|
||||
source,
|
||||
impureProjects,
|
||||
}: let
|
||||
impureResolveScriptsList =
|
||||
l.listToAttrs
|
||||
(
|
||||
l.map
|
||||
(
|
||||
project:
|
||||
l.nameValuePair
|
||||
"Name: ${project.name}; Subsystem: ${project.subsystem or "?"}; relPath: ${project.relPath}"
|
||||
(utils.makeTranslateScript {inherit project source;})
|
||||
)
|
||||
impureProjects
|
||||
);
|
||||
|
||||
resolveImpureScript =
|
||||
utils.writePureShellScriptBin
|
||||
"resolve"
|
||||
[]
|
||||
''
|
||||
${l.concatStringsSep "\n"
|
||||
(l.mapAttrsToList
|
||||
(title: script: ''
|
||||
echo "Resolving:: ${title}"
|
||||
${script}/bin/resolve
|
||||
'')
|
||||
impureResolveScriptsList)}
|
||||
'';
|
||||
in
|
||||
resolveImpureScript;
|
||||
|
||||
makeOutputs = {
|
||||
source ? throw "pass a 'source' to 'makeOutputs'",
|
||||
discoveredProjects ?
|
||||
framework.functions.discoverers.discoverProjects {
|
||||
inherit settings source;
|
||||
},
|
||||
pname ? null,
|
||||
projects ? {},
|
||||
settings ? [],
|
||||
packageOverrides ? {},
|
||||
sourceOverrides ? old: {},
|
||||
inject ? {},
|
||||
}: let
|
||||
# if projects are defined manually, ignore discoveredProjects
|
||||
finalProjects =
|
||||
if projects != {}
|
||||
then let
|
||||
projectsList = l.attrValues projects;
|
||||
in
|
||||
# skip discovery and just add required attributes to project list
|
||||
l.forEach projectsList
|
||||
(proj:
|
||||
proj
|
||||
// {
|
||||
relPath = proj.relPath or "";
|
||||
translator = proj.translator or (l.head proj.translators);
|
||||
dreamLockPath =
|
||||
framework.functions.discoverers.getDreamLockPath
|
||||
proj
|
||||
(l.head projectsList);
|
||||
})
|
||||
else discoveredProjects;
|
||||
|
||||
impureProjects =
|
||||
l.filter
|
||||
(proj:
|
||||
framework.translators."${proj.translator}".type
|
||||
== "impure")
|
||||
finalProjects;
|
||||
|
||||
resolveImpureScript = generateImpureResolveScript {
|
||||
inherit impureProjects source;
|
||||
};
|
||||
|
||||
translatedProjects = translateProjects {
|
||||
discoveredProjects = finalProjects;
|
||||
inherit
|
||||
pname
|
||||
settings
|
||||
source
|
||||
;
|
||||
};
|
||||
|
||||
realizedProjects = realizeProjects {
|
||||
inherit
|
||||
inject
|
||||
packageOverrides
|
||||
sourceOverrides
|
||||
translatedProjects
|
||||
source
|
||||
;
|
||||
};
|
||||
|
||||
impureFakeDerivations =
|
||||
l.listToAttrs
|
||||
(l.map
|
||||
(proj:
|
||||
l.nameValuePair
|
||||
proj.name
|
||||
rec {
|
||||
type = "derivation";
|
||||
name = proj.name;
|
||||
resolve = utils.makeTranslateScript {
|
||||
project = proj;
|
||||
inherit source;
|
||||
};
|
||||
drvPath = throw ''
|
||||
The ${proj.subsystem} package ${proj.name} contains unresolved impurities.
|
||||
Resolve by running the .resolve attribute of this derivation
|
||||
or by resolving all impure projects by running the `resolveImpure` package
|
||||
'';
|
||||
})
|
||||
impureProjects);
|
||||
in
|
||||
realizedProjects
|
||||
// {
|
||||
packages =
|
||||
l.warnIf
|
||||
(realizeProjects.packages.resolveImpure or null != null)
|
||||
''
|
||||
a builder outputted a package named 'resolveImpure'
|
||||
this will be overridden by dream2nix!
|
||||
''
|
||||
impureFakeDerivations
|
||||
// (realizedProjects.packages or {})
|
||||
// {resolveImpure = resolveImpureScript;};
|
||||
};
|
||||
in {
|
||||
inherit
|
||||
callPackageDream
|
||||
dream2nixWithExternals
|
||||
framework
|
||||
fetchSources
|
||||
realizeProjects
|
||||
translateProjects
|
||||
riseAndShine
|
||||
updaters
|
||||
makeOutputsForDreamLock
|
||||
makeOutputs
|
||||
;
|
||||
}
|
||||
import ./modules/framework.nix
|
||||
|
17
src/lib.nix
17
src/lib.nix
@ -12,10 +12,9 @@
|
||||
l = lib // builtins;
|
||||
|
||||
initDream2nix = config: pkgs:
|
||||
import ./default.nix
|
||||
{
|
||||
loadedConfig = config;
|
||||
inherit inputs pkgs externalPaths externalSources;
|
||||
import ./modules/framework.nix {
|
||||
inherit lib inputs pkgs externalPaths externalSources;
|
||||
dream2nixConfig = config;
|
||||
};
|
||||
|
||||
loadConfig = config'': let
|
||||
@ -89,13 +88,9 @@
|
||||
config = loadConfig (args.config or {});
|
||||
|
||||
framework = import ./modules/framework.nix {
|
||||
inherit lib externalSources inputs;
|
||||
inherit lib externalPaths externalSources inputs;
|
||||
dream2nixConfig = config;
|
||||
dream2nixConfigFile = l.toFile "dream2nix-config.json" (l.toJSON config);
|
||||
pkgs = throw "pkgs is not available before nixpkgs is imported";
|
||||
externals = throw "externals is not available before nixpkgs is imported";
|
||||
dream2nixWithExternals = throw "not available before nixpkgs is imported";
|
||||
dream2nixInterface = throw "not available before nixpkgs is imported";
|
||||
};
|
||||
|
||||
systems =
|
||||
@ -140,7 +135,7 @@
|
||||
l.mapAttrs
|
||||
(system: pkgs: let
|
||||
dream2nix = dream2nixFor."${system}";
|
||||
allOutputs = dream2nix.makeOutputs {
|
||||
allOutputs = dream2nix.dream2nixInterface.makeOutputs {
|
||||
discoveredProjects = finalProjects;
|
||||
inherit
|
||||
source
|
||||
@ -193,7 +188,7 @@
|
||||
l.mapAttrs
|
||||
(system: pkgs: let
|
||||
dream2nix = dream2nixFor."${system}";
|
||||
allOutputs = dream2nix.framework.utils.makeOutputsForIndexes {
|
||||
allOutputs = dream2nix.utils.makeOutputsForIndexes {
|
||||
inherit
|
||||
source
|
||||
indexes
|
||||
|
6
src/modules/dream2nix-interface/default.nix
Normal file
6
src/modules/dream2nix-interface/default.nix
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
imports = [
|
||||
./implementation.nix
|
||||
./interface.nix
|
||||
];
|
||||
}
|
523
src/modules/dream2nix-interface/implementation.nix
Normal file
523
src/modules/dream2nix-interface/implementation.nix
Normal file
@ -0,0 +1,523 @@
|
||||
{config, ...}: let
|
||||
l = config.lib // builtins;
|
||||
b = builtins;
|
||||
|
||||
inherit (config) dream2nixConfig pkgs utils dlib lib;
|
||||
|
||||
dreamOverrides = let
|
||||
overridesDirs =
|
||||
config.dream2nixConfig.overridesDirs
|
||||
++ (lib.optionals (b ? getEnv && b.getEnv "d2nOverridesDir" != "") [
|
||||
(b.getEnv "d2nOverridesDir")
|
||||
]);
|
||||
in
|
||||
utils.loadOverridesDirs overridesDirs pkgs;
|
||||
|
||||
# automatically find a suitable builder for a given dream lock
|
||||
findBuilder = dreamLock: let
|
||||
subsystem = dreamLock._generic.subsystem;
|
||||
in
|
||||
if ! config.buildersBySubsystem ? ${subsystem}
|
||||
then throw "Could not find any builder for subsystem '${subsystem}'"
|
||||
else config.buildersBySubsystem.${subsystem}.default;
|
||||
|
||||
# detect if granular or combined fetching must be used
|
||||
findFetcher = dreamLock:
|
||||
if null != dreamLock._generic.sourcesAggregatedHash or null
|
||||
then config.functions.combinedFetcher
|
||||
else config.functions.defaultFetcher;
|
||||
|
||||
# fetch only sources and do not build
|
||||
fetchSources = {
|
||||
dreamLock,
|
||||
sourceRoot ? null,
|
||||
fetcher ? null,
|
||||
extract ? false,
|
||||
sourceOverrides ? oldSources: {},
|
||||
} @ args: let
|
||||
# if dream lock is a file, read and parse it
|
||||
dreamLock' = (utils.dream-lock.readDreamLock {inherit dreamLock;}).lock;
|
||||
|
||||
fetcher =
|
||||
if args.fetcher or null == null
|
||||
then findFetcher dreamLock'
|
||||
else args.fetcher;
|
||||
|
||||
fetched = fetcher rec {
|
||||
inherit sourceOverrides sourceRoot;
|
||||
defaultPackage = dreamLock._generic.defaultPackage;
|
||||
defaultPackageVersion = dreamLock._generic.packages."${defaultPackage}";
|
||||
sources = dreamLock'.sources;
|
||||
sourcesAggregatedHash = dreamLock'._generic.sourcesAggregatedHash;
|
||||
};
|
||||
|
||||
fetchedSources = fetched.fetchedSources;
|
||||
in
|
||||
fetched
|
||||
// {
|
||||
fetchedSources =
|
||||
if extract
|
||||
then
|
||||
lib.mapAttrs
|
||||
(key: source: utils.extractSource {inherit source;})
|
||||
fetchedSources
|
||||
else fetchedSources;
|
||||
};
|
||||
|
||||
# build a dream lock via a specific builder
|
||||
callBuilder = {
|
||||
builder,
|
||||
builderArgs,
|
||||
fetchedSources,
|
||||
sourceRoot,
|
||||
dreamLock,
|
||||
inject,
|
||||
sourceOverrides,
|
||||
packageOverrides,
|
||||
allOutputs,
|
||||
} @ args: let
|
||||
# inject dependencies
|
||||
dreamLock = utils.dream-lock.injectDependencies args.dreamLock inject;
|
||||
|
||||
dreamLockInterface = (utils.dream-lock.readDreamLock {inherit dreamLock;}).interface;
|
||||
|
||||
produceDerivation = name: pkg:
|
||||
utils.applyOverridesToPackage {
|
||||
inherit pkg;
|
||||
outputs = allOutputs;
|
||||
pname = name;
|
||||
conditionalOverrides = packageOverrides;
|
||||
};
|
||||
|
||||
outputs = builder.build (builderArgs
|
||||
// {
|
||||
inherit
|
||||
produceDerivation
|
||||
dreamLock
|
||||
sourceRoot
|
||||
;
|
||||
|
||||
inherit
|
||||
(dreamLockInterface)
|
||||
subsystemAttrs
|
||||
getSourceSpec
|
||||
getRoot
|
||||
getDependencies
|
||||
getCyclicDependencies
|
||||
defaultPackageName
|
||||
defaultPackageVersion
|
||||
packages
|
||||
packageVersions
|
||||
;
|
||||
|
||||
getSource = utils.dream-lock.getSource fetchedSources;
|
||||
});
|
||||
|
||||
# Makes the packages tree compatible with flakes schema.
|
||||
# For each package the attr `{pname}` will link to the latest release.
|
||||
# Other package versions will be inside: `{pname}.versions`
|
||||
# Adds a `default` package by using `defaultPackageName` and `defaultPackageVersion`.
|
||||
formattedOutputs =
|
||||
outputs
|
||||
// {
|
||||
packages = let
|
||||
allPackages = outputs.packages or {};
|
||||
|
||||
latestPackages =
|
||||
lib.mapAttrs'
|
||||
(pname: releases: let
|
||||
latest =
|
||||
releases."${dlib.latestVersion (b.attrNames releases)}";
|
||||
in (lib.nameValuePair
|
||||
"${pname}"
|
||||
(latest
|
||||
// {
|
||||
versions = releases;
|
||||
})))
|
||||
allPackages;
|
||||
|
||||
defaultPackage =
|
||||
allPackages
|
||||
."${dreamLockInterface.defaultPackageName}"
|
||||
."${dreamLockInterface.defaultPackageVersion}";
|
||||
in
|
||||
latestPackages // {default = defaultPackage;};
|
||||
};
|
||||
in
|
||||
formattedOutputs;
|
||||
|
||||
riseAndShine = throw ''
|
||||
`riseAndShine` is deprecated. See usage in readme.md.
|
||||
'';
|
||||
|
||||
makeOutputsForDreamLock = {
|
||||
dreamLock,
|
||||
sourceRoot ? null,
|
||||
fetcher ? null,
|
||||
builder ? null,
|
||||
builderArgs ? {},
|
||||
inject ? {},
|
||||
sourceOverrides ? oldSources: {},
|
||||
packageOverrides ? {},
|
||||
} @ args: let
|
||||
# parse dreamLock
|
||||
dreamLockLoaded = utils.dream-lock.readDreamLock {inherit (args) dreamLock;};
|
||||
dreamLock = dreamLockLoaded.lock;
|
||||
dreamLockInterface = dreamLockLoaded.interface;
|
||||
|
||||
builder' =
|
||||
if builder == null
|
||||
then findBuilder dreamLock
|
||||
else if l.isString builder
|
||||
then config.buildersBySubsystem.${dreamLock._generic.subsystem}.${builder}
|
||||
else builder;
|
||||
|
||||
fetcher' =
|
||||
if fetcher == null
|
||||
then findFetcher dreamLock
|
||||
else fetcher;
|
||||
|
||||
fetchedSources =
|
||||
(fetchSources {
|
||||
inherit dreamLock sourceOverrides sourceRoot;
|
||||
fetcher = fetcher';
|
||||
})
|
||||
.fetchedSources;
|
||||
|
||||
builderOutputs = callBuilder {
|
||||
inherit
|
||||
dreamLock
|
||||
fetchedSources
|
||||
allOutputs
|
||||
sourceOverrides
|
||||
sourceRoot
|
||||
;
|
||||
|
||||
builder = builder';
|
||||
|
||||
inherit builderArgs;
|
||||
|
||||
packageOverrides =
|
||||
lib.recursiveUpdate
|
||||
(dreamOverrides."${dreamLock._generic.subsystem}" or {})
|
||||
(args.packageOverrides or {});
|
||||
|
||||
inject = args.inject or {};
|
||||
};
|
||||
|
||||
allOutputs = builderOutputs;
|
||||
in
|
||||
allOutputs;
|
||||
|
||||
translateProjects = {
|
||||
discoveredProjects ?
|
||||
config.functions.discoverers.discoverProjects
|
||||
{inherit settings tree;},
|
||||
projects ? {},
|
||||
source ? throw "Pass either `source` or `tree` to translateProjects",
|
||||
tree ? dlib.prepareSourceTree {inherit source;},
|
||||
pname,
|
||||
settings ? [],
|
||||
} @ args: let
|
||||
getTranslator = translatorName:
|
||||
config.translators.${translatorName};
|
||||
|
||||
isImpure = project: translatorName:
|
||||
(getTranslator translatorName).type == "impure";
|
||||
|
||||
getInvalidationHash = project:
|
||||
dlib.calcInvalidationHash {
|
||||
inherit project source;
|
||||
# TODO: add translatorArgs
|
||||
translatorArgs = {};
|
||||
translator = project.translator;
|
||||
config = dream2nixConfig;
|
||||
};
|
||||
|
||||
isResolved = project: let
|
||||
dreamLockExists =
|
||||
l.pathExists "${toString dream2nixConfig.projectRoot}/${project.dreamLockPath}";
|
||||
|
||||
dreamLockValid =
|
||||
project.dreamLock._generic.invalidationHash
|
||||
or ""
|
||||
== project.invalidationHash;
|
||||
in
|
||||
dreamLockExists && dreamLockValid;
|
||||
|
||||
getProjectKey = project: "${project.name}_|_${project.subsystem}_|_${project.relPath}";
|
||||
|
||||
# list of projects extended with some information requried for processing
|
||||
projectsList =
|
||||
l.map
|
||||
(project: (let
|
||||
self =
|
||||
project
|
||||
// rec {
|
||||
dreamLock =
|
||||
(utils.dream-lock.readDreamLock {
|
||||
dreamLock = "${toString dream2nixConfig.projectRoot}/${project.dreamLockPath}";
|
||||
})
|
||||
.lock;
|
||||
impure = isImpure project translator;
|
||||
invalidationHash = getInvalidationHash project;
|
||||
key = getProjectKey project;
|
||||
resolved = isResolved self;
|
||||
translator = project.translator or (l.head project.translators);
|
||||
};
|
||||
in
|
||||
self))
|
||||
discoveredProjects;
|
||||
|
||||
# projects without existing valid dream-lock.json
|
||||
projectsPureUnresolved =
|
||||
l.filter
|
||||
(project: ! project.resolved && ! project.impure)
|
||||
projectsList;
|
||||
|
||||
# already resolved projects
|
||||
projectsResolved =
|
||||
l.filter
|
||||
(project: project.resolved)
|
||||
projectsList;
|
||||
|
||||
# list of pure projects extended with 'dreamLock' attribute
|
||||
projectsResolvedOnTheFly =
|
||||
l.forEach projectsPureUnresolved
|
||||
(proj: let
|
||||
translator = getTranslator proj.translator;
|
||||
dreamLock'' = translator.finalTranslate {
|
||||
inherit source tree discoveredProjects;
|
||||
project = proj;
|
||||
};
|
||||
|
||||
/*
|
||||
simpleTranslate2 exposes result via `.result` in order to allow for
|
||||
unit testing via `.inputs`.
|
||||
*/
|
||||
dreamLock' = dreamLock''.result or dreamLock'';
|
||||
|
||||
dreamLock =
|
||||
dreamLock'
|
||||
// {
|
||||
_generic =
|
||||
dreamLock'._generic
|
||||
// {
|
||||
invalidationHash = proj.invalidationHash;
|
||||
};
|
||||
};
|
||||
in
|
||||
proj
|
||||
// {
|
||||
inherit dreamLock;
|
||||
});
|
||||
|
||||
resolvedProjects = projectsResolved ++ projectsResolvedOnTheFly;
|
||||
in
|
||||
resolvedProjects;
|
||||
|
||||
# transform a list of resolved projects to buildable outputs
|
||||
realizeProjects = {
|
||||
inject ? {},
|
||||
translatedProjects ? translateProjects {inherit pname settings source;},
|
||||
# alternative way of calling (for debugging)
|
||||
pname ? null,
|
||||
source ? null,
|
||||
packageOverrides ? {},
|
||||
sourceOverrides ? oldSources: {},
|
||||
settings ? [],
|
||||
}: let
|
||||
dreamLocks = l.forEach translatedProjects (proj: proj.dreamLock);
|
||||
|
||||
defaultSourceOverride = dreamLock:
|
||||
if source == null
|
||||
then {}
|
||||
else let
|
||||
defaultPackage = dreamLock._generic.defaultPackage;
|
||||
defaultPackageVersion =
|
||||
dreamLock._generic.packages."${defaultPackage}";
|
||||
in {
|
||||
"${defaultPackage}"."${defaultPackageVersion}" = "${source}/${dreamLock._generic.location}";
|
||||
};
|
||||
|
||||
# extends each package with a `.resolve` attribute
|
||||
# and applies sourceOverrides
|
||||
outputsForProject = proj: let
|
||||
outputs = makeOutputsForDreamLock {
|
||||
inherit inject packageOverrides;
|
||||
sourceRoot = source;
|
||||
builder = proj.builder or null;
|
||||
dreamLock = proj.dreamLock;
|
||||
sourceOverrides = oldSources:
|
||||
dlib.recursiveUpdateUntilDepth
|
||||
1
|
||||
(defaultSourceOverride proj.dreamLock)
|
||||
(sourceOverrides oldSources);
|
||||
};
|
||||
in
|
||||
outputs
|
||||
// {
|
||||
packages =
|
||||
l.mapAttrs
|
||||
(pname: pkg:
|
||||
pkg.overrideAttrs (old: {
|
||||
passthru =
|
||||
old.passthru
|
||||
or {}
|
||||
// {
|
||||
resolve = utils.makeTranslateScript {
|
||||
inherit source;
|
||||
invalidationHash = proj.invalidationHash;
|
||||
project = proj;
|
||||
};
|
||||
};
|
||||
}))
|
||||
(outputs.packages or {});
|
||||
};
|
||||
|
||||
projectOutputs = l.map outputsForProject translatedProjects;
|
||||
in
|
||||
dlib.mergeFlakes projectOutputs;
|
||||
|
||||
generateImpureResolveScript = {
|
||||
source,
|
||||
impureProjects,
|
||||
}: let
|
||||
impureResolveScriptsList =
|
||||
l.listToAttrs
|
||||
(
|
||||
l.map
|
||||
(
|
||||
project:
|
||||
l.nameValuePair
|
||||
"Name: ${project.name}; Subsystem: ${project.subsystem or "?"}; relPath: ${project.relPath}"
|
||||
(utils.makeTranslateScript {inherit project source;})
|
||||
)
|
||||
impureProjects
|
||||
);
|
||||
|
||||
resolveImpureScript =
|
||||
utils.writePureShellScriptBin
|
||||
"resolve"
|
||||
[]
|
||||
''
|
||||
${l.concatStringsSep "\n"
|
||||
(l.mapAttrsToList
|
||||
(title: script: ''
|
||||
echo "Resolving:: ${title}"
|
||||
${script}/bin/resolve
|
||||
'')
|
||||
impureResolveScriptsList)}
|
||||
'';
|
||||
in
|
||||
resolveImpureScript;
|
||||
|
||||
makeOutputs = {
|
||||
source ? throw "pass a 'source' to 'makeOutputs'",
|
||||
discoveredProjects ?
|
||||
config.functions.discoverers.discoverProjects {
|
||||
inherit settings source;
|
||||
},
|
||||
pname ? null,
|
||||
projects ? {},
|
||||
settings ? [],
|
||||
packageOverrides ? {},
|
||||
sourceOverrides ? old: {},
|
||||
inject ? {},
|
||||
}: let
|
||||
# if projects are defined manually, ignore discoveredProjects
|
||||
finalProjects =
|
||||
if projects != {}
|
||||
then let
|
||||
projectsList = l.attrValues projects;
|
||||
in
|
||||
# skip discovery and just add required attributes to project list
|
||||
l.forEach projectsList
|
||||
(proj:
|
||||
proj
|
||||
// {
|
||||
relPath = proj.relPath or "";
|
||||
translator = proj.translator or (l.head proj.translators);
|
||||
dreamLockPath =
|
||||
config.functions.discoverers.getDreamLockPath
|
||||
proj
|
||||
(l.head projectsList);
|
||||
})
|
||||
else discoveredProjects;
|
||||
|
||||
impureProjects =
|
||||
l.filter
|
||||
(proj:
|
||||
config.translators."${proj.translator}".type
|
||||
== "impure")
|
||||
finalProjects;
|
||||
|
||||
resolveImpureScript = generateImpureResolveScript {
|
||||
inherit impureProjects source;
|
||||
};
|
||||
|
||||
translatedProjects = translateProjects {
|
||||
discoveredProjects = finalProjects;
|
||||
inherit
|
||||
pname
|
||||
settings
|
||||
source
|
||||
;
|
||||
};
|
||||
|
||||
realizedProjects = realizeProjects {
|
||||
inherit
|
||||
inject
|
||||
packageOverrides
|
||||
sourceOverrides
|
||||
translatedProjects
|
||||
source
|
||||
;
|
||||
};
|
||||
|
||||
impureFakeDerivations =
|
||||
l.listToAttrs
|
||||
(l.map
|
||||
(proj:
|
||||
l.nameValuePair
|
||||
proj.name
|
||||
{
|
||||
type = "derivation";
|
||||
name = proj.name;
|
||||
resolve = utils.makeTranslateScript {
|
||||
project = proj;
|
||||
inherit source;
|
||||
};
|
||||
drvPath = throw ''
|
||||
The ${proj.subsystem} package ${proj.name} contains unresolved impurities.
|
||||
Resolve by running the .resolve attribute of this derivation
|
||||
or by resolving all impure projects by running the `resolveImpure` package
|
||||
'';
|
||||
})
|
||||
impureProjects);
|
||||
in
|
||||
realizedProjects
|
||||
// {
|
||||
packages =
|
||||
l.warnIf
|
||||
(realizeProjects.packages.resolveImpure or null != null)
|
||||
''
|
||||
a builder outputted a package named 'resolveImpure'
|
||||
this will be overridden by dream2nix!
|
||||
''
|
||||
impureFakeDerivations
|
||||
// (realizedProjects.packages or {})
|
||||
// {resolveImpure = resolveImpureScript;};
|
||||
};
|
||||
in {
|
||||
config.dream2nixInterface = {
|
||||
inherit
|
||||
fetchSources
|
||||
realizeProjects
|
||||
translateProjects
|
||||
riseAndShine
|
||||
makeOutputsForDreamLock
|
||||
makeOutputs
|
||||
;
|
||||
};
|
||||
}
|
10
src/modules/dream2nix-interface/interface.nix
Normal file
10
src/modules/dream2nix-interface/interface.nix
Normal file
@ -0,0 +1,10 @@
|
||||
{config, ...}: let
|
||||
l = config.lib // builtins;
|
||||
t = l.types;
|
||||
in {
|
||||
options = {
|
||||
dream2nixInterface = l.mkOption {
|
||||
type = t.lazyAttrsOf t.raw;
|
||||
};
|
||||
};
|
||||
}
|
6
src/modules/externals/default.nix
vendored
Normal file
6
src/modules/externals/default.nix
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
imports = [
|
||||
./implementation.nix
|
||||
./interface.nix
|
||||
];
|
||||
}
|
103
src/modules/externals/implementation.nix
vendored
Normal file
103
src/modules/externals/implementation.nix
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
{config, ...}: let
|
||||
l = config.lib // builtins;
|
||||
inherit (config) pkgs externalSources;
|
||||
in {
|
||||
config = {
|
||||
externals = {
|
||||
devshell = {
|
||||
makeShell = import "${externalSources.devshell}/modules" pkgs;
|
||||
imports.c = "${externalSources.devshell}/extra/language/c.nix";
|
||||
};
|
||||
crane = let
|
||||
importLibFile = name: import "${externalSources.crane}/lib/${name}.nix";
|
||||
|
||||
makeHook = attrs: name:
|
||||
pkgs.makeSetupHook
|
||||
({inherit name;} // attrs)
|
||||
"${externalSources.crane}/pkgs/${name}.sh";
|
||||
genHooks = names: attrs: l.genAttrs names (makeHook attrs);
|
||||
in
|
||||
{
|
||||
cargoHostTarget,
|
||||
cargoBuildBuild,
|
||||
}: rec {
|
||||
otherHooks =
|
||||
genHooks [
|
||||
"cargoHelperFunctions"
|
||||
"configureCargoCommonVarsHook"
|
||||
"configureCargoVendoredDepsHook"
|
||||
]
|
||||
{};
|
||||
installHooks =
|
||||
genHooks [
|
||||
"inheritCargoArtifactsHook"
|
||||
"installCargoArtifactsHook"
|
||||
]
|
||||
{
|
||||
substitutions = {
|
||||
zstd = "${pkgs.pkgsBuildBuild.zstd}/bin/zstd";
|
||||
};
|
||||
};
|
||||
installLogHook = genHooks ["installFromCargoBuildLogHook"] {
|
||||
substitutions = {
|
||||
cargo = "${cargoBuildBuild}/bin/cargo";
|
||||
jq = "${pkgs.pkgsBuildBuild.jq}/bin/jq";
|
||||
};
|
||||
};
|
||||
|
||||
# These aren't used by dream2nix
|
||||
crateNameFromCargoToml = null;
|
||||
vendorCargoDeps = null;
|
||||
|
||||
writeTOML = importLibFile "writeTOML" {
|
||||
inherit (pkgs) runCommand pkgsBuildBuild;
|
||||
};
|
||||
cleanCargoToml = importLibFile "cleanCargoToml" {};
|
||||
findCargoFiles = importLibFile "findCargoFiles" {
|
||||
inherit (pkgs) lib;
|
||||
};
|
||||
mkDummySrc = importLibFile "mkDummySrc" {
|
||||
inherit (pkgs) writeText runCommandLocal lib;
|
||||
inherit writeTOML cleanCargoToml findCargoFiles;
|
||||
};
|
||||
|
||||
mkCargoDerivation = importLibFile "mkCargoDerivation" {
|
||||
cargo = cargoHostTarget;
|
||||
inherit (pkgs) stdenv lib;
|
||||
inherit
|
||||
(installHooks)
|
||||
inheritCargoArtifactsHook
|
||||
installCargoArtifactsHook
|
||||
;
|
||||
inherit
|
||||
(otherHooks)
|
||||
configureCargoCommonVarsHook
|
||||
configureCargoVendoredDepsHook
|
||||
;
|
||||
cargoHelperFunctionsHook = otherHooks.cargoHelperFunctions;
|
||||
};
|
||||
buildDepsOnly = importLibFile "buildDepsOnly" {
|
||||
inherit
|
||||
mkCargoDerivation
|
||||
crateNameFromCargoToml
|
||||
vendorCargoDeps
|
||||
mkDummySrc
|
||||
;
|
||||
};
|
||||
cargoBuild = importLibFile "cargoBuild" {
|
||||
inherit
|
||||
mkCargoDerivation
|
||||
buildDepsOnly
|
||||
crateNameFromCargoToml
|
||||
vendorCargoDeps
|
||||
;
|
||||
};
|
||||
buildPackage = importLibFile "buildPackage" {
|
||||
inherit (pkgs) removeReferencesTo lib;
|
||||
inherit (installLogHook) installFromCargoBuildLogHook;
|
||||
inherit cargoBuild;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
10
src/modules/externals/interface.nix
vendored
Normal file
10
src/modules/externals/interface.nix
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{config, ...}: let
|
||||
l = config.lib // builtins;
|
||||
t = l.types;
|
||||
in {
|
||||
options = {
|
||||
externals = l.mkOption {
|
||||
type = t.lazyAttrsOf t.raw;
|
||||
};
|
||||
};
|
||||
}
|
@ -27,7 +27,7 @@ in {
|
||||
|
||||
outputs =
|
||||
l.mapAttrs
|
||||
(_: args: instance.makeOutputs args)
|
||||
(_: args: instance.dream2nixInterface.makeOutputs args)
|
||||
config.dream2nix.inputs;
|
||||
|
||||
getAttrFromOutputs = attrName:
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
lib,
|
||||
dream2nixConfig,
|
||||
lib ? (args.pkgs or (import <nixpkgs> {})).lib,
|
||||
dream2nixConfig ? {},
|
||||
...
|
||||
} @ args: let
|
||||
topLevel = import ./top-level.nix args;
|
||||
|
@ -41,18 +41,18 @@
|
||||
--show-trace --impure --raw --expr "
|
||||
let
|
||||
dream2nix = import ${dream2nixWithExternals} {
|
||||
config = ${dream2nixConfigFile};
|
||||
dream2nixConfig = ${dream2nixConfigFile};
|
||||
};
|
||||
translatorArgs =
|
||||
(builtins.fromJSON
|
||||
(builtins.unsafeDiscardStringContext (builtins.readFile '''$1''')));
|
||||
dreamLock' =
|
||||
dream2nix.framework.translatorsBySubsystem.${subsystem}.${name}.finalTranslate
|
||||
dream2nix.translatorsBySubsystem.${subsystem}.${name}.finalTranslate
|
||||
translatorArgs;
|
||||
# simpleTranslate2 puts dream-lock in result
|
||||
dreamLock = dreamLock'.result or dreamLock';
|
||||
in
|
||||
dream2nix.framework.utils.dream-lock.toJSON
|
||||
dream2nix.utils.dream-lock.toJSON
|
||||
# don't use nix to detect cycles, this will be more efficient in python
|
||||
(dreamLock // {
|
||||
_generic = builtins.removeAttrs dreamLock._generic [ \"cyclicDependencies\" ];
|
||||
|
@ -1,15 +1,43 @@
|
||||
{
|
||||
externals,
|
||||
externalSources,
|
||||
inputs,
|
||||
lib,
|
||||
pkgs,
|
||||
dream2nixConfig,
|
||||
dream2nixConfigFile,
|
||||
dream2nixWithExternals,
|
||||
dream2nixInterface,
|
||||
inputs ?
|
||||
(import ../../flake-compat.nix {
|
||||
src = ../../.;
|
||||
inherit (pkgs) system;
|
||||
})
|
||||
.inputs,
|
||||
lib ? pkgs.lib,
|
||||
pkgs ? import <nixpkgs> {},
|
||||
dream2nixConfig ?
|
||||
if builtins ? getEnv && builtins.getEnv "dream2nixConfig" != ""
|
||||
# if called via CLI, load config via env
|
||||
then builtins.toPath (builtins.getEnv "dream2nixConfig")
|
||||
# load from default directory
|
||||
else {},
|
||||
externalPaths ? null,
|
||||
externalSources ? null,
|
||||
} @ args: let
|
||||
b = builtins;
|
||||
t = lib.types;
|
||||
|
||||
externalDir =
|
||||
if externalPaths != null
|
||||
then
|
||||
(import ../utils/external-dir.nix {
|
||||
inherit externalPaths externalSources pkgs;
|
||||
})
|
||||
# if called via CLI, load externals via env
|
||||
else if b ? getEnv && b.getEnv "d2nExternalDir" != ""
|
||||
then ../. + (b.getEnv "d2nExternalDir")
|
||||
# load from default directory
|
||||
else ../external;
|
||||
|
||||
externalSources =
|
||||
args.externalSources
|
||||
or (
|
||||
lib.genAttrs
|
||||
(lib.attrNames (builtins.readDir externalDir))
|
||||
(inputName: "${../. + externalDir}/${inputName}")
|
||||
);
|
||||
in {
|
||||
imports = [
|
||||
./functions.discoverers
|
||||
@ -34,41 +62,64 @@ in {
|
||||
./dlib.parsing
|
||||
./dlib.construct
|
||||
./dlib.simpleTranslate2
|
||||
./externals
|
||||
./dream2nix-interface
|
||||
];
|
||||
options = {
|
||||
lib = lib.mkOption {
|
||||
type = t.raw;
|
||||
};
|
||||
externals = lib.mkOption {
|
||||
type = t.lazyAttrsOf t.raw;
|
||||
};
|
||||
externalSources = lib.mkOption {
|
||||
type = t.lazyAttrsOf t.path;
|
||||
};
|
||||
inputs = lib.mkOption {
|
||||
type = t.lazyAttrsOf t.attrs;
|
||||
};
|
||||
pkgs = lib.mkOption {
|
||||
type = t.raw;
|
||||
};
|
||||
externalDir = lib.mkOption {
|
||||
type = t.path;
|
||||
};
|
||||
externalPaths = lib.mkOption {
|
||||
type = t.listOf t.str;
|
||||
};
|
||||
externalSources = lib.mkOption {
|
||||
type = t.lazyAttrsOf t.path;
|
||||
};
|
||||
dream2nixWithExternals = lib.mkOption {
|
||||
type = t.path;
|
||||
};
|
||||
dream2nixConfig = lib.mkOption {
|
||||
type = t.submoduleWith {
|
||||
modules = [./config];
|
||||
};
|
||||
};
|
||||
dream2nixWithExternals = lib.mkOption {
|
||||
type = t.path;
|
||||
};
|
||||
dream2nixConfigFile = lib.mkOption {
|
||||
type = t.path;
|
||||
};
|
||||
dream2nixInterface = lib.mkOption {
|
||||
type = t.raw;
|
||||
};
|
||||
};
|
||||
config =
|
||||
args
|
||||
// {
|
||||
lib = args.lib // builtins;
|
||||
};
|
||||
config = {
|
||||
inherit
|
||||
dream2nixConfig
|
||||
pkgs
|
||||
inputs
|
||||
externalPaths
|
||||
externalSources
|
||||
externalDir
|
||||
;
|
||||
|
||||
lib = lib // builtins;
|
||||
|
||||
dream2nixConfigFile = b.toFile "dream2nix-config.json" (b.toJSON dream2nixConfig);
|
||||
|
||||
# the location of the dream2nix framework for self references (update scripts, etc.)
|
||||
dream2nixWithExternals =
|
||||
if b.pathExists (../. + "/external")
|
||||
then ../.
|
||||
else
|
||||
pkgs.runCommandLocal "dream2nix-full-src" {} ''
|
||||
cp -r ${../.} $out
|
||||
chmod +w $out
|
||||
mkdir $out/external
|
||||
cp -r ${externalDir}/* $out/external/
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ def aggregate_hashes(lock, outputDreamLock, dream2nix_src, dream2nix_config):
|
||||
# compute FOD hash of aggregated sources
|
||||
proc = nix(
|
||||
"build", "--impure", "-L", "--show-trace", "--expr",
|
||||
f"(import {dream2nix_src} {{ config = {dream2nix_config}; }}).fetchSources {{ dreamLock = {outputDreamLock}; }}"
|
||||
f"(import {dream2nix_src} {{ dream2nixConfig = {dream2nix_config}; }}).dream2nixInterface.fetchSources {{ dreamLock = {outputDreamLock}; }}"
|
||||
)
|
||||
print(proc.stderr.decode())
|
||||
# read the output hash from the failed build log
|
||||
|
@ -25,7 +25,7 @@ def callNixFunction(function_path, **kwargs):
|
||||
d2n = (import {dream2nix_src} {{}});
|
||||
in
|
||||
builtins.toJSON (
|
||||
(d2n.framework.dlib.callViaEnv d2n.{function_path})
|
||||
(d2n.dlib.callViaEnv d2n.{function_path})
|
||||
)
|
||||
''',
|
||||
env=env
|
||||
@ -63,11 +63,11 @@ def eval(attr_path, wrapper_code=None, **kwargs):
|
||||
d2n = (import {dream2nix_src} {{}});
|
||||
result' =
|
||||
if "{is_function_call}" == "True"
|
||||
then d2n.framework.dlib.callViaEnv d2n.{attr_path}
|
||||
then d2n.dlib.callViaEnv d2n.{attr_path}
|
||||
else d2n.{attr_path};
|
||||
result = (d2n.callPackageDream
|
||||
result = (d2n.pkgs.callPackage
|
||||
{wrapper_code_file.name}
|
||||
{{ result = result'; }});
|
||||
(d2n // {{ result = result'; }}));
|
||||
in
|
||||
b.toJSON (
|
||||
# remove override attributes added by callPackage
|
||||
@ -101,7 +101,7 @@ def buildNixFunction(function_path, **kwargs):
|
||||
let
|
||||
d2n = (import {dream2nix_src} {{}});
|
||||
in
|
||||
(d2n.framework.dlib.callViaEnv d2n.{function_path})
|
||||
(d2n.dlib.callViaEnv d2n.{function_path})
|
||||
''',
|
||||
env=env
|
||||
)
|
||||
|
@ -4,7 +4,7 @@
|
||||
}: cwd: let
|
||||
b = builtins;
|
||||
dream2nix = import dream2nixWithExternals {
|
||||
config = b.path {path = dream2nixConfig;};
|
||||
dream2nixConfig = b.path {path = dream2nixConfig;};
|
||||
};
|
||||
parsed = b.fromTOML (builtins.readFile "${cwd}/gomod2nix.toml");
|
||||
pkgs = import <nixpkgs> {};
|
||||
@ -14,7 +14,7 @@
|
||||
(goName: depAttrs: depAttrs // {inherit goName;})
|
||||
parsed;
|
||||
translated =
|
||||
dream2nix.framework.utils.simpleTranslate
|
||||
dream2nix.utils.simpleTranslate
|
||||
({
|
||||
getDepByNameVer,
|
||||
dependenciesByOriginalID,
|
||||
@ -68,4 +68,4 @@
|
||||
};
|
||||
});
|
||||
in
|
||||
dream2nix.framework.utils.dream-lock.toJSON translated
|
||||
dream2nix.utils.dream-lock.toJSON translated
|
||||
|
42
templates/default.nix
Normal file
42
templates/default.nix
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
lib,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
l = lib // builtins;
|
||||
in {
|
||||
flake = {
|
||||
templates =
|
||||
{
|
||||
default = self.templates.simple;
|
||||
simple = {
|
||||
description = "Simple dream2nix flake";
|
||||
path = ./templates/simple;
|
||||
welcomeText = ''
|
||||
You just created a simple dream2nix package!
|
||||
|
||||
start with typing `nix flake show` to discover the projects attributes.
|
||||
|
||||
commands:
|
||||
|
||||
- `nix develop` <-- enters the devShell
|
||||
- `nix build .#` <-- builds the default package (`.#default`)
|
||||
|
||||
|
||||
Start hacking and -_- have some fun!
|
||||
|
||||
> dont forget to add nix `result` folder to your `.gitignore`
|
||||
|
||||
'';
|
||||
};
|
||||
}
|
||||
// (
|
||||
l.genAttrs
|
||||
(self.lib.dlib.listDirs ../examples)
|
||||
(name: {
|
||||
description = "Example: ${name} template";
|
||||
path = ../examples/${name};
|
||||
})
|
||||
);
|
||||
};
|
||||
}
|
76
tests/default.nix
Normal file
76
tests/default.nix
Normal file
@ -0,0 +1,76 @@
|
||||
{
|
||||
inputs,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
perSystem = {
|
||||
config,
|
||||
pkgs,
|
||||
system,
|
||||
...
|
||||
}: let
|
||||
b = builtins;
|
||||
|
||||
callTests = f:
|
||||
pkgs.callPackage f {
|
||||
inherit self;
|
||||
framework = config.d2n;
|
||||
};
|
||||
in {
|
||||
apps = {
|
||||
tests-unit.type = "app";
|
||||
tests-unit.program =
|
||||
b.toString
|
||||
(callTests ./unit);
|
||||
|
||||
tests-integration.type = "app";
|
||||
tests-integration.program =
|
||||
b.toString
|
||||
(callTests ./integration);
|
||||
|
||||
tests-integration-d2n-flakes.type = "app";
|
||||
tests-integration-d2n-flakes.program =
|
||||
b.toString
|
||||
(callTests ./integration-d2n-flakes);
|
||||
|
||||
tests-examples.type = "app";
|
||||
tests-examples.program =
|
||||
b.toString
|
||||
(callTests ./examples);
|
||||
|
||||
tests-all.type = "app";
|
||||
tests-all.program =
|
||||
b.toString
|
||||
(config.d2n.utils.writePureShellScript
|
||||
[
|
||||
inputs.alejandra.defaultPackage.${system}
|
||||
pkgs.coreutils
|
||||
pkgs.gitMinimal
|
||||
pkgs.nix
|
||||
]
|
||||
''
|
||||
echo "check for correct formatting"
|
||||
WORKDIR=$(realpath ./.)
|
||||
cd $TMPDIR
|
||||
cp -r $WORKDIR ./repo
|
||||
cd ./repo
|
||||
${config.apps.format.program} --fail-on-change
|
||||
cd -
|
||||
|
||||
echo "running unit tests"
|
||||
${config.apps.tests-unit.program}
|
||||
|
||||
echo "running integration tests"
|
||||
${config.apps.tests-integration.program}
|
||||
|
||||
echo "checking flakes under ./examples"
|
||||
${config.apps.tests-examples.program}
|
||||
|
||||
echo "running nix flake check"
|
||||
cd $WORKDIR
|
||||
nix flake show >/dev/null
|
||||
nix flake check
|
||||
'');
|
||||
};
|
||||
};
|
||||
}
|
@ -11,7 +11,6 @@
|
||||
nix,
|
||||
pkgs,
|
||||
framework,
|
||||
dream2nixWithExternals,
|
||||
...
|
||||
}: let
|
||||
l = lib // builtins;
|
||||
|
@ -7,7 +7,6 @@
|
||||
git,
|
||||
parallel,
|
||||
nix,
|
||||
dream2nixWithExternals,
|
||||
framework,
|
||||
...
|
||||
}: let
|
||||
|
@ -9,15 +9,18 @@
|
||||
nix,
|
||||
pkgs,
|
||||
framework,
|
||||
dream2nixWithExternals,
|
||||
callPackageDream,
|
||||
...
|
||||
}: let
|
||||
l = lib // builtins;
|
||||
testDirs = l.attrNames (l.readDir ./tests);
|
||||
testScripts =
|
||||
map
|
||||
(dir: callPackageDream (./tests + "/${dir}") {inherit self;})
|
||||
(
|
||||
dir:
|
||||
pkgs.callPackage
|
||||
(./tests + "/${dir}")
|
||||
{inherit self framework;}
|
||||
)
|
||||
testDirs;
|
||||
testScriptsFile = pkgs.writeText "scripts-list" (l.concatStringsSep "\n" testScripts);
|
||||
execTest =
|
||||
|
@ -5,7 +5,6 @@
|
||||
nix,
|
||||
git,
|
||||
python3,
|
||||
dream2nixWithExternals,
|
||||
framework,
|
||||
...
|
||||
}: let
|
||||
|
@ -26,7 +26,7 @@ exampleDreamLock = dict(
|
||||
|
||||
def test_dream_lock_inject():
|
||||
result = nix_ffi.callNixFunction(
|
||||
'framework.utils.dream-lock.injectDependencies',
|
||||
'utils.dream-lock.injectDependencies',
|
||||
dreamLock=exampleDreamLock,
|
||||
inject=dict(
|
||||
example={
|
||||
@ -43,7 +43,7 @@ def test_dream_lock_inject():
|
||||
|
||||
def test_dream_lock_replace_root_sources():
|
||||
result = nix_ffi.callNixFunction(
|
||||
'framework.utils.dream-lock.replaceRootSources',
|
||||
'utils.dream-lock.replaceRootSources',
|
||||
dreamLock=exampleDreamLock,
|
||||
newSourceRoot=dict(
|
||||
type = "http",
|
||||
|
@ -5,7 +5,7 @@ import pytest
|
||||
|
||||
def get_projects_to_test():
|
||||
tests = nix_ffi.eval(
|
||||
'framework.translators',
|
||||
'translators',
|
||||
wrapper_code = '''
|
||||
{result, ...}: let
|
||||
lib = (import <nixpkgs> {}).lib;
|
||||
@ -65,7 +65,7 @@ def check_format_sourceSpec(sourceSpec):
|
||||
@pytest.mark.parametrize("p", projects)
|
||||
def test_packageName(p):
|
||||
defaultPackage = nix_ffi.eval(
|
||||
f"framework.translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
f"translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
params=dict(
|
||||
project=p['project'],
|
||||
source=p['source'],
|
||||
@ -81,7 +81,7 @@ def test_packageName(p):
|
||||
@pytest.mark.parametrize("p", projects)
|
||||
def test_exportedPackages(p):
|
||||
exportedPackages = nix_ffi.eval(
|
||||
f"framework.translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
f"translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
params=dict(
|
||||
project=p['project'],
|
||||
source=p['source'],
|
||||
@ -97,7 +97,7 @@ def test_exportedPackages(p):
|
||||
@pytest.mark.parametrize("p", projects)
|
||||
def test_extraObjects(p):
|
||||
extraObjects = nix_ffi.eval(
|
||||
f"framework.translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
f"translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
params=dict(
|
||||
project=p['project'],
|
||||
source=p['source'],
|
||||
@ -121,7 +121,7 @@ def test_extraObjects(p):
|
||||
@pytest.mark.parametrize("p", projects)
|
||||
def test_location(p):
|
||||
location = nix_ffi.eval(
|
||||
f"framework.translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
f"translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
params=dict(
|
||||
project=p['project'],
|
||||
source=p['source'],
|
||||
@ -136,7 +136,7 @@ def test_location(p):
|
||||
@pytest.mark.parametrize("p", projects)
|
||||
def test_serializedRawObjects(p):
|
||||
serializedRawObjects = nix_ffi.eval(
|
||||
f"framework.translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
f"translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
params=dict(
|
||||
project=p['project'],
|
||||
source=p['source'],
|
||||
@ -159,7 +159,7 @@ def test_serializedRawObjects(p):
|
||||
@pytest.mark.parametrize("p", projects)
|
||||
def test_subsystemName(p):
|
||||
subsystemName = nix_ffi.eval(
|
||||
f"framework.translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
f"translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
params=dict(
|
||||
project=p['project'],
|
||||
source=p['source'],
|
||||
@ -175,7 +175,7 @@ def test_subsystemName(p):
|
||||
@pytest.mark.parametrize("p", projects)
|
||||
def test_subsystemAttrs(p):
|
||||
subsystemAttrs = nix_ffi.eval(
|
||||
f"framework.translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
f"translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
params=dict(
|
||||
project=p['project'],
|
||||
source=p['source'],
|
||||
@ -191,7 +191,7 @@ def test_subsystemAttrs(p):
|
||||
@pytest.mark.parametrize("p", projects)
|
||||
def test_translatorName(p):
|
||||
translatorName = nix_ffi.eval(
|
||||
f"framework.translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
f"translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
params=dict(
|
||||
project=p['project'],
|
||||
source=p['source'],
|
||||
@ -207,18 +207,18 @@ def test_translatorName(p):
|
||||
@pytest.mark.parametrize("p", projects)
|
||||
def test_extractors(p):
|
||||
finalObjects = nix_ffi.eval(
|
||||
f"framework.translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
f"translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
params=dict(
|
||||
project=p['project'],
|
||||
source=p['source'],
|
||||
),
|
||||
wrapper_code = '''
|
||||
{result, framework, ...}:
|
||||
{result, dlib, ...}:
|
||||
let
|
||||
l = builtins;
|
||||
inputs = result.inputs;
|
||||
rawObjects = inputs.serializedRawObjects;
|
||||
s = framework.dlib.simpleTranslate2;
|
||||
s = dlib.simpleTranslate2;
|
||||
|
||||
finalObjects = s.mkFinalObjects rawObjects inputs.extractors;
|
||||
allDependencies = s.makeDependencies finalObjects;
|
||||
@ -241,18 +241,18 @@ def test_extractors(p):
|
||||
@pytest.mark.parametrize("p", projects)
|
||||
def test_keys(p):
|
||||
objectsByKey = nix_ffi.eval(
|
||||
f"framework.translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
f"translatorsBySubsystem.{p['subsystem']}.{p['translator']}.finalTranslate",
|
||||
params=dict(
|
||||
project=p['project'],
|
||||
source=p['source'],
|
||||
),
|
||||
wrapper_code = '''
|
||||
{result, framework, ...}:
|
||||
{result, dlib, ...}:
|
||||
let
|
||||
l = builtins;
|
||||
inputs = result.inputs;
|
||||
rawObjects = inputs.serializedRawObjects;
|
||||
s = framework.dlib.simpleTranslate2;
|
||||
s = dlib.simpleTranslate2;
|
||||
|
||||
finalObjects = s.mkFinalObjects rawObjects inputs.extractors;
|
||||
allDependencies = s.makeDependencies finalObjects;
|
||||
|
@ -68,7 +68,7 @@ import nix_ffi
|
||||
])
|
||||
def test_translateShortcut(shortcut, expected):
|
||||
result = nix_ffi.callNixFunction(
|
||||
'framework.functions.fetchers.translateShortcut',
|
||||
'functions.fetchers.translateShortcut',
|
||||
shortcut=shortcut,
|
||||
computeHash=False,
|
||||
)
|
||||
|
@ -5,5 +5,5 @@ import nix_ffi
|
||||
('3', [ '2', '3', '1' ]),
|
||||
])
|
||||
def test_latestVersion(expected, versions):
|
||||
result = nix_ffi.callNixFunction('framework.dlib.latestVersion', versions=versions)
|
||||
result = nix_ffi.callNixFunction('dlib.latestVersion', versions=versions)
|
||||
assert result == expected
|
||||
|
Loading…
Reference in New Issue
Block a user