Skip to content

Commit cafd79e

Browse files
committed
Link versioned keg-only formulae by default
Link `@` versioned or `-full` formulae by default if their unversioned or unfull siblings are not installed.
1 parent 0ac3954 commit cafd79e

4 files changed

Lines changed: 172 additions & 3 deletions

File tree

Library/Homebrew/formula.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,28 @@ def versioned_formulae
652652
end.sort_by(&:version).reverse
653653
end
654654

655+
# Returns the sibling `-full` or non-`-full` formula names for any Formula.
656+
sig { returns(T::Array[String]) }
657+
def full_formulae_names
658+
[
659+
if name.end_with?("-full")
660+
name.delete_suffix("-full")
661+
else
662+
"#{name}-full"
663+
end,
664+
]
665+
end
666+
667+
# Returns sibling `-full` or non-`-full` Formula objects for any Formula.
668+
sig { returns(T::Array[Formula]) }
669+
def full_formulae
670+
full_formulae_names.filter_map do |formula_name|
671+
Formula[formula_name]
672+
rescue FormulaUnavailableError
673+
nil
674+
end.sort_by(&:version).reverse
675+
end
676+
655677
# Whether this {Formula} is version-synced with other formulae.
656678
sig { returns(T::Boolean) }
657679
def synced_with_other_formulae?

Library/Homebrew/formula_installer.rb

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ def initialize(
113113
@overwrite = overwrite
114114
@keep_tmp = keep_tmp
115115
@debug_symbols = debug_symbols
116-
@link_keg = T.let(!formula.keg_only? || link_keg, T::Boolean)
116+
@installed_as_dependency = installed_as_dependency
117+
@installed_on_request = installed_on_request
118+
link_keg ||= auto_link_versioned_keg_only?
119+
@link_keg = T.let(link_keg, T::Boolean)
117120
@show_header = show_header
118121
@ignore_deps = ignore_deps
119122
@only_deps = only_deps
@@ -131,8 +134,6 @@ def initialize(
131134
@verbose = verbose
132135
@quiet = quiet
133136
@debug = debug
134-
@installed_as_dependency = installed_as_dependency
135-
@installed_on_request = installed_on_request
136137
@options = options
137138
@requirement_messages = T.let([], T::Array[String])
138139
@poured_bottle = T.let(false, T::Boolean)
@@ -1701,6 +1702,18 @@ def forbidden_formula_check
17011702

17021703
private
17031704

1705+
sig { returns(T::Boolean) }
1706+
def auto_link_versioned_keg_only?
1707+
return false if installed_as_dependency?
1708+
return false unless formula.keg_only?
1709+
return false unless formula.keg_only_reason.versioned_formula?
1710+
return false if formula.any_version_installed?
1711+
return false if formula.versioned_formulae.any?(&:any_version_installed?)
1712+
return false if formula.full_formulae.any?(&:any_version_installed?)
1713+
1714+
true
1715+
end
1716+
17041717
sig { void }
17051718
def lock
17061719
return unless self.class.locked.empty?

Library/Homebrew/test/formula_installer_spec.rb

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,88 @@ def temporary_install(formula, **options)
8383
end
8484
end
8585

86+
describe "versioned keg-only linking defaults" do
87+
let(:base_name) { "homebrew-versioned-formula" }
88+
let(:formula_name) { "#{base_name}@1.0" }
89+
let(:keg_only_formula) do
90+
formula formula_name do
91+
url "foo-1.0"
92+
keg_only :versioned_formula
93+
end
94+
end
95+
96+
before do
97+
allow(keg_only_formula).to receive_messages(any_version_installed?: false, versioned_formulae: [],
98+
full_formulae: [])
99+
end
100+
101+
it "links by default when no sibling variants are installed" do
102+
fi = described_class.new(keg_only_formula)
103+
104+
expect(fi.link_keg).to be true
105+
end
106+
107+
it "does not link by default when any version is already installed" do
108+
allow(keg_only_formula).to receive(:any_version_installed?).and_return(true)
109+
110+
fi = described_class.new(keg_only_formula)
111+
112+
expect(fi.link_keg).to be false
113+
end
114+
115+
it "links when explicitly requested" do
116+
allow(keg_only_formula).to receive(:any_version_installed?).and_return(true)
117+
118+
fi = described_class.new(keg_only_formula, link_keg: true)
119+
120+
expect(fi.link_keg).to be true
121+
end
122+
123+
it "does not link by default when another @-versioned formula is installed" do
124+
other_version = formula "#{base_name}@2.0" do
125+
url "foo-2.0"
126+
keg_only :versioned_formula
127+
end
128+
allow(other_version).to receive(:any_version_installed?).and_return(true)
129+
allow(keg_only_formula).to receive(:versioned_formulae).and_return([other_version])
130+
131+
fi = described_class.new(keg_only_formula)
132+
133+
expect(fi.link_keg).to be false
134+
end
135+
136+
it "does not link by default when the -full variant is installed" do
137+
full_variant = formula "#{base_name}-full" do
138+
url "foo-full-1.0"
139+
keg_only :versioned_formula
140+
end
141+
allow(full_variant).to receive(:any_version_installed?).and_return(true)
142+
allow(keg_only_formula).to receive(:full_formulae).and_return([full_variant])
143+
144+
fi = described_class.new(keg_only_formula)
145+
146+
expect(fi.link_keg).to be false
147+
end
148+
149+
it "does not link by default when the non-full variant is installed" do
150+
full_formula = formula "#{base_name}-full" do
151+
url "foo-full-1.0"
152+
keg_only :versioned_formula
153+
end
154+
non_full_variant = formula base_name do
155+
url "foo-1.0"
156+
keg_only :versioned_formula
157+
end
158+
allow(full_formula).to receive(:any_version_installed?).and_return(false)
159+
allow(non_full_variant).to receive(:any_version_installed?).and_return(true)
160+
allow(full_formula).to receive_messages(versioned_formulae: [], full_formulae: [non_full_variant])
161+
162+
fi = described_class.new(full_formula)
163+
164+
expect(fi.link_keg).to be false
165+
end
166+
end
167+
86168
describe "#check_install_sanity" do
87169
it "raises on direct cyclic dependency" do
88170
ENV["HOMEBREW_DEVELOPER"] = "1"

Library/Homebrew/test/formula_spec.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,58 @@
180180
end
181181
end
182182

183+
describe "#full_formulae_names" do
184+
let(:f) do
185+
formula "foo" do
186+
url "foo-1.0"
187+
end
188+
end
189+
190+
let(:f_full) do
191+
formula "foo-full" do
192+
url "foo-full-1.0"
193+
end
194+
end
195+
196+
let(:f_versioned) do
197+
formula "foo@2.0" do
198+
url "foo-2.0"
199+
end
200+
end
201+
202+
it "returns sibling full and non-full names" do
203+
expect(f.full_formulae_names).to eq ["foo-full"]
204+
expect(f_full.full_formulae_names).to eq ["foo"]
205+
expect(f_versioned.full_formulae_names).to eq ["foo@2.0-full"]
206+
end
207+
end
208+
209+
describe "#full_formulae" do
210+
let(:f) do
211+
formula "foo" do
212+
url "foo-1.0"
213+
end
214+
end
215+
216+
let(:f_full) do
217+
formula "foo-full" do
218+
url "foo-full-1.0"
219+
end
220+
end
221+
222+
before do
223+
allow(Formulary).to receive(:load_formula_from_path).with(f_full.name, f_full.path).and_return(f_full)
224+
allow(Formulary).to receive(:factory).with(f_full.name).and_return(f_full)
225+
allow(f).to receive(:full_formulae_names).and_return([f_full.name])
226+
end
227+
228+
it "returns array with sibling full formulae" do
229+
FileUtils.touch f.path
230+
FileUtils.touch f_full.path
231+
expect(f.full_formulae).to eq [f_full]
232+
end
233+
end
234+
183235
example "installed alias with core" do
184236
f = formula do
185237
url "foo-1.0"

0 commit comments

Comments
 (0)