Skip to content

Commit

Permalink
Improve error reporting around bad sources
Browse files Browse the repository at this point in the history
  • Loading branch information
evanphx committed Jun 1, 2011
1 parent a14d587 commit c041cc5
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 16 deletions.
11 changes: 11 additions & 0 deletions lib/rubygems/command_manager.rb
Expand Up @@ -122,6 +122,17 @@ def run(args)
alert_error "While executing gem ... (#{ex.class})\n #{ex.to_s}"
ui.errs.puts "\t#{ex.backtrace.join "\n\t"}" if
Gem.configuration.backtrace

if Gem.configuration.really_verbose and \
ex.kind_of?(Gem::Exception) and ex.source_exception
e = ex.source_exception

ui.errs.puts "Because of: (#{e.class})\n #{e.to_s}"
if Gem.configuration.backtrace
ui.errs.puts "\t#{e.backtrace.join "\n\t"}"
end
end

terminate_interaction(1)
rescue Interrupt
alert_error "Interrupted"
Expand Down
2 changes: 1 addition & 1 deletion lib/rubygems/commands/sources_command.rb
Expand Up @@ -77,7 +77,7 @@ def execute
rescue URI::Error, ArgumentError
say "#{source_uri} is not a URI"
terminate_interaction 1
rescue Gem::RemoteFetcher::FetchError => e
rescue Gem::RemoteFetcher::FetchError, Gem::SourceError => e
say "Error fetching #{source_uri}:\n\t#{e.message}"
terminate_interaction 1
end
Expand Down
22 changes: 21 additions & 1 deletion lib/rubygems/exceptions.rb
@@ -1,7 +1,9 @@
##
# Base exception class for RubyGems. All exception raised by RubyGems are a
# subclass of this one.
class Gem::Exception < RuntimeError; end
class Gem::Exception < RuntimeError
attr_accessor :source_exception
end

class Gem::CommandLineError < Gem::Exception; end

Expand Down Expand Up @@ -89,3 +91,21 @@ def initialize(exit_code)
end

end

##
# An error that indicates there is an error with the source
# itself (such as the latest_spec file being invalid)

class Gem::SourceError < Gem::Exception
def initialize(message, uri)
@uri = uri
super message
end

attr_reader :uri

def to_s
"#{super} (#{@uri})"
end
end

41 changes: 33 additions & 8 deletions lib/rubygems/remote_fetcher.rb
Expand Up @@ -32,6 +32,13 @@ def to_s # :nodoc:

end

##
# A FetchError that indicates that the reason for not being
# able to fetch data was that the host could not be contacted

class UnknownHostError < FetchError
end

@fetcher = nil

##
Expand Down Expand Up @@ -221,18 +228,32 @@ def fetch_path(uri, mtime = nil, head = false)
uri = URI.parse uri unless URI::Generic === uri

raise ArgumentError, "bad uri: #{uri}" unless uri
raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}" unless
uri.scheme

unless uri.scheme
raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}"
end

data = send "fetch_#{uri.scheme}", uri, mtime, head
data = Gem.gunzip data if data and not head and uri.to_s =~ /gz$/

if data and !head and uri.to_s =~ /gz$/
begin
data = Gem.gunzip data
rescue Zlib::GzipFile::Error
raise FetchError.new("server did not return a valid file", uri.to_s)
end
end

data
rescue FetchError
raise
rescue Timeout::Error
raise FetchError.new('timed out', uri.to_s)
raise UnknownHostError.new('timed out', uri.to_s)
rescue IOError, SocketError, SystemCallError => e
raise FetchError.new("#{e.class}: #{e}", uri.to_s)
if e.message =~ /getaddrinfo/
raise UnknownHostError.new('no such name', uri.to_s)
else
raise FetchError.new("#{e.class}: #{e}", uri.to_s)
end
end

##
Expand All @@ -246,9 +267,13 @@ def cache_update_path(uri, path = nil)
Gem.read_binary(path)
else
data = fetch_path(uri)
open(path, 'wb') do |io|
io.write data
end if path

if path
open(path, 'wb') do |io|
io.write data
end
end

data
end
end
Expand Down
20 changes: 15 additions & 5 deletions lib/rubygems/spec_fetcher.rb
Expand Up @@ -256,11 +256,21 @@ def load_specs(source_uri, file)
local_file = File.join(cache_dir, file_name)
retried = false

spec_dump = if @update_cache then
FileUtils.mkdir_p cache_dir
@fetcher.cache_update_path(spec_path, local_file)
else
@fetcher.cache_update_path(spec_path)
begin
spec_dump = if @update_cache then
FileUtils.mkdir_p cache_dir
@fetcher.cache_update_path(spec_path, local_file)
else
@fetcher.cache_update_path(spec_path)
end
rescue Gem::RemoteFetcher::UnknownHostError => e
exc = Gem::SourceError.new("Could not contact source", source_uri)
exc.source_exception = e
raise exc
rescue Gem::RemoteFetcher::FetchError => e
exc = Gem::SourceError.new("Bad source, unable to get specs", source_uri)
exc.source_exception = e
raise exc
end

begin
Expand Down
2 changes: 1 addition & 1 deletion test/rubygems/test_gem_commands_sources_command.rb
Expand Up @@ -90,7 +90,7 @@ def test_execute_add_nonexistent_source

expected = <<-EOF
Error fetching http://beta-gems.example.com:
\tit died (#{uri})
\tBad source, unable to get specs (http://beta-gems.example.com)
EOF

assert_equal expected, @ui.output
Expand Down

0 comments on commit c041cc5

Please sign in to comment.