From affcf9ba1ef419cb366af6f7482734b23b885c6b Mon Sep 17 00:00:00 2001 From: talyz Date: Tue, 3 Mar 2020 20:07:32 +0100 Subject: [PATCH] bundlerEnv: Add option to copy gem files instead of symlinking The way ruby loads gems and keeps track of their paths seems to not always work very well when the gems are accessed through symlinks. Ruby will then complain that the same files are loaded multiple times; it relies on the file's full path to determine whether the file is loaded or not. This adds an option to simply copy all gem files into the environment instead, which gets rid of this issue, but may instead result in major file duplication. --- .../ruby-modules/bundled-common/default.nix | 18 ++++++- .../ruby-modules/bundler-env/default.nix | 49 ++++++++++++------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/pkgs/development/ruby-modules/bundled-common/default.nix b/pkgs/development/ruby-modules/bundled-common/default.nix index 0812ff590a50..66f33f6e31f4 100644 --- a/pkgs/development/ruby-modules/bundled-common/default.nix +++ b/pkgs/development/ruby-modules/bundled-common/default.nix @@ -1,4 +1,4 @@ -{ stdenv, runCommand, ruby, lib +{ stdenv, runCommand, ruby, lib, rsync , defaultGemConfig, buildRubyGem, buildEnv , makeWrapper , bundler @@ -13,6 +13,7 @@ , lockfile ? null , gemset ? null , ruby ? defs.ruby +, copyGemFiles ? false # Copy gem files instead of symlinking , gemConfig ? defaultGemConfig , postBuild ? null , document ? [] @@ -96,7 +97,8 @@ let envPaths = lib.attrValues gems ++ lib.optional (!hasBundler) bundler; - basicEnv = buildEnv { + + basicEnvArgs = { inherit buildInputs ignoreCollisions; name = name'; @@ -154,5 +156,17 @@ let }; }; }; + + basicEnv = + if copyGemFiles then + runCommand name' basicEnvArgs '' + mkdir -p $out + for i in $paths; do + ${rsync}/bin/rsync -a $i/lib $out/ + done + eval "$postBuild" + '' + else + buildEnv basicEnvArgs; in basicEnv diff --git a/pkgs/development/ruby-modules/bundler-env/default.nix b/pkgs/development/ruby-modules/bundler-env/default.nix index 9e9ccb128cf9..d412d10102f7 100644 --- a/pkgs/development/ruby-modules/bundler-env/default.nix +++ b/pkgs/development/ruby-modules/bundler-env/default.nix @@ -1,4 +1,6 @@ -{ ruby, lib, callPackage, defaultGemConfig, buildEnv, bundler }@defs: +{ ruby, lib, callPackage, defaultGemConfig, buildEnv, runCommand +, bundler, rsync +}@defs: { name ? null , pname ? null @@ -8,6 +10,7 @@ , gemset ? null , groups ? ["default"] , ruby ? defs.ruby +, copyGemFiles ? false # Copy gem files instead of symlinking , gemConfig ? defaultGemConfig , postBuild ? null , document ? [] @@ -38,23 +41,35 @@ in if pname == null then basicEnv // { inherit name basicEnv; } else - (buildEnv { - inherit ignoreCollisions; + let + bundlerEnvArgs = { + inherit ignoreCollisions; - name = basicEnv.name; + name = basicEnv.name; - paths = envPaths; - pathsToLink = [ "/lib" ]; + paths = envPaths; + pathsToLink = [ "/lib" ]; - postBuild = genStubsScript { - inherit lib ruby bundler groups; - confFiles = basicEnv.confFiles; - binPaths = [ basicEnv.gems.${pname} ]; - } + lib.optionalString (postBuild != null) postBuild; + 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; - } // passthru; - }) + meta = { platforms = ruby.meta.platforms; } // meta; + passthru = basicEnv.passthru // { + inherit basicEnv; + inherit (basicEnv) env; + } // passthru; + }; + in + if copyGemFiles then + runCommand basicEnv.name bundlerEnvArgs '' + mkdir -p $out + for i in $paths; do + ${rsync}/bin/rsync -a $i/lib $out/ + done + eval "$postBuild" + '' + else + buildEnv bundlerEnvArgs