diff options
Diffstat (limited to 'nixpkgs/pkgs/development/ruby-modules')
28 files changed, 1947 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/development/ruby-modules/bundix/default.nix b/nixpkgs/pkgs/development/ruby-modules/bundix/default.nix new file mode 100644 index 000000000000..92f14114cf10 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundix/default.nix @@ -0,0 +1,44 @@ +{ buildRubyGem, fetchFromGitHub, makeWrapper, lib, bundler, nix, + nix-prefetch-git }: + +buildRubyGem rec { + inherit (bundler) ruby; + + name = "${gemName}-${version}"; + gemName = "bundix"; + version = "2.4.1"; + + src = fetchFromGitHub { + owner = "manveru"; + repo = "bundix"; + rev = version; + sha256 = "175qmv7dj7v50v71b78dzn5pb4a35ml6p15asks9q1rrlkz0n4gn"; + }; + + buildInputs = [ ruby bundler ]; + nativeBuildInputs = [ makeWrapper ]; + + preFixup = '' + wrapProgram $out/bin/bundix \ + --prefix PATH : "${nix.out}/bin" \ + --prefix PATH : "${nix-prefetch-git.out}/bin" \ + --prefix PATH : "${bundler.out}/bin" \ + --set GEM_HOME "${bundler}/${bundler.ruby.gemPath}" \ + --set GEM_PATH "${bundler}/${bundler.ruby.gemPath}" + ''; + + 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 qyliss zimbatm ]; + platforms = lib.platforms.all; + }; +} diff --git a/nixpkgs/pkgs/development/ruby-modules/bundled-common/default.nix b/nixpkgs/pkgs/development/ruby-modules/bundled-common/default.nix new file mode 100644 index 000000000000..c31dfb63b3cd --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundled-common/default.nix @@ -0,0 +1,158 @@ +{ stdenv, runCommand, ruby, lib +, defaultGemConfig, buildRubyGem, buildEnv +, makeWrapper +, bundler +}@defs: + +{ + name ? null +, pname ? null +, mainGemName ? null +, gemdir ? null +, gemfile ? null +, lockfile ? null +, gemset ? null +, ruby ? defs.ruby +, gemConfig ? defaultGemConfig +, postBuild ? null +, document ? [] +, meta ? {} +, groups ? null +, ignoreCollisions ? false +, buildInputs ? [] +, ... +}@args: + +assert name == null -> pname != null; + +with import ./functions.nix { inherit lib gemConfig; }; + +let + gemFiles = bundlerFiles args; + + importedGemset = if builtins.typeOf gemFiles.gemset != "set" + then import gemFiles.gemset + else gemFiles.gemset; + + filteredGemset = filterGemset { inherit ruby groups; } importedGemset; + + configuredGemset = lib.flip lib.mapAttrs filteredGemset (name: attrs: + applyGemConfigs (attrs // { inherit ruby; gemName = name; }) + ); + + hasBundler = builtins.hasAttr "bundler" filteredGemset; + + bundler = + if hasBundler then gems.bundler + else defs.bundler.override (attrs: { inherit ruby; }); + + gems = lib.flip lib.mapAttrs configuredGemset (name: attrs: buildGem name attrs); + + name' = if name != null then + name + else + let + gem = gems."${pname}"; + version = gem.version; + in + "${pname}-${version}"; + + pname' = if pname != null then + pname + else + name; + + copyIfBundledByPath = { bundledByPath ? false, ...}: + (if bundledByPath then + assert gemFiles.gemdir != null; "cp -a ${gemFiles.gemdir}/* $out/" #*/ + else "" + ); + + maybeCopyAll = pkgname: if pkgname == null then "" else + let + mainGem = gems."${pkgname}" or (throw "bundlerEnv: gem ${pkgname} not found"); + in + copyIfBundledByPath mainGem; + + # 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 + ${maybeCopyAll mainGemName} + cp ${gemFiles.gemfile} $out/Gemfile || ls -l $out/Gemfile + cp ${gemFiles.lockfile} $out/Gemfile.lock || ls -l $out/Gemfile.lock + ''; + + buildGem = name: attrs: ( + let + gemAttrs = composeGemAttrs ruby gems name attrs; + in + if gemAttrs.type == "path" then + pathDerivation (gemAttrs.source // gemAttrs) + else + buildRubyGem gemAttrs + ); + + envPaths = lib.attrValues gems ++ lib.optional (!hasBundler) bundler; + + basicEnv = buildEnv { + inherit buildInputs ignoreCollisions; + + name = name'; + + paths = envPaths; + pathsToLink = [ "/lib" ]; + + postBuild = genStubsScript (defs // args // { + inherit confFiles bundler groups; + binPaths = envPaths; + }) + lib.optionalString (postBuild != null) postBuild; + + meta = { platforms = ruby.meta.platforms; } // meta; + + passthru = rec { + inherit ruby bundler gems confFiles envPaths; + + wrappedRuby = stdenv.mkDerivation { + name = "wrapped-ruby-${pname'}"; + 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 ${basicEnv}/${ruby.gemPath} \ + --set BUNDLE_FROZEN 1 \ + --set GEM_HOME ${basicEnv}/${ruby.gemPath} \ + --set GEM_PATH ${basicEnv}/${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 = "${pname'}-interactive-environment"; + nativeBuildInputs = [ wrappedRuby basicEnv ]; + 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 + basicEnv diff --git a/nixpkgs/pkgs/development/ruby-modules/bundled-common/functions.nix b/nixpkgs/pkgs/development/ruby-modules/bundled-common/functions.nix new file mode 100644 index 000000000000..6324f27e9faf --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundled-common/functions.nix @@ -0,0 +1,93 @@ +{ lib, gemConfig, ... }: + +let + inherit (lib) attrValues concatMap converge filterAttrs getAttrs + intersectLists; + +in rec { + bundlerFiles = { + gemfile ? null + , lockfile ? null + , gemset ? null + , gemdir ? null + , ... + }: { + inherit gemdir; + + gemfile = + if gemfile == null then assert gemdir != null; gemdir + "/Gemfile" + else gemfile; + + lockfile = + if lockfile == null then assert gemdir != null; gemdir + "/Gemfile.lock" + else lockfile; + + gemset = + if gemset == null then assert gemdir != null; gemdir + "/gemset.nix" + else gemset; + }; + + filterGemset = { ruby, groups, ... }: gemset: + let + platformGems = filterAttrs (_: platformMatches ruby) gemset; + directlyMatchingGems = filterAttrs (_: groupMatches groups) platformGems; + + expandDependencies = gems: + let + depNames = concatMap (gem: gem.dependencies or []) (attrValues gems); + deps = getAttrs depNames platformGems; + in + gems // deps; + in + converge expandDependencies directlyMatchingGems; + + platformMatches = {rubyEngine, version, ...}: attrs: ( + !(attrs ? "platforms") || + builtins.length attrs.platforms == 0 || + builtins.any (platform: + platform.engine == rubyEngine && + (!(platform ? "version") || platform.version == version.majMin) + ) attrs.platforms + ); + + groupMatches = groups: attrs: + groups == null || !(attrs ? "groups") || + (intersectLists (groups ++ [ "default" ]) attrs.groups) != []; + + applyGemConfigs = attrs: + (if gemConfig ? "${attrs.gemName}" + then attrs // gemConfig."${attrs.gemName}" attrs + else attrs); + + genStubsScript = { lib, ruby, confFiles, bundler, groups, binPaths, ... }: '' + ${ruby}/bin/ruby ${./gen-bin-stubs.rb} \ + "${ruby}/bin/ruby" \ + "${confFiles}/Gemfile" \ + "$out/${ruby.gemPath}" \ + "${bundler}/${ruby.gemPath}" \ + ${lib.escapeShellArg binPaths} \ + ${lib.escapeShellArg groups} + ''; + + pathDerivation = { gemName, version, path, ... }: + let + res = { + type = "derivation"; + bundledByPath = true; + name = gemName; + version = version; + outPath = path; + outputs = [ "out" ]; + out = res; + outputName = "out"; + }; + in res; + + composeGemAttrs = ruby: gems: name: attrs: ((removeAttrs attrs ["platforms"]) // { + inherit ruby; + inherit (attrs.source) type; + source = removeAttrs attrs.source ["type"]; + gemName = name; + gemPath = map (gemName: gems."${gemName}") (attrs.dependencies or []); + }); +} diff --git a/nixpkgs/pkgs/development/ruby-modules/bundled-common/gen-bin-stubs.rb b/nixpkgs/pkgs/development/ruby-modules/bundled-common/gen-bin-stubs.rb new file mode 100644 index 000000000000..fe8c43f55ed1 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundled-common/gen-bin-stubs.rb @@ -0,0 +1,48 @@ +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 +groups = ARGV[5].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") + .force_encoding('UTF-8').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.dump} +ENV["BUNDLE_PATH"] = #{bundle_path.dump} +ENV['BUNDLE_FROZEN'] = '1' + +Gem.use_paths(#{bundler_gem_path.dump}, ENV["GEM_PATH"]) + +require 'bundler' +Bundler.setup(#{groups.map(&:dump).join(', ')}) + +load Gem.bin_path(#{name.dump}, #{exe.dump}) +EOF + FileUtils.chmod("+x", "#{out}/bin/#{exe}") + end + end +end diff --git a/nixpkgs/pkgs/development/ruby-modules/bundled-common/test.nix b/nixpkgs/pkgs/development/ruby-modules/bundled-common/test.nix new file mode 100644 index 000000000000..7c5932c4e761 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundled-common/test.nix @@ -0,0 +1,50 @@ +{ stdenv, writeText, lib, ruby, defaultGemConfig, callPackage, test, stubs, should }: +let + testConfigs = { + inherit lib; + gemConfig = defaultGemConfig; + }; + functions = (import ./functions.nix testConfigs); +in + builtins.concatLists [ + ( test.run "All set, no gemdir" (functions.bundlerFiles { + gemfile = test/Gemfile; + lockfile = test/Gemfile.lock; + gemset = test/gemset.nix; + }) { + gemfile = should.equal test/Gemfile; + lockfile = should.equal test/Gemfile.lock; + gemset = should.equal test/gemset.nix; + }) + + ( test.run "Just gemdir" (functions.bundlerFiles { + gemdir = test/.; + }) { + gemfile = should.equal test/Gemfile; + lockfile = should.equal test/Gemfile.lock; + gemset = should.equal test/gemset.nix; + }) + + ( test.run "Gemset and dir" (functions.bundlerFiles { + gemdir = test/.; + gemset = test/extraGemset.nix; + }) { + gemfile = should.equal test/Gemfile; + lockfile = should.equal test/Gemfile.lock; + gemset = should.equal test/extraGemset.nix; + }) + + ( test.run "Filter empty gemset" {} (set: functions.filterGemset {inherit ruby; groups = ["default"]; } set == {})) + ( let gemSet = { test = { groups = ["x" "y"]; }; }; + in + test.run "Filter matches a group" gemSet (set: functions.filterGemset {inherit ruby; groups = ["y" "z"];} set == gemSet)) + ( let gemSet = { test = { platforms = []; }; }; + in + test.run "Filter matches empty platforms list" gemSet (set: functions.filterGemset {inherit ruby; groups = [];} set == gemSet)) + ( let gemSet = { test = { platforms = [{engine = ruby.rubyEngine; version = ruby.version.majMin;}]; }; }; + in + test.run "Filter matches on platform" gemSet (set: functions.filterGemset {inherit ruby; groups = [];} set == gemSet)) + ( let gemSet = { test = { groups = ["x" "y"]; }; }; + in + test.run "Filter excludes based on groups" gemSet (set: functions.filterGemset {inherit ruby; groups = ["a" "b"];} set == {})) + ] diff --git a/nixpkgs/pkgs/development/ruby-modules/bundler-app/default.nix b/nixpkgs/pkgs/development/ruby-modules/bundler-app/default.nix new file mode 100644 index 000000000000..d0ad56538b94 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundler-app/default.nix @@ -0,0 +1,63 @@ +{ lib, stdenv, callPackage, runCommand, makeWrapper, ruby }@defs: + +# Use for simple installation of Ruby tools shipped in a Gem. +# Start with a Gemfile that includes `gem <toolgem>` +# > nix-shell -p bundler bundix +# (shell)> bundle lock +# (shell)> bundix +# Then use rubyTool in the default.nix: + +# rubyTool { pname = "gemifiedTool"; gemdir = ./.; exes = ["gemified-tool"]; } +# The 'exes' parameter ensures that a copy of e.g. rake doesn't polute the system. +{ + # use the name of the name in question; its version will be picked up from the gemset + pname + # gemdir is the location of the Gemfile{,.lock} and gemset.nix; usually ./. +, gemdir + # Exes is the list of executables provided by the gems in the Gemfile +, exes ? [] + # Scripts are ruby programs depend on gems in the Gemfile (e.g. scripts/rails) +, scripts ? [] +, ruby ? defs.ruby +, gemfile ? null +, lockfile ? null +, gemset ? null +, preferLocalBuild ? false +, allowSubstitutes ? false +, installManpages ? true +, meta ? {} +, buildInputs ? [] +, postBuild ? "" +, gemConfig ? null +, passthru ? {} +}@args: + +let + basicEnv = (callPackage ../bundled-common {}) args; + + cmdArgs = removeAttrs args [ "pname" "postBuild" "gemConfig" ] // { + inherit preferLocalBuild allowSubstitutes; # pass the defaults + + buildInputs = buildInputs ++ lib.optional (scripts != []) makeWrapper; + }; +in + runCommand basicEnv.name cmdArgs '' + mkdir -p $out/bin + ${(lib.concatMapStrings (x: "ln -s '${basicEnv}/bin/${x}' $out/bin/${x};\n") exes)} + ${(lib.concatMapStrings (s: "makeWrapper $out/bin/$(basename ${s}) $srcdir/${s} " + + "--set BUNDLE_GEMFILE ${basicEnv.confFiles}/Gemfile "+ + "--set BUNDLE_PATH ${basicEnv}/${ruby.gemPath} "+ + "--set BUNDLE_FROZEN 1 "+ + "--set GEM_HOME ${basicEnv}/${ruby.gemPath} "+ + "--set GEM_PATH ${basicEnv}/${ruby.gemPath} "+ + "--run \"cd $srcdir\";\n") scripts)} + + ${lib.optionalString installManpages '' + for section in {1..9}; do + mandir="$out/share/man/man$section" + find -L ${basicEnv}/${ruby.gemPath}/gems/${basicEnv.name} \( -wholename "*/man/*.$section" -o -wholename "*/man/man$section/*.$section" \) -print -execdir mkdir -p $mandir \; -execdir cp '{}' $mandir \; + done + ''} + + ${postBuild} + '' diff --git a/nixpkgs/pkgs/development/ruby-modules/bundler-env/default.nix b/nixpkgs/pkgs/development/ruby-modules/bundler-env/default.nix new file mode 100644 index 000000000000..5d1489ba2005 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundler-env/default.nix @@ -0,0 +1,59 @@ +{ ruby, lib, callPackage, defaultGemConfig, buildEnv, bundler }@defs: + +{ name ? null +, pname ? null +, gemdir ? null +, gemfile ? null +, lockfile ? null +, gemset ? null +, groups ? ["default"] +, ruby ? defs.ruby +, gemConfig ? defaultGemConfig +, postBuild ? null +, document ? [] +, meta ? {} +, ignoreCollisions ? false +, ... +}@args: + +let + inherit (import ../bundled-common/functions.nix {inherit lib ruby gemConfig groups; }) genStubsScript; + + basicEnv = (callPackage ../bundled-common {}) (args // { inherit pname name; mainGemName = pname; }); + + inherit (basicEnv) envPaths; + # Idea here is a mkDerivation that gen-bin-stubs new stubs "as specified" - + # either specific executables or the bin/ for certain gem(s), but + # incorporates the basicEnv as a requirement so that its $out is in our path. + + # When stubbing the bins for a gem, we should use the gem expression + # directly, which means that basicEnv should somehow make it available. + + # Different use cases should use different variations on this file, rather + # than the expression trying to deduce a use case. + + # The basicEnv should be put into passthru so that e.g. nix-shell can use it. +in + if pname == null then + basicEnv // { inherit name basicEnv; } + else + (buildEnv { + inherit ignoreCollisions; + + name = basicEnv.name; + + paths = envPaths; + pathsToLink = [ "/lib" ]; + + postBuild = genStubsScript { + inherit lib ruby bundler groups; + confFiles = basicEnv.confFiles; + binPaths = [ basicEnv.gems."${pname}" ]; + } + lib.optionalString (postBuild != null) postBuild; + + meta = { platforms = ruby.meta.platforms; } // meta; + passthru = basicEnv.passthru // { + inherit basicEnv; + inherit (basicEnv) env; + }; + }) diff --git a/nixpkgs/pkgs/development/ruby-modules/bundler-env/test.nix b/nixpkgs/pkgs/development/ruby-modules/bundler-env/test.nix new file mode 100644 index 000000000000..e42f1bf25711 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundler-env/test.nix @@ -0,0 +1,33 @@ +{ stdenv, writeText, lib, ruby, defaultGemConfig, callPackage, test, stubs, should}: +let + bundlerEnv = callPackage ./default.nix stubs // { + basicEnv = callPackage ../bundled-common stubs; + }; + + justName = bundlerEnv { + name = "test-0.1.2"; + gemset = ./test/gemset.nix; + }; + + pnamed = bundlerEnv { + pname = "test"; + gemdir = ./test; + gemset = ./test/gemset.nix; + gemfile = ./test/Gemfile; + lockfile = ./test/Gemfile.lock; + }; +in + builtins.concatLists [ + (test.run "bundlerEnv { name }" justName { + name = should.equal "test-0.1.2"; + }) + (test.run "bundlerEnv { pname }" pnamed + [ + (should.haveKeys [ "name" "env" "postBuild" ]) + { + name = should.equal "test-0.1.2"; + env = should.beASet; + postBuild = should.havePrefix "/nix/store"; + } + ]) + ] diff --git a/nixpkgs/pkgs/development/ruby-modules/bundler-env/test/Gemfile b/nixpkgs/pkgs/development/ruby-modules/bundler-env/test/Gemfile new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundler-env/test/Gemfile diff --git a/nixpkgs/pkgs/development/ruby-modules/bundler-env/test/Gemfile.lock b/nixpkgs/pkgs/development/ruby-modules/bundler-env/test/Gemfile.lock new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundler-env/test/Gemfile.lock diff --git a/nixpkgs/pkgs/development/ruby-modules/bundler-env/test/gemset.nix b/nixpkgs/pkgs/development/ruby-modules/bundler-env/test/gemset.nix new file mode 100644 index 000000000000..53f15f96bc6d --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundler-env/test/gemset.nix @@ -0,0 +1,10 @@ +{ + test = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1j5r0anj8m4qlf2psnldip4b8ha2bsscv11lpdgnfh4nnchzjnxw"; + type = "gem"; + }; + version = "0.1.2"; + }; +} diff --git a/nixpkgs/pkgs/development/ruby-modules/bundler/default.nix b/nixpkgs/pkgs/development/ruby-modules/bundler/default.nix new file mode 100644 index 000000000000..decde250ac23 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/bundler/default.nix @@ -0,0 +1,14 @@ +{ buildRubyGem, ruby }: + +buildRubyGem rec { + inherit ruby; + name = "${gemName}-${version}"; + gemName = "bundler"; + version = "1.17.2"; + source.sha256 = "0dbnq6703mjvgsri45vaw7b4wjqr89z1h8xkzsacqcp24a706m5r"; + dontPatchShebangs = true; + + postFixup = '' + sed -i -e "s/activate_bin_path/bin_path/g" $out/bin/bundle + ''; +} diff --git a/nixpkgs/pkgs/development/ruby-modules/gem-config/default.nix b/nixpkgs/pkgs/development/ruby-modules/gem-config/default.nix new file mode 100644 index 000000000000..7fdf5c839013 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/gem-config/default.nix @@ -0,0 +1,438 @@ +# 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_1_2_22, gpgme, utillinux, fetchpatch, tzdata, icu, libffi +, cmake, libssh2, openssl, mysql, darwin, git, perl, pcre, gecode_3, curl +, msgpack, qt59, libsodium, snappy, libossp_uuid, lxc, libpcap, xorg, gtk2, buildRubyGem +, cairo, re2, rake, gobject-introspection, gdk_pixbuf, zeromq, graphicsmagick, libcxx, file +, libselinux ? null, libsepol ? null, libvirt +}@args: + +let + v8 = v8_3_16_14; + + rainbow_rake = buildRubyGem { + pname = "rake"; + gemName = "rake"; + source.sha256 = "01j8fc9bqjnrsxbppncai05h43315vmz9fwg28qdsgcjw9ck1d7n"; + type = "gem"; + version = "12.0.0"; + }; +in + +{ + atk = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ gtk2 pcre rake ]; + }; + + bundler = attrs: + let + templates = "${attrs.ruby.gemPath}/gems/${attrs.gemName}-${attrs.version}/lib/bundler/templates/"; + in { + # patching shebangs would fail on the templates/Executable file, so we + # temporarily remove the executable flag. + preFixup = "chmod -x $out/${templates}/Executable"; + postFixup = '' + chmod +x $out/${templates}/Executable + + # Allows to load another bundler version + sed -i -e "s/activate_bin_path/bin_path/g" $out/bin/bundle + ''; + }; + + cairo = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ gtk2 pcre xorg.libpthreadstubs xorg.libXdmcp]; + }; + + cairo-gobject = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ cairo pcre xorg.libpthreadstubs xorg.libXdmcp ]; + }; + + capybara-webkit = attrs: { + buildInputs = [ qt59.qtbase qt59.qtwebkit ] ++ stdenv.lib.optionals stdenv.isDarwin [ darwin.apple_sdk.frameworks.Cocoa ]; + NIX_CFLAGS_COMPILE = stdenv.lib.optionalString stdenv.isDarwin "-I${libcxx}/include/c++/v1"; + }; + + charlock_holmes = attrs: { + buildInputs = [ which icu zlib ]; + }; + + curb = attrs: { + buildInputs = [ curl ]; + }; + + curses = attrs: { + buildInputs = [ ncurses ]; + }; + + 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}"@' + ''; + }; + + ethon = attrs: { + dontBuild = false; + postPatch = '' + substituteInPlace lib/ethon/curls/settings.rb \ + --replace "libcurl" "${curl.out}/lib/libcurl${stdenv.hostPlatform.extensions.sharedLibrary}" + ''; + }; + + fog-dnsimple = attrs: { + postInstall = '' + cd $(cat $out/nix-support/gem-meta/install-path) + rm {$out/bin,bin,../../bin}/{setup,console} + ''; + }; + + redis-rack = attrs: { + dontBuild = false; + preBuild = '' + exec 3>&1 + output="$(gem build $gemspec | tee >(cat - >&3))" + exec 3>&- + sed -i 's!"rake".freeze!!' $gemspec + ''; + }; + + ffi-rzmq-core = attrs: { + postInstall = '' + installPath=$(cat $out/nix-support/gem-meta/install-path) + sed -i $installPath/lib/ffi-rzmq-core/libzmq.rb -e 's@inside_gem =.*@inside_gem = "${zeromq}/lib"@' + ''; + }; + + mini_magick = attrs: { + postInstall = '' + installPath=$(cat $out/nix-support/gem-meta/install-path) + echo -e "\nENV['PATH'] += ':${graphicsmagick}/bin'\n" >> $installPath/lib/mini_magick/configuration.rb + ''; + }; + + do_sqlite3 = attrs: { + buildInputs = [ sqlite ]; + }; + + eventmachine = attrs: { + buildInputs = [ openssl ]; + }; + + ffi = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ libffi ]; + }; + + gdk_pixbuf2 = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ rake gdk_pixbuf ]; + }; + + gpgme = attrs: { + buildInputs = [ gpgme ]; + }; + + gio2 = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ gtk2 pcre gobject-introspection ] ++ lib.optionals stdenv.isLinux [ utillinux libselinux libsepol ]; + }; + + gitlab-markup = attrs: { meta.priority = 1; }; + + glib2 = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ gtk2 pcre ]; + }; + + gtk2 = attrs: { + nativeBuildInputs = [ pkgconfig ] ++ lib.optionals stdenv.isLinux [ utillinux libselinux libsepol ]; + buildInputs = [ gtk2 pcre xorg.libpthreadstubs xorg.libXdmcp]; + # CFLAGS must be set for this gem to detect gdkkeysyms.h correctly + CFLAGS = "-I${gtk2.dev}/include/gtk-2.0 -I/non-existent-path"; + }; + + gobject-introspection = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ gobject-introspection gtk2 pcre ]; + }; + + grpc = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ openssl ]; + hardeningDisable = [ "format" ]; + NIX_CFLAGS_COMPILE = [ "-Wno-error=stringop-overflow" "-Wno-error=implicit-fallthrough" ]; + }; + + hitimes = attrs: { + buildInputs = + stdenv.lib.optionals stdenv.isDarwin + [ darwin.apple_sdk.frameworks.CoreServices ]; + }; + + iconv = attrs: { + buildFlags = lib.optional stdenv.isDarwin "--with-iconv-dir=${libiconv}"; + }; + + # disable bundle install as it can't install anything in addition to what is + # specified in pkgs/applications/misc/jekyll/Gemfile anyway. Also do chmod_R + # to compensate for read-only files in site_template in nix store. + jekyll = attrs: { + postInstall = '' + installPath=$(cat $out/nix-support/gem-meta/install-path) + sed -i $installPath/lib/jekyll/commands/new.rb \ + -e 's@Exec.run("bundle", "install"@Exec.run("true"@' \ + -e 's@FileUtils.cp_r site_template + "/.", path@FileUtils.cp_r site_template + "/.", path; FileUtils.chmod_R "u+w", path@' + ''; + }; + + # 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" ]; + }; + + libxml-ruby = attrs: { + buildFlags = [ + "--with-xml2-lib=${libxml2.out}/lib" + "--with-xml2-include=${libxml2.dev}/include/libxml2" + ]; + }; + + magic = attrs: { + buildInputs = [ file ]; + postInstall = '' + installPath=$(cat $out/nix-support/gem-meta/install-path) + sed -e 's@ENV\["MAGIC_LIB"\] ||@ENV\["MAGIC_LIB"\] || "${file}/lib/libmagic.so" ||@' -i $installPath/lib/magic/api.rb + ''; + }; + + metasploit-framework = attrs: { + preInstall = '' + export HOME=$TMPDIR + ''; + }; + + msgpack = attrs: { + buildInputs = [ msgpack ]; + }; + + mysql = attrs: { + buildInputs = [ mysql.connector-c zlib openssl ]; + }; + + mysql2 = attrs: { + buildInputs = [ mysql.connector-c zlib openssl ]; + }; + + ncursesw = attrs: { + buildInputs = [ ncurses ]; + buildFlags = [ + "--with-cflags=-I${ncurses.dev}/include" + "--with-ldflags=-L${ncurses.out}/lib" + ]; + }; + + nokogiri = attrs: { + buildFlags = [ + "--use-system-libraries" + "--with-zlib-dir=${zlib.dev}" + "--with-xml2-lib=${libxml2.out}/lib" + "--with-xml2-include=${libxml2.dev}/include/libxml2" + "--with-xslt-lib=${libxslt.out}/lib" + "--with-xslt-include=${libxslt.dev}/include" + "--with-exslt-lib=${libxslt.out}/lib" + "--with-exslt-include=${libxslt.dev}/include" + ] ++ lib.optional stdenv.isDarwin "--with-iconv-dir=${libiconv}"; + }; + + pango = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ gtk2 xorg.libXdmcp pcre xorg.libpthreadstubs ]; + }; + + patron = attrs: { + buildInputs = [ curl ]; + }; + + pcaprub = attrs: { + buildInputs = [ libpcap ]; + }; + + pg = attrs: { + buildFlags = [ + "--with-pg-config=${postgresql}/bin/pg_config" + ]; + }; + + puma = attrs: { + buildInputs = [ openssl ]; + }; + + rainbow = attrs: { + buildInputs = [ rainbow_rake ]; + }; + + rbnacl = spec: { + postInstall = '' + sed -i $(cat $out/nix-support/gem-meta/install-path)/lib/rbnacl.rb -e "2a \ + RBNACL_LIBSODIUM_GEM_LIB_PATH = '${libsodium.out}/lib/libsodium${stdenv.hostPlatform.extensions.sharedLibrary}' + " + ''; + }; + + re2 = attrs: { + buildInputs = [ re2 ]; + }; + + rmagick = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ imagemagick which ]; + }; + + ruby-libvirt = attrs: { + buildInputs = [ libvirt pkgconfig ]; + buildFlags = [ + "--with-libvirt-include=${libvirt}/include" + "--with-libvirt-lib=${libvirt}/lib" + ]; + }; + + ruby-lxc = attrs: { + buildInputs = [ lxc ]; + }; + + ruby-terminfo = attrs: { + buildInputs = [ ncurses ]; + buildFlags = [ + "--with-cflags=-I${ncurses.dev}/include" + "--with-ldflags=-L${ncurses.out}/lib" + ]; + }; + rugged = attrs: { + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ cmake openssl libssh2 zlib ]; + dontUseCmakeConfigure = true; + }; + + sassc = attrs: { + nativeBuildInputs = [ rake ]; + }; + + scrypt = attrs: + if stdenv.isDarwin then { + dontBuild = false; + postPatch = '' + sed -i -e "s/-arch i386//" Rakefile ext/scrypt/Rakefile + ''; + } else {}; + + sequel_pg = attrs: { + buildInputs = [ postgresql ]; + }; + + snappy = attrs: { + buildInputs = [ args.snappy ]; + }; + + sqlite3 = attrs: { + buildFlags = [ + "--with-sqlite3-include=${sqlite.dev}/include" + "--with-sqlite3-lib=${sqlite.out}/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 gpg' + ''; + }; + + rb-readline = attrs: { + dontBuild = false; + postPatch = '' + substituteInPlace lib/rbreadline.rb \ + --replace 'infocmp' '${ncurses.dev}/bin/infocmp' + ''; + }; + + timfel-krb5-auth = attrs: { + buildInputs = [ kerberos ]; + }; + + tiny_tds = attrs: { + nativeBuildInputs = [ pkgconfig openssl ]; + }; + + therubyracer = attrs: { + buildFlags = [ + "--with-v8-dir=${v8}" + "--with-v8-include=${v8}/include" + "--with-v8-lib=${v8}/lib" + ]; + }; + + typhoeus = attrs: { + buildInputs = [ curl ]; + }; + + tzinfo = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") { + dontBuild = false; + postPatch = '' + substituteInPlace lib/tzinfo/zoneinfo_data_source.rb \ + --replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo" + ''; + }; + + uuid4r = attrs: { + buildInputs = [ which libossp_uuid ]; + }; + + xapian-ruby = attrs: { + # use the system xapian + dontBuild = false; + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ xapian_1_2_22 zlib ]; + postPatch = '' + cp ${./xapian-Rakefile} Rakefile + ''; + preInstall = '' + export XAPIAN_CONFIG=${xapian_1_2_22}/bin/xapian-config + ''; + }; + + zookeeper = attrs: { + buildInputs = stdenv.lib.optionals stdenv.isDarwin [ darwin.cctools ]; + }; + +} diff --git a/nixpkgs/pkgs/development/ruby-modules/gem-config/mkrf_conf_xapian.rb b/nixpkgs/pkgs/development/ruby-modules/gem-config/mkrf_conf_xapian.rb new file mode 100644 index 000000000000..e19f06e23ac2 --- /dev/null +++ b/nixpkgs/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/nixpkgs/pkgs/development/ruby-modules/gem-config/xapian-Rakefile b/nixpkgs/pkgs/development/ruby-modules/gem-config/xapian-Rakefile new file mode 100644 index 000000000000..9f0b8e72f08c --- /dev/null +++ b/nixpkgs/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/nixpkgs/pkgs/development/ruby-modules/gem/default.nix b/nixpkgs/pkgs/development/ruby-modules/gem/default.nix new file mode 100644 index 000000000000..b0abb2c54fc5 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/gem/default.nix @@ -0,0 +1,228 @@ +# 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, fetchurl, fetchgit, makeWrapper, git, darwin +, ruby, bundler +} @ 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 ? [] +, meta ? {} +, patches ? [] +, gemPath ? [] +, dontStrip ? true +# 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 +, dontInstallManpages ? false +, propagatedBuildInputs ? [] +, propagatedUserEnvPkgs ? [] +, buildFlags ? [] +, passthru ? {} +, ...} @ attrs: + +let + src = attrs.src or ( + if type == "gem" then + fetchurl { + urls = map ( + remote: "${remote}/gems/${gemName}-${version}.gem" + ) (attrs.source.remotes or [ "https://rubygems.org" ]); + inherit (attrs.source) sha256; + } + else if type == "git" then + fetchgit { + inherit (attrs.source) url rev sha256 fetchSubmodules; + leaveDotGit = true; + } + else if type == "url" then + fetchurl attrs.source + 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 ((builtins.removeAttrs attrs ["source"]) // { + inherit ruby; + inherit dontBuild; + inherit dontStrip; + inherit type; + + buildInputs = [ + ruby makeWrapper + ] ++ lib.optionals (type == "git") [ git ] + ++ lib.optionals (type != "gem") [ bundler ] + ++ lib.optional stdenv.isDarwin darwin.libobjc + ++ buildInputs; + + #name = builtins.trace (attrs.name or "no attr.name" ) "${namePrefix}${gemName}-${version}"; + name = attrs.name or "${namePrefix}${gemName}-${version}"; + + inherit src; + + 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 == "url") '' + ruby ${./nix-bundle-install.rb} \ + "path" \ + '${gemName}' \ + '${version}' \ + '${lib.escapeShellArgs buildFlags}' + ''} + ${lib.optionalString (type == "git") '' + ruby ${./nix-bundle-install.rb} \ + "git" \ + '${gemName}' \ + '${version}' \ + '${lib.escapeShellArgs buildFlags}' \ + '${attrs.source.url}' \ + '${src}' \ + '${attrs.source.rev}' + ''} + + ${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 \ + --install-dir "$GEM_HOME" \ + --build-root '/' \ + --backtrace \ + --no-env-shebang \ + ${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" + ''} + + ${lib.optionalString (!dontInstallManpages) '' + for section in {1..9}; do + mandir="$out/share/man/man$section" + find $out/lib \( -wholename "*/man/*.$section" -o -wholename "*/man/man$section/*.$section" \) \ + -execdir mkdir -p $mandir \; -execdir cp '{}' $mandir \; + done + ''} + + runHook postInstall + ''; + + propagatedBuildInputs = gemPath ++ propagatedBuildInputs; + propagatedUserEnvPkgs = gemPath ++ propagatedUserEnvPkgs; + + passthru = passthru // { isRubyGem = true; }; + inherit meta; +}) + +) diff --git a/nixpkgs/pkgs/development/ruby-modules/gem/gem-post-build.rb b/nixpkgs/pkgs/development/ruby-modules/gem/gem-post-build.rb new file mode 100644 index 000000000000..f0322b67f61f --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/gem/gem-post-build.rb @@ -0,0 +1,81 @@ +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(File::PATH_SEPARATOR) +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. +# + +require 'rubygems' + +Gem.paths = { + 'GEM_PATH' => ( + ENV['GEM_PATH'].to_s.split(File::PATH_SEPARATOR) + + #{([gem_home] + gem_path).to_s} + ).join(File::PATH_SEPARATOR) +} + +load Gem.activate_bin_path(#{spec.name.inspect}, #{exe.inspect}, #{spec.version.to_s.inspect}) + EOF + end + + FileUtils.chmod("+x", "#{bin_path}/#{exe}") +end diff --git a/nixpkgs/pkgs/development/ruby-modules/gem/nix-bundle-install.rb b/nixpkgs/pkgs/development/ruby-modules/gem/nix-bundle-install.rb new file mode 100644 index 000000000000..142d2da9bee2 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/gem/nix-bundle-install.rb @@ -0,0 +1,182 @@ +require 'rbconfig' +require 'bundler/vendored_thor' +require 'bundler' +require 'rubygems/command' +require 'fileutils' +require 'pathname' +require 'tmpdir' + +if defined?(Encoding.default_internal) + Encoding.default_internal = Encoding::UTF_8 + Encoding.default_external = Encoding::UTF_8 +end + +# Options: +# +# type - installation type, either "git" or "path" +# name - the gem name +# version - gem version +# build-flags - build arguments +# +# Git-only options: +# +# uri - git repo uri +# repo - path to local checkout +# ref - the commit hash + +ruby = File.join(ENV["ruby"], "bin", RbConfig::CONFIG['ruby_install_name']) +out = ENV["out"] +bin_dir = File.join(ENV["out"], "bin") + +type = ARGV[0] +name = ARGV[1] +version = ARGV[2] +build_flags = ARGV[3] +if type == "git" + uri = ARGV[4] + REPO = ARGV[5] + ref = ARGV[6] +end + +# options to pass to bundler +options = { + "name" => name, + "version" => version, +} +if type == "path" + options.merge!({ + "path" => Dir.pwd, + }) +elsif type == "git" + options.merge!({ + "uri" => uri, + "ref" => ref, + }) +end + +# 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 + +if type == "git" + 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 +end + +# UI +verbose = false +no_color = false +Bundler.ui = Bundler::UI::Shell.new({"no-color" => no_color}) +Bundler.ui.level = "debug" if verbose + +# Install +if type == "git" + source = Bundler::Source::Git.new(options) +else + source = Bundler::Source::Path.new(options) +end +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 +if type == "git" + File.open("#{meta}/install-path", "w") do |f| + f.write source.install_path.to_s + end +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 +if type == "git" + 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 +end diff --git a/nixpkgs/pkgs/development/ruby-modules/runtests.sh b/nixpkgs/pkgs/development/ruby-modules/runtests.sh new file mode 100755 index 000000000000..8bb8c8a5462c --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/runtests.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -o xtrace +cd $(dirname $0) +find . -name text.nix +testfiles=$(find . -name test.nix) +nix-build -E "with import <nixpkgs> {}; callPackage testing/driver.nix { testFiles = [ $testfiles ]; }" --show-trace && cat result diff --git a/nixpkgs/pkgs/development/ruby-modules/solargraph/Gemfile b/nixpkgs/pkgs/development/ruby-modules/solargraph/Gemfile new file mode 100644 index 000000000000..fa41b7c1d216 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/solargraph/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' do + gem 'solargraph' +end diff --git a/nixpkgs/pkgs/development/ruby-modules/solargraph/Gemfile.lock b/nixpkgs/pkgs/development/ruby-modules/solargraph/Gemfile.lock new file mode 100644 index 000000000000..a936dd25d925 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/solargraph/Gemfile.lock @@ -0,0 +1,50 @@ +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.0) + eventmachine (1.2.7) + htmlentities (4.3.4) + jaro_winkler (1.5.1) + kramdown (1.17.0) + mini_portile2 (2.3.0) + nokogiri (1.8.5) + mini_portile2 (~> 2.3.0) + parallel (1.12.1) + parser (2.5.3.0) + ast (~> 2.4.0) + powerpack (0.1.2) + rainbow (3.0.0) + reverse_markdown (1.1.0) + nokogiri + rubocop (0.60.0) + jaro_winkler (~> 1.5.1) + parallel (~> 1.10) + parser (>= 2.5, != 2.5.1.1) + powerpack (~> 0.1) + rainbow (>= 2.2.2, < 4.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.4.0) + ruby-progressbar (1.10.0) + solargraph (0.29.1) + eventmachine (~> 1.2, >= 1.2.5) + htmlentities (~> 4.3, >= 4.3.4) + kramdown (~> 1.16) + parser (~> 2.3) + reverse_markdown (~> 1.0, >= 1.0.5) + rubocop (~> 0.52) + thor (~> 0.19, >= 0.19.4) + tilt (~> 2.0) + yard (~> 0.9) + thor (0.20.3) + tilt (2.0.9) + unicode-display_width (1.4.0) + yard (0.9.16) + +PLATFORMS + ruby + +DEPENDENCIES + solargraph! + +BUNDLED WITH + 1.17.1 diff --git a/nixpkgs/pkgs/development/ruby-modules/solargraph/default.nix b/nixpkgs/pkgs/development/ruby-modules/solargraph/default.nix new file mode 100644 index 000000000000..2f60dacd358b --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/solargraph/default.nix @@ -0,0 +1,15 @@ +{ lib, bundlerApp }: + +bundlerApp rec { + pname = "solargraph"; + exes = ["solargraph" "solargraph-runtime"]; + gemdir = ./.; + + meta = with lib; { + description = "IDE tools for the Ruby language"; + homepage = http://www.github.com/castwide/solargraph; + license = licenses.mit; + maintainers = with maintainers; [ worldofpeace ]; + platforms = platforms.unix; + }; +} diff --git a/nixpkgs/pkgs/development/ruby-modules/solargraph/gemset.nix b/nixpkgs/pkgs/development/ruby-modules/solargraph/gemset.nix new file mode 100644 index 000000000000..bfb5496444af --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/solargraph/gemset.nix @@ -0,0 +1,159 @@ +{ + ast = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "184ssy3w93nkajlz2c70ifm79jp3j737294kbc5fjw69v1w0n9x7"; + type = "gem"; + }; + version = "2.4.0"; + }; + eventmachine = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0wh9aqb0skz80fhfn66lbpr4f86ya2z5rx6gm5xlfhd05bj1ch4r"; + type = "gem"; + }; + version = "1.2.7"; + }; + htmlentities = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1nkklqsn8ir8wizzlakncfv42i32wc0w9hxp00hvdlgjr7376nhj"; + type = "gem"; + }; + version = "4.3.4"; + }; + jaro_winkler = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0rr797nqz081bfk30m2apj5h24bg5d1jr1c8p3xwx4hbwsrbclah"; + type = "gem"; + }; + version = "1.5.1"; + }; + kramdown = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1n1c4jmrh5ig8iv1rw81s4mw4xsp4v97hvf8zkigv4hn5h542qjq"; + type = "gem"; + }; + version = "1.17.0"; + }; + mini_portile2 = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "13d32jjadpjj6d2wdhkfpsmy68zjx90p49bgf8f7nkpz86r1fr11"; + type = "gem"; + }; + version = "2.3.0"; + }; + nokogiri = { + dependencies = ["mini_portile2"]; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0byyxrazkfm29ypcx5q4syrv126nvjnf7z6bqi01sqkv4llsi4qz"; + type = "gem"; + }; + version = "1.8.5"; + }; + parallel = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "01hj8v1qnyl5ndrs33g8ld8ibk0rbcqdpkpznr04gkbxd11pqn67"; + type = "gem"; + }; + version = "1.12.1"; + }; + parser = { + dependencies = ["ast"]; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1zjk0w1kjj3xk8ymy1430aa4gg0k8ckphfj88br6il4pm83f0n1f"; + type = "gem"; + }; + version = "2.5.3.0"; + }; + powerpack = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1r51d67wd467rpdfl6x43y84vwm8f5ql9l9m85ak1s2sp3nc5hyv"; + type = "gem"; + }; + version = "0.1.2"; + }; + rainbow = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0bb2fpjspydr6x0s8pn1pqkzmxszvkfapv0p4627mywl7ky4zkhk"; + type = "gem"; + }; + version = "3.0.0"; + }; + reverse_markdown = { + dependencies = ["nokogiri"]; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0w7y5n74daajvl9gixr91nh8670d7mkgspkk3ql71m8azq3nffbg"; + type = "gem"; + }; + version = "1.1.0"; + }; + rubocop = { + dependencies = ["jaro_winkler" "parallel" "parser" "powerpack" "rainbow" "ruby-progressbar" "unicode-display_width"]; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1ivk049z3mp12nc6v1wn35bsq1g7nz1i2r4xwzqf0v25hm2v7n1i"; + type = "gem"; + }; + version = "0.60.0"; + }; + ruby-progressbar = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1cv2ym3rl09svw8940ny67bav7b2db4ms39i4raaqzkf59jmhglk"; + type = "gem"; + }; + version = "1.10.0"; + }; + solargraph = { + dependencies = ["eventmachine" "htmlentities" "kramdown" "parser" "reverse_markdown" "rubocop" "thor" "tilt" "yard"]; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "12sy1rdz2fk3aba43701qp1250xm8w26rlizypd6h5rnmmqm5q54"; + type = "gem"; + }; + version = "0.29.1"; + }; + thor = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1yhrnp9x8qcy5vc7g438amd5j9sw83ih7c30dr6g6slgw9zj3g29"; + type = "gem"; + }; + version = "0.20.3"; + }; + tilt = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0ca4k0clwf0rkvy7726x4nxpjxkpv67w043i39saxgldxd97zmwz"; + type = "gem"; + }; + version = "2.0.9"; + }; + unicode-display_width = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0040bsdpcmvp8w31lqi2s9s4p4h031zv52401qidmh25cgyh4a57"; + type = "gem"; + }; + version = "1.4.0"; + }; + yard = { + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0lmmr1839qgbb3zxfa7jf5mzy17yjl1yirwlgzdhws4452gqhn67"; + type = "gem"; + }; + version = "0.9.16"; + }; +} \ No newline at end of file diff --git a/nixpkgs/pkgs/development/ruby-modules/testing/assertions.nix b/nixpkgs/pkgs/development/ruby-modules/testing/assertions.nix new file mode 100644 index 000000000000..f28cfcd508d4 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/testing/assertions.nix @@ -0,0 +1,28 @@ +{ test, lib, ...}: +{ + equal = expected: actual: + if actual == expected then + (test.passed "= ${toString expected}") else + (test.failed ( + "expected '${toString expected}'(${builtins.typeOf expected})" + + " != "+ + "actual '${toString actual}'(${builtins.typeOf actual})" + )); + + beASet = actual: + if builtins.isAttrs actual then + (test.passed "is a set") else + (test.failed "is not a set, was ${builtins.typeOf actual}: ${toString actual}"); + + haveKeys = expected: actual: + if builtins.all + (ex: builtins.any (ac: ex == ac) (builtins.attrNames actual)) + expected then + (test.passed "has expected keys") else + (test.failed "keys differ: expected: [${lib.concatStringsSep ";" expected}] actual: [${lib.concatStringsSep ";" (builtins.attrNames actual)}]"); + + havePrefix = expected: actual: + if lib.hasPrefix expected actual then + (test.passed "has prefix '${expected}'") else + (test.failed "prefix '${expected}' not found in '${actual}'"); +} diff --git a/nixpkgs/pkgs/development/ruby-modules/testing/driver.nix b/nixpkgs/pkgs/development/ruby-modules/testing/driver.nix new file mode 100644 index 000000000000..65e7c8d4416d --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/testing/driver.nix @@ -0,0 +1,20 @@ +/* +Run with: +nix-build -E 'with import <nixpkgs> { }; callPackage ./test.nix {}' --show-trace; and cat result + +Confusingly, the ideal result ends with something like: +error: build of ‘/nix/store/3245f3dcl2wxjs4rci7n069zjlz8qg85-test-results.tap.drv’ failed +*/ +{ writeText, lib, callPackage, testFiles, stdenv, ruby }@defs: +let + testTools = rec { + test = import ./testing.nix; + stubs = import ./stubs.nix defs; + should = import ./assertions.nix { inherit test lib; }; + }; + + tap = import ./tap-support.nix; + + results = builtins.concatLists (map (file: callPackage file testTools) testFiles); +in + writeText "test-results.tap" (tap.output results) diff --git a/nixpkgs/pkgs/development/ruby-modules/testing/stubs.nix b/nixpkgs/pkgs/development/ruby-modules/testing/stubs.nix new file mode 100644 index 000000000000..aaab2f689602 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/testing/stubs.nix @@ -0,0 +1,30 @@ +{ stdenv, lib, ruby, callPackage, ... }: +let + mkDerivation = {name, ...}@argSet: + derivation { + inherit name; + text = (builtins.toJSON (lib.filterAttrs ( n: v: builtins.any (x: x == n) ["name" "system"]) argSet)); + builder = stdenv.shell; + args = [ "-c" "echo $(<$textPath) > $out"]; + system = stdenv.hostPlatform.system; + passAsFile = ["text"]; + }; + fetchurl = {url?"", urls ? [],...}: "fetchurl:${if urls == [] then url else builtins.head urls}"; + + stdenv' = stdenv // { + inherit mkDerivation; + stubbed = true; + }; + ruby' = ruby // { + stdenv = stdenv'; + stubbed = true; + }; +in + { + ruby = ruby'; + buildRubyGem = callPackage ../gem { + inherit fetchurl; + ruby = ruby'; + }; + stdenv = stdenv'; + } diff --git a/nixpkgs/pkgs/development/ruby-modules/testing/tap-support.nix b/nixpkgs/pkgs/development/ruby-modules/testing/tap-support.nix new file mode 100644 index 000000000000..74fcceebaa04 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/testing/tap-support.nix @@ -0,0 +1,21 @@ +with builtins; +let + withIndexes = list: genList (idx: (elemAt list idx) // {index = idx;}) (length list); + + testLine = report: "${okStr report} ${toString (report.index + 1)} ${report.description}" + testDirective report + testYaml report; + + # These are part of the TAP spec, not yet implemented. + #c.f. https://github.com/NixOS/nixpkgs/issues/27071 + testDirective = report: ""; + testYaml = report: ""; + + okStr = { result, ...}: if result == "pass" then "ok" else "not ok"; +in + { + output = reports: '' + TAP version 13 + 1..${toString (length reports)}'' + (foldl' (l: r: l + "\n" + r) "" (map testLine (withIndexes reports))) + '' + + # Finished at ${toString currentTime} + ''; + } diff --git a/nixpkgs/pkgs/development/ruby-modules/testing/testing.nix b/nixpkgs/pkgs/development/ruby-modules/testing/testing.nix new file mode 100644 index 000000000000..43d10fca0444 --- /dev/null +++ b/nixpkgs/pkgs/development/ruby-modules/testing/testing.nix @@ -0,0 +1,62 @@ +with builtins; +let + /* + underTest = { + x = { + a = 1; + b = "2"; + }; + }; + + tests = [ + (root: false) + { + x = [ + (set: true) + { + a = (a: a > 1); + b = (b: b == "3"); + } + ]; + } + ]; + + results = run "Examples" underTest tests; + */ + + passed = desc: { + result = "pass"; + description = desc; + }; + + failed = desc: { + result = "failed"; + description = desc; + }; + + prefixName = name: res: { + inherit (res) result; + description = "${name}: ${res.description}"; + }; + + run = name: under: tests: if isList tests then + (concatLists (map (run name under) tests)) + else if isAttrs tests then + (concatLists (map ( + subName: run (name + "." + subName) (if hasAttr subName under then getAttr subName under else "<MISSING!>") (getAttr subName tests) + ) (attrNames tests))) + else if isFunction tests then + let + res = tests under; + in + if isBool res then + [ + (prefixName name (if tests under then passed "passed" else failed "failed")) + ] + else + [ (prefixName name res) ] + else [ + failed (name ": not a function, list or set") + ]; +in + { inherit run passed failed; } |