1require 'rbconfig'
2require 'bundler/vendored_thor'
3require 'bundler'
4require 'rubygems/command'
5require 'fileutils'
6require 'pathname'
7require 'tmpdir'
8
9# Options:
10#
11# name - the gem name
12# uri - git repo uri
13# repo - path to local checkout
14# ref - the commit hash
15# version - gem version
16# build-flags - build arguments
17
18ruby = File.join(ENV["ruby"], "bin", RbConfig::CONFIG['ruby_install_name'])
19out = ENV["out"]
20bin_dir = File.join(ENV["out"], "bin")
21
22name = ARGV[0]
23uri = ARGV[1]
24REPO = ARGV[2]
25ref = ARGV[3]
26version = ARGV[4]
27build_flags = ARGV[5]
28
29# options to pass to bundler
30options = {
31 "name" => name,
32 "uri" => uri,
33 "ref" => ref,
34 "version" => version,
35}
36
37# Monkey-patch Bundler to use our local checkout.
38# I wish we didn't have to do this, but bundler does not expose an API to do
39# these kinds of things.
40Bundler.module_eval do
41 def self.requires_sudo?
42 false
43 end
44
45 def self.root
46 # we don't have a Gemfile, so it doesn't make sense to try to make paths
47 # relative to the (non existent) parent directory thereof, so we give a
48 # nonsense path here.
49 Pathname.new("/no-root-path")
50 end
51
52 def self.bundle_path
53 Pathname.new(ENV["GEM_HOME"])
54 end
55
56 def self.locked_gems
57 nil
58 end
59end
60
61Bundler::Source::Git.class_eval do
62 def allow_git_ops?
63 true
64 end
65end
66
67Bundler::Source::Git::GitProxy.class_eval do
68 def checkout
69 unless path.exist?
70 FileUtils.mkdir_p(path.dirname)
71 FileUtils.cp_r(File.join(REPO, ".git"), path)
72 system("chmod -R +w #{path}")
73 end
74 end
75
76 def copy_to(destination, submodules=false)
77 unless File.exist?(destination.join(".git"))
78 FileUtils.mkdir_p(destination.dirname)
79 FileUtils.cp_r(REPO, destination)
80 system("chmod -R +w #{destination}")
81 end
82 end
83end
84
85# UI
86verbose = false
87no_color = false
88Bundler.ui = Bundler::UI::Shell.new({"no-color" => no_color})
89Bundler.ui.level = "debug" if verbose
90
91# Install
92source = Bundler::Source::Git.new(options)
93spec = source.specs.search_all(name).first
94Bundler.rubygems.with_build_args [build_flags] do
95 source.install(spec)
96end
97
98msg = spec.post_install_message
99if msg
100 Bundler.ui.confirm "Post-install message from #{name}:"
101 Bundler.ui.info msg
102end
103
104# Write out the binstubs
105if spec.executables.any?
106 FileUtils.mkdir_p(bin_dir)
107 spec.executables.each do |exe|
108 wrapper = File.join(bin_dir, exe)
109 File.open(wrapper, "w") do |f|
110 f.write(<<-EOF)
111#!#{ruby}
112#
113# This file was generated by Nix.
114#
115# The application '#{exe}' is installed as part of a gem, and
116# this file is here to facilitate running it.
117#
118
119require 'rubygems'
120require 'bundler/setup'
121
122load Gem.bin_path(#{spec.name.inspect}, #{exe.inspect})
123EOF
124 end
125
126 FileUtils.chmod("+x", wrapper)
127 end
128end
129
130# Write out metadata
131meta = "#{out}/nix-support/gem-meta"
132FileUtils.mkdir_p(meta)
133FileUtils.ln_s(spec.loaded_from.to_s, "#{meta}/spec")
134File.open("#{meta}/name", "w") do |f|
135 f.write spec.name
136end
137File.open("#{meta}/install-path", "w") do |f|
138 f.write source.install_path.to_s
139end
140File.open("#{meta}/require-paths", "w") do |f|
141 f.write spec.require_paths.join(" ")
142end
143File.open("#{meta}/executables", "w") do |f|
144 f.write spec.executables.join(" ")
145end
146
147# make the lib available during bundler/git installs
148File.open("#{out}/nix-support/setup-hook", "a") do |f|
149 spec.require_paths.each do |dir|
150 f.puts("addToSearchPath RUBYLIB #{source.install_path}/#{dir}")
151 end
152end