diff --git a/pkgs/applications/misc/jekyll/default.nix b/pkgs/applications/misc/jekyll/default.nix index 5e9505e9f320..e11e7361ffa3 100644 --- a/pkgs/applications/misc/jekyll/default.nix +++ b/pkgs/applications/misc/jekyll/default.nix @@ -8,8 +8,6 @@ bundlerEnv { lockfile = ./Gemfile.lock; gemset = ./gemset.nix; - buildInputs = [ curl ]; - meta = with lib; { description = "Simple, blog aware, static site generator"; homepage = http://jekyllrb.com/; diff --git a/pkgs/applications/networking/cluster/panamax/api/default.nix b/pkgs/applications/networking/cluster/panamax/api/default.nix index dcfef83f1bec..6e20f7c23038 100644 --- a/pkgs/applications/networking/cluster/panamax/api/default.nix +++ b/pkgs/applications/networking/cluster/panamax/api/default.nix @@ -1,6 +1,6 @@ -{ stdenv, buildEnv, fetchgit, fetchurl, makeWrapper, bundlerEnv, bundler_HEAD +{ stdenv, buildEnv, fetchgit, fetchurl, makeWrapper, bundlerEnv, bundler , ruby, libxslt, libxml2, sqlite, openssl, docker -, dataDir ? "/var/lib/panamax-api" }: +, dataDir ? "/var/lib/panamax-api" }@args: with stdenv.lib; @@ -14,9 +14,9 @@ stdenv.mkDerivation rec { gemset = ./gemset.nix; gemfile = ./Gemfile; lockfile = ./Gemfile.lock; - buildInputs = [ openssl ]; }; - bundler = bundler_HEAD.override { inherit ruby; }; + + bundler = args.bundler.override { inherit ruby; }; database_yml = builtins.toFile "database.yml" '' production: diff --git a/pkgs/applications/networking/cluster/panamax/ui/default.nix b/pkgs/applications/networking/cluster/panamax/ui/default.nix index 3dac10613625..88e0efc18a64 100644 --- a/pkgs/applications/networking/cluster/panamax/ui/default.nix +++ b/pkgs/applications/networking/cluster/panamax/ui/default.nix @@ -1,5 +1,5 @@ -{ stdenv, fetchgit, fetchurl, makeWrapper, bundlerEnv, bundler_HEAD -, ruby, rubygemsFun, openssl, sqlite, dataDir ? "/var/lib/panamax-ui"}: +{ stdenv, fetchgit, fetchurl, makeWrapper, bundlerEnv, bundler +, ruby, openssl, sqlite, dataDir ? "/var/lib/panamax-ui"}@args: with stdenv.lib; @@ -13,10 +13,9 @@ stdenv.mkDerivation rec { gemset = ./gemset.nix; gemfile = ./Gemfile; lockfile = ./Gemfile.lock; - buildInputs = [ openssl ]; }; - bundler = bundler_HEAD.override { inherit ruby; }; + bundler = args.bundler.override { inherit ruby; }; src = fetchgit { rev = "refs/tags/v${version}"; diff --git a/pkgs/development/interpreters/ruby/build-ruby-gem/default.nix b/pkgs/development/interpreters/ruby/build-ruby-gem/default.nix new file mode 100644 index 000000000000..d050faca2454 --- /dev/null +++ b/pkgs/development/interpreters/ruby/build-ruby-gem/default.nix @@ -0,0 +1,208 @@ +# This builds gems in a way that is compatible with bundler. +# +# Bundler installs gems from git sources _very_ differently from how RubyGems +# installes gem packages, though they both install gem packages similarly. +# +# We monkey-patch Bundler to remove any impurities and then drive its internals +# to install git gems. +# +# For the sake of simplicity, gem packages are installed with the standard `gem` +# program. +# +# Note that bundler does not support multiple prefixes; it assumes that all +# gems are installed in a common prefix, and has no support for specifying +# otherwise. Therefore, if you want to be able to use the resulting derivations +# with bundler, you need to create a symlink forrest first, which is what +# `bundlerEnv` does for you. +# +# Normal gem packages can be used outside of bundler; a binstub is created in +# $out/bin. + +{ lib, ruby, rubygems, bundler, fetchurl, fetchgit, makeWrapper, git, buildRubyGem +} @ defs: + +lib.makeOverridable ( + +{ name ? null +, gemName +, version ? null +, type ? "gem" +, document ? [] # e.g. [ "ri" "rdoc" ] +, platform ? "ruby" +, ruby ? defs.ruby +, stdenv ? ruby.stdenv +, namePrefix ? "${ruby.name}" + "-" +, buildInputs ? [] +, doCheck ? false +, meta ? {} +, patches ? [] +, gemPath ? [] +, dontStrip ? true +, remotes ? ["https://rubygems.org"] +# Assume we don't have to build unless strictly necessary (e.g. the source is a +# git checkout). +# If you need to apply patches, make sure to set `dontBuild = false`; +, dontBuild ? true +, propagatedBuildInputs ? [] +, propagatedUserEnvPkgs ? [] +, buildFlags ? null +, passthru ? {} +, ...} @ attrs: + +if ! builtins.elem type [ "git" "gem" ] +then throw "buildRubyGem: don't know how to build a gem of type \"${type}\"" +else + +let + shellEscape = x: "'${lib.replaceChars ["'"] [("'\\'" + "'")] x}'"; + rubygems = (attrs.rubygems or defs.rubygems).override { + inherit ruby; + }; + src = attrs.src or ( + if type == "gem" + then fetchurl { + urls = map (remote: "${remote}/gems/${gemName}-${version}.gem") remotes; + inherit (attrs) sha256; + } else fetchgit { + inherit (attrs) url rev sha256 fetchSubmodules; + leaveDotGit = true; + } + ); + documentFlag = + if document == [] + then "-N" + else "--document ${lib.concatStringsSep "," document}"; + +in + +stdenv.mkDerivation (attrs // { + inherit ruby rubygems; + inherit doCheck; + inherit dontBuild; + inherit dontStrip; + inherit type; + + buildInputs = [ + ruby rubygems makeWrapper + ] ++ lib.optionals (type == "git") [ git bundler ] + ++ buildInputs; + + name = attrs.name or (namePrefix + gemName); + + inherit src; + + phases = attrs.phases or [ "unpackPhase" "patchPhase" "buildPhase" "installPhase" "fixupPhase" ]; + + unpackPhase = attrs.unpackPhase or '' + runHook preUnpack + + if [[ -f $src && $src == *.gem ]]; then + if [[ -z "$dontBuild" ]]; then + # we won't know the name of the directory that RubyGems creates, + # so we'll just use a glob to find it and move it over. + gempkg="$src" + sourceRoot=source + gem unpack $gempkg --target=container + cp -r container/* $sourceRoot + rm -r container + + # copy out the original gemspec, for convenience during patching / + # overrides. + gem specification $gempkg --ruby > original.gemspec + gemspec=$(readlink -f .)/original.gemspec + else + gempkg="$src" + fi + else + # Fall back to the original thing for everything else. + dontBuild="" + preUnpack="" postUnpack="" unpackPhase + fi + + runHook postUnpack + ''; + + buildPhase = attrs.buildPhase or '' + runHook preBuild + + if [[ "$type" == "gem" ]]; then + if [[ -z "$gemspec" ]]; then + gemspec="$(find . -name '*.gemspec')" + echo "found the following gemspecs:" + echo "$gemspec" + gemspec="$(echo "$gemspec" | head -n1)" + fi + + exec 3>&1 + output="$(gem build $gemspec | tee >(cat - >&3))" + exec 3>&- + + gempkg=$(echo "$output" | grep -oP 'File: \K(.*)') + + echo "gem package built: $gempkg" + fi + + runHook postBuild + ''; + + # Note: + # We really do need to keep the $out/${ruby.gemPath}/cache. + # This is very important in order for many parts of RubyGems/Bundler to not blow up. + # See https://github.com/bundler/bundler/issues/3327 + installPhase = attrs.installPhase or '' + runHook preInstall + + export GEM_HOME=$out/${ruby.gemPath} + mkdir -p $GEM_HOME + + echo "buildFlags: $buildFlags" + + ${lib.optionalString (type == "git") '' + ruby ${./nix-bundle-install.rb} \ + ${gemName} \ + ${attrs.url} \ + ${src} \ + ${attrs.rev} \ + ${version} \ + ${shellEscape (toString buildFlags)} + ''} + + ${lib.optionalString (type == "gem") '' + if [[ -z "$gempkg" ]]; then + echo "failure: \$gempkg path unspecified" 1>&2 + exit 1 + elif [[ ! -f "$gempkg" ]]; then + echo "failure: \$gempkg path invalid" 1>&2 + exit 1 + fi + + gem install \ + --local \ + --force \ + --http-proxy 'http://nodtd.invalid' \ + --ignore-dependencies \ + --build-root '/' \ + --backtrace \ + ${documentFlag} \ + $gempkg $gemFlags -- $buildFlags + + # looks like useless files which break build repeatability and consume space + rm -fv $out/${ruby.gemPath}/doc/*/*/created.rid || true + rm -fv $out/${ruby.gemPath}/gems/*/ext/*/mkmf.log || true + + # write out metadata and binstubs + spec=$(echo $out/${ruby.gemPath}/specifications/*.gemspec) + ruby ${./gem-post-build.rb} "$spec" + ''} + + runHook postInstall + ''; + + propagatedBuildInputs = gemPath ++ propagatedBuildInputs; + propagatedUserEnvPkgs = gemPath ++ propagatedUserEnvPkgs; + + passthru = passthru // { isRubyGem = true; }; + inherit meta; +}) + +) diff --git a/pkgs/development/interpreters/ruby/build-ruby-gem/gem-post-build.rb b/pkgs/development/interpreters/ruby/build-ruby-gem/gem-post-build.rb new file mode 100644 index 000000000000..112a9accc335 --- /dev/null +++ b/pkgs/development/interpreters/ruby/build-ruby-gem/gem-post-build.rb @@ -0,0 +1,77 @@ +require 'rbconfig' +require 'rubygems' +require 'rubygems/specification' +require 'fileutils' + +ruby = File.join(ENV["ruby"], "bin", RbConfig::CONFIG['ruby_install_name']) +out = ENV["out"] +bin_path = File.join(ENV["out"], "bin") +gem_home = ENV["GEM_HOME"] +gem_path = ENV["GEM_PATH"].split(":") +install_path = Dir.glob("#{gem_home}/gems/*").first +gemspec_path = ARGV[0] + +if defined?(Encoding.default_internal) + Encoding.default_internal = Encoding::UTF_8 + Encoding.default_external = Encoding::UTF_8 +end + +gemspec_content = File.read(gemspec_path) +spec = nil +if gemspec_content[0..2] == "---" # YAML header + spec = Gem::Specification.from_yaml(gemspec_content) +else + spec = Gem::Specification.load(gemspec_path) +end + +FileUtils.mkdir_p("#{out}/nix-support") + +# write meta-data +meta = "#{out}/nix-support/gem-meta" +FileUtils.mkdir_p(meta) +FileUtils.ln_s(gemspec_path, "#{meta}/spec") +File.open("#{meta}/name", "w") do |f| + f.write(spec.name) +end +File.open("#{meta}/install-path", "w") do |f| + f.write(install_path) +end +File.open("#{meta}/require-paths", "w") do |f| + f.write(spec.require_paths.join(" ")) +end +File.open("#{meta}/executables", "w") do |f| + f.write(spec.executables.join(" ")) +end + +# add this gem to the GEM_PATH for dependencies +File.open("#{out}/nix-support/setup-hook", "a") do |f| + f.puts("addToSearchPath GEM_PATH #{gem_home}") + spec.require_paths.each do |dir| + f.puts("addToSearchPath RUBYLIB #{install_path}/#{dir}") + end +end + +# create regular rubygems binstubs +FileUtils.mkdir_p(bin_path) +spec.executables.each do |exe| + File.open("#{bin_path}/#{exe}", "w") do |f| + f.write(<<-EOF) +#!#{ruby} +# +# This file was generated by Nix. +# +# The application '#{exe}' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +gem_path = ENV["GEM_PATH"] +ENV["GEM_PATH"] = "\#{gem_path}\#{":" unless gem_path.nil? || gem_path.empty?}#{(gem_path+[gem_home]).join(":")}" + +require 'rubygems' + +load Gem.bin_path(#{spec.name.inspect}, #{exe.inspect}) + EOF + end + + FileUtils.chmod("+x", "#{bin_path}/#{exe}") +end diff --git a/pkgs/development/interpreters/ruby/build-ruby-gem/nix-bundle-install.rb b/pkgs/development/interpreters/ruby/build-ruby-gem/nix-bundle-install.rb new file mode 100644 index 000000000000..647b83b52c38 --- /dev/null +++ b/pkgs/development/interpreters/ruby/build-ruby-gem/nix-bundle-install.rb @@ -0,0 +1,153 @@ +require 'rbconfig' +require 'bundler/vendored_thor' +require 'bundler' +require 'rubygems/command' +require 'fileutils' +require 'pathname' +require 'tmpdir' + +# Options: +# +# name - the gem name +# uri - git repo uri +# repo - path to local checkout +# ref - the commit hash +# version - gem version +# build-flags - build arguments + +ruby = File.join(ENV["ruby"], "bin", RbConfig::CONFIG['ruby_install_name']) +out = ENV["out"] +bin_dir = File.join(ENV["out"], "bin") + +name = ARGV[0] +uri = ARGV[1] +REPO = ARGV[2] +ref = ARGV[3] +version = ARGV[4] +build_flags = ARGV[5] + +# options to pass to bundler +options = { + "name" => name, + "uri" => uri, + "ref" => ref, + "version" => version, +} + +# Monkey-patch Bundler to use our local checkout. +# I wish we didn't have to do this, but bundler does not expose an API to do +# these kinds of things. +Bundler.module_eval do + def self.requires_sudo? + false + end + + def self.root + # we don't have a Gemfile, so it doesn't make sense to try to make paths + # relative to the (non existent) parent directory thereof, so we give a + # nonsense path here. + Pathname.new("/no-root-path") + end + + def self.bundle_path + Pathname.new(ENV["GEM_HOME"]) + end + + def self.locked_gems + nil + end +end + +Bundler::Source::Git.class_eval do + def allow_git_ops? + true + end +end + +Bundler::Source::Git::GitProxy.class_eval do + def checkout + unless path.exist? + FileUtils.mkdir_p(path.dirname) + FileUtils.cp_r(File.join(REPO, ".git"), path) + system("chmod -R +w #{path}") + end + end + + def copy_to(destination, submodules=false) + unless File.exist?(destination.join(".git")) + FileUtils.mkdir_p(destination.dirname) + FileUtils.cp_r(REPO, destination) + system("chmod -R +w #{destination}") + end + end +end + +# UI +verbose = false +no_color = false +Bundler.ui = Bundler::UI::Shell.new({"no-color" => no_color}) +Bundler.ui.level = "debug" if verbose + +# Install +source = Bundler::Source::Git.new(options) +spec = source.specs.search_all(name).first +Bundler.rubygems.with_build_args [build_flags] do + source.install(spec) +end + +msg = spec.post_install_message +if msg + Bundler.ui.confirm "Post-install message from #{name}:" + Bundler.ui.info msg +end + +# Write out the binstubs +if spec.executables.any? + FileUtils.mkdir_p(bin_dir) + spec.executables.each do |exe| + wrapper = File.join(bin_dir, exe) + File.open(wrapper, "w") do |f| + stub = generate_stub(spec.name, exe) + f.write(<<-EOF) +#!#{ruby} +# +# This file was generated by Nix. +# +# The application '#{exe}' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path(#{spec.name.inspect}, #{exe.inspect}) +EOF + end + + FileUtils.chmod("+x", wrapper) + end +end + +# Write out metadata +meta = "#{out}/nix-support/gem-meta" +FileUtils.mkdir_p(meta) +FileUtils.ln_s(spec.loaded_from.to_s, "#{meta}/spec") +File.open("#{meta}/name", "w") do |f| + f.write spec.name +end +File.open("#{meta}/install-path", "w") do |f| + f.write source.install_path.to_s +end +File.open("#{meta}/require-paths", "w") do |f| + f.write spec.require_paths.join(" ") +end +File.open("#{meta}/executables", "w") do |f| + f.write spec.executables.join(" ") +end + +# make the lib available during bundler/git installs +File.open("#{out}/nix-support/setup-hook", "a") do |f| + spec.require_paths.each do |dir| + f.puts("addToSearchPath RUBYLIB #{source.install_path}/#{dir}") + end +end diff --git a/pkgs/development/interpreters/ruby/bundix/Gemfile b/pkgs/development/interpreters/ruby/bundix/Gemfile deleted file mode 100644 index 4899cafc3738..000000000000 --- a/pkgs/development/interpreters/ruby/bundix/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "http://rubygems.org" -gem "bundix", - :git => "https://github.com/cstrahan/bundix.git", - :ref => "v1.0.3" diff --git a/pkgs/development/interpreters/ruby/bundix/Gemfile.lock b/pkgs/development/interpreters/ruby/bundix/Gemfile.lock deleted file mode 100644 index f241a3bafd4f..000000000000 --- a/pkgs/development/interpreters/ruby/bundix/Gemfile.lock +++ /dev/null @@ -1,18 +0,0 @@ -GIT - remote: https://github.com/cstrahan/bundix.git - revision: c879cf901ff8084b4c97aaacfb5ecbdb0f95cc03 - ref: v1.0.3 - specs: - bundix (1.0.2) - thor (~> 0.19.1) - -GEM - remote: http://rubygems.org/ - specs: - thor (0.19.1) - -PLATFORMS - ruby - -DEPENDENCIES - bundix! diff --git a/pkgs/development/interpreters/ruby/bundix/default.nix b/pkgs/development/interpreters/ruby/bundix/default.nix index 0196adb8f4c8..b5a49043c60b 100644 --- a/pkgs/development/interpreters/ruby/bundix/default.nix +++ b/pkgs/development/interpreters/ruby/bundix/default.nix @@ -1,9 +1,20 @@ -{ ruby, bundlerEnv }: +{ ruby, fetchgit, buildRubyGem, bundler }: -bundlerEnv { - name = "bundix"; - inherit ruby; - gemset = ./gemset.nix; - gemfile = ./Gemfile; - lockfile = ./Gemfile.lock; +let + thor = buildRubyGem { + gemName = "thor"; + version = "0.19.1"; + type = "gem"; + sha256 = "08p5gx18yrbnwc6xc0mxvsfaxzgy2y9i78xq7ds0qmdm67q39y4z"; + }; + +in buildRubyGem { + gemName = "bundix"; + version = "1.0.4"; + gemPath = [ thor bundler ]; + src = fetchgit { + url = "https://github.com/cstrahan/bundix.git"; + rev = "6dcf1f71c61584f5c9b919ee9df7b0c554862076"; + sha256 = "1w17bvc9srcgr4ry81ispcj35g9kxihbyknmqp8rnd4h5090b7b2"; + }; } diff --git a/pkgs/development/interpreters/ruby/bundix/gemset.nix b/pkgs/development/interpreters/ruby/bundix/gemset.nix deleted file mode 100644 index f8f6546671d9..000000000000 --- a/pkgs/development/interpreters/ruby/bundix/gemset.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bundix" = { - version = "1.0.2"; - source = { - type = "git"; - url = "https://github.com/cstrahan/bundix.git"; - rev = "c879cf901ff8084b4c97aaacfb5ecbdb0f95cc03"; - sha256 = "05kmdnq4qa5h8l3asv05cjpnyplnqqx6hrqybj2cjlzmdxnkkgyj"; - fetchSubmodules = false; - }; - dependencies = [ - "thor" - ]; - }; - "thor" = { - version = "0.19.1"; - source = { - type = "gem"; - sha256 = "08p5gx18yrbnwc6xc0mxvsfaxzgy2y9i78xq7ds0qmdm67q39y4z"; - }; - }; -} \ No newline at end of file diff --git a/pkgs/development/interpreters/ruby/bundler-env/default.nix b/pkgs/development/interpreters/ruby/bundler-env/default.nix index 9fa6e52c4557..c7570d815e3b 100644 --- a/pkgs/development/interpreters/ruby/bundler-env/default.nix +++ b/pkgs/development/interpreters/ruby/bundler-env/default.nix @@ -1,312 +1,75 @@ { stdenv, runCommand, writeText, writeScript, writeScriptBin, ruby, lib -, callPackage, defaultGemConfig, fetchurl, fetchgit, buildRubyGem , bundler_HEAD +, callPackage, defaultGemConfig, fetchurl, fetchgit, buildRubyGem, buildEnv +, rubygems , git +, makeWrapper +, bundler +, tree }@defs: -# This is a work-in-progress. -# The idea is that his will replace load-ruby-env.nix. - { name, gemset, gemfile, lockfile, ruby ? defs.ruby, gemConfig ? defaultGemConfig -, enableParallelBuilding ? false # TODO: this might not work, given the env-var shinanigans. -, postInstall ? null -, documentation ? false +, postBuild ? null +, document ? [] , meta ? {} +, ignoreCollisions ? false , ... }@args: let shellEscape = x: "'${lib.replaceChars ["'"] [("'\\'" + "'")] x}'"; - const = x: y: x; - bundler = bundler_HEAD.override { inherit ruby; }; - inherit (builtins) attrValues; - - gemName = attrs: "${attrs.name}-${attrs.version}.gem"; - - fetchers.path = attrs: attrs.source.path; - fetchers.gem = attrs: fetchurl { - url = "${attrs.source.source or "https://rubygems.org"}/downloads/${gemName attrs}"; - inherit (attrs.source) sha256; - }; - fetchers.git = attrs: fetchgit { - inherit (attrs.source) url rev sha256 fetchSubmodules; - leaveDotGit = true; - }; - - applySrc = attrs: - attrs // { - src = (fetchers."${attrs.source.type}" attrs); - }; - + importedGemset = import gemset; applyGemConfigs = attrs: - if gemConfig ? "${attrs.name}" - then attrs // gemConfig."${attrs.name}" attrs - else attrs; - - needsPatch = attrs: - (attrs ? patches) || (attrs ? prePatch) || (attrs ? postPatch); - - # patch a gem or source tree. - # for gems, the gem is unpacked, patched, and then repacked. - # see: https://github.com/fedora-ruby/gem-patch/blob/master/lib/rubygems/patcher.rb - applyPatches = attrs: - if !needsPatch attrs - then attrs - else attrs // { src = - stdenv.mkDerivation { - name = gemName attrs; - phases = [ "unpackPhase" "patchPhase" "installPhase" ]; - buildInputs = [ ruby ] ++ attrs.buildInputs or []; - patches = attrs.patches or [ ]; - prePatch = attrs.prePatch or "true"; - postPatch = attrs.postPatch or "true"; - unpackPhase = '' - runHook preUnpack - - if [[ -f ${attrs.src} ]]; then - isGem=1 - # we won't know the name of the directory that RubyGems creates, - # so we'll just use a glob to find it and move it over. - gem unpack ${attrs.src} --target=container - cp -r container/* contents - rm -r container - else - cp -r ${attrs.src} contents - chmod -R +w contents - fi - - cd contents - runHook postUnpack - ''; - installPhase = '' - runHook preInstall - - if [[ -n "$isGem" ]]; then - ${writeScript "repack.rb" '' - #!${ruby}/bin/ruby - require 'rubygems' - require 'rubygems/package' - require 'fileutils' - - Encoding.default_internal = Encoding::UTF_8 - Encoding.default_external = Encoding::UTF_8 - - if Gem::VERSION < '2.0' - load "${./package-1.8.rb}" - end - - out = ENV['out'] - files = Dir['**/{.[^\.]*,*}'] - - package = Gem::Package.new("${attrs.src}") - patched_package = Gem::Package.new(package.spec.file_name) - patched_package.spec = package.spec.clone - patched_package.spec.files = files - - patched_package.build(false) - - FileUtils.cp(patched_package.spec.file_name, out) - ''} - else - cp -r . $out - fi - - runHook postInstall - ''; - }; - }; - - instantiate = (attrs: - applyPatches (applyGemConfigs (applySrc attrs)) + (if gemConfig ? "${attrs.gemName}" + then attrs // gemConfig."${attrs.gemName}" attrs + else attrs); + configuredGemset = lib.flip lib.mapAttrs importedGemset (name: attrs: + applyGemConfigs (attrs // { gemName = name; }) ); + hasBundler = builtins.hasAttr "bundler" importedGemset; + bundler = if hasBundler then gems.bundler else defs.bundler.override (attrs: { inherit ruby; }); + rubygems = defs.rubygems.override (attrs: { inherit ruby; }); + gems = lib.flip lib.mapAttrs configuredGemset (name: attrs: + buildRubyGem ((removeAttrs attrs ["source"]) // attrs.source // { + inherit ruby rubygems; + gemName = name; + gemPath = map (gemName: gems."${gemName}") (attrs.dependencies or []); + })); + # We have to normalize the Gemfile.lock, otherwise bundler tries to be + # helpful by doing so at run time, causing executables to immediately bail + # out. Yes, I'm serious. + confFiles = runCommand "gemfile-and-lockfile" {} '' + mkdir -p $out + cp ${gemfile} $out/Gemfile + cp ${lockfile} $out/Gemfile.lock - instantiated = lib.flip lib.mapAttrs (import gemset) (name: attrs: - instantiate (attrs // { inherit name; }) - ); - - needsPreInstall = attrs: - (attrs ? preInstall) || (attrs ? buildInputs) || (attrs ? nativeBuildInputs); - - # TODO: support cross compilation? look at stdenv/generic/default.nix. - runPreInstallers = lib.fold (next: acc: - if !needsPreInstall next - then acc - else acc + '' - ${writeScript "${next.name}-pre-install" '' - #!${stdenv.shell} - - export nativeBuildInputs="${toString ((next.nativeBuildInputs or []) ++ (next.buildInputs or []))}" - - source ${stdenv}/setup - - header "running pre-install script for ${next.name}" - - ${next.preInstall or ""} - - ${ruby}/bin/ruby -e 'print ENV.inspect' > env/${next.name} - - stopNest - ''} - '' - ) "" (attrValues instantiated); - - # copy *.gem to ./gems - copyGems = lib.fold (next: acc: - if next.source.type == "gem" - then acc + "cp ${next.src} gems/${gemName next}\n" - else acc - ) "" (attrValues instantiated); - - runRuby = name: env: command: - runCommand name env '' - ${ruby}/bin/ruby ${writeText name command} - ''; - - # TODO: include json_pure, so the version of ruby doesn't matter. - # not all rubies have support for JSON built-in, - # so we'll convert JSON to ruby expressions. - json2rb = writeScript "json2rb" '' - #!${ruby}/bin/ruby - begin - require 'json' - rescue LoadError => ex - require 'json_pure' - end - - puts JSON.parse(STDIN.read).inspect + cd $out + chmod +w Gemfile.lock + source ${rubygems}/nix-support/setup-hook + export GEM_PATH=${bundler}/${ruby.gemPath} + ${ruby}/bin/ruby -rubygems -e \ + "require 'bundler'; Bundler.definition.lock('Gemfile.lock')" ''; + envPaths = lib.attrValues gems ++ lib.optional (!hasBundler) bundler; + bundlerEnv = buildEnv { + inherit name ignoreCollisions; + paths = envPaths; + pathsToLink = [ "/lib" ]; + postBuild = '' + source ${rubygems}/nix-support/setup-hook - # dump the instantiated gemset as a ruby expression. - serializedGemset = runCommand "gemset.rb" { json = builtins.toJSON instantiated; } '' - printf '%s' "$json" | ${json2rb} > $out - ''; - - # this is a mapping from a source type and identifier (uri/path/etc) - # to the pure store path. - # we'll use this from the patched bundler to make fetching sources pure. - sources = runRuby "sources.rb" { gemset = serializedGemset; } '' - out = ENV['out'] - gemset = eval(File.read(ENV['gemset'])) - - sources = { - "git" => { }, - "path" => { }, - "gem" => { }, - "svn" => { } - } - - gemset.each_value do |spec| - type = spec["source"]["type"] - val = spec["src"] - key = - case type - when "gem" - spec["name"] - when "git" - spec["source"]["url"] - when "path" - spec["source"]["originalPath"] - when "svn" - nil # TODO - end - - sources[type][key] = val if key - end - - File.open(out, "wb") do |f| - f.print sources.inspect - end - ''; - - # rewrite PATH sources to point into the nix store. - purifiedLockfile = runRuby "purifiedLockfile" {} '' - out = ENV['out'] - sources = eval(File.read("${sources}")) - paths = sources["path"] - - lockfile = File.read("${lockfile}") - - paths.each_pair do |impure, pure| - lockfile.gsub!(/^ remote: #{Regexp.escape(impure)}/, " remote: #{pure}") - end - - File.open(out, "wb") do |f| - f.print lockfile - end - ''; - - needsBuildFlags = attrs: attrs ? buildFlags; - - mkBuildFlags = spec: - "export BUNDLE_BUILD__${lib.toUpper spec.name}='${lib.concatStringsSep " " (map shellEscape spec.buildFlags)}'"; - - allBuildFlags = - lib.concatStringsSep "\n" - (map mkBuildFlags - (lib.filter needsBuildFlags (attrValues instantiated))); - - derivation = stdenv.mkDerivation { - inherit name; - - buildInputs = [ - ruby - bundler - git - ] ++ args.buildInputs or []; - - phases = [ "installPhase" "fixupPhase" ]; - - outputs = [ - "out" # the installed libs/bins - "bundle" # supporting files for bundler - ]; - - installPhase = '' - mkdir -p $bundle - export BUNDLE_GEMFILE=$bundle/Gemfile - cp ${gemfile} $BUNDLE_GEMFILE - cp ${purifiedLockfile} $BUNDLE_GEMFILE.lock - - export NIX_GEM_SOURCES=${sources} - export NIX_BUNDLER_GEMPATH=${bundler}/${ruby.gemPath} - - export GEM_HOME=$out/${ruby.gemPath} - export GEM_PATH=$NIX_BUNDLER_GEMPATH:$GEM_HOME - mkdir -p $GEM_HOME - - ${allBuildFlags} - - mkdir gems - cp ${bundler}/${bundler.ruby.gemPath}/cache/bundler-*.gem gems - ${copyGems} - - ${lib.optionalString (!documentation) '' - mkdir home - HOME="$(pwd -P)/home" - echo "gem: --no-rdoc --no-ri" > $HOME/.gemrc - ''} - - mkdir env - ${runPreInstallers} - - mkdir $out/bin - cp ${./monkey_patches.rb} monkey_patches.rb - export RUBYOPT="-rmonkey_patches.rb -I $(pwd -P)" - bundler install --frozen --binstubs ${lib.optionalString enableParallelBuilding "--jobs $NIX_BUILD_CORES"} - RUBYOPT="" - - runHook postInstall - ''; - - inherit postInstall; - + ${ruby}/bin/ruby ${./gen-bin-stubs.rb} \ + "${ruby}/bin/ruby" \ + "${confFiles}/Gemfile" \ + "$out/${ruby.gemPath}" \ + "${bundler}/${ruby.gemPath}" \ + ${shellEscape (toString envPaths)} + '' + lib.optionalString (postBuild != null) postBuild; passthru = { - inherit ruby; - inherit bundler; - + inherit ruby bundler meta gems; env = let irbrc = builtins.toFile "irbrc" '' - if not ENV["OLD_IRBRC"].empty? + if !(ENV["OLD_IRBRC"].nil? || ENV["OLD_IRBRC"].empty?) require ENV["OLD_IRBRC"] end require 'rubygems' @@ -314,12 +77,12 @@ let ''; in stdenv.mkDerivation { name = "interactive-${name}-environment"; - nativeBuildInputs = [ ruby derivation ]; + nativeBuildInputs = [ ruby bundlerEnv ]; shellHook = '' - export BUNDLE_GEMFILE=${derivation.bundle}/Gemfile - export GEM_HOME=${derivation}/${ruby.gemPath} - export NIX_BUNDLER_GEMPATH=${bundler}/${ruby.gemPath} - export GEM_PATH=$NIX_BUNDLER_GEMPATH:$GEM_HOME + export BUNDLE_GEMFILE=${confFiles}/Gemfile + export BUNDLE_PATH=${bundlerEnv}/${ruby.gemPath} + export GEM_HOME=${bundlerEnv}/${ruby.gemPath} + export GEM_PATH=${bundlerEnv}/${ruby.gemPath} export OLD_IRBRC="$IRBRC" export IRBRC=${irbrc} ''; @@ -331,8 +94,8 @@ let ''; }; }; - - inherit meta; }; -in derivation +in + +bundlerEnv diff --git a/pkgs/development/interpreters/ruby/bundler-env/gen-bin-stubs.rb b/pkgs/development/interpreters/ruby/bundler-env/gen-bin-stubs.rb new file mode 100644 index 000000000000..fac9c9ad9446 --- /dev/null +++ b/pkgs/development/interpreters/ruby/bundler-env/gen-bin-stubs.rb @@ -0,0 +1,46 @@ +require 'rbconfig' +require 'rubygems' +require 'rubygems/specification' +require 'fileutils' + +# args/settings +out = ENV["out"] +ruby = ARGV[0] +gemfile = ARGV[1] +bundle_path = ARGV[2] +bundler_gem_path = ARGV[3] +paths = ARGV[4].split + +# generate binstubs +FileUtils.mkdir_p("#{out}/bin") +paths.each do |path| + next unless File.directory?("#{path}/nix-support/gem-meta") + + name = File.read("#{path}/nix-support/gem-meta/name") + executables = File.read("#{path}/nix-support/gem-meta/executables").split + executables.each do |exe| + File.open("#{out}/bin/#{exe}", "w") do |f| + f.write(<<-EOF) +#!#{ruby} +# +# This file was generated by Nix. +# +# The application '#{exe}' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] = "#{gemfile}" +ENV["BUNDLE_PATH"] = "#{bundle_path}" + +gem_path = ENV["GEM_PATH"] +ENV["GEM_PATH"] = "\#{gem_path}\#{":" unless gem_path.nil? || gem_path.empty?}#{bundler_gem_path}" + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path(#{name.inspect}, #{exe.inspect}) +EOF + FileUtils.chmod("+x", "#{out}/bin/#{exe}") + end + end +end diff --git a/pkgs/development/interpreters/ruby/bundler-env/monkey_patches.rb b/pkgs/development/interpreters/ruby/bundler-env/monkey_patches.rb deleted file mode 100644 index f68a20212cee..000000000000 --- a/pkgs/development/interpreters/ruby/bundler-env/monkey_patches.rb +++ /dev/null @@ -1,246 +0,0 @@ -require 'bundler' - -# Undo the RUBYOPT trickery. -opt = ENV['RUBYOPT'].dup -opt.gsub!(/-rmonkey_patches.rb -I [^ ]*/, '') -ENV['RUBYOPT'] = opt - -Bundler.module_eval do - class << self - # mappings from original uris to store paths. - def nix_gem_sources - @nix_gem_sources ||= - begin - src = ENV['NIX_GEM_SOURCES'] - eval(Bundler.read_file(src)) - end - end - - # extract the gemspecs from the gems pulled from Rubygems. - def nix_gemspecs - @nix_gemspecs ||= Dir.glob("gems/*.gem").map do |path| - Bundler.rubygems.spec_from_gem(path) - end - end - - # swap out ENV - def nix_with_env(env, &block) - if env - old_env = ENV.to_hash - begin - ENV.replace(env) - block.call - ensure - ENV.replace(old_env) - end - else - block.call - end - end - - # map a git uri to a fetchgit store path. - def nix_git(uri) - Pathname.new(nix_gem_sources["git"][uri]) - end - end -end - -Bundler::Source::Git::GitProxy.class_eval do - def checkout - unless path.exist? - FileUtils.mkdir_p(path.dirname) - FileUtils.cp_r(Bundler.nix_git(@uri).join(".git"), path) - system("chmod -R +w #{path}") - end - end - - def copy_to(destination, submodules=false) - unless File.exist?(destination.join(".git")) - FileUtils.mkdir_p(destination.dirname) - FileUtils.cp_r(Bundler.nix_git(@uri), destination) - system("chmod -R +w #{destination}") - end - end -end - -Bundler::Fetcher.class_eval do - def use_api - true - end - - def fetch_dependency_remote_specs(gem_names) - Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(',')}" - deps_list = [] - - spec_list = gem_names.map do |name| - spec = Bundler.nix_gemspecs.detect {|spec| spec.name == name } - if spec.nil? - msg = "WARNING: Could not find gemspec for '#{name}'" - Bundler.ui.warn msg - nil - else - dependencies = spec.dependencies. - select {|dep| dep.type != :development}. - map do |dep| - deps_list << dep.name - dep - end - - [spec.name, spec.version, spec.platform, dependencies] - end - end - - spec_list.compact! - - [spec_list, deps_list.uniq] - end -end - -Bundler::Source::Rubygems.class_eval do - # We copy all gems into $PWD/gems, and this allows RubyGems to find those - # gems during installation. - def fetchers - @fetchers ||= [ - Bundler::Fetcher.new(URI.parse("file://#{File.expand_path(Dir.pwd)}")) - ] - end - - # Look-up gems that were originally from RubyGems. - def remote_specs - @remote_specs ||= - begin - lockfile = Bundler::LockfileParser.new(Bundler.read_file(Bundler.default_lockfile)) - gem_names = lockfile.specs. - select {|spec| spec.source.is_a?(Bundler::Source::Rubygems)}. - map {|spec| spec.name} - idx = Bundler::Index.new - api_fetchers.each do |f| - Bundler.ui.info "Fetching source index from #{f.uri}" - idx.use f.specs(gem_names, self) - end - idx - end - end -end - -Bundler::Installer.class_eval do - - # WHY: - # This allows us to provide a typical Nix experience, where - # `buildInputs` and/or `preInstall` may set up the $PATH and other env-vars - # as needed. By swapping out the environment per install, we can have finer - # grained control than we would have otherwise. - # - # HOW: - # This is a wrapper around the original `install_gem_from_spec`. - # We expect that a "pre-installer" might exist at `pre-installers/`, - # and if it does, we execute it. - # The pre-installer is expected to dump its environment variables as a Ruby - # hash to `env/`. - # We then swap out the environment for the duration of the install, - # and then set it back to what it was originally. - alias original_install_gem_from_spec install_gem_from_spec - def install_gem_from_spec(spec, standalone = false, worker = 0) - env_dump = "env/#{spec.name}" - if File.exist?(env_dump) - env = eval(Bundler.read_file(env_dump)) - unless env - Bundler.ui.error "The environment variables for #{spec.name} could not be loaded!" - exit 1 - end - Bundler.nix_with_env(env) do - original_install_gem_from_spec(spec, standalone, worker) - end - else - original_install_gem_from_spec(spec, standalone, worker) - end - end - - def generate_bundler_executable_stubs(spec, options = {}) - return if spec.executables.empty? - - out = ENV['out'] - - spec.executables.each do |executable| - next if executable == "bundle" || executable == "bundler" - - binstub_path = "#{out}/bin/#{executable}" - - File.open(binstub_path, 'w', 0777 & ~File.umask) do |f| - f.print <<-TEXT -#!#{RbConfig.ruby} - -old_gemfile = ENV["BUNDLE_GEMFILE"] -old_gem_home = ENV["GEM_HOME"] -old_gem_path = ENV["GEM_PATH"] - -ENV["BUNDLE_GEMFILE"] = - "#{ENV["BUNDLE_GEMFILE"]}" -ENV["GEM_HOME"] = - "#{ENV["GEM_HOME"]}" -ENV["GEM_PATH"] = - "#{ENV["NIX_BUNDLER_GEMPATH"]}:\#{ENV["GEM_HOME"]}\#{old_gem_path ? ":\#{old_gem_path}" : ""}}" - -require 'rubygems' -require 'bundler/setup' - -ENV["BUNDLE_GEMFILE"] = old_gemfile -ENV["GEM_HOME"] = old_gem_home -ENV["GEM_PATH"] = old_gem_path - -load Gem.bin_path('#{spec.name}', '#{executable}') -TEXT - end - end - end -end - -Gem::Installer.class_eval do - # Make the wrappers automagically use bundler. - # - # Stage 1. - # Set $BUNDLE_GEMFILE so bundler knows what gems to load. - # Set $GEM_HOME to the installed gems, because bundler looks there for - # non-Rubygems installed gems (e.g. git/svn/path sources). - # Set $GEM_PATH to include both bundler and installed gems. - # - # Stage 2. - # Setup bundler, locking down the gem versions. - # - # Stage 3. - # Reset $BUNDLE_GEMFILE, $GEM_HOME, $GEM_PATH. - # - # Stage 4. - # Run the actual executable. - def app_script_text(bin_file_name) - return <<-TEXT -#!#{RbConfig.ruby} -# -# This file was generated by Nix's RubyGems. -# -# The application '#{spec.name}' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -old_gemfile = ENV["BUNDLE_GEMFILE"] -old_gem_home = ENV["GEM_HOME"] -old_gem_path = ENV["GEM_PATH"] - -ENV["BUNDLE_GEMFILE"] = - "#{ENV["BUNDLE_GEMFILE"]}" -ENV["GEM_HOME"] = - "#{ENV["GEM_HOME"]}" -ENV["GEM_PATH"] = - "#{ENV["NIX_BUNDLER_GEMPATH"]}:\#{ENV["GEM_HOME"]}\#{old_gem_path ? ":\#{old_gem_path}" : ""}}" - -require 'rubygems' -require 'bundler/setup' - -ENV["BUNDLE_GEMFILE"] = old_gemfile -ENV["GEM_HOME"] = old_gem_home -ENV["GEM_PATH"] = old_gem_path - -load Gem.bin_path('#{spec.name}', '#{bin_file_name}') -TEXT - end -end diff --git a/pkgs/development/interpreters/ruby/bundler-env/package-1.8.rb b/pkgs/development/interpreters/ruby/bundler-env/package-1.8.rb deleted file mode 100644 index 079b65f97ece..000000000000 --- a/pkgs/development/interpreters/ruby/bundler-env/package-1.8.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'rubygems/installer' -require 'rubygems/builder' - -# Simulate RubyGems 2.0 behavior. - -module Gem::Package - def self.new(gem) - @gem = gem - self - end - - def self.extract_files(dir) - installer = Gem::Installer.new @gem - installer.unpack(dir) - end - - def self.build(skip_validation=false) - builder = Gem::Builder.new(spec) - builder.build - end - - def self.spec=(spec) - @spec = spec - end - - def self.spec - @spec ||= Gem::Installer.new(@gem).spec - end -end diff --git a/pkgs/development/interpreters/ruby/bundler.nix b/pkgs/development/interpreters/ruby/bundler.nix index 3789170f57fe..cdcd12990e27 100644 --- a/pkgs/development/interpreters/ruby/bundler.nix +++ b/pkgs/development/interpreters/ruby/bundler.nix @@ -1,17 +1,10 @@ { buildRubyGem, makeWrapper, ruby, coreutils }: -buildRubyGem { - name = "bundler-1.10.6"; - namePrefix = ""; +buildRubyGem rec { + inherit ruby; + name = "${gemName}-${version}"; + gemName = "bundler"; + version = "1.10.6"; sha256 = "1vlzfq0bkkj4jyq6av0y55mh5nj5n0f3mfbmmifwgkh44g8k6agv"; dontPatchShebangs = true; - postInstall = '' - find $out -type f -perm -0100 | while read f; do - substituteInPlace $f \ - --replace "/usr/bin/env" "${coreutils}/bin/env" - done - - wrapProgram $out/bin/bundler \ - --prefix PATH ":" ${ruby}/bin - ''; } diff --git a/pkgs/development/interpreters/ruby/gem.nix b/pkgs/development/interpreters/ruby/gem.nix deleted file mode 100644 index bbc38226266b..000000000000 --- a/pkgs/development/interpreters/ruby/gem.nix +++ /dev/null @@ -1,136 +0,0 @@ -{ lib, ruby, rubygemsFun, fetchurl, makeWrapper, git } @ defs: - -lib.makeOverridable ( - -{ name -, ruby ? defs.ruby -, rubygems ? (rubygemsFun ruby) -, stdenv ? ruby.stdenv -, namePrefix ? "${lib.replaceStrings ["-"] ["_"] ruby.name}" + "-" -, buildInputs ? [] -, doCheck ? false -, dontBuild ? true -, meta ? {} -, gemPath ? [] -, ...} @ attrs: - -stdenv.mkDerivation (attrs // { - inherit ruby rubygems; - inherit doCheck; - - buildInputs = [ ruby rubygems makeWrapper git ] ++ buildInputs; - - name = namePrefix + name; - - src = if attrs ? src - then attrs.src - else fetchurl { - url = "http://rubygems.org/downloads/${attrs.name}.gem"; - inherit (attrs) sha256; - }; - - phases = [ "unpackPhase" "patchPhase" "buildPhase" "checkPhase" "installPhase" "fixupPhase" ]; - - # The source is expected to either be a gem package or a directory. - # - # - Gem packages are already built, so they don't even need to be unpacked. - # They will skip the buildPhase. - # - A directory containing the sources will need to go through all of the - # usual phases. - unpackPhase= '' - gemRegex="\.gem" - if [[ $src =~ $gemRegex ]] - then - runHook preUnpack - echo "source is a gem package, won't unpack" - gempkg=$src - dontBuild=1 - runHook postUnpack - else - # Fall back to the original thing for everything else. - unpackPhase - fi - ''; - - checkPhase = "true"; - - buildPhase = '' - runHook preBuild - - # TODO: Investigate. The complete working tree is touched by fetchgit. - if [ -d .git ]; then - git reset - fi - - gemspec=$(find . -name '*.gemspec') - echo "found the following gemspecs:" - echo "$gemspec" - - gemspec=$(echo "$gemspec" | head -n1) - echo "building $gemspec" - - exec 3>&1 - output=$(gem build $gemspec | tee >(cat - >&3)) - exec 3>&- - - gempkg=$(echo "$output" | grep -oP 'File: \K(.*)') - - echo "gem package built: $gempkg" - - runHook postBuild - ''; - - installPhase = '' - runHook preInstall - - # NOTE: This does NOT build the unpacked gem, but installs $src directly. - # Gems that have not been downloaded from rubygems.org may need a - # separate buildPhase. - # --ignore-dependencies is necessary as rubygems otherwise always - # connects to the repository, thus breaking pure builds. - GEM_HOME=$out/${ruby.gemPath} \ - gem install \ - --local \ - --force \ - --http-proxy "http://nodtd.invalid" \ - --ignore-dependencies \ - --build-root "/" \ - --backtrace \ - $gempkg $gemFlags -- $buildFlags - - # Yes, we really do need the $out/${ruby.gemPath}/cache. - # This is very important in order for many parts of RubyGems/Bundler to not blow up. - # See https://github.com/bundler/bundler/issues/3327 - - mkdir -p $out/bin - for prog in $out/${ruby.gemPath}/gems/*/bin/*; do - makeWrapper $prog $out/bin/$(basename $prog) \ - --prefix GEM_PATH : "$out/${ruby.gemPath}:$GEM_PATH" \ - --prefix RUBYLIB : "${rubygems}/lib" \ - $extraWrapperFlags ''${extraWrapperFlagsArray[@]} - done - #--prefix RUBYOPT rubygems \ - - # looks like useless files which break build repeatability and consume space - rm -fv $out/${ruby.gemPath}/doc/*/*/created.rid || true - rm -fv $out/${ruby.gemPath}/gems/*/ext/*/mkmf.log || true - - mkdir -p $out/nix-support - - cat > $out/nix-support/setup-hook <= v3.16.14.8, + # otherwise the gem will fail to link to the libv8 binary. + # see: https://github.com/cowboyd/libv8/pull/161 libv8 = attrs: { buildInputs = [ which v8 python ]; - buildFlags = [ - "--with-system-v8=true" - ]; + buildFlags = [ "--with-system-v8=true" ]; }; mysql2 = attrs: { @@ -73,12 +82,20 @@ in buildInputs = lib.optional stdenv.isDarwin darwin.libobjc; }; + patron = attrs: { + buildInputs = [ curl ]; + }; + pg = attrs: { buildFlags = [ "--with-pg-config=${postgresql}/bin/pg_config" ]; }; + puma = attrs: { + buildInputs = [ openssl ]; + }; + rmagick = attrs: { buildInputs = [ imagemagick pkgconfig ]; }; @@ -95,6 +112,7 @@ in }; sup = attrs: { + dontBuild = false; # prevent sup from trying to dynamically install `xapian-ruby`. postPatch = '' cp ${./mkrf_conf_xapian.rb} ext/mkrf_conf_xapian.rb @@ -118,6 +136,7 @@ in }; tzinfo = attrs: { + dontBuild = false; postPatch = '' substituteInPlace lib/tzinfo/zoneinfo_data_source.rb \ --replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo" @@ -130,6 +149,7 @@ in xapian-ruby = attrs: { # use the system xapian + dontBuild = false; buildInputs = [ xapian pkgconfig zlib ]; postPatch = '' cp ${./xapian-Rakefile} Rakefile diff --git a/pkgs/development/interpreters/ruby/bundler-env/mkrf_conf_xapian.rb b/pkgs/development/interpreters/ruby/gemconfig/mkrf_conf_xapian.rb similarity index 100% rename from pkgs/development/interpreters/ruby/bundler-env/mkrf_conf_xapian.rb rename to pkgs/development/interpreters/ruby/gemconfig/mkrf_conf_xapian.rb diff --git a/pkgs/development/interpreters/ruby/bundler-env/xapian-Rakefile b/pkgs/development/interpreters/ruby/gemconfig/xapian-Rakefile similarity index 100% rename from pkgs/development/interpreters/ruby/bundler-env/xapian-Rakefile rename to pkgs/development/interpreters/ruby/gemconfig/xapian-Rakefile diff --git a/pkgs/development/interpreters/ruby/load-ruby-env.nix b/pkgs/development/interpreters/ruby/load-ruby-env.nix deleted file mode 100644 index c4356ed5f50f..000000000000 --- a/pkgs/development/interpreters/ruby/load-ruby-env.nix +++ /dev/null @@ -1,69 +0,0 @@ -{ ruby, lib, callPackage, gemFixes, fetchurl, fetchgit, buildRubyGem }@defs: - -# This function builds a set of gems. You first convert your Gemfile to an attrset -# called a "gemset", and then use this function to build the gemset. -# -# A gemset looks like the following: -# -# { -# libv8 = { -# version = "3.16.14.7"; -# src = { -# type = "gem"; -# sha256 = "..."; -# }; -# }; -# therubyracer = { -# version = "0.12.1"; -# dependencies = [ "libv8" ]; -# src = { -# type = "gem"; -# sha256 = "..."; -# }; -# }; -# } -# -# If you use these gems as build inputs, the GEM_PATH will be updated -# appropriately, and command like `bundle exec` should work out of the box. - -{ gemset, ruby ? defs.ruby, fixes ? gemFixes }@args: - -let - const = x: y: x; - - fetchers.path = attrs: attrs.src.path; - fetchers.gem = attrs: fetchurl { - url = "${attrs.src.source or "https://rubygems.org"}/downloads/${attrs.name}-${attrs.version}.gem"; - inherit (attrs.src) sha256; - }; - fetchers.git = attrs: fetchgit { - inherit (attrs.src) url rev sha256 fetchSubmodules; - leaveDotGit = true; - }; - - instantiate = (attrs: - let - defaultAttrs = { - name = "${attrs.name}-${attrs.version}"; - inherit ruby gemPath; - }; - gemPath = map (name: gemset''."${name}") (attrs.dependencies or []); - fixedAttrs = attrs // (fixes."${attrs.name}" or (const {})) attrs; - withSource = fixedAttrs // - (if (lib.isDerivation fixedAttrs.src || builtins.isString fixedAttrs.src) - then {} - else { src = (fetchers."${fixedAttrs.src.type}" fixedAttrs); }); - - in - buildRubyGem (withSource // defaultAttrs) - ); - - gemset' = if builtins.isAttrs gemset then gemset else import gemset; - - gemset'' = lib.flip lib.mapAttrs gemset' (name: attrs: - if (lib.isDerivation attrs) - then attrs - else instantiate (attrs // { inherit name; }) - ); - -in gemset'' diff --git a/pkgs/development/interpreters/ruby/rubygems.nix b/pkgs/development/interpreters/ruby/rubygems.nix index f4942b840919..b6ac04808979 100644 --- a/pkgs/development/interpreters/ruby/rubygems.nix +++ b/pkgs/development/interpreters/ruby/rubygems.nix @@ -1,37 +1,35 @@ -args @ { makeWrapper, ruby, ... }: with args; +{ stdenv, lib, fetchurl, makeWrapper, ruby }: -rec { - name = "rubygems-" + version; +stdenv.mkDerivation rec { + name = "rubygems-${version}"; version = "2.4.1"; src = fetchurl { url = "http://production.cf.rubygems.org/rubygems/${name}.tgz"; sha256 = "0cpr6cx3h74ykpb0cp4p4xg7a8j0bhz3sk271jq69l4mm4zy4h4f"; }; - buildInputs = [ruby makeWrapper]; - configureFlags = []; + patches = [ ./gem_hook.patch ]; - doInstall = fullDepEntry ('' + buildInputs = [ruby makeWrapper]; + + buildPhase = ":"; + + installPhase = '' ruby setup.rb --prefix=$out/ + wrapProgram $out/bin/gem --prefix RUBYLIB : $out/lib - find $out -type f -name "*.rb" | xargs sed -i "s@/usr/bin/env@$(type -p env)@g" + + find $out -type f -name "*.rb" | + xargs sed -i "s@/usr/bin/env@$(type -p env)@g" + mkdir -pv $out/nix-support cat > $out/nix-support/setup-hook <