From f59eb358c29c5f40601a99e3f1bf7e8e891f10ba Mon Sep 17 00:00:00 2001 From: Mike McQuaid <mike@mikemcquaid.com> Date: Mon, 20 Mar 2017 20:37:12 +0100 Subject: [PATCH] missing_formula: subsume historic logic. These methods belong together so combine them in a single class to provide a simpler API. --- Library/Homebrew/cmd/info.rb | 17 +----- Library/Homebrew/cmd/install.rb | 16 +---- Library/Homebrew/cmd/search.rb | 4 +- Library/Homebrew/exceptions.rb | 13 ----- Library/Homebrew/historic.rb | 57 ------------------ Library/Homebrew/missing_formula.rb | 55 +++++++++++++++++- Library/Homebrew/test/historic_test.rb | 46 --------------- Library/Homebrew/test/missing_formula_spec.rb | 58 ++++++++++++++++++- 8 files changed, 116 insertions(+), 150 deletions(-) delete mode 100644 Library/Homebrew/historic.rb delete mode 100644 Library/Homebrew/test/historic_test.rb diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index 5c96e5c506..7e18155567 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -23,7 +23,6 @@ require "formula" require "keg" require "tab" require "json" -require "historic" module Homebrew module_function @@ -57,22 +56,10 @@ module Homebrew end rescue FormulaUnavailableError => e # No formula with this name, try a missing formula lookup - if (missing_formula = Homebrew::MissingFormula.missing_formula(f)) - ofail "#{e.message}\n#{missing_formula}" + if (reason = Homebrew::MissingFormula.reason(f)) + ofail "#{e.message}\n#{reason}" else ofail e.message - - # No point in searching if the specified tap isn't tapped yet - next if e.instance_of?(TapFormulaUnavailableError) && !e.tap.installed? - - migrations = search_for_migrated_formula(f) - next unless migrations.empty? - ohai "Searching among deleted formulae..." - begin - search_for_deleted_formula(f) - rescue - nil - end end end end diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index a0f95887b1..bd7897171f 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -62,7 +62,6 @@ require "formula_installer" require "tap" require "hardware" require "development_tools" -require "historic" module Homebrew module_function @@ -207,24 +206,13 @@ module Homebrew # formula was found, but there's a problem with its implementation). ofail e.message rescue FormulaUnavailableError => e - if (missing_formula = Homebrew::MissingFormula.missing_formula(e.name)) - ofail "#{e.message}\n#{missing_formula}" + if (reason = Homebrew::MissingFormula.reason(e.name)) + ofail "#{e.message}\n#{reason}" elsif e.name == "updog" ofail "What's updog?" else ofail e.message - migrations = search_for_migrated_formula(e.name) - return unless migrations.empty? - - ohai "Searching among deleted formulae..." - begin - search_for_deleted_formula(e.name) - return - rescue - nil - end - query = query_regexp(e.name) ohai "Searching for similarly named formulae..." diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb index 6887805d6e..db5898872f 100644 --- a/Library/Homebrew/cmd/search.rb +++ b/Library/Homebrew/cmd/search.rb @@ -67,12 +67,12 @@ module Homebrew if $stdout.tty? count = local_results.length + tap_results.length - if msg = Homebrew::MissingFormula.missing_formula(query) + if reason = Homebrew::MissingFormula.reason(query) if count > 0 puts puts "If you meant #{query.inspect} specifically:" end - puts msg + puts reason elsif count.zero? puts "No formula found for #{query.inspect}." begin diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index e9885890bb..77da4489e8 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -94,19 +94,6 @@ class TapFormulaUnavailableError < FormulaUnavailableError end end -class FormulaExistsError < RuntimeError - attr_reader :name, :path - - def initialize(name, path) - @name = name - @path = path - end - - def to_s - "Formula #{name} exists in #{path}" - end -end - class FormulaClassUnavailableError < FormulaUnavailableError attr_reader :path attr_reader :class_name diff --git a/Library/Homebrew/historic.rb b/Library/Homebrew/historic.rb deleted file mode 100644 index 0afb9646ab..0000000000 --- a/Library/Homebrew/historic.rb +++ /dev/null @@ -1,57 +0,0 @@ -require "formulary" -require "tap" - -module Homebrew - module_function - - # name should not be qualified, since migration of qualified names is already - # handled in Formulary::TapLoader.formula_name_path. - def search_for_migrated_formula(name, options = {}) - print_messages = options.fetch(:print_messages, true) - migrations = [] - Tap.each do |old_tap| - new_tap_name = old_tap.tap_migrations[name] - next unless new_tap_name - migrations << [old_tap, new_tap_name] - next unless print_messages - deprecation = (new_tap_name == "homebrew/boneyard") ? "deprecated " : "" - puts "A #{deprecation}formula named \"#{name}\" has been migrated from #{old_tap} to #{new_tap_name}." - end - migrations - end - - # name may be qualified. - def search_for_deleted_formula(name, options = {}) - print_messages = options.fetch(:print_messages, true) - warn_shallow = options.fetch(:warn_shallow, false) - - path = Formulary.path name - raise FormulaExistsError.new(name, path) if File.exist? path - path.to_s =~ HOMEBREW_TAP_PATH_REGEX - tap = Tap.new ($1 == "Homebrew" ? "homebrew" : $1), $2.strip_prefix("homebrew-") - raise TapUnavailableError, tap.name unless File.exist? tap.path - relpath = path.relative_path_from tap.path - - cd tap.path - - if warn_shallow && File.exist?(".git/shallow") - opoo <<-EOS.undend - The git repository is a shallow clone therefore the output may be incomplete. - Use `git fetch -C #{tap.path} --unshallow` to get the full repository. - EOS - end - - log_cmd = "git log --name-only --max-count=1 --format=$'format:%H\\n%h' -- #{relpath}" - hash, hash_abbrev, relpath = Utils.popen_read(log_cmd).lines.map(&:chomp) - if hash.to_s.empty? || hash_abbrev.to_s.empty? || relpath.to_s.empty? - raise FormulaUnavailableError, name - end - - if print_messages - puts "#{name} was deleted from #{tap.name} in commit #{hash_abbrev}." - puts "Run `brew boneyard #{name}` to show the formula's content prior to its removal." - end - - [tap, relpath, hash, hash_abbrev] - end -end diff --git a/Library/Homebrew/missing_formula.rb b/Library/Homebrew/missing_formula.rb index 28738a0dc9..ba09f7426b 100644 --- a/Library/Homebrew/missing_formula.rb +++ b/Library/Homebrew/missing_formula.rb @@ -6,7 +6,7 @@ module Homebrew module MissingFormula class << self def reason(name) - blacklisted_reason(name) + blacklisted_reason(name) || tap_migration_reason(name) || deleted_reason(name) end def blacklisted_reason(name) @@ -100,6 +100,59 @@ module Homebrew end alias generic_blacklisted_reason blacklisted_reason + def tap_migration_reason(name) + message = nil + + Tap.each do |old_tap| + new_tap_name = old_tap.tap_migrations[name] + next unless new_tap_name + message = <<-EOS.undent + It was migrated from #{old_tap} to #{new_tap_name}. + You can access it again by running: + brew tap #{new_tap_name} + EOS + break + end + + message + end + + def deleted_reason(name) + path = Formulary.path name + return if File.exist? path + tap = Tap.from_path(path) + return unless File.exist? tap.path + relative_path = path.relative_path_from tap.path + + tap.path.cd do + # We know this may return incomplete results for shallow clones but + # we don't want to nag everyone with a shallow clone to unshallow it. + log_command = "git log --name-only --max-count=1 --format=%H\\\\n%h\\\\n%B -- #{relative_path}" + hash, short_hash, *commit_message, relative_path = + Utils.popen_read(log_command).gsub("\\n", "\n").lines.map(&:chomp) + if hash.to_s.empty? || short_hash.to_s.empty? || + relative_path.to_s.empty? + return + end + + commit_message = commit_message.reject(&:empty?).join("\n ") + + commit_message.sub!(/ \(#(\d+)\)$/, " (#{tap.issues_url}/\\1)") + commit_message.gsub!(/(Closes|Fixes) #(\d+)/, "\\1 #{tap.issues_url}/\\2") + + <<-EOS.undent + #{name} was deleted from #{tap.name} in commit #{short_hash}: + #{commit_message} + + To show the formula before removal run: + git -C "$(brew --repo #{tap})" show #{short_hash}^:#{relative_path} + + If you still use this formula consider creating your own tap: + http://docs.brew.sh/How-to-Create-and-Maintain-a-Tap.html + EOS + end + end + require "extend/os/missing_formula" end end diff --git a/Library/Homebrew/test/historic_test.rb b/Library/Homebrew/test/historic_test.rb deleted file mode 100644 index d09656fe0b..0000000000 --- a/Library/Homebrew/test/historic_test.rb +++ /dev/null @@ -1,46 +0,0 @@ -require "testing_env" -require "historic" - -class HistoricTest < Homebrew::TestCase - def setup - super - - @path = Tap::TAP_DIRECTORY/"homebrew/homebrew-foo" - @path.mkpath - @tap = Tap.new("Homebrew", "foo") - - (@path/"tap_migrations.json").write <<-EOS.undent - { "migrated-formula": "homebrew/bar" } - EOS - (@path/"Formula/to-delete.rb").write "placeholder" - - @path.cd do - shutup do - system "git", "init" - system "git", "add", "--all" - system "git", "commit", "-m", "initial state" - system "git", "rm", "Formula/to-delete.rb" - system "git", "commit", "-m", "delete formula 'to-delete'" - end - end - end - - def teardown - @path.rmtree - - super - end - - def test_search_for_migrated_formula - migrations = Homebrew.search_for_migrated_formula("migrated-formula", print_messages: false) - assert_equal [[@tap, "homebrew/bar"]], migrations - end - - def test_search_for_deleted_formula - tap, relpath, hash, = Homebrew.search_for_deleted_formula("homebrew/foo/to-delete", - print_messages: false) - assert_equal tap, @tap - assert_equal relpath, "Formula/to-delete.rb" - assert_equal `git rev-parse HEAD`.chomp, hash - end -end diff --git a/Library/Homebrew/test/missing_formula_spec.rb b/Library/Homebrew/test/missing_formula_spec.rb index 11b93316fd..f395965a6a 100644 --- a/Library/Homebrew/test/missing_formula_spec.rb +++ b/Library/Homebrew/test/missing_formula_spec.rb @@ -1,13 +1,13 @@ require "missing_formula" describe Homebrew::MissingFormula do - context ".reason" do + context "::reason" do subject { described_class.reason("gem") } it { is_expected.to_not be_nil } end - context ".blacklisted_reason" do + context "::blacklisted_reason" do matcher(:be_blacklisted) do match(&Homebrew::MissingFormula.method(:blacklisted_reason)) end @@ -122,4 +122,58 @@ describe Homebrew::MissingFormula do end end end + + context "::tap_migration_reason" do + subject { described_class.tap_migration_reason(formula) } + + before do + Tap.clear_cache + tap_path = Tap::TAP_DIRECTORY/"homebrew/homebrew-foo" + tap_path.mkpath + (tap_path/"tap_migrations.json").write <<-EOS.undent + { "migrated-formula": "homebrew/bar" } + EOS + end + + context "with a migrated formula" do + let(:formula) { "migrated-formula" } + it { is_expected.to_not be_nil } + end + + context "with a missing formula" do + let(:formula) { "missing-formula" } + it { is_expected.to be_nil } + end + end + + context "::deleted_reason" do + subject { described_class.deleted_reason(formula) } + + before do + Tap.clear_cache + tap_path = Tap::TAP_DIRECTORY/"homebrew/homebrew-foo" + tap_path.mkpath + (tap_path/"deleted-formula.rb").write "placeholder" + + tap_path.cd do + shutup do + system "git", "init" + system "git", "add", "--all" + system "git", "commit", "-m", "initial state" + system "git", "rm", "deleted-formula.rb" + system "git", "commit", "-m", "delete formula 'deleted-formula'" + end + end + end + + context "with a deleted formula" do + let(:formula) { "homebrew/foo/deleted-formula" } + it { is_expected.to_not be_nil } + end + + context "with a formula that never existed" do + let(:formula) { "homebrew/foo/missing-formula" } + it { is_expected.to be_nil } + end + end end -- GitLab