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