1# frozen_string_literal: true
2
3RSpec.shared_examples "bundle install --standalone" do
4  shared_examples "common functionality" do
5    it "still makes the gems available to normal bundler" do
6      args = expected_gems.map {|k, v| "#{k} #{v}" }
7      expect(the_bundle).to include_gems(*args)
8    end
9
10    it "generates a bundle/bundler/setup.rb" do
11      expect(bundled_app("bundle/bundler/setup.rb")).to exist
12    end
13
14    it "makes the gems available without bundler" do
15      testrb = String.new <<-RUBY
16        $:.unshift File.expand_path("bundle")
17        require "bundler/setup"
18
19      RUBY
20      expected_gems.each do |k, _|
21        testrb << "\nrequire \"#{k}\""
22        testrb << "\nputs #{k.upcase}"
23      end
24      Dir.chdir(bundled_app) do
25        ruby testrb, :no_lib => true
26      end
27
28      expect(out).to eq(expected_gems.values.join("\n"))
29    end
30
31    it "works on a different system" do
32      FileUtils.mv(bundled_app, "#{bundled_app}2")
33
34      testrb = String.new <<-RUBY
35        $:.unshift File.expand_path("bundle")
36        require "bundler/setup"
37
38      RUBY
39      expected_gems.each do |k, _|
40        testrb << "\nrequire \"#{k}\""
41        testrb << "\nputs #{k.upcase}"
42      end
43      Dir.chdir("#{bundled_app}2") do
44        ruby testrb, :no_lib => true
45      end
46
47      expect(out).to eq(expected_gems.values.join("\n"))
48    end
49  end
50
51  describe "with simple gems" do
52    before do
53      gemfile <<-G
54        source "file://#{gem_repo1}"
55        gem "rails"
56      G
57      bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true)
58    end
59
60    let(:expected_gems) do
61      {
62        "actionpack" => "2.3.2",
63        "rails" => "2.3.2",
64      }
65    end
66
67    include_examples "common functionality"
68  end
69
70  describe "with gems with native extension", :ruby_repo do
71    before do
72      install_gemfile <<-G, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true)
73        source "file://#{gem_repo1}"
74        gem "very_simple_binary"
75      G
76    end
77
78    it "generates a bundle/bundler/setup.rb with the proper paths", :rubygems => "2.4" do
79      expected_path = bundled_app("bundle/bundler/setup.rb")
80      extension_line = File.read(expected_path).each_line.find {|line| line.include? "/extensions/" }.strip
81      expect(extension_line).to start_with '$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/'
82      expect(extension_line).to end_with '/very_simple_binary-1.0"'
83    end
84  end
85
86  describe "with gem that has an invalid gemspec" do
87    before do
88      build_git "bar", :gemspec => false do |s|
89        s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0')
90        s.write "bar.gemspec", <<-G
91          lib = File.expand_path('../lib/', __FILE__)
92          $:.unshift lib unless $:.include?(lib)
93          require 'bar/version'
94
95          Gem::Specification.new do |s|
96            s.name        = 'bar'
97            s.version     = BAR_VERSION
98            s.summary     = 'Bar'
99            s.files       = Dir["lib/**/*.rb"]
100            s.author      = 'Anonymous'
101            s.require_path = [1,2]
102          end
103        G
104      end
105      install_gemfile <<-G, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true)
106        gem "bar", :git => "#{lib_path("bar-1.0")}"
107      G
108    end
109
110    it "outputs a helpful error message" do
111      expect(out).to include("You have one or more invalid gemspecs that need to be fixed.")
112      expect(out).to include("bar 1.0 has an invalid gemspec")
113    end
114  end
115
116  describe "with a combination of gems and git repos" do
117    before do
118      build_git "devise", "1.0"
119
120      gemfile <<-G
121        source "file://#{gem_repo1}"
122        gem "rails"
123        gem "devise", :git => "#{lib_path("devise-1.0")}"
124      G
125      bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true)
126    end
127
128    let(:expected_gems) do
129      {
130        "actionpack" => "2.3.2",
131        "devise" => "1.0",
132        "rails" => "2.3.2",
133      }
134    end
135
136    include_examples "common functionality"
137  end
138
139  describe "with groups" do
140    before do
141      build_git "devise", "1.0"
142
143      gemfile <<-G
144        source "file://#{gem_repo1}"
145        gem "rails"
146
147        group :test do
148          gem "rspec"
149          gem "rack-test"
150        end
151      G
152      bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true)
153    end
154
155    let(:expected_gems) do
156      {
157        "actionpack" => "2.3.2",
158        "rails" => "2.3.2",
159      }
160    end
161
162    include_examples "common functionality"
163
164    it "allows creating a standalone file with limited groups" do
165      bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => "default")
166
167      Dir.chdir(bundled_app) do
168        load_error_ruby <<-RUBY, "spec", :no_lib => true
169          $:.unshift File.expand_path("bundle")
170          require "bundler/setup"
171
172          require "actionpack"
173          puts ACTIONPACK
174          require "spec"
175        RUBY
176      end
177
178      expect(last_command.stdout).to eq("2.3.2")
179      expect(last_command.stderr).to eq("ZOMG LOAD ERROR")
180    end
181
182    it "allows --without to limit the groups used in a standalone" do
183      bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle"), :without => "test").merge(:standalone => true)
184
185      Dir.chdir(bundled_app) do
186        load_error_ruby <<-RUBY, "spec", :no_lib => true
187          $:.unshift File.expand_path("bundle")
188          require "bundler/setup"
189
190          require "actionpack"
191          puts ACTIONPACK
192          require "spec"
193        RUBY
194      end
195
196      expect(last_command.stdout).to eq("2.3.2")
197      expect(last_command.stderr).to eq("ZOMG LOAD ERROR")
198    end
199
200    it "allows --path to change the location of the standalone bundle", :bundler => "< 2" do
201      bundle! "install", forgotten_command_line_options(:path => "path/to/bundle").merge(:standalone => true)
202
203      Dir.chdir(bundled_app) do
204        ruby <<-RUBY, :no_lib => true
205          $:.unshift File.expand_path("path/to/bundle")
206          require "bundler/setup"
207
208          require "actionpack"
209          puts ACTIONPACK
210        RUBY
211      end
212
213      expect(last_command.stdout).to eq("2.3.2")
214    end
215
216    it "allows --path to change the location of the standalone bundle", :bundler => "2" do
217      bundle! "install", forgotten_command_line_options(:path => "path/to/bundle").merge(:standalone => true)
218      path = File.expand_path("path/to/bundle")
219
220      Dir.chdir(bundled_app) do
221        ruby <<-RUBY, :no_lib => true
222          $:.unshift File.expand_path(#{path.dump})
223          require "bundler/setup"
224
225          require "actionpack"
226          puts ACTIONPACK
227        RUBY
228      end
229
230      expect(last_command.stdout).to eq("2.3.2")
231    end
232
233    it "allows remembered --without to limit the groups used in a standalone" do
234      bundle! :install, forgotten_command_line_options(:without => "test")
235      bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true)
236
237      Dir.chdir(bundled_app) do
238        load_error_ruby <<-RUBY, "spec", :no_lib => true
239          $:.unshift File.expand_path("bundle")
240          require "bundler/setup"
241
242          require "actionpack"
243          puts ACTIONPACK
244          require "spec"
245        RUBY
246      end
247
248      expect(last_command.stdout).to eq("2.3.2")
249      expect(last_command.stderr).to eq("ZOMG LOAD ERROR")
250    end
251  end
252
253  describe "with gemcutter's dependency API" do
254    let(:source_uri) { "http://localgemserver.test" }
255
256    describe "simple gems" do
257      before do
258        gemfile <<-G
259          source "#{source_uri}"
260          gem "rails"
261        G
262        bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true, :artifice => "endpoint")
263      end
264
265      let(:expected_gems) do
266        {
267          "actionpack" => "2.3.2",
268          "rails" => "2.3.2",
269        }
270      end
271
272      include_examples "common functionality"
273    end
274  end
275
276  describe "with --binstubs", :bundler => "< 2" do
277    before do
278      gemfile <<-G
279        source "file://#{gem_repo1}"
280        gem "rails"
281      G
282      bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true, :binstubs => true)
283    end
284
285    let(:expected_gems) do
286      {
287        "actionpack" => "2.3.2",
288        "rails" => "2.3.2",
289      }
290    end
291
292    include_examples "common functionality"
293
294    it "creates stubs that use the standalone load path" do
295      Dir.chdir(bundled_app) do
296        expect(`bin/rails -v`.chomp).to eql "2.3.2"
297      end
298    end
299
300    it "creates stubs that can be executed from anywhere" do
301      require "tmpdir"
302      Dir.chdir(Dir.tmpdir) do
303        sys_exec!(%(#{bundled_app("bin/rails")} -v))
304        expect(out).to eq("2.3.2")
305      end
306    end
307
308    it "creates stubs that can be symlinked" do
309      pending "File.symlink is unsupported on Windows" if Bundler::WINDOWS
310
311      symlink_dir = tmp("symlink")
312      FileUtils.mkdir_p(symlink_dir)
313      symlink = File.join(symlink_dir, "rails")
314
315      File.symlink(bundled_app("bin/rails"), symlink)
316      sys_exec!("#{symlink} -v")
317      expect(out).to eq("2.3.2")
318    end
319
320    it "creates stubs with the correct load path" do
321      extension_line = File.read(bundled_app("bin/rails")).each_line.find {|line| line.include? "$:.unshift" }.strip
322      expect(extension_line).to eq %($:.unshift File.expand_path "../../bundle", path.realpath)
323    end
324  end
325end
326
327RSpec.describe "bundle install --standalone" do
328  include_examples("bundle install --standalone")
329end
330
331RSpec.describe "bundle install --standalone run in a subdirectory" do
332  before do
333    Dir.chdir(bundled_app("bob").tap(&:mkpath))
334  end
335
336  include_examples("bundle install --standalone")
337end
338