nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{ stdenv, runCommand, ruby, lib, rsync
2, defaultGemConfig, buildRubyGem, buildEnv
3, makeBinaryWrapper
4, bundler
5}@defs:
6
7{
8 name ? null
9, pname ? null
10, mainGemName ? null
11, gemdir ? null
12, gemfile ? null
13, lockfile ? null
14, gemset ? null
15, ruby ? defs.ruby
16, copyGemFiles ? false # Copy gem files instead of symlinking
17, gemConfig ? defaultGemConfig
18, postBuild ? null
19, document ? []
20, meta ? {}
21, groups ? null
22, ignoreCollisions ? false
23, buildInputs ? []
24, ...
25}@args:
26
27assert name == null -> pname != null;
28
29with import ./functions.nix { inherit lib gemConfig; };
30
31let
32 gemFiles = bundlerFiles args;
33
34 importedGemset = if builtins.typeOf gemFiles.gemset != "set"
35 then import gemFiles.gemset
36 else gemFiles.gemset;
37
38 filteredGemset = filterGemset { inherit ruby groups; } importedGemset;
39
40 configuredGemset = lib.flip lib.mapAttrs filteredGemset (name: attrs:
41 applyGemConfigs (attrs // { inherit ruby document; gemName = name; })
42 );
43
44 hasBundler = builtins.hasAttr "bundler" filteredGemset;
45
46 bundler =
47 if hasBundler then gems.bundler
48 else defs.bundler.override (attrs: { inherit ruby; });
49
50 gems = lib.flip lib.mapAttrs configuredGemset (name: attrs: buildGem name attrs);
51
52 name' = if name != null then
53 name
54 else
55 let
56 gem = gems.${pname};
57 version = gem.version;
58 in
59 "${pname}-${version}";
60
61 pname' = if pname != null then
62 pname
63 else
64 name;
65
66 copyIfBundledByPath = { bundledByPath ? false, ...}:
67 (if bundledByPath then
68 assert gemFiles.gemdir != null; "cp -a ${gemFiles.gemdir}/* $out/" #*/
69 else ""
70 );
71
72 maybeCopyAll = pkgname: if pkgname == null then "" else
73 let
74 mainGem = gems.${pkgname} or (throw "bundlerEnv: gem ${pkgname} not found");
75 in
76 copyIfBundledByPath mainGem;
77
78 # We have to normalize the Gemfile.lock, otherwise bundler tries to be
79 # helpful by doing so at run time, causing executables to immediately bail
80 # out. Yes, I'm serious.
81 confFiles = runCommand "gemfile-and-lockfile" {} ''
82 mkdir -p $out
83 ${maybeCopyAll mainGemName}
84 cp ${gemFiles.gemfile} $out/Gemfile || ls -l $out/Gemfile
85 cp ${gemFiles.lockfile} $out/Gemfile.lock || ls -l $out/Gemfile.lock
86 '';
87
88 buildGem = name: attrs: (
89 let
90 gemAttrs = composeGemAttrs ruby gems name attrs;
91 in
92 if gemAttrs.type == "path" then
93 pathDerivation (gemAttrs.source // gemAttrs)
94 else
95 buildRubyGem gemAttrs
96 );
97
98 envPaths = lib.attrValues gems ++ lib.optional (!hasBundler) bundler;
99
100
101 basicEnvArgs = {
102 inherit buildInputs ignoreCollisions;
103
104 name = name';
105
106 paths = envPaths;
107 pathsToLink = [ "/lib" ];
108
109 postBuild = genStubsScript (defs // args // {
110 inherit confFiles bundler groups;
111 binPaths = envPaths;
112 }) + lib.optionalString (postBuild != null) postBuild;
113
114 meta = { platforms = ruby.meta.platforms; } // meta;
115
116 passthru = rec {
117 inherit ruby bundler gems confFiles envPaths;
118
119 wrappedRuby = stdenv.mkDerivation {
120 name = "wrapped-ruby-${pname'}";
121
122 nativeBuildInputs = [ makeBinaryWrapper ];
123
124 dontUnpack = true;
125
126 buildPhase = ''
127 mkdir -p $out/bin
128 for i in ${ruby}/bin/*; do
129 makeWrapper "$i" $out/bin/$(basename "$i") \
130 --set BUNDLE_GEMFILE ${confFiles}/Gemfile \
131 --unset BUNDLE_PATH \
132 --set BUNDLE_FROZEN 1 \
133 --set GEM_HOME ${basicEnv}/${ruby.gemPath} \
134 --set GEM_PATH ${basicEnv}/${ruby.gemPath}
135 done
136 '';
137
138 dontInstall = true;
139
140 doCheck = true;
141 checkPhase = ''
142 $out/bin/ruby --help > /dev/null
143 '';
144
145 inherit (ruby) meta;
146 };
147
148 env = let
149 irbrc = builtins.toFile "irbrc" ''
150 if !(ENV["OLD_IRBRC"].nil? || ENV["OLD_IRBRC"].empty?)
151 require ENV["OLD_IRBRC"]
152 end
153 require 'rubygems'
154 require 'bundler/setup'
155 '';
156 in stdenv.mkDerivation {
157 name = "${pname'}-interactive-environment";
158 nativeBuildInputs = [ wrappedRuby basicEnv ];
159 shellHook = ''
160 export OLD_IRBRC=$IRBRC
161 export IRBRC=${irbrc}
162 '';
163 buildCommand = ''
164 echo >&2 ""
165 echo >&2 "*** Ruby 'env' attributes are intended for interactive nix-shell sessions, not for building! ***"
166 echo >&2 ""
167 exit 1
168 '';
169 };
170 };
171 };
172
173 basicEnv =
174 if copyGemFiles then
175 runCommand name' basicEnvArgs ''
176 mkdir -p $out
177 for i in $paths; do
178 ${rsync}/bin/rsync -a $i/lib $out/
179 done
180 eval "$postBuild"
181 ''
182 else
183 buildEnv basicEnvArgs;
184in
185 basicEnv