summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2018-11-26 23:25:04 -0800
committerLamont Granquist <lamont@scriptkiddie.org>2018-11-27 10:01:51 -0800
commitc57afa039c9e09db061ce762c74aa23a05e2fa08 (patch)
tree6276d356747b9bd3209f85e078f19d22afb5e548
parentec4aa7e9e75a5e941c8a9d9414ca2a97f5a44916 (diff)
downloadchef-c57afa039c9e09db061ce762c74aa23a05e2fa08.tar.gz
gem_package provider supports --no-document and rubygems 3.x
should still maintain backcompat for rubygems < 2.0 for RHEL6 and other old platforms. Signed-off-by: Lamont Granquist <lamont@scriptkiddie.org>
-rw-r--r--lib/chef/provider/package/rubygems.rb54
-rw-r--r--spec/unit/provider/package/rubygems_spec.rb56
2 files changed, 85 insertions, 25 deletions
diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb
index d99dce8972..cd595e64f4 100644
--- a/lib/chef/provider/package/rubygems.rb
+++ b/lib/chef/provider/package/rubygems.rb
@@ -1,7 +1,7 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2008-2016, 2010-2017, Chef Software Inc.
+# Copyright:: Copyright 2008-2016, 2010-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -49,42 +49,44 @@ class Chef
DEFAULT_UNINSTALLER_OPTS = { ignore: true, executables: true }.freeze
- ##
# The paths where rubygems should search for installed gems.
# Implemented by subclasses.
def gem_paths
raise NotImplementedError
end
- ##
# A rubygems source index containing the list of gemspecs for all
# available gems in the gem installation.
# Implemented by subclasses
- # === Returns
- # Gem::SourceIndex
+ #
+ # @return [Gem::SourceIndex]
+ #
def gem_source_index
raise NotImplementedError
end
- ##
# A rubygems specification object containing the list of gemspecs for all
# available gems in the gem installation.
# Implemented by subclasses
# For rubygems >= 1.8.0
- # === Returns
- # Gem::Specification
+ #
+ # @return [Gem::Specification]
+ #
def gem_specification
raise NotImplementedError
end
- ##
+ def rubygems_version
+ raise NotImplementedError
+ end
+
# Lists the installed versions of +gem_name+, constrained by the
# version spec in +gem_dep+
- # === Arguments
- # Gem::Dependency +gem_dep+ is a Gem::Dependency object, its version
- # specification constrains which gems are returned.
- # === Returns
- # [Gem::Specification] an array of Gem::Specification objects
+ #
+ # @param gem_dep [Gem::Dependency] the version specification that constrains
+ # which gems are used.
+ # @return [Array<Gem::Specification>] an array of Gem::Specification objects
+ #
def installed_versions(gem_dep)
rubygems_version = Gem::Version.new(Gem::VERSION)
if rubygems_version >= Gem::Version.new("2.7")
@@ -266,6 +268,10 @@ class Chef
Gem::Specification
end
+ def rubygems_version
+ Gem::VERSION
+ end
+
def candidate_version_from_remote(gem_dependency, *sources)
with_gem_sources(*sources) do
find_newest_remote_version(gem_dependency, *sources)
@@ -293,6 +299,10 @@ class Chef
@gem_binary_location = gem_binary_location
end
+ def rubygems_version
+ @rubygems_version ||= shell_out!("#{@gem_binary_location} --version").stdout.chomp
+ end
+
def gem_paths
if self.class.gempath_cache.key?(@gem_binary_location)
self.class.gempath_cache[@gem_binary_location]
@@ -547,9 +557,9 @@ class Chef
end
src_str = src.empty? ? "" : " #{src.join(" ")}"
if !version.nil? && !version.empty?
- shell_out!("#{gem_binary_path} install #{name} -q --no-rdoc --no-ri -v \"#{version}\"#{src_str}#{opts}", env: nil)
+ shell_out!("#{gem_binary_path} install #{name} -q #{rdoc_string} -v \"#{version}\"#{src_str}#{opts}", env: nil)
else
- shell_out!("#{gem_binary_path} install \"#{name}\" -q --no-rdoc --no-ri #{src_str}#{opts}", env: nil)
+ shell_out!("#{gem_binary_path} install \"#{name}\" -q #{rdoc_string} #{src_str}#{opts}", env: nil)
end
end
@@ -585,6 +595,18 @@ class Chef
private
+ def rdoc_string
+ if needs_nodocument?
+ "--no-document"
+ else
+ "--no-rdoc --no-ri"
+ end
+ end
+
+ def needs_nodocument?
+ Gem::Requirement.new(">= 3.0.0.beta1").satisfied_by?(Gem::Version.new(gem_env.rubygems_version))
+ end
+
def opts
expand_options(new_resource.options)
end
diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb
index 2e9888fb78..1bafefe5e8 100644
--- a/spec/unit/provider/package/rubygems_spec.rb
+++ b/spec/unit/provider/package/rubygems_spec.rb
@@ -396,6 +396,10 @@ describe Chef::Provider::Package::Rubygems do
allow(RbConfig::CONFIG).to receive(:[]).with("arch").and_call_original
allow(File).to receive(:executable?).and_return false
allow(File).to receive(:executable?).with("#{bindir}/gem").and_return true
+ # XXX: we can't stub the provider object directly here because referencing it will create it and that
+ # will break later tests that want to test the initialize method, so we stub any instance
+ # (yet more evidence that initialize methods should be thin and do very little work)
+ allow_any_instance_of(Chef::Provider::Package::Rubygems).to receive(:needs_nodocument?).and_return true
end
describe "when new_resource version is nil" do
@@ -696,7 +700,25 @@ describe Chef::Provider::Package::Rubygems do
let(:options) { "-i /alt/install/location" }
it "installs the gem by shelling out when options are provided as a String" do
+ expected = "gem install rspec-core -q --no-document -v \"#{target_version}\" --source=https://www.rubygems.org #{options}"
+ expect(provider).to receive(:shell_out_compacted!).with(expected, env: nil, timeout: 900)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "unmockening needs_nodocument?" do
+ expected = "gem install rspec-core -q --no-document -v \"#{target_version}\" --source=https://www.rubygems.org #{options}"
+ expect(provider).to receive(:needs_nodocument?).and_call_original
+ stub_const("Gem::VERSION", "3.0.0")
+ expect(provider).to receive(:shell_out_compacted!).with(expected, env: nil, timeout: 900)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "when the rubygems_version is old it uses the old flags" do
expected = "gem install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --source=https://www.rubygems.org #{options}"
+ expect(provider).to receive(:needs_nodocument?).and_call_original
+ stub_const("Gem::VERSION", "2.8.0")
expect(provider).to receive(:shell_out_compacted!).with(expected, env: nil, timeout: 900)
provider.run_action(:install)
expect(new_resource).to be_updated_by_last_action
@@ -709,7 +731,7 @@ describe Chef::Provider::Package::Rubygems do
it "installs the gem with rubygems.org as an added source" do
Chef::Config[:rubygems_url] = "https://mirror1"
expect(provider.gem_env).to receive(:candidate_version_from_remote).with(gem_dep, Chef::Config[:rubygems_url]).and_return(version)
- expected = "#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --source=https://mirror1"
+ expected = "#{gem_binary} install rspec-core -q --no-document -v \"#{target_version}\" --source=https://mirror1"
expect(provider).to receive(:shell_out_compacted!).with(expected, env: nil, timeout: 900)
provider.run_action(:install)
expect(new_resource).to be_updated_by_last_action
@@ -721,7 +743,7 @@ describe Chef::Provider::Package::Rubygems do
let(:gem_binary) { "/foo/bar" }
it "installs the gem with rubygems.org as an added source" do
- expected = "#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --source=#{source} --source=https://www.rubygems.org"
+ expected = "#{gem_binary} install rspec-core -q --no-document -v \"#{target_version}\" --source=#{source} --source=https://www.rubygems.org"
expect(provider).to receive(:shell_out_compacted!).with(expected, env: nil, timeout: 900)
provider.run_action(:install)
expect(new_resource).to be_updated_by_last_action
@@ -732,7 +754,7 @@ describe Chef::Provider::Package::Rubygems do
it "ignores the Chef::Config setting" do
Chef::Config[:rubygems_url] = "https://ignored"
- expected = "#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --source=#{source}"
+ expected = "#{gem_binary} install rspec-core -q --no-document -v \"#{target_version}\" --source=#{source}"
expect(provider).to receive(:shell_out_compacted!).with(expected, env: nil, timeout: 900)
provider.run_action(:install)
expect(new_resource).to be_updated_by_last_action
@@ -745,7 +767,7 @@ describe Chef::Provider::Package::Rubygems do
let(:gem_binary) { "/foo/bar" }
it "installs the gem with an array as an added source" do
- expected = "#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --source=https://mirror1 --source=https://mirror2 --source=https://www.rubygems.org"
+ expected = "#{gem_binary} install rspec-core -q --no-document -v \"#{target_version}\" --source=https://mirror1 --source=https://mirror2 --source=https://www.rubygems.org"
expect(provider).to receive(:shell_out_compacted!).with(expected, env: nil, timeout: 900)
provider.run_action(:install)
expect(new_resource).to be_updated_by_last_action
@@ -756,7 +778,7 @@ describe Chef::Provider::Package::Rubygems do
it "ignores the Chef::Config setting" do
Chef::Config[:rubygems_url] = "https://ignored"
- expected = "#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --source=https://mirror1 --source=https://mirror2"
+ expected = "#{gem_binary} install rspec-core -q --no-document -v \"#{target_version}\" --source=https://mirror1 --source=https://mirror2"
expect(provider).to receive(:shell_out_compacted!).with(expected, env: nil, timeout: 900)
provider.run_action(:install)
expect(new_resource).to be_updated_by_last_action
@@ -770,7 +792,7 @@ describe Chef::Provider::Package::Rubygems do
it "installs the gem" do
new_resource.clear_sources(true)
- expected = "#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --clear-sources --source=#{source} --source=https://www.rubygems.org"
+ expected = "#{gem_binary} install rspec-core -q --no-document -v \"#{target_version}\" --clear-sources --source=#{source} --source=https://www.rubygems.org"
expect(provider).to receive(:shell_out_compacted!).with(expected, env: nil, timeout: 900)
provider.run_action(:install)
expect(new_resource).to be_updated_by_last_action
@@ -782,7 +804,7 @@ describe Chef::Provider::Package::Rubygems do
let(:options) { "-i /alt/install/location" }
it "installs the gem by shelling out when options are provided but no version is given" do
- expected = "gem install rspec-core -q --no-rdoc --no-ri -v \"#{candidate_version}\" --source=https://www.rubygems.org #{options}"
+ expected = "gem install rspec-core -q --no-document -v \"#{candidate_version}\" --source=https://www.rubygems.org #{options}"
expect(provider).to receive(:shell_out_compacted!).with(expected, env: nil, timeout: 900)
provider.run_action(:install)
expect(new_resource).to be_updated_by_last_action
@@ -846,6 +868,22 @@ describe Chef::Provider::Package::Rubygems do
let(:gem_binary) { "/usr/weird/bin/gem" }
it "installs the gem by shelling out to gem install" do
+ expect(provider).to receive(:shell_out_compacted!).with("#{gem_binary} install rspec-core -q --no-document -v \"#{target_version}\" --source=https://www.rubygems.org", env: nil, timeout: 900)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "unmockening needs_nodocument?" do
+ expect(provider).to receive(:needs_nodocument?).and_call_original
+ expect(provider.gem_env).to receive(:shell_out!).with("#{gem_binary} --version").and_return(instance_double(Mixlib::ShellOut, stdout: "3.0.0\n"))
+ expect(provider).to receive(:shell_out_compacted!).with("#{gem_binary} install rspec-core -q --no-document -v \"#{target_version}\" --source=https://www.rubygems.org", env: nil, timeout: 900)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "when the rubygems_version is old it uses the old flags" do
+ expect(provider).to receive(:needs_nodocument?).and_call_original
+ expect(provider.gem_env).to receive(:shell_out!).with("#{gem_binary} --version").and_return(instance_double(Mixlib::ShellOut, stdout: "2.8.0\n"))
expect(provider).to receive(:shell_out_compacted!).with("#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --source=https://www.rubygems.org", env: nil, timeout: 900)
provider.run_action(:install)
expect(new_resource).to be_updated_by_last_action
@@ -856,7 +894,7 @@ describe Chef::Provider::Package::Rubygems do
let(:target_version) { ">= 0" }
it "installs the gem by shelling out to gem install" do
- expect(provider).to receive(:shell_out_compacted!).with("#{gem_binary} install #{source} -q --no-rdoc --no-ri -v \"#{target_version}\"", env: nil, timeout: 900)
+ expect(provider).to receive(:shell_out_compacted!).with("#{gem_binary} install #{source} -q --no-document -v \"#{target_version}\"", env: nil, timeout: 900)
provider.run_action(:install)
expect(new_resource).to be_updated_by_last_action
end
@@ -868,7 +906,7 @@ describe Chef::Provider::Package::Rubygems do
it "installs the gem from file by shelling out to gem install when the package is a path and the source is nil" do
expect(new_resource.source).to eq(gem_name)
- expect(provider).to receive(:shell_out_compacted!).with("#{gem_binary} install #{gem_name} -q --no-rdoc --no-ri -v \"#{target_version}\"", env: nil, timeout: 900)
+ expect(provider).to receive(:shell_out_compacted!).with("#{gem_binary} install #{gem_name} -q --no-document -v \"#{target_version}\"", env: nil, timeout: 900)
provider.run_action(:install)
expect(new_resource).to be_updated_by_last_action
end