Merge branch 'master' into integrate-uninstall-reinstall

This commit is contained in:
William Ma 2020-07-02 15:13:10 -04:00
commit 3459931a8d
48 changed files with 6308 additions and 398 deletions

View File

@ -114,6 +114,9 @@ jobs:
- name: Run brew man - name: Run brew man
run: brew man --fail-if-changed run: brew man --fail-if-changed
- name: Check for outdated license data
run: brew update-license-data --fail-if-changed
- name: Run brew tests - name: Run brew tests
run: | run: |
# brew tests doesn't like world writable directories # brew tests doesn't like world writable directories
@ -136,8 +139,7 @@ jobs:
HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# set variables for coverage reporting # set variables for coverage reporting
HOMEBREW_CI_NAME: github-actions HOMEBREW_CODECOV_TOKEN: 3ea0364c-80ce-47a3-9fba-93a940d4b5d7
HOMEBREW_COVERALLS_REPO_TOKEN: 3F6U6ZqctoNJwKyREremsqMgpU3qYgxFk
# These cannot be queried at the macOS level on GitHub Actions. # These cannot be queried at the macOS level on GitHub Actions.
HOMEBREW_LANGUAGES: en-GB HOMEBREW_LANGUAGES: en-GB

7
.gitignore vendored
View File

@ -86,7 +86,7 @@
**/vendor/bundle/ruby/*/gems/byebug-*/ **/vendor/bundle/ruby/*/gems/byebug-*/
**/vendor/bundle/ruby/*/gems/coderay-*/ **/vendor/bundle/ruby/*/gems/coderay-*/
**/vendor/bundle/ruby/*/gems/connection_pool-*/ **/vendor/bundle/ruby/*/gems/connection_pool-*/
**/vendor/bundle/ruby/*/gems/coveralls-*/ **/vendor/bundle/ruby/*/gems/codecov-*/
**/vendor/bundle/ruby/*/gems/diff-lcs-*/ **/vendor/bundle/ruby/*/gems/diff-lcs-*/
**/vendor/bundle/ruby/*/gems/docile-*/ **/vendor/bundle/ruby/*/gems/docile-*/
**/vendor/bundle/ruby/*/gems/domain_name-*/ **/vendor/bundle/ruby/*/gems/domain_name-*/
@ -127,11 +127,8 @@
**/vendor/bundle/ruby/*/gems/ruby-prof-*/ **/vendor/bundle/ruby/*/gems/ruby-prof-*/
**/vendor/bundle/ruby/*/gems/ruby-progressbar-*/ **/vendor/bundle/ruby/*/gems/ruby-progressbar-*/
**/vendor/bundle/ruby/*/gems/simplecov-*/ **/vendor/bundle/ruby/*/gems/simplecov-*/
**/vendor/bundle/ruby/*/gems/simplecov-cobertura-*/
**/vendor/bundle/ruby/*/gems/simplecov-html-*/ **/vendor/bundle/ruby/*/gems/simplecov-html-*/
**/vendor/bundle/ruby/*/gems/term-ansicolor-*/ **/vendor/bundle/ruby/*/gems/url-*/
**/vendor/bundle/ruby/*/gems/thor-*/
**/vendor/bundle/ruby/*/gems/tins-*/
**/vendor/bundle/ruby/*/gems/unf_ext-*/ **/vendor/bundle/ruby/*/gems/unf_ext-*/
**/vendor/bundle/ruby/*/gems/unf-*/ **/vendor/bundle/ruby/*/gems/unf-*/
**/vendor/bundle/ruby/*/gems/unicode-display_width-*/ **/vendor/bundle/ruby/*/gems/unicode-display_width-*/

View File

@ -1,4 +1,5 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# frozen_string_literal: true
require "English" require "English"
@ -20,7 +21,8 @@ SimpleCov.start do
# Just save result, but don't write formatted output. # Just save result, but don't write formatted output.
coverage_result = Coverage.result coverage_result = Coverage.result
SimpleCov.add_not_loaded_files(coverage_result) # TODO: this method is private, find a better way.
SimpleCov.send(:add_not_loaded_files, coverage_result)
simplecov_result = SimpleCov::Result.new(coverage_result) simplecov_result = SimpleCov::Result.new(coverage_result)
SimpleCov::ResultMerger.store_result(simplecov_result) SimpleCov::ResultMerger.store_result(simplecov_result)
@ -50,8 +52,8 @@ SimpleCov.start do
require "rbconfig" require "rbconfig"
host_os = RbConfig::CONFIG["host_os"] host_os = RbConfig::CONFIG["host_os"]
add_filter %r{/os/mac} if host_os !~ /darwin/ add_filter %r{/os/mac} unless /darwin/.match?(host_os)
add_filter %r{/os/linux} if host_os !~ /linux/ add_filter %r{/os/linux} unless /linux/.match?(host_os)
# Add groups and the proper project name to the output. # Add groups and the proper project name to the output.
project_name "Homebrew" project_name "Homebrew"

View File

@ -4,7 +4,7 @@ source "https://rubygems.org"
# installed gems # installed gems
gem "byebug" gem "byebug"
gem "coveralls", "~> 0.8", require: false gem "codecov", require: false
gem "parallel_tests" gem "parallel_tests"
gem "ronn", require: false gem "ronn", require: false
gem "rspec" gem "rspec"

View File

@ -9,15 +9,13 @@ GEM
zeitwerk (~> 2.2, >= 2.2.2) zeitwerk (~> 2.2, >= 2.2.2)
ast (2.4.1) ast (2.4.1)
byebug (11.1.3) byebug (11.1.3)
codecov (0.1.17)
json
simplecov
url
concurrent-ruby (1.1.6) concurrent-ruby (1.1.6)
connection_pool (2.2.3) connection_pool (2.2.3)
coveralls (0.8.23) diff-lcs (1.4.4)
json (>= 1.8, < 3)
simplecov (~> 0.16.1)
term-ansicolor (~> 1.3)
thor (>= 0.19.4, < 2.0)
tins (~> 1.6)
diff-lcs (1.4.3)
docile (1.3.2) docile (1.3.2)
domain_name (0.5.20190701) domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
@ -99,24 +97,18 @@ GEM
rubocop (>= 0.68.1) rubocop (>= 0.68.1)
ruby-macho (2.2.0) ruby-macho (2.2.0)
ruby-progressbar (1.10.1) ruby-progressbar (1.10.1)
simplecov (0.16.1) simplecov (0.18.5)
docile (~> 1.1) docile (~> 1.1)
json (>= 1.8, < 3) simplecov-html (~> 0.11)
simplecov-html (~> 0.10.0) simplecov-html (0.12.2)
simplecov-html (0.10.2)
sync (0.5.0)
term-ansicolor (1.7.1)
tins (~> 1.0)
thor (1.0.1)
thread_safe (0.3.6) thread_safe (0.3.6)
tins (1.25.0)
sync
tzinfo (1.2.7) tzinfo (1.2.7)
thread_safe (~> 0.1) thread_safe (~> 0.1)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.7) unf_ext (0.0.7.7)
unicode-display_width (1.7.0) unicode-display_width (1.7.0)
url (0.3.2)
webrobots (0.1.2) webrobots (0.1.2)
zeitwerk (2.3.1) zeitwerk (2.3.1)
@ -126,8 +118,8 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
activesupport activesupport
byebug byebug
codecov
concurrent-ruby concurrent-ruby
coveralls (~> 0.8)
mechanize mechanize
parallel_tests parallel_tests
plist plist
@ -143,4 +135,4 @@ DEPENDENCIES
simplecov simplecov
BUNDLED WITH BUNDLED WITH
1.17.2 1.17.3

View File

@ -41,7 +41,7 @@ class Bintray
def upload(local_file, repo:, package:, version:, remote_file:, sha256: nil) def upload(local_file, repo:, package:, version:, remote_file:, sha256: nil)
url = "#{API_URL}/content/#{@bintray_org}/#{repo}/#{package}/#{version}/#{remote_file}" url = "#{API_URL}/content/#{@bintray_org}/#{repo}/#{package}/#{version}/#{remote_file}"
args = ["--upload-file", local_file] args = ["--fail", "--upload-file", local_file]
args += ["--header", "X-Checksum-Sha2: #{sha256}"] unless sha256.blank? args += ["--header", "X-Checksum-Sha2: #{sha256}"] unless sha256.blank?
result = open_api url, *args result = open_api url, *args
json = JSON.parse(result.stdout) json = JSON.parse(result.stdout)
@ -50,12 +50,15 @@ class Bintray
result result
end end
def publish(repo:, package:, version:, file_count:) def publish(repo:, package:, version:, file_count:, warn_on_error: false)
url = "#{API_URL}/content/#{@bintray_org}/#{repo}/#{package}/#{version}/publish" url = "#{API_URL}/content/#{@bintray_org}/#{repo}/#{package}/#{version}/publish"
result = open_api url, "--request", "POST" result = open_api url, "--request", "POST", "--fail"
json = JSON.parse(result.stdout) json = JSON.parse(result.stdout)
if file_count.present? && json["files"] != file_count if file_count.present? && json["files"] != file_count
raise "Bottle publish failed: expected #{file_count} bottles, but published #{json["files"]} instead." message = "Bottle publish failed: expected #{file_count} bottles, but published #{json["files"]} instead."
raise message unless warn_on_error
opoo message
end end
odebug "Published #{json["files"]} bottles" odebug "Published #{json["files"]} bottles"
@ -143,7 +146,7 @@ class Bintray
end end
end end
def upload_bottle_json(json_files, publish_package: false) def upload_bottle_json(json_files, publish_package: false, warn_on_error: false)
bottles_hash = json_files.reduce({}) do |hash, json_file| bottles_hash = json_files.reduce({}) do |hash, json_file|
hash.deep_merge(JSON.parse(IO.read(json_file))) hash.deep_merge(JSON.parse(IO.read(json_file)))
end end
@ -161,14 +164,19 @@ class Bintray
odebug "Checking remote file #{@bintray_org}/#{bintray_repo}/#{filename}" odebug "Checking remote file #{@bintray_org}/#{bintray_repo}/#{filename}"
if file_published? repo: bintray_repo, remote_file: filename if file_published? repo: bintray_repo, remote_file: filename
raise Error, <<~EOS already_published = "#{filename} is already published."
#{filename} is already published. failed_message = <<~EOS
#{already_published}
Please remove it manually from: Please remove it manually from:
https://bintray.com/#{@bintray_org}/#{bintray_repo}/#{bintray_package}/view#files https://bintray.com/#{@bintray_org}/#{bintray_repo}/#{bintray_package}/view#files
Or run: Or run:
curl -X DELETE -u $HOMEBREW_BINTRAY_USER:$HOMEBREW_BINTRAY_KEY \\ curl -X DELETE -u $HOMEBREW_BINTRAY_USER:$HOMEBREW_BINTRAY_KEY \\
https://api.bintray.com/content/#{@bintray_org}/#{bintray_repo}/#{filename} https://api.bintray.com/content/#{@bintray_org}/#{bintray_repo}/#{filename}
EOS EOS
raise Error, failed_message unless warn_on_error
opoo already_published
next
end end
if !formula_packaged[formula_name] && !package_exists?(repo: bintray_repo, package: bintray_package) if !formula_packaged[formula_name] && !package_exists?(repo: bintray_repo, package: bintray_package)
@ -189,7 +197,11 @@ class Bintray
bottle_count = bottle_hash["bottle"]["tags"].length bottle_count = bottle_hash["bottle"]["tags"].length
odebug "Publishing #{@bintray_org}/#{bintray_repo}/#{bintray_package}/#{version}" odebug "Publishing #{@bintray_org}/#{bintray_repo}/#{bintray_package}/#{version}"
publish repo: bintray_repo, package: bintray_package, version: version, file_count: bottle_count publish(repo: bintray_repo,
package: bintray_package,
version: version,
file_count: bottle_count,
warn_on_error: warn_on_error)
end end
end end
end end

View File

@ -211,6 +211,8 @@ module Homebrew
puts "From: #{Formatter.url(github_info(f))}" puts "From: #{Formatter.url(github_info(f))}"
puts "License: #{f.license}" if f.license
unless f.deps.empty? unless f.deps.empty?
ohai "Dependencies" ohai "Dependencies"
%w[build required recommended optional].map do |type| %w[build required recommended optional].map do |type|

View File

@ -7,6 +7,7 @@ require "install"
require "search" require "search"
require "cleanup" require "cleanup"
require "cli/parser" require "cli/parser"
require "upgrade"
module Homebrew module Homebrew
module_function module_function
@ -261,6 +262,9 @@ module Homebrew
install_formula(f) install_formula(f)
Cleanup.install_formula_clean!(f) Cleanup.install_formula_clean!(f)
end end
check_installed_dependents
Homebrew.messages.display_messages Homebrew.messages.display_messages
rescue FormulaUnreadableError, FormulaClassUnavailableError, rescue FormulaUnreadableError, FormulaClassUnavailableError,
TapFormulaUnreadableError, TapFormulaClassUnavailableError => e TapFormulaUnreadableError, TapFormulaClassUnavailableError => e

View File

@ -11,10 +11,10 @@ module Homebrew
usage_banner <<~EOS usage_banner <<~EOS
`readall` [<options>] [<tap>] `readall` [<options>] [<tap>]
Import all formulae from the specified <tap>, or from all installed taps if none is provided. Import all items from the specified <tap>, or from all installed taps if none is provided.
This can be useful for debugging issues across all formulae when making This can be useful for debugging issues across all items when making
significant changes to `formula.rb`, testing the performance of loading significant changes to `formula.rb`, testing the performance of loading
all formulae or checking if any current formulae have Ruby issues. all items or checking if any current formulae/casks have Ruby issues.
EOS EOS
switch "--aliases", switch "--aliases",
description: "Verify any alias symlinks in each tap." description: "Verify any alias symlinks in each tap."
@ -30,7 +30,7 @@ module Homebrew
if args.syntax? if args.syntax?
scan_files = "#{HOMEBREW_LIBRARY_PATH}/**/*.rb" scan_files = "#{HOMEBREW_LIBRARY_PATH}/**/*.rb"
ruby_files = Dir.glob(scan_files).reject { |file| file =~ %r{/(vendor|cask)/} } ruby_files = Dir.glob(scan_files).reject { |file| file =~ %r{/(vendor)/} }
Homebrew.failed = true unless Readall.valid_ruby_syntax?(ruby_files) Homebrew.failed = true unless Readall.valid_ruby_syntax?(ruby_files)
end end

View File

@ -9,6 +9,7 @@ require "cleanup"
require "cask/cmd" require "cask/cmd"
require "cask/utils" require "cask/utils"
require "cask/macos" require "cask/macos"
require "upgrade"
module Homebrew module Homebrew
module_function module_function
@ -69,6 +70,9 @@ module Homebrew
reinstall_formula(f) reinstall_formula(f)
Cleanup.install_formula_clean!(f) Cleanup.install_formula_clean!(f)
end end
check_installed_dependents
Homebrew.messages.display_messages Homebrew.messages.display_messages
return if casks.empty? return if casks.empty?

View File

@ -1,12 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
require "install"
require "reinstall"
require "formula_installer"
require "development_tools"
require "messages"
require "cleanup"
require "cli/parser" require "cli/parser"
require "formula_installer"
require "install"
require "upgrade"
module Homebrew module Homebrew
module_function module_function
@ -114,241 +111,8 @@ module Homebrew
upgrade_formulae(formulae_to_install) upgrade_formulae(formulae_to_install)
check_dependents(formulae_to_install) check_installed_dependents
Homebrew.messages.display_messages Homebrew.messages.display_messages
end end
def upgrade_formulae(formulae_to_install)
return if formulae_to_install.empty?
return if args.dry_run?
# Sort keg-only before non-keg-only formulae to avoid any needless conflicts
# with outdated, non-keg-only versions of formulae being upgraded.
formulae_to_install.sort! do |a, b|
if !a.keg_only? && b.keg_only?
1
elsif a.keg_only? && !b.keg_only?
-1
else
0
end
end
formulae_to_install.each do |f|
Migrator.migrate_if_needed(f)
begin
upgrade_formula(f)
Cleanup.install_formula_clean!(f)
rescue UnsatisfiedRequirements => e
Homebrew.failed = true
onoe "#{f}: #{e}"
end
end
end
def upgrade_formula(f)
return if args.dry_run?
if f.opt_prefix.directory?
keg = Keg.new(f.opt_prefix.resolved_path)
keg_had_linked_opt = true
keg_was_linked = keg.linked?
end
formulae_maybe_with_kegs = [f] + f.old_installed_formulae
outdated_kegs = formulae_maybe_with_kegs
.map(&:linked_keg)
.select(&:directory?)
.map { |k| Keg.new(k.resolved_path) }
linked_kegs = outdated_kegs.select(&:linked?)
if f.opt_prefix.directory?
keg = Keg.new(f.opt_prefix.resolved_path)
tab = Tab.for_keg(keg)
end
build_options = BuildOptions.new(Options.create(args.flags_only), f.options)
options = build_options.used_options
options |= f.build.used_options
options &= f.options
fi = FormulaInstaller.new(f)
fi.options = options
fi.build_bottle = args.build_bottle?
fi.installed_on_request = args.named.present?
fi.link_keg ||= keg_was_linked if keg_had_linked_opt
if tab
fi.build_bottle ||= tab.built_bottle?
fi.installed_as_dependency = tab.installed_as_dependency
fi.installed_on_request ||= tab.installed_on_request
end
upgrade_version = if f.optlinked?
"#{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
else
"-> #{f.pkg_version}"
end
oh1 "Upgrading #{Formatter.identifier(f.full_specified_name)} #{upgrade_version} #{fi.options.to_a.join(" ")}"
fi.prelude
fi.fetch
# first we unlink the currently active keg for this formula otherwise it is
# possible for the existing build to interfere with the build we are about to
# do! Seriously, it happens!
outdated_kegs.each(&:unlink)
fi.install
fi.finish
rescue FormulaInstallationAlreadyAttemptedError
# We already attempted to upgrade f as part of the dependency tree of
# another formula. In that case, don't generate an error, just move on.
nil
rescue CannotInstallFormulaError => e
ofail e
rescue BuildError => e
e.dump
puts
Homebrew.failed = true
rescue DownloadError => e
ofail e
ensure
# restore previous installation state if build failed
begin
linked_kegs.each(&:link) unless f.latest_version_installed?
rescue
nil
end
end
# @private
def depends_on(a, b)
if a.opt_or_installed_prefix_keg
&.runtime_dependencies
&.any? { |d| d["full_name"] == b.full_name }
1
else
a <=> b
end
end
def check_dependents(formulae_to_install)
return if formulae_to_install.empty?
oh1 "Checking for dependents of upgraded formulae..." unless args.dry_run?
outdated_dependents =
formulae_to_install.flat_map(&:runtime_installed_formula_dependents)
.select(&:outdated?)
if outdated_dependents.blank?
ohai "No dependents found!" unless args.dry_run?
return
end
outdated_dependents -= formulae_to_install if args.dry_run?
upgradeable_dependents =
outdated_dependents.reject(&:pinned?)
.sort { |a, b| depends_on(a, b) }
pinned_dependents =
outdated_dependents.select(&:pinned?)
.sort { |a, b| depends_on(a, b) }
if pinned_dependents.present?
plural = "dependent".pluralize(pinned_dependents.count)
ohai "Not upgrading #{pinned_dependents.count} pinned #{plural}:"
puts(pinned_dependents.map do |f|
"#{f.full_specified_name} #{f.pkg_version}"
end.join(", "))
end
# Print the upgradable dependents.
if upgradeable_dependents.blank?
ohai "No outdated dependents to upgrade!" unless args.dry_run?
else
plural = "dependent".pluralize(upgradeable_dependents.count)
verb = args.dry_run? ? "Would upgrade" : "Upgrading"
ohai "#{verb} #{upgradeable_dependents.count} #{plural}:"
formulae_upgrades = upgradeable_dependents.map do |f|
name = f.full_specified_name
if f.optlinked?
"#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
else
"#{name} #{f.pkg_version}"
end
end
puts formulae_upgrades.join(", ")
end
upgrade_formulae(upgradeable_dependents)
# Assess the dependents tree again now we've upgraded.
oh1 "Checking for dependents of upgraded formulae..." unless args.dry_run?
broken_dependents = CacheStoreDatabase.use(:linkage) do |db|
formulae_to_install.flat_map(&:runtime_installed_formula_dependents)
.select do |f|
keg = f.opt_or_installed_prefix_keg
next unless keg
LinkageChecker.new(keg, cache_db: db)
.broken_library_linkage?
end.compact
end
if broken_dependents.blank?
if args.dry_run?
ohai "No currently broken dependents found!"
opoo "If they are broken by the upgrade they will also be upgraded or reinstalled."
else
ohai "No broken dependents found!"
end
return
end
reinstallable_broken_dependents =
broken_dependents.reject(&:outdated?)
.reject(&:pinned?)
.sort { |a, b| depends_on(a, b) }
outdated_pinned_broken_dependents =
broken_dependents.select(&:outdated?)
.select(&:pinned?)
.sort { |a, b| depends_on(a, b) }
# Print the pinned dependents.
if outdated_pinned_broken_dependents.present?
count = outdated_pinned_broken_dependents.count
plural = "dependent".pluralize(outdated_pinned_broken_dependents.count)
onoe "Not reinstalling #{count} broken and outdated, but pinned #{plural}:"
$stderr.puts(outdated_pinned_broken_dependents.map do |f|
"#{f.full_specified_name} #{f.pkg_version}"
end.join(", "))
end
# Print the broken dependents.
if reinstallable_broken_dependents.blank?
ohai "No broken dependents to reinstall!"
else
count = reinstallable_broken_dependents.count
plural = "dependent".pluralize(reinstallable_broken_dependents.count)
ohai "Reinstalling #{count} broken #{plural} from source:"
puts reinstallable_broken_dependents.map(&:full_specified_name)
.join(", ")
end
return if args.dry_run?
reinstallable_broken_dependents.each do |f|
reinstall_formula(f, build_from_source: true)
rescue FormulaInstallationAlreadyAttemptedError
# We already attempted to reinstall f as part of the dependency tree of
# another formula. In that case, don't generate an error, just move on.
nil
rescue CannotInstallFormulaError => e
ofail e
rescue BuildError => e
e.dump
puts
Homebrew.failed = true
rescue DownloadError => e
ofail e
end
end
end end

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,7 @@ require "date"
require "missing_formula" require "missing_formula"
require "digest" require "digest"
require "cli/parser" require "cli/parser"
require "json"
module Homebrew module Homebrew
module_function module_function
@ -109,7 +110,9 @@ module Homebrew
# Check style in a single batch run up front for performance # Check style in a single batch run up front for performance
style_results = Style.check_style_json(style_files, options) if style_files style_results = Style.check_style_json(style_files, options) if style_files
# load licenses
spdx = HOMEBREW_LIBRARY_PATH/"data/spdx.json"
spdx_data = JSON.parse(spdx.read)
new_formula_problem_lines = [] new_formula_problem_lines = []
audit_formulae.sort.each do |f| audit_formulae.sort.each do |f|
only = only_cops ? ["style"] : args.only only = only_cops ? ["style"] : args.only
@ -120,6 +123,7 @@ module Homebrew
git: git, git: git,
only: only, only: only,
except: args.except, except: args.except,
spdx_data: spdx_data,
} }
options[:style_offenses] = style_results.file_offenses(f.path) if style_results options[:style_offenses] = style_results.file_offenses(f.path) if style_results
options[:display_cop_names] = args.display_cop_names? options[:display_cop_names] = args.display_cop_names?
@ -215,6 +219,7 @@ module Homebrew
@new_formula_problems = [] @new_formula_problems = []
@text = FormulaText.new(formula.path) @text = FormulaText.new(formula.path)
@specs = %w[stable devel head].map { |s| formula.send(s) }.compact @specs = %w[stable devel head].map { |s| formula.send(s) }.compact
@spdx_data = options[:spdx_data]
end end
def audit_style def audit_style
@ -327,6 +332,27 @@ module Homebrew
openssl@1.1 openssl@1.1
].freeze ].freeze
def audit_license
if formula.license.present?
if @spdx_data["licenses"].any? { |lic| lic["licenseId"] == formula.license }
return unless @online
user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if @new_formula
return if user.blank?
github_license = GitHub.get_repo_license(user, repo)
return if github_license && (github_license == formula.license)
problem "License mismatch - GitHub license is: #{github_license}, "\
"but Formulae license states: #{formula.license}."
else
problem "#{formula.license} is not a standard SPDX license."
end
elsif @new_formula
problem "No license specified for package."
end
end
def audit_deps def audit_deps
@specs.each do |spec| @specs.each do |spec|
# Check for things we don't like to depend on. # Check for things we don't like to depend on.
@ -502,8 +528,9 @@ module Homebrew
end end
def audit_github_repository def audit_github_repository
user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if @new_formula
return if user.nil?
return if user.blank?
warning = SharedAudits.github(user, repo) warning = SharedAudits.github(user, repo)
return if warning.nil? return if warning.nil?
@ -512,8 +539,8 @@ module Homebrew
end end
def audit_gitlab_repository def audit_gitlab_repository
user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*}) user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*}) if @new_formula
return if user.nil? return if user.blank?
warning = SharedAudits.gitlab(user, repo) warning = SharedAudits.gitlab(user, repo)
return if warning.nil? return if warning.nil?
@ -522,8 +549,8 @@ module Homebrew
end end
def audit_bitbucket_repository def audit_bitbucket_repository
user, repo = get_repo_data(%r{https?://bitbucket\.org/([^/]+)/([^/]+)/?.*}) user, repo = get_repo_data(%r{https?://bitbucket\.org/([^/]+)/([^/]+)/?.*}) if @new_formula
return if user.nil? return if user.blank?
warning = SharedAudits.bitbucket(user, repo) warning = SharedAudits.bitbucket(user, repo)
return if warning.nil? return if warning.nil?
@ -534,7 +561,6 @@ module Homebrew
def get_repo_data(regex) def get_repo_data(regex)
return unless @core_tap return unless @core_tap
return unless @online return unless @online
return unless @new_formula
_, user, repo = *regex.match(formula.stable.url) if formula.stable _, user, repo = *regex.match(formula.stable.url) if formula.stable
_, user, repo = *regex.match(formula.homepage) unless user _, user, repo = *regex.match(formula.homepage) unless user

View File

@ -531,25 +531,21 @@ module Homebrew
odie "--keep-old was passed but there was no existing bottle block!" if args.keep_old? odie "--keep-old was passed but there was no existing bottle block!" if args.keep_old?
puts output puts output
update_or_add = "add" update_or_add = "add"
if s.include? "stable do" pattern = /(
indent = s.slice(/^( +)stable do/, 1).length (\ {2}\#[^\n]*\n)* # comments
string = s.sub!(/^ {#{indent}}stable do(.|\n)+?^ {#{indent}}end\n/m, '\0' + output + "\n") \ {2}( # two spaces at the beginning
else (url|head)\ ['"][\S\ ]+['"] # url or head with a string
pattern = /( (
(\ {2}\#[^\n]*\n)* # comments ,[\S\ ]*$ # url may have options
\ {2}( # two spaces at the beginning (\n^\ {3}[\S\ ]+$)* # options can be in multiple lines
(url|head)\ ['"][\S\ ]+['"] # url or head with a string )?|
( (homepage|desc|sha256|version|mirror|license)\ ['"][\S\ ]+['"]| # specs with a string
,[\S\ ]*$ # url may have options (revision|version_scheme)\ \d+| # revision with a number
(\n^\ {3}[\S\ ]+$)* # options can be in multiple lines (stable|livecheck)\ do(\n+^\ {4}[\S\ ]+$)*\n+^\ {2}end # components with blocks
)?| )\n+ # multiple empty lines
(homepage|desc|sha1|sha256|version|mirror)\ ['"][\S\ ]+['"]| # specs with a string )+
(revision|version_scheme)\ \d+ # revision with a number /mx
)\n+ # multiple empty lines string = s.sub!(pattern, '\0' + output + "\n")
)+
/mx
string = s.sub!(pattern, '\0' + output + "\n")
end
odie "Bottle block addition failed!" unless string odie "Bottle block addition failed!" unless string
end end
end end

View File

@ -47,6 +47,8 @@ module Homebrew
description: "Explicitly set the <name> of the new formula." description: "Explicitly set the <name> of the new formula."
flag "--set-version=", flag "--set-version=",
description: "Explicitly set the <version> of the new formula." description: "Explicitly set the <version> of the new formula."
flag "--set-license=",
description: "Explicitly set the <license> of the new formula."
flag "--tap=", flag "--tap=",
description: "Generate the new formula within the given tap, specified as <user>`/`<repo>." description: "Generate the new formula within the given tap, specified as <user>`/`<repo>."
switch :force switch :force
@ -68,11 +70,13 @@ module Homebrew
version = args.set_version version = args.set_version
name = args.set_name name = args.set_name
license = args.set_license
tap = args.tap tap = args.tap
fc = FormulaCreator.new fc = FormulaCreator.new
fc.name = name fc.name = name
fc.version = version fc.version = version
fc.license = license
fc.tap = Tap.fetch(tap || "homebrew/core") fc.tap = Tap.fetch(tap || "homebrew/core")
raise TapUnavailableError, tap unless fc.tap.installed? raise TapUnavailableError, tap unless fc.tap.installed?

View File

@ -191,7 +191,10 @@ module Homebrew
# Remove any existing version suffixes, as a new one will be added later # Remove any existing version suffixes, as a new one will be added later
name.sub!(/\b@(.*)\z\b/i, "") name.sub!(/\b@(.*)\z\b/i, "")
versioned_name = Formulary.class_s("#{name}@#{version}") versioned_name = Formulary.class_s("#{name}@#{version}")
result.gsub!("class #{class_name} < Formula", "class #{versioned_name} < Formula") result.sub!("class #{class_name} < Formula", "class #{versioned_name} < Formula")
# Remove bottle blocks, they won't work.
result.sub!(/ bottle do.+?end\n\n/m, "") if destination_tap != source_tap
path = destination_tap.path/"Formula/#{name}@#{version}.rb" path = destination_tap.path/"Formula/#{name}@#{version}.rb"
if path.exist? if path.exist?
@ -205,7 +208,8 @@ module Homebrew
odebug "Overwriting existing formula at #{path}" odebug "Overwriting existing formula at #{path}"
path.delete path.delete
end end
ohai "Writing formula for #{name} from revision #{rev} to #{path}" ohai "Writing formula for #{name} from revision #{rev} to:"
puts path
path.write result path.write result
end end

View File

@ -33,6 +33,9 @@ module Homebrew
switch "--resolve", switch "--resolve",
description: "When a patch fails to apply, leave in progress and allow user to resolve, "\ description: "When a patch fails to apply, leave in progress and allow user to resolve, "\
"instead of aborting." "instead of aborting."
switch "--warn-on-upload-failure",
description: "Warn instead of raising an error if the bottle upload fails. "\
"Useful for repairing bottle uploads that previously failed."
flag "--workflow=", flag "--workflow=",
description: "Retrieve artifacts from the specified workflow (default: `tests.yml`)." description: "Retrieve artifacts from the specified workflow (default: `tests.yml`)."
flag "--artifact=", flag "--artifact=",
@ -73,13 +76,18 @@ module Homebrew
end end
end end
def signoff!(pr, path: ".") def signoff!(pr, tap:)
message = Utils.popen_read "git", "-C", path, "log", "-1", "--pretty=%B" message = Utils.popen_read "git", "-C", tap.path, "log", "-1", "--pretty=%B"
subject = message.lines.first.strip subject = message.lines.first.strip
# Skip the subject and separate lines that look like trailers (e.g. "Co-authored-by") # Skip the subject and separate lines that look like trailers (e.g. "Co-authored-by")
# from lines that look like regular body text. # from lines that look like regular body text.
trailers, body = message.lines.drop(1).partition { |s| s.match?(/^[a-z-]+-by:/i) } trailers, body = message.lines.drop(1).partition { |s| s.match?(/^[a-z-]+-by:/i) }
# Approving reviewers also sign-off on merge
trailers += GitHub.approved_reviews(tap.user, "homebrew-#{tap.repo}", pr).map do |r|
"Signed-off-by: #{r["name"]} <#{r["email"]}>\n"
end
trailers = trailers.uniq.join.strip trailers = trailers.uniq.join.strip
body = body.join.strip.gsub(/\n{3,}/, "\n\n") body = body.join.strip.gsub(/\n{3,}/, "\n\n")
@ -90,7 +98,7 @@ module Homebrew
if Homebrew.args.dry_run? if Homebrew.args.dry_run?
puts "git commit --amend --signoff -m $message" puts "git commit --amend --signoff -m $message"
else else
safe_system "git", "-C", path, "commit", "--amend", "--signoff", "--allow-empty", "-q", "-m", new_message safe_system "git", "-C", tap.path, "commit", "--amend", "--signoff", "--allow-empty", "-q", "-m", new_message
end end
end end
@ -232,7 +240,7 @@ module Homebrew
cd dir do cd dir do
original_commit = Utils.popen_read("git", "-C", tap.path, "rev-parse", "HEAD").chomp original_commit = Utils.popen_read("git", "-C", tap.path, "rev-parse", "HEAD").chomp
cherry_pick_pr! pr, path: tap.path cherry_pick_pr! pr, path: tap.path
signoff! pr, path: tap.path unless args.clean? signoff! pr, tap: tap unless args.clean?
unless args.no_upload? unless args.no_upload?
mirror_formulae(tap, original_commit, org: bintray_org, repo: mirror_repo, publish: !args.no_publish?) mirror_formulae(tap, original_commit, org: bintray_org, repo: mirror_repo, publish: !args.no_publish?)
@ -253,9 +261,10 @@ module Homebrew
upload_args << "--verbose" if Homebrew.args.verbose? upload_args << "--verbose" if Homebrew.args.verbose?
upload_args << "--no-publish" if args.no_publish? upload_args << "--no-publish" if args.no_publish?
upload_args << "--dry-run" if args.dry_run? upload_args << "--dry-run" if args.dry_run?
upload_args << "--warn-on-upload-failure" if args.warn_on_upload_failure?
upload_args << "--root_url=#{args.root_url}" if args.root_url upload_args << "--root_url=#{args.root_url}" if args.root_url
upload_args << "--bintray-org=#{bintray_org}" upload_args << "--bintray-org=#{bintray_org}"
system HOMEBREW_BREW_FILE, *upload_args safe_system HOMEBREW_BREW_FILE, *upload_args
end end
end end
end end

View File

@ -17,6 +17,9 @@ module Homebrew
description: "Apply the bottle commit and upload the bottles, but don't publish them." description: "Apply the bottle commit and upload the bottles, but don't publish them."
switch "-n", "--dry-run", switch "-n", "--dry-run",
description: "Print what would be done rather than doing it." description: "Print what would be done rather than doing it."
switch "--warn-on-upload-failure",
description: "Warn instead of raising an error if the bottle upload fails. "\
"Useful for repairing bottle uploads that previously failed."
flag "--bintray-org=", flag "--bintray-org=",
description: "Upload to the specified Bintray organisation (default: `homebrew`)." description: "Upload to the specified Bintray organisation (default: `homebrew`)."
flag "--root-url=", flag "--root-url=",
@ -42,13 +45,15 @@ module Homebrew
if args.dry_run? if args.dry_run?
puts "brew #{bottle_args.join " "}" puts "brew #{bottle_args.join " "}"
else else
system HOMEBREW_BREW_FILE, *bottle_args safe_system HOMEBREW_BREW_FILE, *bottle_args
end end
if args.dry_run? if args.dry_run?
puts "Upload bottles described by these JSON files to Bintray:\n #{Dir["*.json"].join("\n ")}" puts "Upload bottles described by these JSON files to Bintray:\n #{Dir["*.json"].join("\n ")}"
else else
bintray.upload_bottle_json Dir["*.json"], publish_package: !args.no_publish? bintray.upload_bottle_json(Dir["*.json"],
publish_package: !args.no_publish?,
warn_on_error: args.warn_on_upload_failure?)
end end
end end
end end

View File

@ -0,0 +1,39 @@
# frozen_string_literal: true
require "commands"
require "cli/parser"
require "json"
require "net/http"
require "open-uri"
module Homebrew
module_function
SPDX_PATH = (HOMEBREW_LIBRARY_PATH/"data/spdx.json").freeze
SPDX_DATA_URL = "https://raw.githubusercontent.com/spdx/license-list-data/HEAD/json/licenses.json"
def update_license_data_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`update_license_data` <cmd>
Update SPDX license data in the Homebrew repository.
EOS
switch "--fail-if-changed",
description: "Return a failing status code if current license data's version is different from " \
"the upstream. This can be used to notify CI when the SPDX license data is out of date."
max_named 0
end
end
def update_license_data
update_license_data_args.parse
ohai "Updating SPDX license data..."
curl_download(SPDX_DATA_URL, to: SPDX_PATH, partial: false)
return unless args.fail_if_changed?
safe_system "git", "diff", "--stat", "--exit-code", SPDX_PATH
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
module Readall
class << self
def valid_casks?(*)
true
end
end
end

View File

@ -12,6 +12,7 @@ module Homebrew
check_xcode_minimum_version check_xcode_minimum_version
check_clt_minimum_version check_clt_minimum_version
check_if_xcode_needs_clt_installed check_if_xcode_needs_clt_installed
check_if_supported_sdk_available
].freeze ].freeze
end end
@ -357,6 +358,34 @@ module Homebrew
Untap them with `brew untap`. Untap them with `brew untap`.
EOS EOS
end end
def check_if_supported_sdk_available
return unless MacOS.sdk_root_needed?
return if MacOS.sdk
locator = MacOS.sdk_locator
source = if locator.source == :clt
"CLT"
else
"Xcode"
end
all_sdks = locator.all_sdks
sdks_found_msg = unless all_sdks.empty?
<<~EOS
Homebrew found the following SDKs in the #{source} install:
#{locator.all_sdks.map(&:version).join("\n ")}
EOS
end
<<~EOS
Could not find an SDK that supports macOS #{MacOS.version}.
You may have have an outdated or incompatible #{source}.
#{sdks_found_msg}
Please update #{source} or uninstall it if no updates are available.
EOS
end
end end
end end
end end

View File

@ -0,0 +1,3 @@
# frozen_string_literal: true
require "extend/os/linux/readall" if OS.linux?

View File

@ -351,6 +351,9 @@ class Formula
# @see .desc= # @see .desc=
delegate desc: :"self.class" delegate desc: :"self.class"
# The SPDX ID of the software license.
delegate license: :"self.class"
# The homepage for the software. # The homepage for the software.
# @method homepage # @method homepage
# @see .homepage= # @see .homepage=
@ -1687,6 +1690,7 @@ class Formula
"aliases" => aliases.sort, "aliases" => aliases.sort,
"versioned_formulae" => versioned_formulae.map(&:name), "versioned_formulae" => versioned_formulae.map(&:name),
"desc" => desc, "desc" => desc,
"license" => license,
"homepage" => homepage, "homepage" => homepage,
"versions" => { "versions" => {
"stable" => stable&.version&.to_s, "stable" => stable&.version&.to_s,
@ -2211,6 +2215,13 @@ class Formula
# <pre>desc "Example formula"</pre> # <pre>desc "Example formula"</pre>
attr_rw :desc attr_rw :desc
# @!attribute [w]
# The SPDX ID of the open-source license that the formula uses.
# Shows when running `brew info`.
#
# <pre>license "BSD-2-Clause"</pre>
attr_rw :license
# @!attribute [w] homepage # @!attribute [w] homepage
# The homepage for the software. Used by users to get more information # The homepage for the software. Used by users to get more information
# about the software and Homebrew maintainers as a point of contact for # about the software and Homebrew maintainers as a point of contact for
@ -2648,9 +2659,13 @@ class Formula
# #
# The block will create, run in and delete a temporary directory. # The block will create, run in and delete a temporary directory.
# #
# We are fine if the executable does not error out, so we know linking # We want tests that don't require any user input
# and building the software was OK. # and test the basic functionality of the application.
# <pre>system bin/"foobar", "--version"</pre> # For example foo build-foo input.foo is a good test
# and foo --version and foo --help are bad tests.
# However, a bad test is better than no test at all.
#
# See: https://docs.brew.sh/Formula-Cookbook#add-a-test-to-the-formula
# #
# <pre>(testpath/"test.file").write <<~EOS # <pre>(testpath/"test.file").write <<~EOS
# writing some test file, if you need to # writing some test file, if you need to

View File

@ -6,7 +6,7 @@ require "erb"
module Homebrew module Homebrew
class FormulaCreator class FormulaCreator
attr_reader :url, :sha256, :desc, :homepage attr_reader :url, :sha256, :desc, :homepage
attr_accessor :name, :version, :tap, :path, :mode attr_accessor :name, :version, :tap, :path, :mode, :license
def url=(url) def url=(url)
@url = url @url = url
@ -100,6 +100,7 @@ module Homebrew
<% end %> <% end %>
sha256 "#{sha256}" sha256 "#{sha256}"
<% end %> <% end %>
license "#{license}"
<% if mode == :cmake %> <% if mode == :cmake %>
depends_on "cmake" => :build depends_on "cmake" => :build

View File

@ -77,6 +77,14 @@ class FormulaInstaller
@attempted = Set.new @attempted = Set.new
end end
def self.installed
@installed ||= Set.new
end
def self.clear_installed
@installed = Set.new
end
# When no build tools are available and build flags are passed through ARGV, # When no build tools are available and build flags are passed through ARGV,
# it's necessary to interrupt the user before any sort of installation # it's necessary to interrupt the user before any sort of installation
# can proceed. Only invoked when the user has no developer tools. # can proceed. Only invoked when the user has no developer tools.
@ -292,7 +300,7 @@ class FormulaInstaller
self.class.attempted << formula self.class.attempted << formula
if pour_bottle?(warn: true) if pour_bottle?
begin begin
pour pour
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
@ -700,6 +708,8 @@ class FormulaInstaller
ohai "Summary" if verbose? || show_summary_heading? ohai "Summary" if verbose? || show_summary_heading?
puts summary puts summary
self.class.installed << formula
ensure ensure
unlock unlock
end end
@ -983,11 +993,24 @@ class FormulaInstaller
return if only_deps? return if only_deps?
unless pour_bottle? if pour_bottle?(warn: true)
formula.fetch_patches begin
formula.resources.each(&:fetch) downloader.fetch
end rescue Exception => e # rubocop:disable Lint/RescueException
raise if Homebrew::EnvConfig.developer? ||
Homebrew::EnvConfig.no_bottle_source_fallback? ||
e.is_a?(Interrupt)
@pour_failed = true
onoe e.message
opoo "Bottle installation failed: building from source."
fetch_dependencies
end
end
return if pour_bottle?
formula.fetch_patches
formula.resources.each(&:fetch)
downloader.fetch downloader.fetch
end end

View File

@ -97,14 +97,16 @@ module OS
# If no specific SDK is requested, the SDK matching the OS version is returned, # If no specific SDK is requested, the SDK matching the OS version is returned,
# if available. Otherwise, the latest SDK is returned. # if available. Otherwise, the latest SDK is returned.
def sdk(v = nil) def sdk_locator
@locator ||= if CLT.installed? && CLT.provides_sdk? if CLT.installed? && CLT.provides_sdk?
CLTSDKLocator.new CLT.sdk_locator
else else
XcodeSDKLocator.new Xcode.sdk_locator
end end
end
@locator.sdk_if_applicable(v) def sdk(v = nil)
sdk_locator.sdk_if_applicable(v)
end end
def sdk_for_formula(f, v = nil) def sdk_for_formula(f, v = nil)

View File

@ -31,6 +31,10 @@ module OS
SDK.new v, path, source SDK.new v, path, source
end end
def all_sdks
sdk_paths.map { |v, p| SDK.new v, p, source }
end
def sdk_if_applicable(v = nil) def sdk_if_applicable(v = nil)
sdk = begin sdk = begin
if v.nil? if v.nil?
@ -47,15 +51,11 @@ module OS
sdk sdk
end end
private
def source def source
nil nil
end end
def source_version private
OS::Mac::Version::NULL
end
def sdk_prefix def sdk_prefix
"" ""
@ -81,15 +81,11 @@ module OS
end end
class XcodeSDKLocator < BaseSDKLocator class XcodeSDKLocator < BaseSDKLocator
private
def source def source
:xcode :xcode
end end
def source_version private
OS::Mac::Xcode.version
end
def sdk_prefix def sdk_prefix
@sdk_prefix ||= begin @sdk_prefix ||= begin
@ -105,15 +101,11 @@ module OS
end end
class CLTSDKLocator < BaseSDKLocator class CLTSDKLocator < BaseSDKLocator
private
def source def source
:clt :clt
end end
def source_version private
OS::Mac::CLT.version
end
# While CLT SDKs existed prior to Xcode 10, those packages also # While CLT SDKs existed prior to Xcode 10, those packages also
# installed a traditional Unix-style header layout and we prefer # installed a traditional Unix-style header layout and we prefer

View File

@ -107,10 +107,12 @@ module OS
!prefix.nil? !prefix.nil?
end end
def sdk(v = nil) def sdk_locator
@locator ||= XcodeSDKLocator.new @sdk_locator ||= XcodeSDKLocator.new
end
@locator.sdk_if_applicable(v) def sdk(v = nil)
sdk_locator.sdk_if_applicable(v)
end end
def sdk_path(v = nil) def sdk_path(v = nil)
@ -219,10 +221,12 @@ module OS
version >= "8" version >= "8"
end end
def sdk(v = nil) def sdk_locator
@locator ||= CLTSDKLocator.new @sdk_locator ||= CLTSDKLocator.new
end
@locator.sdk_if_applicable(v) def sdk(v = nil)
sdk_locator.sdk_if_applicable(v)
end end
def sdk_path(v = nil) def sdk_path(v = nil)

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "formula" require "formula"
require "cask/cask_loader"
module Readall module Readall
class << self class << self
@ -35,28 +36,43 @@ module Readall
end end
def valid_formulae?(formulae) def valid_formulae?(formulae)
failed = false success = true
formulae.each do |file| formulae.each do |file|
Formulary.factory(file) Formulary.factory(file)
rescue Interrupt rescue Interrupt
raise raise
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
onoe "Invalid formula: #{file}" onoe "Invalid formula: #{file}"
puts e $stderr.puts e
failed = true success = false
end end
!failed success
end
def valid_casks?(casks)
success = true
casks.each do |file|
Cask::CaskLoader.load(file)
rescue Interrupt
raise
rescue Exception => e # rubocop:disable Lint/RescueException
onoe "Invalid cask: #{file}"
$stderr.puts e
success = false
end
success
end end
def valid_tap?(tap, options = {}) def valid_tap?(tap, options = {})
failed = false success = true
if options[:aliases] if options[:aliases]
valid_aliases = valid_aliases?(tap.alias_dir, tap.formula_dir) valid_aliases = valid_aliases?(tap.alias_dir, tap.formula_dir)
failed = true unless valid_aliases success = false unless valid_aliases
end end
valid_formulae = valid_formulae?(tap.formula_files) valid_formulae = valid_formulae?(tap.formula_files)
failed = true unless valid_formulae valid_casks = valid_casks?(tap.cask_files)
!failed success = false if !valid_formulae || !valid_casks
success
end end
private private
@ -79,3 +95,5 @@ module Readall
end end
end end
end end
require "extend/os/readall"

View File

@ -24,7 +24,8 @@ module RuboCop
[{ name: :mirror, type: :method_call }], [{ name: :mirror, type: :method_call }],
[{ name: :version, type: :method_call }], [{ name: :version, type: :method_call }],
[{ name: :sha256, type: :method_call }], [{ name: :sha256, type: :method_call }],
[{ name: :revision, type: :method_call }], [{ name: :license, type: :method_call }],
[{ name: :revision, type: :method_call }],
[{ name: :version_scheme, type: :method_call }], [{ name: :version_scheme, type: :method_call }],
[{ name: :head, type: :method_call }], [{ name: :head, type: :method_call }],
[{ name: :stable, type: :block_call }], [{ name: :stable, type: :block_call }],

View File

@ -453,7 +453,6 @@ false:
- ./utils/github.rb - ./utils/github.rb
- ./utils/notability.rb - ./utils/notability.rb
- ./utils/popen.rb - ./utils/popen.rb
- ./utils/tty.rb
- ./utils/user.rb - ./utils/user.rb
false: false:
@ -889,6 +888,7 @@ true:
- ./tap_constants.rb - ./tap_constants.rb
- ./test/support/helper/fixtures.rb - ./test/support/helper/fixtures.rb
- ./test/support/lib/config.rb - ./test/support/lib/config.rb
- ./utils/tty.rb
- ./version/null.rb - ./version/null.rb
strict: strict:

View File

@ -0,0 +1,36 @@
# typed: strict
module Tty
include Kernel
sig{ params(string: String).returns(String) }
def strip_ansi(string)
end
sig{ returns(Integer) }
def width()
end
sig{ params(string: String).returns(T.nilable(String)) }
def truncate(string)
end
def append_to_escape_sequence(code)
end
sig{ returns(String) }
def current_escape_sequence()
end
sig{ void }
def reset_escape_sequence!()
end
sig{ returns(String) }
def to_s
end
sig { returns(T::Boolean) }
def color?
end
end

View File

@ -0,0 +1,9 @@
codecov:
fixes:
- "::Library/Homebrew/"
coverage:
round: nearest
status:
project:
default:
threshold: 0.05%

View File

@ -8,7 +8,7 @@ describe "Homebrew.search_args" do
end end
describe "brew search", :integration_test do describe "brew search", :integration_test do
it "falls back to a GitHub tap search when no formula is found", :needs_network do it "falls back to a GitHub tap search when no formula is found", :needs_macos, :needs_network do
setup_test_formula "testball" setup_test_formula "testball"
setup_remote_tap "homebrew/cask" setup_remote_tap "homebrew/cask"
@ -16,4 +16,13 @@ describe "brew search", :integration_test do
.to output(/firefox/).to_stdout .to output(/firefox/).to_stdout
.and be_a_success .and be_a_success
end end
# doesn't actually need Linux but only want one integration test per-OS.
it "finds formula in search", :need_linux do
setup_test_formula "testball"
expect { brew "search", "testball" }
.to output(/testball/).to_stdout
.and be_a_success
end
end end

View File

@ -79,6 +79,92 @@ module Homebrew
end end
end end
describe "#audit_license" do
let(:spdx_data) {
JSON.parse Pathname(File.join(File.dirname(__FILE__), "../../data/spdx.json")).read
}
let(:custom_spdx_id) { "zzz" }
let(:standard_mismatch_spdx_id) { "0BSD" }
it "does not check if the formula is not a new formula" do
fa = formula_auditor "foo", <<~RUBY, spdx_data: spdx_data, new_formula: false
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
license ""
end
RUBY
fa.audit_license
expect(fa.problems).to be_empty
end
it "detects no license info" do
fa = formula_auditor "foo", <<~RUBY, spdx_data: spdx_data, new_formula: true
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
license ""
end
RUBY
fa.audit_license
expect(fa.problems.first).to match "No license specified for package."
end
it "detects if license is not a standard spdx-id" do
fa = formula_auditor "foo", <<~RUBY, spdx_data: spdx_data, new_formula: true
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
license "#{custom_spdx_id}"
end
RUBY
fa.audit_license
expect(fa.problems.first).to match "#{custom_spdx_id} is not a standard SPDX license."
end
it "verifies that a license info is a standard spdx id" do
fa = formula_auditor "foo", <<~RUBY, spdx_data: spdx_data, new_formula: true
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
license "0BSD"
end
RUBY
fa.audit_license
expect(fa.problems).to be_empty
end
it "checks online and verifies that a standard license id is the same "\
"as what is indicated on its Github repo" do
fa = formula_auditor "cask", <<~RUBY, spdx_data: spdx_data, online: true, core_tap: true, new_formula: true
class Cask < Formula
url "https://github.com/cask/cask/archive/v0.8.4.tar.gz"
head "https://github.com/cask/cask.git"
license "GPL-3.0"
end
RUBY
fa.audit_license
expect(fa.problems).to be_empty
end
it "checks online and detects that a formula-specified license is not "\
"the same as what is indicated on its Github repository" do
fa = formula_auditor "cask", <<~RUBY, online: true, spdx_data: spdx_data, core_tap: true, new_formula: true
class Cask < Formula
url "https://github.com/cask/cask/archive/v0.8.4.tar.gz"
head "https://github.com/cask/cask.git"
license "#{standard_mismatch_spdx_id}"
end
RUBY
fa.audit_license
expect(fa.problems.first).to match "License mismatch - GitHub license is: GPL-3.0, "\
"but Formulae license states: #{standard_mismatch_spdx_id}."
end
end
describe "#audit_file" do describe "#audit_file" do
specify "no issue" do specify "no issue" do
fa = formula_auditor "foo", <<~RUBY fa = formula_auditor "foo", <<~RUBY

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
require "cmd/shared_examples/args_parse"
describe "Homebrew.update_license_data_args" do
it_behaves_like "parseable arguments"
end

View File

@ -19,6 +19,18 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do
RUBY RUBY
end end
it "When license precedes sha256" do
expect_offense(<<~RUBY)
class Foo < Formula
homepage "https://brew.sh"
url "https://brew.sh/foo-1.0.tgz"
license "0BSD"
sha256 "samplesha256"
^^^^^^^^^^^^^^^^^^^^^ `sha256` (line 5) should be put before `license` (line 4)
end
RUBY
end
it "When `bottle` precedes `livecheck`" do it "When `bottle` precedes `livecheck`" do
expect_offense(<<~RUBY) expect_offense(<<~RUBY)
class Foo < Formula class Foo < Formula

View File

@ -4,12 +4,10 @@ if ENV["HOMEBREW_TESTS_COVERAGE"]
require "simplecov" require "simplecov"
formatters = [SimpleCov::Formatter::HTMLFormatter] formatters = [SimpleCov::Formatter::HTMLFormatter]
if ENV["HOMEBREW_COVERALLS_REPO_TOKEN"] && RUBY_PLATFORM[/darwin/] if ENV["HOMEBREW_CODECOV_TOKEN"] && RUBY_PLATFORM[/darwin/]
require "coveralls" require "codecov"
Coveralls::Output.no_color if !ENV["HOMEBREW_COLOR"] && (ENV["HOMEBREW_NO_COLOR"] || !$stdout.tty?) formatters << SimpleCov::Formatter::Codecov
formatters << Coveralls::SimpleCov::Formatter
if ENV["TEST_ENV_NUMBER"] if ENV["TEST_ENV_NUMBER"]
SimpleCov.at_exit do SimpleCov.at_exit do
@ -18,16 +16,7 @@ if ENV["HOMEBREW_TESTS_COVERAGE"]
end end
end end
ENV["CI_NAME"] = ENV["HOMEBREW_CI_NAME"] ENV["CODECOV_TOKEN"] = ENV["HOMEBREW_CODECOV_TOKEN"]
ENV["COVERALLS_REPO_TOKEN"] = ENV["HOMEBREW_COVERALLS_REPO_TOKEN"]
ENV["CI_BUILD_NUMBER"] = ENV["HOMEBREW_CI_BUILD_NUMBER"]
ENV["CI_BRANCH"] = ENV["HOMEBREW_CI_BRANCH"]
%r{refs/pull/(?<pr>\d+)/merge} =~ ENV["HOMEBREW_CI_BUILD_NUMBER"]
ENV["CI_PULL_REQUEST"] = pr
ENV["CI_BUILD_URL"] = "https://github.com/#{ENV["HOMEBREW_GITHUB_REPOSITORY"]}/pull/#{pr}/checks"
ENV["CI_JOB_ID"] = ENV["TEST_ENV_NUMBER"] || "1"
end end
SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new(formatters) SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new(formatters)
@ -174,6 +163,7 @@ RSpec.configure do |config|
Keg.clear_cache Keg.clear_cache
Tab.clear_cache Tab.clear_cache
FormulaInstaller.clear_attempted FormulaInstaller.clear_attempted
FormulaInstaller.clear_installed
TEST_DIRECTORIES.each(&:mkpath) TEST_DIRECTORIES.each(&:mkpath)

View File

@ -46,7 +46,7 @@ RSpec.shared_context "integration test" do
example.run example.run
ensure ensure
FileUtils.rm_r HOMEBREW_PREFIX/"bin" FileUtils.rm_rf HOMEBREW_PREFIX/"bin"
end end
# Generate unique ID to be able to # Generate unique ID to be able to

View File

@ -42,6 +42,13 @@ describe GitHub do
end end
end end
describe "::approved_reviews", :needs_network do
it "can get reviews for a pull request" do
reviews = subject.approved_reviews("Homebrew", "homebrew-core", 1, commit: "deadbeef")
expect(reviews).to eq([])
end
end
describe "::get_artifact_url", :needs_network do describe "::get_artifact_url", :needs_network do
it "fails to find a nonexistant workflow" do it "fails to find a nonexistant workflow" do
expect { expect {

242
Library/Homebrew/upgrade.rb Normal file
View File

@ -0,0 +1,242 @@
# frozen_string_literal: true
require "reinstall"
require "formula_installer"
require "development_tools"
require "messages"
require "cleanup"
module Homebrew
module_function
def upgrade_formulae(formulae_to_install)
return if formulae_to_install.empty?
return if args.dry_run?
# Sort keg-only before non-keg-only formulae to avoid any needless conflicts
# with outdated, non-keg-only versions of formulae being upgraded.
formulae_to_install.sort! do |a, b|
if !a.keg_only? && b.keg_only?
1
elsif a.keg_only? && !b.keg_only?
-1
else
0
end
end
formulae_to_install.each do |f|
Migrator.migrate_if_needed(f)
begin
upgrade_formula(f)
Cleanup.install_formula_clean!(f)
rescue UnsatisfiedRequirements => e
Homebrew.failed = true
onoe "#{f}: #{e}"
end
end
end
def upgrade_formula(f)
return if args.dry_run?
if f.opt_prefix.directory?
keg = Keg.new(f.opt_prefix.resolved_path)
keg_had_linked_opt = true
keg_was_linked = keg.linked?
end
formulae_maybe_with_kegs = [f] + f.old_installed_formulae
outdated_kegs = formulae_maybe_with_kegs
.map(&:linked_keg)
.select(&:directory?)
.map { |k| Keg.new(k.resolved_path) }
linked_kegs = outdated_kegs.select(&:linked?)
if f.opt_prefix.directory?
keg = Keg.new(f.opt_prefix.resolved_path)
tab = Tab.for_keg(keg)
end
build_options = BuildOptions.new(Options.create(args.flags_only), f.options)
options = build_options.used_options
options |= f.build.used_options
options &= f.options
fi = FormulaInstaller.new(f)
fi.options = options
fi.build_bottle = args.build_bottle?
fi.installed_on_request = args.named.present?
fi.link_keg ||= keg_was_linked if keg_had_linked_opt
if tab
fi.build_bottle ||= tab.built_bottle?
fi.installed_as_dependency = tab.installed_as_dependency
fi.installed_on_request ||= tab.installed_on_request
end
upgrade_version = if f.optlinked?
"#{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
else
"-> #{f.pkg_version}"
end
oh1 "Upgrading #{Formatter.identifier(f.full_specified_name)} #{upgrade_version} #{fi.options.to_a.join(" ")}"
fi.prelude
fi.fetch
# first we unlink the currently active keg for this formula otherwise it is
# possible for the existing build to interfere with the build we are about to
# do! Seriously, it happens!
outdated_kegs.each(&:unlink)
fi.install
fi.finish
rescue FormulaInstallationAlreadyAttemptedError
# We already attempted to upgrade f as part of the dependency tree of
# another formula. In that case, don't generate an error, just move on.
nil
rescue CannotInstallFormulaError => e
ofail e
rescue BuildError => e
e.dump
puts
Homebrew.failed = true
rescue DownloadError => e
ofail e
ensure
# restore previous installation state if build failed
begin
linked_kegs.each(&:link) unless f.latest_version_installed?
rescue
nil
end
end
def check_installed_dependents
installed_formulae = FormulaInstaller.installed.to_a
return if installed_formulae.empty?
outdated_dependents =
installed_formulae.flat_map(&:runtime_installed_formula_dependents)
.select(&:outdated?)
return if outdated_dependents.blank?
outdated_dependents -= installed_formulae if args.dry_run?
upgradeable_dependents =
outdated_dependents.reject(&:pinned?)
.sort { |a, b| depends_on(a, b) }
pinned_dependents =
outdated_dependents.select(&:pinned?)
.sort { |a, b| depends_on(a, b) }
if pinned_dependents.present?
plural = "dependent".pluralize(pinned_dependents.count)
ohai "Not upgrading #{pinned_dependents.count} pinned #{plural}:"
puts(pinned_dependents.map do |f|
"#{f.full_specified_name} #{f.pkg_version}"
end.join(", "))
end
# Print the upgradable dependents.
if upgradeable_dependents.blank?
ohai "No outdated dependents to upgrade!" unless args.dry_run?
else
plural = "dependent".pluralize(upgradeable_dependents.count)
verb = args.dry_run? ? "Would upgrade" : "Upgrading"
ohai "#{verb} #{upgradeable_dependents.count} #{plural}:"
formulae_upgrades = upgradeable_dependents.map do |f|
name = f.full_specified_name
if f.optlinked?
"#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
else
"#{name} #{f.pkg_version}"
end
end
puts formulae_upgrades.join(", ")
end
upgrade_formulae(upgradeable_dependents)
# Assess the dependents tree again now we've upgraded.
oh1 "Checking for dependents of upgraded formulae..." unless args.dry_run?
broken_dependents = CacheStoreDatabase.use(:linkage) do |db|
formulae_to_install.flat_map(&:runtime_installed_formula_dependents)
.select do |f|
keg = f.opt_or_installed_prefix_keg
next unless keg
LinkageChecker.new(keg, cache_db: db)
.broken_library_linkage?
end.compact
end
if broken_dependents.blank?
if args.dry_run?
ohai "No currently broken dependents found!"
opoo "If they are broken by the upgrade they will also be upgraded or reinstalled."
else
ohai "No broken dependents found!"
end
return
end
reinstallable_broken_dependents =
broken_dependents.reject(&:outdated?)
.reject(&:pinned?)
.sort { |a, b| depends_on(a, b) }
outdated_pinned_broken_dependents =
broken_dependents.select(&:outdated?)
.select(&:pinned?)
.sort { |a, b| depends_on(a, b) }
# Print the pinned dependents.
if outdated_pinned_broken_dependents.present?
count = outdated_pinned_broken_dependents.count
plural = "dependent".pluralize(outdated_pinned_broken_dependents.count)
onoe "Not reinstalling #{count} broken and outdated, but pinned #{plural}:"
$stderr.puts(outdated_pinned_broken_dependents.map do |f|
"#{f.full_specified_name} #{f.pkg_version}"
end.join(", "))
end
# Print the broken dependents.
if reinstallable_broken_dependents.blank?
ohai "No broken dependents to reinstall!"
else
count = reinstallable_broken_dependents.count
plural = "dependent".pluralize(reinstallable_broken_dependents.count)
ohai "Reinstalling #{count} broken #{plural} from source:"
puts reinstallable_broken_dependents.map(&:full_specified_name)
.join(", ")
end
return if args.dry_run?
reinstallable_broken_dependents.each do |f|
reinstall_formula(f, build_from_source: true)
rescue FormulaInstallationAlreadyAttemptedError
# We already attempted to reinstall f as part of the dependency tree of
# another formula. In that case, don't generate an error, just move on.
nil
rescue CannotInstallFormulaError => e
ofail e
rescue BuildError => e
e.dump
puts
Homebrew.failed = true
rescue DownloadError => e
ofail e
end
end
# @private
def depends_on(a, b)
if a.opt_or_installed_prefix_keg
&.runtime_dependencies
&.any? { |d| d["full_name"] == b.full_name }
1
else
a <=> b
end
end
end

View File

@ -54,21 +54,25 @@ def curl(*args, secrets: [], **options)
secrets: secrets secrets: secrets
end end
def curl_download(*args, to: nil, **options) def curl_download(*args, to: nil, partial: true, **options)
destination = Pathname(to) destination = Pathname(to)
destination.dirname.mkpath destination.dirname.mkpath
range_stdout = curl_output("--location", "--range", "0-1", if partial
"--dump-header", "-", range_stdout = curl_output("--location", "--range", "0-1",
"--write-out", "%\{http_code}", "--dump-header", "-",
"--output", "/dev/null", *args, **options).stdout "--write-out", "%\{http_code}",
headers, _, http_status = range_stdout.partition("\r\n\r\n") "--output", "/dev/null", *args, **options).stdout
headers, _, http_status = range_stdout.partition("\r\n\r\n")
supports_partial_download = http_status.to_i == 206 # Partial Content supports_partial_download = http_status.to_i == 206 # Partial Content
if supports_partial_download && if supports_partial_download &&
destination.exist? && destination.exist? &&
destination.size == %r{^.*Content-Range: bytes \d+-\d+/(\d+)\r\n.*$}m.match(headers)&.[](1)&.to_i destination.size == %r{^.*Content-Range: bytes \d+-\d+/(\d+)\r\n.*$}m.match(headers)&.[](1)&.to_i
return # We've already downloaded all the bytes return # We've already downloaded all the bytes
end
else
supports_partial_download = false
end end
continue_at = if destination.exist? && supports_partial_download continue_at = if destination.exist? && supports_partial_download

View File

@ -392,6 +392,52 @@ module GitHub
open_api(uri) { |json| json.fetch("items", []) } open_api(uri) { |json| json.fetch("items", []) }
end end
def approved_reviews(user, repo, pr, commit: nil)
url = "https://api.github.com/graphql"
data = {
query: <<~EOS,
{ repository(name: "#{repo}", owner: "#{user}") {
pullRequest(number: #{pr}) {
reviews(states: APPROVED, first: 100) {
nodes {
author {
... on User { email login name databaseId }
... on Organization { email login name databaseId }
}
authorAssociation
commit { oid }
}
}
}
}
}
EOS
}
result = open_api(url, scopes: ["user:email"], data: data, request_method: "POST")
raise Error, result["errors"] if result["errors"].present?
reviews = result["data"]["repository"]["pullRequest"]["reviews"]["nodes"]
reviews.map do |r|
next if commit.present? && commit != r["commit"]["oid"]
next unless %w[MEMBER OWNER].include? r["authorAssociation"]
email = if r["author"]["email"].blank?
"#{r["author"]["databaseId"]}+#{r["author"]["login"]}@users.noreply.github.com"
else
r["author"]["email"]
end
name = r["author"]["name"].presence || r["author"]["login"]
{
"email" => email,
"name" => name,
"login" => r["author"]["login"],
}
end.compact
end
def dispatch_event(user, repo, event, **payload) def dispatch_event(user, repo, event, **payload)
url = "#{API_URL}/repos/#{user}/#{repo}/dispatches" url = "#{API_URL}/repos/#{user}/#{repo}/dispatches"
open_api(url, data: { event_type: event, client_payload: payload }, open_api(url, data: { event_type: event, client_payload: payload },
@ -474,6 +520,15 @@ module GitHub
open_api(url, scopes: ["admin:org", "user"], data: data, request_method: "POST") open_api(url, scopes: ["admin:org", "user"], data: data, request_method: "POST")
end end
def get_repo_license(user, repo)
response = GitHub.open_api("#{GitHub::API_URL}/repos/#{user}/#{repo}/license")
return unless response.key?("license")
response["license"]["spdx_id"]
rescue GitHub::HTTPNotFoundError
nil
end
def api_errors def api_errors
[GitHub::AuthenticationFailedError, GitHub::HTTPNotFoundError, [GitHub::AuthenticationFailedError, GitHub::HTTPNotFoundError,
GitHub::RateLimitExceededError, GitHub::Error, JSON::ParserError].freeze GitHub::RateLimitExceededError, GitHub::Error, JSON::ParserError].freeze

View File

@ -86,6 +86,7 @@ unpin
untap untap
up up
update update
update-license-data
update-report update-report
update-reset update-reset
update-test update-test

View File

@ -6,6 +6,13 @@ This is a page for maintainers to diagnose certain build errors.
## Issues ## Issues
### Bottle publishes failed but the commits are correct in the git history
Follow these steps to fix this issue:
* `git reset --hard <SHA>` in homebrew/core to reset to the commit before before all the commits created by `brew pr-pull`.
* `brew pr-pull <options>` to upload the right bottles. Add the `--warn-on-upload-failure` flag if the bottles have been partially uploaded and you're certain that the bottle checksums will match the checksums already present in the `bottle do` block of the formula.
* `git reset --hard origin/master` to return to the latest commit and discard the commits made by `brew pr-pull`.
### `ld: internal error: atom not found in symbolIndex(__ZN10SQInstance3GetERK11SQObjectPtrRS0_) for architecture x86_64` ### `ld: internal error: atom not found in symbolIndex(__ZN10SQInstance3GetERK11SQObjectPtrRS0_) for architecture x86_64`
The exact atom may be different. The exact atom may be different.

View File

@ -369,10 +369,10 @@ Rerun the post-install steps for *`formula`*.
### `readall` [*`options`*] [*`tap`*] ### `readall` [*`options`*] [*`tap`*]
Import all formulae from the specified *`tap`*, or from all installed taps if none Import all items from the specified *`tap`*, or from all installed taps if none is
is provided. This can be useful for debugging issues across all formulae when provided. This can be useful for debugging issues across all items when making
making significant changes to `formula.rb`, testing the performance of loading significant changes to `formula.rb`, testing the performance of loading all
all formulae or checking if any current formulae have Ruby issues. items or checking if any current formulae/casks have Ruby issues.
* `--aliases`: * `--aliases`:
Verify any alias symlinks in each tap. Verify any alias symlinks in each tap.
@ -793,6 +793,8 @@ a simple example. For the complete API, see:
Explicitly set the *`name`* of the new formula. Explicitly set the *`name`* of the new formula.
* `--set-version`: * `--set-version`:
Explicitly set the *`version`* of the new formula. Explicitly set the *`version`* of the new formula.
* `--set-license`:
Explicitly set the *`license`* of the new formula.
* `--tap`: * `--tap`:
Generate the new formula within the given tap, specified as *`user`*`/`*`repo`*. Generate the new formula within the given tap, specified as *`user`*`/`*`repo`*.
@ -901,6 +903,8 @@ repository.
Do not warn if pulling to a branch besides master (useful for testing). Do not warn if pulling to a branch besides master (useful for testing).
* `--resolve`: * `--resolve`:
When a patch fails to apply, leave in progress and allow user to resolve, instead of aborting. When a patch fails to apply, leave in progress and allow user to resolve, instead of aborting.
* `--warn-on-upload-failure`:
Warn instead of raising an error if the bottle upload fails. Useful for repairing bottle uploads that previously failed.
* `--workflow`: * `--workflow`:
Retrieve artifacts from the specified workflow (default: `tests.yml`). Retrieve artifacts from the specified workflow (default: `tests.yml`).
* `--artifact`: * `--artifact`:
@ -922,6 +926,8 @@ Apply the bottle commit and publish bottles to Bintray.
Apply the bottle commit and upload the bottles, but don't publish them. Apply the bottle commit and upload the bottles, but don't publish them.
* `-n`, `--dry-run`: * `-n`, `--dry-run`:
Print what would be done rather than doing it. Print what would be done rather than doing it.
* `--warn-on-upload-failure`:
Warn instead of raising an error if the bottle upload fails. Useful for repairing bottle uploads that previously failed.
* `--bintray-org`: * `--bintray-org`:
Upload to the specified Bintray organisation (default: `homebrew`). Upload to the specified Bintray organisation (default: `homebrew`).
* `--root-url`: * `--root-url`:
@ -1028,6 +1034,13 @@ directory.
* `-g`, `--git`: * `-g`, `--git`:
Initialise a Git repository in the unpacked source. This is useful for creating patches for the software. Initialise a Git repository in the unpacked source. This is useful for creating patches for the software.
### `update_license_data` *`cmd`*
Update SPDX license data in the Homebrew repository.
* `--fail-if-changed`:
Return a failing status code if current license data's version is different from the upstream. This can be used to notify CI when the SPDX license data is out of date.
### `update-test` [*`options`*] ### `update-test` [*`options`*]
Run a test of `brew update` with a new repository clone. If no options are Run a test of `brew update` with a new repository clone. If no options are

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BREW\-CASK" "1" "June 2020" "Homebrew" "brew-cask" .TH "BREW\-CASK" "1" "July 2020" "Homebrew" "brew-cask"
. .
.SH "NAME" .SH "NAME"
\fBbrew\-cask\fR \- a friendly binary installer for macOS \fBbrew\-cask\fR \- a friendly binary installer for macOS

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BREW" "1" "June 2020" "Homebrew" "brew" .TH "BREW" "1" "July 2020" "Homebrew" "brew"
. .
.SH "NAME" .SH "NAME"
\fBbrew\fR \- The Missing Package Manager for macOS \fBbrew\fR \- The Missing Package Manager for macOS
@ -486,7 +486,7 @@ Pin the specified \fIformula\fR, preventing them from being upgraded when issuin
Rerun the post\-install steps for \fIformula\fR\. Rerun the post\-install steps for \fIformula\fR\.
. .
.SS "\fBreadall\fR [\fIoptions\fR] [\fItap\fR]" .SS "\fBreadall\fR [\fIoptions\fR] [\fItap\fR]"
Import all formulae from the specified \fItap\fR, or from all installed taps if none is provided\. This can be useful for debugging issues across all formulae when making significant changes to \fBformula\.rb\fR, testing the performance of loading all formulae or checking if any current formulae have Ruby issues\. Import all items from the specified \fItap\fR, or from all installed taps if none is provided\. This can be useful for debugging issues across all items when making significant changes to \fBformula\.rb\fR, testing the performance of loading all items or checking if any current formulae/casks have Ruby issues\.
. .
.TP .TP
\fB\-\-aliases\fR \fB\-\-aliases\fR
@ -1047,6 +1047,10 @@ Explicitly set the \fIname\fR of the new formula\.
Explicitly set the \fIversion\fR of the new formula\. Explicitly set the \fIversion\fR of the new formula\.
. .
.TP .TP
\fB\-\-set\-license\fR
Explicitly set the \fIlicense\fR of the new formula\.
.
.TP
\fB\-\-tap\fR \fB\-\-tap\fR
Generate the new formula within the given tap, specified as \fIuser\fR\fB/\fR\fIrepo\fR\. Generate the new formula within the given tap, specified as \fIuser\fR\fB/\fR\fIrepo\fR\.
. .
@ -1172,6 +1176,10 @@ Do not warn if pulling to a branch besides master (useful for testing)\.
When a patch fails to apply, leave in progress and allow user to resolve, instead of aborting\. When a patch fails to apply, leave in progress and allow user to resolve, instead of aborting\.
. .
.TP .TP
\fB\-\-warn\-on\-upload\-failure\fR
Warn instead of raising an error if the bottle upload fails\. Useful for repairing bottle uploads that previously failed\.
.
.TP
\fB\-\-workflow\fR \fB\-\-workflow\fR
Retrieve artifacts from the specified workflow (default: \fBtests\.yml\fR)\. Retrieve artifacts from the specified workflow (default: \fBtests\.yml\fR)\.
. .
@ -1207,6 +1215,10 @@ Apply the bottle commit and upload the bottles, but don\'t publish them\.
Print what would be done rather than doing it\. Print what would be done rather than doing it\.
. .
.TP .TP
\fB\-\-warn\-on\-upload\-failure\fR
Warn instead of raising an error if the bottle upload fails\. Useful for repairing bottle uploads that previously failed\.
.
.TP
\fB\-\-bintray\-org\fR \fB\-\-bintray\-org\fR
Upload to the specified Bintray organisation (default: \fBhomebrew\fR)\. Upload to the specified Bintray organisation (default: \fBhomebrew\fR)\.
. .
@ -1331,6 +1343,13 @@ Patches for \fIformula\fR will be applied to the unpacked source\.
\fB\-g\fR, \fB\-\-git\fR \fB\-g\fR, \fB\-\-git\fR
Initialise a Git repository in the unpacked source\. This is useful for creating patches for the software\. Initialise a Git repository in the unpacked source\. This is useful for creating patches for the software\.
. .
.SS "\fBupdate_license_data\fR \fIcmd\fR"
Update SPDX license data in the Homebrew repository\.
.
.TP
\fB\-\-fail\-if\-changed\fR
Return a failing status code if current license data\'s version is different from the upstream\. This can be used to notify CI when the SPDX license data is out of date\.
.
.SS "\fBupdate\-test\fR [\fIoptions\fR]" .SS "\fBupdate\-test\fR [\fIoptions\fR]"
Run a test of \fBbrew update\fR with a new repository clone\. If no options are passed, use \fBorigin/master\fR as the start commit\. Run a test of \fBbrew update\fR with a new repository clone\. If no options are passed, use \fBorigin/master\fR as the start commit\.
. .