Skip to content

Commit

Permalink
Merge pull request #16014 from apainintheneck/scrub-sorbet-runtime-fr…
Browse files Browse the repository at this point in the history
…om-backtrace

utils/backtrace: scrub sorbet-runtime from backtrace
  • Loading branch information
MikeMcQuaid authored Sep 22, 2023
2 parents 1f80e82 + 85bd4c7 commit 073a4bb
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 20 deletions.
8 changes: 4 additions & 4 deletions Library/Homebrew/brew.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
Homebrew::Help.help cmd, remaining_args: args.remaining, usage_error: e.message
rescue SystemExit => e
onoe "Kernel.exit" if args.debug? && !e.success?
$stderr.puts e.backtrace if args.debug?
$stderr.puts Utils::Backtrace.clean(e) if args.debug?
raise
rescue Interrupt
$stderr.puts # seemingly a newline is typical
Expand Down Expand Up @@ -175,7 +175,7 @@
raise if e.message.empty?

onoe e
$stderr.puts e.backtrace if args.debug?
$stderr.puts Utils::Backtrace.clean(e) if args.debug?

exit 1
rescue MethodDeprecatedError => e
Expand All @@ -184,7 +184,7 @@
$stderr.puts "If reporting this issue please do so at (not Homebrew/brew or Homebrew/homebrew-core):"
$stderr.puts " #{Formatter.url(e.issues_url)}"
end
$stderr.puts e.backtrace if args.debug?
$stderr.puts Utils::Backtrace.clean(e) if args.debug?
exit 1
rescue Exception => e # rubocop:disable Lint/RescueException
onoe e
Expand All @@ -196,7 +196,7 @@
$stderr.puts " #{Formatter.url(OS::ISSUES_URL)}"
end
end
$stderr.puts e.backtrace
$stderr.puts Utils::Backtrace.clean(e)
exit 1
else
exit 1 if Homebrew.failed?
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/cask/audit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def run!

self
rescue => e
odebug e, e.backtrace
odebug e, ::Utils::Backtrace.clean(e)
add_error "exception while auditing #{cask}: #{e.message}"
self
end
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/cmd/install.rb
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def self.install
# Need to rescue before `FormulaUnavailableError` (superclass of this)
# is handled, as searching for a formula doesn't make sense here (the
# formula was found, but there's a problem with its implementation).
$stderr.puts e.backtrace if Homebrew::EnvConfig.developer?
$stderr.puts Utils::Backtrace.clean(e) if Homebrew::EnvConfig.developer?
ofail e.message
rescue FormulaOrCaskUnavailableError, Cask::CaskUnavailableError => e
Homebrew.failed = true
Expand Down
4 changes: 2 additions & 2 deletions Library/Homebrew/cmd/update-report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def output_update_report
begin
reporter = Reporter.new(tap)
rescue Reporter::ReporterRevisionUnsetError => e
onoe "#{e.message}\n#{e.backtrace&.join("\n")}" if Homebrew::EnvConfig.developer?
onoe "#{e.message}\n#{Utils::Backtrace.clean(e)&.join("\n")}" if Homebrew::EnvConfig.developer?
next
end
if reporter.updated?
Expand Down Expand Up @@ -629,7 +629,7 @@ def migrate_tap_migration
system HOMEBREW_BREW_FILE, "link", new_full_name, "--overwrite"
end
rescue Exception => e # rubocop:disable Lint/RescueException
onoe "#{e.message}\n#{e.backtrace&.join("\n")}" if Homebrew::EnvConfig.developer?
onoe "#{e.message}\n#{Utils::Backtrace.clean(e)&.join("\n")}" if Homebrew::EnvConfig.developer?
end
next
end
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/dev-cmd/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def test
rescue Exception => e # rubocop:disable Lint/RescueException
retry if retry_test?(f, args: args)
ofail "#{f.full_name}: failed"
$stderr.puts e, e.backtrace
$stderr.puts e, Utils::Backtrace.clean(e)
ensure
ENV.replace(env)
end
Expand Down
10 changes: 5 additions & 5 deletions Library/Homebrew/formula_installer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,7 @@ def link(keg)
ofail "An unexpected error occurred during the `brew link` step"
puts "The formula built, but is not symlinked into #{HOMEBREW_PREFIX}"
puts e
puts e.backtrace if debug?
puts Utils::Backtrace.clean(e) if debug?
@show_summary_heading = true
ignore_interrupts do
keg.unlink
Expand Down Expand Up @@ -1081,7 +1081,7 @@ def install_service
rescue Exception => e # rubocop:disable Lint/RescueException
puts e
ofail "Failed to install service files"
odebug e, e.backtrace
odebug e, Utils::Backtrace.clean(e)
end

sig { params(keg: Keg).void }
Expand All @@ -1091,7 +1091,7 @@ def fix_dynamic_linkage(keg)
ofail "Failed to fix install linkage"
puts "The formula built, but you may encounter issues using it or linking other"
puts "formulae against it."
odebug e, e.backtrace
odebug e, Utils::Backtrace.clean(e)
@show_summary_heading = true
end

Expand All @@ -1102,7 +1102,7 @@ def clean
rescue Exception => e # rubocop:disable Lint/RescueException
opoo "The cleaning step did not complete successfully"
puts "Still, the installation was successful, so we will link it into your prefix."
odebug e, e.backtrace
odebug e, Utils::Backtrace.clean(e)
Homebrew.failed = true
@show_summary_heading = true
end
Expand Down Expand Up @@ -1171,7 +1171,7 @@ def post_install
opoo "The post-install step did not complete successfully"
puts "You can try again using:"
puts " brew postinstall #{formula.full_name}"
odebug e, e.backtrace, always_display: Homebrew::EnvConfig.developer?
odebug e, Utils::Backtrace.clean(e), always_display: Homebrew::EnvConfig.developer?
Homebrew.failed = true
@show_summary_heading = true
end
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/formula_versions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def formula_at_revision(revision, formula_relative_path = relative_path, &_block
rescue *IGNORED_EXCEPTIONS => e
# We rescue these so that we can skip bad versions and
# continue walking the history
odebug "#{e} in #{name} at revision #{revision}", e.backtrace
odebug "#{e} in #{name} at revision #{revision}", Utils::Backtrace.clean(e)
rescue FormulaUnavailableError
nil
ensure
Expand Down
4 changes: 2 additions & 2 deletions Library/Homebrew/livecheck/livecheck.rb
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ def run_checks(
name += " (cask)" if ambiguous_casks.include?(formula_or_cask)

onoe "#{Tty.blue}#{name}#{Tty.reset}: #{e}"
$stderr.puts e.backtrace if debug && !e.is_a?(Livecheck::Error)
$stderr.puts Utils::Backtrace.clean(e) if debug && !e.is_a?(Livecheck::Error)
print_resources_info(resource_version_info, verbose: verbose) if check_for_resources
nil
end
Expand Down Expand Up @@ -1016,7 +1016,7 @@ def resource_version(
status_hash(resource, "error", [e.to_s], verbose: verbose)
elsif !quiet
onoe "#{Tty.blue}#{resource.name}#{Tty.reset}: #{e}"
$stderr.puts e.backtrace if debug && !e.is_a?(Livecheck::Error)
$stderr.puts Utils::Backtrace.clean(e) if debug && !e.is_a?(Livecheck::Error)
nil
end
end
Expand Down
4 changes: 2 additions & 2 deletions Library/Homebrew/migrator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def migrate
rescue Exception => e # rubocop:disable Lint/RescueException
onoe "The migration did not complete successfully."
puts e
puts e.backtrace if debug?
puts Utils::Backtrace.clean(e) if debug?
puts "Backing up..."
ignore_interrupts { backup_oldname }
ensure
Expand Down Expand Up @@ -358,7 +358,7 @@ def link_newname
rescue Exception => e # rubocop:disable Lint/RescueException
onoe "An unexpected error occurred during linking"
puts e
puts e.backtrace if debug?
puts Utils::Backtrace.clean(e) if debug?
ignore_interrupts { new_keg.unlink(verbose: verbose?) }
raise
end
Expand Down
90 changes: 90 additions & 0 deletions Library/Homebrew/test/utils/backtrace_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# frozen_string_literal: true

require "utils/backtrace"

describe Utils::Backtrace do
let(:backtrace_no_sorbet_paths) do
[
"/Library/Homebrew/downloadable.rb:75:in",
"/Library/Homebrew/downloadable.rb:50:in",
"/Library/Homebrew/cmd/fetch.rb:236:in",
"/Library/Homebrew/cmd/fetch.rb:201:in",
"/Library/Homebrew/cmd/fetch.rb:178:in",
"/Library/Homebrew/simulate_system.rb:29:in",
"/Library/Homebrew/cmd/fetch.rb:166:in",
"/Library/Homebrew/cmd/fetch.rb:163:in",
"/Library/Homebrew/cmd/fetch.rb:163:in",
"/Library/Homebrew/cmd/fetch.rb:94:in",
"/Library/Homebrew/cmd/fetch.rb:94:in",
"/Library/Homebrew/brew.rb:94:in",
]
end

let(:backtrace_with_sorbet_paths) do
[
"/Library/Homebrew/downloadable.rb:75:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/_methods.rb:270:in",
"/Library/Homebrew/downloadable.rb:50:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/_methods.rb:270:in",
"/Library/Homebrew/cmd/fetch.rb:236:in",
"/Library/Homebrew/cmd/fetch.rb:201:in",
"/Library/Homebrew/cmd/fetch.rb:178:in",
"/Library/Homebrew/simulate_system.rb:29:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/_methods.rb:270:in",
"/Library/Homebrew/cmd/fetch.rb:166:in",
"/Library/Homebrew/cmd/fetch.rb:163:in",
"/Library/Homebrew/cmd/fetch.rb:163:in",
"/Library/Homebrew/cmd/fetch.rb:94:in",
"/Library/Homebrew/cmd/fetch.rb:94:in",
"/Library/Homebrew/brew.rb:94:in",
]
end

let(:backtrace_with_sorbet_error) do
backtrace_with_sorbet_paths.drop(1)
end

def exception_with(backtrace:)
exception = StandardError.new
exception.set_backtrace(backtrace) if backtrace
exception
end

before do
allow(described_class).to receive(:sorbet_runtime_path)
.and_return("/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime")
allow(Context).to receive(:current).and_return(Context::ContextStruct.new(verbose: false))
end

it "handles nil backtrace" do
exception = exception_with backtrace: nil
expect(described_class.clean(exception)).to be_nil
end

it "handles empty array backtrace" do
exception = exception_with backtrace: []
expect(described_class.clean(exception)).to eq []
end

it "removes sorbet paths when top error is not from sorbet" do
exception = exception_with backtrace: backtrace_with_sorbet_paths
expect(described_class.clean(exception)).to eq backtrace_no_sorbet_paths
end

it "includes sorbet paths when top error is not from sorbet and verbose is set" do
allow(Context).to receive(:current).and_return(Context::ContextStruct.new(verbose: true))
exception = exception_with backtrace: backtrace_with_sorbet_paths
expect(described_class.clean(exception)).to eq backtrace_with_sorbet_paths
end

it "doesn't change backtrace when error is from sorbet" do
exception = exception_with backtrace: backtrace_with_sorbet_error
expect(described_class.clean(exception)).to eq backtrace_with_sorbet_error
end
end
1 change: 1 addition & 0 deletions Library/Homebrew/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require "time"

require "utils/analytics"
require "utils/backtrace"
require "utils/curl"
require "utils/fork"
require "utils/formatter"
Expand Down
36 changes: 36 additions & 0 deletions Library/Homebrew/utils/backtrace.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# typed: true
# frozen_string_literal: true

module Utils
module Backtrace
# Cleans `sorbet-runtime` gem paths from the backtrace unless...
# 1. `verbose` is set
# 2. first backtrace line starts with `sorbet-runtime`
# - This implies that the error is related to Sorbet.
sig { params(error: Exception).returns(T.nilable(T::Array[String])) }
def self.clean(error)
backtrace = error.backtrace

return backtrace if Context.current.verbose?
return backtrace if backtrace.blank?
return backtrace if backtrace.fetch(0).start_with?(sorbet_runtime_path)

old_backtrace_length = backtrace.length
backtrace.reject { |line| line.start_with?(sorbet_runtime_path) }
.tap { |new_backtrace| print_backtrace_message if old_backtrace_length > new_backtrace.length }
end

def self.sorbet_runtime_path
@sorbet_runtime_path ||= "#{Gem.paths.home}/gems/sorbet-runtime"
end

def self.print_backtrace_message
return if @print_backtrace_message

opoo "Removed Sorbet lines from backtrace!"
puts "Rerun with --verbose to see the original backtrace" unless Homebrew::EnvConfig.no_env_hints?

@print_backtrace_message = true
end
end
end
2 changes: 1 addition & 1 deletion Library/Homebrew/utils/repology.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def self.single_package_query(name, repository:)
data = JSON.parse(output)
{ name => data }
rescue => e
error_output = [errors, "#{e.class}: #{e}", e.backtrace].compact
error_output = [errors, "#{e.class}: #{e}", Utils::Backtrace.clean(e)].compact
if Homebrew::EnvConfig.developer?
$stderr.puts(*error_output)
else
Expand Down

0 comments on commit 073a4bb

Please sign in to comment.