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.
This commit is contained in:
talyz 2020-03-03 20:07:32 +01:00 committed by Milan
parent 17721d3b33
commit affcf9ba1e
2 changed files with 48 additions and 19 deletions

View file

@ -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

View file

@ -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