diff options
author | Alyssa Ross <hi@alyssa.is> | 2018-12-11 21:18:22 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2018-12-11 21:26:07 +0000 |
commit | 67b1265fb3d38ead5a57fee838405a2d997777c2 (patch) | |
tree | 0c127dd8432ca416db5c56f3460ec12e8cfaf746 | |
parent | ac19d5e34f384c66b71aecb921433acc5447bc51 (diff) |
bundlerEnv: ensure dependencies always included
Suppose I have a Gemfile like this:
source "https://rubygems.org"
gem "actioncable"
gem "websocket-driver", group: :test
The gemset.nix generated by Bundix 2.4.1 will set ActionCable's groups
to [ "default" ], and websocket-driver's to [ "test" ]. This means that
the generated bundlerEnv wouldn't include websocket-driver unless the
test group was included, even though it's required by the default group.
This is arguably a bug in Bundix (websocket-driver's groups should
probably be [ "default" "test" ] or just [ "default" ]), but there's no
reason bundlerEnv should omit dependencies even given such an input --
it won't necessarily come from Bundix, and it would be good for
bundlerEnv to do the right thing.
To fix this, filterGemset is now a recursive function, that adds
dependencies of gems in the group to the filtered gemset until it
stabilises on the gems that match the required groups, and all of their
recursive dependencies.
-rw-r--r-- | lib/attrsets.nix | 9 | ||||
-rw-r--r-- | lib/default.nix | 4 | ||||
-rw-r--r-- | lib/fixed-points.nix | 10 | ||||
-rw-r--r-- | pkgs/development/ruby-modules/bundled-common/functions.nix | 20 |
4 files changed, 39 insertions, 4 deletions
diff --git a/lib/attrsets.nix b/lib/attrsets.nix index 2a1b866dbc5e..d374d229f597 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -94,6 +94,15 @@ rec { attrValues = builtins.attrValues or (attrs: attrVals (attrNames attrs) attrs); + /* Given a set of attribute names, return the set of the corresponding + attributes from the given set. + + Example: + getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; } + => { a = 1; b = 2; } + */ + getAttrs = names: attrs: genAttrs names (name: attrs.${name}); + /* Collect each attribute named `attr' from a list of attribute sets. Sets that don't contain the named attribute are ignored. diff --git a/lib/default.nix b/lib/default.nix index d7a05fec8338..e4e3e7d325a4 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -61,10 +61,10 @@ let boolToString mergeAttrs flip mapNullable inNixShell min max importJSON warn info nixpkgsVersion version mod compare splitByAndCompare functionArgs setFunctionArgs isFunction; - inherit (fixedPoints) fix fix' extends composeExtensions + inherit (fixedPoints) fix fix' converge extends composeExtensions makeExtensible makeExtensibleWithCustomName; inherit (attrsets) attrByPath hasAttrByPath setAttrByPath - getAttrFromPath attrVals attrValues catAttrs filterAttrs + getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs filterAttrsRecursive foldAttrs collect nameValuePair mapAttrs mapAttrs' mapAttrsToList mapAttrsRecursive mapAttrsRecursiveCond genAttrs isDerivation toDerivation optionalAttrs diff --git a/lib/fixed-points.nix b/lib/fixed-points.nix index 7169c46fcbbc..2f818c88de5d 100644 --- a/lib/fixed-points.nix +++ b/lib/fixed-points.nix @@ -24,6 +24,16 @@ rec { # for a concrete example. fix' = f: let x = f x // { __unfix__ = f; }; in x; + # Return the fixpoint that `f` converges to when called recursively, starting + # with the input `x`. + # + # nix-repl> converge (x: x / 2) 16 + # 0 + converge = f: x: + if (f x) == x + then x + else converge f (f x); + # Modify the contents of an explicitly recursive attribute set in a way that # honors `self`-references. This is accomplished with a function # diff --git a/pkgs/development/ruby-modules/bundled-common/functions.nix b/pkgs/development/ruby-modules/bundled-common/functions.nix index b8e666a92f9a..81e2fa353295 100644 --- a/pkgs/development/ruby-modules/bundled-common/functions.nix +++ b/pkgs/development/ruby-modules/bundled-common/functions.nix @@ -1,5 +1,9 @@ { lib, gemConfig, ... }: -rec { + +let + inherit (lib) attrValues concatMap converge filterAttrs getAttrs; + +in rec { bundlerFiles = { gemfile ? null , lockfile ? null @@ -22,7 +26,19 @@ rec { else gemset; }; - filterGemset = {ruby, groups,...}: gemset: lib.filterAttrs (name: attrs: platformMatches ruby attrs && groupMatches groups attrs) gemset; + filterGemset = { ruby, groups, ... }: gemset: + let + platformGems = filterAttrs (_: platformMatches ruby) gemset; + directlyMatchingGems = filterAttrs (_: groupMatches groups) platformGems; + + expandDependencies = gems: + let + depNames = concatMap (gem: gem.dependencies or []) (attrValues gems); + deps = getAttrs depNames platformGems; + in + gems // deps; + in + converge expandDependencies directlyMatchingGems; platformMatches = {rubyEngine, version, ...}: attrs: ( !(attrs ? "platforms") || |