diff --git a/lib/default.nix b/lib/default.nix index 2d7a0aebb0..e3e3de576f 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -160,15 +160,24 @@ in { let packageToComponents = _name: package: # look for the components with this group if there are any let components = package.components.${group} or {}; - # set recurseForDerivations unless it's a derivation itself (e.g. the "library" component) or an empty set - in if lib.isDerivation components || components == {} - then components - else recurseIntoAttrs components; + in { + inherit (package.identifier) name; + # set recurseForDerivations unless it's a derivation itself (e.g. the "library" component) or an empty set + components = + if lib.isDerivation components || components == {} + then components + else recurseIntoAttrs components; + }; packageFilter = _name: package: (package.isHaskell or false) && packageSel package; filteredPkgs = lib.filterAttrs packageFilter haskellPackages; # at this point we can filter out packages that don't have any of the given kind of component - packagesByComponent = lib.filterAttrs (_: components: components != {}) (lib.mapAttrs packageToComponents filteredPkgs); - in recurseIntoAttrs packagesByComponent; + packagesByComponent = lib.mapAttrsToList packageToComponents filteredPkgs; + packagesGroupedByName = builtins.groupBy (x: x.name) packagesByComponent; + combined = + lib.filterAttrs (_: components: components != {}) ( + builtins.mapAttrs (_name: packages: + builtins.foldl' (a: b: a // b) {} (map (x: x.components) packages)) packagesGroupedByName); + in recurseIntoAttrs combined; # Equivalent to collectComponents with (_: true) as selection function. # Useful for pre-filtered package-set. @@ -184,7 +193,7 @@ in { # This can be used to collect all the test runs in your project, so that can be run in CI. collectChecks = packageSel: haskellPackages: let packageFilter = _name: package: (package.isHaskell or false) && packageSel package; - in recurseIntoAttrs (lib.mapAttrs (_: p: p.checks) (lib.filterAttrs packageFilter haskellPackages)); + in recurseIntoAttrs (lib.filterAttrs (_: x: x != {} && x != recurseIntoAttrs {}) (lib.mapAttrs (_: p: p.checks) (lib.filterAttrs packageFilter haskellPackages))); # Equivalent to collectChecks with (_: true) as selection function. # Useful for pre-filtered package-set. diff --git a/modules/install-plan/redirect.nix b/modules/install-plan/redirect.nix index b634904239..d2c7328b4f 100644 --- a/modules/install-plan/redirect.nix +++ b/modules/install-plan/redirect.nix @@ -1,7 +1,7 @@ # Add `hsPkgs.${pkg-name}` based on the available targets in the plan. {pkgs, lib, config, ...}: let - redirect = redirectName: packageTargets: + redirect = existing: redirectName: packageTargets: let componentsByName = builtins.listToAttrs (map (x: { name = x.component-name; value = x.available; }) packageTargets); lookupComponent = collectionName: name: available: @@ -14,8 +14,8 @@ let else if builtins.isString (builtins.head available) then throw "${builtins.head available} looking for ${attrPath}" else if collectionName == "" - then config.hsPkgs.${(builtins.head available).id}.components.library - else config.hsPkgs.${(builtins.head available).id}.components.${collectionName}.${name}; + then existing.${(builtins.head available).id}.components.library + else existing.${(builtins.head available).id}.components.${collectionName}.${name}; componentsWithPrefix = collectionName: prefix: lib.listToAttrs (lib.concatLists (lib.mapAttrsToList (n: available: lib.optional (lib.hasPrefix "${prefix}:" n && (builtins.length available != 1 || !builtins.elem (builtins.head available) ["TargetNotBuildable" "TargetNotLocal"])) ( @@ -24,44 +24,49 @@ let value = lookupComponent collectionName name available; in { inherit name value; } )) componentsByName)); - defaultTargetPackage = config.hsPkgs.${(builtins.head ( + defaultTargetId = (builtins.head ( # Use the package identified by the library component componentsByName.lib or # Or by the first component componentsByName.${builtins.head (builtins.attrNames componentsByName)} - )).id}; - in rec { - isRedirect = true; + )).id; + defaultTargetPackage = existing.${defaultTargetId}; + in defaultTargetPackage // rec { + isRedirect = redirectName != defaultTargetId; identifier = rec { name = (builtins.head packageTargets).pkg-name; version = (builtins.head packageTargets).pkg-version; id = "${name}-${version}"; }; components = lib.mapAttrs componentsWithPrefix pkgs.haskell-nix.haskellLib.componentPrefix // lib.optionalAttrs (componentsByName ? lib) { library = lookupComponent "" "" componentsByName.lib; }; - checks = pkgs.recurseIntoAttrs (builtins.mapAttrs - (_: d: pkgs.haskell-nix.haskellLib.check d) - (lib.filterAttrs (_: d: d.config.doCheck) components.tests)); - inherit (defaultTargetPackage) buildType setup; + checks = pkgs.recurseIntoAttrs ( + lib.filterAttrs (_: x: x != {}) ( + builtins.mapAttrs + (_: d: pkgs.haskell-nix.haskellLib.check d) + (lib.filterAttrs (_: d: d.config.doCheck) components.tests))); }; in { - hsPkgs = - # Redirects with just the package name - builtins.removeAttrs (builtins.mapAttrs (packageName: packageTargets: - let - byVersion = builtins.groupBy (x: x.pkg-version) packageTargets; - versions = builtins.attrNames byVersion; - in if builtins.length versions != 1 - then let - err = throw "Multiple versions for ${packageName} ${builtins.toJSON versions}"; - in { - isRedirect = true; - identifier = { name = packageName; version = err; }; - components = err; - checks = err; - } - else redirect packageName packageTargets) (builtins.groupBy (x: x.pkg-name) config.plan-json.targets)) config.preExistingPkgs + options.hsPkgs = lib.mkOption { + type = lib.types.unspecified; + apply = existing: existing // + # Redirects with just the package name + builtins.removeAttrs (builtins.mapAttrs (packageName: packageTargets: + let + byVersion = builtins.groupBy (x: x.pkg-version) packageTargets; + versions = builtins.attrNames byVersion; + in if builtins.length versions != 1 + then let + err = throw "Multiple versions for ${packageName} ${builtins.toJSON versions}"; + in { + isRedirect = true; + identifier = { name = packageName; version = err; }; + components = err; + checks = err; + } + else redirect existing packageName packageTargets) (builtins.groupBy (x: x.pkg-name) config.plan-json.targets)) config.preExistingPkgs - # Redirect for `${name}-${version}` - // builtins.mapAttrs (packageNameAndVersion: packageTargets: redirect packageNameAndVersion packageTargets) - (builtins.groupBy (x: "${x.pkg-name}-${x.pkg-version}") config.plan-json.targets); + # Redirect for `${name}-${version}` + // builtins.mapAttrs (packageNameAndVersion: packageTargets: redirect existing packageNameAndVersion packageTargets) + (builtins.groupBy (x: "${x.pkg-name}-${x.pkg-version}") config.plan-json.targets); + }; }