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 runs-on: ubuntu-latest
steps: steps:
- name: Lock Outdated Threads - name: Lock Outdated Threads
uses: dessant/lock-threads@486f7380c15596f92b724e4260e4981c68d6bde6 uses: dessant/lock-threads@1621939cecf8586399a6b60d2a7af9469232b5b6
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
issue-lock-inactive-days: 30 issue-lock-inactive-days: 30

4
.gitignore vendored
View File

@ -194,5 +194,7 @@
# Unignore tests' bundle config # Unignore tests' bundle config
!/Library/Homebrew/test/.bundle/config !/Library/Homebrew/test/.bundle/config
# Unignore vscode configuration # Unignore editor configuration
!/.sublime
/.sublime/homebrew.sublime-workspace
!/.vscode !/.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/* \ && rm -rf /var/lib/apt/lists/* \
&& localedef -i en_US -f UTF-8 en_US.UTF-8 \ && localedef -i en_US -f UTF-8 en_US.UTF-8 \
&& useradd -m -s /bin/bash linuxbrew \ && 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 ENV PATH=/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:$PATH
WORKDIR /home/linuxbrew WORKDIR /home/linuxbrew

View File

@ -11,7 +11,7 @@ GEM
public_suffix (>= 2.0.2, < 5.0) public_suffix (>= 2.0.2, < 5.0)
ast (2.4.2) ast (2.4.2)
bindata (2.4.10) bindata (2.4.10)
bootsnap (1.7.5) bootsnap (1.7.7)
msgpack (~> 1.0) msgpack (~> 1.0)
byebug (11.1.3) byebug (11.1.3)
coderay (1.1.3) coderay (1.1.3)
@ -121,7 +121,7 @@ GEM
rubocop-ast (>= 1.8.0, < 2.0) rubocop-ast (>= 1.8.0, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0) unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.8.0) rubocop-ast (1.9.0)
parser (>= 3.0.1.1) parser (>= 3.0.1.1)
rubocop-performance (1.11.4) rubocop-performance (1.11.4)
rubocop (>= 1.7.0, < 2.0) 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 # frozen_string_literal: true
if ENV["HOMEBREW_STACKPROF"] if ENV["HOMEBREW_STACKPROF"]
require_relative "utils/gems"
Homebrew.setup_gem_environment!
require "stackprof" require "stackprof"
StackProf.start(mode: :wall, raw: true) StackProf.start(mode: :wall, raw: true)
end end

View File

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

View File

@ -19,6 +19,12 @@ module Cask
[:switch, "--greedy", { [:switch, "--greedy", {
description: "Also include casks with `auto_updates true` or `version :latest`.", 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 ].freeze
sig { returns(Homebrew::CLI::Parser) } sig { returns(Homebrew::CLI::Parser) }
@ -42,6 +48,8 @@ module Cask
*casks, *casks,
force: args.force?, force: args.force?,
greedy: args.greedy?, greedy: args.greedy?,
greedy_latest: args.greedy_latest?,
greedy_auto_updates: args.greedy_auto_updates?,
dry_run: args.dry_run?, dry_run: args.dry_run?,
binaries: args.binaries?, binaries: args.binaries?,
quarantine: args.quarantine?, quarantine: args.quarantine?,
@ -58,6 +66,8 @@ module Cask
args: Homebrew::CLI::Args, args: Homebrew::CLI::Args,
force: T.nilable(T::Boolean), force: T.nilable(T::Boolean),
greedy: 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), dry_run: T.nilable(T::Boolean),
skip_cask_deps: T.nilable(T::Boolean), skip_cask_deps: T.nilable(T::Boolean),
verbose: T.nilable(T::Boolean), verbose: T.nilable(T::Boolean),
@ -71,6 +81,8 @@ module Cask
args:, args:,
force: false, force: false,
greedy: false, greedy: false,
greedy_latest: false,
greedy_auto_updates: false,
dry_run: false, dry_run: false,
skip_cask_deps: false, skip_cask_deps: false,
verbose: false, verbose: false,
@ -83,7 +95,8 @@ module Cask
outdated_casks = if casks.empty? outdated_casks = if casks.empty?
Caskroom.casks(config: Config.from_args(args)).select do |cask| 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 end
else else
casks.select do |cask| casks.select do |cask|
@ -107,7 +120,16 @@ module Cask
return false if outdated_casks.empty? return false if outdated_casks.empty?
if casks.empty? && !greedy 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 end
verb = dry_run ? "Would upgrade" : "Upgrading" verb = dry_run ? "Would upgrade" : "Upgrading"

View File

@ -2,7 +2,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "delegate" require "delegate"
require "bottle_api" require "api"
require "cli/args" require "cli/args"
module Homebrew module Homebrew
@ -94,8 +94,9 @@ module Homebrew
unreadable_error = nil unreadable_error = nil
if only != :cask if only != :cask
if prefer_loading_from_json && ENV["HOMEBREW_JSON_CORE"].present? && BottleAPI.bottle_available?(name) if prefer_loading_from_json && ENV["HOMEBREW_JSON_CORE"].present? &&
BottleAPI.fetch_bottles(name) Homebrew::API::Bottle.available?(name)
Homebrew::API::Bottle.fetch_bottles(name)
end end
begin begin
@ -324,7 +325,11 @@ module Homebrew
# Return keg if it is the only installed keg # Return keg if it is the only installed keg
return kegs if kegs.length == 1 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 end
def resolve_default_keg(name) def resolve_default_keg(name)

View File

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

View File

@ -11,6 +11,7 @@ require "tab"
require "json" require "json"
require "utils/spdx" require "utils/spdx"
require "deprecate_disable" require "deprecate_disable"
require "api"
module Homebrew module Homebrew
extend T::Sig extend T::Sig
@ -243,8 +244,8 @@ module Homebrew
def info_formula(f, args:) def info_formula(f, args:)
specs = [] specs = []
if ENV["HOMEBREW_JSON_CORE"].present? && BottleAPI.bottle_available?(f.name) if ENV["HOMEBREW_JSON_CORE"].present? && Homebrew::API::Bottle.available?(f.name)
info = BottleAPI.fetch(f.name) info = Homebrew::API::Bottle.fetch(f.name)
latest_version = info["pkg_version"].split("_").first latest_version = info["pkg_version"].split("_").first
bottle_exists = info["bottles"].key?(Utils::Bottles.tag.to_s) || info["bottles"].key?("all") 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 "cli/parser"
require "cask/cmd" require "cask/cmd"
require "cask/caskroom" require "cask/caskroom"
require "bottle_api" require "api"
module Homebrew module Homebrew
extend T::Sig extend T::Sig
@ -37,7 +37,13 @@ module Homebrew
"formula is outdated. Otherwise, the repository's HEAD will only be checked for "\ "formula is outdated. Otherwise, the repository's HEAD will only be checked for "\
"updates when a new stable or development version has been released." "updates when a new stable or development version has been released."
switch "--greedy", 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 "--quiet", "--verbose", "--json"
conflicts "--formula", "--cask" conflicts "--formula", "--cask"
@ -93,7 +99,7 @@ module Homebrew
outdated_kegs = f.outdated_kegs(fetch_head: args.fetch_HEAD?) outdated_kegs = f.outdated_kegs(fetch_head: args.fetch_HEAD?)
current_version = if ENV["HOMEBREW_JSON_CORE"].present? && (f.core_formula? || f.tap.blank?) 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? elsif f.alias_changed? && !f.latest_formula.latest_version_installed?
latest = f.latest_formula latest = f.latest_formula
"#{latest.name} (#{latest.pkg_version})" "#{latest.name} (#{latest.pkg_version})"
@ -119,7 +125,7 @@ module Homebrew
else else
c = formula_or_cask 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 end
end end
@ -144,7 +150,7 @@ module Homebrew
else else
c = formula_or_cask 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 end
end end
@ -194,7 +200,8 @@ module Homebrew
if formula_or_cask.is_a?(Formula) if formula_or_cask.is_a?(Formula)
formula_or_cask.outdated?(fetch_head: args.fetch_HEAD?) formula_or_cask.outdated?(fetch_head: args.fetch_HEAD?)
else 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 end
end end

View File

@ -12,7 +12,7 @@ require "cask/cmd"
require "cask/utils" require "cask/utils"
require "cask/macos" require "cask/macos"
require "upgrade" require "upgrade"
require "bottle_api" require "api"
module Homebrew module Homebrew
extend T::Sig extend T::Sig
@ -90,9 +90,9 @@ module Homebrew
formula = Formulary.factory(name) formula = Formulary.factory(name)
next unless formula.any_version_installed? next unless formula.any_version_installed?
next if formula.tap.present? && !formula.core_formula? 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 rescue FormulaUnavailableError
next next
end end

View File

@ -78,7 +78,7 @@ module Homebrew
string_or_regex = query_regexp(query) string_or_regex = query_regexp(query)
if args.desc? if args.desc?
search_descriptions(string_or_regex) search_descriptions(string_or_regex, args)
elsif args.pull_request? elsif args.pull_request?
only = if args.open? && !args.closed? only = if args.open? && !args.closed?
"open" "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`. #: 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 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)` #: 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_CELLAR and HOMEBREW_PREFIX are set by extend/ENV/super.rb
# HOMEBREW_REPOSITORY is set by bin/brew # HOMEBREW_REPOSITORY is set by bin/brew
# shellcheck disable=SC2154 # shellcheck disable=SC2154
homebrew-shellenv() { homebrew-shellenv() {
[[ "${HOMEBREW_SHELLENV_PREFIX}" == "${HOMEBREW_PREFIX}" ]] && return
case "$(/bin/ps -p "${PPID}" -c -o comm=)" in case "$(/bin/ps -p "${PPID}" -c -o comm=)" in
fish|-fish) fish | -fish)
echo "set -gx HOMEBREW_PREFIX \"${HOMEBREW_PREFIX}\";" echo "set -gx HOMEBREW_PREFIX \"${HOMEBREW_PREFIX}\";"
echo "set -gx HOMEBREW_CELLAR \"${HOMEBREW_CELLAR}\";" echo "set -gx HOMEBREW_CELLAR \"${HOMEBREW_CELLAR}\";"
echo "set -gx HOMEBREW_REPOSITORY \"${HOMEBREW_REPOSITORY}\";" 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 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 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;" 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_PREFIX ${HOMEBREW_PREFIX};"
echo "setenv HOMEBREW_CELLAR ${HOMEBREW_CELLAR};" echo "setenv HOMEBREW_CELLAR ${HOMEBREW_CELLAR};"
echo "setenv HOMEBREW_REPOSITORY ${HOMEBREW_REPOSITORY};" 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 PATH ${HOMEBREW_PREFIX}/bin:${HOMEBREW_PREFIX}/sbin:\$PATH;"
echo "setenv MANPATH ${HOMEBREW_PREFIX}/share/man\`[ \${?MANPATH} == 1 ] && echo \":\${MANPATH}\"\`:;" echo "setenv MANPATH ${HOMEBREW_PREFIX}/share/man\`[ \${?MANPATH} == 1 ] && echo \":\${MANPATH}\"\`:;"
echo "setenv INFOPATH ${HOMEBREW_PREFIX}/share/info\`[ \${?INFOPATH} == 1 ] && echo \":\${INFOPATH}\"\`;" 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_PREFIX=\"${HOMEBREW_PREFIX}\";"
echo "export HOMEBREW_CELLAR=\"${HOMEBREW_CELLAR}\";" echo "export HOMEBREW_CELLAR=\"${HOMEBREW_CELLAR}\";"
echo "export HOMEBREW_REPOSITORY=\"${HOMEBREW_REPOSITORY}\";" 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 PATH=\"${HOMEBREW_PREFIX}/bin:${HOMEBREW_PREFIX}/sbin\${PATH+:\$PATH}\";"
echo "export MANPATH=\"${HOMEBREW_PREFIX}/share/man\${MANPATH+:\$MANPATH}:\";" echo "export MANPATH=\"${HOMEBREW_PREFIX}/share/man\${MANPATH+:\$MANPATH}:\";"
echo "export INFOPATH=\"${HOMEBREW_PREFIX}/share/info:\${INFOPATH:-}\";" echo "export INFOPATH=\"${HOMEBREW_PREFIX}/share/info:\${INFOPATH:-}\";"

View File

@ -8,7 +8,7 @@ require "upgrade"
require "cask/cmd" require "cask/cmd"
require "cask/utils" require "cask/utils"
require "cask/macos" require "cask/macos"
require "bottle_api" require "api"
module Homebrew module Homebrew
extend T::Sig extend T::Sig
@ -163,9 +163,9 @@ module Homebrew
if ENV["HOMEBREW_JSON_CORE"].present? if ENV["HOMEBREW_JSON_CORE"].present?
formulae_to_install.map! do |formula| formulae_to_install.map! do |formula|
next formula if formula.tap.present? && !formula.core_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) Formulary.factory(formula.name)
rescue FormulaUnavailableError rescue FormulaUnavailableError
formula formula

View File

@ -1,44 +1,23 @@
{ {
"licenseListVersion": "3.13", "licenseListVersion": "3.14",
"exceptions": [ "exceptions": [
{ {
"reference": "./eCos-exception-2.0.json", "reference": "./GPL-CC-1.0.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./eCos-exception-2.0.html", "detailsUrl": "./GPL-CC-1.0.html",
"referenceNumber": 1, "referenceNumber": 1,
"name": "eCos exception 2.0", "name": "GPL Cooperation Commitment 1.0",
"licenseExceptionId": "eCos-exception-2.0", "licenseExceptionId": "GPL-CC-1.0",
"seeAlso": [ "seeAlso": [
"http://ecos.sourceware.org/license-overview.html" "https://github.com/gplcc/gplcc/blob/master/Project/COMMITMENT",
] "https://gplcc.github.io/gplcc/Project/README-PROJECT.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"
] ]
}, },
{ {
"reference": "./openvpn-openssl-exception.json", "reference": "./openvpn-openssl-exception.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./openvpn-openssl-exception.html", "detailsUrl": "./openvpn-openssl-exception.html",
"referenceNumber": 4, "referenceNumber": 2,
"name": "OpenVPN OpenSSL Exception", "name": "OpenVPN OpenSSL Exception",
"licenseExceptionId": "openvpn-openssl-exception", "licenseExceptionId": "openvpn-openssl-exception",
"seeAlso": [ "seeAlso": [
@ -46,32 +25,89 @@
] ]
}, },
{ {
"reference": "./Bootloader-exception.json", "reference": "./WxWindows-exception-3.1.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./Bootloader-exception.html", "detailsUrl": "./WxWindows-exception-3.1.html",
"referenceNumber": 5, "referenceNumber": 3,
"name": "Bootloader Distribution Exception", "name": "WxWindows Library Exception 3.1",
"licenseExceptionId": "Bootloader-exception", "licenseExceptionId": "WxWindows-exception-3.1",
"seeAlso": [ "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, "isDeprecatedLicenseId": false,
"detailsUrl": "./OCCT-exception-1.0.html", "detailsUrl": "./GPL-3.0-linking-exception.html",
"referenceNumber": 6, "referenceNumber": 4,
"name": "Open CASCADE Exception 1.0", "name": "GPL-3.0 Linking Exception",
"licenseExceptionId": "OCCT-exception-1.0", "licenseExceptionId": "GPL-3.0-linking-exception",
"seeAlso": [ "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", "reference": "./Bison-exception-2.2.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./Bison-exception-2.2.html", "detailsUrl": "./Bison-exception-2.2.html",
"referenceNumber": 7, "referenceNumber": 10,
"name": "Bison exception 2.2", "name": "Bison exception 2.2",
"licenseExceptionId": "Bison-exception-2.2", "licenseExceptionId": "Bison-exception-2.2",
"seeAlso": [ "seeAlso": [
@ -79,60 +115,26 @@
] ]
}, },
{ {
"reference": "./Swift-exception.json", "reference": "./OCCT-exception-1.0.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./Swift-exception.html", "detailsUrl": "./OCCT-exception-1.0.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",
"referenceNumber": 11, "referenceNumber": 11,
"name": "GPL-3.0 Linking Exception (with Corresponding Source)", "name": "Open CASCADE Exception 1.0",
"licenseExceptionId": "GPL-3.0-linking-source-exception", "licenseExceptionId": "OCCT-exception-1.0",
"seeAlso": [ "seeAlso": [
"https://www.gnu.org/licenses/gpl-faq.en.html#GPLIncompatibleLibs", "http://www.opencascade.com/content/licensing"
"https://github.com/mirror/wget/blob/master/src/http.c#L20"
] ]
}, },
{ {
"reference": "./FLTK-exception.json", "reference": "./Autoconf-exception-2.0.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./FLTK-exception.html", "detailsUrl": "./Autoconf-exception-2.0.html",
"referenceNumber": 12, "referenceNumber": 12,
"name": "FLTK exception", "name": "Autoconf exception 2.0",
"licenseExceptionId": "FLTK-exception", "licenseExceptionId": "Autoconf-exception-2.0",
"seeAlso": [ "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" "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", "reference": "./GCC-exception-3.1.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./GCC-exception-3.1.html", "detailsUrl": "./GCC-exception-3.1.html",
"referenceNumber": 27, "referenceNumber": 14,
"name": "GCC Runtime Library exception 3.1", "name": "GCC Runtime Library exception 3.1",
"licenseExceptionId": "GCC-exception-3.1", "licenseExceptionId": "GCC-exception-3.1",
"seeAlso": [ "seeAlso": [
"http://www.gnu.org/licenses/gcc-exception-3.1.html" "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", "reference": "./OCaml-LGPL-linking-exception.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./OCaml-LGPL-linking-exception.html", "detailsUrl": "./OCaml-LGPL-linking-exception.html",
"referenceNumber": 28, "referenceNumber": 20,
"name": "OCaml LGPL Linking Exception", "name": "OCaml LGPL Linking Exception",
"licenseExceptionId": "OCaml-LGPL-linking-exception", "licenseExceptionId": "OCaml-LGPL-linking-exception",
"seeAlso": [ "seeAlso": [
@ -315,21 +227,65 @@
] ]
}, },
{ {
"reference": "./gnu-javamail-exception.json", "reference": "./Qt-GPL-exception-1.0.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./gnu-javamail-exception.html", "detailsUrl": "./Qt-GPL-exception-1.0.html",
"referenceNumber": 29, "referenceNumber": 21,
"name": "GNU JavaMail exception", "name": "Qt GPL exception 1.0",
"licenseExceptionId": "gnu-javamail-exception", "licenseExceptionId": "Qt-GPL-exception-1.0",
"seeAlso": [ "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", "reference": "./Classpath-exception-2.0.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./Classpath-exception-2.0.html", "detailsUrl": "./Classpath-exception-2.0.html",
"referenceNumber": 30, "referenceNumber": 26,
"name": "Classpath exception 2.0", "name": "Classpath exception 2.0",
"licenseExceptionId": "Classpath-exception-2.0", "licenseExceptionId": "Classpath-exception-2.0",
"seeAlso": [ "seeAlso": [
@ -337,80 +293,11 @@
"https://fedoraproject.org/wiki/Licensing/GPL_Classpath_Exception" "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", "reference": "./Qwt-exception-1.0.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./Qwt-exception-1.0.html", "detailsUrl": "./Qwt-exception-1.0.html",
"referenceNumber": 37, "referenceNumber": 27,
"name": "Qwt exception 1.0", "name": "Qwt exception 1.0",
"licenseExceptionId": "Qwt-exception-1.0", "licenseExceptionId": "Qwt-exception-1.0",
"seeAlso": [ "seeAlso": [
@ -421,7 +308,7 @@
"reference": "./LZMA-exception.json", "reference": "./LZMA-exception.json",
"isDeprecatedLicenseId": false, "isDeprecatedLicenseId": false,
"detailsUrl": "./LZMA-exception.html", "detailsUrl": "./LZMA-exception.html",
"referenceNumber": 38, "referenceNumber": 28,
"name": "LZMA exception", "name": "LZMA exception",
"licenseExceptionId": "LZMA-exception", "licenseExceptionId": "LZMA-exception",
"seeAlso": [ "seeAlso": [
@ -429,38 +316,151 @@
] ]
}, },
{ {
"reference": "./freertos-exception-2.0.json", "reference": "./Autoconf-exception-3.0.json",
"isDeprecatedLicenseId": false, "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, "referenceNumber": 39,
"name": "FreeRTOS Exception 2.0", "name": "FLTK exception",
"licenseExceptionId": "freertos-exception-2.0", "licenseExceptionId": "FLTK-exception",
"seeAlso": [ "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, "isDeprecatedLicenseId": false,
"detailsUrl": "./u-boot-exception-2.0.html", "detailsUrl": "./LGPL-3.0-linking-exception.html",
"referenceNumber": 40, "referenceNumber": 40,
"name": "U-Boot exception 2.0", "name": "LGPL-3.0 Linking Exception",
"licenseExceptionId": "u-boot-exception-2.0", "licenseExceptionId": "LGPL-3.0-linking-exception",
"seeAlso": [ "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, "isDeprecatedLicenseId": false,
"detailsUrl": "./i2p-gpl-java-exception.html", "detailsUrl": "./SHL-2.1.html",
"referenceNumber": 41, "referenceNumber": 41,
"name": "i2p GPL+Java Exception", "name": "Solderpad Hardware License v2.1",
"licenseExceptionId": "i2p-gpl-java-exception", "licenseExceptionId": "SHL-2.1",
"seeAlso": [ "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 "erb"
require "archive" require "archive"
require "zlib" require "zlib"
require "api"
BOTTLE_ERB = <<-EOS BOTTLE_ERB = <<-EOS
bottle do bottle do
@ -333,8 +334,6 @@ module Homebrew
root_url = args.root_url root_url = args.root_url
formulae_brew_sh_path = Utils::Analytics.formula_path
relocatable = T.let(false, T::Boolean) relocatable = T.let(false, T::Boolean)
skip_relocation = T.let(false, T::Boolean) skip_relocation = T.let(false, T::Boolean)
@ -561,7 +560,7 @@ module Homebrew
"filename" => filename.url_encode, "filename" => filename.url_encode,
"local_filename" => filename.to_s, "local_filename" => filename.to_s,
"sha256" => sha256, "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, "tab" => tab.to_bottle_hash,
}, },
}, },

View File

@ -151,14 +151,30 @@ module Homebrew
end end
def livecheck_result(formula_or_cask) def livecheck_result(formula_or_cask)
skip_result = Livecheck::SkipConditions.skip_information(formula_or_cask) name = Livecheck.formula_or_cask_name(formula_or_cask)
if skip_result.present?
return "#{skip_result[:status]}#{" - #{skip_result[:messages].join(", ")}" if skip_result[:messages].present?}" 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 end
version_info = Livecheck.latest_version( version_info = Livecheck.latest_version(
formula_or_cask, 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? latest = version_info[:latest] if version_info.present?

View File

@ -40,16 +40,24 @@ module Homebrew
EOS EOS
end end
paths = args.named.to_paths.select do |path| 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? next path if path.exist?
raise UsageError, "#{path} doesn't exist on disk. " \ raise UsageError, "#{path} doesn't exist on disk. " \
"Run #{Formatter.identifier("brew create --set-name #{path.basename} $URL")} " \ "Run #{Formatter.identifier("brew create --set-name #{path.basename} $URL")} " \
"to create a new formula!" "to create a new formula!"
end.presence end.presence
end
# If no formulae are listed, open the project root in an editor.
paths ||= [HOMEBREW_REPOSITORY]
exec_editor(*paths) exec_editor(*paths)
end end

View File

@ -3,6 +3,7 @@
require "cli/parser" require "cli/parser"
require "formula" require "formula"
require "api"
module Homebrew module Homebrew
extend T::Sig extend T::Sig
@ -87,7 +88,7 @@ module Homebrew
formula_installs = {} formula_installs = {}
ohai "Getting analytics data..." 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? if analytics.blank?
raise UsageError, raise UsageError,

View File

@ -388,7 +388,10 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
ohai "Downloading #{url}" 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 fresh = if cached_location.exist? && url_time
url_time <= cached_location.mtime url_time <= cached_location.mtime
@ -449,7 +452,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
return @resolved_info_cache[url] if @resolved_info_cache.include?(url) return @resolved_info_cache[url] if @resolved_info_cache.include?(url)
if (domain = Homebrew::EnvConfig.artifact_domain) 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 end
out, _, status= curl_output("--location", "--silent", "--head", "--request", "GET", url.to_s, timeout: timeout) out, _, status= curl_output("--location", "--silent", "--head", "--request", "GET", url.to_s, timeout: timeout)
@ -507,8 +510,9 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
.last .last
basename = filenames.last || parse_basename(redirect_url) 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 end
def _fetch(url:, resolved_url:, timeout:) def _fetch(url:, resolved_url:, timeout:)
@ -564,7 +568,8 @@ class CurlGitHubPackagesDownloadStrategy < CurlDownloadStrategy
def initialize(url, name, version, **meta) def initialize(url, name, version, **meta)
meta ||= {} meta ||= {}
meta[:headers] ||= [] 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) super(url, name, version, meta)
end end

View File

@ -170,6 +170,9 @@ module Homebrew
description: "Use this GitHub personal access token when accessing the GitHub Packages Registry "\ description: "Use this GitHub personal access token when accessing the GitHub Packages Registry "\
"(where bottles may be stored).", "(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: { HOMEBREW_GITHUB_PACKAGES_USER: {
description: "Use this username when accessing the GitHub Packages Registry (where bottles may be stored).", 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}: The following #{flag_text}:
#{flags.join(", ")} #{flags.join(", ")}
#{require_text} building tools, but none are installed. #{require_text} building tools, but none are installed.
#{DevelopmentTools.installation_instructions}#{bottle_text} #{DevelopmentTools.installation_instructions} #{bottle_text}
EOS EOS
super message 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 Homebrew
module Search module Search
module Extension module Extension
def search_descriptions(string_or_regex) def search_descriptions(string_or_regex, args)
super super
puts puts
return if args.formula?
ohai "Casks" ohai "Casks"
Cask::Cask.to_a.extend(Searchable) Cask::Cask.to_a.extend(Searchable)
.search(string_or_regex, &:name) .search(string_or_regex, &:name)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,6 +18,8 @@ class Livecheck
def initialize(formula_or_cask) def initialize(formula_or_cask)
@formula_or_cask = formula_or_cask @formula_or_cask = formula_or_cask
@referenced_cask_name = nil
@referenced_formula_name = nil
@regex = nil @regex = nil
@skip = false @skip = false
@skip_msg = nil @skip_msg = nil
@ -25,6 +27,42 @@ class Livecheck
@url = nil @url = nil
end 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 # Sets the `@regex` instance variable to the provided `Regexp` or returns the
# `@regex` instance variable when no argument is provided. # `@regex` instance variable when no argument is provided.
# #
@ -109,6 +147,8 @@ class Livecheck
# @return [Hash] # @return [Hash]
def to_hash def to_hash
{ {
"cask" => @referenced_cask_name,
"formula" => @referenced_formula_name,
"regex" => @regex, "regex" => @regex,
"skip" => @skip, "skip" => @skip,
"skip_msg" => @skip_msg, "skip_msg" => @skip_msg,

View File

@ -9,6 +9,8 @@ require "ruby-progressbar"
require "uri" require "uri"
module Homebrew module Homebrew
# rubocop:disable Metrics/ModuleLength
# The {Livecheck} module consists of methods used by the `brew livecheck` # The {Livecheck} module consists of methods used by the `brew livecheck`
# command. These methods print the requested livecheck information # command. These methods print the requested livecheck information
# for formulae. # for formulae.
@ -82,6 +84,74 @@ module Homebrew
end end
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 # Executes the livecheck logic for each formula/cask in the
# `formulae_and_casks_to_check` array and prints the results. # `formulae_and_casks_to_check` array and prints the results.
sig { sig {
@ -139,6 +209,7 @@ module Homebrew
) )
end end
# rubocop:disable Metrics/BlockLength
formulae_checked = formulae_and_casks_to_check.map.with_index do |formula_or_cask, i| 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) formula = formula_or_cask if formula_or_cask.is_a?(Formula)
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask) 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) use_full_name = full_name || ambiguous_names.include?(formula_or_cask)
name = formula_or_cask_name(formula_or_cask, full_name: use_full_name) 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? if debug && i.positive?
puts <<~EOS puts <<~EOS
@ -156,7 +230,17 @@ module Homebrew
puts puts
end 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? if skip_info.present?
next skip_info if json next skip_info if json
@ -188,7 +272,9 @@ module Homebrew
else else
version_info = latest_version( version_info = latest_version(
formula_or_cask, 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? version_info[:latest] if version_info.present?
end end
@ -262,6 +348,7 @@ module Homebrew
nil nil
end end
end end
# rubocop:enable Metrics/BlockLength
puts "No newer upstream versions." if newer_only && !has_a_newer_upstream_version && !debug && !json puts "No newer upstream versions." if newer_only && !has_a_newer_upstream_version && !debug && !json
@ -445,26 +532,39 @@ module Homebrew
sig { sig {
params( params(
formula_or_cask: T.any(Formula, Cask::Cask), 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, json: T::Boolean,
full_name: T::Boolean, full_name: T::Boolean,
verbose: T::Boolean, verbose: T::Boolean,
debug: T::Boolean, debug: T::Boolean,
).returns(T.nilable(Hash)) ).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) formula = formula_or_cask if formula_or_cask.is_a?(Formula)
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask) cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
has_livecheckable = formula_or_cask.livecheckable? has_livecheckable = formula_or_cask.livecheckable?
livecheck = formula_or_cask.livecheck livecheck = formula_or_cask.livecheck
livecheck_url = livecheck.url referenced_livecheck = referenced_formula_or_cask&.livecheck
livecheck_regex = livecheck.regex
livecheck_strategy = livecheck.strategy
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 = [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 debug
if formula if formula
@ -474,8 +574,18 @@ module Homebrew
puts "Cask: #{cask_name(formula_or_cask, full_name: full_name)}" puts "Cask: #{cask_name(formula_or_cask, full_name: full_name)}"
end end
puts "Livecheckable?: #{has_livecheckable ? "Yes" : "No"}" 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 end
# rubocop:disable Metrics/BlockLength
urls.each_with_index do |original_url, i| urls.each_with_index do |original_url, i|
if debug if debug
puts puts
@ -499,7 +609,7 @@ module Homebrew
livecheck_strategy: livecheck_strategy, livecheck_strategy: livecheck_strategy,
url_provided: livecheck_url.present?, url_provided: livecheck_url.present?,
regex_provided: livecheck_regex.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 = Strategy.from_symbol(livecheck_strategy) || strategies.first
strategy_name = livecheck_strategy_names[strategy] strategy_name = livecheck_strategy_names[strategy]
@ -514,7 +624,7 @@ module Homebrew
end end
if livecheck_strategy.present? 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" odebug "#{strategy_name} strategy requires a regex or block"
next next
elsif livecheck_url.blank? elsif livecheck_url.blank?
@ -529,7 +639,7 @@ module Homebrew
next if strategy.blank? next if strategy.blank?
strategy_data = begin 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 rescue ArgumentError => e
raise unless e.message.include?("unknown keyword: cask") raise unless e.message.include?("unknown keyword: cask")
@ -584,6 +694,17 @@ module Homebrew
if json && verbose if json && verbose
version_info[:meta] = {} 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] = {}
version_info[:meta][:url][:symbol] = livecheck_url if livecheck_url.is_a?(Symbol) && livecheck_url_string version_info[:meta][:url][:symbol] = livecheck_url if livecheck_url.is_a?(Symbol) && livecheck_url_string
version_info[:meta][:url][:original] = original_url version_info[:meta][:url][:original] = original_url
@ -599,8 +720,10 @@ module Homebrew
return version_info return version_info
end end
# rubocop:enable Metrics/BlockLength
nil nil
end end
end end
# rubocop:enable Metrics/ModuleLength
end end

View File

@ -201,6 +201,54 @@ module Homebrew
{} {}
end 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. # Prints default livecheck output in relation to skip conditions.
sig { params(skip_hash: Hash).void } sig { params(skip_hash: Hash).void }
def print_skip_information(skip_hash) def print_skip_information(skip_hash)

View File

@ -52,7 +52,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), 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]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -59,7 +59,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), 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]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -50,7 +50,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), 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]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -19,7 +19,7 @@ module Homebrew
PRIORITY = 0 PRIORITY = 0
# The `Regexp` used to determine if the strategy applies to the URL. # 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. # Whether the strategy can be applied to the provided URL.
# #
@ -37,20 +37,25 @@ module Homebrew
sig { sig {
params( params(
content: String, 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)) ).returns(T.nilable(String))
} }
def self.version_from_content(content, &block) def self.version_from_content(content, &block)
require "yaml" require "yaml"
return unless (yaml = YAML.safe_load(content)) yaml = YAML.safe_load(content)
return if yaml.blank?
if block if block
value = block.call(yaml) case (value = block.call(yaml))
return value if value.is_a?(String) when String
return value
when nil
return
else
raise TypeError, "Return value of `strategy :electron_builder` block must be a string." raise TypeError, "Return value of `strategy :electron_builder` block must be a string."
end end
end
yaml["version"] yaml["version"]
end end
@ -65,7 +70,7 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), 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]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

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

View File

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

View File

@ -67,7 +67,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), 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]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -55,7 +55,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), 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]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -59,7 +59,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), 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]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

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

View File

@ -50,7 +50,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), 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]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

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

View File

@ -56,7 +56,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), 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]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -62,7 +62,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), 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]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

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

View File

@ -85,7 +85,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), 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]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

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

View File

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

View File

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

View File

@ -3038,6 +3038,8 @@ module Bootsnap::LoadPathCache::ChangeObserver::ArrayMixin
def []=(*args, &block); end def []=(*args, &block); end
def append(*entries); end
def clear(*args, &block); end def clear(*args, &block); end
def collect!(*args, &block); end def collect!(*args, &block); end
@ -3064,6 +3066,8 @@ module Bootsnap::LoadPathCache::ChangeObserver::ArrayMixin
def pop(*args, &block); end def pop(*args, &block); end
def prepend(*entries); end
def push(*entries); end def push(*entries); end
def reject!(*args, &block); 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 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 end
module BottleAPI
extend ::T::Private::Methods::MethodHooks
extend ::T::Private::Methods::SingletonMethodHooks
end
class BottleSpecification class BottleSpecification
extend ::T::Private::Methods::MethodHooks extend ::T::Private::Methods::MethodHooks
extend ::T::Private::Methods::SingletonMethodHooks extend ::T::Private::Methods::SingletonMethodHooks
@ -9658,6 +9657,31 @@ module Homebrew
MIN_PORT = ::T.let(nil, ::T.untyped) MIN_PORT = ::T.let(nil, ::T.untyped)
end 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 module Homebrew::Assertions
include ::Minitest::Assertions include ::Minitest::Assertions
def assert_include(*args); end def assert_include(*args); end
@ -9775,6 +9799,8 @@ module Homebrew::EnvConfig
def self.display_install_times?(); end def self.display_install_times?(); end
def self.docker_registry_token(); end
def self.editor(); end def self.editor(); end
def self.fail_log_lines(); end def self.fail_log_lines(); end

View File

@ -1,11 +1,9 @@
# typed: false # typed: false
# frozen_string_literal: true # frozen_string_literal: true
describe BottleAPI do require "api"
before do
ENV["HOMEBREW_JSON_CORE"] = "1"
end
describe Homebrew::API::Bottle do
let(:bottle_json) { let(:bottle_json) {
<<~EOS <<~EOS
{ {
@ -28,14 +26,6 @@ describe BottleAPI do
EOS EOS
} }
let(:bottle_hash) { JSON.parse(bottle_json) } 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) def mock_curl_output(stdout: "", success: true)
curl_output = OpenStruct.new(stdout: stdout, success?: success) 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 it "raises an error if the formula does not exist" do
mock_curl_output success: false 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 end
it "raises an error if the bottle JSON is invalid" do it "raises an error if the bottle JSON is invalid" do
@ -60,40 +50,21 @@ describe BottleAPI do
end end
end end
describe "::latest_pkg_version" do describe "::available?" 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
it "returns `true` if `fetch` succeeds" do it "returns `true` if `fetch` succeeds" do
allow(described_class).to receive(:fetch) allow(described_class).to receive(:fetch)
expect(described_class.bottle_available?("foo")).to eq true expect(described_class.available?("foo")).to eq true
end end
it "returns `false` if `fetch` fails" do it "returns `false` if `fetch` fails" do
allow(described_class).to receive(:fetch).and_raise ArgumentError 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
end end
describe "::fetch_bottles" do describe "::fetch_bottles" do
before do before do
ENV["HOMEBREW_JSON_CORE"] = "1"
allow(described_class).to receive(:fetch).and_return bottle_hash allow(described_class).to receive(:fetch).and_return bottle_hash
end 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/1.0").mkpath
(HOMEBREW_CELLAR/"foo/2.0").mkpath (HOMEBREW_CELLAR/"foo/2.0").mkpath
(HOMEBREW_CELLAR/"bar/1.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 end
it "resolves the latest kegs with #resolve_latest_keg" do it "resolves the latest kegs with #resolve_latest_keg" do
latest_kegs = described_class.new("foo", "bar").to_latest_kegs latest_kegs = described_class.new("foo", "bar", "baz").to_latest_kegs
expect(latest_kegs.map(&:name)).to eq ["foo", "bar"] 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"] expect(latest_kegs.map { |k| k.version.version.to_s }).to eq ["2.0", "1.0", "HEAD-2"]
end end
it "when there are no matching kegs returns an empty array" do 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 it "works if plist is set" do
formula = Testball.new formula = Testball.new
path = formula.plist_path 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).twice.and_return("PLIST")
expect(formula).to receive(:plist_path).and_call_original expect(formula).to receive(:plist_path).and_call_original
@ -241,7 +241,7 @@ describe FormulaInstaller do
plist_path = formula.plist_path plist_path = formula.plist_path
service_path = formula.systemd_service_path service_path = formula.systemd_service_path
service = Homebrew::Service.new(formula) service = Homebrew::Service.new(formula)
formula.prefix.mkpath formula.opt_prefix.mkpath
expect(formula).to receive(:plist).and_return(nil) expect(formula).to receive(:plist).and_return(nil)
expect(formula).to receive(:service?).exactly(3).and_return(true) expect(formula).to receive(:service?).exactly(3).and_return(true)
@ -264,7 +264,7 @@ describe FormulaInstaller do
it "returns without definition" do it "returns without definition" do
formula = Testball.new formula = Testball.new
path = formula.plist_path path = formula.plist_path
formula.prefix.mkpath formula.opt_prefix.mkpath
expect(formula).to receive(:plist).and_return(nil) expect(formula).to receive(:plist).and_return(nil)
expect(formula).to receive(:service?).exactly(3).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 it "errors with duplicate definition" do
formula = Testball.new formula = Testball.new
path = formula.plist_path path = formula.plist_path
formula.prefix.mkpath formula.opt_prefix.mkpath
expect(formula).to receive(:plist).and_return("plist") expect(formula).to receive(:plist).and_return("plist")
expect(formula).to receive(:service?).and_return(true) expect(formula).to receive(:service?).and_return(true)

View File

@ -701,7 +701,16 @@ describe Formula do
end end
end end
specify "#service" do 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
specify "service complicated" do
f = formula do f = formula do
url "https://brew.sh/test-1.0.tbz" url "https://brew.sh/test-1.0.tbz"
end end
@ -728,6 +737,18 @@ describe Formula do
expect(f.service).not_to eq(nil) expect(f.service).not_to eq(nil)
end 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 specify "dependencies" do
f1 = formula "f1" do f1 = formula "f1" do
url "f1-1.0" url "f1-1.0"

View File

@ -44,6 +44,15 @@ describe Homebrew::Livecheck do
RUBY RUBY
end 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 describe "::formula_name" do
it "returns the name of the formula" do it "returns the name of the formula" do
expect(livecheck.formula_name(f)).to eq("test") expect(livecheck.formula_name(f)).to eq("test")

View File

@ -264,7 +264,7 @@ describe Homebrew::Livecheck::SkipConditions do
} }
end end
describe "::skip_conditions" do describe "::skip_information" do
context "when a formula without a livecheckable is deprecated" do context "when a formula without a livecheckable is deprecated" do
it "skips" do it "skips" do
expect(skip_conditions.skip_information(formulae[:deprecated])) expect(skip_conditions.skip_information(formulae[:deprecated]))
@ -293,21 +293,21 @@ describe Homebrew::Livecheck::SkipConditions do
end end
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 it "skips" do
expect(skip_conditions.skip_information(formulae[:gist])) expect(skip_conditions.skip_information(formulae[:gist]))
.to eq(status_hashes[:formula][:gist]) .to eq(status_hashes[:formula][:gist])
end end
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 it "skips" do
expect(skip_conditions.skip_information(formulae[:google_code_archive])) expect(skip_conditions.skip_information(formulae[:google_code_archive]))
.to eq(status_hashes[:formula][:google_code_archive]) .to eq(status_hashes[:formula][:google_code_archive])
end end
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 it "skips" do
expect(skip_conditions.skip_information(formulae[:internet_archive])) expect(skip_conditions.skip_information(formulae[:internet_archive]))
.to eq(status_hashes[:formula][:internet_archive]) .to eq(status_hashes[:formula][:internet_archive])
@ -364,6 +364,108 @@ describe Homebrew::Livecheck::SkipConditions do
end end
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 describe "::print_skip_information" do
context "when a formula without a livecheckable is deprecated" do context "when a formula without a livecheckable is deprecated" do
it "prints skip information" 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" expect(version).to eq "1.2.4"
end 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
end end

View File

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

View File

@ -28,6 +28,40 @@ describe Livecheck do
end end
let(:livecheckable_c) { described_class.new(c) } 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 describe "#regex" do
it "returns nil if not set" do it "returns nil if not set" do
expect(livecheckable_f.regex).to be nil expect(livecheckable_f.regex).to be nil
@ -128,6 +162,8 @@ describe Livecheck do
it "returns a Hash of all instance variables" do it "returns a Hash of all instance variables" do
expect(livecheckable_f.to_hash).to eq( expect(livecheckable_f.to_hash).to eq(
{ {
"cask" => nil,
"formula" => nil,
"regex" => nil, "regex" => nil,
"skip" => false, "skip" => false,
"skip_msg" => nil, "skip_msg" => nil,

View File

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

View File

@ -4,6 +4,7 @@
require "context" require "context"
require "erb" require "erb"
require "settings" require "settings"
require "api"
module Utils module Utils
# Helper module for fetching and reporting analytics data. # Helper module for fetching and reporting analytics data.
@ -129,7 +130,12 @@ module Utils
def output(args:, filter: nil) def output(args:, filter: nil)
days = args.days || "30" days = args.days || "30"
category = args.category || "install" 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? return if json.blank? || json["items"].blank?
os_version = category == "os-version" os_version = category == "os-version"
@ -182,17 +188,27 @@ module Utils
end end
def formula_output(f, args:) 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? return if json.blank? || json["analytics"].blank?
get_analytics(json, args: args) get_analytics(json, args: args)
rescue ArgumentError
# Ignore failed API requests
nil
end end
def cask_output(cask, args:) 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? return if json.blank? || json["analytics"].blank?
get_analytics(json, args: args) get_analytics(json, args: args)
rescue ArgumentError
# Ignore failed API requests
nil
end end
sig { returns(String) } sig { returns(String) }
@ -317,18 +333,6 @@ module Utils
Homebrew::Settings.read(key) == "true" Homebrew::Settings.read(key) == "true"
end 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) def format_count(count)
count.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse count.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
end end
@ -336,23 +340,6 @@ module Utils
def format_percent(percent) def format_percent(percent)
format("%<percent>.2f", percent: percent) format("%<percent>.2f", percent: percent)
end 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 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}/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}/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}/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}/extensions/x86_64-darwin-14/2.6.0-static/bootsnap-1.7.7"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.7.5/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.7.7/lib"
$:.unshift "#{path}/" $:.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}/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" $:.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-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-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/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/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/unicode-display_width-2.0.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.18.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.18.4/lib"

View File

@ -1479,6 +1479,8 @@ _brew_outdated() {
--fetch-HEAD --fetch-HEAD
--formula --formula
--greedy --greedy
--greedy-auto-updates
--greedy-latest
--help --help
--json --json
--quiet --quiet
@ -2333,6 +2335,8 @@ _brew_upgrade() {
--force-bottle --force-bottle
--formula --formula
--greedy --greedy
--greedy-auto-updates
--greedy-latest
--help --help
--ignore-pinned --ignore-pinned
--input-methoddir --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 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 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 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 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 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`)' __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 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 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 -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 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 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`)' __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 \ _arguments \
'--debug[Display any debugging information]' \ '--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]' \ '--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]' \ '--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. ]' \ '(--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`)]' \ '(--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)]' \ '--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]' \ '(--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[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]' \ '--help[Show this message]' \
'(--cask)--ignore-pinned[Set a successful exit status even if pinned formulae are not upgraded]' \ '(--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`)]' \ '(--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)--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`)]' \ '(--formula)--vst3-plugindir[Target location for VST3 Plugins (default: `~/Library/Audio/Plug-Ins/VST3`)]' \
- outdated_formula \ - 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_formula:__brew_outdated_formulae' \
- outdated_cask \ - 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]' \ '(--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` 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 ### `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`. 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`. 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 ### 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: 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 ### Install the formula
```sh ```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. `--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) ffi (>= 1.15.0)
eventmachine (1.2.7) eventmachine (1.2.7)
execjs (2.8.1) execjs (2.8.1)
faraday (1.5.1) faraday (1.7.0)
faraday-em_http (~> 1.0) faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0) faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1) faraday-excon (~> 1.1)
@ -34,6 +34,7 @@ GEM
faraday-net_http (~> 1.0) faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.1) faraday-net_http_persistent (~> 1.1)
faraday-patron (~> 1.0) faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
ruby2_keywords (>= 0.0.4) ruby2_keywords (>= 0.0.4)
faraday-em_http (1.0.0) faraday-em_http (1.0.0)
@ -43,10 +44,11 @@ GEM
faraday-net_http (1.0.1) faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0) faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0) faraday-patron (1.0.0)
faraday-rack (1.0.0)
ffi (1.15.3) ffi (1.15.3)
forwardable-extended (2.6.0) forwardable-extended (2.6.0)
gemoji (3.0.1) gemoji (3.0.1)
github-pages (215) github-pages (218)
github-pages-health-check (= 1.17.2) github-pages-health-check (= 1.17.2)
jekyll (= 3.9.0) jekyll (= 3.9.0)
jekyll-avatar (= 0.7.0) jekyll-avatar (= 0.7.0)
@ -67,19 +69,19 @@ GEM
jekyll-seo-tag (= 2.7.1) jekyll-seo-tag (= 2.7.1)
jekyll-sitemap (= 1.4.0) jekyll-sitemap (= 1.4.0)
jekyll-swiss (= 1.0.0) jekyll-swiss (= 1.0.0)
jekyll-theme-architect (= 0.1.1) jekyll-theme-architect (= 0.2.0)
jekyll-theme-cayman (= 0.1.1) jekyll-theme-cayman (= 0.2.0)
jekyll-theme-dinky (= 0.1.1) jekyll-theme-dinky (= 0.2.0)
jekyll-theme-hacker (= 0.1.2) jekyll-theme-hacker (= 0.2.0)
jekyll-theme-leap-day (= 0.1.1) jekyll-theme-leap-day (= 0.2.0)
jekyll-theme-merlot (= 0.1.1) jekyll-theme-merlot (= 0.2.0)
jekyll-theme-midnight (= 0.1.1) jekyll-theme-midnight (= 0.2.0)
jekyll-theme-minimal (= 0.1.1) jekyll-theme-minimal (= 0.2.0)
jekyll-theme-modernist (= 0.1.1) jekyll-theme-modernist (= 0.2.0)
jekyll-theme-primer (= 0.5.4) jekyll-theme-primer (= 0.6.0)
jekyll-theme-slate (= 0.1.1) jekyll-theme-slate (= 0.2.0)
jekyll-theme-tactile (= 0.1.1) jekyll-theme-tactile (= 0.2.0)
jekyll-theme-time-machine (= 0.1.1) jekyll-theme-time-machine (= 0.2.0)
jekyll-titles-from-headings (= 0.5.3) jekyll-titles-from-headings (= 0.5.3)
jemoji (= 0.12.0) jemoji (= 0.12.0)
kramdown (= 2.3.1) kramdown (= 2.3.1)
@ -168,45 +170,45 @@ GEM
jekyll-sitemap (1.4.0) jekyll-sitemap (1.4.0)
jekyll (>= 3.7, < 5.0) jekyll (>= 3.7, < 5.0)
jekyll-swiss (1.0.0) jekyll-swiss (1.0.0)
jekyll-theme-architect (0.1.1) jekyll-theme-architect (0.2.0)
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 (> 3.5, < 5.0) jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0) jekyll-seo-tag (~> 2.0)
jekyll-theme-leap-day (0.1.1) jekyll-theme-cayman (0.2.0)
jekyll (~> 3.5) jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0) jekyll-seo-tag (~> 2.0)
jekyll-theme-merlot (0.1.1) jekyll-theme-dinky (0.2.0)
jekyll (~> 3.5) jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0) jekyll-seo-tag (~> 2.0)
jekyll-theme-midnight (0.1.1) jekyll-theme-hacker (0.2.0)
jekyll (~> 3.5) jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0) jekyll-seo-tag (~> 2.0)
jekyll-theme-minimal (0.1.1) jekyll-theme-leap-day (0.2.0)
jekyll (~> 3.5) jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0) jekyll-seo-tag (~> 2.0)
jekyll-theme-modernist (0.1.1) jekyll-theme-merlot (0.2.0)
jekyll (~> 3.5) jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.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 (> 3.5, < 5.0)
jekyll-github-metadata (~> 2.9) jekyll-github-metadata (~> 2.9)
jekyll-seo-tag (~> 2.0) jekyll-seo-tag (~> 2.0)
jekyll-theme-slate (0.1.1) jekyll-theme-slate (0.2.0)
jekyll (~> 3.5) jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0) jekyll-seo-tag (~> 2.0)
jekyll-theme-tactile (0.1.1) jekyll-theme-tactile (0.2.0)
jekyll (~> 3.5) jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0) jekyll-seo-tag (~> 2.0)
jekyll-theme-time-machine (0.1.1) jekyll-theme-time-machine (0.2.0)
jekyll (~> 3.5) jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0) jekyll-seo-tag (~> 2.0)
jekyll-titles-from-headings (0.5.3) jekyll-titles-from-headings (0.5.3)
jekyll (>= 3.3, < 5.0) jekyll (>= 3.3, < 5.0)
@ -221,19 +223,19 @@ GEM
kramdown-parser-gfm (1.1.0) kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0) kramdown (~> 2.0)
liquid (4.0.3) liquid (4.0.3)
listen (3.5.1) listen (3.6.0)
rb-fsevent (~> 0.10, >= 0.10.3) rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10) rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6) mercenary (0.3.6)
mini_portile2 (2.5.3) mini_portile2 (2.6.1)
minima (2.5.1) minima (2.5.1)
jekyll (>= 3.5, < 5.0) jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9) jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1) jekyll-seo-tag (~> 2.1)
minitest (5.14.4) minitest (5.14.4)
multipart-post (2.1.1) multipart-post (2.1.1)
nokogiri (1.11.7) nokogiri (1.12.2)
mini_portile2 (~> 2.5.0) mini_portile2 (~> 2.6.1)
racc (~> 1.4) racc (~> 1.4)
nokogumbo (2.0.5) nokogumbo (2.0.5)
nokogiri (~> 1.8, >= 1.8.4) 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 - make sure it is one commit per revision bump
- if CI is green and... - if CI is green and...
- formula `bottle :unneeded`, you can merge it through GitHub UI
- bottles need to be pulled, and... - 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, 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` - 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 tests
brew install --build-from-source <CHANGED_FORMULA> brew install --build-from-source <CHANGED_FORMULA>
brew test <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`. 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`". * 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-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. 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`: * `--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`* [...] ### `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`. 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 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)` 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`*] ### `tap` [*`options`*] [*`user`*`/`*`repo`*] [*`URL`*]
@ -703,6 +708,10 @@ upgraded formulae or, every 30 days, for all formulae.
Skip installing cask dependencies. Skip installing cask dependencies.
* `--greedy`: * `--greedy`:
Also include casks with `auto_updates true` or `version :latest`. 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`* [...] ### `uses` [*`options`*] *`formula`* [...]
@ -1981,6 +1990,9 @@ example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just
- `HOMEBREW_GITHUB_PACKAGES_TOKEN` - `HOMEBREW_GITHUB_PACKAGES_TOKEN`
<br>Use this GitHub personal access token when accessing the GitHub Packages Registry (where bottles may be stored). <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` - `HOMEBREW_GITHUB_PACKAGES_USER`
<br>Use this username when accessing the GitHub Packages Registry (where bottles may be stored). <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 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BREW" "1" "July 2021" "Homebrew" "brew" .TH "BREW" "1" "August 2021" "Homebrew" "brew"
. .
.SH "NAME" .SH "NAME"
\fBbrew\fR \- The Missing Package Manager for macOS (or Linux) \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 .TP
\fB\-\-greedy\fR \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 [\.\.\.]" .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\. 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\. 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 .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]" .SS "\fBtap\fR [\fIoptions\fR] [\fIuser\fR\fB/\fR\fIrepo\fR] [\fIURL\fR]"
Tap a formula repository\. Tap a formula repository\.
@ -971,6 +979,14 @@ Skip installing cask dependencies\.
\fB\-\-greedy\fR \fB\-\-greedy\fR
Also include casks with \fBauto_updates true\fR or \fBversion :latest\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 [\.\.\.]" .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\. 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)\. Use this GitHub personal access token when accessing the GitHub Packages Registry (where bottles may be stored)\.
. .
.TP .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 \fBHOMEBREW_GITHUB_PACKAGES_USER\fR
. .
.br .br