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