148 lines
3.7 KiB
Nix
148 lines
3.7 KiB
Nix
{ stdenv, runCommand, writeText, writeScriptBin, ruby, lib, callPackage
|
|
, gemFixes, fetchurl, fetchgit, buildRubyGem
|
|
}@defs:
|
|
|
|
# This is a work-in-progress.
|
|
# The idea is that his will replace load-ruby-env.nix,
|
|
# using (a patched) bundler to handle the entirety of the installation process.
|
|
|
|
{ name, gemset, gemfile, lockfile, 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;
|
|
};
|
|
|
|
fixSpec = attrs:
|
|
attrs // (fixes."${attrs.name}" or (const {})) attrs;
|
|
|
|
instantiate = (attrs:
|
|
let
|
|
withFixes = fixSpec attrs;
|
|
withSource = withFixes //
|
|
(if (lib.isDerivation withFixes.src || builtins.isString withFixes.src)
|
|
then { source = attrs.src; }
|
|
else { source = attrs.src; src = (fetchers."${attrs.src.type}" attrs); });
|
|
|
|
in
|
|
withSource
|
|
);
|
|
|
|
instantiated = lib.flip lib.mapAttrs (import gemset) (name: attrs:
|
|
instantiate (attrs // { inherit name; })
|
|
);
|
|
|
|
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 = writeScriptBin "json2rb" ''
|
|
#!${ruby}/bin/ruby
|
|
begin
|
|
require 'json'
|
|
rescue LoadError => ex
|
|
require 'json_pure'
|
|
end
|
|
|
|
puts JSON.parse(STDIN.read).inspect
|
|
'';
|
|
|
|
# dump the instantiated gemset as a ruby expression.
|
|
serializedGemset = runCommand "gemset.rb" { json = builtins.toJSON instantiated; } ''
|
|
printf '%s' "$json" | ${json2rb}/bin/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.
|
|
pureLockfile = runRuby "pureLockfile" { inherit sources; } ''
|
|
out = ENV['out']
|
|
paths = eval(File.read(ENV['sources']))
|
|
|
|
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
|
|
'';
|
|
|
|
in
|
|
|
|
stdenv.mkDerivation {
|
|
inherit name;
|
|
outputs = [
|
|
"out" # the installed libs/bins
|
|
"bundler" # supporting files for bundler
|
|
];
|
|
phases = [ "installPhase" "fixupPhase" ];
|
|
installPhase = ''
|
|
# Copy the Gemfile and Gemfile.lock
|
|
mkdir -p $bundler
|
|
BUNDLE_GEMFILE=$bundler/Gemfile
|
|
cp ${gemfile} $BUNDLE_GEMFILE
|
|
cp ${pureLockfile} $BUNDLE_GEMFILE.lock
|
|
|
|
export NIX_GEM_SOURCES=${sources}
|
|
|
|
export GEM_HOME=$out/${ruby.gemPath}
|
|
export GEM_PATH=$GEM_HOME
|
|
mkdir -p $GEM_HOME
|
|
|
|
bundler install
|
|
'';
|
|
passthru = {
|
|
inherit ruby;
|
|
};
|
|
}
|