mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Deprecate default_formula Requirement DSL
This has been a nightmare in terms of the complexity to our dependency system and the whack-a-mole required on bugs. If a Requirement resolves to a Formula it should just use `depends_on "formula"` instead. This matches the effective behaviour all users of bottles (the vast majority of users and installs) and what we're doing in Homebrew/homebrew-core.
This commit is contained in:
parent
b66010605d
commit
b70b5429d0
@ -48,9 +48,6 @@ class Build
|
|||||||
Requirement.prune
|
Requirement.prune
|
||||||
elsif req.build? && dependent != formula
|
elsif req.build? && dependent != formula
|
||||||
Requirement.prune
|
Requirement.prune
|
||||||
elsif req.satisfied? && (dep = req.to_dependency) && dep.installed?
|
|
||||||
deps << dep
|
|
||||||
Requirement.prune
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -94,26 +94,14 @@ module Homebrew
|
|||||||
if ARGV.include?("--include-requirements")
|
if ARGV.include?("--include-requirements")
|
||||||
deps
|
deps
|
||||||
else
|
else
|
||||||
deps.map do |dep|
|
deps.select { |dep| dep.is_a? Dependency }
|
||||||
if dep.is_a? Dependency
|
|
||||||
dep
|
|
||||||
elsif dep.default_formula?
|
|
||||||
dep.to_dependency
|
|
||||||
end
|
|
||||||
end.compact
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def dep_display_name(dep)
|
def dep_display_name(dep)
|
||||||
str = if dep.is_a? Requirement
|
str = if dep.is_a? Requirement
|
||||||
if ARGV.include?("--include-requirements")
|
if ARGV.include?("--include-requirements")
|
||||||
if dep.default_formula?
|
":#{dep.display_s}"
|
||||||
":#{dep.display_s} (#{dep_display_name(dep.to_dependency)})"
|
|
||||||
else
|
|
||||||
":#{dep.display_s}"
|
|
||||||
end
|
|
||||||
elsif dep.default_formula?
|
|
||||||
dep_display_name(dep.to_dependency)
|
|
||||||
else
|
else
|
||||||
# This shouldn't happen, but we'll put something here to help debugging
|
# This shouldn't happen, but we'll put something here to help debugging
|
||||||
"::#{dep.name}"
|
"::#{dep.name}"
|
||||||
@ -207,7 +195,7 @@ module Homebrew
|
|||||||
max = dependables.length - 1
|
max = dependables.length - 1
|
||||||
@dep_stack.push f.name
|
@dep_stack.push f.name
|
||||||
dependables.each_with_index do |dep, i|
|
dependables.each_with_index do |dep, i|
|
||||||
next if !ARGV.include?("--include-requirements") && dep.is_a?(Requirement) && !dep.default_formula?
|
next if !ARGV.include?("--include-requirements") && dep.is_a?(Requirement)
|
||||||
tree_lines = if i == max
|
tree_lines = if i == max
|
||||||
"└──"
|
"└──"
|
||||||
else
|
else
|
||||||
@ -223,9 +211,6 @@ module Homebrew
|
|||||||
else
|
else
|
||||||
"│ "
|
"│ "
|
||||||
end
|
end
|
||||||
if dep.is_a?(Requirement) && dep.default_formula?
|
|
||||||
recursive_deps_tree(Formulary.factory(dep.to_dependency.name), prefix + prefix_addition, true)
|
|
||||||
end
|
|
||||||
if dep.is_a? Dependency
|
if dep.is_a? Dependency
|
||||||
recursive_deps_tree(Formulary.factory(dep.name), prefix + prefix_addition, true)
|
recursive_deps_tree(Formulary.factory(dep.name), prefix + prefix_addition, true)
|
||||||
end
|
end
|
||||||
|
@ -113,9 +113,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
reqs.any? do |req|
|
reqs.any? { |req| req.name == ff.name }
|
||||||
req.name == ff.name || [ff.name, ff.full_name].include?(req.default_formula)
|
|
||||||
end
|
|
||||||
rescue FormulaUnavailableError
|
rescue FormulaUnavailableError
|
||||||
# Silently ignore this case as we don't care about things used in
|
# Silently ignore this case as we don't care about things used in
|
||||||
# taps that aren't currently tapped.
|
# taps that aren't currently tapped.
|
||||||
|
@ -1486,15 +1486,10 @@ class Formula
|
|||||||
# Returns a list of Dependency objects that are required at runtime.
|
# Returns a list of Dependency objects that are required at runtime.
|
||||||
# @private
|
# @private
|
||||||
def runtime_dependencies
|
def runtime_dependencies
|
||||||
runtime_dependencies = recursive_dependencies do |_, dependency|
|
recursive_dependencies do |_, dependency|
|
||||||
Dependency.prune if dependency.build?
|
Dependency.prune if dependency.build?
|
||||||
Dependency.prune if !dependency.required? && build.without?(dependency)
|
Dependency.prune if !dependency.required? && build.without?(dependency)
|
||||||
end
|
end
|
||||||
runtime_requirement_deps = recursive_requirements do |_, requirement|
|
|
||||||
Requirement.prune if requirement.build?
|
|
||||||
Requirement.prune if !requirement.required? && build.without?(requirement)
|
|
||||||
end.map(&:to_dependency).compact
|
|
||||||
runtime_dependencies + runtime_requirement_deps
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a list of formulae depended on by this formula that aren't
|
# Returns a list of formulae depended on by this formula that aren't
|
||||||
@ -1552,7 +1547,6 @@ class Formula
|
|||||||
hsh["requirements"] = requirements.map do |req|
|
hsh["requirements"] = requirements.map do |req|
|
||||||
{
|
{
|
||||||
"name" => req.name,
|
"name" => req.name,
|
||||||
"default_formula" => req.default_formula,
|
|
||||||
"cask" => req.cask,
|
"cask" => req.cask,
|
||||||
"download" => req.download,
|
"download" => req.download,
|
||||||
}
|
}
|
||||||
|
@ -415,16 +415,6 @@ class FormulaInstaller
|
|||||||
raise UnsatisfiedRequirements, fatals
|
raise UnsatisfiedRequirements, fatals
|
||||||
end
|
end
|
||||||
|
|
||||||
def install_requirement_formula?(req_dependency, req, dependent, install_bottle_for_dependent)
|
|
||||||
return false unless req_dependency
|
|
||||||
return false if req.build? && dependent.installed?
|
|
||||||
return true unless req.satisfied?
|
|
||||||
return false if req.run?
|
|
||||||
return true if build_bottle?
|
|
||||||
return true if req.satisfied_by_formula?
|
|
||||||
install_bottle_for_dependent
|
|
||||||
end
|
|
||||||
|
|
||||||
def runtime_requirements(formula)
|
def runtime_requirements(formula)
|
||||||
runtime_deps = formula.runtime_dependencies.map(&:to_formula)
|
runtime_deps = formula.runtime_dependencies.map(&:to_formula)
|
||||||
recursive_requirements = formula.recursive_requirements do |dependent, _|
|
recursive_requirements = formula.recursive_requirements do |dependent, _|
|
||||||
@ -443,17 +433,9 @@ class FormulaInstaller
|
|||||||
f.recursive_requirements do |dependent, req|
|
f.recursive_requirements do |dependent, req|
|
||||||
build = effective_build_options_for(dependent)
|
build = effective_build_options_for(dependent)
|
||||||
install_bottle_for_dependent = install_bottle_for?(dependent, build)
|
install_bottle_for_dependent = install_bottle_for?(dependent, build)
|
||||||
use_default_formula = install_bottle_for_dependent || build_bottle?
|
|
||||||
req_dependency = req.to_dependency(use_default_formula: use_default_formula)
|
|
||||||
|
|
||||||
if (req.optional? || req.recommended?) && build.without?(req)
|
if (req.optional? || req.recommended?) && build.without?(req)
|
||||||
Requirement.prune
|
Requirement.prune
|
||||||
elsif req.build? && use_default_formula && req_dependency&.installed?
|
|
||||||
Requirement.prune
|
|
||||||
elsif install_requirement_formula?(req_dependency, req, dependent, install_bottle_for_dependent)
|
|
||||||
deps.unshift(req_dependency)
|
|
||||||
formulae.unshift(req_dependency.to_formula)
|
|
||||||
Requirement.prune
|
|
||||||
elsif req.satisfied?
|
elsif req.satisfied?
|
||||||
Requirement.prune
|
Requirement.prune
|
||||||
elsif !runtime_requirements.include?(req) && install_bottle_for_dependent
|
elsif !runtime_requirements.include?(req) && install_bottle_for_dependent
|
||||||
|
@ -62,8 +62,7 @@ class LinkageChecker
|
|||||||
formula.build.without?(dep)
|
formula.build.without?(dep)
|
||||||
end
|
end
|
||||||
declared_deps = formula.deps.reject { |dep| filter_out.call(dep) }.map(&:name)
|
declared_deps = formula.deps.reject { |dep| filter_out.call(dep) }.map(&:name)
|
||||||
declared_requirement_deps = formula.requirements.reject { |req| filter_out.call(req) }.map(&:default_formula).compact
|
declared_dep_names = declared_deps.map { |dep| dep.split("/").last }
|
||||||
declared_dep_names = (declared_deps + declared_requirement_deps).map { |dep| dep.split("/").last }
|
|
||||||
undeclared_deps = @brewed_dylibs.keys.reject do |full_name|
|
undeclared_deps = @brewed_dylibs.keys.reject do |full_name|
|
||||||
name = full_name.split("/").last
|
name = full_name.split("/").last
|
||||||
next true if name == formula.name
|
next true if name == formula.name
|
||||||
|
@ -9,13 +9,11 @@ require "build_environment"
|
|||||||
class Requirement
|
class Requirement
|
||||||
include Dependable
|
include Dependable
|
||||||
|
|
||||||
attr_reader :tags, :name, :cask, :download, :default_formula
|
attr_reader :tags, :name, :cask, :download
|
||||||
|
|
||||||
def initialize(tags = [])
|
def initialize(tags = [])
|
||||||
@default_formula = self.class.default_formula
|
|
||||||
@cask ||= self.class.cask
|
@cask ||= self.class.cask
|
||||||
@download ||= self.class.download
|
@download ||= self.class.download
|
||||||
@formula = nil
|
|
||||||
tags.each do |tag|
|
tags.each do |tag|
|
||||||
next unless tag.is_a? Hash
|
next unless tag.is_a? Hash
|
||||||
@cask ||= tag[:cask]
|
@cask ||= tag[:cask]
|
||||||
@ -56,12 +54,6 @@ class Requirement
|
|||||||
result = self.class.satisfy.yielder { |p| instance_eval(&p) }
|
result = self.class.satisfy.yielder { |p| instance_eval(&p) }
|
||||||
@satisfied_result = result
|
@satisfied_result = result
|
||||||
return false unless result
|
return false unless result
|
||||||
|
|
||||||
if parent = satisfied_result_parent
|
|
||||||
parent.to_s =~ %r{(#{Regexp.escape(HOMEBREW_CELLAR)}|#{Regexp.escape(HOMEBREW_PREFIX)}/opt)/([\w+-.@]+)}
|
|
||||||
@formula = Regexp.last_match(2)
|
|
||||||
end
|
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -71,10 +63,6 @@ class Requirement
|
|||||||
self.class.fatal || false
|
self.class.fatal || false
|
||||||
end
|
end
|
||||||
|
|
||||||
def default_formula?
|
|
||||||
self.class.default_formula || false
|
|
||||||
end
|
|
||||||
|
|
||||||
def satisfied_result_parent
|
def satisfied_result_parent
|
||||||
return unless @satisfied_result.is_a?(Pathname)
|
return unless @satisfied_result.is_a?(Pathname)
|
||||||
parent = @satisfied_result.resolved_path.parent
|
parent = @satisfied_result.resolved_path.parent
|
||||||
@ -124,24 +112,6 @@ class Requirement
|
|||||||
"#<#{self.class.name}: #{name.inspect} #{tags.inspect}>"
|
"#<#{self.class.name}: #{name.inspect} #{tags.inspect}>"
|
||||||
end
|
end
|
||||||
|
|
||||||
def formula
|
|
||||||
@formula || self.class.default_formula
|
|
||||||
end
|
|
||||||
|
|
||||||
def satisfied_by_formula?
|
|
||||||
!@formula.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_dependency(use_default_formula: false)
|
|
||||||
if use_default_formula && default_formula?
|
|
||||||
Dependency.new(self.class.default_formula, tags, method(:modify_build_environment), name)
|
|
||||||
elsif formula =~ HOMEBREW_TAP_FORMULA_REGEX
|
|
||||||
TapDependency.new(formula, tags, method(:modify_build_environment), name)
|
|
||||||
elsif formula
|
|
||||||
Dependency.new(formula, tags, method(:modify_build_environment), name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def display_s
|
def display_s
|
||||||
name
|
name
|
||||||
end
|
end
|
||||||
@ -167,8 +137,11 @@ class Requirement
|
|||||||
include BuildEnvironment::DSL
|
include BuildEnvironment::DSL
|
||||||
|
|
||||||
attr_reader :env_proc, :build
|
attr_reader :env_proc, :build
|
||||||
attr_rw :fatal, :default_formula
|
attr_rw :fatal, :cask, :download
|
||||||
attr_rw :cask, :download
|
|
||||||
|
def default_formula(val = nil)
|
||||||
|
# odeprecated "Requirement.default_formula"
|
||||||
|
end
|
||||||
|
|
||||||
def satisfy(options = nil, &block)
|
def satisfy(options = nil, &block)
|
||||||
return @satisfied if options.nil? && !block_given?
|
return @satisfied if options.nil? && !block_given?
|
||||||
|
@ -132,64 +132,4 @@ describe FormulaInstaller do
|
|||||||
fi.check_install_sanity
|
fi.check_install_sanity
|
||||||
}.to raise_error(CannotInstallFormulaError)
|
}.to raise_error(CannotInstallFormulaError)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#install_requirement_formula?", :needs_compat do
|
|
||||||
before do
|
|
||||||
@requirement = Python3Requirement.new
|
|
||||||
@requirement_dependency = @requirement.to_dependency
|
|
||||||
@install_bottle_for_dependent = false
|
|
||||||
allow(@requirement).to receive(:satisfied?).and_return(satisfied?)
|
|
||||||
allow(@requirement).to receive(:satisfied_by_formula?).and_return(satisfied_by_formula?)
|
|
||||||
allow(@requirement).to receive(:build?).and_return(build?)
|
|
||||||
@dependent = formula do
|
|
||||||
url "foo"
|
|
||||||
version "0.1"
|
|
||||||
depends_on :python3
|
|
||||||
end
|
|
||||||
allow(@dependent).to receive(:installed?).and_return(installed?)
|
|
||||||
@fi = FormulaInstaller.new(@dependent)
|
|
||||||
end
|
|
||||||
|
|
||||||
subject { @fi.install_requirement_formula?(@requirement_dependency, @requirement, @dependent, @install_bottle_for_dependent) }
|
|
||||||
|
|
||||||
context "it returns false when requirement is satisfied" do
|
|
||||||
let(:satisfied?) { true }
|
|
||||||
let(:satisfied_by_formula?) { false }
|
|
||||||
let(:build?) { false }
|
|
||||||
let(:installed?) { false }
|
|
||||||
it { is_expected.to be false }
|
|
||||||
end
|
|
||||||
|
|
||||||
context "it returns false when requirement is satisfied but default formula is installed" do
|
|
||||||
let(:satisfied?) { true }
|
|
||||||
let(:satisfied_by_formula?) { false }
|
|
||||||
let(:build?) { false }
|
|
||||||
let(:installed?) { false }
|
|
||||||
it { is_expected.to be false }
|
|
||||||
end
|
|
||||||
|
|
||||||
context "it returns false when requirement is :build and dependent is installed" do
|
|
||||||
let(:satisfied?) { false }
|
|
||||||
let(:satisfied_by_formula?) { false }
|
|
||||||
let(:build?) { true }
|
|
||||||
let(:installed?) { true }
|
|
||||||
it { is_expected.to be false }
|
|
||||||
end
|
|
||||||
|
|
||||||
context "it returns true when requirement isn't satisfied" do
|
|
||||||
let(:satisfied?) { false }
|
|
||||||
let(:satisfied_by_formula?) { false }
|
|
||||||
let(:build?) { false }
|
|
||||||
let(:installed?) { false }
|
|
||||||
it { is_expected.to be true }
|
|
||||||
end
|
|
||||||
|
|
||||||
context "it returns true when requirement is satisfied by a formula" do
|
|
||||||
let(:satisfied?) { true }
|
|
||||||
let(:satisfied_by_formula?) { true }
|
|
||||||
let(:build?) { false }
|
|
||||||
let(:installed?) { false }
|
|
||||||
it { is_expected.to be true }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -2,7 +2,6 @@ require "extend/ENV"
|
|||||||
require "requirement"
|
require "requirement"
|
||||||
|
|
||||||
describe Requirement do
|
describe Requirement do
|
||||||
alias_matcher :have_a_default_formula, :be_a_default_formula
|
|
||||||
alias_matcher :be_a_build_requirement, :be_a_build
|
alias_matcher :be_a_build_requirement, :be_a_build
|
||||||
|
|
||||||
subject { klass.new }
|
subject { klass.new }
|
||||||
@ -173,60 +172,6 @@ describe Requirement do
|
|||||||
its(:option_names) { are_expected.to eq(["foo"]) }
|
its(:option_names) { are_expected.to eq(["foo"]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#default_formula?" do
|
|
||||||
context "#default_formula specified" do
|
|
||||||
let(:klass) do
|
|
||||||
Class.new(described_class) do
|
|
||||||
default_formula "foo"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it { is_expected.to have_a_default_formula }
|
|
||||||
end
|
|
||||||
|
|
||||||
context "#default_formula omitted" do
|
|
||||||
it { is_expected.not_to have_a_default_formula }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#to_dependency" do
|
|
||||||
let(:klass) do
|
|
||||||
Class.new(described_class) do
|
|
||||||
default_formula "foo"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns a Dependency for its default Formula" do
|
|
||||||
expect(subject.to_dependency).to eq(Dependency.new("foo"))
|
|
||||||
end
|
|
||||||
|
|
||||||
context "#modify_build_environment" do
|
|
||||||
context "with error" do
|
|
||||||
let(:klass) do
|
|
||||||
Class.new(described_class) do
|
|
||||||
class ModifyBuildEnvironmentError < StandardError; end
|
|
||||||
|
|
||||||
default_formula "foo"
|
|
||||||
|
|
||||||
satisfy do
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
env do
|
|
||||||
raise ModifyBuildEnvironmentError
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raises an error" do
|
|
||||||
expect {
|
|
||||||
subject.to_dependency.modify_build_environment
|
|
||||||
}.to raise_error(klass.const_get(:ModifyBuildEnvironmentError))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#modify_build_environment" do
|
describe "#modify_build_environment" do
|
||||||
context "without env proc" do
|
context "without env proc" do
|
||||||
let(:klass) { Class.new(described_class) }
|
let(:klass) { Class.new(described_class) }
|
||||||
|
11
docs/Building-Against-Non-Homebrew-Dependencies.md
Normal file
11
docs/Building-Against-Non-Homebrew-Dependencies.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Building Against Non-Homebrew Dependencies
|
||||||
|
|
||||||
|
## History
|
||||||
|
|
||||||
|
Originally Homebrew was a build-from-source package manager and all user environment variables and non-Homebrew-installed software were available to builds. Since then Homebrew added `Requirement`s to specify dependencies on non-Homebrew software (such as those provided by `brew cask` like X11/XQuartz), the `superenv` build system to strip out unspecified dependencies, environment filtering to stop the user environment leaking into Homebrew builds and `default_formula` to specify that a `Requirement` can be satisifed by a particular formula.
|
||||||
|
|
||||||
|
As Homebrew became primarily a binary package manager, most users were fulfilling `Requirement`s with the `default_formula`, not with arbitrary alternatives. To improve quality and reduce variation, Homebrew now exclusively supports using the default formula, as an ordinary dependency, and no longer supports using arbitrary alternatives.
|
||||||
|
|
||||||
|
## Today
|
||||||
|
|
||||||
|
If you wish to build against custom non-Homebrew dependencies that are provided by Homebrew (e.g. a non-Homebrew, non-macOS `ruby`) then you must [create and maintain your own tap](How-to-Create-and-Maintain-a-Tap.md) as these formulae will not be accepted in Homebrew/homebrew-core. Once you have done that you can specify `env :std` in the formula which will allow a e.g. `which ruby` to access your existing `PATH` variable and allow compilation to link against this Ruby.
|
@ -33,6 +33,7 @@
|
|||||||
- [Python for Formula Authors](Python-for-Formula-Authors.md)
|
- [Python for Formula Authors](Python-for-Formula-Authors.md)
|
||||||
- [Migrating A Formula To A Tap](Migrating-A-Formula-To-A-Tap.md)
|
- [Migrating A Formula To A Tap](Migrating-A-Formula-To-A-Tap.md)
|
||||||
- [Rename A Formula](Rename-A-Formula.md)
|
- [Rename A Formula](Rename-A-Formula.md)
|
||||||
|
- [Building Against Non-Homebrew Dependencies](Building-Against-Non-Homebrew-Dependencies.md)
|
||||||
- [How To Create (And Maintain) A Tap](How-to-Create-and-Maintain-a-Tap.md)
|
- [How To Create (And Maintain) A Tap](How-to-Create-and-Maintain-a-Tap.md)
|
||||||
- [Brew Test Bot](Brew-Test-Bot.md)
|
- [Brew Test Bot](Brew-Test-Bot.md)
|
||||||
- [Prose Style Guidelines](Prose-Style-Guidelines.md)
|
- [Prose Style Guidelines](Prose-Style-Guidelines.md)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user