{ lib , singleOut , callPackage }: with (callPackage ./modules.nix { inherit singleOut; }); rec { mkPackageSpec = packageDescr@ { src , main ? null , ghcOpts ? [] , dependencies ? [] , extra-files ? [] , extra-directories ? [] , packages ? [] }: { packageMain = main; packageBase = src; packageGhcOpts = ghcOpts; packageDependencies = mkPerModuleAttr dependencies; # TODO: merge extra files and extra dirs together packageExtraFiles = mkPerModuleAttr extra-files; packageExtraDirectories = mkPerModuleAttr extra-directories; packagePackages = map mkPackageSpec packages; }; mkPerModuleAttr = attr: if builtins.isList attr then (_: attr) else if builtins.isAttrs attr then (x: attr.${x}) else if builtins.isFunction attr then attr else abort "Unknown type for per module attributes: ${builtins.typeOf attr}"; flattenPackages = topPkgSpec: [topPkgSpec] ++ lib.lists.concatMap (flattenPackages) topPkgSpec.packagePackages; # Traverses all transitive packages and returns the first package spec that # contains a module with given name. If none is found, returns the supplied # default value. pkgSpecByModuleName = topPkgSpec: def: modName: ( lib.findFirst (pkgSpec: lib.lists.elem modName (listModulesInDir pkgSpec.packageBase) ) def (flattenPackages topPkgSpec) ); }