1
1
forked from extern/flakelight
flakelight/default.nix

376 lines
12 KiB
Nix
Raw Normal View History

2023-04-09 02:56:06 +02:00
# flakelite -- Framework for making flakes simple
# Copyright (C) 2023 Archit Gupta <archit@accelbread.com>
# SPDX-License-Identifier: MIT
localInputs:
2023-04-09 02:56:06 +02:00
let
2023-04-15 23:23:29 +02:00
inherit (builtins) intersectAttrs isPath readDir;
inherit (localInputs.nixpkgs.lib) attrNames attrVals callPackageWith
composeManyExtensions filter filterAttrs foldAttrs foldl functionArgs
genAttrs hasSuffix isFunction isList isString listToAttrs mapAttrs
mapAttrsToList mapAttrs' mergeAttrs nameValuePair optional optionalAttrs
optionalString parseDrvName pathExists pipe recursiveUpdate removePrefix
removeSuffix zipAttrsWith;
2023-04-09 02:56:06 +02:00
exports = {
2023-04-15 22:42:53 +02:00
inherit mkFlake systems importDir autoImport autoImportAttrs defaultPkgName
supportedSystem mergeModules moduleAttrs rootAttrs ensureFn fnConcat
2023-04-16 01:59:02 +02:00
fnUpdate callFn filterArgs callPkg callPkgs tryImport;
};
2023-04-15 23:23:29 +02:00
builtinModule = { src, inputs, root }: {
inputs = { inherit (localInputs) nixpkgs; };
withOverlays = params: [
(final: prev: {
flakelite = params // {
inputs' = mapAttrs
(_: mapAttrs
(_: v: v.${prev.system} or { }))
inputs;
meta = {
platforms = root.systems;
} // optionalAttrs (root ? description) {
inherit (root) description;
} // optionalAttrs (root ? license) {
license =
if isList root.license
then attrVals root.license final.lib.licenses
else final.lib.licenses.${root.license};
};
};
})
];
2023-04-09 02:56:06 +02:00
checks = { pkgs, lib, ... }:
(optionalAttrs (pathExists (src + /.editorconfig)) {
editorconfig = "${lib.getExe pkgs.editorconfig-checker}"
+ optionalString (!pathExists (src + /.ecrc))
" -disable-indent-size -disable-max-line-length";
});
devTools = pkgs: with pkgs; [ nixpkgs-fmt nodePackages.prettier ];
2023-04-09 02:56:06 +02:00
formatters = {
"*.nix" = "nixpkgs-fmt";
"*.md | *.json | *.yml" = "prettier --write";
2023-04-09 02:56:06 +02:00
};
};
2023-04-15 22:42:53 +02:00
importDir = path: genAttrs
(pipe (readDir path) [
attrNames
(filter (s: s != "default.nix"))
(filter (hasSuffix ".nix"))
(map (removeSuffix ".nix"))
2023-04-15 20:02:06 +02:00
(map (removePrefix "_"))
])
(p: import (path + (if pathExists
2023-04-15 20:02:06 +02:00
(path + "/_${p}.nix") then "/_${p}.nix" else "/${p}.nix")));
2023-04-15 22:42:53 +02:00
autoImport = dir: attr:
if pathExists (dir + "/${attr}.nix")
then import (dir + "/${attr}.nix")
else if pathExists (dir + "/${attr}/default.nix")
then import (dir + "/${attr}")
else if pathExists (dir + "/${attr}")
then importDir (dir + "/${attr}")
2023-04-15 13:41:27 +02:00
else null;
2023-04-15 22:42:53 +02:00
moduleAttrs = [
"inputs"
2023-04-15 13:41:27 +02:00
"withOverlay"
"withOverlays"
"package"
"packages"
"devTools"
"devShell"
"devShells"
"env"
"overlay"
"overlays"
"app"
2023-04-15 13:41:27 +02:00
"apps"
"checks"
2023-04-15 15:36:46 +02:00
"nixosModule"
2023-04-15 13:41:27 +02:00
"nixosModules"
"nixosConfigurations"
2023-04-15 15:36:46 +02:00
"template"
2023-04-15 13:41:27 +02:00
"templates"
"formatters"
2023-04-15 22:42:53 +02:00
];
rootAttrs = moduleAttrs ++ [
2023-04-15 13:41:27 +02:00
"systems"
"perSystem"
"outputs"
2023-04-15 22:42:53 +02:00
"nixDir"
2023-04-15 13:41:27 +02:00
];
2023-04-15 22:42:53 +02:00
autoImportAttrs = dir: attrs:
filterAttrs (_: v: v != null) (genAttrs attrs (autoImport dir));
ensureFn = v: if isFunction v then v else _: v;
2023-04-15 22:42:53 +02:00
fnConcat = f1: f2: args: (f1 args) ++ (f2 args);
fnUpdate = f1: f2: args: (f1 args) // (f2 args);
mergeModules = m1: m2: {
inputs = m1.inputs // m2.inputs;
withOverlays = m1.withOverlays ++ m2.withOverlays;
packages = m1.packages // m2.packages;
2023-04-15 22:42:53 +02:00
devTools = fnConcat m1.devTools m2.devTools;
devShells = fnUpdate m1.devShells m2.devShells;
env = fnUpdate m1.env m2.env;
overlays = zipAttrsWith (_: composeManyExtensions)
[ m1.overlays m2.overlays ];
2023-04-15 22:42:53 +02:00
apps = fnUpdate m1.apps m2.apps;
checks = fnUpdate m1.checks m2.checks;
nixosModules = m1.nixosModules // m2.nixosModules;
nixosConfigurations = m1.nixosConfigurations // m2.nixosConfigurations;
templates = m1.templates // m2.templates;
2023-04-15 22:42:53 +02:00
formatters = fnUpdate m1.formatters m2.formatters;
};
2023-04-15 22:42:53 +02:00
callFn = args: f:
let
2023-04-15 23:23:29 +02:00
f' = ensureFn f;
in
2023-04-15 23:23:29 +02:00
if functionArgs f' == { } then f' args
else f' (intersectAttrs (functionArgs f) args);
2023-04-16 01:59:02 +02:00
filterArgs = x: args: callFn args x;
2023-04-15 23:23:29 +02:00
tryImport = x: if (isPath x) || (isString x) then import x else x;
callPkg = args: f:
let
f' = ensureFn (tryImport f);
in
if functionArgs f' == { } then f' args
else (args.callPackage or (callPackageWith args)) f' { };
callPkgs = pkgs: mapAttrs (_: callPkg pkgs);
2023-04-15 22:42:53 +02:00
defaultPkgName = root: pkg: root.name or pkg.pname or (parseDrvName pkg).name;
supportedSystem = { lib, stdenv, ... }: pkg:
if pkg ? meta.platforms
then lib.meta.availableOn stdenv.hostPlatform pkg
else true;
2023-04-15 22:42:53 +02:00
systems = rec {
linuxDefault = [
"x86_64-linux"
"aarch64-linux"
];
linuxAll = linuxDefault ++ [
"armv6l-linux"
"armv7l-linux"
"i686-linux"
];
};
mkFlake = src: root:
2023-04-09 02:56:06 +02:00
let
modules = root.modules or (pipe (removeAttrs root'.inputs [ "self" ]) [
2023-04-09 02:56:06 +02:00
(filterAttrs (_: v: v ? flakeliteModule))
(mapAttrsToList (_: v: v.flakeliteModule))
]);
2023-04-15 22:42:53 +02:00
nonSysArgs = exports // {
args = nonSysArgs;
flakelite = exports;
root = root';
inherit src;
inherit (merged) inputs;
inherit (merged.inputs.nixpkgs) lib;
2023-04-15 22:42:53 +02:00
};
2023-04-15 23:23:29 +02:00
applyNonSysArgs = callFn nonSysArgs;
2023-04-15 22:42:53 +02:00
moduleAttrDefaults = {
inputs = { };
2023-04-09 02:56:06 +02:00
withOverlays = [ ];
packages = { };
devTools = _: [ ];
devShells = _: { };
2023-04-09 02:56:06 +02:00
env = _: { };
overlays = { };
apps = _: { };
checks = _: { };
nixosModules = { };
nixosConfigurations = { };
templates = { };
formatters = _: { };
};
normalizeModule = module:
let
2023-04-15 22:42:53 +02:00
module' = moduleAttrDefaults // module;
2023-04-09 02:56:06 +02:00
in
module' // {
2023-04-15 22:42:53 +02:00
withOverlays = (applyNonSysArgs module'.withOverlays)
2023-04-09 02:56:06 +02:00
++ optional (module' ? withOverlay) module'.withOverlay;
2023-04-15 22:42:53 +02:00
packages = (applyNonSysArgs module'.packages)
// optionalAttrs (module' ? package) {
2023-04-09 02:56:06 +02:00
default = module'.package;
};
2023-04-16 01:59:02 +02:00
devTools = filterArgs module'.devTools;
devShells = fnUpdate (filterArgs module'.devShells)
(_: optionalAttrs (module' ? devShell) {
default = module'.devShell;
});
2023-04-16 01:59:02 +02:00
env = filterArgs module'.env;
2023-04-15 22:42:53 +02:00
overlays = (applyNonSysArgs module'.overlays)
// optionalAttrs (module' ? overlay) {
2023-04-09 02:56:06 +02:00
default = module'.overlay;
};
2023-04-16 01:59:02 +02:00
apps = fnUpdate (filterArgs module'.apps)
(_: optionalAttrs (module' ? app) {
default = module'.app;
});
2023-04-16 01:59:02 +02:00
checks = filterArgs module'.checks;
2023-04-15 22:42:53 +02:00
nixosModules = (applyNonSysArgs module'.nixosModules)
2023-04-15 15:36:46 +02:00
// optionalAttrs (module' ? nixosModule) {
default = module'.nixosModule;
};
2023-04-15 22:42:53 +02:00
nixosConfigurations = applyNonSysArgs module'.nixosConfigurations;
templates = (applyNonSysArgs module'.templates)
2023-04-15 15:36:46 +02:00
// optionalAttrs (module' ? template) {
default = module'.template;
};
2023-04-16 01:59:02 +02:00
formatters = filterArgs module'.formatters;
2023-04-09 02:56:06 +02:00
};
root' =
let
2023-04-15 14:07:03 +02:00
nixDir = root.nixDir or (src + ./nix);
2023-04-15 22:42:53 +02:00
fullRoot = (autoImportAttrs nixDir rootAttrs) // root;
in
2023-04-15 22:42:53 +02:00
normalizeModule fullRoot // {
2023-04-16 01:59:02 +02:00
systems = applyNonSysArgs (fullRoot.systems or systems.linuxDefault);
perSystem = filterArgs (fullRoot.perSystem or { });
outputs = applyNonSysArgs (fullRoot.outputs or { });
2023-04-15 14:07:03 +02:00
inherit nixDir;
raw = root;
};
2023-04-15 22:42:53 +02:00
merged = foldl mergeModules moduleAttrDefaults
2023-04-15 23:23:29 +02:00
((map (m: normalizeModule (applyNonSysArgs m))
2023-04-15 22:42:53 +02:00
([ builtinModule ] ++ modules)) ++ [ root' ]);
2023-04-09 02:56:06 +02:00
pkgsFor = system: import merged.inputs.nixpkgs {
2023-04-09 02:56:06 +02:00
inherit system;
overlays = merged.withOverlays ++ [
2023-04-15 23:23:29 +02:00
(final: _: callPkgs final merged.packages)
];
2023-04-09 02:56:06 +02:00
};
systemPkgs = listToAttrs (map
(system: nameValuePair system (pkgsFor system))
root'.systems);
2023-04-15 22:42:53 +02:00
mkCheck = pkgs: name: cmd:
if pkgs.lib.isDerivation cmd then cmd else
pkgs.runCommand "check-${name}" { } ''
cp --no-preserve=mode -r ${src} src
cd src
${cmd}
touch $out
'';
2023-04-09 02:56:06 +02:00
isApp = x: (x ? type) && (x.type == "app") && (x ? program);
mkApp = pkgs: app:
let
2023-04-15 23:23:29 +02:00
app' = callFn pkgs app;
in
if isApp app' then app'
else { type = "app"; program = "${app'}"; };
2023-04-09 02:56:06 +02:00
eachSystem = fn: foldAttrs mergeAttrs { } (map
(system: mapAttrs
(_: v: { ${system} = v; })
(fn systemPkgs.${system}))
root'.systems);
2023-04-15 22:42:53 +02:00
recUpdateSets = foldl
(acc: new: recursiveUpdate acc ((ensureFn new) acc))
2023-04-09 02:56:06 +02:00
{ };
replaceDefault = set:
if set ? default
then (removeAttrs set [ "default" ]) //
2023-04-15 22:42:53 +02:00
{ ${defaultPkgName root' set.default} = set.default; }
2023-04-09 02:56:06 +02:00
else set;
in
2023-04-15 22:42:53 +02:00
recUpdateSets [
2023-04-09 02:56:06 +02:00
(optionalAttrs (merged.packages != { }) ({
2023-04-15 23:23:29 +02:00
overlays.default = final: _: callPkgs
2023-04-09 02:56:06 +02:00
(final.appendOverlays merged.withOverlays)
(replaceDefault merged.packages);
} // eachSystem (pkgs: rec {
packages = filterAttrs (_: supportedSystem pkgs)
2023-04-15 23:23:29 +02:00
(intersectAttrs merged.packages pkgs);
2023-04-15 22:42:53 +02:00
checks = mapAttrs' (n: nameValuePair ("packages-" + n)) packages;
2023-04-09 02:56:06 +02:00
})))
(prev: optionalAttrs (merged.overlays != { }) ({
overlays = zipAttrsWith (_: composeManyExtensions)
[ (prev.overlays or { }) merged.overlays ];
}))
(eachSystem ({ pkgs, lib, ... }:
optionalAttrs (merged.formatters pkgs != { }) rec {
formatter = pkgs.writeShellScriptBin "formatter" ''
PATH=${lib.makeBinPath (merged.devTools pkgs)}
for f in "$@"; do
if [ -d "$f" ]; then
${pkgs.fd}/bin/fd "$f" -Htf -x "$0"
else
case "$(${pkgs.coreutils}/bin/basename "$f")" in
2023-04-15 22:42:53 +02:00
${toString (mapAttrsToList (n: v: "${n}) ${v} \"$f\";;")
2023-04-09 02:56:06 +02:00
(merged.formatters pkgs))}
esac
fi
done &>/dev/null
'';
checks.formatting = mkCheck pkgs "formatting" ''
${lib.getExe formatter} .
${pkgs.diffutils}/bin/diff -qr ${src} . |\
sed 's/Files .* and \(.*\) differ/File \1 not formatted/g'
'';
}))
2023-04-15 22:42:53 +02:00
(eachSystem (pkgs:
2023-04-09 02:56:06 +02:00
let
2023-04-15 22:42:53 +02:00
checks = mapAttrs (mkCheck pkgs) (merged.checks pkgs);
2023-04-09 02:56:06 +02:00
in
optionalAttrs (checks != { }) { inherit checks; }))
(eachSystem (pkgs:
2023-04-09 02:56:06 +02:00
let
apps = mapAttrs (_: mkApp pkgs) (merged.apps pkgs);
2023-04-09 02:56:06 +02:00
in
optionalAttrs (apps != { }) { inherit apps; }))
(optionalAttrs (merged.nixosModules != { }) {
inherit (merged) nixosModules;
})
(optionalAttrs (merged.nixosConfigurations != { }) {
inherit (merged) nixosConfigurations;
2023-04-15 22:42:53 +02:00
checks = recUpdateSets (mapAttrsToList
(n: v: {
${v.config.nixpkgs.system}."nixos-${n}" =
v.config.system.build.toplevel;
})
merged.nixosConfigurations);
2023-04-09 02:56:06 +02:00
})
(optionalAttrs (merged.templates != { }) {
inherit (merged) templates;
})
(prev: eachSystem ({ pkgs, system, mkShell, ... }: {
devShells.default = mkShell (merged.env pkgs // {
inputsFrom = optional (prev ? packages.${system}.default)
prev.packages.${system}.default;
packages = merged.devTools pkgs;
});
2023-04-15 23:23:29 +02:00
} // (callPkgs pkgs (merged.devShells pkgs))))
2023-04-09 02:56:06 +02:00
(eachSystem root'.perSystem)
root'.outputs
];
in
exports