summaryrefslogtreecommitdiffstats
path: root/pkgs/development/ruby-modules
diff options
context:
space:
mode:
authorzimbatm <zimbatm@zimbatm.com>2016-03-15 20:49:07 +0000
committerzimbatm <zimbatm@zimbatm.com>2016-03-19 22:06:26 +0000
commit5a64bc44ead7099857e5ecec339e87a80a60796e (patch)
tree8130746780b4d7c7e636e4e70433418b86951478 /pkgs/development/ruby-modules
parent3547ffa89fec408e93627c03f8bf0b3c98bde0e2 (diff)
move all ruby modules to development/ruby-modules
Diffstat (limited to 'pkgs/development/ruby-modules')
-rw-r--r--pkgs/development/ruby-modules/bundix/default.nix44
-rw-r--r--pkgs/development/ruby-modules/bundler-env/default.nix108
-rw-r--r--pkgs/development/ruby-modules/bundler-env/gen-bin-stubs.rb44
-rw-r--r--pkgs/development/ruby-modules/bundler/default.nix10
-rw-r--r--pkgs/development/ruby-modules/gem-config/default.nix166
-rw-r--r--pkgs/development/ruby-modules/gem-config/mkrf_conf_xapian.rb14
-rw-r--r--pkgs/development/ruby-modules/gem-config/xapian-Rakefile38
-rw-r--r--pkgs/development/ruby-modules/gem/default.nix209
-rw-r--r--pkgs/development/ruby-modules/gem/gem-post-build.rb76
-rw-r--r--pkgs/development/ruby-modules/gem/nix-bundle-install.rb152
10 files changed, 861 insertions, 0 deletions
diff --git a/pkgs/development/ruby-modules/bundix/default.nix b/pkgs/development/ruby-modules/bundix/default.nix
new file mode 100644
index 000000000000..ac3abcdcdf7b
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundix/default.nix
@@ -0,0 +1,44 @@
+{ buildRubyGem, lib, bundler, ruby, nix, nix-prefetch-git }:
+
+buildRubyGem rec {
+ inherit ruby;
+
+ name = "${gemName}-${version}";
+ gemName = "bundix";
+ version = "2.0.8";
+
+ sha256 = "0ikpf2g01izadjpdnc4k2rb9v4g11f1jk2y5alxc7n7rxjkwdc66";
+
+ buildInputs = [bundler];
+
+ postInstall = ''
+ substituteInPlace $GEM_HOME/gems/${gemName}-${version}/lib/bundix.rb \
+ --replace \
+ "'nix-instantiate'" \
+ "'${nix}/bin/nix-instantiate'" \
+ --replace \
+ "'nix-hash'" \
+ "'${nix}/bin/nix-hash'" \
+ --replace \
+ "'nix-prefetch-url'" \
+ "'${nix}/bin/nix-prefetch-url'" \
+ --replace \
+ "'nix-prefetch-git'" \
+ "'${nix-prefetch-git}/bin/nix-prefetch-git'"
+ '';
+
+ meta = {
+ inherit version;
+ description = "Creates Nix packages from Gemfiles";
+ longDescription = ''
+ This is a tool that converts Gemfile.lock files to nix expressions.
+
+ The output is then usable by the bundlerEnv derivation to list all the
+ dependencies of a ruby package.
+ '';
+ homepage = "https://github.com/manveru/bundix";
+ license = "MIT";
+ maintainers = with lib.maintainers; [ manveru zimbatm ];
+ platforms = lib.platforms.all;
+ };
+}
diff --git a/pkgs/development/ruby-modules/bundler-env/default.nix b/pkgs/development/ruby-modules/bundler-env/default.nix
new file mode 100644
index 000000000000..d5e2154ab3b3
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundler-env/default.nix
@@ -0,0 +1,108 @@
+{ stdenv, runCommand, writeText, writeScript, writeScriptBin, ruby, lib
+, callPackage, defaultGemConfig, fetchurl, fetchgit, buildRubyGem, buildEnv
+, git
+, makeWrapper
+, bundler
+, tree
+}@defs:
+
+{ name, gemset, gemfile, lockfile, ruby ? defs.ruby, gemConfig ? defaultGemConfig
+, postBuild ? null
+, document ? []
+, meta ? {}
+, ignoreCollisions ? false
+, ...
+}@args:
+
+let
+
+ shellEscape = x: "'${lib.replaceChars ["'"] [("'\\'" + "'")] x}'";
+ importedGemset = import gemset;
+ applyGemConfigs = 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; });
+ gems = lib.flip lib.mapAttrs configuredGemset (name: attrs:
+ buildRubyGem ((removeAttrs attrs ["source"]) // attrs.source // {
+ inherit ruby;
+ 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
+
+ cd $out
+ chmod +w Gemfile.lock
+ 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 = ''
+ ${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 = rec {
+ inherit ruby bundler meta gems;
+
+ wrappedRuby = stdenv.mkDerivation {
+ name = "wrapped-ruby-${name}";
+ nativeBuildInputs = [ makeWrapper ];
+ buildCommand = ''
+ mkdir -p $out/bin
+ for i in ${ruby}/bin/*; do
+ makeWrapper "$i" $out/bin/$(basename "$i") \
+ --set BUNDLE_GEMFILE ${confFiles}/Gemfile \
+ --set BUNDLE_PATH ${bundlerEnv}/${ruby.gemPath} \
+ --set GEM_HOME ${bundlerEnv}/${ruby.gemPath} \
+ --set GEM_PATH ${bundlerEnv}/${ruby.gemPath}
+ done
+ '';
+ };
+
+ env = let
+ irbrc = builtins.toFile "irbrc" ''
+ if !(ENV["OLD_IRBRC"].nil? || ENV["OLD_IRBRC"].empty?)
+ require ENV["OLD_IRBRC"]
+ end
+ require 'rubygems'
+ require 'bundler/setup'
+ '';
+ in stdenv.mkDerivation {
+ name = "interactive-${name}-environment";
+ nativeBuildInputs = [ wrappedRuby bundlerEnv ];
+ shellHook = ''
+ export OLD_IRBRC="$IRBRC"
+ export IRBRC=${irbrc}
+ '';
+ buildCommand = ''
+ echo >&2 ""
+ echo >&2 "*** Ruby 'env' attributes are intended for interactive nix-shell sessions, not for building! ***"
+ echo >&2 ""
+ exit 1
+ '';
+ };
+ };
+ };
+
+in
+
+bundlerEnv
diff --git a/pkgs/development/ruby-modules/bundler-env/gen-bin-stubs.rb b/pkgs/development/ruby-modules/bundler-env/gen-bin-stubs.rb
new file mode 100644
index 000000000000..fa77682cfd59
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundler-env/gen-bin-stubs.rb
@@ -0,0 +1,44 @@
+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.use_paths("#{bundler_gem_path}", ENV["GEM_PATH"])
+
+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/ruby-modules/bundler/default.nix b/pkgs/development/ruby-modules/bundler/default.nix
new file mode 100644
index 000000000000..718da20b0068
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundler/default.nix
@@ -0,0 +1,10 @@
+{ buildRubyGem, makeWrapper, ruby, coreutils }:
+
+buildRubyGem rec {
+ inherit ruby;
+ name = "${gemName}-${version}";
+ gemName = "bundler";
+ version = "1.11.2";
+ sha256 = "0s37j1hyngc4shq0in8f9y1knjdqkisdg3dd1mfwgq7n1bz8zan7";
+ dontPatchShebangs = true;
+}
diff --git a/pkgs/development/ruby-modules/gem-config/default.nix b/pkgs/development/ruby-modules/gem-config/default.nix
new file mode 100644
index 000000000000..dd4ae725095d
--- /dev/null
+++ b/pkgs/development/ruby-modules/gem-config/default.nix
@@ -0,0 +1,166 @@
+# The standard set of gems in nixpkgs including potential fixes.
+#
+# The gemset is derived from two points of entry:
+# - An attrset describing a gem, including version, source and dependencies
+# This is just meta data, most probably automatically generated by a tool
+# like Bundix (https://github.com/aflatter/bundix).
+# {
+# name = "bundler";
+# version = "1.6.5";
+# sha256 = "1s4x0f5by9xs2y24jk6krq5ky7ffkzmxgr4z1nhdykdmpsi2zd0l";
+# dependencies = [ "rake" ];
+# }
+# - An optional derivation that may override how the gem is built. For popular
+# gems that don't behave correctly, fixes are already provided in the form of
+# derivations.
+#
+# This seperates "what to build" (the exact gem versions) from "how to build"
+# (to make gems behave if necessary).
+
+{ lib, fetchurl, writeScript, ruby, kerberos, libxml2, libxslt, python, stdenv, which
+, libiconv, postgresql, v8_3_16_14, clang, sqlite, zlib, imagemagick
+, pkgconfig , ncurses, xapian, gpgme, utillinux, fetchpatch, tzdata, icu, libffi
+, cmake, libssh2, openssl, mysql, darwin, git, perl, gecode_3, curl
+, libmsgpack
+}:
+
+let
+ v8 = v8_3_16_14;
+in
+
+{
+ charlock_holmes = attrs: {
+ buildInputs = [ which icu zlib ];
+ };
+
+ dep-selector-libgecode = attrs: {
+ USE_SYSTEM_GECODE = true;
+ postInstall = ''
+ installPath=$(cat $out/nix-support/gem-meta/install-path)
+ sed -i $installPath/lib/dep-selector-libgecode.rb -e 's@VENDORED_GECODE_DIR =.*@VENDORED_GECODE_DIR = "${gecode_3}"@'
+ '';
+ };
+
+ eventmachine = attrs: {
+ buildInputs = [ openssl ];
+ };
+
+ ffi = attrs: {
+ buildInputs = [ libffi pkgconfig ];
+ };
+
+ gpgme = attrs: {
+ buildInputs = [ gpgme ];
+ };
+
+ # note that you need version >= 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" ];
+ };
+
+ msgpack = attrs: {
+ buildInputs = [ libmsgpack ];
+ };
+
+ mysql2 = attrs: {
+ buildInputs = [ mysql.lib zlib openssl ];
+ };
+
+ ncursesw = attrs: {
+ buildInputs = [ ncurses ];
+ buildFlags = [
+ "--with-cflags=-I${ncurses}/include"
+ "--with-ldflags=-L${ncurses}/lib"
+ ];
+ };
+
+ nokogiri = attrs: {
+ buildFlags = [
+ "--use-system-libraries"
+ "--with-zlib-dir=${zlib}"
+ "--with-xml2-lib=${libxml2}/lib"
+ "--with-xml2-include=${libxml2}/include/libxml2"
+ "--with-xslt-lib=${libxslt}/lib"
+ "--with-xslt-include=${libxslt}/include"
+ "--with-exslt-lib=${libxslt}/lib"
+ "--with-exslt-include=${libxslt}/include"
+ ] ++ lib.optional stdenv.isDarwin "--with-iconv-dir=${libiconv}";
+ };
+
+ patron = attrs: {
+ buildInputs = [ curl ];
+ };
+
+ pg = attrs: {
+ buildFlags = [
+ "--with-pg-config=${postgresql}/bin/pg_config"
+ ];
+ };
+
+ puma = attrs: {
+ buildInputs = [ openssl ];
+ };
+
+ rmagick = attrs: {
+ buildInputs = [ imagemagick pkgconfig ];
+ };
+
+ rugged = attrs: {
+ buildInputs = [ cmake pkgconfig openssl libssh2 zlib ];
+ };
+
+ sqlite3 = attrs: {
+ buildFlags = [
+ "--with-sqlite3-include=${sqlite}/include"
+ "--with-sqlite3-lib=${sqlite}/lib"
+ ];
+ };
+
+ sup = attrs: {
+ dontBuild = false;
+ # prevent sup from trying to dynamically install `xapian-ruby`.
+ postPatch = ''
+ cp ${./mkrf_conf_xapian.rb} ext/mkrf_conf_xapian.rb
+
+ substituteInPlace lib/sup/crypto.rb \
+ --replace 'which gpg2' \
+ '${which}/bin/which gpg2'
+ '';
+ };
+
+ timfel-krb5-auth = attrs: {
+ buildInputs = [ kerberos ];
+ };
+
+ therubyracer = attrs: {
+ buildFlags = [
+ "--with-v8-dir=${v8}"
+ "--with-v8-include=${v8}/include"
+ "--with-v8-lib=${v8}/lib"
+ ];
+ };
+
+ tzinfo = attrs: {
+ dontBuild = false;
+ postPatch = ''
+ substituteInPlace lib/tzinfo/zoneinfo_data_source.rb \
+ --replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo"
+ '';
+ };
+
+ xapian-ruby = attrs: {
+ # use the system xapian
+ dontBuild = false;
+ buildInputs = [ xapian pkgconfig zlib ];
+ postPatch = ''
+ cp ${./xapian-Rakefile} Rakefile
+ '';
+ preInstall = ''
+ export XAPIAN_CONFIG=${xapian}/bin/xapian-config
+ '';
+ };
+}
+
diff --git a/pkgs/development/ruby-modules/gem-config/mkrf_conf_xapian.rb b/pkgs/development/ruby-modules/gem-config/mkrf_conf_xapian.rb
new file mode 100644
index 000000000000..e19f06e23ac2
--- /dev/null
+++ b/pkgs/development/ruby-modules/gem-config/mkrf_conf_xapian.rb
@@ -0,0 +1,14 @@
+require 'rubygems'
+require 'rubygems/command.rb'
+require 'rubygems/dependency_installer.rb'
+require 'rbconfig'
+
+begin
+ Gem::Command.build_args = ARGV
+rescue NoMethodError
+end
+
+# create dummy rakefile to indicate success
+f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w")
+f.write("task :default\n")
+f.close
diff --git a/pkgs/development/ruby-modules/gem-config/xapian-Rakefile b/pkgs/development/ruby-modules/gem-config/xapian-Rakefile
new file mode 100644
index 000000000000..9f0b8e72f08c
--- /dev/null
+++ b/pkgs/development/ruby-modules/gem-config/xapian-Rakefile
@@ -0,0 +1,38 @@
+# encoding: utf-8
+# Install the xapian binaries into the lib folder of the gem
+require 'rbconfig'
+
+c = RbConfig::CONFIG
+
+def system!(cmd)
+ puts cmd
+ system(cmd) or raise
+end
+
+source_dir = 'xapian_source'
+bindings = Dir["#{source_dir}/xapian-bindings-*"].first
+bindings = File.basename(bindings, ".tar.xz")
+
+task :default do
+ system! "tar -xJf #{source_dir}/#{bindings}.tar.xz"
+
+ prefix = Dir.pwd
+ ENV['LDFLAGS'] = "-L#{prefix}/lib"
+
+ system! "mkdir -p lib"
+
+ Dir.chdir bindings do
+ ENV['RUBY'] ||= "#{c['bindir']}/#{c['RUBY_INSTALL_NAME']}"
+ system! "./configure --prefix=#{prefix} --exec-prefix=#{prefix} --with-ruby"
+ system! "make clean all"
+ end
+
+ system! "cp -r #{bindings}/ruby/.libs/_xapian.* lib"
+ system! "cp #{bindings}/ruby/xapian.rb lib"
+
+ system! "rm lib/*.la"
+ system! "rm lib/*.lai"
+
+ system! "rm -R #{bindings}"
+ system! "rm -R #{source_dir}"
+end
diff --git a/pkgs/development/ruby-modules/gem/default.nix b/pkgs/development/ruby-modules/gem/default.nix
new file mode 100644
index 000000000000..6e1b0c00bd08
--- /dev/null
+++ b/pkgs/development/ruby-modules/gem/default.nix
@@ -0,0 +1,209 @@
+# 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, bundler, fetchurl, fetchgit, makeWrapper, git,
+ buildRubyGem, darwin
+} @ defs:
+
+lib.makeOverridable (
+
+{ name ? null
+, gemName
+, version ? null
+, type ? "gem"
+, document ? [] # e.g. [ "ri" "rdoc" ]
+, platform ? "ruby"
+, ruby ? defs.ruby
+, stdenv ? ruby.stdenv
+, namePrefix ? (let
+ rubyName = builtins.parseDrvName ruby.name;
+ in "${rubyName.name}${rubyName.version}-")
+, 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:
+
+let
+ shellEscape = x: "'${lib.replaceChars ["'"] [("'\\'" + "'")] x}'";
+ src = attrs.src or (
+ if type == "gem" then
+ fetchurl {
+ urls = map (remote: "${remote}/gems/${gemName}-${version}.gem") remotes;
+ inherit (attrs) sha256;
+ }
+ else if type == "git" then
+ fetchgit {
+ inherit (attrs) url rev sha256 fetchSubmodules;
+ leaveDotGit = true;
+ }
+ else
+ throw "buildRubyGem: don't know how to build a gem of type \"${type}\""
+ );
+ documentFlag =
+ if document == []
+ then "-N"
+ else "--document ${lib.concatStringsSep "," document}";
+
+in
+
+stdenv.mkDerivation (attrs // {
+ inherit ruby;
+ inherit doCheck;
+ inherit dontBuild;
+ inherit dontStrip;
+ inherit type;
+
+ buildInputs = [
+ ruby makeWrapper
+ ] ++ lib.optionals (type == "git") [ git bundler ]
+ ++ lib.optional stdenv.isDarwin darwin.libobjc
+ ++ buildInputs;
+
+ name = attrs.name or "${namePrefix}${gemName}-${version}";
+
+ 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/ruby-modules/gem/gem-post-build.rb b/pkgs/development/ruby-modules/gem/gem-post-build.rb
new file mode 100644
index 000000000000..4480c525bf16
--- /dev/null
+++ b/pkgs/development/ruby-modules/gem/gem-post-build.rb
@@ -0,0 +1,76 @@
+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.use_paths "#{gem_home}", #{gem_path.to_s}
+
+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/ruby-modules/gem/nix-bundle-install.rb b/pkgs/development/ruby-modules/gem/nix-bundle-install.rb
new file mode 100644
index 000000000000..48ab5270c22f
--- /dev/null
+++ b/pkgs/development/ruby-modules/gem/nix-bundle-install.rb
@@ -0,0 +1,152 @@
+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|
+ 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