* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38461 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
1b2be1f8ca
commit
eddc0685f2
16
ChangeLog
16
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
|
||||
|
@ -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
|
||||
output << make_entry(matching_tuples, platforms)
|
||||
end
|
||||
end
|
||||
|
||||
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 ', '
|
||||
def entry_details entry, spec, specs, platforms
|
||||
return unless options[:details]
|
||||
|
||||
entry << " (#{list})"
|
||||
end
|
||||
entry << "\n"
|
||||
|
||||
if options[:details] then
|
||||
detail_tuple = matching_tuples.first
|
||||
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
|
||||
|
||||
spec = detail_tuple.last
|
||||
def entry_versions entry, name_tuples, platforms
|
||||
return unless options[:versions]
|
||||
|
||||
unless spec.kind_of? Gem::Specification
|
||||
spec = spec.fetch_spec detail_tuple.first
|
||||
end
|
||||
|
||||
entry << "\n"
|
||||
|
||||
non_ruby = platforms.any? do |_, pls|
|
||||
pls.any? { |pl| pl != Gem::Platform::RUBY }
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
authors = "Author#{spec.authors.length > 1 ? 's' : ''}: "
|
||||
authors << spec.authors.join(', ')
|
||||
entry << format_text(authors, 68, 4)
|
||||
|
||||
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
|
||||
|
||||
if spec.homepage and not spec.homepage.empty? then
|
||||
entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
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 << "\n\n" << format_text(spec.summary, 68, 4)
|
||||
end
|
||||
output << entry
|
||||
|
||||
entry << " (#{list.join ', '})"
|
||||
end
|
||||
|
||||
def make_entry entry_tuples, platforms
|
||||
detail_tuple = entry_tuples.first
|
||||
name_tuple, latest_spec = detail_tuple
|
||||
|
||||
latest_spec = latest_spec.fetch_spec name_tuple unless
|
||||
Gem::Specification === latest_spec
|
||||
|
||||
name_tuples, specs = entry_tuples.flatten.partition do |item|
|
||||
Gem::NameTuple === item
|
||||
end
|
||||
|
||||
say output.join(options[:details] ? "\n\n" : "\n")
|
||||
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?
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
|
@ -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|
|
||||
|
@ -465,6 +465,19 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
||||
Gem.searcher = nil
|
||||
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
|
||||
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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")
|
||||
|
Loading…
x
Reference in New Issue
Block a user