From 7aaee7a002fd8a8d0ed03b839a6867f8d2083fb5 Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Sun, 17 May 2015 12:39:34 -0700 Subject: RubyGems can only validate during chdir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since it turns out that Specification#validate only works correctly if the cwd is the directory that contains the gemspec, we now validate at the same time as we load the gemspec. At least then we’ve already had to chdir, so we can validate correctly. --- lib/bundler.rb | 17 +++++++++++------ lib/bundler/source/path.rb | 11 +---------- spec/bundler/dsl_spec.rb | 13 ------------- spec/install/gemfile/path_spec.rb | 23 +++++++++++++++++++++++ spec/support/builders.rb | 8 +++++--- 5 files changed, 40 insertions(+), 32 deletions(-) diff --git a/lib/bundler.rb b/lib/bundler.rb index 197e88c2..bf06bea4 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -341,27 +341,32 @@ module Bundler raise MarshalError, "#{e.class}: #{e.message}" end - def load_gemspec(file) + def load_gemspec(file, validate = false) @gemspec_cache ||= {} key = File.expand_path(file) - spec = ( @gemspec_cache[key] ||= load_gemspec_uncached(file) ) + @gemspec_cache[key] ||= load_gemspec_uncached(file, validate) # Protect against caching side-effected gemspecs by returning a # new instance each time. - spec.dup if spec + @gemspec_cache[key] if @gemspec_cache[key] end - def load_gemspec_uncached(file) + def load_gemspec_uncached(file, validate = false) path = Pathname.new(file) # Eval the gemspec from its parent directory, because some gemspecs # depend on "./" relative paths. SharedHelpers.chdir(path.dirname.to_s) do contents = path.read if contents[0..2] == "---" # YAML header - eval_yaml_gemspec(path, contents) + spec = eval_yaml_gemspec(path, contents) else - eval_gemspec(path, contents) + spec = eval_gemspec(path, contents) end + spec.validate if spec && validate + spec end + rescue Gem::InvalidSpecificationException => e + raise InvalidOption, "The gemspec at #{file} is not valid. " \ + "The validation error was '#{e.message}'" end def clear_gemspec_cache diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb index 6c2ed858..e586c60b 100644 --- a/lib/bundler/source/path.rb +++ b/lib/bundler/source/path.rb @@ -131,7 +131,7 @@ module Bundler if File.directory?(expanded_path) # We sort depth-first since `<<` will override the earlier-found specs Dir["#{expanded_path}/#{@glob}"].sort_by { |p| -p.split(File::SEPARATOR).size }.each do |file| - if spec = load_and_validate_gemspec(file) + if spec = Bundler.load_gemspec(file, :validate) spec.loaded_from = file.to_s spec.source = self index << spec @@ -219,15 +219,6 @@ module Bundler end end - def load_and_validate_gemspec(file) - spec = load_gemspec(file) - spec.validate - spec - rescue Gem::InvalidSpecificationException => e - raise InvalidOption, "The gemspec at #{file} is not valid. " \ - "The validation error was '#{e.message}'" - end - end end end diff --git a/spec/bundler/dsl_spec.rb b/spec/bundler/dsl_spec.rb index ca97d0c6..bb6388eb 100644 --- a/spec/bundler/dsl_spec.rb +++ b/spec/bundler/dsl_spec.rb @@ -188,17 +188,4 @@ describe Bundler::Dsl do end end - describe "#gemspec" do - it "errors on invalid specs" do - File.open(bundled_app("foo.gemspec"), "w") do |f| - f.write <<-G - Gem::Specification.new do |s| - s.name = "foo" - end - G - end - expect(Bundler).to receive(:default_gemfile).and_return(bundled_app("Gemfile")) - expect { subject.gemspec }.to raise_error(Bundler::InvalidOption).with_message(/missing value for attribute version/) - end - end end diff --git a/spec/install/gemfile/path_spec.rb b/spec/install/gemfile/path_spec.rb index 6ba40964..d754674e 100644 --- a/spec/install/gemfile/path_spec.rb +++ b/spec/install/gemfile/path_spec.rb @@ -126,6 +126,8 @@ describe "bundle install with explicit source paths" do Gem::Specification.new do |s| s.name = 'premailer' s.version = '1.0.0' + s.summary = 'Hi' + s.authors = 'Me' end G end @@ -139,6 +141,26 @@ describe "bundle install with explicit source paths" do should_be_installed "premailer 1.0.0" end + it "errors on invalid specs" do + build_lib "foo" + + gemspec = lib_path("foo-1.0").join("foo.gemspec").to_s + File.open(gemspec, "w") do |f| + f.write <<-G + Gem::Specification.new do |s| + s.name = "foo" + end + G + end + + install_gemfile <<-G, :expect_err => true + gem "foo", :path => "#{lib_path("foo-1.0")}" + G + + expect(out).to match(/missing value for attribute version/) + should_not_be_installed("foo 1.0") + end + it "supports gemspec syntax" do build_lib "foo", "1.0", :path => lib_path("foo") do |s| s.add_dependency "rack", "1.0" @@ -249,6 +271,7 @@ describe "bundle install with explicit source paths" do path "#{lib_path('foo-1.0')}" gem 'foo' G + should_be_installed "foo 1.0" bundle "exec foobar" expect(out).to eq("1.0") diff --git a/spec/support/builders.rb b/spec/support/builders.rb index 1a1c9167..4dbcb298 100644 --- a/spec/support/builders.rb +++ b/spec/support/builders.rb @@ -456,10 +456,12 @@ module Spec end def executables=(val) - Array(val).each do |file| - write "#{@spec.bindir}/#{file}", "require '#{@name}' ; puts #{@name.upcase}" - end @spec.executables = Array(val) + @spec.executables.each do |file| + executable = "#{@spec.bindir}/#{file}" + @spec.files << executable + write executable, "require '#{@name}' ; puts #{@name.upcase}" + end end def add_c_extension -- cgit v1.2.3