Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
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 version = gem.version; 60 in 61 "${pname}-${version}"; 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: if pkgname == null then "" else 74 let 75 mainGem = gems.${pkgname} or (throw "bundlerEnv: gem ${pkgname} not found"); 76 in 77 copyIfBundledByPath mainGem; 78 79 # We have to normalize the Gemfile.lock, otherwise bundler tries to be 80 # helpful by doing so at run time, causing executables to immediately bail 81 # out. Yes, I'm serious. 82 confFiles = runCommand "gemfile-and-lockfile" {} '' 83 mkdir -p $out 84 ${maybeCopyAll mainGemName} 85 cp ${gemFiles.gemfile} $out/Gemfile || ls -l $out/Gemfile 86 cp ${gemFiles.lockfile} $out/Gemfile.lock || ls -l $out/Gemfile.lock 87 88 ${lib.concatMapStringsSep "\n" (path: "cp -r ${path} $out/") extraConfigPaths} 89 ''; 90 91 buildGem = name: attrs: ( 92 let 93 gemAttrs = composeGemAttrs ruby gems name attrs; 94 in 95 if gemAttrs.type == "path" then 96 pathDerivation (gemAttrs.source // gemAttrs) 97 else 98 buildRubyGem gemAttrs 99 ); 100 101 envPaths = lib.attrValues gems ++ lib.optional (!hasBundler) bundler; 102 103 104 basicEnvArgs = { 105 inherit nativeBuildInputs buildInputs ignoreCollisions; 106 107 name = name'; 108 109 paths = envPaths; 110 pathsToLink = [ "/lib" ]; 111 112 postBuild = genStubsScript (defs // args // { 113 inherit confFiles bundler groups; 114 binPaths = envPaths; 115 }) + lib.optionalString (postBuild != null) postBuild; 116 117 meta = { platforms = ruby.meta.platforms; } // meta; 118 119 passthru = rec { 120 inherit ruby bundler gems confFiles envPaths; 121 122 wrappedRuby = stdenv.mkDerivation { 123 name = "wrapped-ruby-${pname'}"; 124 125 nativeBuildInputs = [ makeBinaryWrapper ]; 126 127 dontUnpack = true; 128 129 buildPhase = '' 130 mkdir -p $out/bin 131 for i in ${ruby}/bin/*; do 132 makeWrapper "$i" $out/bin/$(basename "$i") \ 133 --set BUNDLE_GEMFILE ${confFiles}/Gemfile \ 134 --unset BUNDLE_PATH \ 135 --set BUNDLE_FROZEN 1 \ 136 --set GEM_HOME ${basicEnv}/${ruby.gemPath} \ 137 --set GEM_PATH ${basicEnv}/${ruby.gemPath} 138 done 139 ''; 140 141 dontInstall = true; 142 143 doCheck = true; 144 checkPhase = '' 145 $out/bin/ruby --help > /dev/null 146 ''; 147 148 inherit (ruby) meta; 149 }; 150 151 env = let 152 irbrc = builtins.toFile "irbrc" '' 153 if !(ENV["OLD_IRBRC"].nil? || ENV["OLD_IRBRC"].empty?) 154 require ENV["OLD_IRBRC"] 155 end 156 require 'rubygems' 157 require 'bundler/setup' 158 ''; 159 in stdenv.mkDerivation { 160 name = "${pname'}-interactive-environment"; 161 nativeBuildInputs = [ wrappedRuby basicEnv ]; 162 shellHook = '' 163 export OLD_IRBRC=$IRBRC 164 export IRBRC=${irbrc} 165 ''; 166 buildCommand = '' 167 echo >&2 "" 168 echo >&2 "*** Ruby 'env' attributes are intended for interactive nix-shell sessions, not for building! ***" 169 echo >&2 "" 170 exit 1 171 ''; 172 }; 173 }; 174 }; 175 176 basicEnv = 177 if copyGemFiles then 178 runCommand name' basicEnvArgs '' 179 mkdir -p $out 180 for i in $paths; do 181 ${rsync}/bin/rsync -a $i/lib $out/ 182 done 183 eval "$postBuild" 184 '' 185 else 186 buildEnv basicEnvArgs; 187in 188 basicEnv