1 { stdenv, runCommand, ruby, lib, rsync
2 , defaultGemConfig, buildRubyGem, buildEnv
16 , copyGemFiles ? false # Copy gem files instead of symlinking
17 , gemConfig ? defaultGemConfig
22 , ignoreCollisions ? false
23 , nativeBuildInputs ? []
25 , extraConfigPaths ? []
29 assert name == null -> pname != null;
31 with import ./functions.nix { inherit lib gemConfig; };
34 gemFiles = bundlerFiles args;
36 importedGemset = if builtins.typeOf gemFiles.gemset != "set"
37 then import gemFiles.gemset
40 filteredGemset = filterGemset { inherit ruby groups; } importedGemset;
42 configuredGemset = lib.flip lib.mapAttrs filteredGemset (name: attrs:
43 applyGemConfigs (attrs // { inherit ruby document; gemName = name; })
46 hasBundler = builtins.hasAttr "bundler" filteredGemset;
49 if hasBundler then gems.bundler
50 else defs.bundler.override (attrs: { inherit ruby; });
52 gems = lib.flip lib.mapAttrs configuredGemset (name: attrs: buildGem name attrs);
54 name' = if name != null then
63 pname' = if pname != null then
68 copyIfBundledByPath = { bundledByPath ? false, ...}:
69 (lib.optionalString bundledByPath (
70 assert gemFiles.gemdir != null; "cp -a ${gemFiles.gemdir}/* $out/") #*/
73 maybeCopyAll = pkgname: lib.optionalString (pkgname != null) (
75 mainGem = gems.${pkgname} or (throw "bundlerEnv: gem ${pkgname} not found");
77 copyIfBundledByPath mainGem
80 # We have to normalize the Gemfile.lock, otherwise bundler tries to be
81 # helpful by doing so at run time, causing executables to immediately bail
82 # out. Yes, I'm serious.
83 confFiles = runCommand "gemfile-and-lockfile" {} ''
85 ${maybeCopyAll mainGemName}
86 cp ${gemFiles.gemfile} $out/Gemfile || ls -l $out/Gemfile
87 cp ${gemFiles.lockfile} $out/Gemfile.lock || ls -l $out/Gemfile.lock
89 ${lib.concatMapStringsSep "\n" (path: "cp -r ${path} $out/") extraConfigPaths}
92 buildGem = name: attrs: (
94 gemAttrs = composeGemAttrs ruby gems name attrs;
96 if gemAttrs.type == "path" then
97 pathDerivation (gemAttrs.source // gemAttrs)
102 envPaths = lib.attrValues gems ++ lib.optional (!hasBundler) bundler;
106 inherit nativeBuildInputs buildInputs ignoreCollisions;
111 pathsToLink = [ "/lib" ];
113 postBuild = genStubsScript (defs // args // {
114 inherit confFiles bundler groups;
116 }) + lib.optionalString (postBuild != null) postBuild;
118 meta = { platforms = ruby.meta.platforms; } // meta;
121 inherit ruby bundler gems confFiles envPaths;
122 inherit (gems.${pname}) gemType;
124 wrappedRuby = stdenv.mkDerivation {
125 name = "wrapped-ruby-${pname'}";
127 nativeBuildInputs = [ makeBinaryWrapper ];
133 for i in ${ruby}/bin/*; do
134 makeWrapper "$i" $out/bin/$(basename "$i") \
135 --set BUNDLE_GEMFILE ${confFiles}/Gemfile \
136 --unset BUNDLE_PATH \
137 --set BUNDLE_FROZEN 1 \
138 --set GEM_HOME ${basicEnv}/${ruby.gemPath} \
139 --set GEM_PATH ${basicEnv}/${ruby.gemPath}
147 $out/bin/ruby --help > /dev/null
154 irbrc = builtins.toFile "irbrc" ''
155 if !(ENV["OLD_IRBRC"].nil? || ENV["OLD_IRBRC"].empty?)
156 require ENV["OLD_IRBRC"]
159 require 'bundler/setup'
161 in stdenv.mkDerivation {
162 name = "${pname'}-interactive-environment";
163 nativeBuildInputs = [ wrappedRuby basicEnv ];
165 export OLD_IRBRC=$IRBRC
166 export IRBRC=${irbrc}
170 echo >&2 "*** Ruby 'env' attributes are intended for interactive nix-shell sessions, not for building! ***"
180 runCommand name' basicEnvArgs ''
183 ${rsync}/bin/rsync -a $i/lib $out/
188 buildEnv basicEnvArgs;