Merge branch 'master' into dependabot/bundler/Library/Homebrew/sorbet-0.5.6519

This commit is contained in:
Mike McQuaid 2021-08-11 09:30:51 +01:00 committed by GitHub
commit 3b13cf9797
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 6881 additions and 5831 deletions

View File

@ -70,7 +70,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Lock Outdated Threads
uses: dessant/lock-threads@486f7380c15596f92b724e4260e4981c68d6bde6
uses: dessant/lock-threads@1621939cecf8586399a6b60d2a7af9469232b5b6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
issue-lock-inactive-days: 30

4
.gitignore vendored
View File

@ -194,5 +194,7 @@
# Unignore tests' bundle config
!/Library/Homebrew/test/.bundle/config
# Unignore vscode configuration
# Unignore editor configuration
!/.sublime
/.sublime/homebrew.sublime-workspace
!/.vscode

View File

@ -0,0 +1,28 @@
{
"folders":
[
{
"//": "Generated based on the contents of our .gitignore",
"path": "..",
"folder_exclude_patterns": [
"Caskroom",
"Cellar",
"Frameworks",
"bin",
"etc",
"include",
"lib",
"opt",
"sbin",
"share",
"var",
"Library/Homebrew/LinkedKegs",
"Library/Homebrew/Aliases"
],
"follow_symlinks": true
}
],
"settings": {
"tab_size": 2
}
}

View File

@ -29,9 +29,11 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/* \
&& localedef -i en_US -f UTF-8 en_US.UTF-8 \
&& useradd -m -s /bin/bash linuxbrew \
&& echo 'linuxbrew ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers
&& echo 'linuxbrew ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers \
&& su - linuxbrew -c 'mkdir ~/.linuxbrew'
COPY . /home/linuxbrew/.linuxbrew/Homebrew
USER linuxbrew
COPY --chown=linuxbrew:linuxbrew . /home/linuxbrew/.linuxbrew/Homebrew
ENV PATH=/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:$PATH
WORKDIR /home/linuxbrew

View File

@ -11,7 +11,7 @@ GEM
public_suffix (>= 2.0.2, < 5.0)
ast (2.4.2)
bindata (2.4.10)
bootsnap (1.7.5)
bootsnap (1.7.7)
msgpack (~> 1.0)
byebug (11.1.3)
coderay (1.1.3)
@ -121,7 +121,7 @@ GEM
rubocop-ast (>= 1.8.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.8.0)
rubocop-ast (1.9.0)
parser (>= 3.0.1.1)
rubocop-performance (1.11.4)
rubocop (>= 1.7.0, < 2.0)

37
Library/Homebrew/api.rb Normal file
View File

@ -0,0 +1,37 @@
# typed: false
# frozen_string_literal: true
require "api/analytics"
require "api/bottle"
require "api/cask"
require "api/formula"
require "api/versions"
require "extend/cachable"
module Homebrew
# Helper functions for using Homebrew's formulae.brew.sh API.
#
# @api private
module API
extend T::Sig
extend Cachable
module_function
API_DOMAIN = "https://formulae.brew.sh/api"
sig { params(endpoint: String).returns(T.any(String, Hash)) }
def fetch(endpoint)
return cache[endpoint] if cache.present? && cache.key?(endpoint)
api_url = "#{API_DOMAIN}/#{endpoint}"
output = Utils::Curl.curl_output("--fail", "--max-time", "5", api_url)
raise ArgumentError, "No file found at #{Tty.underline}#{api_url}#{Tty.reset}" unless output.success?
cache[endpoint] = JSON.parse(output.stdout)
rescue JSON::ParserError
raise ArgumentError, "Invalid JSON file: #{Tty.underline}#{api_url}#{Tty.reset}"
end
end
end

View File

@ -0,0 +1,28 @@
# typed: false
# frozen_string_literal: true
module Homebrew
module API
# Helper functions for using the analytics JSON API.
#
# @api private
module Analytics
class << self
extend T::Sig
sig { returns(String) }
def analytics_api_path
"analytics"
end
alias generic_analytics_api_path analytics_api_path
sig { params(category: String, days: T.any(Integer, String)).returns(Hash) }
def fetch(category, days)
Homebrew::API.fetch "#{analytics_api_path}/#{category}/#{days}d.json"
end
end
end
end
end
require "extend/os/api/analytics"

View File

@ -0,0 +1,95 @@
# typed: false
# frozen_string_literal: true
require "github_packages"
module Homebrew
module API
# Helper functions for using the bottle JSON API.
#
# @api private
module Bottle
class << self
extend T::Sig
sig { returns(String) }
def bottle_api_path
"bottle"
end
alias generic_bottle_api_path bottle_api_path
GITHUB_PACKAGES_SHA256_REGEX = %r{#{GitHubPackages::URL_REGEX}.*/blobs/sha256:(?<sha256>\h{64})$}.freeze
sig { params(name: String).returns(Hash) }
def fetch(name)
Homebrew::API.fetch "#{bottle_api_path}/#{name}.json"
end
sig { params(name: String).returns(T::Boolean) }
def available?(name)
fetch name
true
rescue ArgumentError
false
end
sig { params(name: String).void }
def fetch_bottles(name)
hash = fetch(name)
bottle_tag = Utils::Bottles.tag.to_s
if !hash["bottles"].key?(bottle_tag) && !hash["bottles"].key?("all")
odie "No bottle available for #{name} on the current OS"
end
download_bottle(hash, bottle_tag)
hash["dependencies"].each do |dep_hash|
existing_formula = begin
Formulary.factory dep_hash["name"]
rescue FormulaUnavailableError
# The formula might not exist if it's not installed and homebrew/core isn't tapped
nil
end
next if existing_formula.present? && existing_formula.latest_version_installed?
download_bottle(dep_hash, bottle_tag)
end
end
sig { params(url: String).returns(T.nilable(String)) }
def checksum_from_url(url)
match = url.match GITHUB_PACKAGES_SHA256_REGEX
return if match.blank?
match[:sha256]
end
sig { params(hash: Hash, tag: String).void }
def download_bottle(hash, tag)
bottle = hash["bottles"][tag]
bottle ||= hash["bottles"]["all"]
return if bottle.blank?
sha256 = bottle["sha256"] || checksum_from_url(bottle["url"])
bottle_filename = ::Bottle::Filename.new(hash["name"], hash["pkg_version"], tag, hash["rebuild"])
resource = Resource.new hash["name"]
resource.url bottle["url"]
resource.sha256 sha256
resource.version hash["pkg_version"]
resource.downloader.resolved_basename = bottle_filename
resource.fetch
# Map the name of this formula to the local bottle path to allow the
# formula to be loaded by passing just the name to `Formulary::factory`.
Formulary.map_formula_name_to_local_bottle_path hash["name"], resource.downloader.cached_location
end
end
end
end
end
require "extend/os/api/bottle"

View File

@ -0,0 +1,20 @@
# typed: false
# frozen_string_literal: true
module Homebrew
module API
# Helper functions for using the cask JSON API.
#
# @api private
module Cask
class << self
extend T::Sig
sig { params(name: String).returns(Hash) }
def fetch(name)
Homebrew::API.fetch "cask/#{name}.json"
end
end
end
end
end

View File

@ -0,0 +1,28 @@
# typed: false
# frozen_string_literal: true
module Homebrew
module API
# Helper functions for using the formula JSON API.
#
# @api private
module Formula
class << self
extend T::Sig
sig { returns(String) }
def formula_api_path
"formula"
end
alias generic_formula_api_path formula_api_path
sig { params(name: String).returns(Hash) }
def fetch(name)
Homebrew::API.fetch "#{formula_api_path}/#{name}.json"
end
end
end
end
end
require "extend/os/api/formula"

View File

@ -0,0 +1,52 @@
# typed: false
# frozen_string_literal: true
module Homebrew
module API
# Helper functions for using the versions JSON API.
#
# @api private
module Versions
class << self
extend T::Sig
def formulae
# The result is cached by Homebrew::API.fetch
Homebrew::API.fetch "versions-formulae.json"
end
def linux
# The result is cached by Homebrew::API.fetch
Homebrew::API.fetch "versions-linux.json"
end
def casks
# The result is cached by Homebrew::API.fetch
Homebrew::API.fetch "versions-casks.json"
end
sig { params(name: String).returns(T.nilable(PkgVersion)) }
def latest_formula_version(name)
versions = if OS.mac? || Homebrew::EnvConfig.force_homebrew_on_linux?
formulae
else
linux
end
return unless versions.key? name
version = Version.new(versions[name]["version"])
revision = versions[name]["revision"]
PkgVersion.new(version, revision)
end
sig { params(token: String).returns(T.nilable(Version)) }
def latest_cask_version(token)
return unless casks.key? token
Version.new(casks[token]["version"])
end
end
end
end
end

View File

@ -1,118 +0,0 @@
# typed: true
# frozen_string_literal: true
require "github_packages"
# Helper functions for using the Bottle JSON API.
#
# @api private
module BottleAPI
extend T::Sig
module_function
FORMULAE_BREW_SH_BOTTLE_API_DOMAIN = if OS.mac?
"https://formulae.brew.sh/api/bottle"
else
"https://formulae.brew.sh/api/bottle-linux"
end.freeze
FORMULAE_BREW_SH_VERSIONS_API_URL = if OS.mac?
"https://formulae.brew.sh/api/versions-formulae.json"
else
"https://formulae.brew.sh/api/versions-linux.json"
end.freeze
GITHUB_PACKAGES_SHA256_REGEX = %r{#{GitHubPackages::URL_REGEX}.*/blobs/sha256:(?<sha256>\h{64})$}.freeze
sig { params(name: String).returns(Hash) }
def fetch(name)
return @cache[name] if @cache.present? && @cache.key?(name)
api_url = "#{FORMULAE_BREW_SH_BOTTLE_API_DOMAIN}/#{name}.json"
output = Utils::Curl.curl_output("--fail", api_url)
raise ArgumentError, "No JSON file found at #{Tty.underline}#{api_url}#{Tty.reset}" unless output.success?
@cache ||= {}
@cache[name] = JSON.parse(output.stdout)
rescue JSON::ParserError
raise ArgumentError, "Invalid JSON file: #{Tty.underline}#{api_url}#{Tty.reset}"
end
sig { params(name: String).returns(T.nilable(PkgVersion)) }
def latest_pkg_version(name)
@formula_versions ||= begin
output = Utils::Curl.curl_output("--fail", FORMULAE_BREW_SH_VERSIONS_API_URL)
JSON.parse(output.stdout)
end
return unless @formula_versions.key? name
version = Version.new(@formula_versions[name]["version"])
revision = @formula_versions[name]["revision"]
PkgVersion.new(version, revision)
end
sig { params(name: String).returns(T::Boolean) }
def bottle_available?(name)
fetch name
true
rescue ArgumentError
false
end
sig { params(name: String).void }
def fetch_bottles(name)
hash = fetch(name)
bottle_tag = Utils::Bottles.tag.to_s
if !hash["bottles"].key?(bottle_tag) && !hash["bottles"].key?("all")
odie "No bottle available for #{name} on the current OS"
end
download_bottle(hash, bottle_tag)
hash["dependencies"].each do |dep_hash|
existing_formula = begin
Formulary.factory dep_hash["name"]
rescue FormulaUnavailableError
# The formula might not exist if it's not installed and homebrew/core isn't tapped
nil
end
next if existing_formula.present? && existing_formula.latest_version_installed?
download_bottle(dep_hash, bottle_tag)
end
end
sig { params(url: String).returns(T.nilable(String)) }
def checksum_from_url(url)
match = url.match GITHUB_PACKAGES_SHA256_REGEX
return if match.blank?
match[:sha256]
end
sig { params(hash: Hash, tag: Symbol).void }
def download_bottle(hash, tag)
bottle = hash["bottles"][tag]
bottle ||= hash["bottles"]["all"]
return if bottle.blank?
sha256 = bottle["sha256"] || checksum_from_url(bottle["url"])
bottle_filename = Bottle::Filename.new(hash["name"], hash["pkg_version"], tag, hash["rebuild"])
resource = Resource.new hash["name"]
resource.url bottle["url"]
resource.sha256 sha256
resource.version hash["pkg_version"]
resource.downloader.resolved_basename = bottle_filename
resource.fetch
# Map the name of this formula to the local bottle path to allow the
# formula to be loaded by passing just the name to `Formulary::factory`.
Formulary.map_formula_name_to_local_bottle_path hash["name"], resource.downloader.cached_location
end
end

View File

@ -1,5 +0,0 @@
# typed: strict
module BottleAPI
include Kernel
end

View File

@ -2,8 +2,6 @@
# frozen_string_literal: true
if ENV["HOMEBREW_STACKPROF"]
require_relative "utils/gems"
Homebrew.setup_gem_environment!
require "stackprof"
StackProf.start(mode: :wall, raw: true)
end

View File

@ -113,16 +113,19 @@ module Cask
@caskroom_path ||= Caskroom.path.join(token)
end
def outdated?(greedy: false)
!outdated_versions(greedy: greedy).empty?
def outdated?(greedy: false, greedy_latest: false, greedy_auto_updates: false)
!outdated_versions(greedy: greedy, greedy_latest: greedy_latest,
greedy_auto_updates: greedy_auto_updates).empty?
end
def outdated_versions(greedy: false)
def outdated_versions(greedy: false, greedy_latest: false, greedy_auto_updates: false)
# special case: tap version is not available
return [] if version.nil?
if greedy
if greedy || (greedy_latest && greedy_auto_updates) || (greedy_auto_updates && auto_updates)
return versions if version.latest?
elsif greedy_latest && version.latest?
return versions
elsif auto_updates
return []
end
@ -137,10 +140,11 @@ module Cask
installed.reject { |v| v == version }
end
def outdated_info(greedy, verbose, json)
def outdated_info(greedy, verbose, json, greedy_latest, greedy_auto_updates)
return token if !verbose && !json
installed_versions = outdated_versions(greedy: greedy).join(", ")
installed_versions = outdated_versions(greedy: greedy, greedy_latest: greedy_latest,
greedy_auto_updates: greedy_auto_updates).join(", ")
if json
{

View File

@ -19,6 +19,12 @@ module Cask
[:switch, "--greedy", {
description: "Also include casks with `auto_updates true` or `version :latest`.",
}],
[:switch, "--greedy-latest", {
description: "Also include casks with `version :latest`.",
}],
[:switch, "--greedy-auto-updates", {
description: "Also include casks with `auto_updates true`.",
}],
].freeze
sig { returns(Homebrew::CLI::Parser) }
@ -40,30 +46,34 @@ module Cask
verbose = ($stdout.tty? || args.verbose?) && !args.quiet?
self.class.upgrade_casks(
*casks,
force: args.force?,
greedy: args.greedy?,
dry_run: args.dry_run?,
binaries: args.binaries?,
quarantine: args.quarantine?,
require_sha: args.require_sha?,
skip_cask_deps: args.skip_cask_deps?,
verbose: verbose,
args: args,
force: args.force?,
greedy: args.greedy?,
greedy_latest: args.greedy_latest?,
greedy_auto_updates: args.greedy_auto_updates?,
dry_run: args.dry_run?,
binaries: args.binaries?,
quarantine: args.quarantine?,
require_sha: args.require_sha?,
skip_cask_deps: args.skip_cask_deps?,
verbose: verbose,
args: args,
)
end
sig {
params(
casks: Cask,
args: Homebrew::CLI::Args,
force: T.nilable(T::Boolean),
greedy: T.nilable(T::Boolean),
dry_run: T.nilable(T::Boolean),
skip_cask_deps: T.nilable(T::Boolean),
verbose: T.nilable(T::Boolean),
binaries: T.nilable(T::Boolean),
quarantine: T.nilable(T::Boolean),
require_sha: T.nilable(T::Boolean),
casks: Cask,
args: Homebrew::CLI::Args,
force: T.nilable(T::Boolean),
greedy: T.nilable(T::Boolean),
greedy_latest: T.nilable(T::Boolean),
greedy_auto_updates: T.nilable(T::Boolean),
dry_run: T.nilable(T::Boolean),
skip_cask_deps: T.nilable(T::Boolean),
verbose: T.nilable(T::Boolean),
binaries: T.nilable(T::Boolean),
quarantine: T.nilable(T::Boolean),
require_sha: T.nilable(T::Boolean),
).returns(T::Boolean)
}
def self.upgrade_casks(
@ -71,6 +81,8 @@ module Cask
args:,
force: false,
greedy: false,
greedy_latest: false,
greedy_auto_updates: false,
dry_run: false,
skip_cask_deps: false,
verbose: false,
@ -83,7 +95,8 @@ module Cask
outdated_casks = if casks.empty?
Caskroom.casks(config: Config.from_args(args)).select do |cask|
cask.outdated?(greedy: greedy)
cask.outdated?(greedy: greedy, greedy_latest: args.greedy_latest?,
greedy_auto_updates: args.greedy_auto_updates?)
end
else
casks.select do |cask|
@ -107,7 +120,16 @@ module Cask
return false if outdated_casks.empty?
if casks.empty? && !greedy
ohai "Casks with 'auto_updates' or 'version :latest' will not be upgraded; pass `--greedy` to upgrade them."
if !args.greedy_auto_updates? && !args.greedy_latest?
ohai "Casks with 'auto_updates true' or 'version :latest'
will not be upgraded; pass `--greedy` to upgrade them."
end
if args.greedy_auto_updates? && !args.greedy_latest?
ohai "Casks with 'version :latest' will not be upgraded; pass `--greedy-latest` to upgrade them."
end
if !args.greedy_auto_updates? && args.greedy_latest?
ohai "Casks with 'auto_updates true' will not be upgraded; pass `--greedy-auto-updates` to upgrade them."
end
end
verb = dry_run ? "Would upgrade" : "Upgrading"

View File

@ -2,7 +2,7 @@
# frozen_string_literal: true
require "delegate"
require "bottle_api"
require "api"
require "cli/args"
module Homebrew
@ -94,8 +94,9 @@ module Homebrew
unreadable_error = nil
if only != :cask
if prefer_loading_from_json && ENV["HOMEBREW_JSON_CORE"].present? && BottleAPI.bottle_available?(name)
BottleAPI.fetch_bottles(name)
if prefer_loading_from_json && ENV["HOMEBREW_JSON_CORE"].present? &&
Homebrew::API::Bottle.available?(name)
Homebrew::API::Bottle.fetch_bottles(name)
end
begin
@ -324,7 +325,11 @@ module Homebrew
# Return keg if it is the only installed keg
return kegs if kegs.length == 1
kegs.reject { |k| k.version.head? }.max_by(&:version)
stable_kegs = kegs.reject { |k| k.version.head? }
return kegs.max_by { |keg| Tab.for_keg(keg).source_modified_time } if stable_kegs.blank?
stable_kegs.max_by(&:version)
end
def resolve_default_keg(name)

View File

@ -92,15 +92,19 @@ module Homebrew
result
end
def load_logs(dir)
def load_logs(dir, basedir = dir)
logs = {}
if dir.exist?
dir.children.sort.each do |file|
contents = file.size? ? file.read : "empty log"
# small enough to avoid GitHub "unicorn" page-load-timeout errors
max_file_size = 1_000_000
contents = truncate_text_to_approximate_size(contents, max_file_size, front_weight: 0.2)
logs[file.basename.to_s] = { content: contents }
if file.directory?
logs.merge! load_logs(file, basedir)
else
contents = file.size? ? file.read : "empty log"
# small enough to avoid GitHub "unicorn" page-load-timeout errors
max_file_size = 1_000_000
contents = truncate_text_to_approximate_size(contents, max_file_size, front_weight: 0.2)
logs[file.relative_path_from(basedir).to_s.tr("/", ":")] = { content: contents }
end
end
end
odie "No logs." if logs.empty?

View File

@ -11,6 +11,7 @@ require "tab"
require "json"
require "utils/spdx"
require "deprecate_disable"
require "api"
module Homebrew
extend T::Sig
@ -243,8 +244,8 @@ module Homebrew
def info_formula(f, args:)
specs = []
if ENV["HOMEBREW_JSON_CORE"].present? && BottleAPI.bottle_available?(f.name)
info = BottleAPI.fetch(f.name)
if ENV["HOMEBREW_JSON_CORE"].present? && Homebrew::API::Bottle.available?(f.name)
info = Homebrew::API::Bottle.fetch(f.name)
latest_version = info["pkg_version"].split("_").first
bottle_exists = info["bottles"].key?(Utils::Bottles.tag.to_s) || info["bottles"].key?("all")

View File

@ -6,7 +6,7 @@ require "keg"
require "cli/parser"
require "cask/cmd"
require "cask/caskroom"
require "bottle_api"
require "api"
module Homebrew
extend T::Sig
@ -37,7 +37,13 @@ module Homebrew
"formula is outdated. Otherwise, the repository's HEAD will only be checked for "\
"updates when a new stable or development version has been released."
switch "--greedy",
description: "Print outdated casks with `auto_updates` or `version :latest`."
description: "Print outdated casks with `auto_updates true` or `version :latest`."
switch "--greedy-latest",
description: "Print outdated casks including those with `version :latest`."
switch "--greedy-auto-updates",
description: "Print outdated casks including those with `auto_updates true`."
conflicts "--quiet", "--verbose", "--json"
conflicts "--formula", "--cask"
@ -93,7 +99,7 @@ module Homebrew
outdated_kegs = f.outdated_kegs(fetch_head: args.fetch_HEAD?)
current_version = if ENV["HOMEBREW_JSON_CORE"].present? && (f.core_formula? || f.tap.blank?)
BottleAPI.latest_pkg_version(f.name)&.to_s || f.pkg_version.to_s
Homebrew::API::Versions.latest_formula_version(f.name)&.to_s || f.pkg_version.to_s
elsif f.alias_changed? && !f.latest_formula.latest_version_installed?
latest = f.latest_formula
"#{latest.name} (#{latest.pkg_version})"
@ -119,7 +125,7 @@ module Homebrew
else
c = formula_or_cask
puts c.outdated_info(args.greedy?, verbose?, false)
puts c.outdated_info(args.greedy?, verbose?, false, args.greedy_latest?, args.greedy_auto_updates?)
end
end
end
@ -144,7 +150,7 @@ module Homebrew
else
c = formula_or_cask
c.outdated_info(args.greedy?, verbose?, true)
c.outdated_info(args.greedy?, verbose?, true, args.greedy_latest?, args.greedy_auto_updates?)
end
end
end
@ -194,7 +200,8 @@ module Homebrew
if formula_or_cask.is_a?(Formula)
formula_or_cask.outdated?(fetch_head: args.fetch_HEAD?)
else
formula_or_cask.outdated?(greedy: args.greedy?)
formula_or_cask.outdated?(greedy: args.greedy?, greedy_latest: args.greedy_latest?,
greedy_auto_updates: args.greedy_auto_updates?)
end
end
end

View File

@ -12,7 +12,7 @@ require "cask/cmd"
require "cask/utils"
require "cask/macos"
require "upgrade"
require "bottle_api"
require "api"
module Homebrew
extend T::Sig
@ -90,9 +90,9 @@ module Homebrew
formula = Formulary.factory(name)
next unless formula.any_version_installed?
next if formula.tap.present? && !formula.core_formula?
next unless BottleAPI.bottle_available?(name)
next unless Homebrew::API::Bottle.available?(name)
BottleAPI.fetch_bottles(name)
Homebrew::API::Bottle.fetch_bottles(name)
rescue FormulaUnavailableError
next
end

View File

@ -78,7 +78,7 @@ module Homebrew
string_or_regex = query_regexp(query)
if args.desc?
search_descriptions(string_or_regex)
search_descriptions(string_or_regex, args)
elsif args.pull_request?
only = if args.open? && !args.closed?
"open"

View File

@ -3,25 +3,30 @@
#: Print export statements. When run in a shell, this installation of Homebrew will be added to your `PATH`, `MANPATH`, and `INFOPATH`.
#:
#: The variables `HOMEBREW_PREFIX`, `HOMEBREW_CELLAR` and `HOMEBREW_REPOSITORY` are also exported to avoid querying them multiple times.
#: The variable `HOMEBREW_SHELLENV_PREFIX` will be exported to avoid adding duplicate entries to the environment variables.
#: Consider adding evaluation of this command's output to your dotfiles (e.g. `~/.profile`, `~/.bash_profile`, or `~/.zprofile`) with: `eval $(brew shellenv)`
# HOMEBREW_CELLAR and HOMEBREW_PREFIX are set by extend/ENV/super.rb
# HOMEBREW_REPOSITORY is set by bin/brew
# shellcheck disable=SC2154
homebrew-shellenv() {
[[ "${HOMEBREW_SHELLENV_PREFIX}" == "${HOMEBREW_PREFIX}" ]] && return
case "$(/bin/ps -p "${PPID}" -c -o comm=)" in
fish|-fish)
fish | -fish)
echo "set -gx HOMEBREW_PREFIX \"${HOMEBREW_PREFIX}\";"
echo "set -gx HOMEBREW_CELLAR \"${HOMEBREW_CELLAR}\";"
echo "set -gx HOMEBREW_REPOSITORY \"${HOMEBREW_REPOSITORY}\";"
echo "set -gx HOMEBREW_SHELLENV_PREFIX \"${HOMEBREW_PREFIX}\";"
echo "set -q PATH; or set PATH ''; set -gx PATH \"${HOMEBREW_PREFIX}/bin\" \"${HOMEBREW_PREFIX}/sbin\" \$PATH;"
echo "set -q MANPATH; or set MANPATH ''; set -gx MANPATH \"${HOMEBREW_PREFIX}/share/man\" \$MANPATH;"
echo "set -q INFOPATH; or set INFOPATH ''; set -gx INFOPATH \"${HOMEBREW_PREFIX}/share/info\" \$INFOPATH;"
;;
csh|-csh|tcsh|-tcsh)
csh | -csh | tcsh | -tcsh)
echo "setenv HOMEBREW_PREFIX ${HOMEBREW_PREFIX};"
echo "setenv HOMEBREW_CELLAR ${HOMEBREW_CELLAR};"
echo "setenv HOMEBREW_REPOSITORY ${HOMEBREW_REPOSITORY};"
echo "setenv HOMEBREW_SHELLENV_PREFIX ${HOMEBREW_PREFIX};"
echo "setenv PATH ${HOMEBREW_PREFIX}/bin:${HOMEBREW_PREFIX}/sbin:\$PATH;"
echo "setenv MANPATH ${HOMEBREW_PREFIX}/share/man\`[ \${?MANPATH} == 1 ] && echo \":\${MANPATH}\"\`:;"
echo "setenv INFOPATH ${HOMEBREW_PREFIX}/share/info\`[ \${?INFOPATH} == 1 ] && echo \":\${INFOPATH}\"\`;"
@ -30,6 +35,7 @@ homebrew-shellenv() {
echo "export HOMEBREW_PREFIX=\"${HOMEBREW_PREFIX}\";"
echo "export HOMEBREW_CELLAR=\"${HOMEBREW_CELLAR}\";"
echo "export HOMEBREW_REPOSITORY=\"${HOMEBREW_REPOSITORY}\";"
echo "export HOMEBREW_SHELLENV_PREFIX=\"${HOMEBREW_PREFIX}\";"
echo "export PATH=\"${HOMEBREW_PREFIX}/bin:${HOMEBREW_PREFIX}/sbin\${PATH+:\$PATH}\";"
echo "export MANPATH=\"${HOMEBREW_PREFIX}/share/man\${MANPATH+:\$MANPATH}:\";"
echo "export INFOPATH=\"${HOMEBREW_PREFIX}/share/info:\${INFOPATH:-}\";"

View File

@ -8,7 +8,7 @@ require "upgrade"
require "cask/cmd"
require "cask/utils"
require "cask/macos"
require "bottle_api"
require "api"
module Homebrew
extend T::Sig
@ -163,9 +163,9 @@ module Homebrew
if ENV["HOMEBREW_JSON_CORE"].present?
formulae_to_install.map! do |formula|
next formula if formula.tap.present? && !formula.core_formula?
next formula unless BottleAPI.bottle_available?(formula.name)
next formula unless Homebrew::API::Bottle.available?(formula.name)
BottleAPI.fetch_bottles(formula.name)
Homebrew::API::Bottle.fetch_bottles(formula.name)
Formulary.factory(formula.name)
rescue FormulaUnavailableError
formula

View File

@ -1,44 +1,23 @@
{
"licenseListVersion": "3.13",
"licenseListVersion": "3.14",
"exceptions": [
{
"reference": "./eCos-exception-2.0.json",
"reference": "./GPL-CC-1.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./eCos-exception-2.0.html",
"detailsUrl": "./GPL-CC-1.0.html",
"referenceNumber": 1,
"name": "eCos exception 2.0",
"licenseExceptionId": "eCos-exception-2.0",
"name": "GPL Cooperation Commitment 1.0",
"licenseExceptionId": "GPL-CC-1.0",
"seeAlso": [
"http://ecos.sourceware.org/license-overview.html"
]
},
{
"reference": "./Qt-LGPL-exception-1.1.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Qt-LGPL-exception-1.1.html",
"referenceNumber": 2,
"name": "Qt LGPL exception 1.1",
"licenseExceptionId": "Qt-LGPL-exception-1.1",
"seeAlso": [
"http://code.qt.io/cgit/qt/qtbase.git/tree/LGPL_EXCEPTION.txt"
]
},
{
"reference": "./PS-or-PDF-font-exception-20170817.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./PS-or-PDF-font-exception-20170817.html",
"referenceNumber": 3,
"name": "PS/PDF font exception (2017-08-17)",
"licenseExceptionId": "PS-or-PDF-font-exception-20170817",
"seeAlso": [
"https://github.com/ArtifexSoftware/urw-base35-fonts/blob/65962e27febc3883a17e651cdb23e783668c996f/LICENSE"
"https://github.com/gplcc/gplcc/blob/master/Project/COMMITMENT",
"https://gplcc.github.io/gplcc/Project/README-PROJECT.html"
]
},
{
"reference": "./openvpn-openssl-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./openvpn-openssl-exception.html",
"referenceNumber": 4,
"referenceNumber": 2,
"name": "OpenVPN OpenSSL Exception",
"licenseExceptionId": "openvpn-openssl-exception",
"seeAlso": [
@ -46,32 +25,89 @@
]
},
{
"reference": "./Bootloader-exception.json",
"reference": "./WxWindows-exception-3.1.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Bootloader-exception.html",
"referenceNumber": 5,
"name": "Bootloader Distribution Exception",
"licenseExceptionId": "Bootloader-exception",
"detailsUrl": "./WxWindows-exception-3.1.html",
"referenceNumber": 3,
"name": "WxWindows Library Exception 3.1",
"licenseExceptionId": "WxWindows-exception-3.1",
"seeAlso": [
"https://github.com/pyinstaller/pyinstaller/blob/develop/COPYING.txt"
"http://www.opensource.org/licenses/WXwindows"
]
},
{
"reference": "./OCCT-exception-1.0.json",
"reference": "./GPL-3.0-linking-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./OCCT-exception-1.0.html",
"referenceNumber": 6,
"name": "Open CASCADE Exception 1.0",
"licenseExceptionId": "OCCT-exception-1.0",
"detailsUrl": "./GPL-3.0-linking-exception.html",
"referenceNumber": 4,
"name": "GPL-3.0 Linking Exception",
"licenseExceptionId": "GPL-3.0-linking-exception",
"seeAlso": [
"http://www.opencascade.com/content/licensing"
"https://www.gnu.org/licenses/gpl-faq.en.html#GPLIncompatibleLibs"
]
},
{
"reference": "./i2p-gpl-java-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./i2p-gpl-java-exception.html",
"referenceNumber": 5,
"name": "i2p GPL+Java Exception",
"licenseExceptionId": "i2p-gpl-java-exception",
"seeAlso": [
"http://geti2p.net/en/get-involved/develop/licenses#java_exception"
]
},
{
"reference": "./OpenJDK-assembly-exception-1.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./OpenJDK-assembly-exception-1.0.html",
"referenceNumber": 6,
"name": "OpenJDK Assembly exception 1.0",
"licenseExceptionId": "OpenJDK-assembly-exception-1.0",
"seeAlso": [
"http://openjdk.java.net/legal/assembly-exception.html"
]
},
{
"reference": "./mif-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./mif-exception.html",
"referenceNumber": 7,
"name": "Macros and Inline Functions Exception",
"licenseExceptionId": "mif-exception",
"seeAlso": [
"http://www.scs.stanford.edu/histar/src/lib/cppsup/exception",
"http://dev.bertos.org/doxygen/",
"https://www.threadingbuildingblocks.org/licensing"
]
},
{
"reference": "./CLISP-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./CLISP-exception-2.0.html",
"referenceNumber": 8,
"name": "CLISP exception 2.0",
"licenseExceptionId": "CLISP-exception-2.0",
"seeAlso": [
"http://sourceforge.net/p/clisp/clisp/ci/default/tree/COPYRIGHT"
]
},
{
"reference": "./freertos-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./freertos-exception-2.0.html",
"referenceNumber": 9,
"name": "FreeRTOS Exception 2.0",
"licenseExceptionId": "freertos-exception-2.0",
"seeAlso": [
"https://web.archive.org/web/20060809182744/http://www.freertos.org/a00114.html"
]
},
{
"reference": "./Bison-exception-2.2.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Bison-exception-2.2.html",
"referenceNumber": 7,
"referenceNumber": 10,
"name": "Bison exception 2.2",
"licenseExceptionId": "Bison-exception-2.2",
"seeAlso": [
@ -79,60 +115,26 @@
]
},
{
"reference": "./Swift-exception.json",
"reference": "./OCCT-exception-1.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Swift-exception.html",
"referenceNumber": 8,
"name": "Swift Exception",
"licenseExceptionId": "Swift-exception",
"seeAlso": [
"https://swift.org/LICENSE.txt",
"https://github.com/apple/swift-package-manager/blob/7ab2275f447a5eb37497ed63a9340f8a6d1e488b/LICENSE.txt#L205"
]
},
{
"reference": "./Linux-syscall-note.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Linux-syscall-note.html",
"referenceNumber": 9,
"name": "Linux Syscall Note",
"licenseExceptionId": "Linux-syscall-note",
"seeAlso": [
"https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/COPYING"
]
},
{
"reference": "./389-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./389-exception.html",
"referenceNumber": 10,
"name": "389 Directory Server Exception",
"licenseExceptionId": "389-exception",
"seeAlso": [
"http://directory.fedoraproject.org/wiki/GPL_Exception_License_Text"
]
},
{
"reference": "./GPL-3.0-linking-source-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./GPL-3.0-linking-source-exception.html",
"detailsUrl": "./OCCT-exception-1.0.html",
"referenceNumber": 11,
"name": "GPL-3.0 Linking Exception (with Corresponding Source)",
"licenseExceptionId": "GPL-3.0-linking-source-exception",
"name": "Open CASCADE Exception 1.0",
"licenseExceptionId": "OCCT-exception-1.0",
"seeAlso": [
"https://www.gnu.org/licenses/gpl-faq.en.html#GPLIncompatibleLibs",
"https://github.com/mirror/wget/blob/master/src/http.c#L20"
"http://www.opencascade.com/content/licensing"
]
},
{
"reference": "./FLTK-exception.json",
"reference": "./Autoconf-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./FLTK-exception.html",
"detailsUrl": "./Autoconf-exception-2.0.html",
"referenceNumber": 12,
"name": "FLTK exception",
"licenseExceptionId": "FLTK-exception",
"name": "Autoconf exception 2.0",
"licenseExceptionId": "Autoconf-exception-2.0",
"seeAlso": [
"http://www.fltk.org/COPYING.php"
"http://ac-archive.sourceforge.net/doc/copyright.html",
"http://ftp.gnu.org/gnu/autoconf/autoconf-2.59.tar.gz"
]
},
{
@ -146,168 +148,78 @@
"http://llvm.org/foundation/relicensing/LICENSE.txt"
]
},
{
"reference": "./GPL-3.0-linking-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./GPL-3.0-linking-exception.html",
"referenceNumber": 14,
"name": "GPL-3.0 Linking Exception",
"licenseExceptionId": "GPL-3.0-linking-exception",
"seeAlso": [
"https://www.gnu.org/licenses/gpl-faq.en.html#GPLIncompatibleLibs"
]
},
{
"reference": "./GCC-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./GCC-exception-2.0.html",
"referenceNumber": 15,
"name": "GCC Runtime Library exception 2.0",
"licenseExceptionId": "GCC-exception-2.0",
"seeAlso": [
"https://gcc.gnu.org/git/?p\u003dgcc.git;a\u003dblob;f\u003dgcc/libgcc1.c;h\u003d762f5143fc6eed57b6797c82710f3538aa52b40b;hb\u003dcb143a3ce4fb417c68f5fa2691a1b1b1053dfba9#l10"
]
},
{
"reference": "./SHL-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./SHL-2.0.html",
"referenceNumber": 16,
"name": "Solderpad Hardware License v2.0",
"licenseExceptionId": "SHL-2.0",
"seeAlso": [
"https://solderpad.org/licenses/SHL-2.0/"
]
},
{
"reference": "./Libtool-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Libtool-exception.html",
"referenceNumber": 17,
"name": "Libtool Exception",
"licenseExceptionId": "Libtool-exception",
"seeAlso": [
"http://git.savannah.gnu.org/cgit/libtool.git/tree/m4/libtool.m4"
]
},
{
"reference": "./Nokia-Qt-exception-1.1.json",
"isDeprecatedLicenseId": true,
"detailsUrl": "./Nokia-Qt-exception-1.1.html",
"referenceNumber": 18,
"name": "Nokia Qt LGPL exception 1.1",
"licenseExceptionId": "Nokia-Qt-exception-1.1",
"seeAlso": [
"https://www.keepassx.org/dev/projects/keepassx/repository/revisions/b8dfb9cc4d5133e0f09cd7533d15a4f1c19a40f2/entry/LICENSE.NOKIA-LGPL-EXCEPTION"
]
},
{
"reference": "./mif-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./mif-exception.html",
"referenceNumber": 19,
"name": "Macros and Inline Functions Exception",
"licenseExceptionId": "mif-exception",
"seeAlso": [
"http://www.scs.stanford.edu/histar/src/lib/cppsup/exception",
"http://dev.bertos.org/doxygen/",
"https://www.threadingbuildingblocks.org/licensing"
]
},
{
"reference": "./SHL-2.1.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./SHL-2.1.html",
"referenceNumber": 20,
"name": "Solderpad Hardware License v2.1",
"licenseExceptionId": "SHL-2.1",
"seeAlso": [
"https://solderpad.org/licenses/SHL-2.1/"
]
},
{
"reference": "./Font-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Font-exception-2.0.html",
"referenceNumber": 21,
"name": "Font exception 2.0",
"licenseExceptionId": "Font-exception-2.0",
"seeAlso": [
"http://www.gnu.org/licenses/gpl-faq.html#FontException"
]
},
{
"reference": "./WxWindows-exception-3.1.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./WxWindows-exception-3.1.html",
"referenceNumber": 22,
"name": "WxWindows Library Exception 3.1",
"licenseExceptionId": "WxWindows-exception-3.1",
"seeAlso": [
"http://www.opensource.org/licenses/WXwindows"
]
},
{
"reference": "./CLISP-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./CLISP-exception-2.0.html",
"referenceNumber": 23,
"name": "CLISP exception 2.0",
"licenseExceptionId": "CLISP-exception-2.0",
"seeAlso": [
"http://sourceforge.net/p/clisp/clisp/ci/default/tree/COPYRIGHT"
]
},
{
"reference": "./Autoconf-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Autoconf-exception-2.0.html",
"referenceNumber": 24,
"name": "Autoconf exception 2.0",
"licenseExceptionId": "Autoconf-exception-2.0",
"seeAlso": [
"http://ac-archive.sourceforge.net/doc/copyright.html",
"http://ftp.gnu.org/gnu/autoconf/autoconf-2.59.tar.gz"
]
},
{
"reference": "./Autoconf-exception-3.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Autoconf-exception-3.0.html",
"referenceNumber": 25,
"name": "Autoconf exception 3.0",
"licenseExceptionId": "Autoconf-exception-3.0",
"seeAlso": [
"http://www.gnu.org/licenses/autoconf-exception-3.0.html"
]
},
{
"reference": "./Universal-FOSS-exception-1.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Universal-FOSS-exception-1.0.html",
"referenceNumber": 26,
"name": "Universal FOSS Exception, Version 1.0",
"licenseExceptionId": "Universal-FOSS-exception-1.0",
"seeAlso": [
"https://oss.oracle.com/licenses/universal-foss-exception/"
]
},
{
"reference": "./GCC-exception-3.1.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./GCC-exception-3.1.html",
"referenceNumber": 27,
"referenceNumber": 14,
"name": "GCC Runtime Library exception 3.1",
"licenseExceptionId": "GCC-exception-3.1",
"seeAlso": [
"http://www.gnu.org/licenses/gcc-exception-3.1.html"
]
},
{
"reference": "./Font-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Font-exception-2.0.html",
"referenceNumber": 15,
"name": "Font exception 2.0",
"licenseExceptionId": "Font-exception-2.0",
"seeAlso": [
"http://www.gnu.org/licenses/gpl-faq.html#FontException"
]
},
{
"reference": "./Libtool-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Libtool-exception.html",
"referenceNumber": 16,
"name": "Libtool Exception",
"licenseExceptionId": "Libtool-exception",
"seeAlso": [
"http://git.savannah.gnu.org/cgit/libtool.git/tree/m4/libtool.m4"
]
},
{
"reference": "./u-boot-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./u-boot-exception-2.0.html",
"referenceNumber": 17,
"name": "U-Boot exception 2.0",
"licenseExceptionId": "u-boot-exception-2.0",
"seeAlso": [
"http://git.denx.de/?p\u003du-boot.git;a\u003dblob;f\u003dLicenses/Exceptions"
]
},
{
"reference": "./Swift-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Swift-exception.html",
"referenceNumber": 18,
"name": "Swift Exception",
"licenseExceptionId": "Swift-exception",
"seeAlso": [
"https://swift.org/LICENSE.txt",
"https://github.com/apple/swift-package-manager/blob/7ab2275f447a5eb37497ed63a9340f8a6d1e488b/LICENSE.txt#L205"
]
},
{
"reference": "./eCos-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./eCos-exception-2.0.html",
"referenceNumber": 19,
"name": "eCos exception 2.0",
"licenseExceptionId": "eCos-exception-2.0",
"seeAlso": [
"http://ecos.sourceware.org/license-overview.html"
]
},
{
"reference": "./OCaml-LGPL-linking-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./OCaml-LGPL-linking-exception.html",
"referenceNumber": 28,
"referenceNumber": 20,
"name": "OCaml LGPL Linking Exception",
"licenseExceptionId": "OCaml-LGPL-linking-exception",
"seeAlso": [
@ -315,21 +227,65 @@
]
},
{
"reference": "./gnu-javamail-exception.json",
"reference": "./Qt-GPL-exception-1.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./gnu-javamail-exception.html",
"referenceNumber": 29,
"name": "GNU JavaMail exception",
"licenseExceptionId": "gnu-javamail-exception",
"detailsUrl": "./Qt-GPL-exception-1.0.html",
"referenceNumber": 21,
"name": "Qt GPL exception 1.0",
"licenseExceptionId": "Qt-GPL-exception-1.0",
"seeAlso": [
"http://www.gnu.org/software/classpathx/javamail/javamail.html"
"http://code.qt.io/cgit/qt/qtbase.git/tree/LICENSE.GPL3-EXCEPT"
]
},
{
"reference": "./Linux-syscall-note.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Linux-syscall-note.html",
"referenceNumber": 22,
"name": "Linux Syscall Note",
"licenseExceptionId": "Linux-syscall-note",
"seeAlso": [
"https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/COPYING"
]
},
{
"reference": "./Bootloader-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Bootloader-exception.html",
"referenceNumber": 23,
"name": "Bootloader Distribution Exception",
"licenseExceptionId": "Bootloader-exception",
"seeAlso": [
"https://github.com/pyinstaller/pyinstaller/blob/develop/COPYING.txt"
]
},
{
"reference": "./PS-or-PDF-font-exception-20170817.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./PS-or-PDF-font-exception-20170817.html",
"referenceNumber": 24,
"name": "PS/PDF font exception (2017-08-17)",
"licenseExceptionId": "PS-or-PDF-font-exception-20170817",
"seeAlso": [
"https://github.com/ArtifexSoftware/urw-base35-fonts/blob/65962e27febc3883a17e651cdb23e783668c996f/LICENSE"
]
},
{
"reference": "./Universal-FOSS-exception-1.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Universal-FOSS-exception-1.0.html",
"referenceNumber": 25,
"name": "Universal FOSS Exception, Version 1.0",
"licenseExceptionId": "Universal-FOSS-exception-1.0",
"seeAlso": [
"https://oss.oracle.com/licenses/universal-foss-exception/"
]
},
{
"reference": "./Classpath-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Classpath-exception-2.0.html",
"referenceNumber": 30,
"referenceNumber": 26,
"name": "Classpath exception 2.0",
"licenseExceptionId": "Classpath-exception-2.0",
"seeAlso": [
@ -337,80 +293,11 @@
"https://fedoraproject.org/wiki/Licensing/GPL_Classpath_Exception"
]
},
{
"reference": "./OpenJDK-assembly-exception-1.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./OpenJDK-assembly-exception-1.0.html",
"referenceNumber": 31,
"name": "OpenJDK Assembly exception 1.0",
"licenseExceptionId": "OpenJDK-assembly-exception-1.0",
"seeAlso": [
"http://openjdk.java.net/legal/assembly-exception.html"
]
},
{
"reference": "./LGPL-3.0-linking-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./LGPL-3.0-linking-exception.html",
"referenceNumber": 32,
"name": "LGPL-3.0 Linking Exception",
"licenseExceptionId": "LGPL-3.0-linking-exception",
"seeAlso": [
"https://raw.githubusercontent.com/go-xmlpath/xmlpath/v2/LICENSE",
"https://github.com/goamz/goamz/blob/master/LICENSE",
"https://github.com/juju/errors/blob/master/LICENSE"
]
},
{
"reference": "./GPL-CC-1.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./GPL-CC-1.0.html",
"referenceNumber": 33,
"name": "GPL Cooperation Commitment 1.0",
"licenseExceptionId": "GPL-CC-1.0",
"seeAlso": [
"https://github.com/gplcc/gplcc/blob/master/Project/COMMITMENT",
"https://gplcc.github.io/gplcc/Project/README-PROJECT.html"
]
},
{
"reference": "./Qt-GPL-exception-1.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Qt-GPL-exception-1.0.html",
"referenceNumber": 34,
"name": "Qt GPL exception 1.0",
"licenseExceptionId": "Qt-GPL-exception-1.0",
"seeAlso": [
"http://code.qt.io/cgit/qt/qtbase.git/tree/LICENSE.GPL3-EXCEPT"
]
},
{
"reference": "./DigiRule-FOSS-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./DigiRule-FOSS-exception.html",
"referenceNumber": 35,
"name": "DigiRule FOSS License Exception",
"licenseExceptionId": "DigiRule-FOSS-exception",
"seeAlso": [
"http://www.digirulesolutions.com/drupal/foss"
]
},
{
"reference": "./Fawkes-Runtime-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Fawkes-Runtime-exception.html",
"referenceNumber": 36,
"name": "Fawkes Runtime Exception",
"licenseExceptionId": "Fawkes-Runtime-exception",
"seeAlso": [
"http://www.fawkesrobotics.org/about/license/"
]
},
{
"reference": "./Qwt-exception-1.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Qwt-exception-1.0.html",
"referenceNumber": 37,
"referenceNumber": 27,
"name": "Qwt exception 1.0",
"licenseExceptionId": "Qwt-exception-1.0",
"seeAlso": [
@ -421,7 +308,7 @@
"reference": "./LZMA-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./LZMA-exception.html",
"referenceNumber": 38,
"referenceNumber": 28,
"name": "LZMA exception",
"licenseExceptionId": "LZMA-exception",
"seeAlso": [
@ -429,38 +316,151 @@
]
},
{
"reference": "./freertos-exception-2.0.json",
"reference": "./Autoconf-exception-3.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./freertos-exception-2.0.html",
"detailsUrl": "./Autoconf-exception-3.0.html",
"referenceNumber": 29,
"name": "Autoconf exception 3.0",
"licenseExceptionId": "Autoconf-exception-3.0",
"seeAlso": [
"http://www.gnu.org/licenses/autoconf-exception-3.0.html"
]
},
{
"reference": "./DigiRule-FOSS-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./DigiRule-FOSS-exception.html",
"referenceNumber": 30,
"name": "DigiRule FOSS License Exception",
"licenseExceptionId": "DigiRule-FOSS-exception",
"seeAlso": [
"http://www.digirulesolutions.com/drupal/foss"
]
},
{
"reference": "./389-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./389-exception.html",
"referenceNumber": 31,
"name": "389 Directory Server Exception",
"licenseExceptionId": "389-exception",
"seeAlso": [
"http://directory.fedoraproject.org/wiki/GPL_Exception_License_Text"
]
},
{
"reference": "./SHL-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./SHL-2.0.html",
"referenceNumber": 32,
"name": "Solderpad Hardware License v2.0",
"licenseExceptionId": "SHL-2.0",
"seeAlso": [
"https://solderpad.org/licenses/SHL-2.0/"
]
},
{
"reference": "./GCC-exception-2.0.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./GCC-exception-2.0.html",
"referenceNumber": 33,
"name": "GCC Runtime Library exception 2.0",
"licenseExceptionId": "GCC-exception-2.0",
"seeAlso": [
"https://gcc.gnu.org/git/?p\u003dgcc.git;a\u003dblob;f\u003dgcc/libgcc1.c;h\u003d762f5143fc6eed57b6797c82710f3538aa52b40b;hb\u003dcb143a3ce4fb417c68f5fa2691a1b1b1053dfba9#l10"
]
},
{
"reference": "./GPL-3.0-linking-source-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./GPL-3.0-linking-source-exception.html",
"referenceNumber": 34,
"name": "GPL-3.0 Linking Exception (with Corresponding Source)",
"licenseExceptionId": "GPL-3.0-linking-source-exception",
"seeAlso": [
"https://www.gnu.org/licenses/gpl-faq.en.html#GPLIncompatibleLibs",
"https://github.com/mirror/wget/blob/master/src/http.c#L20"
]
},
{
"reference": "./Nokia-Qt-exception-1.1.json",
"isDeprecatedLicenseId": true,
"detailsUrl": "./Nokia-Qt-exception-1.1.html",
"referenceNumber": 35,
"name": "Nokia Qt LGPL exception 1.1",
"licenseExceptionId": "Nokia-Qt-exception-1.1",
"seeAlso": [
"https://www.keepassx.org/dev/projects/keepassx/repository/revisions/b8dfb9cc4d5133e0f09cd7533d15a4f1c19a40f2/entry/LICENSE.NOKIA-LGPL-EXCEPTION"
]
},
{
"reference": "./Qt-LGPL-exception-1.1.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Qt-LGPL-exception-1.1.html",
"referenceNumber": 36,
"name": "Qt LGPL exception 1.1",
"licenseExceptionId": "Qt-LGPL-exception-1.1",
"seeAlso": [
"http://code.qt.io/cgit/qt/qtbase.git/tree/LGPL_EXCEPTION.txt"
]
},
{
"reference": "./Fawkes-Runtime-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./Fawkes-Runtime-exception.html",
"referenceNumber": 37,
"name": "Fawkes Runtime Exception",
"licenseExceptionId": "Fawkes-Runtime-exception",
"seeAlso": [
"http://www.fawkesrobotics.org/about/license/"
]
},
{
"reference": "./gnu-javamail-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./gnu-javamail-exception.html",
"referenceNumber": 38,
"name": "GNU JavaMail exception",
"licenseExceptionId": "gnu-javamail-exception",
"seeAlso": [
"http://www.gnu.org/software/classpathx/javamail/javamail.html"
]
},
{
"reference": "./FLTK-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./FLTK-exception.html",
"referenceNumber": 39,
"name": "FreeRTOS Exception 2.0",
"licenseExceptionId": "freertos-exception-2.0",
"name": "FLTK exception",
"licenseExceptionId": "FLTK-exception",
"seeAlso": [
"https://web.archive.org/web/20060809182744/http://www.freertos.org/a00114.html"
"http://www.fltk.org/COPYING.php"
]
},
{
"reference": "./u-boot-exception-2.0.json",
"reference": "./LGPL-3.0-linking-exception.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./u-boot-exception-2.0.html",
"detailsUrl": "./LGPL-3.0-linking-exception.html",
"referenceNumber": 40,
"name": "U-Boot exception 2.0",
"licenseExceptionId": "u-boot-exception-2.0",
"name": "LGPL-3.0 Linking Exception",
"licenseExceptionId": "LGPL-3.0-linking-exception",
"seeAlso": [
"http://git.denx.de/?p\u003du-boot.git;a\u003dblob;f\u003dLicenses/Exceptions"
"https://raw.githubusercontent.com/go-xmlpath/xmlpath/v2/LICENSE",
"https://github.com/goamz/goamz/blob/master/LICENSE",
"https://github.com/juju/errors/blob/master/LICENSE"
]
},
{
"reference": "./i2p-gpl-java-exception.json",
"reference": "./SHL-2.1.json",
"isDeprecatedLicenseId": false,
"detailsUrl": "./i2p-gpl-java-exception.html",
"detailsUrl": "./SHL-2.1.html",
"referenceNumber": 41,
"name": "i2p GPL+Java Exception",
"licenseExceptionId": "i2p-gpl-java-exception",
"name": "Solderpad Hardware License v2.1",
"licenseExceptionId": "SHL-2.1",
"seeAlso": [
"http://geti2p.net/en/get-involved/develop/licenses#java_exception"
"https://solderpad.org/licenses/SHL-2.1/"
]
}
],
"releaseDate": "2021-05-20"
"releaseDate": "2021-08-08"
}

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@ require "utils/inreplace"
require "erb"
require "archive"
require "zlib"
require "api"
BOTTLE_ERB = <<-EOS
bottle do
@ -333,8 +334,6 @@ module Homebrew
root_url = args.root_url
formulae_brew_sh_path = Utils::Analytics.formula_path
relocatable = T.let(false, T::Boolean)
skip_relocation = T.let(false, T::Boolean)
@ -561,7 +560,7 @@ module Homebrew
"filename" => filename.url_encode,
"local_filename" => filename.to_s,
"sha256" => sha256,
"formulae_brew_sh_path" => formulae_brew_sh_path,
"formulae_brew_sh_path" => Homebrew::API::Formula.formula_api_path,
"tab" => tab.to_bottle_hash,
},
},

View File

@ -151,14 +151,30 @@ module Homebrew
end
def livecheck_result(formula_or_cask)
skip_result = Livecheck::SkipConditions.skip_information(formula_or_cask)
if skip_result.present?
return "#{skip_result[:status]}#{" - #{skip_result[:messages].join(", ")}" if skip_result[:messages].present?}"
name = Livecheck.formula_or_cask_name(formula_or_cask)
referenced_formula_or_cask, =
Livecheck.resolve_livecheck_reference(formula_or_cask, full_name: false, debug: false)
# Check skip conditions for a referenced formula/cask
if referenced_formula_or_cask
skip_info = Livecheck::SkipConditions.referenced_skip_information(
referenced_formula_or_cask,
name,
full_name: false,
verbose: false,
)
end
skip_info ||= Livecheck::SkipConditions.skip_information(formula_or_cask, full_name: false, verbose: false)
if skip_info.present?
return "#{skip_info[:status]}#{" - #{skip_info[:messages].join(", ")}" if skip_info[:messages].present?}"
end
version_info = Livecheck.latest_version(
formula_or_cask,
json: true, full_name: false, verbose: false, debug: false,
referenced_formula_or_cask: referenced_formula_or_cask,
json: true, full_name: false, verbose: false, debug: false
)
latest = version_info[:latest] if version_info.present?

View File

@ -40,16 +40,24 @@ module Homebrew
EOS
end
paths = args.named.to_paths.select do |path|
next path if path.exist?
paths = if args.named.empty?
# Sublime requires opting into the project editing path,
# as opposed to VS Code which will infer from the .vscode path
if which_editor == "subl"
["--project", "#{HOMEBREW_REPOSITORY}/.sublime/homebrew.sublime-project"]
else
# If no formulae are listed, open the project root in an editor.
[HOMEBREW_REPOSITORY]
end
else
args.named.to_paths.select do |path|
next path if path.exist?
raise UsageError, "#{path} doesn't exist on disk. " \
"Run #{Formatter.identifier("brew create --set-name #{path.basename} $URL")} " \
"to create a new formula!"
end.presence
# If no formulae are listed, open the project root in an editor.
paths ||= [HOMEBREW_REPOSITORY]
raise UsageError, "#{path} doesn't exist on disk. " \
"Run #{Formatter.identifier("brew create --set-name #{path.basename} $URL")} " \
"to create a new formula!"
end.presence
end
exec_editor(*paths)
end

View File

@ -3,6 +3,7 @@
require "cli/parser"
require "formula"
require "api"
module Homebrew
extend T::Sig
@ -87,7 +88,7 @@ module Homebrew
formula_installs = {}
ohai "Getting analytics data..."
analytics = Utils::Analytics.formulae_brew_sh_json("analytics/install/90d.json")
analytics = Homebrew::API::Analytics.fetch "install", 90
if analytics.blank?
raise UsageError,

View File

@ -388,7 +388,10 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
ohai "Downloading #{url}"
resolved_url, _, url_time, = resolve_url_basename_time_file_size(url, timeout: end_time&.remaining!)
resolved_url, _, url_time, _, is_redirection =
resolve_url_basename_time_file_size(url, timeout: end_time&.remaining!)
# Authorization is no longer valid after redirects
meta[:headers]&.delete_if { |header| header.first&.start_with?("Authorization") } if is_redirection
fresh = if cached_location.exist? && url_time
url_time <= cached_location.mtime
@ -449,7 +452,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
return @resolved_info_cache[url] if @resolved_info_cache.include?(url)
if (domain = Homebrew::EnvConfig.artifact_domain)
url = url.sub(%r{^((ht|f)tps?://)?}, "#{domain.chomp("/")}/")
url = url.sub(%r{^(https?://#{GitHubPackages::URL_DOMAIN}/)?}o, "#{domain.chomp("/")}/")
end
out, _, status= curl_output("--location", "--silent", "--head", "--request", "GET", url.to_s, timeout: timeout)
@ -507,8 +510,9 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
.last
basename = filenames.last || parse_basename(redirect_url)
is_redirection = url != redirect_url
@resolved_info_cache[url] = [redirect_url, basename, time, file_size]
@resolved_info_cache[url] = [redirect_url, basename, time, file_size, is_redirection]
end
def _fetch(url:, resolved_url:, timeout:)
@ -564,7 +568,8 @@ class CurlGitHubPackagesDownloadStrategy < CurlDownloadStrategy
def initialize(url, name, version, **meta)
meta ||= {}
meta[:headers] ||= []
meta[:headers] << ["Authorization: Bearer QQ=="]
token = Homebrew::EnvConfig.artifact_domain ? Homebrew::EnvConfig.docker_registry_token : "QQ=="
meta[:headers] << ["Authorization: Bearer #{token}"] if token.present?
super(url, name, version, meta)
end

View File

@ -170,6 +170,9 @@ module Homebrew
description: "Use this GitHub personal access token when accessing the GitHub Packages Registry "\
"(where bottles may be stored).",
},
HOMEBREW_DOCKER_REGISTRY_TOKEN: {
description: "Use this bearer token for authenticating with a Docker registry proxying GitHub Packages.",
},
HOMEBREW_GITHUB_PACKAGES_USER: {
description: "Use this username when accessing the GitHub Packages Registry (where bottles may be stored).",
},

View File

@ -561,7 +561,7 @@ class BuildFlagsError < RuntimeError
The following #{flag_text}:
#{flags.join(", ")}
#{require_text} building tools, but none are installed.
#{DevelopmentTools.installation_instructions}#{bottle_text}
#{DevelopmentTools.installation_instructions} #{bottle_text}
EOS
super message

View File

@ -0,0 +1,4 @@
# typed: strict
# frozen_string_literal: true
require "extend/os/linux/api/analytics" if OS.linux?

View File

@ -0,0 +1,4 @@
# typed: strict
# frozen_string_literal: true
require "extend/os/linux/api/bottle" if OS.linux?

View File

@ -0,0 +1,4 @@
# typed: strict
# frozen_string_literal: true
require "extend/os/linux/api/formula" if OS.linux?

View File

@ -0,0 +1,16 @@
# typed: false
# frozen_string_literal: true
module Homebrew
module API
module Analytics
class << self
def analytics_api_path
return generic_analytics_api_path if Homebrew::EnvConfig.force_homebrew_on_linux?
"analytics-linux"
end
end
end
end
end

View File

@ -0,0 +1,16 @@
# typed: false
# frozen_string_literal: true
module Homebrew
module API
module Bottle
class << self
def bottle_api_path
return generic_bottle_api_path if Homebrew::EnvConfig.force_homebrew_on_linux?
"bottle-linux"
end
end
end
end
end

View File

@ -0,0 +1,16 @@
# typed: false
# frozen_string_literal: true
module Homebrew
module API
module Formula
class << self
def formula_api_path
return generic_formula_api_path if Homebrew::EnvConfig.force_homebrew_on_linux?
"formula-linux"
end
end
end
end
end

View File

@ -1,23 +0,0 @@
# typed: strict
# frozen_string_literal: true
module Utils
module Analytics
class << self
extend T::Sig
sig { returns(String) }
def formula_path
return generic_formula_path if Homebrew::EnvConfig.force_homebrew_on_linux?
"formula-linux"
end
sig { returns(String) }
def analytics_path
return generic_analytics_path if Homebrew::EnvConfig.force_homebrew_on_linux?
"analytics-linux"
end
end
end
end

View File

@ -7,11 +7,13 @@ require "cask/cask_loader"
module Homebrew
module Search
module Extension
def search_descriptions(string_or_regex)
def search_descriptions(string_or_regex, args)
super
puts
return if args.formula?
ohai "Casks"
Cask::Cask.to_a.extend(Searchable)
.search(string_or_regex, &:name)

View File

@ -1,5 +1,4 @@
# typed: strict
# frozen_string_literal: true
require "extend/os/linux/utils/analytics" if OS.linux?
require "extend/os/mac/utils/analytics" if OS.mac?

View File

@ -261,7 +261,7 @@ class Pathname
else
false
end
rescue Errno::EACCES, Errno::ENOENT, Errno::EBUSY
rescue Errno::EACCES, Errno::ENOENT, Errno::EBUSY, Errno::EPERM
false
end

View File

@ -29,7 +29,7 @@ require "mktemp"
require "find"
require "utils/spdx"
require "extend/on_os"
require "bottle_api"
require "api"
# A formula provides instructions and metadata for Homebrew to install a piece
# of software. Every Homebrew formula is a {Formula}.
@ -520,7 +520,8 @@ class Formula
# exists and is not empty.
# @private
def latest_version_installed?
latest_prefix = if ENV["HOMEBREW_JSON_CORE"].present? && (latest_pkg_version = BottleAPI.latest_pkg_version(name))
latest_prefix = if ENV["HOMEBREW_JSON_CORE"].present? &&
(latest_pkg_version = Homebrew::API::Versions.latest_formula_version(name))
prefix latest_pkg_version
else
latest_installed_prefix
@ -986,13 +987,13 @@ class Formula
# The generated launchd {.plist} file path.
sig { returns(Pathname) }
def plist_path
prefix/"#{plist_name}.plist"
opt_prefix/"#{plist_name}.plist"
end
# The generated systemd {.service} file path.
sig { returns(Pathname) }
def systemd_service_path
prefix/"#{service_name}.service"
opt_prefix/"#{service_name}.service"
end
# The service specification of the software.
@ -1340,7 +1341,7 @@ class Formula
all_kegs = []
current_version = T.let(false, T::Boolean)
latest_version = if ENV["HOMEBREW_JSON_CORE"].present? && (core_formula? || tap.blank?)
BottleAPI.latest_pkg_version(name) || pkg_version
Homebrew::API::Versions.latest_formula_version(name) || pkg_version
else
pkg_version
end
@ -1479,7 +1480,7 @@ class Formula
end
# Standard parameters for cargo builds.
sig { params(root: String, path: String).returns(T::Array[T.any(String, Pathname)]) }
sig { params(root: T.any(String, Pathname), path: String).returns(T::Array[T.any(String, Pathname)]) }
def std_cargo_args(root: prefix, path: ".")
["--locked", "--root", root, "--path", path]
end
@ -1489,13 +1490,19 @@ class Formula
# Setting `CMAKE_FIND_FRAMEWORK` to "LAST" tells CMake to search for our
# libraries before trying to utilize Frameworks, many of which will be from
# 3rd party installs.
sig { returns(T::Array[String]) }
def std_cmake_args
sig {
params(
install_prefix: T.any(String, Pathname),
install_libdir: String,
find_framework: String,
).returns(T::Array[String])
}
def std_cmake_args(install_prefix: prefix, install_libdir: "lib", find_framework: "LAST")
args = %W[
-DCMAKE_INSTALL_PREFIX=#{prefix}
-DCMAKE_INSTALL_LIBDIR=lib
-DCMAKE_INSTALL_PREFIX=#{install_prefix}
-DCMAKE_INSTALL_LIBDIR=#{install_libdir}
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_FIND_FRAMEWORK=LAST
-DCMAKE_FIND_FRAMEWORK=#{find_framework}
-DCMAKE_VERBOSE_MAKEFILE=ON
-Wno-dev
-DBUILD_TESTING=OFF

View File

@ -320,14 +320,16 @@ module FormulaCellarChecks
return if !OS.mac? && !OS.linux?
keg = Keg.new(formula.prefix)
mismatches = keg.binary_executable_or_library_files.reject do |file|
file.arch == Hardware::CPU.arch
mismatches = {}
keg.binary_executable_or_library_files.each do |file|
farch = file.arch
mismatches[file] = farch unless farch == Hardware::CPU.arch
end
return if mismatches.empty?
compatible_universal_binaries, mismatches = mismatches.partition do |file|
file.arch == :universal && file.archs.include?(Hardware::CPU.arch)
end
compatible_universal_binaries, mismatches = mismatches.partition do |file, arch|
arch == :universal && file.archs.include?(Hardware::CPU.arch)
end.map(&:to_h) # To prevent transformation into nested arrays
universal_binaries_expected = if formula.tap.present? && formula.tap.core_tap?
tap_audit_exception(:universal_binary_allowlist, formula.name)
@ -340,9 +342,9 @@ module FormulaCellarChecks
if mismatches.present?
s += <<~EOS
Binaries built for an incompatible architecture were installed into #{formula}'s prefix.
Binaries built for a non-native architecture were installed into #{formula}'s prefix.
The offending files are:
#{mismatches * "\n "}
#{mismatches.map { |m| "#{m.first}\t(#{m.last})" } * "\n "}
EOS
end
@ -350,7 +352,7 @@ module FormulaCellarChecks
s += <<~EOS
Unexpected universal binaries were found.
The offending files are:
#{compatible_universal_binaries * "\n "}
#{compatible_universal_binaries.keys * "\n "}
EOS
end

View File

@ -754,11 +754,11 @@ class FormulaInstaller
ohai "Finishing up" if verbose?
install_service
keg = Keg.new(formula.prefix)
link(keg)
install_service
fix_dynamic_linkage(keg) if !@poured_bottle || !formula.bottle_specification.skip_relocation?
if build_bottle?

View File

@ -15,7 +15,7 @@ class GitHubPackages
URL_DOMAIN = "ghcr.io"
URL_PREFIX = "https://#{URL_DOMAIN}/v2/"
DOCKER_PREFIX = "docker://#{URL_DOMAIN}/"
private_constant :URL_DOMAIN
public_constant :URL_DOMAIN
private_constant :URL_PREFIX
private_constant :DOCKER_PREFIX

View File

@ -18,6 +18,8 @@ class Livecheck
def initialize(formula_or_cask)
@formula_or_cask = formula_or_cask
@referenced_cask_name = nil
@referenced_formula_name = nil
@regex = nil
@skip = false
@skip_msg = nil
@ -25,6 +27,42 @@ class Livecheck
@url = nil
end
# Sets the `@referenced_cask_name` instance variable to the provided `String`
# or returns the `@referenced_cask_name` instance variable when no argument
# is provided. Inherited livecheck values from the referenced cask
# (e.g. regex) can be overridden in the livecheck block.
#
# @param cask_name [String] name of cask to inherit livecheck info from
# @return [String, nil]
def cask(cask_name = nil)
case cask_name
when nil
@referenced_cask_name
when String
@referenced_cask_name = cask_name
else
raise TypeError, "Livecheck#cask expects a String"
end
end
# Sets the `@referenced_formula_name` instance variable to the provided
# `String` or returns the `@referenced_formula_name` instance variable when
# no argument is provided. Inherited livecheck values from the referenced
# formula (e.g. regex) can be overridden in the livecheck block.
#
# @param formula_name [String] name of formula to inherit livecheck info from
# @return [String, nil]
def formula(formula_name = nil)
case formula_name
when nil
@referenced_formula_name
when String
@referenced_formula_name = formula_name
else
raise TypeError, "Livecheck#formula expects a String"
end
end
# Sets the `@regex` instance variable to the provided `Regexp` or returns the
# `@regex` instance variable when no argument is provided.
#
@ -109,6 +147,8 @@ class Livecheck
# @return [Hash]
def to_hash
{
"cask" => @referenced_cask_name,
"formula" => @referenced_formula_name,
"regex" => @regex,
"skip" => @skip,
"skip_msg" => @skip_msg,

View File

@ -9,6 +9,8 @@ require "ruby-progressbar"
require "uri"
module Homebrew
# rubocop:disable Metrics/ModuleLength
# The {Livecheck} module consists of methods used by the `brew livecheck`
# command. These methods print the requested livecheck information
# for formulae.
@ -82,6 +84,74 @@ module Homebrew
end
end
# Resolve formula/cask references in `livecheck` blocks to a final formula
# or cask.
sig {
params(
formula_or_cask: T.any(Formula, Cask::Cask),
first_formula_or_cask: T.any(Formula, Cask::Cask),
references: T::Array[T.any(Formula, Cask::Cask)],
full_name: T::Boolean,
debug: T::Boolean,
).returns(T.nilable(T::Array[T.untyped]))
}
def resolve_livecheck_reference(
formula_or_cask,
first_formula_or_cask = formula_or_cask,
references = [],
full_name: false,
debug: false
)
# Check the livecheck block for a formula or cask reference
livecheck = formula_or_cask.livecheck
livecheck_formula = livecheck.formula
livecheck_cask = livecheck.cask
return [nil, references] if livecheck_formula.blank? && livecheck_cask.blank?
# Load the referenced formula or cask
referenced_formula_or_cask = if livecheck_formula
Formulary.factory(livecheck_formula)
elsif livecheck_cask
Cask::CaskLoader.load(livecheck_cask)
end
# Error if a `livecheck` block references a formula/cask that was already
# referenced (or itself)
if referenced_formula_or_cask == first_formula_or_cask ||
referenced_formula_or_cask == formula_or_cask ||
references.include?(referenced_formula_or_cask)
if debug
# Print the chain of references for debugging
puts "Reference Chain:"
puts formula_or_cask_name(first_formula_or_cask, full_name: full_name)
references << referenced_formula_or_cask
references.each do |ref_formula_or_cask|
puts formula_or_cask_name(ref_formula_or_cask, full_name: full_name)
end
end
raise "Circular formula/cask reference encountered"
end
references << referenced_formula_or_cask
# Check the referenced formula/cask for a reference
next_referenced_formula_or_cask, next_references = resolve_livecheck_reference(
referenced_formula_or_cask,
first_formula_or_cask,
references,
full_name: full_name,
debug: debug,
)
# Returning references along with the final referenced formula/cask
# allows us to print the chain of references in the debug output
[
next_referenced_formula_or_cask || referenced_formula_or_cask,
next_references,
]
end
# Executes the livecheck logic for each formula/cask in the
# `formulae_and_casks_to_check` array and prints the results.
sig {
@ -139,6 +209,7 @@ module Homebrew
)
end
# rubocop:disable Metrics/BlockLength
formulae_checked = formulae_and_casks_to_check.map.with_index do |formula_or_cask, i|
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
@ -146,6 +217,9 @@ module Homebrew
use_full_name = full_name || ambiguous_names.include?(formula_or_cask)
name = formula_or_cask_name(formula_or_cask, full_name: use_full_name)
referenced_formula_or_cask, livecheck_references =
resolve_livecheck_reference(formula_or_cask, full_name: use_full_name, debug: debug)
if debug && i.positive?
puts <<~EOS
@ -156,7 +230,17 @@ module Homebrew
puts
end
skip_info = SkipConditions.skip_information(formula_or_cask, full_name: use_full_name, verbose: verbose)
# Check skip conditions for a referenced formula/cask
if referenced_formula_or_cask
skip_info = SkipConditions.referenced_skip_information(
referenced_formula_or_cask,
name,
full_name: use_full_name,
verbose: verbose,
)
end
skip_info ||= SkipConditions.skip_information(formula_or_cask, full_name: use_full_name, verbose: verbose)
if skip_info.present?
next skip_info if json
@ -188,7 +272,9 @@ module Homebrew
else
version_info = latest_version(
formula_or_cask,
json: json, full_name: use_full_name, verbose: verbose, debug: debug,
referenced_formula_or_cask: referenced_formula_or_cask,
livecheck_references: livecheck_references,
json: json, full_name: use_full_name, verbose: verbose, debug: debug
)
version_info[:latest] if version_info.present?
end
@ -262,6 +348,7 @@ module Homebrew
nil
end
end
# rubocop:enable Metrics/BlockLength
puts "No newer upstream versions." if newer_only && !has_a_newer_upstream_version && !debug && !json
@ -444,27 +531,40 @@ module Homebrew
# the version information. Returns nil if a latest version couldn't be found.
sig {
params(
formula_or_cask: T.any(Formula, Cask::Cask),
json: T::Boolean,
full_name: T::Boolean,
verbose: T::Boolean,
debug: T::Boolean,
formula_or_cask: T.any(Formula, Cask::Cask),
referenced_formula_or_cask: T.nilable(T.any(Formula, Cask::Cask)),
livecheck_references: T::Array[T.any(Formula, Cask::Cask)],
json: T::Boolean,
full_name: T::Boolean,
verbose: T::Boolean,
debug: T::Boolean,
).returns(T.nilable(Hash))
}
def latest_version(formula_or_cask, json: false, full_name: false, verbose: false, debug: false)
def latest_version(
formula_or_cask,
referenced_formula_or_cask: nil,
livecheck_references: [],
json: false, full_name: false, verbose: false, debug: false
)
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
has_livecheckable = formula_or_cask.livecheckable?
livecheck = formula_or_cask.livecheck
livecheck_url = livecheck.url
livecheck_regex = livecheck.regex
livecheck_strategy = livecheck.strategy
referenced_livecheck = referenced_formula_or_cask&.livecheck
livecheck_url_string = livecheck_url_to_string(livecheck_url, formula_or_cask)
livecheck_url = livecheck.url || referenced_livecheck&.url
livecheck_regex = livecheck.regex || referenced_livecheck&.regex
livecheck_strategy = livecheck.strategy || referenced_livecheck&.strategy
livecheck_strategy_block = livecheck.strategy_block || referenced_livecheck&.strategy_block
livecheck_url_string = livecheck_url_to_string(
livecheck_url,
referenced_formula_or_cask || formula_or_cask,
)
urls = [livecheck_url_string] if livecheck_url_string
urls ||= checkable_urls(formula_or_cask)
urls ||= checkable_urls(referenced_formula_or_cask || formula_or_cask)
if debug
if formula
@ -474,8 +574,18 @@ module Homebrew
puts "Cask: #{cask_name(formula_or_cask, full_name: full_name)}"
end
puts "Livecheckable?: #{has_livecheckable ? "Yes" : "No"}"
livecheck_references.each do |ref_formula_or_cask|
case ref_formula_or_cask
when Formula
puts "Formula Ref: #{formula_name(ref_formula_or_cask, full_name: full_name)}"
when Cask::Cask
puts "Cask Ref: #{cask_name(ref_formula_or_cask, full_name: full_name)}"
end
end
end
# rubocop:disable Metrics/BlockLength
urls.each_with_index do |original_url, i|
if debug
puts
@ -499,7 +609,7 @@ module Homebrew
livecheck_strategy: livecheck_strategy,
url_provided: livecheck_url.present?,
regex_provided: livecheck_regex.present?,
block_provided: livecheck.strategy_block.present?,
block_provided: livecheck_strategy_block.present?,
)
strategy = Strategy.from_symbol(livecheck_strategy) || strategies.first
strategy_name = livecheck_strategy_names[strategy]
@ -514,7 +624,7 @@ module Homebrew
end
if livecheck_strategy.present?
if livecheck_strategy == :page_match && (livecheck_regex.blank? && livecheck.strategy_block.blank?)
if livecheck_strategy == :page_match && (livecheck_regex.blank? && livecheck_strategy_block.blank?)
odebug "#{strategy_name} strategy requires a regex or block"
next
elsif livecheck_url.blank?
@ -529,7 +639,7 @@ module Homebrew
next if strategy.blank?
strategy_data = begin
strategy.find_versions(url, livecheck_regex, cask: cask, &livecheck.strategy_block)
strategy.find_versions(url, livecheck_regex, cask: cask, &livecheck_strategy_block)
rescue ArgumentError => e
raise unless e.message.include?("unknown keyword: cask")
@ -584,6 +694,17 @@ module Homebrew
if json && verbose
version_info[:meta] = {}
if livecheck_references.present?
version_info[:meta][:references] = livecheck_references.map do |ref_formula_or_cask|
case ref_formula_or_cask
when Formula
{ formula: formula_name(ref_formula_or_cask, full_name: full_name) }
when Cask::Cask
{ cask: cask_name(ref_formula_or_cask, full_name: full_name) }
end
end
end
version_info[:meta][:url] = {}
version_info[:meta][:url][:symbol] = livecheck_url if livecheck_url.is_a?(Symbol) && livecheck_url_string
version_info[:meta][:url][:original] = original_url
@ -599,8 +720,10 @@ module Homebrew
return version_info
end
# rubocop:enable Metrics/BlockLength
nil
end
end
# rubocop:enable Metrics/ModuleLength
end

View File

@ -201,6 +201,54 @@ module Homebrew
{}
end
# Skip conditions for formulae/casks referenced in a `livecheck` block
# are treated differently than normal. We only respect certain skip
# conditions (returning the related hash) and others are treated as
# errors.
sig {
params(
livecheck_formula_or_cask: T.any(Formula, Cask::Cask),
original_formula_or_cask_name: String,
full_name: T::Boolean,
verbose: T::Boolean,
).returns(T.nilable(Hash))
}
def referenced_skip_information(
livecheck_formula_or_cask,
original_formula_or_cask_name,
full_name: false,
verbose: false
)
skip_info = SkipConditions.skip_information(
livecheck_formula_or_cask,
full_name: full_name,
verbose: verbose,
)
return if skip_info.blank?
referenced_name = Livecheck.formula_or_cask_name(livecheck_formula_or_cask, full_name: full_name)
referenced_type = case livecheck_formula_or_cask
when Formula
:formula
when Cask::Cask
:cask
end
if skip_info[:status] != "error" &&
!(skip_info[:status] == "skipped" && livecheck_formula_or_cask.livecheck.skip?)
error_msg_end = if skip_info[:status] == "skipped"
"automatically skipped"
else
"skipped as #{skip_info[:status]}"
end
raise "Referenced #{referenced_type} (#{referenced_name}) is #{error_msg_end}"
end
skip_info[referenced_type] = original_formula_or_cask_name
skip_info
end
# Prints default livecheck output in relation to skip conditions.
sig { params(skip_hash: Hash).void }
def print_skip_information(skip_hash)

View File

@ -52,7 +52,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -59,7 +59,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -50,7 +50,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -19,7 +19,7 @@ module Homebrew
PRIORITY = 0
# The `Regexp` used to determine if the strategy applies to the URL.
URL_MATCH_REGEX = %r{^https?://.+/.+\.ya?ml$}i.freeze
URL_MATCH_REGEX = %r{^https?://.+/[^/]+\.ya?ml(?:\?[^/?]+)?$}i.freeze
# Whether the strategy can be applied to the provided URL.
#
@ -37,19 +37,24 @@ module Homebrew
sig {
params(
content: String,
block: T.nilable(T.proc.params(arg0: Hash).returns(String)),
block: T.nilable(T.proc.params(arg0: T::Hash[String, T.untyped]).returns(T.nilable(String))),
).returns(T.nilable(String))
}
def self.version_from_content(content, &block)
require "yaml"
return unless (yaml = YAML.safe_load(content))
yaml = YAML.safe_load(content)
return if yaml.blank?
if block
value = block.call(yaml)
return value if value.is_a?(String)
raise TypeError, "Return value of `strategy :electron_builder` block must be a string."
case (value = block.call(yaml))
when String
return value
when nil
return
else
raise TypeError, "Return value of `strategy :electron_builder` block must be a string."
end
end
yaml["version"]
@ -65,7 +70,7 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: Hash).returns(String)),
block: T.nilable(T.proc.params(arg0: T::Hash[String, T.untyped]).returns(T.nilable(String))),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -56,7 +56,7 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: Cask::Cask,
block: T.nilable(T.proc.params(arg0: T::Hash[String, Item]).returns(String)),
block: T.nilable(T.proc.params(arg0: T::Hash[String, Item]).returns(T.nilable(String))),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask:, &block)
@ -69,13 +69,14 @@ module Homebrew
versions = unversioned_cask_checker.all_versions.transform_values { |v| Item.new(bundle_version: v) }
if block
match = block.call(versions)
unless T.unsafe(match).is_a?(String)
case (value = block.call(versions))
when String
match_data[:matches][value] = Version.new(value)
when nil
return match_data
else
raise TypeError, "Return value of `strategy :extract_plist` block must be a string."
end
match_data[:matches][match] = Version.new(match) if match
elsif versions.any?
versions.each_value do |item|
version = item.bundle_version.nice_version

View File

@ -81,8 +81,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: T::Array[String])
.returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: T::Array[String]).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)
@ -102,9 +103,11 @@ module Homebrew
when String
match_data[:matches][value] = Version.new(value)
when Array
value.each do |tag|
value.compact.uniq.each do |tag|
match_data[:matches][tag] = Version.new(tag)
end
when nil
return match_data
else
raise TypeError, "Return value of `strategy :git` block must be a string or array of strings."
end

View File

@ -67,7 +67,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -55,7 +55,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -59,7 +59,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -52,7 +52,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -24,6 +24,9 @@ module Homebrew
# The `Regexp` used to determine if the strategy applies to the URL.
URL_MATCH_REGEX = %r{^https?://}i.freeze
# The header fields to check when a `strategy` block isn't provided.
DEFAULT_HEADERS_TO_CHECK = ["content-disposition", "location"].freeze
# Whether the strategy can be applied to the provided URL.
# The strategy will technically match any HTTP URL but is
# only usable with a `livecheck` block containing a regex
@ -40,8 +43,7 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: T::Hash[String, String])
.returns(T.any(T::Array[String], String))),
block: T.nilable(T.proc.params(arg0: T::Hash[String, String]).returns(T.nilable(String))),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)
@ -52,31 +54,34 @@ module Homebrew
# Merge the headers from all responses into one hash
merged_headers = headers.reduce(&:merge)
if block
match = yield merged_headers, regex
version = if block
case (value = block.call(merged_headers, regex))
when String
value
when nil
return match_data
else
raise TypeError, "Return value of `strategy :header_match` block must be a string."
end
else
match = nil
value = nil
DEFAULT_HEADERS_TO_CHECK.each do |header_name|
header_value = merged_headers[header_name]
next if header_value.blank?
if (filename = merged_headers["content-disposition"])
if regex
match ||= filename[regex, 1]
value = header_value[regex, 1]
else
v = Version.parse(filename, detected_from_url: true)
match ||= v.to_s unless v.null?
v = Version.parse(header_value, detected_from_url: true)
value = v.to_s unless v.null?
end
break if value.present?
end
if (location = merged_headers["location"])
if regex
match ||= location[regex, 1]
else
v = Version.parse(location, detected_from_url: true)
match ||= v.to_s unless v.null?
end
end
value
end
match_data[:matches][match] = Version.new(match) if match
match_data[:matches][version] = Version.new(version) if version
match_data
end

View File

@ -50,7 +50,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -46,7 +46,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -45,13 +45,24 @@ module Homebrew
# @param regex [Regexp] a regex used for matching versions in the
# content
# @return [Array]
sig {
params(
content: String,
regex: Regexp,
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Array[String])
}
def self.page_matches(content, regex, &block)
if block
case (value = block.call(content, regex))
when String
return [value]
when Array
return value
return value.compact.uniq
when nil
return []
else
raise TypeError, "Return value of `strategy :page_match` block must be a string or array of strings."
end
@ -61,10 +72,10 @@ module Homebrew
case match
when String
match
else
when Array
match.first
end
end.uniq
end.compact.uniq
end
# Checks the content at the URL for new versions, using the provided
@ -78,10 +89,12 @@ module Homebrew
sig {
params(
url: String,
regex: T.nilable(Regexp),
regex: Regexp,
cask: T.nilable(Cask::Cask),
provided_content: T.nilable(String),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, provided_content: nil, &block)

View File

@ -56,7 +56,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -62,7 +62,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -144,7 +144,7 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: Item).returns(String)),
block: T.nilable(T.proc.params(arg0: Item).returns(T.nilable(String))),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)
@ -156,19 +156,20 @@ module Homebrew
content = match_data.delete(:content)
if (item = item_from_content(content))
match = if block
value = block.call(item)
unless T.unsafe(value).is_a?(String)
version = if block
case (value = block.call(item))
when String
value
when nil
return match_data
else
raise TypeError, "Return value of `strategy :sparkle` block must be a string."
end
value
else
item.bundle_version&.nice_version
end
match_data[:matches][match] = Version.new(match) if match
match_data[:matches][version] = Version.new(version) if version
end
match_data

View File

@ -85,7 +85,9 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url, regex, cask: nil, &block)

View File

@ -14,7 +14,7 @@ module ReleaseNotes
.returns(String)
}
def generate_release_notes(start_ref, end_ref, markdown: false)
Utils.popen_read(
Utils.safe_popen_read(
"git", "-C", HOMEBREW_REPOSITORY, "log", "--pretty=format:'%s >> - %b%n'", "#{start_ref}..#{end_ref}"
).lines.map do |s|
matches = s.match(%r{.*Merge pull request #(?<pr>\d+) from (?<user>[^/]+)/[^>]*>> - (?<body>.*)})

View File

@ -50,6 +50,10 @@ module RuboCop
skip = find_every_method_call_by_name(livecheck_node, :skip).first
return if skip.present?
formula_node = find_every_method_call_by_name(livecheck_node, :formula).first
cask_node = find_every_method_call_by_name(livecheck_node, :cask).first
return if formula_node.present? || cask_node.present?
livecheck_url = find_every_method_call_by_name(livecheck_node, :url).first
return if livecheck_url.present?

View File

@ -19,7 +19,9 @@ module Homebrew
raise "#{query} is not a valid regex."
end
def search_descriptions(string_or_regex)
def search_descriptions(string_or_regex, args)
return if args.cask?
ohai "Formulae"
CacheStoreDatabase.use(:descriptions) do |db|
cache_store = DescriptionCacheStore.new(db)

View File

@ -1869,6 +1869,7 @@ class RuboCop::AST::ProcessedSource
def preceding_line(token); end
def raw_source; end
def ruby_version; end
def sorted_tokens; end
def start_with?(string); end
def tokens; end
def tokens_within(range_or_node); end
@ -1882,7 +1883,6 @@ class RuboCop::AST::ProcessedSource
def last_token_index(range_or_node); end
def parse(source, ruby_version); end
def parser_class(ruby_version); end
def sorted_tokens; end
def source_range(range_or_node); end
def tokenize(parser); end

View File

@ -3038,6 +3038,8 @@ module Bootsnap::LoadPathCache::ChangeObserver::ArrayMixin
def []=(*args, &block); end
def append(*entries); end
def clear(*args, &block); end
def collect!(*args, &block); end
@ -3064,6 +3066,8 @@ module Bootsnap::LoadPathCache::ChangeObserver::ArrayMixin
def pop(*args, &block); end
def prepend(*entries); end
def push(*entries); end
def reject!(*args, &block); end
@ -3228,11 +3232,6 @@ module Bootsnap
def self.setup(cache_dir:, development_mode: T.unsafe(nil), load_path_cache: T.unsafe(nil), autoload_paths_cache: T.unsafe(nil), disable_trace: T.unsafe(nil), compile_cache_iseq: T.unsafe(nil), compile_cache_yaml: T.unsafe(nil)); end
end
module BottleAPI
extend ::T::Private::Methods::MethodHooks
extend ::T::Private::Methods::SingletonMethodHooks
end
class BottleSpecification
extend ::T::Private::Methods::MethodHooks
extend ::T::Private::Methods::SingletonMethodHooks
@ -9658,6 +9657,31 @@ module Homebrew
MIN_PORT = ::T.let(nil, ::T.untyped)
end
module Homebrew::API::Analytics
extend ::T::Private::Methods::SingletonMethodHooks
end
module Homebrew::API::Bottle
extend ::T::Private::Methods::SingletonMethodHooks
end
module Homebrew::API::Cask
extend ::T::Private::Methods::SingletonMethodHooks
end
module Homebrew::API::Formula
extend ::T::Private::Methods::SingletonMethodHooks
end
module Homebrew::API::Versions
extend ::T::Private::Methods::SingletonMethodHooks
end
module Homebrew::API
extend ::T::Private::Methods::MethodHooks
extend ::T::Private::Methods::SingletonMethodHooks
end
module Homebrew::Assertions
include ::Minitest::Assertions
def assert_include(*args); end
@ -9775,6 +9799,8 @@ module Homebrew::EnvConfig
def self.display_install_times?(); end
def self.docker_registry_token(); end
def self.editor(); end
def self.fail_log_lines(); end

View File

@ -1,11 +1,9 @@
# typed: false
# frozen_string_literal: true
describe BottleAPI do
before do
ENV["HOMEBREW_JSON_CORE"] = "1"
end
require "api"
describe Homebrew::API::Bottle do
let(:bottle_json) {
<<~EOS
{
@ -28,14 +26,6 @@ describe BottleAPI do
EOS
}
let(:bottle_hash) { JSON.parse(bottle_json) }
let(:versions_json) {
<<~EOS
{
"foo":{"version":"1.2.3","revision":0},
"bar":{"version":"1.2","revision":4}
}
EOS
}
def mock_curl_output(stdout: "", success: true)
curl_output = OpenStruct.new(stdout: stdout, success?: success)
@ -51,7 +41,7 @@ describe BottleAPI do
it "raises an error if the formula does not exist" do
mock_curl_output success: false
expect { described_class.fetch("bar") }.to raise_error(ArgumentError, /No JSON file found/)
expect { described_class.fetch("bar") }.to raise_error(ArgumentError, /No file found/)
end
it "raises an error if the bottle JSON is invalid" do
@ -60,40 +50,21 @@ describe BottleAPI do
end
end
describe "::latest_pkg_version" do
it "returns the expected `PkgVersion` when the revision is 0" do
mock_curl_output stdout: versions_json
pkg_version = described_class.latest_pkg_version("foo")
expect(pkg_version.to_s).to eq "1.2.3"
end
it "returns the expected `PkgVersion` when the revision is not 0" do
mock_curl_output stdout: versions_json
pkg_version = described_class.latest_pkg_version("bar")
expect(pkg_version.to_s).to eq "1.2_4"
end
it "returns `nil` when the formula is not in the JSON file" do
mock_curl_output stdout: versions_json
pkg_version = described_class.latest_pkg_version("baz")
expect(pkg_version).to be_nil
end
end
describe "::bottle_available?" do
describe "::available?" do
it "returns `true` if `fetch` succeeds" do
allow(described_class).to receive(:fetch)
expect(described_class.bottle_available?("foo")).to eq true
expect(described_class.available?("foo")).to eq true
end
it "returns `false` if `fetch` fails" do
allow(described_class).to receive(:fetch).and_raise ArgumentError
expect(described_class.bottle_available?("foo")).to eq false
expect(described_class.available?("foo")).to eq false
end
end
describe "::fetch_bottles" do
before do
ENV["HOMEBREW_JSON_CORE"] = "1"
allow(described_class).to receive(:fetch).and_return bottle_hash
end

View File

@ -0,0 +1,55 @@
# typed: false
# frozen_string_literal: true
require "api"
describe Homebrew::API::Versions do
let(:versions_formulae_json) {
<<~EOS
{
"foo":{"version":"1.2.3","revision":0},
"bar":{"version":"1.2","revision":4}
}
EOS
}
let(:versions_casks_json) { '{"foo":{"version":"1.2.3"}}' }
def mock_curl_output(stdout: "", success: true)
curl_output = OpenStruct.new(stdout: stdout, success?: success)
allow(Utils::Curl).to receive(:curl_output).and_return curl_output
end
describe "::latest_formula_version" do
it "returns the expected `PkgVersion` when the revision is 0" do
mock_curl_output stdout: versions_formulae_json
pkg_version = described_class.latest_formula_version("foo")
expect(pkg_version.to_s).to eq "1.2.3"
end
it "returns the expected `PkgVersion` when the revision is not 0" do
mock_curl_output stdout: versions_formulae_json
pkg_version = described_class.latest_formula_version("bar")
expect(pkg_version.to_s).to eq "1.2_4"
end
it "returns `nil` when the formula is not in the JSON file" do
mock_curl_output stdout: versions_formulae_json
pkg_version = described_class.latest_formula_version("baz")
expect(pkg_version).to be_nil
end
end
describe "::latest_cask_version" do
it "returns the expected `Version`" do
mock_curl_output stdout: versions_casks_json
version = described_class.latest_cask_version("foo")
expect(version.to_s).to eq "1.2.3"
end
it "returns `nil` when the cask is not in the JSON file" do
mock_curl_output stdout: versions_casks_json
version = described_class.latest_cask_version("bar")
expect(version).to be_nil
end
end
end

View File

@ -0,0 +1,33 @@
# typed: false
# frozen_string_literal: true
require "api"
describe Homebrew::API do
let(:text) { "foo" }
let(:json) { '{"foo":"bar"}' }
let(:json_hash) { JSON.parse(json) }
def mock_curl_output(stdout: "", success: true)
curl_output = OpenStruct.new(stdout: stdout, success?: success)
allow(Utils::Curl).to receive(:curl_output).and_return curl_output
end
describe "::fetch" do
it "fetches a JSON file" do
mock_curl_output stdout: json
fetched_json = described_class.fetch("foo.json")
expect(fetched_json).to eq json_hash
end
it "raises an error if the file does not exist" do
mock_curl_output success: false
expect { described_class.fetch("bar.txt") }.to raise_error(ArgumentError, /No file found/)
end
it "raises an error if the JSON file is invalid" do
mock_curl_output stdout: text
expect { described_class.fetch("baz.txt") }.to raise_error(ArgumentError, /Invalid JSON file/)
end
end
end

View File

@ -223,12 +223,16 @@ describe Homebrew::CLI::NamedArgs do
(HOMEBREW_CELLAR/"foo/1.0").mkpath
(HOMEBREW_CELLAR/"foo/2.0").mkpath
(HOMEBREW_CELLAR/"bar/1.0").mkpath
(HOMEBREW_CELLAR/"baz/HEAD-1").mkpath
head2 = HOMEBREW_CELLAR/"baz/HEAD-2"
head2.mkpath
(head2/"INSTALL_RECEIPT.json").write (TEST_FIXTURE_DIR/"receipt.json").read
end
it "resolves the latest kegs with #resolve_latest_keg" do
latest_kegs = described_class.new("foo", "bar").to_latest_kegs
expect(latest_kegs.map(&:name)).to eq ["foo", "bar"]
expect(latest_kegs.map { |k| k.version.version.to_s }).to eq ["2.0", "1.0"]
latest_kegs = described_class.new("foo", "bar", "baz").to_latest_kegs
expect(latest_kegs.map(&:name)).to eq ["foo", "bar", "baz"]
expect(latest_kegs.map { |k| k.version.version.to_s }).to eq ["2.0", "1.0", "HEAD-2"]
end
it "when there are no matching kegs returns an empty array" do

View File

@ -223,7 +223,7 @@ describe FormulaInstaller do
it "works if plist is set" do
formula = Testball.new
path = formula.plist_path
formula.prefix.mkpath
formula.opt_prefix.mkpath
expect(formula).to receive(:plist).twice.and_return("PLIST")
expect(formula).to receive(:plist_path).and_call_original
@ -241,7 +241,7 @@ describe FormulaInstaller do
plist_path = formula.plist_path
service_path = formula.systemd_service_path
service = Homebrew::Service.new(formula)
formula.prefix.mkpath
formula.opt_prefix.mkpath
expect(formula).to receive(:plist).and_return(nil)
expect(formula).to receive(:service?).exactly(3).and_return(true)
@ -264,7 +264,7 @@ describe FormulaInstaller do
it "returns without definition" do
formula = Testball.new
path = formula.plist_path
formula.prefix.mkpath
formula.opt_prefix.mkpath
expect(formula).to receive(:plist).and_return(nil)
expect(formula).to receive(:service?).exactly(3).and_return(nil)
@ -282,7 +282,7 @@ describe FormulaInstaller do
it "errors with duplicate definition" do
formula = Testball.new
path = formula.plist_path
formula.prefix.mkpath
formula.opt_prefix.mkpath
expect(formula).to receive(:plist).and_return("plist")
expect(formula).to receive(:service?).and_return(true)

View File

@ -701,31 +701,52 @@ describe Formula do
end
end
specify "#service" do
f = formula do
url "https://brew.sh/test-1.0.tbz"
end
f.class.service do
run [opt_bin/"beanstalkd"]
run_type :immediate
error_log_path var/"log/beanstalkd.error.log"
log_path var/"log/beanstalkd.log"
working_dir var
keep_alive true
end
expect(f.service).not_to eq(nil)
end
specify "service uses simple run" do
f = formula do
url "https://brew.sh/test-1.0.tbz"
service do
run opt_bin/"beanstalkd"
describe "#service" do
specify "no service defined" do
f = formula do
url "https://brew.sh/test-1.0.tbz"
end
expect(f.service).to eq(nil)
end
expect(f.service).not_to eq(nil)
specify "service complicated" do
f = formula do
url "https://brew.sh/test-1.0.tbz"
end
f.class.service do
run [opt_bin/"beanstalkd"]
run_type :immediate
error_log_path var/"log/beanstalkd.error.log"
log_path var/"log/beanstalkd.log"
working_dir var
keep_alive true
end
expect(f.service).not_to eq(nil)
end
specify "service uses simple run" do
f = formula do
url "https://brew.sh/test-1.0.tbz"
service do
run opt_bin/"beanstalkd"
end
end
expect(f.service).not_to eq(nil)
end
specify "service helpers return data" do
f = formula do
url "https://brew.sh/test-1.0.tbz"
end
expect(f.plist_name).to eq("homebrew.mxcl.formula_name")
expect(f.service_name).to eq("homebrew.formula_name")
expect(f.plist_path).to eq(HOMEBREW_PREFIX/"opt/formula_name/homebrew.mxcl.formula_name.plist")
expect(f.systemd_service_path).to eq(HOMEBREW_PREFIX/"opt/formula_name/homebrew.formula_name.service")
end
end
specify "dependencies" do

View File

@ -44,6 +44,15 @@ describe Homebrew::Livecheck do
RUBY
end
describe "::resolve_livecheck_reference" do
context "when a formula/cask has a livecheck block without formula/cask methods" do
it "returns [nil, []]" do
expect(livecheck.resolve_livecheck_reference(f)).to eq([nil, []])
expect(livecheck.resolve_livecheck_reference(c)).to eq([nil, []])
end
end
end
describe "::formula_name" do
it "returns the name of the formula" do
expect(livecheck.formula_name(f)).to eq("test")

View File

@ -264,7 +264,7 @@ describe Homebrew::Livecheck::SkipConditions do
}
end
describe "::skip_conditions" do
describe "::skip_information" do
context "when a formula without a livecheckable is deprecated" do
it "skips" do
expect(skip_conditions.skip_information(formulae[:deprecated]))
@ -293,21 +293,21 @@ describe Homebrew::Livecheck::SkipConditions do
end
end
context "when a formula has a GitHub Gist stable URL" do
context "when a formula without a livecheckable has a GitHub Gist stable URL" do
it "skips" do
expect(skip_conditions.skip_information(formulae[:gist]))
.to eq(status_hashes[:formula][:gist])
end
end
context "when a formula has a Google Code Archive stable URL" do
context "when a formula without a livecheckable has a Google Code Archive stable URL" do
it "skips" do
expect(skip_conditions.skip_information(formulae[:google_code_archive]))
.to eq(status_hashes[:formula][:google_code_archive])
end
end
context "when a formula has an Internet Archive stable URL" do
context "when a formula without a livecheckable has an Internet Archive stable URL" do
it "skips" do
expect(skip_conditions.skip_information(formulae[:internet_archive]))
.to eq(status_hashes[:formula][:internet_archive])
@ -364,6 +364,108 @@ describe Homebrew::Livecheck::SkipConditions do
end
end
describe "::referenced_skip_information" do
let(:original_name) { "original" }
context "when a formula without a livecheckable is deprecated" do
it "errors" do
expect { skip_conditions.referenced_skip_information(formulae[:deprecated], original_name) }
.to raise_error(RuntimeError, "Referenced formula (test_deprecated) is skipped as deprecated")
end
end
context "when a formula without a livecheckable is disabled" do
it "errors" do
expect { skip_conditions.referenced_skip_information(formulae[:disabled], original_name) }
.to raise_error(RuntimeError, "Referenced formula (test_disabled) is skipped as disabled")
end
end
context "when a formula without a livecheckable is versioned" do
it "errors" do
expect { skip_conditions.referenced_skip_information(formulae[:versioned], original_name) }
.to raise_error(RuntimeError, "Referenced formula (test@0.0.1) is skipped as versioned")
end
end
context "when a formula is HEAD-only and not installed" do
it "skips " do
expect(skip_conditions.referenced_skip_information(formulae[:head_only], original_name))
.to eq(status_hashes[:formula][:head_only].merge({ formula: original_name }))
end
end
context "when a formula without a livecheckable has a GitHub Gist stable URL" do
it "errors" do
expect { skip_conditions.referenced_skip_information(formulae[:gist], original_name) }
.to raise_error(RuntimeError, "Referenced formula (test_gist) is automatically skipped")
end
end
context "when a formula without a livecheckable has a Google Code Archive stable URL" do
it "errors" do
expect { skip_conditions.referenced_skip_information(formulae[:google_code_archive], original_name) }
.to raise_error(RuntimeError, "Referenced formula (test_google_code_archive) is automatically skipped")
end
end
context "when a formula without a livecheckable has an Internet Archive stable URL" do
it "errors" do
expect { skip_conditions.referenced_skip_information(formulae[:internet_archive], original_name) }
.to raise_error(RuntimeError, "Referenced formula (test_internet_archive) is automatically skipped")
end
end
context "when a formula has a `livecheck` block containing `skip`" do
it "skips" do
expect(skip_conditions.referenced_skip_information(formulae[:skip], original_name))
.to eq(status_hashes[:formula][:skip].merge({ formula: original_name }))
expect(skip_conditions.referenced_skip_information(formulae[:skip_with_message], original_name))
.to eq(status_hashes[:formula][:skip_with_message].merge({ formula: original_name }))
end
end
context "when a cask without a livecheckable is discontinued" do
it "errors" do
expect { skip_conditions.referenced_skip_information(casks[:discontinued], original_name) }
.to raise_error(RuntimeError, "Referenced cask (test_discontinued) is skipped as discontinued")
end
end
context "when a cask without a livecheckable has `version :latest`" do
it "errors" do
expect { skip_conditions.referenced_skip_information(casks[:latest], original_name) }
.to raise_error(RuntimeError, "Referenced cask (test_latest) is skipped as latest")
end
end
context "when a cask without a livecheckable has an unversioned URL" do
it "errors" do
expect { skip_conditions.referenced_skip_information(casks[:unversioned], original_name) }
.to raise_error(RuntimeError, "Referenced cask (test_unversioned) is skipped as unversioned")
end
end
context "when a cask has a `livecheck` block containing `skip`" do
it "skips" do
expect(skip_conditions.referenced_skip_information(casks[:skip], original_name))
.to eq(status_hashes[:cask][:skip].merge({ cask: original_name }))
expect(skip_conditions.referenced_skip_information(casks[:skip_with_message], original_name))
.to eq(status_hashes[:cask][:skip_with_message].merge({ cask: original_name }))
end
end
it "returns an empty hash for a non-skippable formula" do
expect(skip_conditions.referenced_skip_information(formulae[:basic], original_name)).to eq(nil)
end
it "returns an empty hash for a non-skippable cask" do
expect(skip_conditions.referenced_skip_information(casks[:basic], original_name)).to eq(nil)
end
end
describe "::print_skip_information" do
context "when a formula without a livecheckable is deprecated" do
it "prints skip information" do

View File

@ -54,5 +54,14 @@ describe Homebrew::Livecheck::Strategy::ElectronBuilder do
expect(version).to eq "1.2.4"
end
it "allows a nil return from a strategy block" do
expect(electron_builder.version_from_content(electron_builder_yaml) { next }).to eq(nil)
end
it "errors on an invalid return type from a strategy block" do
expect { electron_builder.version_from_content(electron_builder_yaml) { 123 } }
.to raise_error(TypeError, "Return value of `strategy :electron_builder` block must be a string.")
end
end
end

View File

@ -72,9 +72,13 @@ describe Homebrew::Livecheck::Strategy::PageMatch do
end
it "finds matching text in page content using a strategy block" do
expect(page_match.page_matches(page_content, regex) { |content| content.scan(regex).map(&:first).uniq })
expect(page_match.page_matches(page_content, regex) { |content, regex| content.scan(regex).map(&:first).uniq })
.to eq(page_content_matches)
end
it "allows a nil return from a strategy block" do
expect(page_match.page_matches(page_content, regex) { next }).to eq([])
end
end
describe "::find_versions?" do

View File

@ -28,6 +28,40 @@ describe Livecheck do
end
let(:livecheckable_c) { described_class.new(c) }
describe "#formula" do
it "returns nil if not set" do
expect(livecheckable_f.formula).to be nil
end
it "returns the String if set" do
livecheckable_f.formula("other-formula")
expect(livecheckable_f.formula).to eq("other-formula")
end
it "raises a TypeError if the argument isn't a String" do
expect {
livecheckable_f.formula(123)
}.to raise_error(TypeError, "Livecheck#formula expects a String")
end
end
describe "#cask" do
it "returns nil if not set" do
expect(livecheckable_c.cask).to be nil
end
it "returns the String if set" do
livecheckable_c.cask("other-cask")
expect(livecheckable_c.cask).to eq("other-cask")
end
it "raises a TypeError if the argument isn't a String" do
expect {
livecheckable_c.cask(123)
}.to raise_error(TypeError, "Livecheck#cask expects a String")
end
end
describe "#regex" do
it "returns nil if not set" do
expect(livecheckable_f.regex).to be nil
@ -128,6 +162,8 @@ describe Livecheck do
it "returns a Hash of all instance variables" do
expect(livecheckable_f.to_hash).to eq(
{
"cask" => nil,
"formula" => nil,
"regex" => nil,
"skip" => false,
"skip_msg" => nil,

View File

@ -15,6 +15,7 @@
"bin/foo"
],
"time": 1403827774,
"source_modified_time": 1628303333,
"HEAD": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
"alias_path": "/usr/local/Library/Taps/homebrew/homebrew-core/Aliases/test-formula",
"stdlib": "libcxx",

View File

@ -4,6 +4,7 @@
require "context"
require "erb"
require "settings"
require "api"
module Utils
# Helper module for fetching and reporting analytics data.
@ -129,7 +130,12 @@ module Utils
def output(args:, filter: nil)
days = args.days || "30"
category = args.category || "install"
json = formulae_brew_sh_json("analytics/#{category}/#{days}d.json")
begin
json = Homebrew::API::Analytics.fetch category, days
rescue ArgumentError
# Ignore failed API requests
return
end
return if json.blank? || json["items"].blank?
os_version = category == "os-version"
@ -182,17 +188,27 @@ module Utils
end
def formula_output(f, args:)
json = formulae_brew_sh_json("#{formula_path}/#{f}.json")
return if Homebrew::EnvConfig.no_analytics? || Homebrew::EnvConfig.no_github_api?
json = Homebrew::API::Formula.fetch f.name
return if json.blank? || json["analytics"].blank?
get_analytics(json, args: args)
rescue ArgumentError
# Ignore failed API requests
nil
end
def cask_output(cask, args:)
json = formulae_brew_sh_json("#{cask_path}/#{cask}.json")
return if Homebrew::EnvConfig.no_analytics? || Homebrew::EnvConfig.no_github_api?
json = Homebrew::API::Cask.fetch cask.token
return if json.blank? || json["analytics"].blank?
get_analytics(json, args: args)
rescue ArgumentError
# Ignore failed API requests
nil
end
sig { returns(String) }
@ -317,18 +333,6 @@ module Utils
Homebrew::Settings.read(key) == "true"
end
def formulae_brew_sh_json(endpoint)
return if Homebrew::EnvConfig.no_analytics? || Homebrew::EnvConfig.no_github_api?
output, = curl_output("--max-time", "5",
"https://formulae.brew.sh/api/#{endpoint}")
return if output.blank?
JSON.parse(output)
rescue JSON::ParserError
nil
end
def format_count(count)
count.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
end
@ -336,23 +340,6 @@ module Utils
def format_percent(percent)
format("%<percent>.2f", percent: percent)
end
sig { returns(String) }
def formula_path
"formula"
end
alias generic_formula_path formula_path
sig { returns(String) }
def analytics_path
"analytics"
end
alias generic_analytics_path analytics_path
sig { returns(String) }
def cask_path
"cask"
end
end
end
end

View File

@ -15,8 +15,8 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.10/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-14/2.6.0-static/msgpack-1.4.2"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.4.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-14/2.6.0-static/bootsnap-1.7.5"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.7.5/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-14/2.6.0-static/bootsnap-1.7.7"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.7.7/lib"
$:.unshift "#{path}/"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-14/2.6.0-static/byebug-11.1.3"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/byebug-11.1.3/lib"
@ -78,7 +78,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.9030/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-sorbet-1.8.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec_junit_formatter-0.4.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.8.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.9.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.11.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-2.0.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.18.4/lib"

View File

@ -1479,6 +1479,8 @@ _brew_outdated() {
--fetch-HEAD
--formula
--greedy
--greedy-auto-updates
--greedy-latest
--help
--json
--quiet
@ -2333,6 +2335,8 @@ _brew_upgrade() {
--force-bottle
--formula
--greedy
--greedy-auto-updates
--greedy-latest
--help
--ignore-pinned
--input-methoddir

View File

@ -1029,7 +1029,9 @@ __fish_brew_complete_arg 'outdated' -l cask -d 'List only outdated casks'
__fish_brew_complete_arg 'outdated' -l debug -d 'Display any debugging information'
__fish_brew_complete_arg 'outdated' -l fetch-HEAD -d 'Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository\'s HEAD will only be checked for updates when a new stable or development version has been released'
__fish_brew_complete_arg 'outdated' -l formula -d 'List only outdated formulae'
__fish_brew_complete_arg 'outdated' -l greedy -d 'Print outdated casks with `auto_updates` or `version :latest`'
__fish_brew_complete_arg 'outdated' -l greedy -d 'Print outdated casks with `auto_updates true` or `version :latest`'
__fish_brew_complete_arg 'outdated' -l greedy-auto-updates -d 'Print outdated casks including those with `auto_updates true`'
__fish_brew_complete_arg 'outdated' -l greedy-latest -d 'Print outdated casks including those with `version :latest`'
__fish_brew_complete_arg 'outdated' -l help -d 'Show this message'
__fish_brew_complete_arg 'outdated' -l json -d 'Print output in JSON format. There are two versions: `v1` and `v2`. `v1` is deprecated and is currently the default if no version is specified. `v2` prints outdated formulae and casks. '
__fish_brew_complete_arg 'outdated' -l quiet -d 'List only the names of outdated kegs (takes precedence over `--verbose`)'
@ -1530,6 +1532,8 @@ __fish_brew_complete_arg 'upgrade' -l force -d 'Install formulae without checkin
__fish_brew_complete_arg 'upgrade' -l force-bottle -d 'Install from a bottle if it exists for the current or newest version of macOS, even if it would not normally be used for installation'
__fish_brew_complete_arg 'upgrade' -l formula -d 'Treat all named arguments as formulae. If no named arguments are specified, upgrade only outdated formulae'
__fish_brew_complete_arg 'upgrade' -l greedy -d 'Also include casks with `auto_updates true` or `version :latest`'
__fish_brew_complete_arg 'upgrade' -l greedy-auto-updates -d 'Also include casks with `auto_updates true`'
__fish_brew_complete_arg 'upgrade' -l greedy-latest -d 'Also include casks with `version :latest`'
__fish_brew_complete_arg 'upgrade' -l help -d 'Show this message'
__fish_brew_complete_arg 'upgrade' -l ignore-pinned -d 'Set a successful exit status even if pinned formulae are not upgraded'
__fish_brew_complete_arg 'upgrade' -l input-methoddir -d 'Target location for Input Methods (default: `~/Library/Input Methods`)'

View File

@ -1260,7 +1260,9 @@ _brew_outdated() {
_arguments \
'--debug[Display any debugging information]' \
'--fetch-HEAD[Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository'\''s HEAD will only be checked for updates when a new stable or development version has been released]' \
'--greedy[Print outdated casks with `auto_updates` or `version :latest`]' \
'--greedy[Print outdated casks with `auto_updates true` or `version :latest`]' \
'--greedy-auto-updates[Print outdated casks including those with `auto_updates true`]' \
'--greedy-latest[Print outdated casks including those with `version :latest`]' \
'--help[Show this message]' \
'(--quiet --verbose)--json[Print output in JSON format. There are two versions: `v1` and `v2`. `v1` is deprecated and is currently the default if no version is specified. `v2` prints outdated formulae and casks. ]' \
'(--verbose --json)--quiet[List only the names of outdated kegs (takes precedence over `--verbose`)]' \
@ -1874,6 +1876,8 @@ _brew_upgrade() {
'--force[Install formulae without checking for previously installed keg-only or non-migrated versions. When installing casks, overwrite existing files (binaries and symlinks are excluded, unless originally from the same cask)]' \
'(--cask --build-from-source)--force-bottle[Install from a bottle if it exists for the current or newest version of macOS, even if it would not normally be used for installation]' \
'(--formula)--greedy[Also include casks with `auto_updates true` or `version :latest`]' \
'(--formula)--greedy-auto-updates[Also include casks with `auto_updates true`]' \
'(--formula)--greedy-latest[Also include casks with `version :latest`]' \
'--help[Show this message]' \
'(--cask)--ignore-pinned[Set a successful exit status even if pinned formulae are not upgraded]' \
'(--formula)--input-methoddir[Target location for Input Methods (default: `~/Library/Input Methods`)]' \
@ -1896,7 +1900,7 @@ _brew_upgrade() {
'(--formula)--vst-plugindir[Target location for VST Plugins (default: `~/Library/Audio/Plug-Ins/VST`)]' \
'(--formula)--vst3-plugindir[Target location for VST3 Plugins (default: `~/Library/Audio/Plug-Ins/VST3`)]' \
- outdated_formula \
'(--casks --binaries --require-sha --quarantine --skip-cask-deps --greedy --appdir --colorpickerdir --prefpanedir --qlplugindir --mdimporterdir --dictionarydir --fontdir --servicedir --input-methoddir --internet-plugindir --audio-unit-plugindir --vst-plugindir --vst3-plugindir --screen-saverdir --language)--formula[Treat all named arguments as formulae. If no named arguments are specified, upgrade only outdated formulae]' \
'(--casks --binaries --require-sha --quarantine --skip-cask-deps --greedy --greedy-latest --greedy-auto-updates --appdir --colorpickerdir --prefpanedir --qlplugindir --mdimporterdir --dictionarydir --fontdir --servicedir --input-methoddir --internet-plugindir --audio-unit-plugindir --vst-plugindir --vst3-plugindir --screen-saverdir --language)--formula[Treat all named arguments as formulae. If no named arguments are specified, upgrade only outdated formulae]' \
'*::outdated_formula:__brew_outdated_formulae' \
- outdated_cask \
'(--formulae --build-from-source --interactive --force-bottle --fetch-HEAD --ignore-pinned --keep-tmp --display-times)--cask[Treat all named arguments as casks. If no named arguments are specified, upgrade only outdated casks]' \

View File

@ -96,6 +96,18 @@ end
If tags include the software name as a prefix (e.g. `example-1.2.3`), it's easy to modify the regex accordingly: `/^example[._-]v?(\d+(?:\.\d+)+)$/i`
### Referenced formula/cask
A formula/cask can use the same check as another by using `formula` or `cask`.
```ruby
livecheck do
formula "another-formula"
end
```
The referenced formula/cask should be in the same tap, as a reference to a formula/cask from another tap will generate an error if the user doesn't already have it tapped.
### `strategy` blocks
If the upstream version format needs to be manipulated to match the formula/cask format, a `strategy` block can be used instead of a `regex`.

View File

@ -110,8 +110,6 @@ Youre now at a new prompt with the tarball extracted to a temporary sandbox.
Check the packages `README`. Does the package install with `./configure`, `cmake`, or something else? Delete the commented out `cmake` lines if the package uses `./configure`.
If no compilation is involved and there are no `:build` dependencies, add the line `bottle :unneeded` since bottles are unnecessary in this case. Otherwise, a `bottle` block will be added by Homebrew's CI upon merging the formula's pull-request.
### Check for dependencies
The `README` probably tells you about dependencies and Homebrew or macOS probably already has them. You can check for Homebrew dependencies with `brew search`. Some common dependencies that macOS comes with:
@ -255,7 +253,7 @@ For Python formulae, running `brew update-python-resources <formula>` will autom
### Install the formula
```sh
brew install --verbose --debug foo
brew install --build-from-source --verbose --debug foo
```
`--debug` will ask you to open an interactive shell if the build fails so you can try to figure out what went wrong.

View File

@ -26,7 +26,7 @@ GEM
ffi (>= 1.15.0)
eventmachine (1.2.7)
execjs (2.8.1)
faraday (1.5.1)
faraday (1.7.0)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@ -34,6 +34,7 @@ GEM
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.1)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
multipart-post (>= 1.2, < 3)
ruby2_keywords (>= 0.0.4)
faraday-em_http (1.0.0)
@ -43,10 +44,11 @@ GEM
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
ffi (1.15.3)
forwardable-extended (2.6.0)
gemoji (3.0.1)
github-pages (215)
github-pages (218)
github-pages-health-check (= 1.17.2)
jekyll (= 3.9.0)
jekyll-avatar (= 0.7.0)
@ -67,19 +69,19 @@ GEM
jekyll-seo-tag (= 2.7.1)
jekyll-sitemap (= 1.4.0)
jekyll-swiss (= 1.0.0)
jekyll-theme-architect (= 0.1.1)
jekyll-theme-cayman (= 0.1.1)
jekyll-theme-dinky (= 0.1.1)
jekyll-theme-hacker (= 0.1.2)
jekyll-theme-leap-day (= 0.1.1)
jekyll-theme-merlot (= 0.1.1)
jekyll-theme-midnight (= 0.1.1)
jekyll-theme-minimal (= 0.1.1)
jekyll-theme-modernist (= 0.1.1)
jekyll-theme-primer (= 0.5.4)
jekyll-theme-slate (= 0.1.1)
jekyll-theme-tactile (= 0.1.1)
jekyll-theme-time-machine (= 0.1.1)
jekyll-theme-architect (= 0.2.0)
jekyll-theme-cayman (= 0.2.0)
jekyll-theme-dinky (= 0.2.0)
jekyll-theme-hacker (= 0.2.0)
jekyll-theme-leap-day (= 0.2.0)
jekyll-theme-merlot (= 0.2.0)
jekyll-theme-midnight (= 0.2.0)
jekyll-theme-minimal (= 0.2.0)
jekyll-theme-modernist (= 0.2.0)
jekyll-theme-primer (= 0.6.0)
jekyll-theme-slate (= 0.2.0)
jekyll-theme-tactile (= 0.2.0)
jekyll-theme-time-machine (= 0.2.0)
jekyll-titles-from-headings (= 0.5.3)
jemoji (= 0.12.0)
kramdown (= 2.3.1)
@ -168,45 +170,45 @@ GEM
jekyll-sitemap (1.4.0)
jekyll (>= 3.7, < 5.0)
jekyll-swiss (1.0.0)
jekyll-theme-architect (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-cayman (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-dinky (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-hacker (0.1.2)
jekyll-theme-architect (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-leap-day (0.1.1)
jekyll (~> 3.5)
jekyll-theme-cayman (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-merlot (0.1.1)
jekyll (~> 3.5)
jekyll-theme-dinky (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-midnight (0.1.1)
jekyll (~> 3.5)
jekyll-theme-hacker (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-minimal (0.1.1)
jekyll (~> 3.5)
jekyll-theme-leap-day (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-modernist (0.1.1)
jekyll (~> 3.5)
jekyll-theme-merlot (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-primer (0.5.4)
jekyll-theme-midnight (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-minimal (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-modernist (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-primer (0.6.0)
jekyll (> 3.5, < 5.0)
jekyll-github-metadata (~> 2.9)
jekyll-seo-tag (~> 2.0)
jekyll-theme-slate (0.1.1)
jekyll (~> 3.5)
jekyll-theme-slate (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-tactile (0.1.1)
jekyll (~> 3.5)
jekyll-theme-tactile (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-time-machine (0.1.1)
jekyll (~> 3.5)
jekyll-theme-time-machine (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-titles-from-headings (0.5.3)
jekyll (>= 3.3, < 5.0)
@ -221,19 +223,19 @@ GEM
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3)
listen (3.5.1)
listen (3.6.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
mini_portile2 (2.5.3)
mini_portile2 (2.6.1)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.14.4)
multipart-post (2.1.1)
nokogiri (1.11.7)
mini_portile2 (~> 2.5.0)
nokogiri (1.12.2)
mini_portile2 (~> 2.6.1)
racc (~> 1.4)
nokogumbo (2.0.5)
nokogiri (~> 1.8, >= 1.8.4)

View File

@ -169,7 +169,6 @@ transparency for contributors in addition to the
```
- make sure it is one commit per revision bump
- if CI is green and...
- formula `bottle :unneeded`, you can merge it through GitHub UI
- bottles need to be pulled, and...
- the commits are correct, don't need changes, and BrewTestBot can merge it (doesn't have the label `automerge-skip`): approve the PR to trigger an automatic merge (use `brew pr-publish $PR_ID` to trigger manually in case of a new formula)
- the commits are correct and don't need changes, but BrewTestBot can't merge it (has the label `automerge-skip`), use `brew pr-publish $PR_ID`

View File

@ -60,7 +60,7 @@ To make a new branch and submit it for review, create a GitHub pull request with
brew tests
brew install --build-from-source <CHANGED_FORMULA>
brew test <CHANGED_FORMULA>
brew audit --strict <CHANGED_FORMULA>
brew audit --strict --online <CHANGED_FORMULA>
```
6. [Make a separate commit](Formula-Cookbook.md#commit) for each changed formula with `git add` and `git commit`.
* Please note that our preferred commit message format for simple version updates is "`<FORMULA_NAME> <NEW_VERSION>`", e.g. "`source-highlight 3.1.8`".

View File

@ -465,7 +465,11 @@ information is displayed in interactive shells, and suppressed otherwise.
* `--fetch-HEAD`:
Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository's HEAD will only be checked for updates when a new stable or development version has been released.
* `--greedy`:
Print outdated casks with `auto_updates` or `version :latest`.
Print outdated casks with `auto_updates true` or `version :latest`.
* `--greedy-latest`:
Print outdated casks including those with `version :latest`.
* `--greedy-auto-updates`:
Print outdated casks including those with `auto_updates true`.
### `pin` *`installed_formula`* [...]
@ -565,6 +569,7 @@ The search for *`text`* is extended online to `homebrew/core` and `homebrew/cask
Print export statements. When run in a shell, this installation of Homebrew will be added to your `PATH`, `MANPATH`, and `INFOPATH`.
The variables `HOMEBREW_PREFIX`, `HOMEBREW_CELLAR` and `HOMEBREW_REPOSITORY` are also exported to avoid querying them multiple times.
The variable `HOMEBREW_SHELLENV_PREFIX` will be exported to avoid adding duplicate entries to the environment variables.
Consider adding evaluation of this command's output to your dotfiles (e.g. `~/.profile`, `~/.bash_profile`, or `~/.zprofile`) with: `eval $(brew shellenv)`
### `tap` [*`options`*] [*`user`*`/`*`repo`*] [*`URL`*]
@ -703,6 +708,10 @@ upgraded formulae or, every 30 days, for all formulae.
Skip installing cask dependencies.
* `--greedy`:
Also include casks with `auto_updates true` or `version :latest`.
* `--greedy-latest`:
Also include casks with `version :latest`.
* `--greedy-auto-updates`:
Also include casks with `auto_updates true`.
### `uses` [*`options`*] *`formula`* [...]
@ -1981,6 +1990,9 @@ example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just
- `HOMEBREW_GITHUB_PACKAGES_TOKEN`
<br>Use this GitHub personal access token when accessing the GitHub Packages Registry (where bottles may be stored).
- `HOMEBREW_DOCKER_REGISTRY_TOKEN`
<br>Use this bearer token for authenticating with a Docker registry proxying GitHub Packages.
- `HOMEBREW_GITHUB_PACKAGES_USER`
<br>Use this username when accessing the GitHub Packages Registry (where bottles may be stored).

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 2021" "Homebrew" "brew"
.TH "BREW" "1" "August 2021" "Homebrew" "brew"
.
.SH "NAME"
\fBbrew\fR \- The Missing Package Manager for macOS (or Linux)
@ -640,7 +640,15 @@ Fetch the upstream repository to detect if the HEAD installation of the formula
.
.TP
\fB\-\-greedy\fR
Print outdated casks with \fBauto_updates\fR or \fBversion :latest\fR\.
Print outdated casks with \fBauto_updates true\fR or \fBversion :latest\fR\.
.
.TP
\fB\-\-greedy\-latest\fR
Print outdated casks including those with \fBversion :latest\fR\.
.
.TP
\fB\-\-greedy\-auto\-updates\fR
Print outdated casks including those with \fBauto_updates true\fR\.
.
.SS "\fBpin\fR \fIinstalled_formula\fR [\.\.\.]"
Pin the specified \fIformula\fR, preventing them from being upgraded when issuing the \fBbrew upgrade\fR \fIformula\fR command\. See also \fBunpin\fR\.
@ -784,7 +792,7 @@ Search for \fItext\fR in the given database\.
Print export statements\. When run in a shell, this installation of Homebrew will be added to your \fBPATH\fR, \fBMANPATH\fR, and \fBINFOPATH\fR\.
.
.P
The variables \fBHOMEBREW_PREFIX\fR, \fBHOMEBREW_CELLAR\fR and \fBHOMEBREW_REPOSITORY\fR are also exported to avoid querying them multiple times\. Consider adding evaluation of this command\'s output to your dotfiles (e\.g\. \fB~/\.profile\fR, \fB~/\.bash_profile\fR, or \fB~/\.zprofile\fR) with: \fBeval $(brew shellenv)\fR
The variables \fBHOMEBREW_PREFIX\fR, \fBHOMEBREW_CELLAR\fR and \fBHOMEBREW_REPOSITORY\fR are also exported to avoid querying them multiple times\. The variable \fBHOMEBREW_SHELLENV_PREFIX\fR will be exported to avoid adding duplicate entries to the environment variables\. Consider adding evaluation of this command\'s output to your dotfiles (e\.g\. \fB~/\.profile\fR, \fB~/\.bash_profile\fR, or \fB~/\.zprofile\fR) with: \fBeval $(brew shellenv)\fR
.
.SS "\fBtap\fR [\fIoptions\fR] [\fIuser\fR\fB/\fR\fIrepo\fR] [\fIURL\fR]"
Tap a formula repository\.
@ -971,6 +979,14 @@ Skip installing cask dependencies\.
\fB\-\-greedy\fR
Also include casks with \fBauto_updates true\fR or \fBversion :latest\fR\.
.
.TP
\fB\-\-greedy\-latest\fR
Also include casks with \fBversion :latest\fR\.
.
.TP
\fB\-\-greedy\-auto\-updates\fR
Also include casks with \fBauto_updates true\fR\.
.
.SS "\fBuses\fR [\fIoptions\fR] \fIformula\fR [\.\.\.]"
Show formulae and casks that specify \fIformula\fR as a dependency; that is, show dependents of \fIformula\fR\. When given multiple formula arguments, show the intersection of formulae that use \fIformula\fR\. By default, \fBuses\fR shows all formulae and casks that specify \fIformula\fR as a required or recommended dependency for their stable builds\.
.
@ -2836,6 +2852,12 @@ Use this personal access token for the GitHub API, for features such as \fBbrew
Use this GitHub personal access token when accessing the GitHub Packages Registry (where bottles may be stored)\.
.
.TP
\fBHOMEBREW_DOCKER_REGISTRY_TOKEN\fR
.
.br
Use this bearer token for authenticating with a Docker registry proxying GitHub Packages\.
.
.TP
\fBHOMEBREW_GITHUB_PACKAGES_USER\fR
.
.br