summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--lib/rubygems/commands/query_command.rb184
-rw-r--r--lib/rubygems/specification.rb1
-rw-r--r--lib/rubygems/test_case.rb15
-rw-r--r--lib/rubygems/uninstaller.rb16
-rw-r--r--test/rubygems/test_gem_commands_query_command.rb44
-rw-r--r--test/rubygems/test_gem_commands_uninstall_command.rb18
-rw-r--r--test/rubygems/test_gem_uninstaller.rb61
8 files changed, 236 insertions, 119 deletions
diff --git a/ChangeLog b/ChangeLog
index 69240c4d2c..28a8894733 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+Wed Dec 19 16:18:22 2012 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/commands/query_command.rb: Refactored to improve
+ maintainability.
+ * test/rubygems/test_gem_commands_query_command.rb: Note default gems
+ in gem list details.
+
+ * lib/rubygems/uninstaller.rb: Detect all gems for uninstallation.
+ This allows duplicate installs of default gems to be removed.
+ * lib/rubygems/specification.rb: Allow use of ::each_spec.
+ * lib/rubygems/test_case.rb: Added install_default_gems.
+ * test/rubygems/test_gem_commands_uninstall_command.rb: Moved test
+ down to the uninstaller tests.
+ * test/rubygems/test_gem_uninstaller.rb: Test for uninstallation of
+ default gems and duplicate default gems.
+
Wed Dec 19 15:23:50 2012 Eric Hodel <drbrain@segment7.net>
* doc/syntax/methods.rdoc: Add () around keyword arguments example for
diff --git a/lib/rubygems/commands/query_command.rb b/lib/rubygems/commands/query_command.rb
index 020bc297b4..0ae7924564 100644
--- a/lib/rubygems/commands/query_command.rb
+++ b/lib/rubygems/commands/query_command.rb
@@ -162,12 +162,18 @@ class Gem::Commands::QueryCommand < Gem::Command
n.downcase
end
+ output_versions output, versions
+
+ say output.join(options[:details] ? "\n\n" : "\n")
+ end
+
+ def output_versions output, versions
versions.each do |gem_name, matching_tuples|
matching_tuples = matching_tuples.sort_by { |n,_| n.version }.reverse
platforms = Hash.new { |h,version| h[version] = [] }
- matching_tuples.map do |n,_|
+ matching_tuples.each do |n, _|
platforms[n.version] << n.platform if n.platform
end
@@ -182,97 +188,125 @@ class Gem::Commands::QueryCommand < Gem::Command
end
end
- entry = gem_name.dup
-
- if options[:versions] then
- list = if platforms.empty? or options[:details] then
- matching_tuples.map { |n,_| n.version }.uniq
- else
- platforms.sort.reverse.map do |version, pls|
- if pls == [Gem::Platform::RUBY] then
- version
- else
- ruby = pls.delete Gem::Platform::RUBY
- platform_list = [ruby, *pls.sort].compact
- "#{version} #{platform_list.join ' '}"
- end
- end
- end.join ', '
-
- entry << " (#{list})"
- end
-
- if options[:details] then
- detail_tuple = matching_tuples.first
+ output << make_entry(matching_tuples, platforms)
+ end
+ end
- spec = detail_tuple.last
+ def entry_details entry, spec, specs, platforms
+ return unless options[:details]
- unless spec.kind_of? Gem::Specification
- spec = spec.fetch_spec detail_tuple.first
- end
+ entry << "\n"
- entry << "\n"
+ spec_platforms entry, platforms
+ spec_authors entry, spec
+ spec_homepage entry, spec
+ spec_license entry, spec
+ spec_loaded_from entry, spec, specs
+ spec_summary entry, spec
+ end
- non_ruby = platforms.any? do |_, pls|
- pls.any? { |pl| pl != Gem::Platform::RUBY }
- end
+ def entry_versions entry, name_tuples, platforms
+ return unless options[:versions]
- if non_ruby then
- if platforms.length == 1 then
- title = platforms.values.length == 1 ? 'Platform' : 'Platforms'
- entry << " #{title}: #{platforms.values.sort.join ', '}\n"
+ list =
+ if platforms.empty? or options[:details] then
+ name_tuples.map { |n| n.version }.uniq
+ else
+ platforms.sort.reverse.map do |version, pls|
+ if pls == [Gem::Platform::RUBY] then
+ version
else
- entry << " Platforms:\n"
- platforms.sort_by do |version,|
- version
- end.each do |version, pls|
- label = " #{version}: "
- data = format_text pls.sort.join(', '), 68, label.length
- data[0, label.length] = label
- entry << data << "\n"
- end
+ ruby = pls.delete Gem::Platform::RUBY
+ platform_list = [ruby, *pls.sort].compact
+ "#{version} #{platform_list.join ' '}"
end
end
+ end
- authors = "Author#{spec.authors.length > 1 ? 's' : ''}: "
- authors << spec.authors.join(', ')
- entry << format_text(authors, 68, 4)
+ entry << " (#{list.join ', '})"
+ end
- if spec.rubyforge_project and not spec.rubyforge_project.empty? then
- rubyforge = "Rubyforge: http://rubyforge.org/projects/#{spec.rubyforge_project}"
- entry << "\n" << format_text(rubyforge, 68, 4)
- end
+ def make_entry entry_tuples, platforms
+ detail_tuple = entry_tuples.first
+ name_tuple, latest_spec = detail_tuple
- if spec.homepage and not spec.homepage.empty? then
- entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4)
- end
+ latest_spec = latest_spec.fetch_spec name_tuple unless
+ Gem::Specification === latest_spec
- if spec.license and not spec.license.empty? then
- licenses = "License#{spec.licenses.length > 1 ? 's' : ''}: "
- licenses << spec.licenses.join(', ')
- entry << "\n" << format_text(licenses, 68, 4)
- end
+ name_tuples, specs = entry_tuples.flatten.partition do |item|
+ Gem::NameTuple === item
+ end
- if spec.loaded_from then
- if matching_tuples.length == 1 then
- loaded_from = File.dirname File.dirname(spec.loaded_from)
- entry << "\n" << " Installed at: #{loaded_from}"
- else
- label = 'Installed at'
- matching_tuples.each do |n,s|
- loaded_from = File.dirname File.dirname(s.loaded_from)
- entry << "\n" << " #{label} (#{n.version}): #{loaded_from}"
- label = ' ' * label.length
- end
- end
- end
+ entry = [latest_spec.name]
+
+ entry_versions entry, name_tuples, platforms
+ entry_details entry, latest_spec, specs, platforms
+
+ entry.join
+ end
+
+ def spec_authors entry, spec
+ authors = "Author#{spec.authors.length > 1 ? 's' : ''}: "
+ authors << spec.authors.join(', ')
+ entry << format_text(authors, 68, 4)
+ end
+
+ def spec_homepage entry, spec
+ return if spec.homepage.nil? or spec.homepage.empty?
+
+ entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4)
+ end
+
+ def spec_license entry, spec
+ return if spec.license.nil? or spec.license.empty?
- entry << "\n\n" << format_text(spec.summary, 68, 4)
+ licenses = "License#{spec.licenses.length > 1 ? 's' : ''}: "
+ licenses << spec.licenses.join(', ')
+ entry << "\n" << format_text(licenses, 68, 4)
+ end
+
+ def spec_loaded_from entry, spec, specs
+ return unless spec.loaded_from
+
+ if specs.length == 1 then
+ default = spec.default_gem? ? ' (default)' : nil
+ entry << "\n" << " Installed at#{default}: #{spec.base_dir}"
+ else
+ label = 'Installed at'
+ specs.each do |s|
+ version = s.version.to_s
+ version << ', default' if s.default_gem?
+ entry << "\n" << " #{label} (#{version}): #{s.base_dir}"
+ label = ' ' * label.length
end
- output << entry
end
+ end
- say output.join(options[:details] ? "\n\n" : "\n")
+ def spec_platforms entry, platforms
+ non_ruby = platforms.any? do |_, pls|
+ pls.any? { |pl| pl != Gem::Platform::RUBY }
+ end
+
+ return unless non_ruby
+
+ if platforms.length == 1 then
+ title = platforms.values.length == 1 ? 'Platform' : 'Platforms'
+ entry << " #{title}: #{platforms.values.sort.join ', '}\n"
+ else
+ entry << " Platforms:\n"
+ platforms.sort_by do |version,|
+ version
+ end.each do |version, pls|
+ label = " #{version}: "
+ data = format_text pls.sort.join(', '), 68, label.length
+ data[0, label.length] = label
+ entry << data << "\n"
+ end
+ end
+ end
+
+ def spec_summary entry, spec
+ entry << "\n\n" << format_text(spec.summary, 68, 4)
end
end
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index 0b349bccc7..2c8b73a76b 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -622,7 +622,6 @@ class Gem::Specification
File.join(Gem.default_dir, "specifications", "default")
end
- private
def each_spec(search_dirs) # :nodoc:
search_dirs.each { |dir|
Dir[File.join(dir, "*.gemspec")].each { |path|
diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb
index a652cecf2a..a04c733ccf 100644
--- a/lib/rubygems/test_case.rb
+++ b/lib/rubygems/test_case.rb
@@ -466,6 +466,19 @@ class Gem::TestCase < MiniTest::Unit::TestCase
end
##
+ # Installs the provided default specs including writing the spec file
+
+ def install_default_gems(*specs)
+ install_default_specs(*specs)
+
+ specs.each do |spec|
+ open spec.loaded_from, 'w' do |io|
+ io.write spec.to_ruby_for_cache
+ end
+ end
+ end
+
+ ##
# Install the provided default specs
def install_default_specs(*specs)
@@ -572,7 +585,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
block = proc do |s|
# Since Hash#each is unordered in 1.8, sort
# the keys and iterate that way so the tests are
- # deteriminstic on all implementations.
+ # deterministic on all implementations.
deps.keys.sort.each do |n|
s.add_dependency n, (deps[n] || '>= 0')
end
diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb
index 475211dfe3..d672b9dec1 100644
--- a/lib/rubygems/uninstaller.rb
+++ b/lib/rubygems/uninstaller.rb
@@ -72,7 +72,19 @@ class Gem::Uninstaller
# directory, and the cached .gem file.
def uninstall
- list = Gem::Specification.find_all_by_name(@gem, @version)
+ dependency = Gem::Dependency.new @gem, @version
+
+ list = []
+
+ dirs =
+ Gem::Specification.dirs +
+ [Gem::Specification.default_specifications_dir]
+
+ Gem::Specification.each_spec dirs do |spec|
+ next unless dependency.matches_spec? spec
+
+ list << spec
+ end
default_specs, list = list.partition do |spec|
spec.default_gem?
@@ -80,7 +92,7 @@ class Gem::Uninstaller
list, other_repo_specs = list.partition do |spec|
@gem_home == spec.base_dir or
- (@user_install and spec.base_dir == Gem.user_dir)
+ (@user_install and spec.base_dir == Gem.user_dir)
end
if list.empty? then
diff --git a/test/rubygems/test_gem_commands_query_command.rb b/test/rubygems/test_gem_commands_query_command.rb
index 8ff62b4217..09e6efcd07 100644
--- a/test/rubygems/test_gem_commands_query_command.rb
+++ b/test/rubygems/test_gem_commands_query_command.rb
@@ -106,7 +106,6 @@ pl (1 i386-linux)
@a2.summary = 'This is a lot of text. ' * 4
@a2.authors = ['Abraham Lincoln', 'Hirohito']
@a2.homepage = 'http://a.example.com/'
- @a2.rubyforge_project = 'rubygems'
util_clear_gems
util_setup_spec_fetcher @a1, @a2, @pl1
@@ -123,7 +122,6 @@ pl (1 i386-linux)
a (2)
Authors: Abraham Lincoln, Hirohito
- Rubyforge: http://rubyforge.org/projects/rubygems
Homepage: http://a.example.com/
This is a lot of text. This is a lot of text. This is a lot of text.
@@ -147,7 +145,6 @@ pl (1)
@a2.summary = 'This is a lot of text. ' * 4
@a2.authors = ['Abraham Lincoln', 'Hirohito']
@a2.homepage = 'http://a.example.com/'
- @a2.rubyforge_project = 'rubygems'
@a2.platform = 'universal-darwin'
util_clear_gems
@@ -168,7 +165,6 @@ a (2, 1)
1: x86-linux
2: universal-darwin
Authors: Abraham Lincoln, Hirohito
- Rubyforge: http://rubyforge.org/projects/rubygems
Homepage: http://a.example.com/
This is a lot of text. This is a lot of text. This is a lot of text.
@@ -355,7 +351,6 @@ pl (1 i386-linux)
@a2.summary = 'This is a lot of text. ' * 4
@a2.authors = ['Abraham Lincoln', 'Hirohito']
@a2.homepage = 'http://a.example.com/'
- @a2.rubyforge_project = 'rubygems'
@a2.platform = 'universal-darwin'
util_clear_gems
@@ -380,7 +375,6 @@ a (2, 1)
1: x86-linux
2: universal-darwin
Authors: Abraham Lincoln, Hirohito
- Rubyforge: http://rubyforge.org/projects/rubygems
Homepage: http://a.example.com/
Installed at -
-
@@ -400,5 +394,43 @@ pl \(1\)
assert_match expected, @ui.output
end
+ def test_execute_default_details
+ default_gem_dir = Gem::Specification.default_specifications_dir
+ @a1.loaded_from =
+ File.join default_gem_dir, @a1.spec_name
+
+ @cmd.handle_options %w[-l -d]
+
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ str = @ui.output
+
+ expected = <<-EOF
+
+*** LOCAL GEMS ***
+
+a (3.a, 2, 1)
+ Author: A User
+ Homepage: http://example.com
+ Installed at (3.a): #{@gemhome}
+ (2): #{@gemhome}
+ (1, default): #{@a1.base_dir}
+
+ this is a summary
+
+pl \(1\)
+ Platform: i386-linux
+ Author: A User
+ Homepage: http://example.com
+ Installed at: #{@gemhome}
+
+ this is a summary
+ EOF
+
+ assert_equal expected, @ui.output
+ end
+
end
diff --git a/test/rubygems/test_gem_commands_uninstall_command.rb b/test/rubygems/test_gem_commands_uninstall_command.rb
index 964ce85cc3..844c7b4b97 100644
--- a/test/rubygems/test_gem_commands_uninstall_command.rb
+++ b/test/rubygems/test_gem_commands_uninstall_command.rb
@@ -175,23 +175,5 @@ class TestGemCommandsUninstallCommand < Gem::InstallerTestCase
assert Gem::Specification.find_all_by_name('x').length == 0
end
- def test_execute_default_gem
- default_gem_spec = new_default_spec("default", "2.0.0.0",
- nil, "default/gem.rb")
- install_default_specs(default_gem_spec)
-
- ui = Gem::MockGemUi.new
-
- @cmd.options[:args] = %w[default]
- @cmd.options[:executables] = true
-
- use_ui ui do
- e = assert_raises Gem::InstallError do
- @cmd.execute
- end
- assert_equal "gem \"default\" cannot be uninstalled because it is a default gem",
- e.message
- end
- end
end
diff --git a/test/rubygems/test_gem_uninstaller.rb b/test/rubygems/test_gem_uninstaller.rb
index f6fe4a9a4f..948318a5e3 100644
--- a/test/rubygems/test_gem_uninstaller.rb
+++ b/test/rubygems/test_gem_uninstaller.rb
@@ -172,6 +172,38 @@ class TestGemUninstaller < Gem::InstallerTestCase
assert_same uninstaller, @post_uninstall_hook_arg
end
+ def test_uninstall_default_gem
+ spec = new_default_spec 'default', '2'
+
+ install_default_gems spec
+
+ uninstaller = Gem::Uninstaller.new spec.name, :executables => true
+
+ e = assert_raises Gem::InstallError do
+ uninstaller.uninstall
+ end
+
+ assert_equal 'gem "default" cannot be uninstalled ' +
+ 'because it is a default gem',
+ e.message
+ end
+
+ def test_uninstall_default_gem_with_same_version
+ default_spec = new_default_spec 'default', '2'
+ install_default_gems default_spec
+
+ spec = new_spec 'default', '2'
+ install_gem spec
+
+ Gem::Specification.reset
+
+ uninstaller = Gem::Uninstaller.new spec.name, :executables => true
+
+ uninstaller.uninstall
+
+ refute_path_exists spec.gem_dir
+ end
+
def test_uninstall_nonexistent
uninstaller = Gem::Uninstaller.new 'bogus', :executables => true
@@ -265,8 +297,8 @@ class TestGemUninstaller < Gem::InstallerTestCase
end
def test_uninstall_prompts_about_broken_deps
- util_gem 'r', '1', 'q' => '= 1'
- util_gem 'q', '1'
+ quick_gem 'r', '1' do |s| s.add_dependency 'q', '= 1' end
+ quick_gem 'q', '1'
un = Gem::Uninstaller.new('q')
ui = Gem::MockGemUi.new("y\n")
@@ -287,10 +319,10 @@ class TestGemUninstaller < Gem::InstallerTestCase
end
def test_uninstall_only_lists_unsatified_deps
- util_gem 'r', '1', 'q' => '~> 1.0'
- util_gem 'x', '1', 'q' => '= 1.0'
- util_gem 'q', '1.0'
- util_gem 'q', '1.1'
+ quick_gem 'r', '1' do |s| s.add_dependency 'q', '~> 1.0' end
+ quick_gem 'x', '1' do |s| s.add_dependency 'q', '= 1.0' end
+ quick_gem 'q', '1.0'
+ quick_gem 'q', '1.1'
un = Gem::Uninstaller.new('q', :version => "1.0")
ui = Gem::MockGemUi.new("y\n")
@@ -311,9 +343,9 @@ class TestGemUninstaller < Gem::InstallerTestCase
end
def test_uninstall_doesnt_prompt_when_other_gem_satifies_requirement
- util_gem 'r', '1', 'q' => '~> 1.0'
- util_gem 'q', '1.0'
- util_gem 'q', '1.1'
+ quick_gem 'r', '1' do |s| s.add_dependency 'q', '~> 1.0' end
+ quick_gem 'q', '1.0'
+ quick_gem 'q', '1.1'
un = Gem::Uninstaller.new('q', :version => "1.0")
ui = Gem::MockGemUi.new("y\n")
@@ -328,11 +360,8 @@ class TestGemUninstaller < Gem::InstallerTestCase
end
def test_uninstall_doesnt_prompt_when_removing_a_dev_dep
- util_gem('r', '1') do |s|
- s.add_development_dependency "q", "= 1.0"
- end
-
- util_gem 'q', '1.0'
+ quick_gem 'r', '1' do |s| s.add_development_dependency 'q', '= 1.0' end
+ quick_gem 'q', '1.0'
un = Gem::Uninstaller.new('q', :version => "1.0")
ui = Gem::MockGemUi.new("y\n")
@@ -348,11 +377,11 @@ class TestGemUninstaller < Gem::InstallerTestCase
def test_uninstall_prompt_includes_dep_type
- util_gem 'r', '1' do |s|
+ quick_gem 'r', '1' do |s|
s.add_development_dependency 'q', '= 1'
end
- util_gem 'q', '1'
+ quick_gem 'q', '1'
un = Gem::Uninstaller.new('q', :check_dev => true)
ui = Gem::MockGemUi.new("y\n")