Monorepo for Tangled tangled.org
6

Configure Feed

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

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