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