Merge branch 'Homebrew:master' into mohammad

This commit is contained in:
Mohammad Zain Abbas 2022-08-06 14:59:14 +02:00 committed by GitHub
commit 105135ed91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 682 additions and 125 deletions

View File

@ -124,7 +124,7 @@ GEM
rspec (>= 3, < 4)
rspec_junit_formatter (0.5.1)
rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.32.0)
rubocop (1.33.0)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.1.0.0)

View File

@ -160,7 +160,7 @@ module Homebrew
cleanup = Cleanup.new(dry_run: dry_run)
if cleanup.periodic_clean_due?
cleanup.periodic_clean!
elsif f.latest_version_installed? && !cleanup.skip_clean_formula?(f)
elsif f.latest_version_installed? && !Cleanup.skip_clean_formula?(f)
ohai "Running `brew cleanup #{f}`..."
puts_no_install_cleanup_disable_message_if_not_already!
cleanup.cleanup_formula(f)
@ -177,7 +177,7 @@ module Homebrew
@puts_no_install_cleanup_disable_message_if_not_already = true
end
def skip_clean_formula?(f)
def self.skip_clean_formula?(f)
return false if Homebrew::EnvConfig.no_cleanup_formulae.blank?
skip_clean_formulae = Homebrew::EnvConfig.no_cleanup_formulae.split(",")
@ -215,10 +215,13 @@ module Homebrew
if args.empty?
Formula.installed
.sort_by(&:name)
.reject { |f| skip_clean_formula?(f) }
.reject { |f| Cleanup.skip_clean_formula?(f) }
.each do |formula|
cleanup_formula(formula, quiet: quiet, ds_store: false, cache_db: false)
end
Cleanup.autoremove(dry_run: dry_run?) if Homebrew::EnvConfig.autoremove?
cleanup_cache
cleanup_logs
cleanup_lockfiles
@ -253,7 +256,7 @@ module Homebrew
nil
end
if formula && skip_clean_formula?(formula)
if formula && Cleanup.skip_clean_formula?(formula)
onoe "Refusing to clean #{formula} because it is listed in " \
"#{Tty.bold}HOMEBREW_NO_CLEANUP_FORMULAE#{Tty.reset}!"
elsif formula
@ -519,5 +522,36 @@ module Homebrew
print "and #{d} directories " if d.positive?
puts "from #{HOMEBREW_PREFIX}"
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

View File

@ -303,6 +303,15 @@ module Homebrew
sig { returns(T.nilable(String)) }
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])) }
def groups; end

View File

@ -1,9 +1,8 @@
# typed: true
# frozen_string_literal: true
require "formula"
require "cleanup"
require "cli/parser"
require "uninstall"
module Homebrew
module_function
@ -20,37 +19,9 @@ module Homebrew
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
args = autoremove_args.parse
removable_formulae = get_removable_formulae(Formula.installed)
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)
Cleanup.autoremove(dry_run: args.dry_run?)
end
end

View File

@ -37,7 +37,7 @@ module Homebrew
def leaves
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_as_dependency?)) if args.installed_as_dependency?

View File

@ -50,6 +50,11 @@ module Homebrew
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)
Uninstall.uninstall_kegs(
@ -73,5 +78,7 @@ module Homebrew
force: args.force?,
)
end
Cleanup.autoremove if Homebrew::EnvConfig.autoremove?
end
end

View File

@ -148,6 +148,8 @@ module Homebrew
Homebrew.failed = true if ENV["HOMEBREW_UPDATE_FAILED"]
return if Homebrew::EnvConfig.disable_load_formula?
migrate_gcc_dependents_if_needed
hub = ReporterHub.new
updated_taps = []
@ -289,6 +291,26 @@ module Homebrew
#{e}
EOS
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?
next unless formula.recursive_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
class Reporter

View File

@ -1,10 +1,12 @@
# typed: true
# frozen_string_literal: true
require "simulate_system"
module Homebrew
DEFAULT_PREFIX, DEFAULT_REPOSITORY = if OS.mac? && Hardware::CPU.arm?
[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]
else
[HOMEBREW_DEFAULT_PREFIX, HOMEBREW_DEFAULT_REPOSITORY]

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,42 +368,46 @@ module Homebrew
end
end
def pr_check_conflicts(name, tap_remote_repo, pr)
hash_template = proc { |h, k| h[k] = [] }
def pr_check_conflicts(user, repo, pr)
long_build_pr_files = GitHub.search_issues(
"org:#{name}", repo: tap_remote_repo, state: "open", label: "\"no long build conflict\""
).each_with_object(Hash.new(hash_template)) do |long_build_pr, hash|
"org:#{user}", repo: repo, state: "open", label: "\"no long build conflict\""
).each_with_object({}) do |long_build_pr, hash|
number = long_build_pr["number"]
GitHub.get_pull_request_changed_files(name, tap_remote_repo, number).each do |file|
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(name, tap_remote_repo, pr)
this_pr_files = GitHub.get_pull_request_changed_files("#{user}/#{repo}", pr)
conflicts = this_pr_files.each_with_object(Hash.new(hash_template)) do |file, hash|
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 = "#{tap_remote_repo}/pull/#{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"
# ]
# }
# {
# "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)}
#{JSON.pretty_generate(conflicts)}
EOS
end

View File

@ -36,6 +36,12 @@ module Homebrew
"disable auto-update entirely with HOMEBREW_NO_AUTO_UPDATE.",
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: {
description: "If set, use `bat` for the `brew cat` command.",
boolean: true,
@ -263,8 +269,8 @@ module Homebrew
boolean: true,
},
HOMEBREW_NO_CLEANUP_FORMULAE: {
description: "A comma-separated list of formulae. Homebrew will refuse to clean up a " \
"formula if it appears on this list.",
description: "A comma-separated list of formulae. Homebrew will refuse to clean up " \
"or autoremove a formula if it appears on this list.",
},
HOMEBREW_NO_COLOR: {
description: "If set, do not print text with colour added.",

View File

@ -20,11 +20,6 @@ module OnSystem
sig { params(os_name: Symbol, or_condition: T.nilable(Symbol)).returns(T::Boolean) }
def os_condition_met?(os_name, or_condition = nil)
if Homebrew::EnvConfig.simulate_macos_on_linux?
return false if os_name == :linux
return true if [:macos, *MacOSVersions::SYMBOLS.keys].include?(os_name)
end
return Homebrew::SimulateSystem.send("simulating_or_running_on_#{os_name}?") if BASE_OS_OPTIONS.include?(os_name)
raise ArgumentError, "Invalid OS condition: #{os_name.inspect}" unless MacOSVersions::SYMBOLS.key?(os_name)
@ -36,7 +31,13 @@ module OnSystem
return false if Homebrew::SimulateSystem.simulating_or_running_on_linux?
base_os = MacOS::Version.from_symbol(os_name)
current_os = MacOS::Version.from_symbol(Homebrew::SimulateSystem.current_os)
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_older

View File

@ -8,9 +8,6 @@ class Keg
# Patching the dynamic linker of glibc breaks it.
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)
elf_files.each do |file|
@ -92,16 +89,4 @@ class Keg
end
elf_files
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

View File

@ -1706,14 +1706,46 @@ class Formula
end.uniq(&:name)
end
# An array of all installed {Formula} without dependents
# An array of all installed {Formula} with {Cask} dependents.
# @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?
formulae - formulae.flat_map(&:runtime_formula_dependencies)
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)
return [] if alias_path.nil?

View File

@ -336,7 +336,7 @@ module Homebrew
# The number of conflicts on Linux is absurd.
# 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)
version_hash = {}

View File

@ -368,7 +368,14 @@ class Keg
end
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

View File

@ -3,6 +3,8 @@
OFFICIAL_CASK_TAPS = %w[
cask
cask-drivers
cask-fonts
cask-versions
].freeze

View File

@ -105,7 +105,7 @@ module Homebrew
# 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.
# 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://") }
problem "should always include at least one HTTP mirror"
end

View File

@ -14,12 +14,6 @@ module RuboCop
class ComponentsOrder < FormulaCop
extend AutoCorrector
def on_system_methods
@on_system_methods ||= [:intel, :arm, :macos, :linux, :system, *MacOSVersions::SYMBOLS.keys].map do |m|
:"on_#{m}"
end
end
def audit_formula(_node, _class_node, _parent_class_node, body_node)
@present_components, @offensive_nodes = check_order(FORMULA_COMPONENT_PRECEDENCE_LIST, body_node)

View File

@ -16,7 +16,7 @@ module RuboCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
check_dependency_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)
next unless block

View File

@ -198,6 +198,12 @@ module RuboCop
@file_path !~ Regexp.union(paths_to_exclude)
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

View File

@ -9,7 +9,14 @@ module Homebrew
class << self
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 }
def os=(new_os)
@ -33,16 +40,16 @@ module Homebrew
sig { returns(T::Boolean) }
def simulating_or_running_on_macos?
return OS.mac? if @os.blank?
return OS.mac? if os.blank?
[:macos, *MacOSVersions::SYMBOLS.keys].include?(@os)
[:macos, *MacOSVersions::SYMBOLS.keys].include?(os)
end
sig { returns(T::Boolean) }
def simulating_or_running_on_linux?
return OS.linux? if @os.blank?
return OS.linux? if os.blank?
@os == :linux
os == :linux
end
sig { returns(Symbol) }
@ -52,7 +59,7 @@ module Homebrew
sig { returns(Symbol) }
def current_os
return @os if @os.present?
return T.must(os) if os.present?
return :linux if OS.linux?
MacOS.version.to_sym

View File

@ -170,14 +170,16 @@ class SoftwareSpec
@uses_from_macos_elements << deps
# 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.
# Check whether macOS is new enough for dependency to not be required.
if Homebrew::SimulateSystem.simulating_or_running_on_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
# 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

View File

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

View File

@ -5,4 +5,34 @@ require "cmd/shared_examples/args_parse"
describe "brew autoremove" do
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

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,133 @@ describe Formula do
end
end
describe "::installed_formulae_with_no_dependents" do
let(:formula_is_dep) do
formula "foo" do
url "foo-1.1"
shared_context "with formulae for dependency testing" do
let(:formula_with_deps) do
formula "zero" do
url "zero-1.0"
end
end
let(:formula_with_deps) do
formula "bar" do
url "bar-1.0"
let(:formula_is_dep1) do
formula "one" do
url "one-1.1"
end
end
let(:formula_is_dep2) do
formula "two" do
url "two-1.1"
end
end
let(:formulae) do
[
formula_with_deps,
formula_is_dep,
formula_is_dep1,
formula_is_dep2,
]
end
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
specify "without formulae parameter" do
allow(described_class).to receive(:installed).and_return(formulae)
describe "::formulae_with_no_formula_dependents" do
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])
end
end
specify "with formulae parameter" do
expect(described_class.installed_formulae_with_no_dependents(formulae))
.to eq([formula_with_deps])
describe "::unused_formulae_with_no_formula_dependents" do
include_context "with formulae for dependency testing"
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

View File

@ -114,6 +114,34 @@ describe RuboCop::Cop::FormulaAudit::DependencyOrder do
end
RUBY
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
context "when auditing `depends_on`" do
@ -224,5 +252,33 @@ describe RuboCop::Cop::FormulaAudit::DependencyOrder do
end
RUBY
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

View File

@ -36,6 +36,12 @@ describe Homebrew::SimulateSystem do
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
@ -66,6 +72,12 @@ describe Homebrew::SimulateSystem do
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
@ -114,5 +126,17 @@ describe Homebrew::SimulateSystem do
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

@ -150,6 +150,20 @@ describe SoftwareSpec do
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)

View File

@ -480,7 +480,7 @@ module GitHub
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|
get_pull_request_changed_files(
name, tap_remote_repo, pr["number"]
tap_remote_repo, pr["number"]
).any? { |f| f["filename"] == file }
end
return if pull_requests.blank?
@ -502,8 +502,8 @@ module GitHub
end
end
def get_pull_request_changed_files(name, tap_remote_repo, pr)
API.open_rest(url_to("repos", name, tap_remote_repo, "pulls", pr, "files"))
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)

View File

@ -47,10 +47,10 @@ need_vendored_ruby() {
if [[ -n "${HOMEBREW_FORCE_VENDOR_RUBY}" ]]
then
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
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
return 1
else

View File

@ -86,7 +86,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec_junit_formatter
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.19.1/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/rubocop-1.32.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.33.0/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-rspec-2.12.1/lib"

View File

@ -670,6 +670,25 @@ _brew_config() {
esac
}
_brew_contributions() {
local cur="${COMP_WORDS[COMP_CWORD]}"
case "${cur}" in
-*)
__brewcomp "
--debug
--from
--help
--quiet
--repositories
--to
--verbose
"
return
;;
*)
esac
}
_brew_create() {
local cur="${COMP_WORDS[COMP_CWORD]}"
case "${cur}" in
@ -2479,6 +2498,7 @@ _brew() {
commands) _brew_commands ;;
completions) _brew_completions ;;
config) _brew_config ;;
contributions) _brew_contributions ;;
create) _brew_create ;;
deps) _brew_deps ;;
desc) _brew_desc ;;

View File

@ -529,6 +529,16 @@ __fish_brew_complete_arg 'config' -l quiet -d 'Make some output more quiet'
__fish_brew_complete_arg 'config' -l verbose -d 'Make some output more verbose'
__fish_brew_complete_cmd 'contributions' 'Contributions to Homebrew repos for a user'
__fish_brew_complete_arg 'contributions' -l debug -d 'Display any debugging information'
__fish_brew_complete_arg 'contributions' -l from -d 'Date (ISO-8601 format) to start searching contributions'
__fish_brew_complete_arg 'contributions' -l help -d 'Show this message'
__fish_brew_complete_arg 'contributions' -l quiet -d 'Make some output more quiet'
__fish_brew_complete_arg 'contributions' -l repositories -d 'Specify a comma-separated (no spaces) list of repositories to search. Supported repositories: `brew`, `core`, `cask`, `aliases`, `autoupdate`, `bundle`, `command-not-found`, `test-bot`, `services`, `cask-drivers`, `cask-fonts` and `cask-versions`.Omitting this flag, or specifying `--repositories=all`, will search all repositories'
__fish_brew_complete_arg 'contributions' -l to -d 'Date (ISO-8601 format) to stop searching contributions'
__fish_brew_complete_arg 'contributions' -l verbose -d 'Make some output more verbose'
__fish_brew_complete_cmd 'create' 'Generate a formula or, with `--cask`, a cask for the downloadable file at URL and open it in the editor'
__fish_brew_complete_arg 'create' -l HEAD -d 'Indicate that URL points to the package\'s repository rather than a file'
__fish_brew_complete_arg 'create' -l autotools -d 'Create a basic template for an Autotools-style build'

View File

@ -26,6 +26,7 @@ command
commands
completions
config
contributions
create
deps
desc

View File

@ -152,6 +152,7 @@ __brew_internal_commands() {
'commands:Show lists of built-in and external commands'
'completions:Control whether Homebrew automatically links external tap shell completion files'
'config:Show Homebrew and system configuration info useful for debugging'
'contributions:Contributions to Homebrew repos for a user'
'create:Generate a formula or, with `--cask`, a cask for the downloadable file at URL and open it in the editor'
'deps:Show dependencies for formula'
'desc:Display formula'\''s name and one-line description'
@ -652,6 +653,18 @@ _brew_config() {
'--verbose[Make some output more verbose]'
}
# brew contributions
_brew_contributions() {
_arguments \
'--debug[Display any debugging information]' \
'--from[Date (ISO-8601 format) to start searching contributions]' \
'--help[Show this message]' \
'--quiet[Make some output more quiet]' \
'--repositories[Specify a comma-separated (no spaces) list of repositories to search. Supported repositories: `brew`, `core`, `cask`, `aliases`, `autoupdate`, `bundle`, `command-not-found`, `test-bot`, `services`, `cask-drivers`, `cask-fonts` and `cask-versions`.Omitting this flag, or specifying `--repositories=all`, will search all repositories]' \
'--to[Date (ISO-8601 format) to stop searching contributions]' \
'--verbose[Make some output more verbose]'
}
# brew create
_brew_create() {
_arguments \

View File

@ -544,6 +544,52 @@ Instead of `git diff | pbcopy`, for some editors `git diff >> path/to/your/formu
If anything isnt clear, you can usually figure it out by `grep`ping the `$(brew --repository homebrew/core)` directory. Please submit a pull request to amend this document if you think it will help!
### Handling different system configurations
Often, formulae need different dependencies, resources, patches, conflicts, deprecations or `keg_only` statuses on different OSes and arches. In these cases, the components can be nested inside `on_macos`, `on_linux`, `on_arm` or `on_intel` blocks. For example, here's how to add `gcc` as a Linux-only dependency:
```ruby
on_linux do
depends_on "gcc"
end
```
Components can also be declared for specific macOS versions or version ranges. For example, to declare a dependency only on High Sierra, nest the `depends_on` call inside an `on_high_sierra` block. Add an `:or_older` or `:or_newer` parameter to the `on_high_sierra` method to add the dependency to all macOS versions that meet the condition. For example, to add `gettext` as a build dependency on Mojave and all later macOS versions, use:
```ruby
on_mojave :or_newer do
depends_on "gettext" => :build
end
```
Sometimes, a dependency is needed on certain macOS versions *and* on Linux. In these cases, a special `on_system` method can be used:
```ruby
on_system :linux, macos: :sierra_or_older do
depends_on "gettext" => :build
end
```
To check multiple conditions, nest the corresponding blocks. For example, the following code adds a `gettext` build dependency when on ARM *and* macOS:
```ruby
on_macos do
on_arm do
depends_on "gettext" => :build
end
end
```
#### Inside `def install` and `test do`
Inside `def install` and `test do`, don't use these `on_*` methods. Instead, use `if` statements and the following conditionals:
* `OS.mac?` and `OS.linux?` return `true` or `false` based on the OS
* `Hardware::CPU.intel?` and `Hardware::CPU.arm?` return `true` or `false` based on the arch
* `MacOS.version` returns the current macOS version. Use `==`, `<=` or `>=` to compare to symbols corresponding to macOS versions (e.g. `if MacOS.version >= :mojave`)
See [`rust`](https://github.com/Homebrew/homebrew-core/blob/fe831237a7c24033a48f588a1578ba54f953f922/Formula/rust.rb#L72) for an example.
### `livecheck` blocks
When `brew livecheck` is unable to identify versions for a formula, we can control its behavior using a `livecheck` block. Here is a simple example to check a page for links containing a filename like `example-1.2.tar.gz`:

View File

@ -1081,6 +1081,19 @@ Display the source of a *`formula`* or *`cask`*.
Display the path to the file being used when invoking `brew` *`cmd`*.
### `contributions` *`email|name`* [*`--repositories`*`=`]
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").
* `--repositories`:
Specify a comma-separated (no spaces) list of repositories to search. Supported repositories: `brew`, `core`, `cask`, `aliases`, `autoupdate`, `bundle`, `command-not-found`, `test-bot`, `services`, `cask-drivers`, `cask-fonts` and `cask-versions`.Omitting this flag, or specifying `--repositories=all`, will search all repositories.
* `--from`:
Date (ISO-8601 format) to start searching contributions.
* `--to`:
Date (ISO-8601 format) to stop searching contributions.
### `create` [*`options`*] *`URL`*
Generate a formula or, with `--cask`, a cask for the downloadable file at *`URL`*
@ -1947,6 +1960,9 @@ example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just
*Default:* `300`.
- `HOMEBREW_AUTOREMOVE`
<br>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.
- `HOMEBREW_BAT`
<br>If set, use `bat` for the `brew cat` command.
@ -2127,7 +2143,7 @@ example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just
<br>If set, do not check for broken linkage of dependents or outdated dependents after installing, upgrading or reinstalling formulae. This will result in fewer dependents (and their dependencies) being upgraded or reinstalled but may result in more breakage from running `brew install *`formula`*` or `brew upgrade *`formula`*`.
- `HOMEBREW_NO_CLEANUP_FORMULAE`
<br>A comma-separated list of formulae. Homebrew will refuse to clean up a formula if it appears on this list.
<br>A comma-separated list of formulae. Homebrew will refuse to clean up or autoremove a formula if it appears on this list.
- `HOMEBREW_NO_COLOR`
<br>If set, do not print text with colour added.

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BREW" "1" "July 2022" "Homebrew" "brew"
.TH "BREW" "1" "August 2022" "Homebrew" "brew"
.
.SH "NAME"
\fBbrew\fR \- The Missing Package Manager for macOS (or Linux)
@ -1539,6 +1539,24 @@ Treat all named arguments as casks\.
.SS "\fBcommand\fR \fIcommand\fR [\.\.\.]"
Display the path to the file being used when invoking \fBbrew\fR \fIcmd\fR\.
.
.SS "\fBcontributions\fR \fIemail|name\fR [\fI\-\-repositories\fR\fB=\fR]"
Contributions to Homebrew repos for a user\.
.
.P
The first argument is a name (e\.g\. "BrewTestBot") or an email address (e\.g\. "brewtestbot@brew\.sh")\.
.
.TP
\fB\-\-repositories\fR
Specify a comma\-separated (no spaces) list of repositories to search\. Supported repositories: \fBbrew\fR, \fBcore\fR, \fBcask\fR, \fBaliases\fR, \fBautoupdate\fR, \fBbundle\fR, \fBcommand\-not\-found\fR, \fBtest\-bot\fR, \fBservices\fR, \fBcask\-drivers\fR, \fBcask\-fonts\fR and \fBcask\-versions\fR\.Omitting this flag, or specifying \fB\-\-repositories=all\fR, will search all repositories\.
.
.TP
\fB\-\-from\fR
Date (ISO\-8601 format) to start searching contributions\.
.
.TP
\fB\-\-to\fR
Date (ISO\-8601 format) to stop searching contributions\.
.
.SS "\fBcreate\fR [\fIoptions\fR] \fIURL\fR"
Generate a formula or, with \fB\-\-cask\fR, a cask for the downloadable file at \fIURL\fR and open it in the editor\. Homebrew will attempt to automatically derive the formula name and version, but if it fails, you\'ll have to make your own template\. The \fBwget\fR formula serves as a simple example\. For the complete API, see: \fIhttps://rubydoc\.brew\.sh/Formula\fR
.
@ -2761,6 +2779,12 @@ Run \fBbrew update\fR once every \fBHOMEBREW_AUTO_UPDATE_SECS\fR seconds before
\fIDefault:\fR \fB300\fR\.
.
.TP
\fBHOMEBREW_AUTOREMOVE\fR
.
.br
If set, calls to \fBbrew cleanup\fR and \fBbrew uninstall\fR will automatically remove unused formula dependents and if HOMEBREW_NO_INSTALL_CLEANUP is not set, \fBbrew cleanup\fR will start running \fBbrew autoremove\fR periodically\.
.
.TP
\fBHOMEBREW_BAT\fR
.
.br
@ -3100,7 +3124,7 @@ If set, do not check for broken linkage of dependents or outdated dependents aft
\fBHOMEBREW_NO_CLEANUP_FORMULAE\fR
.
.br
A comma\-separated list of formulae\. Homebrew will refuse to clean up a formula if it appears on this list\.
A comma\-separated list of formulae\. Homebrew will refuse to clean up or autoremove a formula if it appears on this list\.
.
.TP
\fBHOMEBREW_NO_COLOR\fR