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