diff options
Diffstat (limited to 'lib/bundler/errors.rb')
| -rw-r--r-- | lib/bundler/errors.rb | 147 |
1 files changed, 134 insertions, 13 deletions
diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb index f10b6cc68f..dff5d93128 100644 --- a/lib/bundler/errors.rb +++ b/lib/bundler/errors.rb @@ -21,19 +21,11 @@ module Bundler class InstallError < BundlerError; status_code(5); end # Internal error, should be rescued - class VersionConflict < BundlerError - attr_reader :conflicts - - def initialize(conflicts, msg = nil) - super(msg) - @conflicts = conflicts - end - - status_code(6) - end + class SolveFailure < BundlerError; status_code(6); end class GemNotFound < BundlerError; status_code(7); end class InstallHookError < BundlerError; status_code(8); end + class RemovedError < BundlerError; status_code(9); end class GemfileNotFound < BundlerError; status_code(10); end class GitError < BundlerError; status_code(11); end class DeprecatedError < BundlerError; status_code(12); end @@ -55,13 +47,50 @@ module Bundler class CyclicDependencyError < BundlerError; status_code(21); end class GemfileLockNotFound < BundlerError; status_code(22); end class PluginError < BundlerError; status_code(29); end - class SudoNotPermittedError < BundlerError; status_code(30); end class ThreadCreationError < BundlerError; status_code(33); end class APIResponseMismatchError < BundlerError; status_code(34); end class APIResponseInvalidDependenciesError < BundlerError; status_code(35); end class GemfileEvalError < GemfileError; end class MarshalError < StandardError; end + class ChecksumMismatchError < SecurityError + def initialize(lock_name, existing, checksum) + @lock_name = lock_name + @existing = existing + @checksum = checksum + end + + def message + <<~MESSAGE + Bundler found mismatched checksums. This is a potential security risk. + #{@lock_name} #{@existing.to_lock} + from #{@existing.sources.join("\n and ")} + #{@lock_name} #{@checksum.to_lock} + from #{@checksum.sources.join("\n and ")} + + #{mismatch_resolution_instructions} + To ignore checksum security warnings, disable checksum validation with + `bundle config set --local disable_checksum_validation true` + MESSAGE + end + + def mismatch_resolution_instructions + removable, remote = [@existing, @checksum].partition(&:removable?) + case removable.size + when 1 + msg = +"If you trust #{remote.first.sources.first}, to resolve this issue you can:\n" + msg << removable.first.removal_instructions + when 2 + msg = +"To resolve this issue you can either:\n" + msg << @checksum.removal_instructions + msg << "or if you are sure that the new checksum from #{@checksum.sources.first} is correct:\n" + msg << @existing.removal_instructions + end + end + + status_code(37) + end + class PermissionError < BundlerError def initialize(path, permission_type = :write) @path = path @@ -102,7 +131,8 @@ module Bundler attr_reader :orig_exception def initialize(orig_exception, msg) - full_message = msg + "\nGem Load Error is: #{orig_exception.message}\n"\ + full_message = msg + "\nGem Load Error is: + #{orig_exception.full_message(highlight: false)}\n"\ "Backtrace for gem load error is:\n"\ "#{orig_exception.backtrace.join("\n")}\n"\ "Bundler Error Backtrace:\n" @@ -160,6 +190,24 @@ module Bundler status_code(31) end + class ReadOnlyFileSystemError < PermissionError + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "File system is read-only." + end + + status_code(42) + end + + class OperationNotPermittedError < PermissionError + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "Underlying OS system call raised an EPERM error." + end + + status_code(43) + end + class GenericSystemCallError < BundlerError attr_reader :underlying_error @@ -174,7 +222,9 @@ module Bundler class DirectoryRemovalError < BundlerError def initialize(orig_exception, msg) full_message = "#{msg}.\n" \ - "The underlying error was #{orig_exception.class}: #{orig_exception.message}, with backtrace:\n" \ + "The underlying error was #{orig_exception.class}: + #{orig_exception.full_message(highlight: false)}, + with backtrace:\n" \ " #{orig_exception.backtrace.join("\n ")}\n\n" \ "Bundler Error Backtrace:" super(full_message) @@ -182,4 +232,75 @@ module Bundler status_code(36) end + + class InsecureInstallPathError < BundlerError + def initialize(name, path) + @name = name + @path = path + end + + def message + "Bundler cannot reinstall #{@name} because there's a previous installation of it at #{@path} that is unsafe to remove.\n" \ + "The parent of #{@path} is world-writable and does not have the sticky bit set, making it insecure to remove due to potential vulnerabilities.\n" \ + "Please change the permissions of #{File.dirname(@path)} or choose a different install path." + end + + status_code(38) + end + + class CorruptBundlerInstallError < BundlerError + def initialize(loaded_spec) + @loaded_spec = loaded_spec + end + + def message + "The running version of Bundler (#{Bundler::VERSION}) does not match the version of the specification installed for it (#{@loaded_spec.version}). " \ + "This can be caused by reinstalling Ruby without removing previous installation, leaving around an upgraded default version of Bundler. " \ + "Reinstalling Ruby from scratch should fix the problem." + end + + status_code(39) + end + + class InvalidArgumentError < BundlerError; status_code(40); end + + class IncorrectLockfileDependencies < BundlerError + attr_reader :spec, :actual_dependencies, :lockfile_dependencies + + def initialize(spec, actual_dependencies = nil, lockfile_dependencies = nil) + @spec = spec + @actual_dependencies = actual_dependencies + @lockfile_dependencies = lockfile_dependencies + end + + def message + lines = ["Bundler found incorrect dependencies in the lockfile for #{spec.full_name}", ""] + + if @actual_dependencies && @lockfile_dependencies + actual_by_name = @actual_dependencies.each_with_object({}) {|d, h| h[d.name] = d } + lockfile_by_name = @lockfile_dependencies.each_with_object({}) {|d, h| h[d.name] = d } + + (actual_by_name.keys | lockfile_by_name.keys).sort.each do |name| + actual = actual_by_name[name] + lockfile = lockfile_by_name[name] + next if actual && lockfile && actual.requirement == lockfile.requirement + + if actual && lockfile + lines << " #{name}: gemspec specifies #{actual.requirement}, lockfile has #{lockfile.requirement}" + elsif actual + lines << " #{name}: gemspec specifies #{actual.requirement}, not in lockfile" + else + lines << " #{name}: not in gemspec, lockfile has #{lockfile.requirement}" + end + end + + lines << "" + end + + lines << "Please run `bundle install` to regenerate the lockfile." + lines.join("\n") + end + + status_code(41) + end end |
