This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / nix / microvm / user-config.nix
4.8 kB 135 lines
1{ 2 pkgs, 3 lib, 4 options, 5 config, 6 ... 7} @ args: let 8 configPath = /run/spindle/user-config/config.json; 9 userConfig = 10 args.userConfig 11 or ( 12 if builtins.pathExists configPath 13 then lib.importJSON configPath 14 else {} 15 ); 16 17 registry = userConfig.registry or {}; 18 19 # registry targets may be structured attrs or flake ref strings; strings are 20 # parsed by nix itself in getFlake. flakeRefToString rejects unforced attr 21 # values, hence the toJSON round-trip 22 toRefString = target: 23 if builtins.isAttrs target 24 then builtins.flakeRefToString (builtins.fromJSON (builtins.toJSON target)) 25 else target; 26 27 # user registry entries shadow the system registry (which pins nixpkgs) 28 getFlake = ref: builtins.getFlake (toRefString (registry.${ref} or ref)); 29 30 # "flakeref#attr" or a bare attr looked up in nixpkgs. nixpkgs refs use the 31 # already-evaluated pkgs directly instead of re-evaluating via getFlake, 32 # unless the user remapped nixpkgs in their registry 33 resolvePackage = ref: let 34 parts = lib.splitString "#" ref; 35 hasAttr = lib.length parts > 1; 36 flakeRef = 37 if hasAttr 38 then lib.head parts 39 else "nixpkgs"; 40 pkgName = 41 if hasAttr 42 then lib.elemAt parts 1 43 else ref; 44 system = pkgs.stdenv.hostPlatform.system; 45 flake = getFlake flakeRef; 46 notFound = throw "Package ${pkgName} not found in ${flakeRef}"; 47 # pkgName may be dotted (e.g. "python3Packages.requests"), so walk the 48 # attr path rather than doing a single dotted-string lookup 49 pkgPath = lib.splitString "." pkgName; 50 inPackages = ["packages" system] ++ pkgPath; 51 inLegacy = ["legacyPackages" system] ++ pkgPath; 52 in 53 if flakeRef == "nixpkgs" && !(registry ? nixpkgs) 54 then lib.attrByPath pkgPath notFound pkgs 55 else if lib.hasAttrByPath inLegacy flake 56 then lib.getAttrFromPath inLegacy flake 57 else if lib.hasAttrByPath inPackages flake 58 then lib.getAttrFromPath inPackages flake 59 else notFound; 60 61 # strings are resolved as package references only where the option type 62 # actually expects packages; everything else passes through untouched 63 resolveForType = type: v: 64 if type.name == "package" && builtins.isString v 65 then resolvePackage v 66 # path-typed options (e.g. services.udev.packages) accept derivations via 67 # coercion; "#" disambiguates flake refs from actual paths, which are 68 # always absolute 69 else if type.name == "path" && builtins.isString v && lib.hasInfix "#" v && !lib.hasPrefix "/" v 70 then resolvePackage v 71 else if type.name == "nullOr" && v != null 72 then resolveForType type.nestedTypes.elemType v 73 else if type.name == "listOf" && builtins.isList v 74 then map (resolveForType type.nestedTypes.elemType) v 75 else if (type.name == "attrsOf" || type.name == "lazyAttrsOf") && builtins.isAttrs v 76 then builtins.mapAttrs (_: resolveForType type.nestedTypes.elemType) v 77 else if type.name == "submodule" && builtins.isAttrs v 78 then resolveOptions (type.getSubOptions []) v 79 else v; 80 81 resolveOptions = opts: builtins.mapAttrs (name: resolveValue (opts.${name} or null)); 82 83 resolveValue = opt: v: 84 if !builtins.isAttrs opt 85 then v 86 else if lib.isOption opt 87 then resolveForType opt.type v 88 else if builtins.isAttrs v 89 then resolveOptions opt v 90 else v; 91 92 # `foo = true` is shorthand for `foo.enable = true`, but only when an 93 # enable option actually exists under foo 94 hasEnableOption = opt: 95 builtins.isAttrs opt 96 && ( 97 if lib.isOption opt 98 then (opt.type.getSubOptions opt.loc) ? enable 99 else opt ? enable && lib.isOption opt.enable 100 ); 101 102 normalize = opts: name: v: let 103 opt = opts.${name} or null; 104 in 105 if builtins.isBool v && hasEnableOption opt 106 then {enable = v;} 107 else resolveValue opt v; 108 109 # dependencies go into a devshell so we can make use of stdenv setup hooks 110 # (e.g. for pkg-config and such) 111 dependencies = userConfig.dependencies or []; 112 spindleDevShell = pkgs.mkShellNoCC { 113 name = "spindle-deps"; 114 packages = map resolvePackage dependencies; 115 }; 116 spindleDevEnv = spindleDevShell.overrideAttrs (_: { 117 name = "spindle-deps-env"; 118 # materialize the devshell like how nix print-dev-env does internally 119 args = ["${config.nix.package.src}/src/nix/get-env.sh"]; 120 }); 121in { 122 nix.registry = builtins.mapAttrs (name: _: 123 lib.mkForce { 124 to = { 125 type = "path"; 126 path = (getFlake name).outPath; 127 }; 128 }) 129 registry; 130 environment.etc = lib.mkIf (dependencies != []) { 131 "spindle/devshell-drv".text = "${spindleDevEnv}"; 132 }; 133 services = builtins.mapAttrs (normalize (options.services or {})) (userConfig.services or {}); 134 virtualisation = builtins.mapAttrs (normalize (options.virtualisation or {})) (userConfig.virtualisation or {}); 135}