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