Merge branch 'master' into debug-symbols

This commit is contained in:
Lukas Oberhuber 2022-08-10 18:44:09 -10:00
commit 3d60d610dd
299 changed files with 14180 additions and 775 deletions

View File

@ -37,6 +37,7 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 21 days-before-stale: 21
days-before-close: 7 days-before-close: 7
close-issue-reason: "not_planned"
stale-issue-message: > stale-issue-message: >
This issue has been automatically marked as stale because it has not had This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. recent activity. It will be closed if no further activity occurs.

3
.gitignore vendored
View File

@ -150,8 +150,7 @@
**/vendor/bundle/ruby/*/gems/simplecov-*/ **/vendor/bundle/ruby/*/gems/simplecov-*/
**/vendor/bundle/ruby/*/gems/simplecov-html-*/ **/vendor/bundle/ruby/*/gems/simplecov-html-*/
**/vendor/bundle/ruby/*/gems/sorbet-*/ **/vendor/bundle/ruby/*/gems/sorbet-*/
**/vendor/bundle/ruby/*/gems/sorbet-runtime-*/ !**/vendor/bundle/ruby/*/gems/sorbet-runtime-*/
!**/vendor/bundle/ruby/*/gems/sorbet-runtime-stub-*/
**/vendor/bundle/ruby/*/gems/spoom-*/ **/vendor/bundle/ruby/*/gems/spoom-*/
**/vendor/bundle/ruby/*/gems/stackprof-*/ **/vendor/bundle/ruby/*/gems/stackprof-*/
**/vendor/bundle/ruby/*/gems/strscan-*/ **/vendor/bundle/ruby/*/gems/strscan-*/

View File

@ -2,6 +2,8 @@
source "https://rubygems.org" source "https://rubygems.org"
ruby ">= 2.6.0"
# disallowed gems (should not be used) # disallowed gems (should not be used)
# * nokogiri - use rexml instead for XML parsing # * nokogiri - use rexml instead for XML parsing
@ -17,6 +19,7 @@ gem "rspec-github", require: false
gem "rspec-its", require: false gem "rspec-its", require: false
gem "rspec_junit_formatter", require: false gem "rspec_junit_formatter", require: false
gem "rspec-retry", require: false gem "rspec-retry", require: false
gem "rspec-sorbet", require: false
gem "rspec-wait", require: false gem "rspec-wait", require: false
gem "rubocop", require: false gem "rubocop", require: false
gem "rubocop-ast", require: false gem "rubocop-ast", require: false
@ -26,13 +29,12 @@ gem "warning", require: false
group :sorbet, optional: true do group :sorbet, optional: true do
gem "parlour", require: false gem "parlour", require: false
gem "rspec-sorbet", require: false
gem "sorbet-static-and-runtime", require: false gem "sorbet-static-and-runtime", require: false
gem "tapioca", require: false gem "tapioca", require: false
end end
# vendored gems # vendored gems
gem "activesupport", "< 7" # 7 requires Ruby 2.7 gem "activesupport"
gem "addressable" gem "addressable"
gem "concurrent-ruby" gem "concurrent-ruby"
gem "did_you_mean" # remove when HOMEBREW_REQUIRED_RUBY_VERSION >= 2.7 gem "did_you_mean" # remove when HOMEBREW_REQUIRED_RUBY_VERSION >= 2.7
@ -44,4 +46,4 @@ gem "rubocop-rails"
gem "rubocop-rspec" gem "rubocop-rspec"
gem "rubocop-sorbet" gem "rubocop-sorbet"
gem "ruby-macho" gem "ruby-macho"
gem "sorbet-runtime-stub" gem "sorbet-runtime"

View File

@ -11,7 +11,7 @@ GEM
public_suffix (>= 2.0.2, < 5.0) public_suffix (>= 2.0.2, < 5.0)
ast (2.4.2) ast (2.4.2)
bindata (2.4.10) bindata (2.4.10)
bootsnap (1.12.0) bootsnap (1.13.0)
msgpack (~> 1.2) msgpack (~> 1.2)
byebug (11.1.3) byebug (11.1.3)
coderay (1.1.3) coderay (1.1.3)
@ -58,12 +58,12 @@ GEM
mime-types-data (3.2022.0105) mime-types-data (3.2022.0105)
mini_portile2 (2.8.0) mini_portile2 (2.8.0)
minitest (5.16.2) minitest (5.16.2)
msgpack (1.5.3) msgpack (1.5.4)
mustache (1.1.1) mustache (1.1.1)
net-http-digest_auth (1.4.1) net-http-digest_auth (1.4.1)
net-http-persistent (4.0.1) net-http-persistent (4.0.1)
connection_pool (~> 2.2) connection_pool (~> 2.2)
nokogiri (1.13.7) nokogiri (1.13.8)
mini_portile2 (~> 2.8.0) mini_portile2 (~> 2.8.0)
racc (~> 1.4) racc (~> 1.4)
parallel (1.22.1) parallel (1.22.1)
@ -74,7 +74,7 @@ GEM
parser parser
rainbow (~> 3.0) rainbow (~> 3.0)
sorbet-runtime (>= 0.5) sorbet-runtime (>= 0.5)
parser (3.1.2.0) parser (3.1.2.1)
ast (~> 2.4.1) ast (~> 2.4.1)
patchelf (1.3.0) patchelf (1.3.0)
elftools (>= 1.1.3) elftools (>= 1.1.3)
@ -124,19 +124,19 @@ GEM
rspec (>= 3, < 4) rspec (>= 3, < 4)
rspec_junit_formatter (0.5.1) rspec_junit_formatter (0.5.1)
rspec-core (>= 2, < 4, != 2.12.0) rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.31.2) rubocop (1.33.0)
json (~> 2.3) json (~> 2.3)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 3.1.0.0) parser (>= 3.1.0.0)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0) regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0) rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.18.0, < 2.0) rubocop-ast (>= 1.19.1, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0) unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.19.1) rubocop-ast (1.21.0)
parser (>= 3.1.1.0) parser (>= 3.1.1.0)
rubocop-performance (1.14.2) rubocop-performance (1.14.3)
rubocop (>= 1.7.0, < 2.0) rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0) rubocop-ast (>= 0.4.0)
rubocop-rails (2.15.2) rubocop-rails (2.15.2)
@ -159,14 +159,13 @@ GEM
simplecov (~> 0.19) simplecov (~> 0.19)
simplecov-html (0.12.3) simplecov-html (0.12.3)
simplecov_json_formatter (0.1.4) simplecov_json_formatter (0.1.4)
sorbet (0.5.10158) sorbet (0.5.10175)
sorbet-static (= 0.5.10158) sorbet-static (= 0.5.10175)
sorbet-runtime (0.5.10158) sorbet-runtime (0.5.10175)
sorbet-runtime-stub (0.2.0) sorbet-static (0.5.10175-universal-darwin-14)
sorbet-static (0.5.10158-universal-darwin-14) sorbet-static-and-runtime (0.5.10175)
sorbet-static-and-runtime (0.5.10158) sorbet (= 0.5.10175)
sorbet (= 0.5.10158) sorbet-runtime (= 0.5.10175)
sorbet-runtime (= 0.5.10158)
spoom (1.1.11) spoom (1.1.11)
sorbet (>= 0.5.9204) sorbet (>= 0.5.9204)
sorbet-runtime (>= 0.5.9204) sorbet-runtime (>= 0.5.9204)
@ -181,7 +180,7 @@ GEM
thor (>= 1.2.0) thor (>= 1.2.0)
yard-sorbet yard-sorbet
thor (1.2.1) thor (1.2.1)
tzinfo (2.0.4) tzinfo (2.0.5)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
@ -205,7 +204,7 @@ PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
activesupport (< 7) activesupport
addressable addressable
bootsnap bootsnap
byebug byebug
@ -235,10 +234,13 @@ DEPENDENCIES
ruby-macho ruby-macho
simplecov simplecov
simplecov-cobertura simplecov-cobertura
sorbet-runtime-stub sorbet-runtime
sorbet-static-and-runtime sorbet-static-and-runtime
tapioca tapioca
warning warning
RUBY VERSION
ruby 2.6.8p205
BUNDLED WITH BUNDLED WITH
1.17.3 1.17.3

View File

@ -30,10 +30,8 @@ module Homebrew
def all_formulae def all_formulae
@all_formulae ||= begin @all_formulae ||= begin
curl_args = %w[--compressed --silent https://formulae.brew.sh/api/formula.json] curl_args = %w[--compressed --silent https://formulae.brew.sh/api/formula.json]
if cached_formula_json_file.exist? if cached_formula_json_file.exist? && !cached_formula_json_file.empty?
last_modified = cached_formula_json_file.mtime.utc curl_args.prepend("--time-cond", cached_formula_json_file)
last_modified = last_modified.strftime("%a, %d %b %Y %H:%M:%S GMT")
curl_args = ["--header", "If-Modified-Since: #{last_modified}", *curl_args]
end end
curl_download(*curl_args, to: HOMEBREW_CACHE_API/"#{formula_api_path}.json", max_time: 5) curl_download(*curl_args, to: HOMEBREW_CACHE_API/"#{formula_api_path}.json", max_time: 5)

View File

@ -29,6 +29,10 @@ FORMULA_COMPONENT_PRECEDENCE_LIST = [
[{ name: :depends_on, type: :method_call }], [{ name: :depends_on, type: :method_call }],
[{ name: :uses_from_macos, type: :method_call }], [{ name: :uses_from_macos, type: :method_call }],
[{ name: :on_macos, type: :block_call }], [{ name: :on_macos, type: :block_call }],
*MacOSVersions::SYMBOLS.keys.map do |os_name|
[{ name: :"on_#{os_name}", type: :block_call }]
end,
[{ name: :on_system, type: :block_call }],
[{ name: :on_linux, type: :block_call }], [{ name: :on_linux, type: :block_call }],
[{ name: :on_arm, type: :block_call }], [{ name: :on_arm, type: :block_call }],
[{ name: :on_intel, type: :block_call }], [{ name: :on_intel, type: :block_call }],

View File

@ -103,7 +103,15 @@ begin
possible_tap = OFFICIAL_CMD_TAPS.find { |_, cmds| cmds.include?(cmd) } possible_tap = OFFICIAL_CMD_TAPS.find { |_, cmds| cmds.include?(cmd) }
possible_tap = Tap.fetch(possible_tap.first) if possible_tap possible_tap = Tap.fetch(possible_tap.first) if possible_tap
if !possible_tap || possible_tap.installed? || Tap.untapped_official_taps.include?(possible_tap.name) if !possible_tap ||
possible_tap.installed? ||
(blocked_tap = Tap.untapped_official_taps.include?(possible_tap.name))
if blocked_tap
onoe <<~EOS
`brew #{cmd}` is unavailable because #{possible_tap.name} was manually untapped.
Run `brew tap #{possible_tap.name}` to reenable `brew #{cmd}`.
EOS
end
# Check for cask explicitly because it's very common in old guides # Check for cask explicitly because it's very common in old guides
odie "`brew cask` is no longer a `brew` command. Use `brew <command> --cask` instead." if cmd == "cask" odie "`brew cask` is no longer a `brew` command. Use `brew <command> --cask` instead." if cmd == "cask"
odie "Unknown command: #{cmd}" odie "Unknown command: #{cmd}"

View File

@ -90,13 +90,14 @@ module Cask
end end
def os_versions def os_versions
# TODO: use #to_hash_with_variations instead once all casks use on_system blocks
@os_versions ||= begin @os_versions ||= begin
version_os_hash = {} version_os_hash = {}
actual_version = MacOS.full_version.to_s actual_version = MacOS.full_version.to_s
MacOSVersions::SYMBOLS.each do |os_name, os_version| MacOSVersions::SYMBOLS.each do |os_name, os_version|
MacOS.full_version = os_version MacOS.full_version = os_version
cask = CaskLoader.load(token) cask = CaskLoader.load(full_name)
version_os_hash[os_name] = cask.version if cask.version != version version_os_hash[os_name] = cask.version if cask.version != version
end end
@ -219,7 +220,7 @@ module Cask
end end
alias == eql? alias == eql?
def to_hash def to_h
{ {
"token" => token, "token" => token,
"full_token" => full_name, "full_token" => full_name,
@ -243,8 +244,8 @@ module Cask
} }
end end
def to_h def to_hash_with_variations
hash = to_hash hash = to_h
variations = {} variations = {}
hash_keys_to_skip = %w[outdated installed versions] hash_keys_to_skip = %w[outdated installed versions]
@ -252,21 +253,20 @@ module Cask
if @dsl.on_system_blocks_exist? if @dsl.on_system_blocks_exist?
[:arm, :intel].each do |arch| [:arm, :intel].each do |arch|
MacOSVersions::SYMBOLS.each_key do |os_name| MacOSVersions::SYMBOLS.each_key do |os_name|
# Big Sur is the first version of macOS that supports arm bottle_tag = ::Utils::Bottles::Tag.new(system: os_name, arch: arch)
next if arch == :arm && MacOS::Version.from_symbol(os_name) < MacOS::Version.from_symbol(:big_sur) next unless bottle_tag.valid_combination?
Homebrew::SimulateSystem.os = os_name Homebrew::SimulateSystem.os = os_name
Homebrew::SimulateSystem.arch = arch Homebrew::SimulateSystem.arch = arch
refresh refresh
bottle_tag = ::Utils::Bottles::Tag.new(system: os_name, arch: arch).to_sym to_h.each do |key, value|
to_hash.each do |key, value|
next if hash_keys_to_skip.include? key next if hash_keys_to_skip.include? key
next if value.to_s == hash[key].to_s next if value.to_s == hash[key].to_s
variations[bottle_tag] ||= {} variations[bottle_tag.to_sym] ||= {}
variations[bottle_tag][key] = value variations[bottle_tag.to_sym][key] = value
end end
end end
end end

View File

@ -243,6 +243,17 @@ module Cask
end end
end end
# @api public
def arch(arm: nil, intel: nil)
should_return = arm.blank? && intel.blank?
set_unique_stanza(:arch, should_return) do
@on_system_blocks_exist = true
on_arch_conditional(arm: arm, intel: intel)
end
end
# `depends_on` uses a load method so that multiple stanzas can be merged. # `depends_on` uses a load method so that multiple stanzas can be merged.
# @api public # @api public
def depends_on(*args) def depends_on(*args)

View File

@ -1,6 +1,8 @@
# typed: strict # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
require "cask/staged"
module Cask module Cask
class DSL class DSL
# Class corresponding to the `preflight` stanza. # Class corresponding to the `preflight` stanza.

View File

@ -7,7 +7,6 @@ require "utils/topological_hash"
require "cask/config" require "cask/config"
require "cask/download" require "cask/download"
require "cask/staged"
require "cask/quarantine" require "cask/quarantine"
require "cgi" require "cgi"
@ -20,12 +19,6 @@ module Cask
extend T::Sig extend T::Sig
extend Predicable extend Predicable
# TODO: it is unwise for Cask::Staged to be a module, when we are
# dealing with both staged and unstaged casks here. This should
# either be a class which is only sometimes instantiated, or there
# should be explicit checks on whether staged state is valid in
# every method.
include Staged
def initialize(cask, command: SystemCommand, force: false, def initialize(cask, command: SystemCommand, force: false,
skip_cask_deps: false, binaries: true, verbose: false, skip_cask_deps: false, binaries: true, verbose: false,

View File

@ -156,35 +156,44 @@ module Homebrew
def self.install_formula_clean!(f, dry_run: false) def self.install_formula_clean!(f, dry_run: false)
return if Homebrew::EnvConfig.no_install_cleanup? return if Homebrew::EnvConfig.no_install_cleanup?
return unless f.latest_version_installed?
return if skip_clean_formula?(f)
cleanup = Cleanup.new(dry_run: dry_run) if dry_run
if cleanup.periodic_clean_due? ohai "Would run `brew cleanup #{f}`"
cleanup.periodic_clean! else
elsif f.latest_version_installed? && !cleanup.skip_clean_formula?(f)
ohai "Running `brew cleanup #{f}`..." ohai "Running `brew cleanup #{f}`..."
puts_no_install_cleanup_disable_message_if_not_already!
cleanup.cleanup_formula(f)
end end
puts_no_install_cleanup_disable_message_if_not_already!
return if dry_run
Cleanup.new.cleanup_formula(f)
end end
def self.puts_no_install_cleanup_disable_message_if_not_already! def self.puts_no_install_cleanup_disable_message
return if Homebrew::EnvConfig.no_env_hints? return if Homebrew::EnvConfig.no_env_hints?
return if Homebrew::EnvConfig.no_install_cleanup? return if Homebrew::EnvConfig.no_install_cleanup?
return if @puts_no_install_cleanup_disable_message_if_not_already
puts "Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP." puts "Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP."
puts "Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`)." puts "Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`)."
end
def self.puts_no_install_cleanup_disable_message_if_not_already!
return if @puts_no_install_cleanup_disable_message_if_not_already
puts_no_install_cleanup_disable_message
@puts_no_install_cleanup_disable_message_if_not_already = true @puts_no_install_cleanup_disable_message_if_not_already = true
end end
def skip_clean_formula?(f) def self.skip_clean_formula?(f)
return false if Homebrew::EnvConfig.no_cleanup_formulae.blank? return false if Homebrew::EnvConfig.no_cleanup_formulae.blank?
skip_clean_formulae = Homebrew::EnvConfig.no_cleanup_formulae.split(",") skip_clean_formulae = Homebrew::EnvConfig.no_cleanup_formulae.split(",")
skip_clean_formulae.include?(f.name) || (skip_clean_formulae & f.aliases).present? skip_clean_formulae.include?(f.name) || (skip_clean_formulae & f.aliases).present?
end end
def periodic_clean_due? def self.periodic_clean_due?
return false if Homebrew::EnvConfig.no_install_cleanup? return false if Homebrew::EnvConfig.no_install_cleanup?
unless PERIODIC_CLEAN_FILE.exist? unless PERIODIC_CLEAN_FILE.exist?
@ -196,29 +205,33 @@ module Homebrew
PERIODIC_CLEAN_FILE.mtime < CLEANUP_DEFAULT_DAYS.days.ago PERIODIC_CLEAN_FILE.mtime < CLEANUP_DEFAULT_DAYS.days.ago
end end
def periodic_clean! def self.periodic_clean!(dry_run: false)
return false unless periodic_clean_due? return if Homebrew::EnvConfig.no_install_cleanup?
return unless periodic_clean_due?
if dry_run? if dry_run
ohai "Would run `brew cleanup` which has not been run in the last #{CLEANUP_DEFAULT_DAYS} days" oh1 "Would run `brew cleanup` which has not been run in the last #{CLEANUP_DEFAULT_DAYS} days"
else else
ohai "`brew cleanup` has not been run in the last #{CLEANUP_DEFAULT_DAYS} days, running now..." oh1 "`brew cleanup` has not been run in the last #{CLEANUP_DEFAULT_DAYS} days, running now..."
end end
Cleanup.puts_no_install_cleanup_disable_message_if_not_already! puts_no_install_cleanup_disable_message
return if dry_run? return if dry_run
clean!(quiet: true, periodic: true) Cleanup.new.clean!(quiet: true, periodic: true)
end end
def clean!(quiet: false, periodic: false) def clean!(quiet: false, periodic: false)
if args.empty? if args.empty?
Formula.installed Formula.installed
.sort_by(&:name) .sort_by(&:name)
.reject { |f| skip_clean_formula?(f) } .reject { |f| Cleanup.skip_clean_formula?(f) }
.each do |formula| .each do |formula|
cleanup_formula(formula, quiet: quiet, ds_store: false, cache_db: false) cleanup_formula(formula, quiet: quiet, ds_store: false, cache_db: false)
end end
Cleanup.autoremove(dry_run: dry_run?) if Homebrew::EnvConfig.autoremove?
cleanup_cache cleanup_cache
cleanup_logs cleanup_logs
cleanup_lockfiles cleanup_lockfiles
@ -253,7 +266,7 @@ module Homebrew
nil nil
end end
if formula && skip_clean_formula?(formula) if formula && Cleanup.skip_clean_formula?(formula)
onoe "Refusing to clean #{formula} because it is listed in " \ onoe "Refusing to clean #{formula} because it is listed in " \
"#{Tty.bold}HOMEBREW_NO_CLEANUP_FORMULAE#{Tty.reset}!" "#{Tty.bold}HOMEBREW_NO_CLEANUP_FORMULAE#{Tty.reset}!"
elsif formula elsif formula
@ -519,5 +532,36 @@ module Homebrew
print "and #{d} directories " if d.positive? print "and #{d} directories " if d.positive?
puts "from #{HOMEBREW_PREFIX}" puts "from #{HOMEBREW_PREFIX}"
end end
def self.autoremove(dry_run: false)
require "cask/caskroom"
# If this runs after install, uninstall, reinstall or upgrade,
# the cache of installed formulae may no longer be valid.
Formula.clear_cache unless dry_run
# Remove formulae listed in HOMEBREW_NO_CLEANUP_FORMULAE.
formulae = Formula.installed.reject(&method(:skip_clean_formula?))
casks = Cask::Caskroom.casks
removable_formulae = Formula.unused_formulae_with_no_dependents(formulae, casks)
return if removable_formulae.blank?
formulae_names = removable_formulae.map(&:full_name).sort
verb = dry_run ? "Would autoremove" : "Autoremoving"
oh1 "#{verb} #{formulae_names.count} unneeded #{"formula".pluralize(formulae_names.count)}:"
puts formulae_names.join("\n")
return if dry_run
require "uninstall"
kegs_by_rack = removable_formulae.map(&:any_installed_keg).group_by(&:rack)
Uninstall.uninstall_kegs(kegs_by_rack)
# The installed formula cache will be invalid after uninstalling.
Formula.clear_cache
end
end end
end end

View File

@ -303,6 +303,15 @@ module Homebrew
sig { returns(T.nilable(String)) } sig { returns(T.nilable(String)) }
def screen_saverdir; end def screen_saverdir; end
sig { returns(T::Array[String])}
def repositories; end
sig { returns(T.nilable(String)) }
def from; end
sig { returns(T.nilable(String)) }
def to; end
sig { returns(T.nilable(T::Array[String])) } sig { returns(T.nilable(T::Array[String])) }
def groups; end def groups; end

View File

@ -1,9 +1,8 @@
# typed: true # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "formula" require "cleanup"
require "cli/parser" require "cli/parser"
require "uninstall"
module Homebrew module Homebrew
module_function module_function
@ -20,37 +19,9 @@ module Homebrew
end end
end end
def get_removable_formulae(formulae)
removable_formulae = Formula.installed_formulae_with_no_dependents(formulae).reject do |f|
Tab.for_keg(f.any_installed_keg).installed_on_request
end
removable_formulae += get_removable_formulae(formulae - removable_formulae) if removable_formulae.present?
removable_formulae
end
def autoremove def autoremove
args = autoremove_args.parse args = autoremove_args.parse
removable_formulae = get_removable_formulae(Formula.installed) Cleanup.autoremove(dry_run: args.dry_run?)
if (casks = Cask::Caskroom.casks.presence)
removable_formulae -= casks.flat_map { |cask| cask.depends_on[:formula] }
.compact
.map { |f| Formula[f] }
.flat_map { |f| [f, *f.runtime_formula_dependencies].compact }
end
return if removable_formulae.blank?
formulae_names = removable_formulae.map(&:full_name).sort
verb = args.dry_run? ? "Would uninstall" : "Uninstalling"
oh1 "#{verb} #{formulae_names.count} unneeded #{"formula".pluralize(formulae_names.count)}:"
puts formulae_names.join("\n")
return if args.dry_run?
kegs_by_rack = removable_formulae.map(&:any_installed_keg).group_by(&:rack)
Uninstall.uninstall_kegs(kegs_by_rack)
end end
end end

View File

@ -61,6 +61,9 @@ module Homebrew
switch "--all", switch "--all",
depends_on: "--json", depends_on: "--json",
description: "Print JSON of all available formulae." description: "Print JSON of all available formulae."
switch "--variations",
depends_on: "--json",
description: "Include the variations hash in each formula's JSON output."
switch "-v", "--verbose", switch "-v", "--verbose",
description: "Show more verbose analytics data for <formula>." description: "Show more verbose analytics data for <formula>."
switch "--formula", "--formulae", switch "--formula", "--formulae",
@ -202,6 +205,8 @@ module Homebrew
if args.bottle? if args.bottle?
formulae.map(&:to_recursive_bottle_hash) formulae.map(&:to_recursive_bottle_hash)
elsif args.variations?
formulae.map(&:to_hash_with_variations)
else else
formulae.map(&:to_hash) formulae.map(&:to_hash)
end end
@ -216,6 +221,11 @@ module Homebrew
if args.bottle? if args.bottle?
{ "formulae" => formulae.map(&:to_recursive_bottle_hash) } { "formulae" => formulae.map(&:to_recursive_bottle_hash) }
elsif args.variations?
{
"formulae" => formulae.map(&:to_hash_with_variations),
"casks" => casks.map(&:to_hash_with_variations),
}
else else
{ {
"formulae" => formulae.map(&:to_hash), "formulae" => formulae.map(&:to_hash),

View File

@ -260,6 +260,8 @@ module Homebrew
verbose: args.verbose?, verbose: args.verbose?,
) )
Cleanup.periodic_clean!
Homebrew.messages.display_messages(display_times: args.display_times?) Homebrew.messages.display_messages(display_times: args.display_times?)
rescue FormulaUnreadableError, FormulaClassUnavailableError, rescue FormulaUnreadableError, FormulaClassUnavailableError,
TapFormulaUnreadableError, TapFormulaClassUnavailableError => e TapFormulaUnreadableError, TapFormulaClassUnavailableError => e

View File

@ -37,7 +37,7 @@ module Homebrew
def leaves def leaves
args = leaves_args.parse args = leaves_args.parse
leaves_list = Formula.installed_formulae_with_no_dependents leaves_list = Formula.formulae_with_no_formula_dependents(Formula.installed)
leaves_list.select!(&method(:installed_on_request?)) if args.installed_on_request? leaves_list.select!(&method(:installed_on_request?)) if args.installed_on_request?
leaves_list.select!(&method(:installed_as_dependency?)) if args.installed_as_dependency? leaves_list.select!(&method(:installed_as_dependency?)) if args.installed_as_dependency?

View File

@ -158,6 +158,8 @@ module Homebrew
) )
end end
Cleanup.periodic_clean!
Homebrew.messages.display_messages(display_times: args.display_times?) Homebrew.messages.display_messages(display_times: args.display_times?)
end end
end end

View File

@ -82,6 +82,8 @@ module Homebrew
search_names(query, string_or_regex, args) search_names(query, string_or_regex, args)
end end
puts "Use `brew desc` to list packages with a short description." if args.verbose?
print_regex_help(args) print_regex_help(args)
end end

View File

@ -50,6 +50,11 @@ module Homebrew
all_kegs: args.force?, all_kegs: args.force?,
) )
# If ignore_unavailable is true and the named args
# are a series of invalid kegs and casks,
# #to_kegs_to_casks will return empty arrays.
return if all_kegs.blank? && casks.blank?
kegs_by_rack = all_kegs.group_by(&:rack) kegs_by_rack = all_kegs.group_by(&:rack)
Uninstall.uninstall_kegs( Uninstall.uninstall_kegs(
@ -73,5 +78,7 @@ module Homebrew
force: args.force?, force: args.force?,
) )
end end
Cleanup.autoremove if Homebrew::EnvConfig.autoremove?
end end
end end

View File

@ -148,6 +148,8 @@ module Homebrew
Homebrew.failed = true if ENV["HOMEBREW_UPDATE_FAILED"] Homebrew.failed = true if ENV["HOMEBREW_UPDATE_FAILED"]
return if Homebrew::EnvConfig.disable_load_formula? return if Homebrew::EnvConfig.disable_load_formula?
migrate_gcc_dependents_if_needed
hub = ReporterHub.new hub = ReporterHub.new
updated_taps = [] updated_taps = []
@ -289,6 +291,33 @@ module Homebrew
#{e} #{e}
EOS EOS
end end
def migrate_gcc_dependents_if_needed
return if OS.mac?
return if Settings.read("gcc-rpaths.fixed") == "true"
Formula.installed.each do |formula|
next unless formula.tap&.core_tap?
recursive_runtime_dependencies = Dependency.expand(
formula,
cache_key: "update-report",
) do |_, dependency|
Dependency.prune if dependency.build? || dependency.test?
end
next unless recursive_runtime_dependencies.map(&:name).include? "gcc"
keg = formula.installed_kegs.last
tab = Tab.for_keg(keg)
# Force reinstallation upon `brew upgrade` to fix the bottle RPATH.
tab.source["versions"]["version_scheme"] = -1
tab.write
rescue TapFormulaUnavailableError
nil
end
Settings.write "gcc-rpaths.fixed", true
end
end end
class Reporter class Reporter

View File

@ -556,6 +556,9 @@ EOS
[[ -d "${DIR}/.git" ]] || continue [[ -d "${DIR}/.git" ]] || continue
cd "${DIR}" || continue cd "${DIR}" || continue
# Git's fsmonitor prevents the release of our locks
git config --bool core.fsmonitor false
if ! git config --local --get remote.origin.url &>/dev/null if ! git config --local --get remote.origin.url &>/dev/null
then then
opoo "No remote 'origin' in ${DIR}, skipping update!" opoo "No remote 'origin' in ${DIR}, skipping update!"
@ -603,13 +606,13 @@ EOS
# Only try to `git fetch` when the upstream tags have changed # Only try to `git fetch` when the upstream tags have changed
# (so the API does not return 304: unmodified). # (so the API does not return 304: unmodified).
GITHUB_API_ETAG="$(sed -n 's/^ETag: "\([a-f0-9]\{32\}\)".*/\1/p' ".git/GITHUB_HEADERS" 2>/dev/null)" GITHUB_API_ETAG="$(sed -n 's/^ETag: "\([a-f0-9]\{32\}\)".*/\1/p' ".git/GITHUB_HEADERS" 2>/dev/null)"
GITHUB_API_ACCEPT="application/vnd.github.v3+json" GITHUB_API_ACCEPT="application/vnd.github+json"
GITHUB_API_ENDPOINT="tags" GITHUB_API_ENDPOINT="tags"
else else
# Only try to `git fetch` when the upstream branch is at a different SHA # Only try to `git fetch` when the upstream branch is at a different SHA
# (so the API does not return 304: unmodified). # (so the API does not return 304: unmodified).
GITHUB_API_ETAG="$(git rev-parse "refs/remotes/origin/${UPSTREAM_BRANCH_DIR}")" GITHUB_API_ETAG="$(git rev-parse "refs/remotes/origin/${UPSTREAM_BRANCH_DIR}")"
GITHUB_API_ACCEPT="application/vnd.github.v3.sha" GITHUB_API_ACCEPT="application/vnd.github.sha"
GITHUB_API_ENDPOINT="commits/${UPSTREAM_BRANCH_DIR}" GITHUB_API_ENDPOINT="commits/${UPSTREAM_BRANCH_DIR}"
fi fi

View File

@ -115,6 +115,8 @@ module Homebrew
upgrade_outdated_formulae(formulae, args: args) unless only_upgrade_casks upgrade_outdated_formulae(formulae, args: args) unless only_upgrade_casks
upgrade_outdated_casks(casks, args: args) unless only_upgrade_formulae upgrade_outdated_casks(casks, args: args) unless only_upgrade_formulae
Cleanup.periodic_clean!(dry_run: args.dry_run?)
Homebrew.messages.display_messages(display_times: args.display_times?) Homebrew.messages.display_messages(display_times: args.display_times?)
end end

View File

@ -1,10 +1,12 @@
# typed: true # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "simulate_system"
module Homebrew module Homebrew
DEFAULT_PREFIX, DEFAULT_REPOSITORY = if OS.mac? && Hardware::CPU.arm? DEFAULT_PREFIX, DEFAULT_REPOSITORY = if OS.mac? && Hardware::CPU.arm?
[HOMEBREW_MACOS_ARM_DEFAULT_PREFIX, HOMEBREW_MACOS_ARM_DEFAULT_REPOSITORY] [HOMEBREW_MACOS_ARM_DEFAULT_PREFIX, HOMEBREW_MACOS_ARM_DEFAULT_REPOSITORY]
elsif OS.linux? && !EnvConfig.simulate_macos_on_linux? elsif Homebrew::SimulateSystem.simulating_or_running_on_linux?
[HOMEBREW_LINUX_DEFAULT_PREFIX, HOMEBREW_LINUX_DEFAULT_REPOSITORY] [HOMEBREW_LINUX_DEFAULT_PREFIX, HOMEBREW_LINUX_DEFAULT_REPOSITORY]
else else
[HOMEBREW_DEFAULT_PREFIX, HOMEBREW_DEFAULT_REPOSITORY] [HOMEBREW_DEFAULT_PREFIX, HOMEBREW_DEFAULT_REPOSITORY]

View File

@ -161,7 +161,7 @@ class DependencyCollector
elsif strategy <= FossilDownloadStrategy elsif strategy <= FossilDownloadStrategy
Dependency.new("fossil", tags) Dependency.new("fossil", tags)
elsif strategy <= BazaarDownloadStrategy elsif strategy <= BazaarDownloadStrategy
Dependency.new("bazaar", tags) Dependency.new("breezy", tags)
elsif strategy <= CVSDownloadStrategy elsif strategy <= CVSDownloadStrategy
cvs_dep_if_needed(tags) cvs_dep_if_needed(tags)
elsif strategy < AbstractDownloadStrategy elsif strategy < AbstractDownloadStrategy

View File

@ -243,8 +243,8 @@ module Homebrew
elsif new_tag.present? elsif new_tag.present?
[ [
[ [
/#{formula_spec.specs[:tag]}(?=")/, /tag:(\s+")#{formula_spec.specs[:tag]}(?=")/,
new_tag, "tag:\\1#{new_tag}\\2",
], ],
[ [
formula_spec.specs[:revision], formula_spec.specs[:revision],

View File

@ -0,0 +1,109 @@
# typed: true
# frozen_string_literal: true
require "cli/parser"
module Homebrew
extend T::Sig
module_function
SUPPORTED_REPOS = [
%w[brew core cask],
OFFICIAL_CMD_TAPS.keys.map { |t| t.delete_prefix("homebrew/") },
OFFICIAL_CASK_TAPS.reject { |t| t == "cask" },
].flatten.freeze
sig { returns(CLI::Parser) }
def contributions_args
Homebrew::CLI::Parser.new do
usage_banner "`contributions` <email|name> [<--repositories>`=`]"
description <<~EOS
Contributions to Homebrew repos for a user.
The first argument is a name (e.g. "BrewTestBot") or an email address (e.g. "brewtestbot@brew.sh").
EOS
comma_array "--repositories",
description: "Specify a comma-separated (no spaces) list of repositories to search. " \
"Supported repositories: #{SUPPORTED_REPOS.map { |t| "`#{t}`" }.to_sentence}." \
"Omitting this flag, or specifying `--repositories=all`, will search all repositories."
flag "--from=",
description: "Date (ISO-8601 format) to start searching contributions."
flag "--to=",
description: "Date (ISO-8601 format) to stop searching contributions."
named_args number: 1
end
end
sig { void }
def contributions
args = contributions_args.parse
commits = 0
coauthorships = 0
all_repos = args.repositories.nil? || args.repositories.include?("all")
repos = all_repos ? SUPPORTED_REPOS : args.repositories
repos.each do |repo|
if SUPPORTED_REPOS.exclude?(repo)
return ofail "Unsupported repository: #{repo}. Try one of #{SUPPORTED_REPOS.join(", ")}."
end
repo_path = find_repo_path_for_repo(repo)
unless repo_path.exist?
opoo "Repository #{repo} not yet tapped! Tapping it now..."
Tap.fetch("homebrew", repo).install
end
commits += git_log_author_cmd(T.must(repo_path), args)
coauthorships += git_log_coauthor_cmd(T.must(repo_path), args)
end
sentence = "#{args.named.first} directly authored #{commits} commits " \
"and co-authored #{coauthorships} commits " \
"across #{all_repos ? "all Homebrew repos" : repos.to_sentence}"
sentence += if args.from && args.to
" between #{args.from} and #{args.to}"
elsif args.from
" after #{args.from}"
elsif args.to
" before #{args.to}"
else
" in all time"
end
sentence += "."
puts sentence
end
sig { params(repo: String).returns(Pathname) }
def find_repo_path_for_repo(repo)
return HOMEBREW_REPOSITORY if repo == "brew"
Tap.fetch("homebrew", repo).path
end
sig { params(repo_path: Pathname, args: Homebrew::CLI::Args).returns(Integer) }
def git_log_author_cmd(repo_path, args)
cmd = ["git", "-C", repo_path, "log", "--oneline", "--author=#{args.named.first}"]
cmd << "--before=#{args.to}" if args.to
cmd << "--after=#{args.from}" if args.from
Utils.safe_popen_read(*cmd).lines.count
end
sig { params(repo_path: Pathname, args: Homebrew::CLI::Args).returns(Integer) }
def git_log_coauthor_cmd(repo_path, args)
cmd = ["git", "-C", repo_path, "log", "--oneline"]
cmd << "--format='%(trailers:key=Co-authored-by:)'"
cmd << "--before=#{args.to}" if args.to
cmd << "--after=#{args.from}" if args.from
Utils.safe_popen_read(*cmd).lines.count { |l| l.include?(args.named.first) }
end
end

View File

@ -368,6 +368,49 @@ module Homebrew
end end
end end
def pr_check_conflicts(user, repo, pr)
long_build_pr_files = GitHub.search_issues(
"org:#{user}", repo: repo, state: "open", label: "\"no long build conflict\""
).each_with_object({}) do |long_build_pr, hash|
number = long_build_pr["number"]
next if number == pr.to_i
GitHub.get_pull_request_changed_files("#{user}/#{repo}", number).each do |file|
key = file["filename"]
hash[key] ||= []
hash[key] << number
end
end
this_pr_files = GitHub.get_pull_request_changed_files("#{user}/#{repo}", pr)
conflicts = this_pr_files.each_with_object({}) do |file, hash|
filename = file["filename"]
next unless long_build_pr_files.key?(filename)
long_build_pr_files[filename].each do |pr_number|
key = "#{user}/#{repo}/pull/#{pr_number}"
hash[key] ||= []
hash[key] << filename
end
end
return if conflicts.blank?
# Raise an error, display the conflicting PR. For example:
# Error: You are trying to merge a pull request that conflicts with a long running build in:
# {
# "homebrew-core/pull/98809": [
# "Formula/icu4c.rb",
# "Formula/node@10.rb"
# ]
# }
odie <<~EOS
You are trying to merge a pull request that conflicts with a long running build in:
#{JSON.pretty_generate(conflicts)}
EOS
end
def pr_pull def pr_pull
args = pr_pull_args.parse args = pr_pull_args.parse
@ -397,6 +440,8 @@ module Homebrew
opoo "Current branch is #{tap.path.git_branch}: do you need to pull inside #{tap.path.git_origin_branch}?" opoo "Current branch is #{tap.path.git_branch}: do you need to pull inside #{tap.path.git_origin_branch}?"
end end
pr_check_conflicts(user, repo, pr)
ohai "Fetching #{tap} pull request ##{pr}" ohai "Fetching #{tap} pull request ##{pr}"
Dir.mktmpdir pr do |dir| Dir.mktmpdir pr do |dir|
cd dir do cd dir do

View File

@ -88,7 +88,7 @@ module Homebrew
def tests def tests
args = tests_args.parse args = tests_args.parse
Homebrew.install_bundler_gems!(groups: ["sorbet"]) Homebrew.install_bundler_gems!
require "byebug" if args.byebug? require "byebug" if args.byebug?

View File

@ -52,7 +52,8 @@ module Homebrew
"master" "master"
end end
start_commit, end_commit = nil start_commit = nil
end_commit = "HEAD"
cd HOMEBREW_REPOSITORY do cd HOMEBREW_REPOSITORY do
start_commit = if (commit = args.commit) start_commit = if (commit = args.commit)
commit commit
@ -79,14 +80,13 @@ module Homebrew
# ^0 ensures this points to the commit rather than the tag object. # ^0 ensures this points to the commit rather than the tag object.
"#{previous_tag}^0" "#{previous_tag}^0"
else else
Utils.popen_read("git", "rev-parse", "origin/master").chomp Utils.popen_read("git", "merge-base", "origin/master", end_commit).chomp
end end
odie "Could not find start commit!" if start_commit.empty? odie "Could not find start commit!" if start_commit.empty?
start_commit = Utils.popen_read("git", "rev-parse", start_commit).chomp start_commit = Utils.popen_read("git", "rev-parse", start_commit).chomp
odie "Could not find start commit!" if start_commit.empty? odie "Could not find start commit!" if start_commit.empty?
end_commit ||= "HEAD"
end_commit = Utils.popen_read("git", "rev-parse", end_commit).chomp end_commit = Utils.popen_read("git", "rev-parse", end_commit).chomp
odie "Could not find end commit!" if end_commit.empty? odie "Could not find end commit!" if end_commit.empty?

View File

@ -1034,7 +1034,7 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy
output, _, status = curl_output( output, _, status = curl_output(
"--silent", "--head", "--location", "--silent", "--head", "--location",
"-H", "Accept: application/vnd.github.v3.sha", "-H", "Accept: application/vnd.github.sha",
"https://api.github.com/repos/#{@user}/#{@repo}/commits/#{@ref}" "https://api.github.com/repos/#{@user}/#{@repo}/commits/#{@ref}"
) )
@ -1051,7 +1051,7 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy
output, _, status = curl_output( output, _, status = curl_output(
"--silent", "--head", "--location", "--silent", "--head", "--location",
"-H", "Accept: application/vnd.github.v3.sha", "-H", "Accept: application/vnd.github.sha",
"https://api.github.com/repos/#{@user}/#{@repo}/commits/#{commit}" "https://api.github.com/repos/#{@user}/#{@repo}/commits/#{commit}"
) )
@ -1280,7 +1280,7 @@ class BazaarDownloadStrategy < VCSDownloadStrategy
def env def env
{ {
"PATH" => PATH.new(Formula["bazaar"].opt_bin, ENV.fetch("PATH")), "PATH" => PATH.new(Formula["breezy"].opt_bin, ENV.fetch("PATH")),
"BZR_HOME" => HOMEBREW_TEMP, "BZR_HOME" => HOMEBREW_TEMP,
} }
end end

View File

@ -36,6 +36,12 @@ module Homebrew
"disable auto-update entirely with HOMEBREW_NO_AUTO_UPDATE.", "disable auto-update entirely with HOMEBREW_NO_AUTO_UPDATE.",
default: 300, default: 300,
}, },
HOMEBREW_AUTOREMOVE: {
description: "If set, calls to `brew cleanup` and `brew uninstall` will automatically " \
"remove unused formula dependents and if HOMEBREW_NO_INSTALL_CLEANUP is not set, " \
"`brew cleanup` will start running `brew autoremove` periodically.",
boolean: true,
},
HOMEBREW_BAT: { HOMEBREW_BAT: {
description: "If set, use `bat` for the `brew cat` command.", description: "If set, use `bat` for the `brew cat` command.",
boolean: true, boolean: true,
@ -263,8 +269,8 @@ module Homebrew
boolean: true, boolean: true,
}, },
HOMEBREW_NO_CLEANUP_FORMULAE: { HOMEBREW_NO_CLEANUP_FORMULAE: {
description: "A comma-separated list of formulae. Homebrew will refuse to clean up a " \ description: "A comma-separated list of formulae. Homebrew will refuse to clean up " \
"formula if it appears on this list.", "or autoremove a formula if it appears on this list.",
}, },
HOMEBREW_NO_COLOR: { HOMEBREW_NO_COLOR: {
description: "If set, do not print text with colour added.", description: "If set, do not print text with colour added.",

View File

@ -15,25 +15,12 @@ module OnSystem
def arch_condition_met?(arch) def arch_condition_met?(arch)
raise ArgumentError, "Invalid arch condition: #{arch.inspect}" if ARCH_OPTIONS.exclude?(arch) raise ArgumentError, "Invalid arch condition: #{arch.inspect}" if ARCH_OPTIONS.exclude?(arch)
current_arch = Homebrew::SimulateSystem.arch || Hardware::CPU.type arch == Homebrew::SimulateSystem.current_arch
arch == current_arch
end end
sig { params(os_name: Symbol, or_condition: T.nilable(Symbol)).returns(T::Boolean) } sig { params(os_name: Symbol, or_condition: T.nilable(Symbol)).returns(T::Boolean) }
def os_condition_met?(os_name, or_condition = nil) def os_condition_met?(os_name, or_condition = nil)
if Homebrew::EnvConfig.simulate_macos_on_linux? return Homebrew::SimulateSystem.send("simulating_or_running_on_#{os_name}?") if BASE_OS_OPTIONS.include?(os_name)
return false if os_name == :linux
return true if [:macos, *MacOSVersions::SYMBOLS.keys].include?(os_name)
end
if BASE_OS_OPTIONS.include?(os_name)
if Homebrew::SimulateSystem.none?
return OS.linux? if os_name == :linux
return OS.mac? if os_name == :macos
end
return Homebrew::SimulateSystem.send("#{os_name}?")
end
raise ArgumentError, "Invalid OS condition: #{os_name.inspect}" unless MacOSVersions::SYMBOLS.key?(os_name) raise ArgumentError, "Invalid OS condition: #{os_name.inspect}" unless MacOSVersions::SYMBOLS.key?(os_name)
@ -41,10 +28,16 @@ module OnSystem
raise ArgumentError, "Invalid OS `or_*` condition: #{or_condition.inspect}" raise ArgumentError, "Invalid OS `or_*` condition: #{or_condition.inspect}"
end end
return false if Homebrew::SimulateSystem.linux? || (Homebrew::SimulateSystem.none? && OS.linux?) return false if Homebrew::SimulateSystem.simulating_or_running_on_linux?
base_os = MacOS::Version.from_symbol(os_name) base_os = MacOS::Version.from_symbol(os_name)
current_os = MacOS::Version.from_symbol(Homebrew::SimulateSystem.os || MacOS.version.to_sym) current_os = if Homebrew::SimulateSystem.current_os == :macos
# Assume the oldest macOS version when simulating a generic macOS version
# Version::NULL is always treated as less than any other version.
Version::NULL
else
MacOS::Version.from_symbol(Homebrew::SimulateSystem.current_os)
end
return current_os >= base_os if or_condition == :or_newer return current_os >= base_os if or_condition == :or_newer
return current_os <= base_os if or_condition == :or_older return current_os <= base_os if or_condition == :or_older
@ -72,6 +65,13 @@ module OnSystem
result result
end end
end end
base.define_method(:on_arch_conditional) do |arm: nil, intel: nil|
@on_system_blocks_exist = true
return arm if OnSystem.arch_condition_met? :arm
return intel if OnSystem.arch_condition_met? :intel
end
end end
sig { params(base: Class).void } sig { params(base: Class).void }

View File

@ -36,9 +36,21 @@ module Superenv
paths paths
end end
def homebrew_extra_isystem_paths
paths = []
# Add paths for GCC headers when building against glibc@2.13 because we have to use -nostdinc.
if deps.any? { |d| d.name == "glibc@2.13" }
gcc_include_dir = Utils.safe_popen_read(cc, "--print-file-name=include").chomp
gcc_include_fixed_dir = Utils.safe_popen_read(cc, "--print-file-name=include-fixed").chomp
paths << gcc_include_dir << gcc_include_fixed_dir
end
paths
end
def determine_rpath_paths(formula) def determine_rpath_paths(formula)
PATH.new( PATH.new(
*formula&.lib, *formula&.lib,
"#{HOMEBREW_PREFIX}/opt/gcc/lib/gcc/current",
PATH.new(run_time_deps.map { |dep| dep.opt_lib.to_s }).existing, PATH.new(run_time_deps.map { |dep| dep.opt_lib.to_s }).existing,
"#{HOMEBREW_PREFIX}/lib", "#{HOMEBREW_PREFIX}/lib",
) )

View File

@ -23,17 +23,4 @@ class Formula
sig { params(targets: T.nilable(T.any(Pathname, String))).void } sig { params(targets: T.nilable(T.any(Pathname, String))).void }
def deuniversalize_machos(*targets); end def deuniversalize_machos(*targets); end
class << self
undef ignore_missing_libraries
def ignore_missing_libraries(*libs)
libraries = libs.flatten
if libraries.any? { |x| !x.is_a?(String) && !x.is_a?(Regexp) }
raise FormulaSpecificationError, "#{__method__} can handle Strings and Regular Expressions only"
end
allowed_missing_libraries.merge(libraries)
end
end
end end

View File

@ -8,9 +8,6 @@ class Keg
# Patching the dynamic linker of glibc breaks it. # Patching the dynamic linker of glibc breaks it.
return if name.match? Version.formula_optionally_versioned_regex(:glibc) return if name.match? Version.formula_optionally_versioned_regex(:glibc)
# Patching patchelf fails with "Text file busy" or SIGBUS.
return if name == "patchelf"
old_prefix, new_prefix = relocation.replacement_pair_for(:prefix) old_prefix, new_prefix = relocation.replacement_pair_for(:prefix)
elf_files.each do |file| elf_files.each do |file|
@ -33,6 +30,18 @@ class Keg
lib_path = "#{new_prefix}/lib" lib_path = "#{new_prefix}/lib"
rpath << lib_path unless rpath.include? lib_path rpath << lib_path unless rpath.include? lib_path
# Add GCC's lib directory (as of GCC 12+) to RPATH when there is existing linkage.
# This fixes linkage for newly-poured bottles.
if !name.match?(Version.formula_optionally_versioned_regex(:gcc)) &&
rpath.any? { |rp| rp.match?(%r{lib/gcc/\d+$}) }
# TODO: Replace with
# rpath.map! { |path| path = path.sub(%r{lib/gcc/\d+$}, "lib/gcc/current") }
# when
# 1. Homebrew/homebrew-core#106755 is merged
# 2. No formula has a runtime dependency on a versioned GCC (see `envoy.rb`)
rpath.prepend HOMEBREW_PREFIX/"opt/gcc/lib/gcc/current"
end
rpath.join(":") rpath.join(":")
end end
updated[:rpath] = new_rpath if old_rpath != new_rpath updated[:rpath] = new_rpath if old_rpath != new_rpath
@ -80,16 +89,4 @@ class Keg
end end
elf_files elf_files
end end
def self.bottle_dependencies
@bottle_dependencies ||= begin
formulae = []
gcc = Formulary.factory(CompilerSelector.preferred_gcc)
if !Homebrew::EnvConfig.simulate_macos_on_linux? &&
DevelopmentTools.non_apple_gcc_version("gcc") < gcc.version.to_i
formulae << gcc
end
formulae
end
end
end end

View File

@ -72,6 +72,9 @@ class LinkageChecker
@unwanted_system_dylibs = @system_dylibs.reject do |s| @unwanted_system_dylibs = @system_dylibs.reject do |s|
SYSTEM_LIBRARY_ALLOWLIST.include? File.basename(s) SYSTEM_LIBRARY_ALLOWLIST.include? File.basename(s)
end end
@undeclared_deps -= [CompilerSelector.preferred_gcc, "glibc"] # FIXME: Remove this when these dependencies are injected correctly (e.g. through `DependencyCollector`)
# See discussion at
# https://github.com/Homebrew/brew/pull/13577
@undeclared_deps -= [CompilerSelector.preferred_gcc, "glibc", "gcc"]
end end
end end

View File

@ -1,27 +0,0 @@
# typed: true
# frozen_string_literal: true
# The Library/Homebrew/extend/os/software_spec.rb conditional logic will need to be more nuanced
# if this file ever includes more than `uses_from_macos`.
class SoftwareSpec
undef uses_from_macos
def uses_from_macos(deps, bounds = {})
if deps.is_a?(Hash)
bounds = deps.dup
deps = [bounds.shift].to_h
end
@uses_from_macos_elements << deps
bounds = bounds.transform_values { |v| MacOS::Version.from_symbol(v) }
# Linux simulating macOS. Assume oldest macOS version.
return if Homebrew::EnvConfig.simulate_macos_on_linux? && !bounds.key?(:since)
# macOS new enough for dependency to not be required.
return if MacOS.version >= bounds[:since]
depends_on deps
end
end

View File

@ -1,9 +1,4 @@
# typed: strict # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
# This logic will need to be more nuanced if this file includes more than `uses_from_macos`. require "extend/os/linux/software_spec" if OS.linux?
if OS.mac? || Homebrew::EnvConfig.simulate_macos_on_linux?
require "extend/os/mac/software_spec"
elsif OS.linux?
require "extend/os/linux/software_spec"
end

View File

@ -69,9 +69,6 @@ class Formula
extend Cachable extend Cachable
extend Predicable extend Predicable
# @!method inreplace(paths, before = nil, after = nil)
# @see Utils::Inreplace.inreplace
# The name of this {Formula}. # The name of this {Formula}.
# e.g. `this-formula` # e.g. `this-formula`
attr_reader :name attr_reader :name
@ -1706,14 +1703,46 @@ class Formula
end.uniq(&:name) end.uniq(&:name)
end end
# An array of all installed {Formula} without dependents # An array of all installed {Formula} with {Cask} dependents.
# @private # @private
def self.installed_formulae_with_no_dependents(formulae = installed) def self.formulae_with_cask_dependents(casks)
casks.flat_map { |cask| cask.depends_on[:formula] }
.compact
.map { |f| Formula[f] }
.flat_map { |f| [f, *f.runtime_formula_dependencies].compact }
end
# An array of all installed {Formula} without {Formula} dependents
# @private
def self.formulae_with_no_formula_dependents(formulae)
return [] if formulae.blank? return [] if formulae.blank?
formulae - formulae.flat_map(&:runtime_formula_dependencies) formulae - formulae.flat_map(&:runtime_formula_dependencies)
end end
# Recursive function that returns an array of {Formula} without
# {Formula} dependents that weren't installed on request.
# @private
def self.unused_formulae_with_no_formula_dependents(formulae)
unused_formulae = formulae_with_no_formula_dependents(formulae).reject do |f|
Tab.for_keg(f.any_installed_keg).installed_on_request
end
if unused_formulae.present?
unused_formulae += unused_formulae_with_no_formula_dependents(formulae - unused_formulae)
end
unused_formulae
end
# An array of {Formula} without {Formula} or {Cask}
# dependents that weren't installed on request.
# @private
def self.unused_formulae_with_no_dependents(formulae, casks)
unused_formulae = unused_formulae_with_no_formula_dependents(formulae)
unused_formulae - formulae_with_cask_dependents(casks)
end
def self.installed_with_alias_path(alias_path) def self.installed_with_alias_path(alias_path)
return [] if alias_path.nil? return [] if alias_path.nil?
@ -2005,6 +2034,45 @@ class Formula
hsh hsh
end end
# @private
def to_hash_with_variations
hash = to_hash
variations = {}
os_versions = [*MacOSVersions::SYMBOLS.keys, :linux]
if path.exist? && self.class.on_system_blocks_exist?
formula_contents = path.read
[:arm, :intel].each do |arch|
os_versions.each do |os_name|
bottle_tag = Utils::Bottles::Tag.new(system: os_name, arch: arch)
next unless bottle_tag.valid_combination?
Homebrew::SimulateSystem.os = os_name
Homebrew::SimulateSystem.arch = arch
variations_namespace = Formulary.class_s("Variations#{bottle_tag.to_sym.capitalize}")
variations_formula_class = Formulary.load_formula(name, path, formula_contents, variations_namespace,
flags: self.class.build_flags, ignore_errors: true)
variations_formula = variations_formula_class.new(name, path, :stable,
alias_path: alias_path, force_bottle: force_bottle)
variations_formula.to_hash.each do |key, value|
next if value.to_s == hash[key].to_s
variations[bottle_tag.to_sym] ||= {}
variations[bottle_tag.to_sym][key] = value
end
end
end
end
Homebrew::SimulateSystem.clear
hash["variations"] = variations
hash
end
# @api private # @api private
# Generate a hash to be used to install a formula from a JSON file # Generate a hash to be used to install a formula from a JSON file
def to_recursive_bottle_hash(top_level: true) def to_recursive_bottle_hash(top_level: true)
@ -2130,6 +2198,30 @@ class Formula
# end</pre> # end</pre>
def install; end def install; end
# Sometimes we have to change a bit before we install. Mostly we
# prefer a patch, but if you need the {Formula#prefix prefix} of
# this formula in the patch you have to resort to `inreplace`,
# because in the patch you don't have access to any variables
# defined by the formula, as only `HOMEBREW_PREFIX` is available
# in the {DATAPatch embedded patch}.
#
# `inreplace` supports regular expressions:
# <pre>inreplace "somefile.cfg", /look[for]what?/, "replace by #{bin}/tool"</pre>
#
# `inreplace` supports blocks:
# <pre>inreplace "Makefile" do |s|
# s.gsub! "/usr/local", HOMEBREW_PREFIX.to_s
# end
# </pre>
#
# @see Utils::Inreplace.inreplace
# @api public
def inreplace(paths, before = nil, after = nil, audit_result = true) # rubocop:disable Style/OptionalBooleanParameter
super(paths, before, after, audit_result)
rescue Utils::Inreplace::Error
raise BuildError.new(self, "inreplace", paths, nil)
end
protected protected
def setup_home(home) def setup_home(home)
@ -2469,6 +2561,7 @@ class Formula
# The methods below define the formula DSL. # The methods below define the formula DSL.
class << self class << self
extend Predicable
include BuildEnvironment::DSL include BuildEnvironment::DSL
include OnSystem::MacOSAndLinux include OnSystem::MacOSAndLinux
@ -2483,6 +2576,11 @@ class Formula
end end
end end
# Whether this formula contains OS/arch-specific blocks
# (e.g. `on_macos`, `on_arm`, `on_monterey :or_older`, `on_system :linux, macos: :big_sur_or_newer`).
# @private
attr_predicate :on_system_blocks_exist?
# The reason for why this software is not linked (by default) to # The reason for why this software is not linked (by default) to
# {::HOMEBREW_PREFIX}. # {::HOMEBREW_PREFIX}.
# @private # @private
@ -3169,8 +3267,17 @@ class Formula
end end
# Permit links to certain libraries that don't exist. Available on Linux only. # Permit links to certain libraries that don't exist. Available on Linux only.
def ignore_missing_libraries(*) def ignore_missing_libraries(*libs)
raise FormulaSpecificationError, "#{__method__} is available on Linux only" unless Homebrew::SimulateSystem.simulating_or_running_on_linux?
raise FormulaSpecificationError, "#{__method__} is available on Linux only"
end
libraries = libs.flatten
if libraries.any? { |x| !x.is_a?(String) && !x.is_a?(Regexp) }
raise FormulaSpecificationError, "#{__method__} can handle Strings and Regular Expressions only"
end
allowed_missing_libraries.merge(libraries)
end end
# @private # @private

View File

@ -49,6 +49,7 @@ class Formula
def env; end def env; end
def conflicts; end def conflicts; end
def self.on_system_blocks_exist?; end
# This method is included by `OnSystem` # This method is included by `OnSystem`
def self.on_macos(&block); end def self.on_macos(&block); end
end end

View File

@ -307,6 +307,13 @@ module Homebrew
EOS EOS
end end
if dep_f.deprecated? && !formula.deprecated? && !formula.disabled?
problem <<~EOS
Dependency '#{dep.name}' is deprecated but has un-deprecated dependents. Either
un-deprecate '#{dep.name}' or deprecate it and all of its dependents.
EOS
end
# we want to allow uses_from_macos for aliases but not bare dependencies # we want to allow uses_from_macos for aliases but not bare dependencies
if self.class.aliases.include?(dep.name) && spec.uses_from_macos_names.exclude?(dep.name) if self.class.aliases.include?(dep.name) && spec.uses_from_macos_names.exclude?(dep.name)
problem "Dependency '#{dep.name}' is an alias; use the canonical name '#{dep.to_formula.full_name}'." problem "Dependency '#{dep.name}' is an alias; use the canonical name '#{dep.to_formula.full_name}'."
@ -329,7 +336,7 @@ module Homebrew
# The number of conflicts on Linux is absurd. # The number of conflicts on Linux is absurd.
# TODO: remove this and check these there too. # TODO: remove this and check these there too.
return if OS.linux? && !Homebrew::EnvConfig.simulate_macos_on_linux? return if Homebrew::SimulateSystem.simulating_or_running_on_linux?
recursive_runtime_formulae = formula.runtime_formula_dependencies(undeclared: false) recursive_runtime_formulae = formula.runtime_formula_dependencies(undeclared: false)
version_hash = {} version_hash = {}
@ -410,13 +417,11 @@ module Homebrew
end end
def audit_glibc def audit_glibc
return if formula.name != "glibc"
return unless @core_tap return unless @core_tap
return if formula.name != "glibc"
return if [OS::CI_GLIBC_VERSION, "2.27", "2.31", "2.35"].include?(formula.version.to_s)
version = formula.version.to_s problem "The glibc version must be #{OS::CI_GLIBC_VERSION}, as this is the version used by our CI on Linux. " \
return if version == OS::CI_GLIBC_VERSION
problem "The glibc version must be #{version}, as this is the version used by our CI on Linux. " \
"Glibc is for users who have a system Glibc with a lower version, " \ "Glibc is for users who have a system Glibc with a lower version, " \
"which allows them to use our Linux bottles, which were compiled against system Glibc on CI." "which allows them to use our Linux bottles, which were compiled against system Glibc on CI."
end end

View File

@ -136,6 +136,18 @@ module Formulary
class_s = Formulary.class_s(name) class_s = Formulary.class_s(name)
json_formula = Homebrew::API::Formula.all_formulae[name] json_formula = Homebrew::API::Formula.all_formulae[name]
if (bottle_tag = Utils::Bottles.tag.to_s.presence) &&
(variations = json_formula["variations"].presence) &&
(variation = variations[bottle_tag].presence)
json_formula = json_formula.merge(variation)
end
uses_from_macos_names = json_formula["uses_from_macos"].map do |dep|
next dep unless dep.is_a? Hash
dep.keys.first
end
klass = Class.new(::Formula) do klass = Class.new(::Formula) do
desc json_formula["desc"] desc json_formula["desc"]
homepage json_formula["homepage"] homepage json_formula["homepage"]
@ -176,20 +188,18 @@ module Formulary
disable! date: disable_date, because: reason disable! date: disable_date, because: reason
end end
json_formula["build_dependencies"].each do |dep|
depends_on dep => :build
end
json_formula["dependencies"].each do |dep| json_formula["dependencies"].each do |dep|
next if uses_from_macos_names.include? dep
depends_on dep depends_on dep
end end
json_formula["recommended_dependencies"].each do |dep| [:build, :recommended, :optional].each do |type|
depends_on dep => :recommended json_formula["#{type}_dependencies"].each do |dep|
end next if uses_from_macos_names.include? dep
json_formula["optional_dependencies"].each do |dep| depends_on dep => type
depends_on dep => :optional end
end end
json_formula["uses_from_macos"].each do |dep| json_formula["uses_from_macos"].each do |dep|
@ -264,6 +274,7 @@ module Formulary
end end
def self.convert_to_deprecate_disable_reason_string_or_symbol(string) def self.convert_to_deprecate_disable_reason_string_or_symbol(string)
require "deprecate_disable"
return string unless DeprecateDisable::DEPRECATE_DISABLE_REASONS.keys.map(&:to_s).include?(string) return string unless DeprecateDisable::DEPRECATE_DISABLE_REASONS.keys.map(&:to_s).include?(string)
string.to_sym string.to_sym

View File

@ -368,7 +368,14 @@ class Keg
end end
def self.bottle_dependencies def self.bottle_dependencies
[] return [] unless Homebrew::SimulateSystem.simulating_or_running_on_linux?
@bottle_dependencies ||= begin
formulae = []
gcc = Formulary.factory(CompilerSelector.preferred_gcc)
formulae << gcc if DevelopmentTools.non_apple_gcc_version("gcc") < gcc.version.to_i
formulae
end
end end
end end

View File

@ -111,7 +111,8 @@ module Language
raise ShebangDetectionError.new("Python", "formula has multiple Python dependencies") raise ShebangDetectionError.new("Python", "formula has multiple Python dependencies")
end end
python_shebang_rewrite_info(Formula[python_deps.first].opt_bin/"python3") python_dep = python_deps.first
python_shebang_rewrite_info(Formula[python_dep].opt_bin/python_dep.sub("@", ""))
end end
end end

View File

@ -198,7 +198,7 @@ class LinkageChecker
# In macOS Big Sur and later, system libraries do not exist on-disk and instead exist in a cache. # In macOS Big Sur and later, system libraries do not exist on-disk and instead exist in a cache.
# If dlopen finds the dylib, then the linkage is not broken. # If dlopen finds the dylib, then the linkage is not broken.
@system_dylibs << dylib @system_dylibs << dylib
else elsif !system_framework?(dylib)
@broken_dylibs << dylib @broken_dylibs << dylib
end end
else else
@ -306,11 +306,13 @@ class LinkageChecker
def harmless_broken_link?(dylib) def harmless_broken_link?(dylib)
# libgcc_s_* is referenced by programs that use the Java Service Wrapper, # libgcc_s_* is referenced by programs that use the Java Service Wrapper,
# and is harmless on x86(_64) machines # and is harmless on x86(_64) machines
return true if [ [
"/usr/lib/libgcc_s_ppc64.1.dylib", "/usr/lib/libgcc_s_ppc64.1.dylib",
"/opt/local/lib/libgcc/libgcc_s.1.dylib", "/opt/local/lib/libgcc/libgcc_s.1.dylib",
].include?(dylib) ].include?(dylib)
end
def system_framework?(dylib)
dylib.start_with?("/System/Library/Frameworks/") dylib.start_with?("/System/Library/Frameworks/")
end end

View File

@ -143,7 +143,8 @@ class Livecheck
end end
delegate version: :@package_or_resource delegate version: :@package_or_resource
private :version delegate arch: :@package_or_resource
private :version, :arch
# Returns a `Hash` of all instance variable values. # Returns a `Hash` of all instance variable values.
# @return [Hash] # @return [Hash]

View File

@ -3,7 +3,9 @@
OFFICIAL_CASK_TAPS = %w[ OFFICIAL_CASK_TAPS = %w[
cask cask
versions cask-drivers
cask-fonts
cask-versions
].freeze ].freeze
OFFICIAL_CMD_TAPS = { OFFICIAL_CMD_TAPS = {

View File

@ -105,7 +105,7 @@ module Homebrew
# Ideally `ca-certificates` would not be excluded here, but sourcing a HTTP mirror was tricky. # Ideally `ca-certificates` would not be excluded here, but sourcing a HTTP mirror was tricky.
# Instead, we have logic elsewhere to pass `--insecure` to curl when downloading the certs. # Instead, we have logic elsewhere to pass `--insecure` to curl when downloading the certs.
# TODO: try remove the OS/env conditional # TODO: try remove the OS/env conditional
if (OS.mac? || Homebrew::EnvConfig.simulate_macos_on_linux?) && spec_name == :stable && if Homebrew::SimulateSystem.simulating_or_running_on_macos? && spec_name == :stable &&
owner.name != "ca-certificates" && curl_dep && !urls.find { |u| u.start_with?("http://") } owner.name != "ca-certificates" && curl_dep && !urls.find { |u| u.start_with?("http://") }
problem "should always include at least one HTTP mirror" problem "should always include at least one HTTP mirror"
end end

View File

@ -14,12 +14,6 @@ module RuboCop
class ComponentsOrder < FormulaCop class ComponentsOrder < FormulaCop
extend AutoCorrector extend AutoCorrector
def on_system_methods
@on_system_methods ||= [:intel, :arm, :macos, :linux, *MacOSVersions::SYMBOLS.keys].map do |m|
:"on_#{m}"
end
end
def audit_formula(_node, _class_node, _parent_class_node, body_node) def audit_formula(_node, _class_node, _parent_class_node, body_node)
@present_components, @offensive_nodes = check_order(FORMULA_COMPONENT_PRECEDENCE_LIST, body_node) @present_components, @offensive_nodes = check_order(FORMULA_COMPONENT_PRECEDENCE_LIST, body_node)
@ -116,6 +110,15 @@ module RuboCop
end end
def check_on_system_block_content(component_precedence_list, on_system_block) def check_on_system_block_content(component_precedence_list, on_system_block)
if on_system_block.body.block_type? && !on_system_methods.include?(on_system_block.body.method_name)
offending_node(on_system_block)
problem "Nest `#{on_system_block.method_name}` blocks inside `#{on_system_block.body.method_name}` " \
"blocks when there is only one inner block." do |corrector|
original_source = on_system_block.source.split("\n")
new_source = [original_source.second, original_source.first, *original_source.drop(2)]
corrector.replace(on_system_block.source_range, new_source.join("\n"))
end
end
on_system_allowed_methods = %w[ on_system_allowed_methods = %w[
depends_on depends_on
patch patch

View File

@ -16,7 +16,7 @@ module RuboCop
def audit_formula(_node, _class_node, _parent_class_node, body_node) def audit_formula(_node, _class_node, _parent_class_node, body_node)
check_dependency_nodes_order(body_node) check_dependency_nodes_order(body_node)
check_uses_from_macos_nodes_order(body_node) check_uses_from_macos_nodes_order(body_node)
[:head, :stable].each do |block_name| ([:head, :stable] + on_system_methods).each do |block_name|
block = find_block(body_node, block_name) block = find_block(body_node, block_name)
next unless block next unless block

View File

@ -198,6 +198,12 @@ module RuboCop
@file_path !~ Regexp.union(paths_to_exclude) @file_path !~ Regexp.union(paths_to_exclude)
end end
def on_system_methods
@on_system_methods ||= [:intel, :arm, :macos, :linux, :system, *MacOSVersions::SYMBOLS.keys].map do |m|
:"on_#{m}"
end
end
end end
end end
end end

View File

@ -1,6 +1,7 @@
# typed: true # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "macos_versions"
require "rubocops/extend/formula" require "rubocops/extend/formula"
module RuboCop module RuboCop
@ -375,61 +376,171 @@ module RuboCop
# This cop makes sure that OS conditionals are consistent. # This cop makes sure that OS conditionals are consistent.
# #
# @api private # @api private
class OSConditionals < FormulaCop class OnSystemConditionals < FormulaCop
extend AutoCorrector extend AutoCorrector
NO_ON_SYSTEM_METHOD_NAMES = [:install, :post_install].freeze
NO_ON_SYSTEM_BLOCK_NAMES = [:service, :test].freeze
ON_ARCH_OPTIONS = [:intel, :arm].freeze
ON_BASE_OS_OPTIONS = [:macos, :linux].freeze
ON_MACOS_VERSION_OPTIONS = MacOSVersions::SYMBOLS.keys.freeze
ALL_SYSTEM_OPTIONS = [*ON_ARCH_OPTIONS, *ON_BASE_OS_OPTIONS, *ON_MACOS_VERSION_OPTIONS, :system].freeze
MACOS_VERSION_CONDITIONALS = {
"==" => nil,
"<=" => :or_older,
">=" => :or_newer,
}.freeze
ON_SYSTEM_CONDITIONALS = [:<, :<=].freeze
def on_system_method_info(on_system_option)
info = {}
info[:method] = :"on_#{on_system_option}"
info[:if_module], info[:if_method] = if ON_ARCH_OPTIONS.include?(on_system_option)
["Hardware::CPU", :"#{on_system_option}?"]
elsif ON_BASE_OS_OPTIONS.include?(on_system_option)
["OS", on_system_option == :macos ? :mac? : :linux?]
else
["MacOS", :version]
end
info[:on_system_string] = "on_#{on_system_option}"
info[:if_string] = if on_system_option == :system
"if OS.linux? || MacOS.version"
else
"if #{info[:if_module]}.#{info[:if_method]}"
end
info
end
def audit_formula(_node, _class_node, _parent_class_node, body_node) def audit_formula(_node, _class_node, _parent_class_node, body_node)
no_on_os_method_names = [:install, :post_install].freeze top_level_nodes_to_check = []
no_on_os_block_names = [:service, :test].freeze NO_ON_SYSTEM_METHOD_NAMES.each do |formula_method_name|
[[:on_macos, :mac?], [:on_linux, :linux?]].each do |on_method_name, if_method_name| method_node = find_method_def(body_node, formula_method_name)
if_method_and_class = "if OS.#{if_method_name}" top_level_nodes_to_check << [formula_method_name, method_node] if method_node
no_on_os_method_names.each do |formula_method_name| end
method_node = find_method_def(body_node, formula_method_name) NO_ON_SYSTEM_BLOCK_NAMES.each do |formula_block_name|
next unless method_node block_node = find_block(body_node, formula_block_name)
next unless method_called_ever?(method_node, on_method_name) top_level_nodes_to_check << [formula_block_name, block_node] if block_node
end
problem "Don't use '#{on_method_name}' in 'def #{formula_method_name}', " \ ALL_SYSTEM_OPTIONS.each do |on_system_option|
"use '#{if_method_and_class}' instead." do |corrector| method_info = on_system_method_info(on_system_option)
block_node = offending_node.parent
next if block_node.type != :block
# TODO: could fix corrector to handle this but punting for now. top_level_nodes_to_check.each do |top_level_name, top_level_node|
next if block_node.single_line? top_level_node_string = if top_level_node.def_type?
"def #{top_level_name}"
else
"#{top_level_name} do"
end
source_range = offending_node.source_range.join(offending_node.parent.loc.begin) find_every_method_call_by_name(top_level_node, method_info[:method]).each do |method|
corrector.replace(source_range, if_method_and_class) if ON_MACOS_VERSION_OPTIONS.include?(on_system_option)
on_macos_version_method_call(method, on_method: method_info[:method]) do |on_method_parameters|
if on_method_parameters.empty?
method_info[:if_string] = "if MacOS.version == :#{on_system_option}"
else
method_info[:on_system_string] = "#{method_info[:method]} :#{on_method_parameters.first}"
if_condition_operator = MACOS_VERSION_CONDITIONALS.key(on_method_parameters.first)
method_info[:if_string] = "if MacOS.version #{if_condition_operator} :#{on_system_option}"
end
end
elsif method_info[:method] == :on_system
on_system_method_call(method) do |macos_symbol|
base_os, condition = macos_symbol.to_s.split(/_(?=or_)/).map(&:to_sym)
method_info[:on_system_string] = if condition.present?
"on_system :linux, macos: :#{base_os}_#{condition}"
else
"on_system :linux, macos: :#{base_os}"
end
if_condition_operator = MACOS_VERSION_CONDITIONALS.key(condition)
method_info[:if_string] = "if OS.linux? || MacOS.version #{if_condition_operator} :#{base_os}"
end
end
offending_node(method)
problem "Don't use `#{method_info[:on_system_string]}` in `#{top_level_node_string}`, " \
"use `#{method_info[:if_string]}` instead." do |corrector|
block_node = offending_node.parent
next if block_node.type != :block
# TODO: could fix corrector to handle this but punting for now.
next if block_node.single_line?
source_range = offending_node.source_range.join(offending_node.parent.loc.begin)
corrector.replace(source_range, method_info[:if_string])
end
end
end
end
# Don't restrict OS.mac? or OS.linux? usage in taps; they don't care
# as much as we do about e.g. formulae.brew.sh generation, often use
# platform-specific URLs and we don't want to add DSLs to support
# that case.
return if formula_tap != "homebrew-core"
ALL_SYSTEM_OPTIONS.each do |on_system_option|
method_info = on_system_method_info(on_system_option)
if_nodes_to_check = []
if ON_ARCH_OPTIONS.include?(on_system_option)
if_arch_node_search(body_node, arch: method_info[:if_method]) do |if_node, else_node|
else_info = if else_node.present?
{
can_autocorrect: true,
on_system_method: on_system_option == :intel ? "on_arm" : "on_intel",
node: else_node,
}
end
if_nodes_to_check << [if_node, else_info]
end
elsif ON_BASE_OS_OPTIONS.include?(on_system_option)
if_base_os_node_search(body_node, base_os: method_info[:if_method]) do |if_node, else_node|
else_info = if else_node.present?
{
can_autocorrect: true,
on_system_method: on_system_option == :macos ? "on_linux" : "on_macos",
node: else_node,
}
end
if_nodes_to_check << [if_node, else_info]
end
else
if_macos_version_node_search(body_node, os_name: on_system_option) do |if_node, operator, else_node|
if operator == :<
method_info[:on_system_string] = "on_system"
elsif operator == :<=
method_info[:on_system_string] = "on_system :linux, macos: :#{on_system_option}_or_older"
elsif operator != :== && MACOS_VERSION_CONDITIONALS.key?(operator.to_s)
method_info[:on_system_string] = "#{method_info[:method]} " \
":#{MACOS_VERSION_CONDITIONALS[operator.to_s]}"
end
method_info[:if_string] = "if #{method_info[:if_module]}.#{method_info[:if_method]} #{operator} " \
":#{on_system_option}"
if else_node.present? || !MACOS_VERSION_CONDITIONALS.key?(operator.to_s)
else_info = { can_autocorrect: false }
end
if_nodes_to_check << [if_node, else_info]
end end
end end
no_on_os_block_names.each do |formula_block_name| if_nodes_to_check.each do |if_node, else_info|
block_node = find_block(body_node, formula_block_name) # TODO: check to see if it's legal
next unless block_node
next unless block_method_called_in_block?(block_node, on_method_name)
problem "Don't use '#{on_method_name}' in '#{formula_block_name} do', " \
"use '#{if_method_and_class}' instead." do |corrector|
# TODO: could fix corrector to handle this but punting for now.
next if offending_node.single_line?
source_range = offending_node.send_node.source_range.join(offending_node.body.source_range.begin)
corrector.replace(source_range, "#{if_method_and_class}\n")
end
end
# Don't restrict OS.mac? or OS.linux? usage in taps; they don't care
# as much as we do about e.g. formulae.brew.sh generation, often use
# platform-specific URLs and we don't want to add DSLs to support
# that case.
next if formula_tap != "homebrew-core"
find_instance_method_call(body_node, "OS", if_method_name) do |method|
valid = T.let(false, T::Boolean) valid = T.let(false, T::Boolean)
method.each_ancestor do |ancestor| if_node.each_ancestor do |ancestor|
valid_method_names = case ancestor.type valid_method_names = case ancestor.type
when :def when :def
no_on_os_method_names NO_ON_SYSTEM_METHOD_NAMES
when :block when :block
no_on_os_block_names NO_ON_SYSTEM_BLOCK_NAMES
else else
next next
end end
@ -440,19 +551,47 @@ module RuboCop
end end
next if valid next if valid
offending_node(method) offending_node(if_node)
problem "Don't use '#{if_method_and_class}', use '#{on_method_name} do' instead." do |corrector|
if_node = method.parent
next if if_node.type != :if
problem "Don't use `#{method_info[:if_string]}`, " \
"use `#{method_info[:on_system_string]} do` instead." do |corrector|
# TODO: could fix corrector to handle this but punting for now. # TODO: could fix corrector to handle this but punting for now.
next if if_node.unless? next if if_node.unless?
corrector.replace(if_node.source_range, "#{on_method_name} do\n#{if_node.body.source}\nend") if else_info.present?
next unless else_info[:can_autocorrect]
corrector.replace(if_node.source_range,
"#{method_info[:on_system_string]} do\n#{if_node.body.source}\nend\n" \
"#{else_info[:on_system_method]} do\n#{else_info[:node].source}\nend")
else
corrector.replace(if_node.source_range,
"#{method_info[:on_system_string]} do\n#{if_node.body.source}\nend")
end
end end
end end
end end
end end
def_node_matcher :on_macos_version_method_call, <<~PATTERN
(send nil? %on_method (sym ${:or_newer :or_older})?)
PATTERN
def_node_matcher :on_system_method_call, <<~PATTERN
(send nil? :on_system (sym :linux) (hash (pair (sym :macos) (sym $_))))
PATTERN
def_node_search :if_arch_node_search, <<~PATTERN
$(if (send (const (const nil? :Hardware) :CPU) %arch) _ $_)
PATTERN
def_node_search :if_base_os_node_search, <<~PATTERN
$(if (send (const nil? :OS) %base_os) _ $_)
PATTERN
def_node_search :if_macos_version_node_search, <<~PATTERN
$(if (send (send (const nil? :MacOS) :version) ${:== :<= :< :>= :> :!=} (sym %os_name)) _ $_)
PATTERN
end end
# This cop checks for other miscellaneous style violations. # This cop checks for other miscellaneous style violations.

View File

@ -0,0 +1,24 @@
# typed: strict
module RuboCop
module Cop
module FormulaAudit
class OnSystemConditionals < FormulaCop
sig { params(node: T.any, on_method: Symbol, block: T.proc.params(parameters: T::Array[T.any]).void).void }
def on_macos_version_method_call(node, on_method:, &block); end
sig { params(node: T.any, block: T.proc.params(macos_symbol: Symbol).void).void }
def on_system_method_call(node, &block); end
sig { params(node: T.any, arch: Symbol, block: T.proc.params(node: T.any, else_node: T.any).void).void }
def if_arch_node_search(node, arch:, &block); end
sig { params(node: T.any, base_os: Symbol, block: T.proc.params(node: T.any, else_node: T.any).void).void }
def if_base_os_node_search(node, base_os:, &block); end
sig { params(node: T.any, os_name: Symbol, block: T.proc.params(node: T.any, operator: Symbol, else_node: T.any).void).void }
def if_macos_version_node_search(node, os_name:, &block); end
end
end
end
end

View File

@ -82,6 +82,7 @@ module RuboCop
git git
groff groff
gzip gzip
less
openssl openssl
perl perl
php php

View File

@ -376,6 +376,14 @@ module Homebrew
base[:StartCalendarInterval] = @cron.reject { |_, value| value == "*" } base[:StartCalendarInterval] = @cron.reject { |_, value| value == "*" }
end end
# Adding all session types has as the primary effect that if you initialise it through e.g. a Background session
# and you later "physically" sign in to the owning account (Aqua session), things shouldn't flip out.
# Also, we're not checking @process_type here because that is used to indicate process priority and not
# necessarily if it should run in a specific session type. Like database services could run with ProcessType
# Interactive so they have no resource limitations enforced upon them, but they aren't really interactive in the
# general sense.
base[:LimitLoadToSessionType] = %w[Aqua Background LoginWindow StandardIO System]
base.to_plist base.to_plist
end end

View File

@ -305,7 +305,11 @@ class Cmd
end end
def cppflags def cppflags
path_flags("-isystem", isystem_paths) + path_flags("-I", include_paths) args = []
args += path_flags("-isystem", isystem_paths) + path_flags("-I", include_paths)
# Add -nostdinc when building against glibc@2.13 to avoid mixing system and brewed glibc headers.
args << "-nostdinc" if @deps.include?("glibc@2.13")
args
end end
def ldflags_mac(args) def ldflags_mac(args)
@ -323,10 +327,17 @@ class Cmd
def ldflags_linux(args) def ldflags_linux(args)
unless mode == :ld unless mode == :ld
wl = "-Wl," wl = "-Wl,"
args << "-B#{@opt}/glibc/lib" if @deps.include?("glibc@2.13")
args << "-B#{@opt}/glibc@2.13/lib"
else
args << "-B#{@opt}/glibc/lib"
end
end end
args += rpath_flags("#{wl}-rpath=", rpath_paths) args += rpath_flags("#{wl}-rpath=", rpath_paths)
args += ["#{wl}--dynamic-linker=#{dynamic_linker_path}"] if dynamic_linker_path args += ["#{wl}--dynamic-linker=#{dynamic_linker_path}"] if dynamic_linker_path
# Use -rpath-link to make sure linker uses glibc@2.13 rather than the system glibc for indirect
# dependencies because -L will only handle direct dependencies.
args << "#{wl}-rpath-link=#{@opt}/glibc@2.13/lib" if @deps.include?("glibc@2.13")
args args
end end

View File

@ -9,7 +9,14 @@ module Homebrew
class << self class << self
extend T::Sig extend T::Sig
attr_reader :os, :arch attr_reader :arch
sig { returns(T.nilable(Symbol)) }
def os
return :macos if @os.blank? && !OS.mac? && Homebrew::EnvConfig.simulate_macos_on_linux?
@os
end
sig { params(new_os: Symbol).void } sig { params(new_os: Symbol).void }
def os=(new_os) def os=(new_os)
@ -32,18 +39,30 @@ module Homebrew
end end
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def none? def simulating_or_running_on_macos?
@os.nil? && @arch.nil? return OS.mac? if os.blank?
[:macos, *MacOSVersions::SYMBOLS.keys].include?(os)
end end
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def macos? def simulating_or_running_on_linux?
[:macos, *MacOSVersions::SYMBOLS.keys].include?(@os) return OS.linux? if os.blank?
os == :linux
end end
sig { returns(T::Boolean) } sig { returns(Symbol) }
def linux? def current_arch
@os == :linux @arch || Hardware::CPU.type
end
sig { returns(Symbol) }
def current_os
return T.must(os) if os.present?
return :linux if OS.linux?
MacOS.version.to_sym
end end
end end
end end

View File

@ -162,12 +162,27 @@ class SoftwareSpec
add_dep_option(dep) if dep add_dep_option(dep) if dep
end end
def uses_from_macos(spec, _bounds = {}) def uses_from_macos(deps, bounds = {})
spec = [spec.dup.shift].to_h if spec.is_a?(Hash) if deps.is_a?(Hash)
bounds = deps.dup
deps = [bounds.shift].to_h
end
@uses_from_macos_elements << spec @uses_from_macos_elements << deps
depends_on(spec) # Check whether macOS is new enough for dependency to not be required.
if Homebrew::SimulateSystem.simulating_or_running_on_macos?
# Assume the oldest macOS version when simulating a generic macOS version
return if Homebrew::SimulateSystem.current_os == :macos && !bounds.key?(:since)
if Homebrew::SimulateSystem.current_os != :macos
current_os = MacOS::Version.from_symbol(Homebrew::SimulateSystem.current_os)
since_os = MacOS::Version.from_symbol(bounds[:since]) if bounds.key?(:since)
return if current_os >= since_os
end
end
depends_on deps
end end
def uses_from_macos_names def uses_from_macos_names
@ -205,6 +220,8 @@ class SoftwareSpec
def patch(strip = :p1, src = nil, &block) def patch(strip = :p1, src = nil, &block)
p = Patch.create(strip, src, &block) p = Patch.create(strip, src, &block)
return if p.is_a?(ExternalPatch) && p.url.blank?
dependency_collector.add(p.resource) if p.is_a? ExternalPatch dependency_collector.add(p.resource) if p.is_a? ExternalPatch
patches << p patches << p
end end

View File

@ -6,6 +6,7 @@
module RuboCop; end module RuboCop; end
module RuboCop::Cop; end module RuboCop::Cop; end
RuboCop::Cop::IgnoredPattern = RuboCop::Cop::AllowedPattern
module RuboCop::Cop::Performance; end module RuboCop::Cop::Performance; end
class RuboCop::Cop::Performance::AncestorsInclude < ::RuboCop::Cop::Base class RuboCop::Cop::Performance::AncestorsInclude < ::RuboCop::Cop::Base

View File

@ -3157,13 +3157,15 @@ class RuboCop::Cop::Layout::LineContinuationLeadingSpace < ::RuboCop::Cop::Base
private private
def continuation?(line); end def continuation?(line); end
def investigate(first_line, second_line, range_start); end def enforced_style_leading?; end
def offense_range(range_start, matches); end def investigate_leading_style(first_line, end_of_first_line); end
def investigate_trailing_style(second_line, end_of_first_line); end
def leading_offense_range(end_of_first_line, matches); end
def message(_range); end
def raw_lines(node); end def raw_lines(node); end
def trailing_offense_range(end_of_first_line, matches); end
end end
RuboCop::Cop::Layout::LineContinuationLeadingSpace::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Layout::LineContinuationSpacing < ::RuboCop::Cop::Base class RuboCop::Cop::Layout::LineContinuationSpacing < ::RuboCop::Cop::Base
include ::RuboCop::Cop::RangeHelp include ::RuboCop::Cop::RangeHelp
extend ::RuboCop::Cop::AutoCorrector extend ::RuboCop::Cop::AutoCorrector
@ -3216,6 +3218,7 @@ class RuboCop::Cop::Layout::LineLength < ::RuboCop::Cop::Base
def max=(value); end def max=(value); end
def on_array(node); end def on_array(node); end
def on_block(node); end def on_block(node); end
def on_def(node); end
def on_hash(node); end def on_hash(node); end
def on_investigation_end; end def on_investigation_end; end
def on_new_investigation; end def on_new_investigation; end
@ -3417,6 +3420,15 @@ RuboCop::Cop::Layout::MultilineMethodDefinitionBraceLayout::ALWAYS_SAME_LINE_MES
RuboCop::Cop::Layout::MultilineMethodDefinitionBraceLayout::NEW_LINE_MESSAGE = T.let(T.unsafe(nil), String) RuboCop::Cop::Layout::MultilineMethodDefinitionBraceLayout::NEW_LINE_MESSAGE = T.let(T.unsafe(nil), String)
RuboCop::Cop::Layout::MultilineMethodDefinitionBraceLayout::SAME_LINE_MESSAGE = T.let(T.unsafe(nil), String) RuboCop::Cop::Layout::MultilineMethodDefinitionBraceLayout::SAME_LINE_MESSAGE = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Layout::MultilineMethodParameterLineBreaks < ::RuboCop::Cop::Base
include ::RuboCop::Cop::MultilineElementLineBreaks
extend ::RuboCop::Cop::AutoCorrector
def on_def(node); end
end
RuboCop::Cop::Layout::MultilineMethodParameterLineBreaks::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Layout::MultilineOperationIndentation < ::RuboCop::Cop::Base class RuboCop::Cop::Layout::MultilineOperationIndentation < ::RuboCop::Cop::Base
include ::RuboCop::Cop::ConfigurableEnforcedStyle include ::RuboCop::Cop::ConfigurableEnforcedStyle
include ::RuboCop::Cop::Alignment include ::RuboCop::Cop::Alignment
@ -5128,14 +5140,21 @@ class RuboCop::Cop::Lint::NonAtomicFileOperation < ::RuboCop::Cop::Base
def allowable_use_with_if?(if_node); end def allowable_use_with_if?(if_node); end
def autocorrect(corrector, node, range); end def autocorrect(corrector, node, range); end
def autocorrect_replace_method(corrector, node); end
def force_method?(node); end
def force_method_name?(node); end
def force_option?(node); end def force_option?(node); end
def message(node); end def if_node_child?(node); end
def message_remove_file_exist_check(node); end
def register_offense(node, exist_node); end def register_offense(node, exist_node); end
def replacement_method(node); end def replacement_method(node); end
end end
RuboCop::Cop::Lint::NonAtomicFileOperation::MAKE_FORCE_METHODS = T.let(T.unsafe(nil), Array)
RuboCop::Cop::Lint::NonAtomicFileOperation::MAKE_METHODS = T.let(T.unsafe(nil), Array) RuboCop::Cop::Lint::NonAtomicFileOperation::MAKE_METHODS = T.let(T.unsafe(nil), Array)
RuboCop::Cop::Lint::NonAtomicFileOperation::MSG = T.let(T.unsafe(nil), String) RuboCop::Cop::Lint::NonAtomicFileOperation::MSG_CHANGE_FORCE_METHOD = T.let(T.unsafe(nil), String)
RuboCop::Cop::Lint::NonAtomicFileOperation::MSG_REMOVE_FILE_EXIST_CHECK = T.let(T.unsafe(nil), String)
RuboCop::Cop::Lint::NonAtomicFileOperation::REMOVE_FORCE_METHODS = T.let(T.unsafe(nil), Array)
RuboCop::Cop::Lint::NonAtomicFileOperation::REMOVE_METHODS = T.let(T.unsafe(nil), Array) RuboCop::Cop::Lint::NonAtomicFileOperation::REMOVE_METHODS = T.let(T.unsafe(nil), Array)
RuboCop::Cop::Lint::NonAtomicFileOperation::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) RuboCop::Cop::Lint::NonAtomicFileOperation::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
@ -5554,6 +5573,13 @@ end
RuboCop::Cop::Lint::RequireParentheses::MSG = T.let(T.unsafe(nil), String) RuboCop::Cop::Lint::RequireParentheses::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Lint::RequireRangeParentheses < ::RuboCop::Cop::Base
def on_erange(node); end
def on_irange(node); end
end
RuboCop::Cop::Lint::RequireRangeParentheses::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Lint::RequireRelativeSelfPath < ::RuboCop::Cop::Base class RuboCop::Cop::Lint::RequireRelativeSelfPath < ::RuboCop::Cop::Base
include ::RuboCop::Cop::RangeHelp include ::RuboCop::Cop::RangeHelp
extend ::RuboCop::Cop::AutoCorrector extend ::RuboCop::Cop::AutoCorrector
@ -5605,6 +5631,7 @@ RuboCop::Cop::Lint::ReturnInVoidContext::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Lint::SafeNavigationChain < ::RuboCop::Cop::Base class RuboCop::Cop::Lint::SafeNavigationChain < ::RuboCop::Cop::Base
include ::RuboCop::Cop::AllowedMethods include ::RuboCop::Cop::AllowedMethods
include ::RuboCop::Cop::NilMethods include ::RuboCop::Cop::NilMethods
extend ::RuboCop::Cop::AutoCorrector
extend ::RuboCop::Cop::TargetRubyVersion extend ::RuboCop::Cop::TargetRubyVersion
def bad_method?(param0 = T.unsafe(nil)); end def bad_method?(param0 = T.unsafe(nil)); end
@ -5612,6 +5639,8 @@ class RuboCop::Cop::Lint::SafeNavigationChain < ::RuboCop::Cop::Base
private private
def add_safe_navigation_operator(offense_range:, send_node:); end
def autocorrect(corrector, offense_range:, send_node:); end
def method_chain(node); end def method_chain(node); end
end end
@ -7127,11 +7156,16 @@ module RuboCop::Cop::PercentArray
private private
def allowed_bracket_array?(node); end def allowed_bracket_array?(node); end
def build_bracketed_array_with_appropriate_whitespace(elements:, node:); end
def build_message_for_bracketed_array(preferred_array_code); end
def check_bracketed_array(node, literal_prefix); end def check_bracketed_array(node, literal_prefix); end
def check_percent_array(node); end def check_percent_array(node); end
def comments_in_array?(node); end def comments_in_array?(node); end
def invalid_percent_array_contents?(_node); end def invalid_percent_array_contents?(_node); end
def invalid_percent_array_context?(node); end def invalid_percent_array_context?(node); end
def whitespace_between(node); end
def whitespace_leading(node); end
def whitespace_trailing(node); end
end end
module RuboCop::Cop::PercentLiteral module RuboCop::Cop::PercentLiteral
@ -8551,6 +8585,16 @@ end
RuboCop::Cop::Style::EmptyElse::MSG = T.let(T.unsafe(nil), String) RuboCop::Cop::Style::EmptyElse::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Style::EmptyHeredoc < ::RuboCop::Cop::Base
include ::RuboCop::Cop::Heredoc
include ::RuboCop::Cop::RangeHelp
extend ::RuboCop::Cop::AutoCorrector
def on_heredoc(node); end
end
RuboCop::Cop::Style::EmptyHeredoc::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Style::EmptyLambdaParameter < ::RuboCop::Cop::Base class RuboCop::Cop::Style::EmptyLambdaParameter < ::RuboCop::Cop::Base
include ::RuboCop::Cop::EmptyParameter include ::RuboCop::Cop::EmptyParameter
include ::RuboCop::Cop::RangeHelp include ::RuboCop::Cop::RangeHelp
@ -8791,47 +8835,25 @@ RuboCop::Cop::Style::ExponentialNotation::MESSAGES = T.let(T.unsafe(nil), Hash)
class RuboCop::Cop::Style::FetchEnvVar < ::RuboCop::Cop::Base class RuboCop::Cop::Style::FetchEnvVar < ::RuboCop::Cop::Base
extend ::RuboCop::Cop::AutoCorrector extend ::RuboCop::Cop::AutoCorrector
def block_control?(param0 = T.unsafe(nil)); end
def env_with_bracket?(param0 = T.unsafe(nil)); end def env_with_bracket?(param0 = T.unsafe(nil)); end
def offensive_nodes(param0); end
def on_send(node); end def on_send(node); end
def operand_of_or?(param0 = T.unsafe(nil)); end
private private
def allowable_use?(node); end def allowable_use?(node); end
def allowed_var?(node); end def allowed_var?(node); end
def assigned?(node); end def assigned?(node); end
def configured_indentation; end
def conterpart_rhs_of(node); end
def default_nil(node, name_node); end
def default_rhs(node, name_node); end
def default_rhs_in_outer_or(node, name_node); end
def default_rhs_in_same_or(node, name_node); end
def default_to_rhs?(node); end
def first_line_of(source); end
def left_end_of_or_chains?(node); end
def message_chained_with_dot?(node); end def message_chained_with_dot?(node); end
def message_template_for(rhs); end def new_code(name_node); end
def new_code_default_nil(name_node); end
def new_code_default_rhs(node, name_node); end
def new_code_default_rhs_multiline(node, name_node); end
def new_code_default_rhs_single_line(node, name_node); end
def offensive?(node); end def offensive?(node); end
def or_chain_root(node); end def or_lhs?(node); end
def partial_matched?(node, condition); end def partial_matched?(node, condition); end
def rhs_can_be_default_value?(node); end
def rhs_is_block_control?(node); end
def right_end_of_or_chains?(node); end
def used_as_flag?(node); end def used_as_flag?(node); end
def used_if_condition_in_body(node); end def used_if_condition_in_body(node); end
def used_in_condition?(node, condition); end def used_in_condition?(node, condition); end
end end
RuboCop::Cop::Style::FetchEnvVar::MSG_DEFAULT_NIL = T.let(T.unsafe(nil), String) RuboCop::Cop::Style::FetchEnvVar::MSG = T.let(T.unsafe(nil), String)
RuboCop::Cop::Style::FetchEnvVar::MSG_DEFAULT_RHS_MULTILINE_BLOCK = T.let(T.unsafe(nil), String)
RuboCop::Cop::Style::FetchEnvVar::MSG_DEFAULT_RHS_SECOND_ARG_OF_FETCH = T.let(T.unsafe(nil), String)
RuboCop::Cop::Style::FetchEnvVar::MSG_DEFAULT_RHS_SINGLE_LINE_BLOCK = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Style::FileRead < ::RuboCop::Cop::Base class RuboCop::Cop::Style::FileRead < ::RuboCop::Cop::Base
include ::RuboCop::Cop::RangeHelp include ::RuboCop::Cop::RangeHelp
@ -11453,8 +11475,10 @@ class RuboCop::Cop::Style::Semicolon < ::RuboCop::Cop::Base
def check_for_line_terminator_or_opener; end def check_for_line_terminator_or_opener; end
def each_semicolon; end def each_semicolon; end
def expressions_per_line(exprs); end def expressions_per_line(exprs); end
def find_range_node(token_before_semicolon); end
def find_semicolon_positions(line); end def find_semicolon_positions(line); end
def register_semicolon(line, column, after_expression); end def range_nodes; end
def register_semicolon(line, column, after_expression, token_before_semicolon = T.unsafe(nil)); end
def tokens_for_lines; end def tokens_for_lines; end
class << self class << self
@ -11971,6 +11995,7 @@ class RuboCop::Cop::Style::TopLevelMethodDefinition < ::RuboCop::Cop::Base
end end
RuboCop::Cop::Style::TopLevelMethodDefinition::MSG = T.let(T.unsafe(nil), String) RuboCop::Cop::Style::TopLevelMethodDefinition::MSG = T.let(T.unsafe(nil), String)
RuboCop::Cop::Style::TopLevelMethodDefinition::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
class RuboCop::Cop::Style::TrailingBodyOnClass < ::RuboCop::Cop::Base class RuboCop::Cop::Style::TrailingBodyOnClass < ::RuboCop::Cop::Base
include ::RuboCop::Cop::Alignment include ::RuboCop::Cop::Alignment

View File

@ -4,7 +4,11 @@
# This is an autogenerated file for types exported from the `tzinfo` gem. # This is an autogenerated file for types exported from the `tzinfo` gem.
# Please instead update this file by running `bin/tapioca gem tzinfo`. # Please instead update this file by running `bin/tapioca gem tzinfo`.
module TZInfo; end module TZInfo
class << self
def eager_load!; end
end
end
class TZInfo::AbsoluteDayOfYearTransitionRule < ::TZInfo::DayOfYearTransitionRule class TZInfo::AbsoluteDayOfYearTransitionRule < ::TZInfo::DayOfYearTransitionRule
def initialize(day, transition_at = T.unsafe(nil)); end def initialize(day, transition_at = T.unsafe(nil)); end
@ -94,6 +98,7 @@ class TZInfo::DataSource
def country_codes; end def country_codes; end
def data_timezone_identifiers; end def data_timezone_identifiers; end
def eager_load!; end
def get_country_info(code); end def get_country_info(code); end
def get_timezone_info(identifier); end def get_timezone_info(identifier); end
def inspect; end def inspect; end
@ -275,6 +280,7 @@ end
TZInfo::DataSources::ZoneinfoDataSource::DEFAULT_ALTERNATE_ISO3166_TAB_SEARCH_PATH = T.let(T.unsafe(nil), Array) TZInfo::DataSources::ZoneinfoDataSource::DEFAULT_ALTERNATE_ISO3166_TAB_SEARCH_PATH = T.let(T.unsafe(nil), Array)
TZInfo::DataSources::ZoneinfoDataSource::DEFAULT_SEARCH_PATH = T.let(T.unsafe(nil), Array) TZInfo::DataSources::ZoneinfoDataSource::DEFAULT_SEARCH_PATH = T.let(T.unsafe(nil), Array)
TZInfo::DataSources::ZoneinfoDataSource::EXCLUDED_FILENAMES = T.let(T.unsafe(nil), Array)
class TZInfo::DataSources::ZoneinfoDirectoryNotFound < ::StandardError; end class TZInfo::DataSources::ZoneinfoDirectoryNotFound < ::StandardError; end
class TZInfo::DataSources::ZoneinfoReader class TZInfo::DataSources::ZoneinfoReader

View File

@ -2442,6 +2442,8 @@ module Homebrew::EnvConfig
def self.artifact_domain(); end def self.artifact_domain(); end
def self.autoremove?(); end
def self.auto_update_secs(); end def self.auto_update_secs(); end
def self.bat?(); end def self.bat?(); end

View File

@ -1,11 +1,47 @@
# typed: true # typed: true
# frozen_string_literal: true # frozen_string_literal: true
# Explicitly prevent `sorbet-runtime` from being loaded. require "sorbet-runtime"
def gem(name, *)
raise Gem::LoadError if name == "sorbet-runtime"
super # Disable runtime checking unless enabled.
# In the future we should consider not doing this monkey patch,
# if assured that there is no performance hit from removing this.
# There are mechanisms to achieve a middle ground (`default_checked_level`).
unless ENV["HOMEBREW_SORBET_RUNTIME"]
# Redefine T.let etc to make the `checked` parameter default to false rather than true.
# @private
module TNoChecks
def cast(value, type, checked: false)
super(value, type, checked: checked)
end
def let(value, type, checked: false)
super(value, type, checked: checked)
end
def bind(value, type, checked: false)
super(value, type, checked: checked)
end
def assert_type!(value, type, checked: false)
super(value, type, checked: checked)
end
end
# @private
module T
class << self
prepend TNoChecks
end
# Redefine T.sig to be noop.
# @private
module Sig
def sig(arg0 = nil, &blk); end
end
end
# For any cases the above doesn't handle: make sure we don't let TypeError slip through.
T::Configuration.call_validation_error_handler = ->(signature, opts) do end
T::Configuration.inline_type_error_handler = ->(error, opts) do end
end end
require "sorbet-runtime-stub"

View File

@ -7,4 +7,4 @@ require_relative "standalone/load_path"
require_relative "startup/ruby_path" require_relative "startup/ruby_path"
require "startup/config" require "startup/config"
require_relative "startup/bootsnap" require_relative "startup/bootsnap"
require_relative "startup/sorbet" require_relative "standalone/sorbet"

View File

@ -1,10 +0,0 @@
# typed: strict
# frozen_string_literal: true
if ENV["HOMEBREW_SORBET_RUNTIME"]
# This is only supported under the brew environment.
Homebrew.install_bundler_gems!(groups: ["sorbet"])
require "sorbet-runtime"
else
require "standalone/sorbet"
end

View File

@ -211,4 +211,64 @@ describe Cask::Cask, :cask do
end end
end end
end end
describe "#to_hash_with_variations" do
let!(:original_macos_version) { MacOS.full_version.to_s }
let(:expected_variations) {
<<~JSON
{
"arm64_big_sur": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin-arm64/1.2.0/arm.zip",
"version": "1.2.0",
"sha256": "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b"
},
"monterey": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin/1.2.3/intel.zip"
},
"big_sur": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin/1.2.0/intel.zip",
"version": "1.2.0",
"sha256": "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b"
},
"catalina": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin/1.0.0/intel.zip",
"version": "1.0.0",
"sha256": "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216"
},
"mojave": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin/1.0.0/intel.zip",
"version": "1.0.0",
"sha256": "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216"
}
}
JSON
}
before do
# Use a more limited symbols list to shorten the variations hash
symbols = {
monterey: "12",
big_sur: "11",
catalina: "10.15",
mojave: "10.14",
}
stub_const("MacOSVersions::SYMBOLS", symbols)
# For consistency, always run on Monterey and ARM
MacOS.full_version = "12"
allow(Hardware::CPU).to receive(:type).and_return(:arm)
end
after do
MacOS.full_version = original_macos_version
end
it "returns the correct variations hash" do
c = Cask::CaskLoader.load("multiple-versions")
h = c.to_hash_with_variations
expect(h).to be_a(Hash)
expect(JSON.pretty_generate(h["variations"])).to eq expected_variations.strip
end
end
end end

View File

@ -120,9 +120,7 @@ describe Cask::Cmd::List, :cask do
}, },
"conflicts_with": null, "conflicts_with": null,
"container": null, "container": null,
"auto_updates": null, "auto_updates": null
"variations": {
}
}, },
{ {
"token": "local-transmission", "token": "local-transmission",
@ -151,9 +149,7 @@ describe Cask::Cmd::List, :cask do
}, },
"conflicts_with": null, "conflicts_with": null,
"container": null, "container": null,
"auto_updates": null, "auto_updates": null
"variations": {
}
}, },
{ {
"token": "multiple-versions", "token": "multiple-versions",
@ -164,7 +160,7 @@ describe Cask::Cmd::List, :cask do
], ],
"desc": null, "desc": null,
"homepage": "https://brew.sh/", "homepage": "https://brew.sh/",
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.2.3/arm.zip", "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin-arm64/1.2.3/arm.zip",
"appcast": null, "appcast": null,
"version": "1.2.3", "version": "1.2.3",
"versions": { "versions": {
@ -185,32 +181,7 @@ describe Cask::Cmd::List, :cask do
}, },
"conflicts_with": null, "conflicts_with": null,
"container": null, "container": null,
"auto_updates": null, "auto_updates": null
"variations": {
"arm_big_sur": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.2.0/arm.zip",
"version": "1.2.0",
"sha256": "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b"
},
"intel_monterey": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.2.3/intel.zip"
},
"intel_big_sur": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.2.0/intel.zip",
"version": "1.2.0",
"sha256": "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b"
},
"intel_catalina": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.0.0/intel.zip",
"version": "1.0.0",
"sha256": "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216"
},
"intel_mojave": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.0.0/intel.zip",
"version": "1.0.0",
"sha256": "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216"
}
}
}, },
{ {
"token": "third-party-cask", "token": "third-party-cask",
@ -239,9 +210,7 @@ describe Cask::Cmd::List, :cask do
}, },
"conflicts_with": null, "conflicts_with": null,
"container": null, "container": null,
"auto_updates": null, "auto_updates": null
"variations": {
}
} }
] ]
EOS EOS

View File

@ -305,6 +305,38 @@ describe Cask::DSL, :cask do
end end
end end
describe "arch stanza" do
let(:token) { "invalid/invalid-two-arch" }
it "prevents defining multiple arches" do
expect { cask }.to raise_error(Cask::CaskInvalidError, /'arch' stanza may only appear once/)
end
context "when no intel value is specified" do
let(:token) { "arch-arm-only" }
context "when running on arm" do
before do
allow(Hardware::CPU).to receive(:type).and_return(:arm)
end
it "returns the value" do
expect(cask.url.to_s).to eq "file://#{TEST_FIXTURE_DIR}/cask/caffeine-arm.zip"
end
end
context "when running on intel" do
before do
allow(Hardware::CPU).to receive(:type).and_return(:intel)
end
it "defaults to `nil` for the other when no arrays are passed" do
expect(cask.url.to_s).to eq "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
end
end
end
end
describe "appcast stanza" do describe "appcast stanza" do
let(:token) { "with-appcast" } let(:token) { "with-appcast" }

View File

@ -5,4 +5,34 @@ require "cmd/shared_examples/args_parse"
describe "brew autoremove" do describe "brew autoremove" do
it_behaves_like "parseable arguments" it_behaves_like "parseable arguments"
describe "integration test" do
let(:requested_formula) { Formula["testball1"] }
let(:unused_formula) { Formula["testball2"] }
before do
install_test_formula "testball1"
install_test_formula "testball2"
# Make testball2 an unused dependency
tab = Tab.for_name("testball2")
tab.installed_on_request = false
tab.installed_as_dependency = true
tab.write
end
it "only removes unused dependencies", :integration_test do
expect(requested_formula.any_version_installed?).to be true
expect(unused_formula.any_version_installed?).to be true
# When there are unused dependencies
expect { brew "autoremove" }
.to be_a_success
.and output(/Autoremoving/).to_stdout
.and not_to_output.to_stderr
expect(requested_formula.any_version_installed?).to be true
expect(unused_formula.any_version_installed?).to be false
end
end
end end

View File

@ -0,0 +1,8 @@
# typed: false
# frozen_string_literal: true
require "cmd/shared_examples/args_parse"
describe "brew contributions" do
it_behaves_like "parseable arguments"
end

View File

@ -446,40 +446,143 @@ describe Formula do
end end
end end
describe "::installed_formulae_with_no_dependents" do shared_context "with formulae for dependency testing" do
let(:formula_is_dep) do let(:formula_with_deps) do
formula "foo" do formula "zero" do
url "foo-1.1" url "zero-1.0"
end end
end end
let(:formula_with_deps) do let(:formula_is_dep1) do
formula "bar" do formula "one" do
url "bar-1.0" url "one-1.1"
end
end
let(:formula_is_dep2) do
formula "two" do
url "two-1.1"
end end
end end
let(:formulae) do let(:formulae) do
[ [
formula_with_deps, formula_with_deps,
formula_is_dep, formula_is_dep1,
formula_is_dep2,
] ]
end end
before do before do
allow(formula_with_deps).to receive(:runtime_formula_dependencies).and_return([formula_is_dep]) allow(formula_with_deps).to receive(:runtime_formula_dependencies).and_return([formula_is_dep1,
formula_is_dep2])
allow(formula_is_dep1).to receive(:runtime_formula_dependencies).and_return([formula_is_dep2])
end end
end
specify "without formulae parameter" do describe "::formulae_with_no_formula_dependents" do
allow(described_class).to receive(:installed).and_return(formulae) include_context "with formulae for dependency testing"
expect(described_class.installed_formulae_with_no_dependents) it "filters out dependencies" do
expect(described_class.formulae_with_no_formula_dependents(formulae))
.to eq([formula_with_deps]) .to eq([formula_with_deps])
end end
end
specify "with formulae parameter" do describe "::unused_formulae_with_no_formula_dependents" do
expect(described_class.installed_formulae_with_no_dependents(formulae)) include_context "with formulae for dependency testing"
.to eq([formula_with_deps])
let(:tab_from_keg) { double }
before do
allow(Tab).to receive(:for_keg).and_return(tab_from_keg)
end
specify "installed on request" do
allow(tab_from_keg).to receive(:installed_on_request).and_return(true)
expect(described_class.unused_formulae_with_no_formula_dependents(formulae))
.to eq([])
end
specify "not installed on request" do
allow(tab_from_keg).to receive(:installed_on_request).and_return(false)
expect(described_class.unused_formulae_with_no_formula_dependents(formulae))
.to eq(formulae)
end
end
shared_context "with formulae and casks for dependency testing" do
include_context "with formulae for dependency testing"
require "cask/cask_loader"
let(:cask_one_dep) do
Cask::CaskLoader.load(+<<-RUBY)
cask "red" do
depends_on formula: "two"
end
RUBY
end
let(:cask_multiple_deps) do
Cask::CaskLoader.load(+<<-RUBY)
cask "blue" do
depends_on formula: "zero"
end
RUBY
end
let(:cask_no_deps1) do
Cask::CaskLoader.load(+<<-RUBY)
cask "green" do
end
RUBY
end
let(:cask_no_deps2) do
Cask::CaskLoader.load(+<<-RUBY)
cask "purple" do
end
RUBY
end
let(:casks_no_deps) { [cask_no_deps1, cask_no_deps2] }
let(:casks_one_dep) { [cask_no_deps1, cask_no_deps2, cask_one_dep] }
let(:casks_multiple_deps) { [cask_no_deps1, cask_no_deps2, cask_multiple_deps] }
before do
allow(described_class).to receive("[]").with("zero").and_return(formula_with_deps)
allow(described_class).to receive("[]").with("one").and_return(formula_is_dep1)
allow(described_class).to receive("[]").with("two").and_return(formula_is_dep2)
end
end
describe "::formulae_with_cask_dependents" do
include_context "with formulae and casks for dependency testing"
specify "no dependents" do
expect(described_class.formulae_with_cask_dependents(casks_no_deps))
.to eq([])
end
specify "one dependent" do
expect(described_class.formulae_with_cask_dependents(casks_one_dep))
.to eq([formula_is_dep2])
end
specify "multiple dependents" do
expect(described_class.formulae_with_cask_dependents(casks_multiple_deps))
.to eq(formulae)
end
end
describe "::inreplace" do
specify "raises build error on failure" do
f = formula do
url "https://brew.sh/test-1.0.tbz"
end
expect { f.inreplace([]) }.to raise_error(BuildError)
end end
end end
@ -905,6 +1008,99 @@ describe Formula do
expect(h["versions"]["bottle"]).to be_truthy expect(h["versions"]["bottle"]).to be_truthy
end end
describe "#to_hash_with_variations", :needs_macos do
let(:formula_path) { CoreTap.new.formula_dir/"foo-variations.rb" }
let(:formula_content) do
<<~RUBY
class FooVariations < Formula
url "file://#{TEST_FIXTURE_DIR}/tarballs/testball-0.1.tbz"
sha256 TESTBALL_SHA256
on_intel do
depends_on "intel-formula"
end
on_big_sur do
depends_on "big-sur-formula"
end
on_catalina :or_older do
depends_on "catalina-or-older-formula"
end
on_linux do
depends_on "linux-formula"
end
end
RUBY
end
let(:expected_variations) {
<<~JSON
{
"arm64_big_sur": {
"dependencies": [
"big-sur-formula"
]
},
"monterey": {
"dependencies": [
"intel-formula"
]
},
"big_sur": {
"dependencies": [
"intel-formula",
"big-sur-formula"
]
},
"catalina": {
"dependencies": [
"intel-formula",
"catalina-or-older-formula"
]
},
"mojave": {
"dependencies": [
"intel-formula",
"catalina-or-older-formula"
]
},
"x86_64_linux": {
"dependencies": [
"intel-formula",
"linux-formula"
]
}
}
JSON
}
before do
# Use a more limited symbols list to shorten the variations hash
symbols = {
monterey: "12",
big_sur: "11",
catalina: "10.15",
mojave: "10.14",
}
stub_const("MacOSVersions::SYMBOLS", symbols)
# For consistency, always run on Monterey and ARM
allow(MacOS).to receive(:version).and_return(MacOS::Version.new("12"))
allow(Hardware::CPU).to receive(:type).and_return(:arm)
formula_path.dirname.mkpath
formula_path.write formula_content
end
it "returns the correct variations hash" do
h = Formulary.factory("foo-variations").to_hash_with_variations
expect(h).to be_a(Hash)
expect(JSON.pretty_generate(h["variations"])).to eq expected_variations.strip
end
end
specify "#to_recursive_bottle_hash" do specify "#to_recursive_bottle_hash" do
f1 = formula "foo" do f1 = formula "foo" do
url "foo-1.0" url "foo-1.0"
@ -1752,4 +1948,52 @@ describe Formula do
expect(f.test).to eq(2) expect(f.test).to eq(2)
end end
end end
describe "#ignore_missing_libraries" do
after do
Homebrew::SimulateSystem.clear
end
it "adds library to allowed_missing_libraries on Linux", :needs_linux do
Homebrew::SimulateSystem.clear
f = formula do
url "foo-1.0"
ignore_missing_libraries "bar.so"
end
expect(f.class.allowed_missing_libraries.to_a).to eq(["bar.so"])
end
it "adds library to allowed_missing_libraries on macOS when simulating Linux", :needs_macos do
Homebrew::SimulateSystem.os = :linux
f = formula do
url "foo-1.0"
ignore_missing_libraries "bar.so"
end
expect(f.class.allowed_missing_libraries.to_a).to eq(["bar.so"])
end
it "raises an error on macOS", :needs_macos do
Homebrew::SimulateSystem.clear
expect {
formula do
url "foo-1.0"
ignore_missing_libraries "bar.so"
end
}.to raise_error("ignore_missing_libraries is available on Linux only")
end
it "raises an error on Linux when simulating macOS", :needs_linux do
Homebrew::SimulateSystem.os = :macos
expect {
formula do
url "foo-1.0"
ignore_missing_libraries "bar.so"
end
}.to raise_error("ignore_missing_libraries is available on Linux only")
end
end
end end

View File

@ -260,6 +260,26 @@ describe Formulary do
} }
end end
let(:variations_json) do
{
"variations" => {
Utils::Bottles.tag.to_s => {
"dependencies" => ["dep", "variations_dep"],
},
},
}
end
let(:linux_variations_json) do
{
"variations" => {
"x86_64_linux" => {
"dependencies" => ["dep", "uses_from_macos_dep"],
},
},
}
end
before do before do
allow(described_class).to receive(:loader_for).and_return(described_class::FormulaAPILoader.new(formula_name)) allow(described_class).to receive(:loader_for).and_return(described_class::FormulaAPILoader.new(formula_name))
end end
@ -303,6 +323,25 @@ describe Formulary do
formula.install formula.install
}.to raise_error("Cannot build from source from abstract formula.") }.to raise_error("Cannot build from source from abstract formula.")
end end
it "returns a Formula with variations when given a name", :needs_macos do
allow(Homebrew::API::Formula).to receive(:all_formulae).and_return formula_json_contents(variations_json)
formula = described_class.factory(formula_name)
expect(formula).to be_kind_of(Formula)
expect(formula.deps.count).to eq 5
expect(formula.deps.map(&:name).include?("variations_dep")).to be true
end
it "returns a Formula without duplicated deps and uses_from_macos with variations on Linux", :needs_linux do
allow(Homebrew::API::Formula)
.to receive(:all_formulae).and_return formula_json_contents(linux_variations_json)
formula = described_class.factory(formula_name)
expect(formula).to be_kind_of(Formula)
expect(formula.deps.count).to eq 5
expect(formula.deps.map(&:name).include?("uses_from_macos_dep")).to be true
end
end end
end end

View File

@ -7,7 +7,7 @@ require "utils/shebang"
describe Language::Python::Shebang do describe Language::Python::Shebang do
let(:file) { Tempfile.new("python-shebang") } let(:file) { Tempfile.new("python-shebang") }
let(:python_f) do let(:python_f) do
formula "python" do formula "python@3.11" do
url "https://brew.sh/python-1.0.tgz" url "https://brew.sh/python-1.0.tgz"
end end
end end
@ -15,7 +15,7 @@ describe Language::Python::Shebang do
formula "foo" do formula "foo" do
url "https://brew.sh/foo-1.0.tgz" url "https://brew.sh/foo-1.0.tgz"
depends_on "python" depends_on "python@3.11"
end end
end end
@ -37,7 +37,7 @@ describe Language::Python::Shebang do
Utils::Shebang.rewrite_shebang described_class.detected_python_shebang(f), file Utils::Shebang.rewrite_shebang described_class.detected_python_shebang(f), file
expect(File.read(file)).to eq <<~EOS expect(File.read(file)).to eq <<~EOS
#!#{HOMEBREW_PREFIX}/opt/python/bin/python3 #!#{HOMEBREW_PREFIX}/opt/python@3.11/bin/python3.11
a a
b b
c c

View File

@ -1,51 +0,0 @@
# typed: false
# frozen_string_literal: true
require "software_spec"
describe SoftwareSpec do
subject(:spec) { described_class.new }
describe "#uses_from_macos" do
before do
allow(OS).to receive(:mac?).and_return(true)
allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.from_symbol(:sierra))
end
it "adds a macOS dependency if the OS version meets requirements" do
spec.uses_from_macos("foo", since: :el_capitan)
expect(spec.deps).to be_empty
expect(spec.uses_from_macos_elements.first).to eq("foo")
end
it "doesn't add a macOS dependency if the OS version doesn't meet requirements" do
spec.uses_from_macos("foo", since: :high_sierra)
expect(spec.deps.first.name).to eq("foo")
expect(spec.uses_from_macos_elements).to eq(["foo"])
end
it "works with tags" do
spec.uses_from_macos("foo" => :build, :since => :high_sierra)
dep = spec.deps.first
expect(dep.name).to eq("foo")
expect(dep.tags).to include(:build)
end
it "doesn't add a dependency if no OS version is specified" do
spec.uses_from_macos("foo")
spec.uses_from_macos("bar" => :build)
expect(spec.deps).to be_empty
end
it "raises an error if passing invalid OS versions" do
expect {
spec.uses_from_macos("foo", since: :bar)
}.to raise_error(MacOSVersionError, "unknown or unsupported macOS version: :bar")
end
end
end

View File

@ -679,6 +679,130 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do
RUBY RUBY
end end
it "reports an offense when a single `patch` block is inside the `on_arm` block" do
expect_offense(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
on_arm do
^^^^^^^^^ Nest `on_arm` blocks inside `patch` blocks when there is only one inner block.
patch do
url "https://brew.sh/patch1.tar.gz"
sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f"
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
patch do
on_arm do
url "https://brew.sh/patch1.tar.gz"
sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f"
end
end
end
RUBY
end
it "reports an offense when a single `resource` block is inside the `on_linux` block" do
expect_offense(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
on_linux do
^^^^^^^^^^^ Nest `on_linux` blocks inside `resource` blocks when there is only one inner block.
resource do
url "https://brew.sh/resource1.tar.gz"
sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
resource do
on_linux do
url "https://brew.sh/resource1.tar.gz"
sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"
end
end
end
RUBY
end
it "reports an offense when a single `patch` block is inside the `on_monterey :or_newer` block" do
expect_offense(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
on_monterey :or_newer do
^^^^^^^^^^^^^^^^^^^^^^^^ Nest `on_monterey` blocks inside `patch` blocks when there is only one inner block.
patch do
url "https://brew.sh/patch1.tar.gz"
sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f"
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
patch do
on_monterey :or_newer do
url "https://brew.sh/patch1.tar.gz"
sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f"
end
end
end
RUBY
end
it "reports an offense when a single `resource` block is inside the `on_system` block" do
expect_offense(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
on_system :linux, macos: :monterey_or_older do
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Nest `on_system` blocks inside `resource` blocks when there is only one inner block.
resource do
url "https://brew.sh/resource1.tar.gz"
sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
resource do
on_system :linux, macos: :monterey_or_older do
url "https://brew.sh/resource1.tar.gz"
sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"
end
end
end
RUBY
end
it "reports no offenses when a single `on_arm` block is inside the `on_macos` block" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
on_macos do
on_arm do
resource do
url "https://brew.sh/resource1.tar.gz"
sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"
end
end
end
end
RUBY
end
context "when in a resource block" do context "when in a resource block" do
it "reports no offenses for a valid `on_macos` and `on_linux` block" do it "reports no offenses for a valid `on_macos` and `on_linux` block" do
expect_no_offenses(<<~RUBY) expect_no_offenses(<<~RUBY)

View File

@ -114,6 +114,34 @@ describe RuboCop::Cop::FormulaAudit::DependencyOrder do
end end
RUBY RUBY
end end
it "reports and corrects wrong conditional order within a system block" do
expect_offense(<<~RUBY)
class Foo < Formula
homepage "https://brew.sh"
url "https://brew.sh/foo-1.0.tgz"
on_arm do
uses_from_macos "apple" if build.with? "foo"
uses_from_macos "bar"
^^^^^^^^^^^^^^^^^^^^^ dependency "bar" (line 6) should be put before dependency "apple" (line 5)
uses_from_macos "foo" => :optional
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dependency "foo" (line 7) should be put before dependency "apple" (line 5)
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
homepage "https://brew.sh"
url "https://brew.sh/foo-1.0.tgz"
on_arm do
uses_from_macos "bar"
uses_from_macos "foo" => :optional
uses_from_macos "apple" if build.with? "foo"
end
end
RUBY
end
end end
context "when auditing `depends_on`" do context "when auditing `depends_on`" do
@ -224,5 +252,33 @@ describe RuboCop::Cop::FormulaAudit::DependencyOrder do
end end
RUBY RUBY
end end
it "reports and corrects wrong conditional order within a system block" do
expect_offense(<<~RUBY)
class Foo < Formula
homepage "https://brew.sh"
url "https://brew.sh/foo-1.0.tgz"
on_linux do
depends_on "apple" if build.with? "foo"
depends_on "bar"
^^^^^^^^^^^^^^^^ dependency "bar" (line 6) should be put before dependency "apple" (line 5)
depends_on "foo" => :optional
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dependency "foo" (line 7) should be put before dependency "apple" (line 5)
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
homepage "https://brew.sh"
url "https://brew.sh/foo-1.0.tgz"
on_linux do
depends_on "bar"
depends_on "foo" => :optional
depends_on "apple" if build.with? "foo"
end
end
RUBY
end
end end
end end

View File

@ -1,86 +0,0 @@
# typed: false
# frozen_string_literal: true
require "rubocops/lines"
describe RuboCop::Cop::FormulaAudit::OSConditionals do
subject(:cop) { described_class.new }
context "when auditing OS conditionals" do
it "reports an offense when `OS.linux?` is used on Formula class" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
if OS.linux?
^^^^^^^^^ Don't use 'if OS.linux?', use 'on_linux do' instead.
url 'https://brew.sh/linux-1.0.tgz'
else
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
end
it "reports an offense when `OS.mac?` is used on Formula class" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
if OS.mac?
^^^^^^^ Don't use 'if OS.mac?', use 'on_macos do' instead.
url 'https://brew.sh/mac-1.0.tgz'
else
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
end
it "reports an offense when `on_macos` is used in install method" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
on_macos do
^^^^^^^^ Don't use 'on_macos' in 'def install', use 'if OS.mac?' instead.
true
end
end
end
RUBY
end
it "reports an offense when `on_linux` is used in install method" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
on_linux do
^^^^^^^^ Don't use 'on_linux' in 'def install', use 'if OS.linux?' instead.
true
end
end
end
RUBY
end
it "reports an offense when `on_macos` is used in test block" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
test do
on_macos do
^^^^^^^^ Don't use 'on_macos' in 'test do', use 'if OS.mac?' instead.
true
end
end
end
RUBY
end
end
end

View File

@ -0,0 +1,546 @@
# typed: false
# frozen_string_literal: true
require "rubocops/lines"
describe RuboCop::Cop::FormulaAudit::OnSystemConditionals do
subject(:cop) { described_class.new }
context "when auditing OS conditionals" do
it "reports an offense when `OS.linux?` is used on Formula class" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
if OS.linux?
^^^^^^^^^^^^ Don't use `if OS.linux?`, use `on_linux do` instead.
url 'https://brew.sh/linux-1.0.tgz'
else
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
on_linux do
url 'https://brew.sh/linux-1.0.tgz'
end
on_macos do
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
end
it "reports an offense when `OS.mac?` is used on Formula class" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
if OS.mac?
^^^^^^^^^^ Don't use `if OS.mac?`, use `on_macos do` instead.
url 'https://brew.sh/mac-1.0.tgz'
else
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
on_macos do
url 'https://brew.sh/mac-1.0.tgz'
end
on_linux do
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
end
it "reports an offense when `on_macos` is used in install method" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
on_macos do
^^^^^^^^ Don't use `on_macos` in `def install`, use `if OS.mac?` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
if OS.mac?
true
end
end
end
RUBY
end
it "reports an offense when `on_linux` is used in install method" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
on_linux do
^^^^^^^^ Don't use `on_linux` in `def install`, use `if OS.linux?` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
if OS.linux?
true
end
end
end
RUBY
end
it "reports an offense when `on_macos` is used in test block" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
test do
on_macos do
^^^^^^^^ Don't use `on_macos` in `test do`, use `if OS.mac?` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
test do
if OS.mac?
true
end
end
end
RUBY
end
end
context "when auditing Hardware::CPU conditionals" do
it "reports an offense when `Hardware::CPU.arm?` is used on Formula class" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
if Hardware::CPU.arm?
^^^^^^^^^^^^^^^^^^^^^ Don't use `if Hardware::CPU.arm?`, use `on_arm do` instead.
url 'https://brew.sh/linux-1.0.tgz'
else
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
on_arm do
url 'https://brew.sh/linux-1.0.tgz'
end
on_intel do
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
end
it "reports an offense when `Hardware::CPU.intel?` is used on Formula class" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
if Hardware::CPU.intel?
^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if Hardware::CPU.intel?`, use `on_intel do` instead.
url 'https://brew.sh/mac-1.0.tgz'
else
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
on_intel do
url 'https://brew.sh/mac-1.0.tgz'
end
on_arm do
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
end
it "reports an offense when `on_intel` is used in install method" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
on_intel do
^^^^^^^^ Don't use `on_intel` in `def install`, use `if Hardware::CPU.intel?` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
if Hardware::CPU.intel?
true
end
end
end
RUBY
end
it "reports an offense when `on_arm` is used in install method" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
on_arm do
^^^^^^ Don't use `on_arm` in `def install`, use `if Hardware::CPU.arm?` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
if Hardware::CPU.arm?
true
end
end
end
RUBY
end
it "reports an offense when `on_intel` is used in test block" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
test do
on_intel do
^^^^^^^^ Don't use `on_intel` in `test do`, use `if Hardware::CPU.intel?` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
test do
if Hardware::CPU.intel?
true
end
end
end
RUBY
end
end
context "when auditing MacOS.version conditionals" do
it "reports an offense when `MacOS.version ==` is used on Formula class" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
if MacOS.version == :monterey
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version == :monterey`, use `on_monterey do` instead.
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
on_monterey do
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
end
it "reports an offense when `MacOS.version <=` is used on Formula class" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
if MacOS.version <= :monterey
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version <= :monterey`, use `on_system :linux, macos: :monterey_or_older do` instead.
url 'https://brew.sh/mac-1.0.tgz'
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
on_system :linux, macos: :monterey_or_older do
url 'https://brew.sh/mac-1.0.tgz'
end
end
RUBY
end
it "reports an offense when `MacOS.version <` is used on Formula class" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
if MacOS.version < :monterey
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version < :monterey`, use `on_system do` instead.
url 'https://brew.sh/mac-1.0.tgz'
end
end
RUBY
end
it "reports an offense when `MacOS.version >=` is used on Formula class" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
if MacOS.version >= :monterey
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version >= :monterey`, use `on_monterey :or_newer do` instead.
url 'https://brew.sh/mac-1.0.tgz'
else
url 'https://brew.sh/linux-1.0.tgz'
end
end
RUBY
end
it "reports an offense when `MacOS.version >` is used on Formula class" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
if MacOS.version > :monterey
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version > :monterey`, use `on_monterey do` instead.
url 'https://brew.sh/mac-1.0.tgz'
end
end
RUBY
end
it "reports an offense when `on_monterey` is used in install method" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
on_monterey do
^^^^^^^^^^^ Don't use `on_monterey` in `def install`, use `if MacOS.version == :monterey` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
if MacOS.version == :monterey
true
end
end
end
RUBY
end
it "reports an offense when `on_monterey :or_older` is used in install method" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
on_monterey :or_older do
^^^^^^^^^^^^^^^^^^^^^ Don't use `on_monterey :or_older` in `def install`, use `if MacOS.version <= :monterey` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
if MacOS.version <= :monterey
true
end
end
end
RUBY
end
it "reports an offense when `on_monterey :or_newer` is used in install method" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
on_monterey :or_newer do
^^^^^^^^^^^^^^^^^^^^^ Don't use `on_monterey :or_newer` in `def install`, use `if MacOS.version >= :monterey` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
if MacOS.version >= :monterey
true
end
end
end
RUBY
end
it "reports an offense when `on_system :linux, macos: :monterey_or_newer` is used in install method" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
on_system :linux, macos: :monterey_or_newer do
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `on_system :linux, macos: :monterey_or_newer` in `def install`, use `if OS.linux? || MacOS.version >= :monterey` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def install
if OS.linux? || MacOS.version >= :monterey
true
end
end
end
RUBY
end
it "reports an offense when `on_monterey` is used in test block" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
test do
on_monterey do
^^^^^^^^^^^ Don't use `on_monterey` in `test do`, use `if MacOS.version == :monterey` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
test do
if MacOS.version == :monterey
true
end
end
end
RUBY
end
it "reports an offense when `on_system :linux, macos: :monterey` is used in test block" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
test do
on_system :linux, macos: :monterey do
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `on_system :linux, macos: :monterey` in `test do`, use `if OS.linux? || MacOS.version == :monterey` instead.
true
end
end
end
RUBY
expect_correction(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
test do
if OS.linux? || MacOS.version == :monterey
true
end
end
end
RUBY
end
end
end

View File

@ -180,6 +180,14 @@ describe Homebrew::Service do
\t<true/> \t<true/>
\t<key>LegacyTimers</key> \t<key>LegacyTimers</key>
\t<true/> \t<true/>
\t<key>LimitLoadToSessionType</key>
\t<array>
\t\t<string>Aqua</string>
\t\t<string>Background</string>
\t\t<string>LoginWindow</string>
\t\t<string>StandardIO</string>
\t\t<string>System</string>
\t</array>
\t<key>ProcessType</key> \t<key>ProcessType</key>
\t<string>Interactive</string> \t<string>Interactive</string>
\t<key>ProgramArguments</key> \t<key>ProgramArguments</key>
@ -221,6 +229,14 @@ describe Homebrew::Service do
<dict> <dict>
\t<key>Label</key> \t<key>Label</key>
\t<string>homebrew.mxcl.formula_name</string> \t<string>homebrew.mxcl.formula_name</string>
\t<key>LimitLoadToSessionType</key>
\t<array>
\t\t<string>Aqua</string>
\t\t<string>Background</string>
\t\t<string>LoginWindow</string>
\t\t<string>StandardIO</string>
\t\t<string>System</string>
\t</array>
\t<key>ProgramArguments</key> \t<key>ProgramArguments</key>
\t<array> \t<array>
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string> \t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
@ -262,6 +278,14 @@ describe Homebrew::Service do
<dict> <dict>
\t<key>Label</key> \t<key>Label</key>
\t<string>homebrew.mxcl.formula_name</string> \t<string>homebrew.mxcl.formula_name</string>
\t<key>LimitLoadToSessionType</key>
\t<array>
\t\t<string>Aqua</string>
\t\t<string>Background</string>
\t\t<string>LoginWindow</string>
\t\t<string>StandardIO</string>
\t\t<string>System</string>
\t</array>
\t<key>ProgramArguments</key> \t<key>ProgramArguments</key>
\t<array> \t<array>
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string> \t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
@ -289,6 +313,14 @@ describe Homebrew::Service do
<dict> <dict>
\t<key>Label</key> \t<key>Label</key>
\t<string>homebrew.mxcl.formula_name</string> \t<string>homebrew.mxcl.formula_name</string>
\t<key>LimitLoadToSessionType</key>
\t<array>
\t\t<string>Aqua</string>
\t\t<string>Background</string>
\t\t<string>LoginWindow</string>
\t\t<string>StandardIO</string>
\t\t<string>System</string>
\t</array>
\t<key>ProgramArguments</key> \t<key>ProgramArguments</key>
\t<array> \t<array>
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string> \t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
@ -318,6 +350,14 @@ describe Homebrew::Service do
<dict> <dict>
\t<key>Label</key> \t<key>Label</key>
\t<string>homebrew.mxcl.formula_name</string> \t<string>homebrew.mxcl.formula_name</string>
\t<key>LimitLoadToSessionType</key>
\t<array>
\t\t<string>Aqua</string>
\t\t<string>Background</string>
\t\t<string>LoginWindow</string>
\t\t<string>StandardIO</string>
\t\t<string>System</string>
\t</array>
\t<key>ProgramArguments</key> \t<key>ProgramArguments</key>
\t<array> \t<array>
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string> \t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
@ -356,6 +396,14 @@ describe Homebrew::Service do
\t</dict> \t</dict>
\t<key>Label</key> \t<key>Label</key>
\t<string>homebrew.mxcl.formula_name</string> \t<string>homebrew.mxcl.formula_name</string>
\t<key>LimitLoadToSessionType</key>
\t<array>
\t\t<string>Aqua</string>
\t\t<string>Background</string>
\t\t<string>LoginWindow</string>
\t\t<string>StandardIO</string>
\t\t<string>System</string>
\t</array>
\t<key>ProgramArguments</key> \t<key>ProgramArguments</key>
\t<array> \t<array>
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string> \t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
@ -387,6 +435,14 @@ describe Homebrew::Service do
\t</dict> \t</dict>
\t<key>Label</key> \t<key>Label</key>
\t<string>homebrew.mxcl.formula_name</string> \t<string>homebrew.mxcl.formula_name</string>
\t<key>LimitLoadToSessionType</key>
\t<array>
\t\t<string>Aqua</string>
\t\t<string>Background</string>
\t\t<string>LoginWindow</string>
\t\t<string>StandardIO</string>
\t\t<string>System</string>
\t</array>
\t<key>ProgramArguments</key> \t<key>ProgramArguments</key>
\t<array> \t<array>
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string> \t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
@ -418,6 +474,14 @@ describe Homebrew::Service do
\t</dict> \t</dict>
\t<key>Label</key> \t<key>Label</key>
\t<string>homebrew.mxcl.formula_name</string> \t<string>homebrew.mxcl.formula_name</string>
\t<key>LimitLoadToSessionType</key>
\t<array>
\t\t<string>Aqua</string>
\t\t<string>Background</string>
\t\t<string>LoginWindow</string>
\t\t<string>StandardIO</string>
\t\t<string>System</string>
\t</array>
\t<key>ProgramArguments</key> \t<key>ProgramArguments</key>
\t<array> \t<array>
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string> \t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>

View File

@ -0,0 +1,142 @@
# typed: false
# frozen_string_literal: true
require "settings"
describe Homebrew::SimulateSystem do
after do
described_class.clear
end
describe "::simulating_or_running_on_macos?" do
it "returns true on macOS", :needs_macos do
described_class.clear
expect(described_class.simulating_or_running_on_macos?).to be true
end
it "returns false on Linux", :needs_linux do
described_class.clear
expect(described_class.simulating_or_running_on_macos?).to be false
end
it "returns false on macOS when simulating Linux", :needs_macos do
described_class.clear
described_class.os = :linux
expect(described_class.simulating_or_running_on_macos?).to be false
end
it "returns true on Linux when simulating a generic macOS version", :needs_linux do
described_class.clear
described_class.os = :macos
expect(described_class.simulating_or_running_on_macos?).to be true
end
it "returns true on Linux when simulating a specific macOS version", :needs_linux do
described_class.clear
described_class.os = :monterey
expect(described_class.simulating_or_running_on_macos?).to be true
end
it "returns true on Linux with HOMEBREW_SIMULATE_MACOS_ON_LINUX", :needs_linux do
described_class.clear
ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1"
expect(described_class.simulating_or_running_on_macos?).to be true
end
end
describe "::simulating_or_running_on_linux?" do
it "returns true on Linux", :needs_linux do
described_class.clear
expect(described_class.simulating_or_running_on_linux?).to be true
end
it "returns false on macOS", :needs_macos do
described_class.clear
expect(described_class.simulating_or_running_on_linux?).to be false
end
it "returns true on macOS when simulating Linux", :needs_macos do
described_class.clear
described_class.os = :linux
expect(described_class.simulating_or_running_on_linux?).to be true
end
it "returns false on Linux when simulating a generic macOS version", :needs_linux do
described_class.clear
described_class.os = :macos
expect(described_class.simulating_or_running_on_linux?).to be false
end
it "returns false on Linux when simulating a specific macOS version", :needs_linux do
described_class.clear
described_class.os = :monterey
expect(described_class.simulating_or_running_on_linux?).to be false
end
it "returns false on Linux with HOMEBREW_SIMULATE_MACOS_ON_LINUX", :needs_linux do
described_class.clear
ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1"
expect(described_class.simulating_or_running_on_linux?).to be false
end
end
describe "::current_arch" do
it "returns the current architecture" do
described_class.clear
expect(described_class.current_arch).to eq Hardware::CPU.type
end
it "returns the simulated architecture" do
described_class.clear
simulated_arch = if Hardware::CPU.arm?
:intel
else
:arm
end
described_class.arch = simulated_arch
expect(described_class.current_arch).to eq simulated_arch
end
end
describe "::current_os" do
it "returns the current macOS version on macOS", :needs_macos do
described_class.clear
expect(described_class.current_os).to eq MacOS.version.to_sym
end
it "returns `:linux` on Linux", :needs_linux do
described_class.clear
expect(described_class.current_os).to eq :linux
end
it "returns `:linux` when simulating Linux on macOS", :needs_macos do
described_class.clear
described_class.os = :linux
expect(described_class.current_os).to eq :linux
end
it "returns `:macos` when simulating a generic macOS version on Linux", :needs_linux do
described_class.clear
described_class.os = :macos
expect(described_class.current_os).to eq :macos
end
it "returns `:macos` when simulating a specific macOS version on Linux", :needs_linux do
described_class.clear
described_class.os = :monterey
expect(described_class.current_os).to eq :monterey
end
it "returns the current macOS version on macOS with HOMEBREW_SIMULATE_MACOS_ON_LINUX", :needs_macos do
described_class.clear
ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1"
expect(described_class.current_os).to eq MacOS.version.to_sym
end
it "returns `:macos` on Linux with HOMEBREW_SIMULATE_MACOS_ON_LINUX", :needs_linux do
described_class.clear
ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1"
expect(described_class.current_os).to eq :macos
end
end
end

View File

@ -135,27 +135,86 @@ describe SoftwareSpec do
end end
end end
describe "#uses_from_macos" do describe "#uses_from_macos", :needs_linux do
it "allows specifying dependencies", :needs_linux do context "when running on Linux", :needs_linux do
spec.uses_from_macos("foo") it "allows specifying dependencies" do
spec.uses_from_macos("foo")
expect(spec.deps.first.name).to eq("foo") expect(spec.deps.first.name).to eq("foo")
end
it "works with tags" do
spec.uses_from_macos("foo" => :build)
expect(spec.deps.first.name).to eq("foo")
expect(spec.deps.first.tags).to include(:build)
end
it "ignores dependencies with HOMEBREW_SIMULATE_MACOS_ON_LINUX" do
ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1"
spec.uses_from_macos("foo")
expect(spec.deps).to be_empty
end
it "ignores dependencies with tags with HOMEBREW_SIMULATE_MACOS_ON_LINUX" do
ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1"
spec.uses_from_macos("foo" => :build)
expect(spec.deps).to be_empty
end
it "ignores OS version specifications" do
spec.uses_from_macos("foo", since: :mojave)
spec.uses_from_macos("bar" => :build, :since => :mojave)
expect(spec.deps.first.name).to eq("foo")
expect(spec.deps.last.name).to eq("bar")
expect(spec.deps.last.tags).to include(:build)
end
end end
it "works with tags", :needs_linux do context "when running on macOS", :needs_macos do
spec.uses_from_macos("foo" => :build) before do
allow(OS).to receive(:mac?).and_return(true)
allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.from_symbol(:sierra))
end
expect(spec.deps.first.name).to eq("foo") it "adds a macOS dependency if the OS version meets requirements" do
expect(spec.deps.first.tags).to include(:build) spec.uses_from_macos("foo", since: :el_capitan)
end
it "ignores OS version specifications", :needs_linux do expect(spec.deps).to be_empty
spec.uses_from_macos("foo", since: :mojave) expect(spec.uses_from_macos_elements.first).to eq("foo")
spec.uses_from_macos("bar" => :build, :since => :mojave) end
expect(spec.deps.first.name).to eq("foo") it "doesn't add a macOS dependency if the OS version doesn't meet requirements" do
expect(spec.deps.last.name).to eq("bar") spec.uses_from_macos("foo", since: :high_sierra)
expect(spec.deps.last.tags).to include(:build)
expect(spec.deps.first.name).to eq("foo")
expect(spec.uses_from_macos_elements).to eq(["foo"])
end
it "works with tags" do
spec.uses_from_macos("foo" => :build, :since => :high_sierra)
dep = spec.deps.first
expect(dep.name).to eq("foo")
expect(dep.tags).to include(:build)
end
it "doesn't add a dependency if no OS version is specified" do
spec.uses_from_macos("foo")
spec.uses_from_macos("bar" => :build)
expect(spec.deps).to be_empty
end
it "raises an error if passing invalid OS versions" do
expect {
spec.uses_from_macos("foo", since: :bar)
}.to raise_error(MacOSVersionError, "unknown or unsupported macOS version: :bar")
end
end end
end end
@ -171,5 +230,12 @@ describe SoftwareSpec do
expect(spec.patches.count).to eq(1) expect(spec.patches.count).to eq(1)
expect(spec.patches.first.strip).to eq(:p1) expect(spec.patches.first.strip).to eq(:p1)
end end
it "doesn't add a patch with no url" do
spec.patch do
sha256 "7852a7a365f518b12a1afd763a6a80ece88ac7aeea3c9023aa6c1fe46ac5a1ae"
end
expect(spec.patches.empty?).to be true
end
end end
end end

View File

@ -0,0 +1,11 @@
cask "arch-arm-only" do
arch arm: "-arm"
version "1.2.3"
sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine#{arch}.zip"
homepage "https://brew.sh/"
app "Caffeine.app"
end

View File

@ -0,0 +1,12 @@
cask "invalid-two-arch" do
arch arm: "arm", intel: "intel"
arch arm: "amd64", intel: "x86_64"
version "1.2.3"
sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
homepage "https://brew.sh/"
app "Caffeine.app"
end

View File

@ -1,12 +1,10 @@
cask "multiple-versions" do cask "multiple-versions" do
arch = "arm" arch arm: "arm", intel: "intel"
platform = on_arch_conditional arm: "darwin-arm64", intel: "darwin"
version "1.2.3" version "1.2.3"
sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"
on_intel do
arch = "intel"
end
on_big_sur do on_big_sur do
version "1.2.0" version "1.2.0"
sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b"
@ -17,7 +15,7 @@ cask "multiple-versions" do
sha256 "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216" sha256 "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216"
end end
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine/#{version}/#{arch}.zip" url "file://#{TEST_FIXTURE_DIR}/cask/caffeine/#{platform}/#{version}/#{arch}.zip"
homepage "https://brew.sh/" homepage "https://brew.sh/"
app "Caffeine.app" app "Caffeine.app"

View File

@ -36,4 +36,37 @@ describe Utils::Bottles::Tag do
expect(tag.linux?).to be true expect(tag.linux?).to be true
expect(tag.to_sym).to eq(symbol) expect(tag.to_sym).to eq(symbol)
end end
describe "#standardized_arch" do
it "returns :x86_64 for :intel" do
expect(described_class.new(system: :all, arch: :intel).standardized_arch).to eq(:x86_64)
end
it "returns :arm64 for :arm" do
expect(described_class.new(system: :all, arch: :arm).standardized_arch).to eq(:arm64)
end
end
describe "#valid_combination?" do
it "returns true for intel archs" do
tag = described_class.new(system: :big_sur, arch: :intel)
expect(tag.valid_combination?).to be true
tag = described_class.new(system: :linux, arch: :x86_64)
expect(tag.valid_combination?).to be true
end
it "returns false for arm archs and macos versions older than big_sur" do
tag = described_class.new(system: :catalina, arch: :arm64)
expect(tag.valid_combination?).to be false
tag = described_class.new(system: :mojave, arch: :arm)
expect(tag.valid_combination?).to be false
end
it "returns false for arm archs and linux" do
tag = described_class.new(system: :linux, arch: :arm64)
expect(tag.valid_combination?).to be false
tag = described_class.new(system: :linux, arch: :arm)
expect(tag.valid_combination?).to be false
end
end
end end

View File

@ -0,0 +1,44 @@
# typed: false
# frozen_string_literal: true
describe Utils do
describe "ruby_check_version_script" do
subject do
quiet_system "#{HOMEBREW_LIBRARY_PATH}/utils/ruby_check_version_script.rb", required_ruby_version
end
before do
ENV.delete("HOMEBREW_DEVELOPER")
ENV.delete("HOMEBREW_USE_RUBY_FROM_PATH")
end
describe "succeeds on Homebrew required Ruby version" do
let(:required_ruby_version) { HOMEBREW_REQUIRED_RUBY_VERSION }
it { is_expected.to be true }
end
describe "succeeds on newer mismatched major/minor required Ruby version and configurated environment" do
let(:required_ruby_version) { "2.0.0" }
before do
ENV["HOMEBREW_DEVELOPER"] = "1"
ENV["HOMEBREW_USE_RUBY_FROM_PATH"] = "1"
end
it { is_expected.to be true }
end
describe "fails on on mismatched major/minor required Ruby version" do
let(:required_ruby_version) { "1.2.3" }
it { is_expected.to be false }
end
describe "fails on invalid required Ruby version" do
let(:required_ruby_version) { "fish" }
it { is_expected.to be false }
end
end
end

View File

@ -169,14 +169,22 @@ module Utils
[system, arch].hash [system, arch].hash
end end
sig { returns(Symbol) }
def standardized_arch
return :x86_64 if [:x86_64, :intel].include? arch
return :arm64 if [:arm64, :arm].include? arch
arch
end
sig { returns(Symbol) } sig { returns(Symbol) }
def to_sym def to_sym
if system == :all && arch == :all if system == :all && arch == :all
:all :all
elsif macos? && arch == :x86_64 elsif macos? && [:x86_64, :intel].include?(arch)
system system
else else
"#{arch}_#{system}".to_sym "#{standardized_arch}_#{system}".to_sym
end end
end end
@ -203,6 +211,15 @@ module Utils
false false
end end
sig { returns(T::Boolean) }
def valid_combination?
return true unless [:arm64, :arm].include? arch
return false if linux?
# Big Sur is the first version of macOS that runs on ARM
to_macos_version >= :big_sur
end
sig { returns(String) } sig { returns(String) }
def default_prefix def default_prefix
if linux? if linux?

View File

@ -479,8 +479,9 @@ module GitHub
def check_for_duplicate_pull_requests(name, tap_remote_repo, state:, file:, args:, version: nil) def check_for_duplicate_pull_requests(name, tap_remote_repo, state:, file:, args:, version: nil)
pull_requests = fetch_pull_requests(name, tap_remote_repo, state: state, version: version).select do |pr| pull_requests = fetch_pull_requests(name, tap_remote_repo, state: state, version: version).select do |pr|
pr_files = API.open_rest(url_to("repos", tap_remote_repo, "pulls", pr["number"], "files")) get_pull_request_changed_files(
pr_files.any? { |f| f["filename"] == file } tap_remote_repo, pr["number"]
).any? { |f| f["filename"] == file }
end end
return if pull_requests.blank? return if pull_requests.blank?
@ -501,6 +502,10 @@ module GitHub
end end
end end
def get_pull_request_changed_files(tap_remote_repo, pr)
API.open_rest(url_to("repos", tap_remote_repo, "pulls", pr, "files"))
end
def forked_repo_info!(tap_remote_repo, org: nil) def forked_repo_info!(tap_remote_repo, org: nil)
response = create_fork(tap_remote_repo, org: org) response = create_fork(tap_remote_repo, org: org)
# GitHub API responds immediately but fork takes a few seconds to be ready. # GitHub API responds immediately but fork takes a few seconds to be ready.

View File

@ -184,8 +184,7 @@ module GitHub
# This is a no-op if the user is opting out of using the GitHub API. # This is a no-op if the user is opting out of using the GitHub API.
return block_given? ? yield({}) : {} if Homebrew::EnvConfig.no_github_api? return block_given? ? yield({}) : {} if Homebrew::EnvConfig.no_github_api?
args = ["--header", "Accept: application/vnd.github.v3+json", "--write-out", "\n%\{http_code}"] args = ["--header", "Accept: application/vnd.github+json", "--write-out", "\n%\{http_code}"]
args += ["--header", "Accept: application/vnd.github.antiope-preview+json"]
token = credentials token = credentials
args += ["--header", "Authorization: token #{token}"] unless credentials_type == :none args += ["--header", "Authorization: token #{token}"] unless credentials_type == :none

View File

@ -10,7 +10,7 @@ module Utils
module Inreplace module Inreplace
extend T::Sig extend T::Sig
# Error during replacement. # Error during text replacement.
class Error < RuntimeError class Error < RuntimeError
def initialize(errors) def initialize(errors)
formatted_errors = errors.reduce(+"inreplace failed\n") do |s, (path, errs)| formatted_errors = errors.reduce(+"inreplace failed\n") do |s, (path, errs)|
@ -70,7 +70,7 @@ module Utils
Pathname(path).atomic_write(s.inreplace_string) Pathname(path).atomic_write(s.inreplace_string)
end end
raise Error, errors unless errors.empty? raise Utils::Inreplace::Error, errors if errors.present?
end end
# @api private # @api private
@ -86,7 +86,7 @@ module Utils
contents.gsub!(old, new) contents.gsub!(old, new)
end end
raise Error, path => contents.errors unless contents.errors.empty? raise Utils::Inreplace::Error, path => contents.errors if contents.errors.present?
Pathname(path).atomic_write(contents.inreplace_string) unless read_only_run Pathname(path).atomic_write(contents.inreplace_string) unless read_only_run
contents.inreplace_string contents.inreplace_string

View File

@ -47,10 +47,10 @@ need_vendored_ruby() {
if [[ -n "${HOMEBREW_FORCE_VENDOR_RUBY}" ]] if [[ -n "${HOMEBREW_FORCE_VENDOR_RUBY}" ]]
then then
return 0 return 0
elif [[ -n "${HOMEBREW_MACOS_SYSTEM_RUBY_NEW_ENOUGH}" ]] elif [[ -n "${HOMEBREW_MACOS_SYSTEM_RUBY_NEW_ENOUGH}" && -z "${HOMEBREW_USE_RUBY_FROM_PATH}" ]]
then then
return 1 return 1
elif [[ -z "${HOMEBREW_MACOS}" ]] && test_ruby "${HOMEBREW_RUBY_PATH}" elif [[ -z "${HOMEBREW_MACOS}" || -n "${HOMEBREW_USE_RUBY_FROM_PATH}" ]] && test_ruby "${HOMEBREW_RUBY_PATH}"
then then
return 1 return 1
else else

View File

@ -1,4 +1,4 @@
#!/usr/bin/env ruby --enable-frozen-string-literal --disable=gems,did_you_mean,rubyopt #!/usr/bin/env ruby
# typed: true # typed: true
# frozen_string_literal: true # frozen_string_literal: true
@ -17,8 +17,8 @@ ruby_version_major, ruby_version_minor, = ruby_version.canonical_segments
homebrew_required_ruby_version_major, homebrew_required_ruby_version_minor, = homebrew_required_ruby_version_major, homebrew_required_ruby_version_minor, =
homebrew_required_ruby_version.canonical_segments homebrew_required_ruby_version.canonical_segments
if ENV["HOMEBREW_DEVELOPER"].present? && if !ENV.fetch("HOMEBREW_DEVELOPER", "").empty? &&
ENV["HOMEBREW_USE_RUBY_FROM_PATH"].present? && !ENV.fetch("HOMEBREW_USE_RUBY_FROM_PATH", "").empty? &&
ruby_version >= homebrew_required_ruby_version ruby_version >= homebrew_required_ruby_version
return return
elsif ruby_version_major != homebrew_required_ruby_version_major || elsif ruby_version_major != homebrew_required_ruby_version_major ||

View File

@ -6,17 +6,17 @@ path = File.expand_path('..', __FILE__)
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/i18n-1.12.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/i18n-1.12.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/minitest-5.16.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/minitest-5.16.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tzinfo-2.0.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tzinfo-2.0.5/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.6.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.6.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/activesupport-6.1.6.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/activesupport-6.1.6.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/public_suffix-4.0.7/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/public_suffix-4.0.7/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/addressable-2.8.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/addressable-2.8.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.10/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.10/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/msgpack-1.5.3" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/msgpack-1.5.4"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.5.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.5.4/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/bootsnap-1.12.0" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/bootsnap-1.13.0"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.12.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.13.0/lib"
$:.unshift "#{path}/" $:.unshift "#{path}/"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/byebug-11.1.3" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/byebug-11.1.3"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/byebug-11.1.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/byebug-11.1.3/lib"
@ -49,7 +49,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/net-http-persistent-4
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mini_portile2-2.8.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mini_portile2-2.8.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/racc-1.6.0" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/racc-1.6.0"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/racc-1.6.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/racc-1.6.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/nokogiri-1.13.7-x86_64-darwin/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/nokogiri-1.13.8-x86_64-darwin/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubyntlm-0.6.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubyntlm-0.6.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrick-1.7.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrick-1.7.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrobots-0.1.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrobots-0.1.2/lib"
@ -58,9 +58,9 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/method_source-1.0.0/l
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mustache-1.1.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mustache-1.1.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.22.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.22.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.11.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.11.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-3.1.2.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-3.1.2.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.1.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.1.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.10158/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.10175/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parlour-8.0.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parlour-8.0.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.3.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.3.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.6.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.6.0/lib"
@ -83,11 +83,11 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-retry-0.6.2/lib
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-sorbet-1.8.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-sorbet-1.8.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec_junit_formatter-0.5.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec_junit_formatter-0.5.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.19.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.21.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.11.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.11.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-2.2.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-2.2.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.31.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.33.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.14.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.14.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rails-2.15.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rails-2.15.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.12.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.12.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.6.11/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.6.11/lib"
@ -96,10 +96,9 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.12.3
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov_json_formatter-0.1.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov_json_formatter-0.1.4/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-0.21.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-0.21.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-cobertura-2.1.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-cobertura-2.1.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.10158-universal-darwin-15/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.10175-universal-darwin-15/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.10158/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.10175/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-stub-0.2.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-and-runtime-0.5.10175/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-and-runtime-0.5.10158/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thor-1.2.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thor-1.2.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/spoom-1.1.11/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/spoom-1.1.11/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/yard-0.9.28/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/yard-0.9.28/lib"

View File

@ -160,7 +160,7 @@ Performance/FlatMap:
Description: >- Description: >-
Use `Enumerable#flat_map` Use `Enumerable#flat_map`
instead of `Enumerable#map...Array#flatten(1)` instead of `Enumerable#map...Array#flatten(1)`
or `Enumberable#collect..Array#flatten(1)`. or `Enumerable#collect..Array#flatten(1)`.
Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code' Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code'
Enabled: true Enabled: true
VersionAdded: '0.30' VersionAdded: '0.30'

Some files were not shown because too many files have changed in this diff Show More