Merge pull request #15741 from dduugg/stict-type-string_inreplace_extension

This commit is contained in:
Mike McQuaid 2023-07-24 08:40:46 +01:00 committed by GitHub
commit 3b3300546b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 80 additions and 10 deletions

View File

@ -353,18 +353,21 @@ class Formula
# Is the currently active {SoftwareSpec} a {#stable} build? # Is the currently active {SoftwareSpec} a {#stable} build?
# @private # @private
sig { returns(T::Boolean) }
def stable? def stable?
active_spec == stable active_spec == stable
end end
# Is the currently active {SoftwareSpec} a {#head} build? # Is the currently active {SoftwareSpec} a {#head} build?
# @private # @private
sig { returns(T::Boolean) }
def head? def head?
active_spec == head active_spec == head
end end
# Is this formula HEAD-only? # Is this formula HEAD-only?
# @private # @private
sig { returns(T.nilable(T::Boolean)) }
def head_only? def head_only?
head && !stable head && !stable
end end
@ -573,12 +576,14 @@ class Formula
# This is actually just a check for if the {#latest_installed_prefix} directory # This is actually just a check for if the {#latest_installed_prefix} directory
# exists and is not empty. # exists and is not empty.
# @private # @private
sig { returns(T::Boolean) }
def latest_version_installed? def latest_version_installed?
(dir = latest_installed_prefix).directory? && !dir.children.empty? (dir = latest_installed_prefix).directory? && !dir.children.empty?
end end
# If at least one version of {Formula} is installed. # If at least one version of {Formula} is installed.
# @private # @private
sig { returns(T::Boolean) }
def any_version_installed? def any_version_installed?
installed_prefixes.any? { |keg| (keg/Tab::FILENAME).file? } installed_prefixes.any? { |keg| (keg/Tab::FILENAME).file? }
end end
@ -652,11 +657,13 @@ class Formula
end end
# Is the formula linked? # Is the formula linked?
sig { returns(T::Boolean) }
def linked? def linked?
linked_keg.symlink? linked_keg.symlink?
end end
# Is the formula linked to `opt`? # Is the formula linked to `opt`?
sig { returns(T::Boolean) }
def optlinked? def optlinked?
opt_prefix.symlink? opt_prefix.symlink?
end end
@ -708,6 +715,7 @@ class Formula
# #
# No `make install` available? # No `make install` available?
# <pre>bin.install "binary1"</pre> # <pre>bin.install "binary1"</pre>
sig { returns(Pathname) }
def bin def bin
prefix/"bin" prefix/"bin"
end end
@ -715,6 +723,7 @@ class Formula
# The directory where the formula's documentation should be installed. # The directory where the formula's documentation should be installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def doc def doc
share/"doc"/name share/"doc"/name
end end
@ -725,6 +734,7 @@ class Formula
# #
# No `make install` available? # No `make install` available?
# <pre>include.install "example.h"</pre> # <pre>include.install "example.h"</pre>
sig { returns(Pathname) }
def include def include
prefix/"include" prefix/"include"
end end
@ -732,6 +742,7 @@ class Formula
# The directory where the formula's info files should be installed. # The directory where the formula's info files should be installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def info def info
share/"info" share/"info"
end end
@ -742,6 +753,7 @@ class Formula
# #
# No `make install` available? # No `make install` available?
# <pre>lib.install "example.dylib"</pre> # <pre>lib.install "example.dylib"</pre>
sig { returns(Pathname) }
def lib def lib
prefix/"lib" prefix/"lib"
end end
@ -754,6 +766,7 @@ class Formula
# <pre>libexec.install "foo.jar" # <pre>libexec.install "foo.jar"
# bin.write_jar_script libexec/"foo.jar", "foo" # bin.write_jar_script libexec/"foo.jar", "foo"
# </pre> # </pre>
sig { returns(Pathname) }
def libexec def libexec
prefix/"libexec" prefix/"libexec"
end end
@ -763,6 +776,7 @@ class Formula
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
# Often one of the more specific `man` functions should be used instead, # Often one of the more specific `man` functions should be used instead,
# e.g. {#man1}. # e.g. {#man1}.
sig { returns(Pathname) }
def man def man
share/"man" share/"man"
end end
@ -773,6 +787,7 @@ class Formula
# #
# No `make install` available? # No `make install` available?
# <pre>man1.install "example.1"</pre> # <pre>man1.install "example.1"</pre>
sig { returns(Pathname) }
def man1 def man1
man/"man1" man/"man1"
end end
@ -780,6 +795,7 @@ class Formula
# The directory where the formula's man2 pages should be installed. # The directory where the formula's man2 pages should be installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def man2 def man2
man/"man2" man/"man2"
end end
@ -790,6 +806,7 @@ class Formula
# #
# No `make install` available? # No `make install` available?
# <pre>man3.install "man.3"</pre> # <pre>man3.install "man.3"</pre>
sig { returns(Pathname) }
def man3 def man3
man/"man3" man/"man3"
end end
@ -797,6 +814,7 @@ class Formula
# The directory where the formula's man4 pages should be installed. # The directory where the formula's man4 pages should be installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def man4 def man4
man/"man4" man/"man4"
end end
@ -804,6 +822,7 @@ class Formula
# The directory where the formula's man5 pages should be installed. # The directory where the formula's man5 pages should be installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def man5 def man5
man/"man5" man/"man5"
end end
@ -811,6 +830,7 @@ class Formula
# The directory where the formula's man6 pages should be installed. # The directory where the formula's man6 pages should be installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def man6 def man6
man/"man6" man/"man6"
end end
@ -818,6 +838,7 @@ class Formula
# The directory where the formula's man7 pages should be installed. # The directory where the formula's man7 pages should be installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def man7 def man7
man/"man7" man/"man7"
end end
@ -825,6 +846,7 @@ class Formula
# The directory where the formula's man8 pages should be installed. # The directory where the formula's man8 pages should be installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def man8 def man8
man/"man8" man/"man8"
end end
@ -833,6 +855,7 @@ class Formula
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
# Generally we try to migrate these to {#bin} instead. # Generally we try to migrate these to {#bin} instead.
sig { returns(Pathname) }
def sbin def sbin
prefix/"sbin" prefix/"sbin"
end end
@ -852,6 +875,7 @@ class Formula
# #
# Install `./example_code/simple/ones` to `share/demos/examples`: # Install `./example_code/simple/ones` to `share/demos/examples`:
# <pre>(share/"demos").install "example_code/simple/ones" => "examples"</pre> # <pre>(share/"demos").install "example_code/simple/ones" => "examples"</pre>
sig { returns(Pathname) }
def share def share
prefix/"share" prefix/"share"
end end
@ -863,6 +887,7 @@ class Formula
# #
# No `make install` available? # No `make install` available?
# <pre>pkgshare.install "examples"</pre> # <pre>pkgshare.install "examples"</pre>
sig { returns(Pathname) }
def pkgshare def pkgshare
prefix/"share"/name prefix/"share"/name
end end
@ -872,6 +897,7 @@ class Formula
# #
# To install an Emacs mode included with a software package: # To install an Emacs mode included with a software package:
# <pre>elisp.install "contrib/emacs/example-mode.el"</pre> # <pre>elisp.install "contrib/emacs/example-mode.el"</pre>
sig { returns(Pathname) }
def elisp def elisp
prefix/"share/emacs/site-lisp"/name prefix/"share/emacs/site-lisp"/name
end end
@ -880,6 +906,7 @@ class Formula
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
# This is not symlinked into `HOMEBREW_PREFIX`. # This is not symlinked into `HOMEBREW_PREFIX`.
sig { returns(Pathname) }
def frameworks def frameworks
prefix/"Frameworks" prefix/"Frameworks"
end end
@ -888,6 +915,7 @@ class Formula
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
# This is not symlinked into `HOMEBREW_PREFIX`. # This is not symlinked into `HOMEBREW_PREFIX`.
sig { returns(Pathname) }
def kext_prefix def kext_prefix
prefix/"Library/Extensions" prefix/"Library/Extensions"
end end
@ -897,6 +925,7 @@ class Formula
# but will write a new file named `*.default`. # but will write a new file named `*.default`.
# This directory is not inside the `HOMEBREW_CELLAR` so it persists # This directory is not inside the `HOMEBREW_CELLAR` so it persists
# across upgrades. # across upgrades.
sig { returns(Pathname) }
def etc def etc
(HOMEBREW_PREFIX/"etc").extend(InstallRenamed) (HOMEBREW_PREFIX/"etc").extend(InstallRenamed)
end end
@ -905,6 +934,7 @@ class Formula
# e.g. `$HOMEBREW_PREFIX/etc/openssl@1.1` # e.g. `$HOMEBREW_PREFIX/etc/openssl@1.1`
# Anything using `pkgetc.install` will not overwrite other files on # Anything using `pkgetc.install` will not overwrite other files on
# e.g. upgrades but will write a new file named `*.default`. # e.g. upgrades but will write a new file named `*.default`.
sig { returns(Pathname) }
def pkgetc def pkgetc
(HOMEBREW_PREFIX/"etc"/name).extend(InstallRenamed) (HOMEBREW_PREFIX/"etc"/name).extend(InstallRenamed)
end end
@ -912,6 +942,7 @@ class Formula
# The directory where the formula's variable files should be installed. # The directory where the formula's variable files should be installed.
# This directory is not inside the `HOMEBREW_CELLAR` so it persists # This directory is not inside the `HOMEBREW_CELLAR` so it persists
# across upgrades. # across upgrades.
sig { returns(Pathname) }
def var def var
HOMEBREW_PREFIX/"var" HOMEBREW_PREFIX/"var"
end end
@ -920,6 +951,7 @@ class Formula
# installed. # installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def zsh_function def zsh_function
share/"zsh/site-functions" share/"zsh/site-functions"
end end
@ -928,6 +960,7 @@ class Formula
# installed. # installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def fish_function def fish_function
share/"fish/vendor_functions.d" share/"fish/vendor_functions.d"
end end
@ -936,6 +969,7 @@ class Formula
# installed. # installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def bash_completion def bash_completion
prefix/"etc/bash_completion.d" prefix/"etc/bash_completion.d"
end end
@ -944,6 +978,7 @@ class Formula
# installed. # installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def zsh_completion def zsh_completion
share/"zsh/site-functions" share/"zsh/site-functions"
end end
@ -952,6 +987,7 @@ class Formula
# installed. # installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with # This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only. # `brew link` for formulae that are not keg-only.
sig { returns(Pathname) }
def fish_completion def fish_completion
share/"fish/vendor_completions.d" share/"fish/vendor_completions.d"
end end
@ -960,12 +996,14 @@ class Formula
# installation so, despite not being in `HOMEBREW_CELLAR`, they are installed # installation so, despite not being in `HOMEBREW_CELLAR`, they are installed
# there after pouring a bottle. # there after pouring a bottle.
# @private # @private
sig { returns(Pathname) }
def bottle_prefix def bottle_prefix
prefix/".bottle" prefix/".bottle"
end end
# The directory where the formula's installation or test logs will be written. # The directory where the formula's installation or test logs will be written.
# @private # @private
sig { returns(Pathname) }
def logs def logs
HOMEBREW_LOGS + name HOMEBREW_LOGS + name
end end
@ -1220,6 +1258,7 @@ class Formula
# Rarely, you don't want your library symlinked into the main prefix. # Rarely, you don't want your library symlinked into the main prefix.
# See `gettext.rb` for an example. # See `gettext.rb` for an example.
# @see .keg_only # @see .keg_only
sig { returns(T::Boolean) }
def keg_only? def keg_only?
return false unless keg_only_reason return false unless keg_only_reason
@ -1405,6 +1444,7 @@ class Formula
end end
end end
sig { returns(T.nilable(T::Boolean)) }
def migration_needed? def migration_needed?
!oldnames_to_migrate.empty? && !rack.exist? !oldnames_to_migrate.empty? && !rack.exist?
end end
@ -1446,6 +1486,7 @@ class Formula
end end
end end
sig { returns(T::Boolean) }
def new_formula_available? def new_formula_available?
installed_alias_target_changed? && !latest_formula.latest_version_installed? installed_alias_target_changed? && !latest_formula.latest_version_installed?
end end
@ -1456,6 +1497,7 @@ class Formula
# Has the target of the alias used to install this formula changed? # Has the target of the alias used to install this formula changed?
# Returns false if the formula wasn't installed with an alias. # Returns false if the formula wasn't installed with an alias.
sig { returns(T::Boolean) }
def installed_alias_target_changed? def installed_alias_target_changed?
target = current_installed_alias_target target = current_installed_alias_target
return false unless target return false unless target
@ -1464,12 +1506,14 @@ class Formula
end end
# Is this formula the target of an alias used to install an old formula? # Is this formula the target of an alias used to install an old formula?
sig { returns(T::Boolean) }
def supersedes_an_installed_formula? def supersedes_an_installed_formula?
old_installed_formulae.any? old_installed_formulae.any?
end end
# Has the alias used to install the formula changed, or are different # Has the alias used to install the formula changed, or are different
# formulae already installed with this alias? # formulae already installed with this alias?
sig { returns(T::Boolean) }
def alias_changed? def alias_changed?
installed_alias_target_changed? || supersedes_an_installed_formula? installed_alias_target_changed? || supersedes_an_installed_formula?
end end
@ -1490,6 +1534,7 @@ class Formula
end end
# @private # @private
sig { params(fetch_head: T::Boolean).returns(T::Boolean) }
def outdated?(fetch_head: false) def outdated?(fetch_head: false)
!outdated_kegs(fetch_head: fetch_head).empty? !outdated_kegs(fetch_head: fetch_head).empty?
rescue Migrator::MigrationNeededError rescue Migrator::MigrationNeededError
@ -1969,12 +2014,14 @@ class Formula
# True if this formula is provided by Homebrew itself # True if this formula is provided by Homebrew itself
# @private # @private
sig { returns(T.nilable(T::Boolean)) }
def core_formula? def core_formula?
tap&.core_tap? tap&.core_tap?
end end
# True if this formula is provided by external Tap # True if this formula is provided by external Tap
# @private # @private
sig { returns(T::Boolean) }
def tap? def tap?
return false unless tap return false unless tap
@ -1984,6 +2031,7 @@ class Formula
# True if this formula can be installed on this platform # True if this formula can be installed on this platform
# Redefined in extend/os. # Redefined in extend/os.
# @private # @private
sig { returns(T::Boolean) }
def valid_platform? def valid_platform?
requirements.none?(MacOSRequirement) && requirements.none?(LinuxRequirement) requirements.none?(MacOSRequirement) && requirements.none?(LinuxRequirement)
end end
@ -2936,6 +2984,7 @@ class Formula
# Whether a livecheck specification is defined or not. # Whether a livecheck specification is defined or not.
# It returns true when a livecheck block is present in the {Formula} and # It returns true when a livecheck block is present in the {Formula} and
# false otherwise, and is used by livecheck. # false otherwise, and is used by livecheck.
sig { returns(T::Boolean) }
def livecheckable? def livecheckable?
@livecheckable == true @livecheckable == true
end end
@ -2943,6 +2992,7 @@ class Formula
# Whether a service specification is defined or not. # Whether a service specification is defined or not.
# It returns true when a service block is present in the {Formula} and # It returns true when a service block is present in the {Formula} and
# false otherwise, and is used by service. # false otherwise, and is used by service.
sig { returns(T::Boolean) }
def service? def service?
@service_block.present? @service_block.present?
end end
@ -3502,8 +3552,8 @@ class Formula
# Whether this {Formula} is deprecated (i.e. warns on installation). # Whether this {Formula} is deprecated (i.e. warns on installation).
# Defaults to false. # Defaults to false.
# @return [Boolean]
# @see .deprecate! # @see .deprecate!
sig { returns(T::Boolean) }
def deprecated? def deprecated?
@deprecated == true @deprecated == true
end end
@ -3542,8 +3592,8 @@ class Formula
# Whether this {Formula} is disabled (i.e. cannot be installed). # Whether this {Formula} is disabled (i.e. cannot be installed).
# Defaults to false. # Defaults to false.
# @return [Boolean]
# @see .disable! # @see .disable!
sig { returns(T::Boolean) }
def disabled? def disabled?
@disabled == true @disabled == true
end end

View File

@ -7,7 +7,7 @@ describe Utils::Inreplace do
let(:file) { Tempfile.new("test") } let(:file) { Tempfile.new("test") }
before do before do
file.write <<~EOS File.binwrite(file, <<~EOS)
a a
b b
c c
@ -52,4 +52,18 @@ describe Utils::Inreplace do
end.to raise_error(Utils::Inreplace::Error) end.to raise_error(Utils::Inreplace::Error)
end end
end end
describe "#gsub!" do
it "substitutes pathname within file" do
# For a specific instance of this, see https://github.com/Homebrew/homebrew-core/blob/a8b0b10/Formula/loki.rb#L48
described_class.inreplace(file.path) do |s|
s.gsub!(Pathname("b"), Pathname("f"))
end
expect(File.binread(file)).to eq <<~EOS
a
f
c
EOS
end
end
end end

View File

@ -47,6 +47,7 @@ module Utils
} }
def inreplace(paths, before = nil, after = nil, audit_result = true) # rubocop:disable Style/OptionalBooleanParameter def inreplace(paths, before = nil, after = nil, audit_result = true) # rubocop:disable Style/OptionalBooleanParameter
after &&= after.to_s after &&= after.to_s
before = before.to_s if before.is_a?(Pathname)
errors = {} errors = {}
@ -59,7 +60,7 @@ module Utils
if before.nil? && after.nil? if before.nil? && after.nil?
yield s yield s
else else
s.gsub!(T.must(before), after, audit_result) s.gsub!(T.must(before), T.must(after), audit_result)
end end
errors[path] = s.errors unless s.errors.empty? errors[path] = s.errors unless s.errors.empty?

View File

@ -1,16 +1,20 @@
# typed: true # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
# Used by the `inreplace` function (in `utils.rb`). # Used by the `inreplace` function (in `utils.rb`).
# #
# @api private # @api private
class StringInreplaceExtension class StringInreplaceExtension
attr_accessor :errors, :inreplace_string sig { returns(T::Array[String]) }
attr_accessor :errors
sig { returns(String) }
attr_accessor :inreplace_string
sig { params(string: String).void } sig { params(string: String).void }
def initialize(string) def initialize(string)
@inreplace_string = string @inreplace_string = string
@errors = [] @errors = T.let([], T::Array[String])
end end
# Same as `String#sub!`, but warns if nothing was replaced. # Same as `String#sub!`, but warns if nothing was replaced.
@ -27,11 +31,12 @@ class StringInreplaceExtension
# #
# @api public # @api public
sig { sig {
params(before: T.any(Pathname, Regexp, String), after: T.nilable(String), audit_result: T::Boolean) params(before: T.any(Pathname, Regexp, String), after: T.any(Pathname, String), audit_result: T::Boolean)
.returns(T.nilable(String)) .returns(T.nilable(String))
} }
def gsub!(before, after, audit_result = true) # rubocop:disable Style/OptionalBooleanParameter def gsub!(before, after, audit_result = true) # rubocop:disable Style/OptionalBooleanParameter
result = inreplace_string.gsub!(before, after) before = before.to_s if before.is_a?(Pathname)
result = inreplace_string.gsub!(before, after.to_s)
errors << "expected replacement of #{before.inspect} with #{after.inspect}" if audit_result && result.nil? errors << "expected replacement of #{before.inspect} with #{after.inspect}" if audit_result && result.nil?
result result
end end
@ -65,6 +70,6 @@ class StringInreplaceExtension
# @api public # @api public
sig { params(flag: String).returns(String) } sig { params(flag: String).returns(String) }
def get_make_var(flag) def get_make_var(flag)
inreplace_string[/^#{Regexp.escape(flag)}[ \t]*[\\?+:!]?=[ \t]*((?:.*\\\n)*.*)$/, 1] T.must(inreplace_string[/^#{Regexp.escape(flag)}[ \t]*[\\?+:!]?=[ \t]*((?:.*\\\n)*.*)$/, 1])
end end
end end