Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at 23.11 190 lines 4.9 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 31with import ./functions.nix { inherit lib gemConfig; }; 32 33let 34 gemFiles = bundlerFiles args; 35 36 importedGemset = if builtins.typeOf gemFiles.gemset != "set" 37 then import gemFiles.gemset 38 else gemFiles.gemset; 39 40 filteredGemset = filterGemset { inherit ruby groups; } importedGemset; 41 42 configuredGemset = lib.flip lib.mapAttrs filteredGemset (name: attrs: 43 applyGemConfigs (attrs // { inherit ruby document; gemName = name; }) 44 ); 45 46 hasBundler = builtins.hasAttr "bundler" filteredGemset; 47 48 bundler = 49 if hasBundler then gems.bundler 50 else defs.bundler.override (attrs: { inherit ruby; }); 51 52 gems = lib.flip lib.mapAttrs configuredGemset (name: attrs: buildGem name attrs); 53 54 name' = if name != null then 55 name 56 else 57 let 58 gem = gems.${pname}; 59 suffix = gem.suffix; 60 in 61 "${pname}-${suffix}"; 62 63 pname' = if pname != null then 64 pname 65 else 66 name; 67 68 copyIfBundledByPath = { bundledByPath ? false, ...}: 69 (lib.optionalString bundledByPath ( 70 assert gemFiles.gemdir != null; "cp -a ${gemFiles.gemdir}/* $out/") #*/ 71 ); 72 73 maybeCopyAll = pkgname: lib.optionalString (pkgname != null) ( 74 let 75 mainGem = gems.${pkgname} or (throw "bundlerEnv: gem ${pkgname} not found"); 76 in 77 copyIfBundledByPath mainGem 78 ); 79 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" {} '' 84 mkdir -p $out 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 88 89 ${lib.concatMapStringsSep "\n" (path: "cp -r ${path} $out/") extraConfigPaths} 90 ''; 91 92 buildGem = name: attrs: ( 93 let 94 gemAttrs = composeGemAttrs ruby gems name attrs; 95 in 96 if gemAttrs.type == "path" then 97 pathDerivation (gemAttrs.source // gemAttrs) 98 else 99 buildRubyGem gemAttrs 100 ); 101 102 envPaths = lib.attrValues gems ++ lib.optional (!hasBundler) bundler; 103 104 105 basicEnvArgs = { 106 inherit nativeBuildInputs buildInputs ignoreCollisions; 107 108 name = name'; 109 110 paths = envPaths; 111 pathsToLink = [ "/lib" ]; 112 113 postBuild = genStubsScript (defs // args // { 114 inherit confFiles bundler groups; 115 binPaths = envPaths; 116 }) + lib.optionalString (postBuild != null) postBuild; 117 118 meta = { platforms = ruby.meta.platforms; } // meta; 119 120 passthru = rec { 121 inherit ruby bundler gems confFiles envPaths; 122 inherit (gems.${pname}) gemType; 123 124 wrappedRuby = stdenv.mkDerivation { 125 name = "wrapped-ruby-${pname'}"; 126 127 nativeBuildInputs = [ makeBinaryWrapper ]; 128 129 dontUnpack = true; 130 131 buildPhase = '' 132 mkdir -p $out/bin 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} 140 done 141 ''; 142 143 dontInstall = true; 144 145 doCheck = true; 146 checkPhase = '' 147 $out/bin/ruby --help > /dev/null 148 ''; 149 150 inherit (ruby) meta; 151 }; 152 153 env = let 154 irbrc = builtins.toFile "irbrc" '' 155 if !(ENV["OLD_IRBRC"].nil? || ENV["OLD_IRBRC"].empty?) 156 require ENV["OLD_IRBRC"] 157 end 158 require 'rubygems' 159 require 'bundler/setup' 160 ''; 161 in stdenv.mkDerivation { 162 name = "${pname'}-interactive-environment"; 163 nativeBuildInputs = [ wrappedRuby basicEnv ]; 164 shellHook = '' 165 export OLD_IRBRC=$IRBRC 166 export IRBRC=${irbrc} 167 ''; 168 buildCommand = '' 169 echo >&2 "" 170 echo >&2 "*** Ruby 'env' attributes are intended for interactive nix-shell sessions, not for building! ***" 171 echo >&2 "" 172 exit 1 173 ''; 174 }; 175 }; 176 }; 177 178 basicEnv = 179 if copyGemFiles then 180 runCommand name' basicEnvArgs '' 181 mkdir -p $out 182 for i in $paths; do 183 ${rsync}/bin/rsync -a $i/lib $out/ 184 done 185 eval "$postBuild" 186 '' 187 else 188 buildEnv basicEnvArgs; 189in 190 basicEnv