missing_formula: subsume historic logic.
These methods belong together so combine them in a single class to provide a simpler API.
This commit is contained in:
parent
80e95b684e
commit
f59eb358c2
@ -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
|
||||
|
@ -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..."
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user