Merge remote-tracking branch 'origin/master' into deprecate-cask-commands
This commit is contained in:
commit
f364f0c841
67
.github/workflows/triage.yml
vendored
67
.github/workflows/triage.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
||||
steps:
|
||||
- name: Re-run this workflow
|
||||
if: github.event_name == 'schedule' || github.event.action == 'closed'
|
||||
uses: reitermarkus/rerun-workflow@cf91bee6964dfde64eccbf5600c3ea206af11359
|
||||
uses: reitermarkus/rerun-workflow@e2647e8885422412d5acbd61f9add5b1e77ad3ab
|
||||
with:
|
||||
token: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
|
||||
continuous-label: waiting for feedback
|
||||
@ -101,6 +101,30 @@ jobs:
|
||||
}
|
||||
}
|
||||
|
||||
function offsetDate(start, offsetHours, skippedDays) {
|
||||
let end = new Date(start)
|
||||
|
||||
end.setUTCHours(end.getUTCHours() + (offsetHours % 24))
|
||||
|
||||
while (skippedDays.includes(end.getUTCDay()) || offsetHours >= 24) {
|
||||
if (!skippedDays.includes(end.getUTCDay())) {
|
||||
offsetHours -= 24
|
||||
}
|
||||
|
||||
end.setUTCDate(end.getUTCDate() + 1)
|
||||
}
|
||||
|
||||
if (skippedDays.includes(start.getUTCDay())) {
|
||||
end.setUTCHours(offsetHours, 0, 0)
|
||||
}
|
||||
|
||||
return end
|
||||
}
|
||||
|
||||
function formatDate(date) {
|
||||
return date.toISOString().replace(/\.\d+Z$/, ' UTC').replace('T', ' at ')
|
||||
}
|
||||
|
||||
async function reviewPullRequest(pullRequestNumber) {
|
||||
const { data: pullRequest } = await github.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
@ -108,6 +132,12 @@ jobs:
|
||||
pull_number: pullRequestNumber,
|
||||
})
|
||||
|
||||
const { data: user } = await github.users.getAuthenticated()
|
||||
if (pullRequest.user.login == user) {
|
||||
core.warning('Pull request author is a bot.')
|
||||
return
|
||||
}
|
||||
|
||||
if (pullRequest.author_association != 'MEMBER') {
|
||||
core.warning('Pull request author is not a member.')
|
||||
return
|
||||
@ -120,38 +150,21 @@ jobs:
|
||||
const hasReviewLabel = labels.includes(reviewLabel)
|
||||
const hasCriticalLabel = labels.includes(criticalLabel)
|
||||
|
||||
const reviewStartDate = new Date(pullRequest.created_at)
|
||||
const reviewEndDate = new Date(reviewStartDate)
|
||||
switch (reviewStartDate.getDay()) {
|
||||
// Skip from Friday to Monday and from Saturday to Tuesday.
|
||||
case 5:
|
||||
case 6:
|
||||
reviewEndDate.setDate(reviewStartDate.getDate() + 3)
|
||||
break
|
||||
// Skip from Sunday to Tuesday.
|
||||
case 0:
|
||||
reviewEndDate.setDate(reviewStartDate.getDate() + 2)
|
||||
break
|
||||
default:
|
||||
reviewEndDate.setDate(reviewStartDate.getDate() + 1)
|
||||
break
|
||||
}
|
||||
const offsetHours = 24
|
||||
const skippedDays = [
|
||||
6, // Saturday
|
||||
0, // Sunday
|
||||
]
|
||||
|
||||
const currentDate = new Date()
|
||||
const reviewStartDate = new Date(pullRequest.created_at)
|
||||
const reviewEndDate = offsetDate(reviewStartDate, offsetHours, skippedDays)
|
||||
const reviewEnded = currentDate > reviewEndDate
|
||||
|
||||
function formatDate(date) {
|
||||
return date.toISOString().replace(/\.\d+Z$/, ' UTC').replace('T', ' at ')
|
||||
}
|
||||
|
||||
if (reviewEnded || hasCriticalLabel) {
|
||||
let message
|
||||
if (hasCriticalLabel && !reviewEnded) {
|
||||
if (hasReviewLabel) {
|
||||
message = `Review period cancelled due to \`${criticalLabel}\` label.`
|
||||
} else {
|
||||
message = `Review period skipped due to \`${criticalLabel}\` label.`
|
||||
}
|
||||
message = `Review period skipped due to \`${criticalLabel}\` label.`
|
||||
} else {
|
||||
message = 'Review period ended.'
|
||||
}
|
||||
@ -169,7 +182,7 @@ jobs:
|
||||
await approvePullRequest(pullRequestNumber)
|
||||
} else {
|
||||
const message = `Review period will end on ${formatDate(reviewEndDate)}.`
|
||||
core.warning(message)
|
||||
core.info(message)
|
||||
|
||||
await dismissApprovals(pullRequestNumber, 'Review period has not ended yet.')
|
||||
await createOrUpdateComment(pullRequestNumber, 'review-period-begin', message)
|
||||
|
@ -54,8 +54,8 @@ GEM
|
||||
nokogiri (1.10.10)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
ntlm-http (0.1.1)
|
||||
parallel (1.20.0)
|
||||
parallel_tests (3.3.0)
|
||||
parallel (1.20.1)
|
||||
parallel_tests (3.4.0)
|
||||
parallel
|
||||
parlour (4.0.1)
|
||||
commander (~> 4.5)
|
||||
@ -126,11 +126,11 @@ GEM
|
||||
docile (~> 1.1)
|
||||
simplecov-html (~> 0.11)
|
||||
simplecov-html (0.12.3)
|
||||
sorbet (0.5.6100)
|
||||
sorbet-static (= 0.5.6100)
|
||||
sorbet-runtime (0.5.6100)
|
||||
sorbet (0.5.6101)
|
||||
sorbet-static (= 0.5.6101)
|
||||
sorbet-runtime (0.5.6101)
|
||||
sorbet-runtime-stub (0.2.0)
|
||||
sorbet-static (0.5.6100-universal-darwin-14)
|
||||
sorbet-static (0.5.6101-universal-darwin-14)
|
||||
spoom (1.0.6)
|
||||
colorize
|
||||
sorbet (~> 0.5.5)
|
||||
|
@ -160,7 +160,7 @@ update-preinstall() {
|
||||
fi
|
||||
|
||||
if [[ "$HOMEBREW_COMMAND" = "install" || "$HOMEBREW_COMMAND" = "upgrade" ||
|
||||
"$HOMEBREW_COMMAND" = "bump-formula-pr" ||
|
||||
"$HOMEBREW_COMMAND" = "bump-formula-pr" || "$HOMEBREW_COMMAND" = "bump-cask-pr" ||
|
||||
"$HOMEBREW_COMMAND" = "bundle" ||
|
||||
"$HOMEBREW_COMMAND" = "tap" && $HOMEBREW_ARG_COUNT -gt 1 ||
|
||||
"$HOMEBREW_CASK_COMMAND" = "install" || "$HOMEBREW_CASK_COMMAND" = "upgrade" ]]
|
||||
@ -345,7 +345,7 @@ else
|
||||
: "${HOMEBREW_OS_VERSION:=$(uname -r)}"
|
||||
HOMEBREW_OS_USER_AGENT_VERSION="$HOMEBREW_OS_VERSION"
|
||||
|
||||
if [[ -n $HOMEBREW_FORCE_HOMEBREW_ON_LINUX && -n $HOMEBREW_DEVELOPER && -n $HOMEBREW_ON_DEBIAN7 ]]
|
||||
if [[ -n "$HOMEBREW_FORCE_HOMEBREW_ON_LINUX" && -n "$HOMEBREW_ON_DEBIAN7" ]]
|
||||
then
|
||||
# Special version for our debian 7 docker container used to build patchelf and binutils
|
||||
HOMEBREW_MINIMUM_CURL_VERSION="7.25.0"
|
||||
|
@ -13,9 +13,8 @@ class BuildOptions
|
||||
|
||||
# TODO: rename private_include? when include? is removed.
|
||||
# @deprecated
|
||||
def include?(name)
|
||||
odeprecated "BuildOptions#include?"
|
||||
private_include?("--#{name}")
|
||||
def include?(_)
|
||||
odisabled "BuildOptions#include?"
|
||||
end
|
||||
|
||||
# True if a {Formula} is being built with a specific option.
|
||||
@ -65,11 +64,6 @@ class BuildOptions
|
||||
private_include? "HEAD"
|
||||
end
|
||||
|
||||
# @private
|
||||
def devel?
|
||||
odisabled "BuildOptions#devel?"
|
||||
end
|
||||
|
||||
# True if a {Formula} is being built with {Formula.stable} instead of {Formula.head}.
|
||||
# This is the default.
|
||||
# <pre>args << "--some-beta" if build.head?</pre>
|
||||
@ -81,14 +75,12 @@ class BuildOptions
|
||||
# e.g. on newer Intel Macs this means a combined x86_64/x86 binary/library.
|
||||
# <pre>args << "--universal-binary" if build.universal?</pre>
|
||||
def universal?
|
||||
odeprecated "BuildOptions#universal?"
|
||||
private_include?("universal") && option_defined?("universal")
|
||||
odisabled "BuildOptions#universal?"
|
||||
end
|
||||
|
||||
# True if a {Formula} is being built in C++11 mode.
|
||||
def cxx11?
|
||||
odeprecated "BuildOptions#cxx11?"
|
||||
private_include?("c++11") && option_defined?("c++11")
|
||||
odisabled "BuildOptions#cxx11?"
|
||||
end
|
||||
|
||||
# True if the build has any arguments or options specified.
|
||||
|
@ -63,48 +63,39 @@ module Homebrew
|
||||
end
|
||||
|
||||
def formulae
|
||||
odeprecated "args.formulae", "args.named.to_formulae"
|
||||
named.to_formulae
|
||||
odisabled "args.formulae", "args.named.to_formulae"
|
||||
end
|
||||
|
||||
def formulae_and_casks
|
||||
odeprecated "args.formulae_and_casks", "args.named.to_formulae_and_casks"
|
||||
named.to_formulae_and_casks
|
||||
odisabled "args.formulae_and_casks", "args.named.to_formulae_and_casks"
|
||||
end
|
||||
|
||||
def resolved_formulae
|
||||
odeprecated "args.resolved_formulae", "args.named.to_resolved_formulae"
|
||||
named.to_resolved_formulae
|
||||
odisabled "args.resolved_formulae", "args.named.to_resolved_formulae"
|
||||
end
|
||||
|
||||
def resolved_formulae_casks
|
||||
odeprecated "args.resolved_formulae_casks", "args.named.to_resolved_formulae_to_casks"
|
||||
named.to_resolved_formulae_to_casks
|
||||
odisabled "args.resolved_formulae_casks", "args.named.to_resolved_formulae_to_casks"
|
||||
end
|
||||
|
||||
def formulae_paths
|
||||
odeprecated "args.formulae_paths", "args.named.to_formulae_paths"
|
||||
named.to_formulae_paths
|
||||
odisabled "args.formulae_paths", "args.named.to_formulae_paths"
|
||||
end
|
||||
|
||||
def casks
|
||||
odeprecated "args.casks", "args.named.homebrew_tap_cask_names"
|
||||
named.homebrew_tap_cask_names
|
||||
odisabled "args.casks", "args.named.homebrew_tap_cask_names"
|
||||
end
|
||||
|
||||
def loaded_casks
|
||||
odeprecated "args.loaded_casks", "args.named.to_cask"
|
||||
named.to_casks
|
||||
odisabled "args.loaded_casks", "args.named.to_cask"
|
||||
end
|
||||
|
||||
def kegs
|
||||
odeprecated "args.kegs", "args.named.to_kegs"
|
||||
named.to_kegs
|
||||
odisabled "args.kegs", "args.named.to_kegs"
|
||||
end
|
||||
|
||||
def kegs_casks
|
||||
odeprecated "args.kegs", "args.named.to_kegs_to_casks"
|
||||
named.to_kegs_to_casks
|
||||
odisabled "args.kegs", "args.named.to_kegs_to_casks"
|
||||
end
|
||||
|
||||
def build_stable?
|
||||
|
@ -57,16 +57,7 @@ module Homebrew
|
||||
files["00.tap.out"] = { content: tap }
|
||||
end
|
||||
|
||||
if GitHub.api_credentials_type == :none
|
||||
puts <<~EOS
|
||||
You can create a new personal access token:
|
||||
#{GitHub::ALL_SCOPES_URL}
|
||||
#{Utils::Shell.set_variable_in_profile("HOMEBREW_GITHUB_API_TOKEN", "your_token_here")}
|
||||
|
||||
EOS
|
||||
odeprecated "`brew gist-logs` with a password", "HOMEBREW_GITHUB_API_TOKEN"
|
||||
login!
|
||||
end
|
||||
odisabled "`brew gist-logs` with a password", "HOMEBREW_GITHUB_API_TOKEN" if GitHub.api_credentials_type == :none
|
||||
|
||||
# Description formatted to work well as page title when viewing gist
|
||||
descr = if f.core_formula?
|
||||
|
@ -103,8 +103,7 @@ module Homebrew
|
||||
ls_args << "-t" if args.t?
|
||||
|
||||
if !$stdout.tty? && !args.formula?
|
||||
odeprecated "`brew list` to only list formulae", "`brew list --formula`"
|
||||
safe_system "ls", *ls_args, HOMEBREW_CELLAR
|
||||
odisabled "`brew list` to only list formulae", "`brew list --formula`"
|
||||
else
|
||||
safe_system "ls", *ls_args, HOMEBREW_CELLAR
|
||||
list_casks(args: args) unless args.formula?
|
||||
|
@ -50,16 +50,7 @@ module Homebrew
|
||||
|
||||
case (j = json_version(args.json))
|
||||
when :v1, :default
|
||||
odeprecated "brew outdated --json#{j == :v1 ? "=v1" : ""}", "brew outdated --json=v2"
|
||||
|
||||
outdated = if args.formula? || !args.cask?
|
||||
outdated_formulae args: args
|
||||
else
|
||||
outdated_casks args: args
|
||||
end
|
||||
|
||||
puts JSON.generate(json_info(outdated, args: args))
|
||||
|
||||
odisabled "brew outdated --json#{j == :v1 ? "=v1" : ""}", "brew outdated --json=v2"
|
||||
when :v2
|
||||
formulae, casks = if args.formula?
|
||||
[outdated_formulae(args: args), []]
|
||||
|
@ -32,7 +32,7 @@ module Homebrew
|
||||
|
||||
odie "#{name} not found in the Cellar." unless rack.directory?
|
||||
|
||||
# odeprecated "`brew switch`", "`brew link` @-versioned formulae"
|
||||
odeprecated "`brew switch`", "`brew link` @-versioned formulae"
|
||||
|
||||
versions = rack.subdirs
|
||||
.map { |d| Keg.new(d).version }
|
||||
|
@ -1,12 +1,6 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "compat/dependencies_helpers"
|
||||
require "compat/cli/parser"
|
||||
require "compat/extend/nil"
|
||||
require "compat/extend/string"
|
||||
require "compat/formula"
|
||||
require "compat/global"
|
||||
require "compat/language/java"
|
||||
require "compat/language/python"
|
||||
require "compat/os/mac" if OS.mac?
|
||||
|
@ -1,18 +0,0 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/args"
|
||||
|
||||
module DependenciesHelpers
|
||||
module Compat
|
||||
def argv_includes_ignores(argv = nil)
|
||||
unless @printed_includes_ignores_warning
|
||||
odisabled "Homebrew.argv_includes_ignores", "Homebrew.args_includes_ignores"
|
||||
@printed_includes_ignores_warning = true
|
||||
end
|
||||
args_includes_ignores(argv ? Homebrew::CLI::Args.new : Homebrew.args)
|
||||
end
|
||||
end
|
||||
|
||||
prepend Compat
|
||||
end
|
@ -1,9 +0,0 @@
|
||||
# typed: strict
|
||||
|
||||
module DependenciesHelpers
|
||||
module Compat
|
||||
include Kernel
|
||||
|
||||
def args_includes_ignores(args); end
|
||||
end
|
||||
end
|
@ -1,12 +0,0 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
class NilClass
|
||||
module Compat
|
||||
def chuzzle
|
||||
odisabled ".chuzzle", "&.chomp.presence"
|
||||
end
|
||||
end
|
||||
|
||||
prepend Compat
|
||||
end
|
@ -1,7 +0,0 @@
|
||||
# typed: strict
|
||||
|
||||
class NilClass
|
||||
module Compat
|
||||
include Kernel
|
||||
end
|
||||
end
|
@ -1,12 +0,0 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
class String
|
||||
module Compat
|
||||
def chuzzle
|
||||
odisabled ".chuzzle", "&.chomp.presence"
|
||||
end
|
||||
end
|
||||
|
||||
prepend Compat
|
||||
end
|
@ -1,7 +0,0 @@
|
||||
# typed: strict
|
||||
|
||||
class String
|
||||
module Compat
|
||||
include Kernel
|
||||
end
|
||||
end
|
@ -3,33 +3,20 @@
|
||||
|
||||
class Formula
|
||||
module Compat
|
||||
def installed?
|
||||
odisabled "Formula#installed?",
|
||||
"Formula#latest_version_installed? (or Formula#any_version_installed? )"
|
||||
end
|
||||
|
||||
def prepare_patches
|
||||
odisabled "patches", "patch do" if respond_to?(:patches)
|
||||
super
|
||||
end
|
||||
|
||||
def installed_prefix
|
||||
odeprecated "Formula#installed_prefix",
|
||||
"Formula#latest_installed_prefix (or Formula#any_installed_prefix)"
|
||||
latest_installed_prefix
|
||||
odisabled "Formula#installed_prefix",
|
||||
"Formula#latest_installed_prefix (or Formula#any_installed_prefix)"
|
||||
end
|
||||
|
||||
# The currently installed version for this formula. Will raise an exception
|
||||
# if the formula is not installed.
|
||||
# @private
|
||||
def installed_version
|
||||
odeprecated "Formula#installed_version"
|
||||
Keg.new(latest_installed_prefix).version
|
||||
odisabled "Formula#installed_version"
|
||||
end
|
||||
|
||||
def opt_or_installed_prefix_keg
|
||||
odeprecated "Formula#opt_or_installed_prefix_keg", "Formula#any_installed_keg"
|
||||
any_installed_keg
|
||||
odisabled "Formula#opt_or_installed_prefix_keg", "Formula#any_installed_keg"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -7,8 +7,7 @@ module Homebrew
|
||||
|
||||
def args
|
||||
unless @printed_args_warning
|
||||
odeprecated "Homebrew.args", "`args = <command>_args.parse` and pass `args` along the call chain"
|
||||
@printed_args_warning = true
|
||||
odisabled "Homebrew.args", "`args = <command>_args.parse` and pass `args` along the call chain"
|
||||
end
|
||||
|
||||
@args ||= CLI::Args.new
|
||||
|
@ -4,35 +4,9 @@
|
||||
module Language
|
||||
module Haskell
|
||||
module Cabal
|
||||
module Compat
|
||||
def cabal_sandbox(_options = {})
|
||||
odisabled "Language::Haskell::Cabal.cabal_sandbox"
|
||||
end
|
||||
|
||||
def cabal_sandbox_add_source(*_args)
|
||||
odisabled "Language::Haskell::Cabal.cabal_sandbox_add_source"
|
||||
end
|
||||
|
||||
def cabal_install(*_args)
|
||||
odisabled "Language::Haskell::Cabal.cabal_install",
|
||||
"cabal v2-install directly with std_cabal_v2_args"
|
||||
end
|
||||
|
||||
def cabal_configure(_flags)
|
||||
odisabled "Language::Haskell::Cabal.cabal_configure"
|
||||
end
|
||||
|
||||
def cabal_install_tools(*_tools)
|
||||
odisabled "Language::Haskell::Cabal.cabal_install_tools"
|
||||
end
|
||||
|
||||
def install_cabal_package(*_args, **_options)
|
||||
odisabled "Language::Haskell::Cabal.install_cabal_package",
|
||||
"cabal v2-update directly followed by v2-install with std_cabal_v2_args"
|
||||
end
|
||||
def self.included(_)
|
||||
odisabled "include Language::Haskell::Cabal"
|
||||
end
|
||||
|
||||
prepend Compat
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,17 +0,0 @@
|
||||
# typed: false
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Language
|
||||
module Java
|
||||
class << self
|
||||
module Compat
|
||||
def java_home_cmd(_version = nil)
|
||||
odisabled "Language::Java.java_home_cmd",
|
||||
"Language::Java.java_home or Language::Java.overridable_java_home_env"
|
||||
end
|
||||
end
|
||||
|
||||
prepend Compat
|
||||
end
|
||||
end
|
||||
end
|
@ -1,17 +0,0 @@
|
||||
# typed: false
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Language
|
||||
module Python
|
||||
class << self
|
||||
module Compat
|
||||
def rewrite_python_shebang(_python_path)
|
||||
odisabled "Language::Python.rewrite_python_shebang",
|
||||
"Utils::Shebang.rewrite_shebang and Shebang.python_shebang_rewrite_info(python_path)"
|
||||
end
|
||||
end
|
||||
|
||||
prepend Compat
|
||||
end
|
||||
end
|
||||
end
|
@ -1,24 +0,0 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
module OS
|
||||
module Mac
|
||||
class << self
|
||||
module Compat
|
||||
def preferred_arch
|
||||
odisabled "MacOS.preferred_arch", "Hardware::CPU.arch (or ideally let the compiler handle it)"
|
||||
end
|
||||
|
||||
def tcc_db
|
||||
odisabled "MacOS.tcc_db"
|
||||
end
|
||||
|
||||
def pre_mavericks_accessibility_dotfile
|
||||
odisabled "MacOS.pre_mavericks_accessibility_dotfile"
|
||||
end
|
||||
end
|
||||
|
||||
prepend Compat
|
||||
end
|
||||
end
|
||||
end
|
@ -1,11 +0,0 @@
|
||||
# typed: strict
|
||||
|
||||
module OS
|
||||
module Mac
|
||||
class << self
|
||||
module Compat
|
||||
include Kernel
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -34,15 +34,15 @@ module Context
|
||||
end
|
||||
|
||||
def debug?
|
||||
@debug
|
||||
@debug == true
|
||||
end
|
||||
|
||||
def quiet?
|
||||
@quiet
|
||||
@quiet == true
|
||||
end
|
||||
|
||||
def verbose?
|
||||
@verbose
|
||||
@verbose == true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -180,7 +180,7 @@ module Homebrew
|
||||
except: args.except,
|
||||
spdx_license_data: spdx_license_data,
|
||||
spdx_exception_data: spdx_exception_data,
|
||||
tap_audit_exceptions: f.tap.audit_exceptions,
|
||||
tap_audit_exceptions: f.tap&.audit_exceptions,
|
||||
style_offenses: style_offenses ? style_offenses.for_path(f.path) : nil,
|
||||
display_cop_names: args.display_cop_names?,
|
||||
build_stable: args.build_stable?,
|
||||
|
@ -74,7 +74,7 @@ module Homebrew
|
||||
new_hash = args.sha256
|
||||
|
||||
old_version = cask.version
|
||||
old_hash = cask.sha256
|
||||
old_hash = cask.sha256.to_s
|
||||
|
||||
tap_full_name = cask.tap&.full_name
|
||||
origin_branch = Utils::Git.origin_branch(cask.tap.path) if cask.tap
|
||||
@ -159,7 +159,7 @@ module Homebrew
|
||||
lang_cask = Cask::CaskLoader.load(tmp_contents)
|
||||
lang_cask.config = lang_config
|
||||
lang_url = lang_cask.url.to_s
|
||||
lang_old_hash = lang_cask.sha256
|
||||
lang_old_hash = lang_cask.sha256.to_s
|
||||
|
||||
resource_path = fetch_resource(cask, new_version, lang_url)
|
||||
Utils::Tar.validate_file(resource_path)
|
||||
|
@ -336,7 +336,7 @@ module Homebrew
|
||||
end
|
||||
|
||||
unless args.dry_run?
|
||||
resources_checked = PyPI.update_python_resources! formula, new_formula_version,
|
||||
resources_checked = PyPI.update_python_resources! formula, version: new_formula_version,
|
||||
silent: args.quiet?, ignore_non_pypi_packages: true
|
||||
end
|
||||
|
||||
|
@ -6,6 +6,7 @@ require "formula_creator"
|
||||
require "missing_formula"
|
||||
require "cli/parser"
|
||||
require "utils/pypi"
|
||||
require "cask/cask_loader"
|
||||
|
||||
module Homebrew
|
||||
extend T::Sig
|
||||
@ -18,14 +19,16 @@ module Homebrew
|
||||
usage_banner <<~EOS
|
||||
`create` [<options>] <URL>
|
||||
|
||||
Generate a formula for the downloadable file at <URL> and open it in the editor.
|
||||
Homebrew will attempt to automatically derive the formula name and version, but
|
||||
if it fails, you'll have to make your own template. The `wget` formula serves as
|
||||
a simple example. For the complete API, see:
|
||||
Generate a formula or, with `--cask`, a cask for the downloadable file at <URL>
|
||||
and open it in the editor. Homebrew will attempt to automatically derive the
|
||||
formula name and version, but if it fails, you'll have to make your own template.
|
||||
The `wget` formula serves as a simple example. For the complete API, see:
|
||||
<https://rubydoc.brew.sh/Formula>
|
||||
EOS
|
||||
switch "--autotools",
|
||||
description: "Create a basic template for an Autotools-style build."
|
||||
switch "--cask",
|
||||
description: "Create a basic template for a cask."
|
||||
switch "--cmake",
|
||||
description: "Create a basic template for a CMake-style build."
|
||||
switch "--crystal",
|
||||
@ -51,9 +54,10 @@ module Homebrew
|
||||
switch "--HEAD",
|
||||
description: "Indicate that <URL> points to the package's repository rather than a file."
|
||||
flag "--set-name=",
|
||||
description: "Explicitly set the <name> of the new formula."
|
||||
description: "Explicitly set the <name> of the new formula or cask.",
|
||||
required_for: "--cask"
|
||||
flag "--set-version=",
|
||||
description: "Explicitly set the <version> of the new formula."
|
||||
description: "Explicitly set the <version> of the new formula or cask."
|
||||
flag "--set-license=",
|
||||
description: "Explicitly set the <license> of the new formula."
|
||||
flag "--tap=",
|
||||
@ -61,7 +65,12 @@ module Homebrew
|
||||
switch "-f", "--force",
|
||||
description: "Ignore errors for disallowed formula names and names that shadow aliases."
|
||||
|
||||
conflicts "--autotools", "--cmake", "--crystal", "--go", "--meson", "--node", "--perl", "--python", "--rust"
|
||||
conflicts "--autotools", "--cmake", "--crystal", "--go", "--meson", "--node",
|
||||
"--perl", "--python", "--ruby", "--rust", "--cask"
|
||||
conflicts "--cask", "--HEAD"
|
||||
conflicts "--cask", "--set-license"
|
||||
conflicts "--cask", "--tap"
|
||||
|
||||
named 1
|
||||
end
|
||||
end
|
||||
@ -70,24 +79,73 @@ module Homebrew
|
||||
def create
|
||||
args = create_args.parse
|
||||
|
||||
# Ensure that the cache exists so we can fetch the tarball
|
||||
HOMEBREW_CACHE.mkpath
|
||||
path = if args.cask?
|
||||
create_cask(args: args)
|
||||
else
|
||||
create_formula(args: args)
|
||||
end
|
||||
|
||||
url = args.named.first # Pull the first (and only) url from ARGV
|
||||
exec_editor path
|
||||
end
|
||||
|
||||
version = args.set_version
|
||||
name = args.set_name
|
||||
license = args.set_license
|
||||
tap = args.tap
|
||||
def create_cask(args:)
|
||||
url = args.named.first
|
||||
|
||||
if (token = args.set_name).nil?
|
||||
raise UsageError, "The `--set-name` flag is required for creating casks."
|
||||
end
|
||||
|
||||
cask_path = Cask::CaskLoader.path(token)
|
||||
raise Cask::CaskAlreadyCreatedError, token if cask_path.exist?
|
||||
|
||||
version = if args.set_version
|
||||
Version.create(args.set_version)
|
||||
else
|
||||
Version.detect(url.gsub(token, ""))
|
||||
end
|
||||
|
||||
interpolated_url, sha256 = if version.null?
|
||||
[url, ""]
|
||||
else
|
||||
sha256 = if args.no_fetch?
|
||||
""
|
||||
else
|
||||
strategy = DownloadStrategyDetector.detect(url)
|
||||
downloader = strategy.new(url, token, version.to_s, cache: Cask::Cache.path)
|
||||
downloader.fetch
|
||||
downloader.cached_location.sha256
|
||||
end
|
||||
|
||||
[url.gsub(version.to_s, "\#{version}"), sha256]
|
||||
end
|
||||
|
||||
cask_path.atomic_write <<~RUBY
|
||||
cask "#{token}" do
|
||||
version "#{version}"
|
||||
sha256 "#{sha256}"
|
||||
|
||||
url "#{interpolated_url}"
|
||||
name ""
|
||||
desc ""
|
||||
homepage ""
|
||||
|
||||
app ""
|
||||
end
|
||||
RUBY
|
||||
|
||||
puts "Please run `brew audit --cask --new #{token}` before submitting, thanks."
|
||||
cask_path
|
||||
end
|
||||
|
||||
def create_formula(args:)
|
||||
fc = FormulaCreator.new(args)
|
||||
fc.name = name
|
||||
fc.version = version
|
||||
fc.license = license
|
||||
fc.tap = Tap.fetch(tap || "homebrew/core")
|
||||
fc.name = args.name
|
||||
fc.version = args.version
|
||||
fc.license = args.license
|
||||
fc.tap = Tap.fetch(args.tap || "homebrew/core")
|
||||
raise TapUnavailableError, tap unless fc.tap.installed?
|
||||
|
||||
fc.url = url
|
||||
fc.url = args.named.first # Pull the first (and only) url from ARGV
|
||||
|
||||
fc.mode = if args.cmake?
|
||||
:cmake
|
||||
@ -143,8 +201,8 @@ module Homebrew
|
||||
|
||||
PyPI.update_python_resources! Formula[fc.name], ignore_non_pypi_packages: true if args.python?
|
||||
|
||||
puts "Please run `brew audit --new-formula #{fc.name}` before submitting, thanks."
|
||||
exec_editor fc.path
|
||||
puts "Please run `brew audit --new #{fc.name}` before submitting, thanks."
|
||||
fc.path
|
||||
end
|
||||
|
||||
def __gets
|
||||
|
@ -25,13 +25,14 @@ module Homebrew
|
||||
description: "Explicitly set the <version> of the package being installed."
|
||||
|
||||
max_named 0
|
||||
hide_from_man_page!
|
||||
end
|
||||
end
|
||||
|
||||
def diy
|
||||
args = diy_args.parse
|
||||
|
||||
# odeprecated "`brew diy`"
|
||||
odeprecated "`brew diy`"
|
||||
|
||||
path = Pathname.getwd
|
||||
|
||||
|
@ -25,7 +25,6 @@ module Homebrew
|
||||
description: "Upload to Bintray, but don't publish."
|
||||
|
||||
min_named :formula
|
||||
hide_from_man_page!
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -50,7 +50,8 @@ module Homebrew
|
||||
depends_on: "--autosquash",
|
||||
description: "Message to include when autosquashing revision bumps, deletions, and rebuilds."
|
||||
flag "--workflow=",
|
||||
description: "Retrieve artifacts from the specified workflow (default: `tests.yml`)."
|
||||
description: "Retrieve artifacts from the specified workflow (default: `tests.yml`). "\
|
||||
"Legacy: use --workflows instead"
|
||||
flag "--artifact=",
|
||||
description: "Download artifacts with the specified name (default: `bottles`)."
|
||||
flag "--bintray-org=",
|
||||
@ -62,6 +63,11 @@ module Homebrew
|
||||
flag "--bintray-mirror=",
|
||||
description: "Use the specified Bintray repository to automatically mirror stable URLs "\
|
||||
"defined in the formulae (default: `mirror`)."
|
||||
comma_array "--workflows=",
|
||||
description: "Retrieve artifacts from the specified workflow (default: `tests.yml`) "\
|
||||
"Comma-separated list to include multiple workflows."
|
||||
comma_array "--ignore-missing-artifacts=",
|
||||
description: "Comma-separated list of workflows which can be ignored if they have not been run."
|
||||
|
||||
conflicts "--clean", "--autosquash"
|
||||
min_named 1
|
||||
@ -357,7 +363,13 @@ module Homebrew
|
||||
def pr_pull
|
||||
args = pr_pull_args.parse
|
||||
|
||||
workflow = args.workflow || "tests.yml"
|
||||
odeprecated "`brew pr-pull --workflow`", "`brew pr-pull --workflows=`" if args.workflow.presence
|
||||
|
||||
workflows = if args.workflow.blank?
|
||||
args.workflows.presence || ["tests.yml"]
|
||||
else
|
||||
[args.workflow].compact.presence || ["tests.yml"]
|
||||
end
|
||||
artifact = args.artifact || "bottles"
|
||||
bintray_org = args.bintray_org || "homebrew"
|
||||
mirror_repo = args.bintray_mirror || "mirror"
|
||||
@ -401,8 +413,22 @@ module Homebrew
|
||||
next
|
||||
end
|
||||
|
||||
url = GitHub.get_artifact_url(user, repo, pr, workflow_id: workflow, artifact_name: artifact)
|
||||
download_artifact(url, dir, pr)
|
||||
workflows.each do |workflow|
|
||||
workflow_run = GitHub.get_workflow_run(
|
||||
user, repo, pr, workflow_id: workflow, artifact_name: artifact
|
||||
)
|
||||
if args.ignore_missing_artifacts.present? &&
|
||||
args.ignore_missing_artifacts.include?(workflow) &&
|
||||
workflow_run.empty?
|
||||
# Ignore that workflow as it was not executed and we specified
|
||||
# that we could skip it.
|
||||
next
|
||||
end
|
||||
|
||||
ohai "Downloading bottles for workflow: #{workflow}"
|
||||
url = GitHub.get_artifact_url(workflow_run)
|
||||
download_artifact(url, dir, pr)
|
||||
end
|
||||
|
||||
next if args.no_upload?
|
||||
|
||||
|
@ -1,52 +0,0 @@
|
||||
# typed: false
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "net/http"
|
||||
require "net/https"
|
||||
require "json"
|
||||
require "cli/parser"
|
||||
require "formula"
|
||||
require "formulary"
|
||||
require "version"
|
||||
require "pkg_version"
|
||||
require "formula_info"
|
||||
|
||||
module Homebrew
|
||||
extend T::Sig
|
||||
|
||||
module_function
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def pull_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
usage_banner <<~EOS
|
||||
`pull` [<options>] <patch>
|
||||
|
||||
Get a patch from a GitHub commit or pull request and apply it to Homebrew.
|
||||
|
||||
Each <patch> may be the number of a pull request in `homebrew/core`
|
||||
or the URL of any pull request or commit on GitHub.
|
||||
EOS
|
||||
switch "--bump",
|
||||
description: "For one-formula PRs, automatically reword commit message to our preferred format."
|
||||
switch "--clean",
|
||||
description: "Do not rewrite or otherwise modify the commits found in the pulled PR."
|
||||
switch "--ignore-whitespace",
|
||||
description: "Silently ignore whitespace discrepancies when applying diffs."
|
||||
switch "--resolve",
|
||||
description: "When a patch fails to apply, leave in progress and allow user to resolve, instead "\
|
||||
"of aborting."
|
||||
switch "--branch-okay",
|
||||
description: "Do not warn if pulling to a branch besides master (useful for testing)."
|
||||
switch "--no-pbcopy",
|
||||
description: "Do not copy anything to the system clipboard."
|
||||
|
||||
min_named 1
|
||||
hide_from_man_page!
|
||||
end
|
||||
end
|
||||
|
||||
def pull
|
||||
odisabled "brew pull", "gh pr checkout"
|
||||
end
|
||||
end
|
@ -54,7 +54,9 @@ module Homebrew
|
||||
safe_system(ENV["SHELL"], args.named.first)
|
||||
else
|
||||
subshell = if ENV["SHELL"].include?("zsh")
|
||||
"PS1='brew %B%F{green}%~%f%b$ ' #{ENV["SHELL"]} -d"
|
||||
"PS1='brew %B%F{green}%~%f%b$ ' #{ENV["SHELL"]} -d -f"
|
||||
elsif ENV["SHELL"].include?("bash")
|
||||
"PS1=\"brew \\[\\033[1;32m\\]\\w\\[\\033[0m\\]$ \" #{ENV["SHELL"]} --noprofile --norc"
|
||||
else
|
||||
"PS1=\"brew \\[\\033[1;32m\\]\\w\\[\\033[0m\\]$ \" #{ENV["SHELL"]}"
|
||||
end
|
||||
|
@ -26,6 +26,13 @@ module Homebrew
|
||||
flag "--version=",
|
||||
description: "Use the specified <version> when finding resources for <formula>. "\
|
||||
"If no version is specified, the current version for <formula> will be used."
|
||||
flag "--package-name=",
|
||||
description: "Use the specified <package-name> when finding resources for <formula>. "\
|
||||
"If no package name is specified, it will be inferred from the formula's stable URL."
|
||||
comma_array "--extra-packages=",
|
||||
description: "Include these additional packages when finding resources."
|
||||
comma_array "--exclude-packages=",
|
||||
description: "Exclude these packages when finding resources."
|
||||
|
||||
min_named :formula
|
||||
end
|
||||
@ -35,7 +42,13 @@ module Homebrew
|
||||
args = update_python_resources_args.parse
|
||||
|
||||
args.named.to_formulae.each do |formula|
|
||||
PyPI.update_python_resources! formula, args.version, print_only: args.print_only?, silent: args.silent?,
|
||||
PyPI.update_python_resources! formula,
|
||||
version: args.version,
|
||||
package_name: args.package_name,
|
||||
extra_packages: args.extra_packages,
|
||||
exclude_packages: args.exclude_packages,
|
||||
print_only: args.print_only?,
|
||||
silent: args.silent?,
|
||||
ignore_non_pypi_packages: args.ignore_non_pypi_packages?
|
||||
end
|
||||
end
|
||||
|
@ -351,6 +351,7 @@ module Homebrew
|
||||
end
|
||||
|
||||
# Needs a custom implementation.
|
||||
sig { returns(String) }
|
||||
def make_jobs
|
||||
jobs = ENV["HOMEBREW_MAKE_JOBS"].to_i
|
||||
return jobs.to_s if jobs.positive?
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "hardware"
|
||||
@ -7,11 +7,22 @@ require "extend/ENV/shared"
|
||||
require "extend/ENV/std"
|
||||
require "extend/ENV/super"
|
||||
|
||||
def superenv?(env)
|
||||
env != "std" && Superenv.bin
|
||||
module Kernel
|
||||
extend T::Sig
|
||||
|
||||
sig { params(env: T.nilable(String)).returns(T::Boolean) }
|
||||
def superenv?(env)
|
||||
return false if env == "std"
|
||||
|
||||
!Superenv.bin.nil?
|
||||
end
|
||||
private :superenv?
|
||||
end
|
||||
|
||||
module EnvActivation
|
||||
extend T::Sig
|
||||
|
||||
sig { params(env: T.nilable(String)).void }
|
||||
def activate_extensions!(env: nil)
|
||||
if superenv?(env)
|
||||
extend(Superenv)
|
||||
@ -20,25 +31,41 @@ module EnvActivation
|
||||
end
|
||||
end
|
||||
|
||||
def with_build_environment(env: nil, cc: nil, build_bottle: false, bottle_arch: nil)
|
||||
sig do
|
||||
params(
|
||||
env: T.nilable(String),
|
||||
cc: T.nilable(String),
|
||||
build_bottle: T.nilable(T::Boolean),
|
||||
bottle_arch: T.nilable(String),
|
||||
_block: T.proc.returns(T.untyped),
|
||||
).returns(T.untyped)
|
||||
end
|
||||
def with_build_environment(env: nil, cc: nil, build_bottle: false, bottle_arch: nil, &_block)
|
||||
old_env = to_hash.dup
|
||||
tmp_env = to_hash.dup.extend(EnvActivation)
|
||||
tmp_env.activate_extensions!(env: env)
|
||||
tmp_env.setup_build_environment(cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch)
|
||||
T.cast(tmp_env, EnvActivation).activate_extensions!(env: env)
|
||||
T.cast(tmp_env, T.any(Superenv, Stdenv))
|
||||
.setup_build_environment(cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch)
|
||||
replace(tmp_env)
|
||||
yield
|
||||
ensure
|
||||
replace(old_env)
|
||||
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
replace(old_env)
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(key: T.any(String, Symbol)).returns(T::Boolean) }
|
||||
def sensitive?(key)
|
||||
/(cookie|key|token|password)/i =~ key
|
||||
key.match?(/(cookie|key|token|password)/i)
|
||||
end
|
||||
|
||||
sig { returns(T::Hash[String, String]) }
|
||||
def sensitive_environment
|
||||
select { |key, _| sensitive?(key) }
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def clear_sensitive_environment!
|
||||
each_key { |key| delete key if sensitive?(key) }
|
||||
end
|
||||
|
49
Library/Homebrew/extend/ENV.rbi
Normal file
49
Library/Homebrew/extend/ENV.rbi
Normal file
@ -0,0 +1,49 @@
|
||||
# typed: strict
|
||||
|
||||
module EnvMethods
|
||||
include Kernel
|
||||
|
||||
sig { params(key: String).returns(T::Boolean) }
|
||||
def key?(key); end
|
||||
|
||||
sig { params(key: String).returns(T.nilable(String)) }
|
||||
def [](key); end
|
||||
|
||||
sig { params(key: String).returns(String) }
|
||||
def fetch(key); end
|
||||
|
||||
sig { params(key: String, value: T.nilable(T.any(String, PATH))).returns(T.nilable(String)) }
|
||||
def []=(key, value); end
|
||||
|
||||
sig { params(block: T.proc.params(arg0: [String, String]).returns(T::Boolean)).returns(T::Hash[String, String]) }
|
||||
def select(&block); end
|
||||
|
||||
sig { params(block: T.proc.params(arg0: String).void).void }
|
||||
def each_key(&block); end
|
||||
|
||||
sig { params(key: String).returns(T.nilable(String)) }
|
||||
def delete(key); end
|
||||
|
||||
sig do
|
||||
params(other: T.any(T::Hash[String, String], Sorbet::Private::Static::ENVClass))
|
||||
.returns(Sorbet::Private::Static::ENVClass)
|
||||
end
|
||||
def replace(other); end
|
||||
|
||||
sig { returns(T::Hash[String, String]) }
|
||||
def to_hash; end
|
||||
end
|
||||
|
||||
module EnvActivation
|
||||
include EnvMethods
|
||||
end
|
||||
|
||||
class Sorbet
|
||||
module Private
|
||||
module Static
|
||||
class ENVClass
|
||||
include EnvActivation
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "compilers"
|
||||
@ -11,13 +11,16 @@ require "development_tools"
|
||||
# @see Stdenv
|
||||
# @see https://www.rubydoc.info/stdlib/Env Ruby's ENV API
|
||||
module SharedEnvExtension
|
||||
extend T::Sig
|
||||
|
||||
include CompilerConstants
|
||||
|
||||
# @private
|
||||
CC_FLAG_VARS = %w[CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS].freeze
|
||||
# @private
|
||||
private_constant :CC_FLAG_VARS
|
||||
|
||||
FC_FLAG_VARS = %w[FCFLAGS FFLAGS].freeze
|
||||
# @private
|
||||
private_constant :FC_FLAG_VARS
|
||||
|
||||
SANITIZED_VARS = %w[
|
||||
CDPATH CLICOLOR_FORCE
|
||||
CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH
|
||||
@ -28,8 +31,16 @@ module SharedEnvExtension
|
||||
GOBIN GOPATH GOROOT PERL_MB_OPT PERL_MM_OPT
|
||||
LIBRARY_PATH LD_LIBRARY_PATH LD_PRELOAD LD_RUN_PATH
|
||||
].freeze
|
||||
private_constant :SANITIZED_VARS
|
||||
|
||||
# @private
|
||||
sig do
|
||||
params(
|
||||
formula: T.nilable(Formula),
|
||||
cc: T.nilable(String),
|
||||
build_bottle: T.nilable(T::Boolean),
|
||||
bottle_arch: T.nilable(T::Boolean),
|
||||
).void
|
||||
end
|
||||
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil)
|
||||
@formula = formula
|
||||
@cc = cc
|
||||
@ -37,57 +48,62 @@ module SharedEnvExtension
|
||||
@bottle_arch = bottle_arch
|
||||
reset
|
||||
end
|
||||
private :setup_build_environment
|
||||
|
||||
# @private
|
||||
sig { void }
|
||||
def reset
|
||||
SANITIZED_VARS.each { |k| delete(k) }
|
||||
end
|
||||
private :reset
|
||||
|
||||
sig { returns(T::Hash[String, String]) }
|
||||
def remove_cc_etc
|
||||
keys = %w[CC CXX OBJC OBJCXX LD CPP CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS LDFLAGS CPPFLAGS]
|
||||
removed = Hash[*keys.flat_map { |key| [key, self[key]] }]
|
||||
keys.each do |key|
|
||||
delete(key)
|
||||
end
|
||||
removed
|
||||
keys.map { |key| [key, delete(key)] }.to_h
|
||||
end
|
||||
|
||||
sig { params(newflags: String).void }
|
||||
def append_to_cflags(newflags)
|
||||
append(CC_FLAG_VARS, newflags)
|
||||
end
|
||||
|
||||
sig { params(val: T.any(Regexp, String)).void }
|
||||
def remove_from_cflags(val)
|
||||
remove CC_FLAG_VARS, val
|
||||
end
|
||||
|
||||
sig { params(value: String).void }
|
||||
def append_to_cccfg(value)
|
||||
append("HOMEBREW_CCCFG", value, "")
|
||||
end
|
||||
|
||||
sig { params(keys: T.any(String, T::Array[String]), value: T.untyped, separator: String).void }
|
||||
def append(keys, value, separator = " ")
|
||||
value = value.to_s
|
||||
Array(keys).each do |key|
|
||||
old = self[key]
|
||||
if old.nil? || old.empty?
|
||||
self[key] = value
|
||||
old_value = self[key]
|
||||
self[key] = if old_value.nil? || old_value.empty?
|
||||
value
|
||||
else
|
||||
self[key] += separator + value
|
||||
old_value + separator + value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(keys: T.any(String, T::Array[String]), value: T.untyped, separator: String).void }
|
||||
def prepend(keys, value, separator = " ")
|
||||
value = value.to_s
|
||||
Array(keys).each do |key|
|
||||
old = self[key]
|
||||
self[key] = if old.nil? || old.empty?
|
||||
old_value = self[key]
|
||||
self[key] = if old_value.nil? || old_value.empty?
|
||||
value
|
||||
else
|
||||
value + separator + old
|
||||
value + separator + old_value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(key: String, path: String).void }
|
||||
def append_path(key, path)
|
||||
self[key] = PATH.new(self[key]).append(path)
|
||||
end
|
||||
@ -99,61 +115,78 @@ module SharedEnvExtension
|
||||
# Prepending a system path such as /usr/bin is a no-op so that requirements
|
||||
# don't accidentally override superenv shims or formulae's `bin` directories.
|
||||
# <pre>ENV.prepend_path "PATH", which("emacs").dirname</pre>
|
||||
sig { params(key: String, path: String).void }
|
||||
def prepend_path(key, path)
|
||||
return if %w[/usr/bin /bin /usr/sbin /sbin].include? path.to_s
|
||||
|
||||
self[key] = PATH.new(self[key]).prepend(path)
|
||||
end
|
||||
|
||||
sig { params(key: String, path: T.any(String, Pathname)).void }
|
||||
def prepend_create_path(key, path)
|
||||
path = Pathname.new(path) unless path.is_a? Pathname
|
||||
path = Pathname(path)
|
||||
path.mkpath
|
||||
prepend_path key, path
|
||||
end
|
||||
|
||||
sig { params(keys: T.any(String, T::Array[String]), value: T.untyped).void }
|
||||
def remove(keys, value)
|
||||
return if value.nil?
|
||||
|
||||
Array(keys).each do |key|
|
||||
next unless self[key]
|
||||
old_value = self[key]
|
||||
next if old_value.nil?
|
||||
|
||||
self[key] = self[key].sub(value, "")
|
||||
delete(key) if self[key].empty?
|
||||
new_value = old_value.sub(value, "")
|
||||
if new_value.empty?
|
||||
delete(key)
|
||||
else
|
||||
self[key] = new_value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def cc
|
||||
self["CC"]
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def cxx
|
||||
self["CXX"]
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def cflags
|
||||
self["CFLAGS"]
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def cxxflags
|
||||
self["CXXFLAGS"]
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def cppflags
|
||||
self["CPPFLAGS"]
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def ldflags
|
||||
self["LDFLAGS"]
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def fc
|
||||
self["FC"]
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def fflags
|
||||
self["FFLAGS"]
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def fcflags
|
||||
self["FCFLAGS"]
|
||||
end
|
||||
@ -164,8 +197,7 @@ module SharedEnvExtension
|
||||
# # modify CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS in one go:
|
||||
# ENV.append_to_cflags "-I ./missing/includes"
|
||||
# end</pre>
|
||||
#
|
||||
# @return [Symbol]
|
||||
sig { returns(T.any(Symbol, String)) }
|
||||
def compiler
|
||||
@compiler ||= if (cc = @cc)
|
||||
warn_about_non_apple_gcc(cc) if cc.match?(GNU_GCC_REGEXP)
|
||||
@ -189,27 +221,31 @@ module SharedEnvExtension
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
sig { returns(T.any(String, Pathname)) }
|
||||
def determine_cc
|
||||
COMPILER_SYMBOL_MAP.invert.fetch(compiler, compiler)
|
||||
end
|
||||
private :determine_cc
|
||||
|
||||
COMPILERS.each do |compiler|
|
||||
define_method(compiler) do
|
||||
@compiler = compiler
|
||||
self.cc = determine_cc
|
||||
self.cxx = determine_cxx
|
||||
|
||||
send(:cc=, send(:determine_cc))
|
||||
send(:cxx=, send(:determine_cxx))
|
||||
end
|
||||
end
|
||||
|
||||
# Snow Leopard defines an NCURSES value the opposite of most distros.
|
||||
# @see https://bugs.python.org/issue6848
|
||||
# Currently only used by aalib in core.
|
||||
sig { void }
|
||||
def ncurses_define
|
||||
append "CPPFLAGS", "-DNCURSES_OPAQUE=0"
|
||||
end
|
||||
|
||||
# @private
|
||||
sig { void }
|
||||
def userpaths!
|
||||
path = PATH.new(self["PATH"]).select do |p|
|
||||
# put Superenv.bin and opt path at the first
|
||||
@ -228,6 +264,7 @@ module SharedEnvExtension
|
||||
self["PATH"] = path
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def fortran
|
||||
# Ignore repeated calls to this function as it will misleadingly warn about
|
||||
# building with an alternative Fortran compiler without optimization flags,
|
||||
@ -260,6 +297,7 @@ module SharedEnvExtension
|
||||
end
|
||||
|
||||
# @private
|
||||
sig { returns(Symbol) }
|
||||
def effective_arch
|
||||
if @build_bottle && @bottle_arch
|
||||
@bottle_arch.to_sym
|
||||
@ -269,6 +307,7 @@ module SharedEnvExtension
|
||||
end
|
||||
|
||||
# @private
|
||||
sig { params(name: String).returns(Formula) }
|
||||
def gcc_version_formula(name)
|
||||
version = name[GNU_GCC_REGEXP, 1]
|
||||
gcc_version_name = "gcc@#{version}"
|
||||
@ -282,6 +321,7 @@ module SharedEnvExtension
|
||||
end
|
||||
|
||||
# @private
|
||||
sig { params(name: String).void }
|
||||
def warn_about_non_apple_gcc(name)
|
||||
begin
|
||||
gcc_formula = gcc_version_formula(name)
|
||||
@ -299,30 +339,40 @@ module SharedEnvExtension
|
||||
EOS
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def permit_arch_flags; end
|
||||
|
||||
# A no-op until we enable this by default again (which we may never do).
|
||||
sig { void }
|
||||
def permit_weak_imports; end
|
||||
|
||||
# @private
|
||||
sig { params(cc: T.any(Symbol, String)).returns(T::Boolean) }
|
||||
def compiler_any_clang?(cc = compiler)
|
||||
%w[clang llvm_clang].include?(cc.to_s)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
sig { params(_flags: T::Array[String], _map: T::Hash[Symbol, String]).void }
|
||||
def set_cpu_flags(_flags, _map = {}); end
|
||||
|
||||
sig { params(val: T.any(String, Pathname)).returns(String) }
|
||||
def cc=(val)
|
||||
self["CC"] = self["OBJC"] = val.to_s
|
||||
end
|
||||
|
||||
sig { params(val: T.any(String, Pathname)).returns(String) }
|
||||
def cxx=(val)
|
||||
self["CXX"] = self["OBJCXX"] = val.to_s
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def homebrew_cc
|
||||
self["HOMEBREW_CC"]
|
||||
end
|
||||
|
||||
sig { params(value: String, source: String).returns(Symbol) }
|
||||
def fetch_compiler(value, source)
|
||||
COMPILER_SYMBOL_MAP.fetch(value) do |other|
|
||||
case other
|
||||
@ -334,10 +384,9 @@ module SharedEnvExtension
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def check_for_compiler_universal_support
|
||||
return unless homebrew_cc.match?(GNU_GCC_REGEXP)
|
||||
|
||||
raise "Non-Apple GCC can't build universal binaries"
|
||||
raise "Non-Apple GCC can't build universal binaries" if homebrew_cc&.match?(GNU_GCC_REGEXP)
|
||||
end
|
||||
end
|
||||
|
||||
|
15
Library/Homebrew/extend/ENV/shared.rbi
Normal file
15
Library/Homebrew/extend/ENV/shared.rbi
Normal file
@ -0,0 +1,15 @@
|
||||
# typed: strict
|
||||
|
||||
module SharedEnvExtension
|
||||
include EnvMethods
|
||||
end
|
||||
|
||||
class Sorbet
|
||||
module Private
|
||||
module Static
|
||||
class ENVClass
|
||||
include SharedEnvExtension
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "hardware"
|
||||
@ -14,8 +14,16 @@ module Stdenv
|
||||
SAFE_CFLAGS_FLAGS = "-w -pipe"
|
||||
|
||||
# @private
|
||||
def setup_build_environment(**options)
|
||||
super(**options)
|
||||
sig do
|
||||
params(
|
||||
formula: T.nilable(Formula),
|
||||
cc: T.nilable(String),
|
||||
build_bottle: T.nilable(T::Boolean),
|
||||
bottle_arch: T.nilable(T::Boolean),
|
||||
).void
|
||||
end
|
||||
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil)
|
||||
super
|
||||
|
||||
self["HOMEBREW_ENV"] = "std"
|
||||
|
||||
@ -49,13 +57,14 @@ module Stdenv
|
||||
|
||||
send(compiler)
|
||||
|
||||
return unless cc.match?(GNU_GCC_REGEXP)
|
||||
return unless cc&.match?(GNU_GCC_REGEXP)
|
||||
|
||||
gcc_formula = gcc_version_formula(cc)
|
||||
append_path "PATH", gcc_formula.opt_bin.to_s
|
||||
end
|
||||
alias generic_setup_build_environment setup_build_environment
|
||||
|
||||
sig { returns(T::Array[Pathname]) }
|
||||
def homebrew_extra_pkg_config_paths
|
||||
[]
|
||||
end
|
||||
@ -73,10 +82,11 @@ module Stdenv
|
||||
# Removes the MAKEFLAGS environment variable, causing make to use a single job.
|
||||
# This is useful for makefiles with race conditions.
|
||||
# When passed a block, MAKEFLAGS is removed only for the duration of the block and is restored after its completion.
|
||||
def deparallelize
|
||||
sig { params(block: T.proc.returns(T.untyped)).returns(T.untyped) }
|
||||
def deparallelize(&block)
|
||||
old = self["MAKEFLAGS"]
|
||||
remove "MAKEFLAGS", /-j\d+/
|
||||
if block_given?
|
||||
if block
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
@ -89,30 +99,33 @@ module Stdenv
|
||||
|
||||
%w[O3 O2 O1 O0 Os].each do |opt|
|
||||
define_method opt do
|
||||
remove_from_cflags(/-O./)
|
||||
append_to_cflags "-#{opt}"
|
||||
send(:remove_from_cflags, /-O./)
|
||||
send(:append_to_cflags, "-#{opt}")
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
sig { returns(T.any(String, Pathname)) }
|
||||
def determine_cc
|
||||
s = super
|
||||
DevelopmentTools.locate(s) || Pathname.new(s)
|
||||
DevelopmentTools.locate(s) || Pathname(s)
|
||||
end
|
||||
private :determine_cc
|
||||
|
||||
# @private
|
||||
sig { returns(Pathname) }
|
||||
def determine_cxx
|
||||
dir, base = determine_cc.split
|
||||
dir, base = Pathname(determine_cc).split
|
||||
dir/base.to_s.sub("gcc", "g++").sub("clang", "clang++")
|
||||
end
|
||||
private :determine_cxx
|
||||
|
||||
GNU_GCC_VERSIONS.each do |n|
|
||||
define_method(:"gcc-#{n}") do
|
||||
super()
|
||||
set_cpu_cflags
|
||||
send(:set_cpu_cflags)
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def clang
|
||||
super()
|
||||
replace_in_cflags(/-Xarch_#{Hardware::CPU.arch_32_bit} (-march=\S*)/, '\1')
|
||||
@ -124,16 +137,19 @@ module Stdenv
|
||||
set_cpu_cflags(map)
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def m64
|
||||
append_to_cflags "-m64"
|
||||
append "LDFLAGS", "-arch #{Hardware::CPU.arch_64_bit}"
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def m32
|
||||
append_to_cflags "-m32"
|
||||
append "LDFLAGS", "-arch #{Hardware::CPU.arch_32_bit}"
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def universal_binary
|
||||
check_for_compiler_universal_support
|
||||
|
||||
@ -141,33 +157,38 @@ module Stdenv
|
||||
append "LDFLAGS", Hardware::CPU.universal_archs.as_arch_flags
|
||||
|
||||
return if compiler_any_clang?
|
||||
return unless Hardware.is_32_bit?
|
||||
return unless Hardware::CPU.is_32_bit?
|
||||
|
||||
# Can't mix "-march" for a 32-bit CPU with "-arch x86_64"
|
||||
replace_in_cflags(/-march=\S*/, "-Xarch_#{Hardware::CPU.arch_32_bit} \\0")
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def cxx11
|
||||
append "CXX", "-std=c++11"
|
||||
libcxx
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def libcxx
|
||||
append "CXX", "-stdlib=libc++" if compiler == :clang
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def libstdcxx
|
||||
append "CXX", "-stdlib=libstdc++" if compiler == :clang
|
||||
end
|
||||
|
||||
# @private
|
||||
sig { params(before: Regexp, after: String).void }
|
||||
def replace_in_cflags(before, after)
|
||||
CC_FLAG_VARS.each do |key|
|
||||
self[key] = self[key].sub(before, after) if key?(key)
|
||||
self[key] = fetch(key).sub(before, after) if key?(key)
|
||||
end
|
||||
end
|
||||
|
||||
# Convenience method to set all C compiler flags in one shot.
|
||||
sig { params(val: String).void }
|
||||
def define_cflags(val)
|
||||
CC_FLAG_VARS.each { |key| self[key] = val }
|
||||
end
|
||||
@ -175,6 +196,7 @@ module Stdenv
|
||||
# Sets architecture-specific flags for every environment variable
|
||||
# given in the list `flags`.
|
||||
# @private
|
||||
sig { params(flags: T::Array[String], map: T::Hash[Symbol, String]).void }
|
||||
def set_cpu_flags(flags, map = Hardware::CPU.optimization_flags)
|
||||
cflags =~ /(-Xarch_#{Hardware::CPU.arch_32_bit} )-march=/
|
||||
xarch = Regexp.last_match(1).to_s
|
||||
@ -186,19 +208,23 @@ module Stdenv
|
||||
append flags, map.fetch(effective_arch)
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def x11; end
|
||||
|
||||
# @private
|
||||
sig { params(map: T::Hash[Symbol, String]).void }
|
||||
def set_cpu_cflags(map = Hardware::CPU.optimization_flags) # rubocop:disable Naming/AccessorMethodName
|
||||
set_cpu_flags(CC_FLAG_VARS, map)
|
||||
end
|
||||
|
||||
sig { returns(Integer) }
|
||||
def make_jobs
|
||||
Homebrew::EnvConfig.make_jobs.to_i
|
||||
end
|
||||
|
||||
# This method does nothing in stdenv since there's no arg refurbishment
|
||||
# @private
|
||||
sig { void }
|
||||
def refurbish_args; end
|
||||
end
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "extend/ENV/shared"
|
||||
@ -22,6 +22,7 @@ module Superenv
|
||||
# @private
|
||||
attr_accessor :keg_only_deps, :deps, :run_time_deps, :x11
|
||||
|
||||
sig { params(base: Superenv).void }
|
||||
def self.extended(base)
|
||||
base.keg_only_deps = []
|
||||
base.deps = []
|
||||
@ -29,8 +30,10 @@ module Superenv
|
||||
end
|
||||
|
||||
# @private
|
||||
sig { returns(T.nilable(Pathname)) }
|
||||
def self.bin; end
|
||||
|
||||
sig { void }
|
||||
def reset
|
||||
super
|
||||
# Configure scripts generated by autoconf 2.61 or later export as_nl, which
|
||||
@ -39,8 +42,16 @@ module Superenv
|
||||
end
|
||||
|
||||
# @private
|
||||
def setup_build_environment(**options)
|
||||
super(**options)
|
||||
sig do
|
||||
params(
|
||||
formula: T.nilable(Formula),
|
||||
cc: T.nilable(String),
|
||||
build_bottle: T.nilable(T::Boolean),
|
||||
bottle_arch: T.nilable(T::Boolean),
|
||||
).void
|
||||
end
|
||||
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil)
|
||||
super
|
||||
send(compiler)
|
||||
|
||||
self["HOMEBREW_ENV"] = "super"
|
||||
@ -89,18 +100,22 @@ module Superenv
|
||||
|
||||
private
|
||||
|
||||
sig { params(val: T.any(String, Pathname)).returns(String) }
|
||||
def cc=(val)
|
||||
self["HOMEBREW_CC"] = super
|
||||
end
|
||||
|
||||
sig { params(val: T.any(String, Pathname)).returns(String) }
|
||||
def cxx=(val)
|
||||
self["HOMEBREW_CXX"] = super
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def determine_cxx
|
||||
determine_cc.to_s.gsub("gcc", "g++").gsub("clang", "clang++")
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Pathname]) }
|
||||
def homebrew_extra_paths
|
||||
[]
|
||||
end
|
||||
@ -115,7 +130,7 @@ module Superenv
|
||||
path.append("/usr/bin", "/bin", "/usr/sbin", "/sbin")
|
||||
|
||||
begin
|
||||
path.append(gcc_version_formula(homebrew_cc).opt_bin) if homebrew_cc.match?(GNU_GCC_REGEXP)
|
||||
path.append(gcc_version_formula(T.must(homebrew_cc)).opt_bin) if homebrew_cc&.match?(GNU_GCC_REGEXP)
|
||||
rescue FormulaUnavailableError
|
||||
# Don't fail and don't add these formulae to the path if they don't exist.
|
||||
nil
|
||||
@ -124,6 +139,7 @@ module Superenv
|
||||
path.existing
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Pathname]) }
|
||||
def homebrew_extra_pkg_config_paths
|
||||
[]
|
||||
end
|
||||
@ -143,6 +159,7 @@ module Superenv
|
||||
).existing
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Pathname]) }
|
||||
def homebrew_extra_aclocal_paths
|
||||
[]
|
||||
end
|
||||
@ -156,6 +173,7 @@ module Superenv
|
||||
).existing
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Pathname]) }
|
||||
def homebrew_extra_isystem_paths
|
||||
[]
|
||||
end
|
||||
@ -173,6 +191,7 @@ module Superenv
|
||||
PATH.new(keg_only_deps.map(&:opt_include)).existing
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Pathname]) }
|
||||
def homebrew_extra_library_paths
|
||||
[]
|
||||
end
|
||||
@ -187,6 +206,7 @@ module Superenv
|
||||
PATH.new(paths).existing
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def determine_dependencies
|
||||
deps.map(&:name).join(",")
|
||||
end
|
||||
@ -199,6 +219,7 @@ module Superenv
|
||||
).existing
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Pathname]) }
|
||||
def homebrew_extra_cmake_include_paths
|
||||
[]
|
||||
end
|
||||
@ -208,6 +229,7 @@ module Superenv
|
||||
PATH.new(homebrew_extra_cmake_include_paths).existing
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Pathname]) }
|
||||
def homebrew_extra_cmake_library_paths
|
||||
[]
|
||||
end
|
||||
@ -217,6 +239,7 @@ module Superenv
|
||||
PATH.new(homebrew_extra_cmake_library_paths).existing
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Pathname]) }
|
||||
def homebrew_extra_cmake_frameworks_paths
|
||||
[]
|
||||
end
|
||||
@ -229,14 +252,17 @@ module Superenv
|
||||
).existing
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def determine_make_jobs
|
||||
Homebrew::EnvConfig.make_jobs
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def determine_optflags
|
||||
Hardware::CPU.optimization_flags.fetch(effective_arch)
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def determine_cccfg
|
||||
""
|
||||
end
|
||||
@ -246,9 +272,10 @@ module Superenv
|
||||
# Removes the MAKEFLAGS environment variable, causing make to use a single job.
|
||||
# This is useful for makefiles with race conditions.
|
||||
# When passed a block, MAKEFLAGS is removed only for the duration of the block and is restored after its completion.
|
||||
def deparallelize
|
||||
sig { params(block: T.proc.returns(T.untyped)).returns(T.untyped) }
|
||||
def deparallelize(&block)
|
||||
old = delete("MAKEFLAGS")
|
||||
if block_given?
|
||||
if block
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
@ -259,56 +286,64 @@ module Superenv
|
||||
old
|
||||
end
|
||||
|
||||
sig { returns(Integer) }
|
||||
def make_jobs
|
||||
self["MAKEFLAGS"] =~ /-\w*j(\d+)/
|
||||
[Regexp.last_match(1).to_i, 1].max
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def universal_binary
|
||||
check_for_compiler_universal_support
|
||||
|
||||
self["HOMEBREW_ARCHFLAGS"] = Hardware::CPU.universal_archs.as_arch_flags
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def permit_arch_flags
|
||||
append_to_cccfg "K"
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def m32
|
||||
append "HOMEBREW_ARCHFLAGS", "-m32"
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def m64
|
||||
append "HOMEBREW_ARCHFLAGS", "-m64"
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def cxx11
|
||||
append_to_cccfg "x"
|
||||
append_to_cccfg "g" if homebrew_cc == "clang"
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def libcxx
|
||||
append_to_cccfg "g" if compiler == :clang
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def libstdcxx
|
||||
append_to_cccfg "h" if compiler == :clang
|
||||
end
|
||||
|
||||
# @private
|
||||
sig { void }
|
||||
def refurbish_args
|
||||
append_to_cccfg "O"
|
||||
end
|
||||
|
||||
%w[O3 O2 O1 O0 Os].each do |opt|
|
||||
define_method opt do
|
||||
self["HOMEBREW_OPTIMIZATION_LEVEL"] = opt
|
||||
send(:[]=, "HOMEBREW_OPTIMIZATION_LEVEL", opt)
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def set_x11_env_if_installed; end
|
||||
|
||||
def set_cpu_flags(_arg0, _arg1 = "", _arg2 = {}); end
|
||||
end
|
||||
|
||||
require "extend/os/extend/ENV/super"
|
||||
|
@ -27,7 +27,7 @@ module Superenv
|
||||
|
||||
def homebrew_extra_paths
|
||||
paths = []
|
||||
paths << MacOS::XQuartz.bin.to_s if x11?
|
||||
paths << MacOS::XQuartz.bin if x11?
|
||||
paths
|
||||
end
|
||||
|
||||
|
@ -69,7 +69,7 @@ module Hardware
|
||||
# conflict between what `uname` reports and the underlying `sysctl` flags,
|
||||
# since the `sysctl` flags don't change behaviour under Rosetta 2.
|
||||
def in_rosetta2?
|
||||
intel? && physical_cpu_arm64?
|
||||
sysctl_bool("sysctl.proc_translated")
|
||||
end
|
||||
|
||||
def features
|
||||
|
@ -26,14 +26,14 @@ class JavaRequirement < Requirement
|
||||
end
|
||||
|
||||
def java_home_cmd
|
||||
# TODO: enable for all macOS versions and Linux on next minor release
|
||||
# TODO: disable for all macOS versions and Linux on next minor release
|
||||
# but --version with ranges is broken on Big Sur today.
|
||||
if MacOS.version >= :big_sur && @version&.end_with?("+")
|
||||
odisabled %Q(depends_on java: "#{@version}"),
|
||||
'depends_on "openjdk@11", depends_on "openjdk@8" or depends_on "openjdk"'
|
||||
end
|
||||
# odeprecated "depends_on :java",
|
||||
# 'depends_on "openjdk@11", depends_on "openjdk@8" or depends_on "openjdk"'
|
||||
odeprecated "depends_on :java",
|
||||
'depends_on "openjdk@11", depends_on "openjdk@8" or depends_on "openjdk"'
|
||||
|
||||
return unless File.executable?("/usr/libexec/java_home")
|
||||
|
||||
|
@ -113,11 +113,6 @@ class Formula
|
||||
# @private
|
||||
attr_reader :stable
|
||||
|
||||
# @private
|
||||
def devel
|
||||
odisabled "Formula#devel"
|
||||
end
|
||||
|
||||
# The HEAD {SoftwareSpec} for this {Formula}.
|
||||
# Installed when using `brew install --HEAD`.
|
||||
# This is always installed with the version `HEAD` and taken from the latest
|
||||
@ -328,11 +323,6 @@ class Formula
|
||||
active_spec == stable
|
||||
end
|
||||
|
||||
# @private
|
||||
def devel?
|
||||
odisabled "Formula#devel?"
|
||||
end
|
||||
|
||||
# Is the currently active {SoftwareSpec} a {#head} build?
|
||||
# @private
|
||||
def head?
|
||||
@ -2227,10 +2217,6 @@ class Formula
|
||||
raise "You cannot override Formula#brew in class #{name}"
|
||||
when :test
|
||||
define_method(:test_defined?) { true }
|
||||
when :patches
|
||||
odisabled "a Formula#patches definition", "'patch do' block calls"
|
||||
when :options
|
||||
odisabled "a Formula#options definition", "'option do' block calls"
|
||||
end
|
||||
end
|
||||
|
||||
@ -2274,10 +2260,7 @@ class Formula
|
||||
if args.nil?
|
||||
@licenses
|
||||
else
|
||||
if args.is_a? Array
|
||||
odeprecated "`license [...]`", "`license any_of: [...]`"
|
||||
args = { any_of: args }
|
||||
end
|
||||
odisabled "`license [...]`", "`license any_of: [...]`" if args.is_a? Array
|
||||
@licenses = args
|
||||
end
|
||||
end
|
||||
@ -2463,11 +2446,6 @@ class Formula
|
||||
@stable.instance_eval(&block)
|
||||
end
|
||||
|
||||
# @private
|
||||
def devel
|
||||
odisabled "'devel' blocks in formulae", "'head' blocks or @-versioned formulae"
|
||||
end
|
||||
|
||||
# @!attribute [w] head
|
||||
# Adds a {.head} {SoftwareSpec}.
|
||||
# This can be installed by passing the `--HEAD` option to allow
|
||||
|
@ -1,6 +1,7 @@
|
||||
# typed: false
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "deprecate_disable"
|
||||
require "formula_text_auditor"
|
||||
require "resource_auditor"
|
||||
|
||||
@ -325,6 +326,11 @@ module Homebrew
|
||||
|
||||
return if version_conflicts.empty?
|
||||
|
||||
return if formula.disabled?
|
||||
|
||||
return if formula.deprecated? &&
|
||||
formula.deprecation_reason != DeprecateDisable::DEPRECATE_DISABLE_REASONS[:versioned_formula]
|
||||
|
||||
problem <<~EOS
|
||||
#{formula.full_name} contains conflicting version recursive dependencies:
|
||||
#{version_conflicts.to_a.join ", "}
|
||||
|
@ -225,12 +225,12 @@ module Formulary
|
||||
|
||||
def load_file(flags:)
|
||||
if %r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(?:/Formula)?/(?<formula_name>[\w+-.@]+).rb} =~ url # rubocop:disable Style/CaseLikeIf
|
||||
odisabled "Installation of #{formula_name} from a GitHub commit URL",
|
||||
"'brew extract #{formula_name}' to stable tap on GitHub"
|
||||
raise UsageError, "Installation of #{formula_name} from a GitHub commit URL is unsupported! " \
|
||||
"'brew extract #{formula_name}' to stable tap on GitHub instead."
|
||||
elsif url.match?(%r{^(https?|ftp)://})
|
||||
odisabled "Non-checksummed download of #{name} formula file from an arbitrary URL",
|
||||
"'brew extract' or 'brew create' and 'brew tap-new' to create a "\
|
||||
"formula file in a tap on GitHub"
|
||||
raise UsageError, "Non-checksummed download of #{name} formula file from an arbitrary URL is unsupported! ",
|
||||
"'brew extract' or 'brew create' and 'brew tap-new' to create a "\
|
||||
"formula file in a tap on GitHub instead."
|
||||
end
|
||||
HOMEBREW_CACHE_FORMULA.mkpath
|
||||
FileUtils.rm_f(path)
|
||||
|
@ -7,7 +7,7 @@ module Language
|
||||
# @api public
|
||||
module Python
|
||||
def self.major_minor_version(python)
|
||||
version = /\d\.\d/.match `#{python} --version 2>&1`
|
||||
version = /\d\.\d+/.match `#{python} --version 2>&1`
|
||||
return unless version
|
||||
|
||||
Version.create(version.to_s)
|
||||
|
@ -44,13 +44,6 @@ module OS
|
||||
Version.new "11.0"
|
||||
end
|
||||
|
||||
def latest_stable_version
|
||||
# TODO: bump version when new macOS is released and also update
|
||||
# references in docs/Installation.md and
|
||||
# https://github.com/Homebrew/install/blob/HEAD/install.sh
|
||||
Version.new "11.0"
|
||||
end
|
||||
|
||||
def outdated_release?
|
||||
# TODO: bump version when new macOS is released and also update
|
||||
# references in docs/Installation.md and
|
||||
@ -59,7 +52,10 @@ module OS
|
||||
end
|
||||
|
||||
def prerelease?
|
||||
version > latest_stable_version
|
||||
# TODO: bump version when new macOS is released or announced
|
||||
# and also update references in docs/Installation.md and
|
||||
# https://github.com/Homebrew/install/blob/HEAD/install.sh
|
||||
version >= "12.0"
|
||||
end
|
||||
|
||||
def languages
|
||||
|
@ -22,7 +22,7 @@ module OS
|
||||
def latest_version
|
||||
latest_stable = "12.2"
|
||||
case MacOS.version
|
||||
when "11.0" then latest_stable
|
||||
when /^11\./ then latest_stable
|
||||
when "10.15" then "12.2"
|
||||
when "10.14" then "11.3.1"
|
||||
when "10.13" then "10.1"
|
||||
@ -45,7 +45,7 @@ module OS
|
||||
sig { returns(String) }
|
||||
def minimum_version
|
||||
case MacOS.version
|
||||
when "11.0" then "12.2"
|
||||
when /^11\./ then "12.2"
|
||||
when "10.15" then "11.0"
|
||||
when "10.14" then "10.2"
|
||||
when "10.13" then "9.0"
|
||||
@ -275,7 +275,7 @@ module OS
|
||||
sig { returns(String) }
|
||||
def latest_clang_version
|
||||
case MacOS.version
|
||||
when "11.0", "10.15" then "1200.0.32.27"
|
||||
when /^11\./, "10.15" then "1200.0.32.27"
|
||||
when "10.14" then "1100.0.33.17"
|
||||
when "10.13" then "1000.10.44.2"
|
||||
when "10.12" then "900.0.39.2"
|
||||
@ -291,7 +291,7 @@ module OS
|
||||
sig { returns(String) }
|
||||
def minimum_version
|
||||
case MacOS.version
|
||||
when "11.0" then "12.0.0"
|
||||
when /^11\./ then "12.0.0"
|
||||
when "10.15" then "11.0.0"
|
||||
when "10.14" then "10.0.0"
|
||||
when "10.13" then "9.0.0"
|
||||
|
@ -41,14 +41,8 @@ module Patch
|
||||
else
|
||||
{}
|
||||
end.each_pair do |strip, urls|
|
||||
Array(urls).each do |url|
|
||||
patch = case url
|
||||
when :DATA
|
||||
DATAPatch.new(strip)
|
||||
else
|
||||
LegacyPatch.new(strip, url)
|
||||
end
|
||||
patches << patch
|
||||
Array(urls).each do
|
||||
patches << DATAPatch.new(strip)
|
||||
end
|
||||
end
|
||||
|
||||
@ -196,15 +190,3 @@ class ExternalPatch
|
||||
"#<#{self.class.name}: #{strip.inspect} #{url.inspect}>"
|
||||
end
|
||||
end
|
||||
|
||||
# A legacy patch.
|
||||
#
|
||||
# Legacy patches have no checksum and are not cached.
|
||||
#
|
||||
# @api private
|
||||
class LegacyPatch < ExternalPatch
|
||||
def initialize(strip, _url)
|
||||
odisabled "legacy patches", "'patch do' blocks"
|
||||
super(strip)
|
||||
end
|
||||
end
|
||||
|
@ -34,6 +34,9 @@ class JavaRequirement < Requirement
|
||||
end
|
||||
|
||||
def initialize(tags = [])
|
||||
odeprecated "depends_on :java",
|
||||
'"depends_on "openjdk@11", "depends_on "openjdk@8" or "depends_on "openjdk"'
|
||||
|
||||
@version = tags.shift if tags.first&.match?(/^\d/)
|
||||
super(tags)
|
||||
@cask = suggestion.token
|
||||
|
@ -14,16 +14,10 @@ class MacOSRequirement < Requirement
|
||||
attr_reader :comparator, :version
|
||||
|
||||
def initialize(tags = [], comparator: ">=")
|
||||
begin
|
||||
@version = if comparator == "==" && tags.first.respond_to?(:map)
|
||||
tags.shift.map { |s| MacOS::Version.from_symbol(s) }
|
||||
else
|
||||
MacOS::Version.from_symbol(tags.shift) unless tags.empty?
|
||||
end
|
||||
rescue MacOSVersionError => e
|
||||
raise if e.version != :mavericks
|
||||
|
||||
odisabled "depends_on :macos => :mavericks"
|
||||
@version = if comparator == "==" && tags.first.respond_to?(:map)
|
||||
tags.shift.map { |s| MacOS::Version.from_symbol(s) }
|
||||
else
|
||||
MacOS::Version.from_symbol(tags.shift) unless tags.empty?
|
||||
end
|
||||
|
||||
@comparator = comparator
|
||||
|
@ -150,6 +150,8 @@ module RuboCop
|
||||
|
||||
valid_node ||= child.method_name.to_s == "patch"
|
||||
valid_node ||= child.method_name.to_s == "resource"
|
||||
valid_node ||= child.method_name.to_s == "deprecate!"
|
||||
valid_node ||= child.method_name.to_s == "disable!"
|
||||
|
||||
@offensive_node = on_os_block
|
||||
@offense_source_range = on_os_block.source_range
|
||||
|
@ -95,21 +95,6 @@ module RuboCop
|
||||
end
|
||||
end
|
||||
|
||||
find_strings(body_node).each do |n|
|
||||
next unless regex_match_group(n, /JAVA_HOME/i)
|
||||
|
||||
next if @formula_name.match?(/^openjdk(@|$)/)
|
||||
|
||||
next if find_every_method_call_by_name(body_node, :depends_on).any? do |dependency|
|
||||
dependency.each_descendant(:str).count.zero? ||
|
||||
regex_match_group(dependency.each_descendant(:str).first, /^openjdk(@|$)/) ||
|
||||
depends_on?(:java)
|
||||
end
|
||||
|
||||
offending_node(n)
|
||||
problem "Use `depends_on :java` to set JAVA_HOME"
|
||||
end
|
||||
|
||||
prefix_path(body_node) do |prefix_node, path|
|
||||
next unless match = path.match(%r{^(bin|include|libexec|lib|sbin|share|Frameworks)(?:/| |$)})
|
||||
|
||||
|
21
Library/Homebrew/sorbet/plugins/delegate.rb
Normal file
21
Library/Homebrew/sorbet/plugins/delegate.rb
Normal file
@ -0,0 +1,21 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
source = ARGV[5]
|
||||
|
||||
methods = if (single = source[/delegate\s+([^:]+):\s+/, 1])
|
||||
[single]
|
||||
else
|
||||
multiple = source[/delegate\s+\[(.*?)\]\s+=>\s+/m, 1]
|
||||
non_comments = multiple.gsub(/\#.*$/, "")
|
||||
non_comments.scan(/:([^:,\s]+)/).flatten
|
||||
end
|
||||
|
||||
methods.each do |method|
|
||||
puts <<~RUBY
|
||||
# typed: strict
|
||||
|
||||
sig {params(arg0: T.untyped).returns(T.untyped)}
|
||||
def #{method}(*arg0); end
|
||||
RUBY
|
||||
end
|
@ -3,7 +3,8 @@
|
||||
|
||||
source = ARGV[5]
|
||||
|
||||
/\busing +Magic\b/.match(source) do |_|
|
||||
case source[/\Ausing\s+(.*)\Z/, 1]
|
||||
when "Magic"
|
||||
puts <<-RUBY
|
||||
# typed: strict
|
||||
|
||||
@ -18,4 +19,13 @@ source = ARGV[5]
|
||||
def zipinfo; end
|
||||
end
|
||||
RUBY
|
||||
when "HashValidator"
|
||||
puts <<-RUBY
|
||||
# typed: strict
|
||||
|
||||
class ::Hash
|
||||
sig { params(valid_keys: T.untyped).void }
|
||||
def assert_valid_keys!(*valid_keys); end
|
||||
end
|
||||
RUBY
|
||||
end
|
@ -5841,22 +5841,6 @@ module Cask::Utils
|
||||
extend ::T::Private::Methods::SingletonMethodHooks
|
||||
end
|
||||
|
||||
class Caveats
|
||||
def empty?(*args, &block); end
|
||||
|
||||
def to_s(*args, &block); end
|
||||
end
|
||||
|
||||
class Checksum
|
||||
def [](*args, &block); end
|
||||
|
||||
def empty?(*args, &block); end
|
||||
|
||||
def length(*args, &block); end
|
||||
|
||||
def to_s(*args, &block); end
|
||||
end
|
||||
|
||||
class Class
|
||||
def any_instance(); end
|
||||
|
||||
@ -11897,14 +11881,6 @@ module MachO
|
||||
def self.open(filename); end
|
||||
end
|
||||
|
||||
module MachOShim
|
||||
def delete_rpath(*args, &block); end
|
||||
|
||||
def dylib_id(*args, &block); end
|
||||
|
||||
def rpaths(*args, &block); end
|
||||
end
|
||||
|
||||
Markdown = RDiscount
|
||||
|
||||
module Marshal
|
||||
@ -15369,18 +15345,6 @@ class Pathname
|
||||
extend ::T::Private::Methods::SingletonMethodHooks
|
||||
end
|
||||
|
||||
class PkgVersion
|
||||
def major(*args, &block); end
|
||||
|
||||
def major_minor(*args, &block); end
|
||||
|
||||
def major_minor_patch(*args, &block); end
|
||||
|
||||
def minor(*args, &block); end
|
||||
|
||||
def patch(*args, &block); end
|
||||
end
|
||||
|
||||
class Proc
|
||||
include ::MethodSource::SourceLocation::ProcExtensions
|
||||
include ::MethodSource::MethodExtensions
|
||||
@ -28595,6 +28559,7 @@ class Socket
|
||||
IPV6_PATHMTU = ::T.let(nil, ::T.untyped)
|
||||
IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped)
|
||||
IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped)
|
||||
IP_DONTFRAG = ::T.let(nil, ::T.untyped)
|
||||
IP_PORTRANGE = ::T.let(nil, ::T.untyped)
|
||||
IP_RECVDSTADDR = ::T.let(nil, ::T.untyped)
|
||||
IP_RECVIF = ::T.let(nil, ::T.untyped)
|
||||
@ -28686,6 +28651,7 @@ module Socket::Constants
|
||||
IPV6_PATHMTU = ::T.let(nil, ::T.untyped)
|
||||
IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped)
|
||||
IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped)
|
||||
IP_DONTFRAG = ::T.let(nil, ::T.untyped)
|
||||
IP_PORTRANGE = ::T.let(nil, ::T.untyped)
|
||||
IP_RECVDSTADDR = ::T.let(nil, ::T.untyped)
|
||||
IP_RECVIF = ::T.let(nil, ::T.untyped)
|
||||
@ -29246,6 +29212,11 @@ end
|
||||
class SynchronizedDelegator
|
||||
end
|
||||
|
||||
class SystemCommand::Result
|
||||
extend ::T::Private::Methods::MethodHooks
|
||||
extend ::T::Private::Methods::SingletonMethodHooks
|
||||
end
|
||||
|
||||
class SystemCommand
|
||||
extend ::T::Private::Methods::MethodHooks
|
||||
extend ::T::Private::Methods::SingletonMethodHooks
|
||||
|
@ -2,5 +2,6 @@ ruby_extra_args:
|
||||
- --disable-gems
|
||||
|
||||
triggers:
|
||||
using: sorbet/plugins/unpack_strategy_magic.rb
|
||||
using: sorbet/plugins/using.rb
|
||||
attr_predicate: sorbet/plugins/attr_predicate.rb
|
||||
delegate: sorbet/plugins/delegate.rb
|
||||
|
@ -9,7 +9,6 @@ require "shellwords"
|
||||
require "extend/io"
|
||||
require "extend/predicable"
|
||||
require "extend/hash_validator"
|
||||
using HashValidator
|
||||
|
||||
# Class for running sub-processes and capturing their output and exit status.
|
||||
#
|
||||
@ -17,14 +16,16 @@ using HashValidator
|
||||
class SystemCommand
|
||||
extend T::Sig
|
||||
|
||||
using HashValidator
|
||||
|
||||
# Helper functions for calling {SystemCommand.run}.
|
||||
module Mixin
|
||||
def system_command(*args)
|
||||
SystemCommand.run(*args)
|
||||
T.unsafe(SystemCommand).run(*args)
|
||||
end
|
||||
|
||||
def system_command!(*args)
|
||||
SystemCommand.run!(*args)
|
||||
T.unsafe(SystemCommand).run!(*args)
|
||||
end
|
||||
end
|
||||
|
||||
@ -34,11 +35,11 @@ class SystemCommand
|
||||
attr_reader :pid
|
||||
|
||||
def self.run(executable, **options)
|
||||
new(executable, **options).run!
|
||||
T.unsafe(self).new(executable, **options).run!
|
||||
end
|
||||
|
||||
def self.run!(command, **options)
|
||||
run(command, **options, must_succeed: true)
|
||||
T.unsafe(self).run(command, **options, must_succeed: true)
|
||||
end
|
||||
|
||||
sig { returns(SystemCommand::Result) }
|
||||
@ -63,45 +64,61 @@ class SystemCommand
|
||||
result
|
||||
end
|
||||
|
||||
sig do
|
||||
params(
|
||||
executable: T.any(String, Pathname),
|
||||
args: T::Array[T.any(String, Integer, Float, URI::Generic)],
|
||||
sudo: T::Boolean,
|
||||
env: T::Hash[String, String],
|
||||
input: T.any(String, T::Array[String]),
|
||||
must_succeed: T::Boolean,
|
||||
print_stdout: T::Boolean,
|
||||
print_stderr: T::Boolean,
|
||||
verbose: T::Boolean,
|
||||
secrets: T::Array[String],
|
||||
chdir: T.any(String, Pathname),
|
||||
).void
|
||||
end
|
||||
def initialize(executable, args: [], sudo: false, env: {}, input: [], must_succeed: false,
|
||||
print_stdout: false, print_stderr: true, verbose: false, secrets: [], **options)
|
||||
print_stdout: false, print_stderr: true, verbose: false, secrets: [], chdir: T.unsafe(nil))
|
||||
require "extend/ENV"
|
||||
@executable = executable
|
||||
@args = args
|
||||
@sudo = sudo
|
||||
@input = Array(input)
|
||||
@print_stdout = print_stdout
|
||||
@print_stderr = print_stderr
|
||||
@verbose = verbose
|
||||
@secrets = (Array(secrets) + ENV.sensitive_environment.values).uniq
|
||||
@must_succeed = must_succeed
|
||||
options.assert_valid_keys!(:chdir)
|
||||
@options = options
|
||||
@env = env
|
||||
|
||||
@env.each_key do |name|
|
||||
env.each_key do |name|
|
||||
next if /^[\w&&\D]\w*$/.match?(name)
|
||||
|
||||
raise ArgumentError, "Invalid variable name: '#{name}'"
|
||||
end
|
||||
@env = env
|
||||
@input = Array(input)
|
||||
@must_succeed = must_succeed
|
||||
@print_stdout = print_stdout
|
||||
@print_stderr = print_stderr
|
||||
@verbose = verbose
|
||||
@secrets = (Array(secrets) + ENV.sensitive_environment.values).uniq
|
||||
@chdir = chdir
|
||||
end
|
||||
|
||||
sig { returns(T::Array[String]) }
|
||||
def command
|
||||
[*sudo_prefix, *env_args, executable.to_s, *expanded_args]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :executable, :args, :input, :options, :env
|
||||
attr_reader :executable, :args, :input, :chdir, :env
|
||||
|
||||
attr_predicate :sudo?, :print_stdout?, :print_stderr?, :must_succeed?
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def verbose?
|
||||
return super if @verbose.nil?
|
||||
|
||||
@verbose
|
||||
end
|
||||
|
||||
sig { returns(T::Array[String]) }
|
||||
def env_args
|
||||
set_variables = env.compact.map do |name, value|
|
||||
sanitized_name = Shellwords.escape(name)
|
||||
@ -114,6 +131,7 @@ class SystemCommand
|
||||
["/usr/bin/env", *set_variables]
|
||||
end
|
||||
|
||||
sig { returns(T::Array[String]) }
|
||||
def sudo_prefix
|
||||
return [] unless sudo?
|
||||
|
||||
@ -121,11 +139,12 @@ class SystemCommand
|
||||
["/usr/bin/sudo", *askpass_flags, "-E", "--"]
|
||||
end
|
||||
|
||||
sig { returns(T::Array[String]) }
|
||||
def expanded_args
|
||||
@expanded_args ||= args.map do |arg|
|
||||
if arg.respond_to?(:to_path)
|
||||
File.absolute_path(arg)
|
||||
elsif arg.is_a?(Integer) || arg.is_a?(Float) || arg.is_a?(URI)
|
||||
elsif arg.is_a?(Integer) || arg.is_a?(Float) || arg.is_a?(URI::Generic)
|
||||
arg.to_s
|
||||
else
|
||||
arg.to_str
|
||||
@ -137,7 +156,7 @@ class SystemCommand
|
||||
executable, *args = command
|
||||
|
||||
raw_stdin, raw_stdout, raw_stderr, raw_wait_thr =
|
||||
Open3.popen3(env, [executable, executable], *args, **options)
|
||||
T.unsafe(Open3).popen3(env, [executable, executable], *args, **{ chdir: chdir }.compact)
|
||||
@pid = raw_wait_thr.pid
|
||||
|
||||
write_input_to(raw_stdin)
|
||||
@ -158,7 +177,7 @@ class SystemCommand
|
||||
loop do
|
||||
readable_sources, = IO.select(sources)
|
||||
|
||||
readable_sources = readable_sources.reject(&:eof?)
|
||||
readable_sources = T.must(readable_sources).reject(&:eof?)
|
||||
|
||||
break if readable_sources.empty?
|
||||
|
||||
@ -176,10 +195,20 @@ class SystemCommand
|
||||
|
||||
# Result containing the output and exit status of a finished sub-process.
|
||||
class Result
|
||||
extend T::Sig
|
||||
|
||||
include Context
|
||||
|
||||
attr_accessor :command, :status, :exit_status
|
||||
|
||||
sig do
|
||||
params(
|
||||
command: T::Array[String],
|
||||
output: T::Array[[Symbol, String]],
|
||||
status: Process::Status,
|
||||
secrets: T::Array[String],
|
||||
).void
|
||||
end
|
||||
def initialize(command, output, status, secrets:)
|
||||
@command = command
|
||||
@output = output
|
||||
@ -188,57 +217,65 @@ class SystemCommand
|
||||
@secrets = secrets
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def assert_success!
|
||||
return if @status.success?
|
||||
|
||||
raise ErrorDuringExecution.new(command, status: @status, output: @output, secrets: @secrets)
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def stdout
|
||||
@stdout ||= @output.select { |type,| type == :stdout }
|
||||
.map { |_, line| line }
|
||||
.join
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def stderr
|
||||
@stderr ||= @output.select { |type,| type == :stderr }
|
||||
.map { |_, line| line }
|
||||
.join
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def merged_output
|
||||
@merged_output ||= @output.map { |_, line| line }
|
||||
.join
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def success?
|
||||
return false if @exit_status.nil?
|
||||
|
||||
@exit_status.zero?
|
||||
end
|
||||
|
||||
sig { returns([String, String, Process::Status]) }
|
||||
def to_ary
|
||||
[stdout, stderr, status]
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(T.any(Array, Hash))) }
|
||||
def plist
|
||||
@plist ||= begin
|
||||
output = stdout
|
||||
|
||||
if /\A(?<garbage>.*?)<\?\s*xml/m =~ output
|
||||
output = output.sub(/\A#{Regexp.escape(garbage)}/m, "")
|
||||
warn_plist_garbage(garbage)
|
||||
output = output.sub(/\A(.*?)(\s*<\?\s*xml)/m) do
|
||||
warn_plist_garbage(T.must(Regexp.last_match(1)))
|
||||
Regexp.last_match(2)
|
||||
end
|
||||
|
||||
if %r{<\s*/\s*plist\s*>(?<garbage>.*?)\Z}m =~ output
|
||||
output = output.sub(/#{Regexp.escape(garbage)}\Z/, "")
|
||||
warn_plist_garbage(garbage)
|
||||
output = output.sub(%r{(<\s*/\s*plist\s*>\s*)(.*?)\Z}m) do
|
||||
warn_plist_garbage(T.must(Regexp.last_match(2)))
|
||||
Regexp.last_match(1)
|
||||
end
|
||||
|
||||
Plist.parse_xml(output)
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(garbage: String).void }
|
||||
def warn_plist_garbage(garbage)
|
||||
return unless verbose?
|
||||
return unless garbage.match?(/\S/)
|
||||
|
@ -233,23 +233,17 @@ class Tab < OpenStruct
|
||||
end
|
||||
|
||||
def universal?
|
||||
odeprecated "Tab#universal?"
|
||||
include?("universal")
|
||||
odisabled "Tab#universal?"
|
||||
end
|
||||
|
||||
def cxx11?
|
||||
odeprecated "Tab#cxx11?"
|
||||
include?("c++11")
|
||||
odisabled "Tab#cxx11?"
|
||||
end
|
||||
|
||||
def head?
|
||||
spec == :head
|
||||
end
|
||||
|
||||
def devel?
|
||||
odisabled "Tab#devel?"
|
||||
end
|
||||
|
||||
def stable?
|
||||
spec == :stable
|
||||
end
|
||||
@ -314,10 +308,6 @@ class Tab < OpenStruct
|
||||
Version.create(versions["stable"]) if versions["stable"]
|
||||
end
|
||||
|
||||
def devel_version
|
||||
odisabled "Tab#devel_version"
|
||||
end
|
||||
|
||||
def head_version
|
||||
Version.create(versions["head"]) if versions["head"]
|
||||
end
|
||||
|
@ -21,11 +21,13 @@ class Tap
|
||||
HOMEBREW_TAP_FORMULA_RENAMES_FILE = "formula_renames.json"
|
||||
HOMEBREW_TAP_MIGRATIONS_FILE = "tap_migrations.json"
|
||||
HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR = "audit_exceptions"
|
||||
HOMEBREW_TAP_PYPI_FORMULA_MAPPINGS = "pypi_formula_mappings.json"
|
||||
|
||||
HOMEBREW_TAP_JSON_FILES = %W[
|
||||
#{HOMEBREW_TAP_FORMULA_RENAMES_FILE}
|
||||
#{HOMEBREW_TAP_MIGRATIONS_FILE}
|
||||
#{HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR}/*.json
|
||||
#{HOMEBREW_TAP_PYPI_FORMULA_MAPPINGS}
|
||||
].freeze
|
||||
|
||||
def self.fetch(*args)
|
||||
@ -112,6 +114,7 @@ class Tap
|
||||
@formula_renames = nil
|
||||
@tap_migrations = nil
|
||||
@audit_exceptions = nil
|
||||
@pypi_formula_mappings = nil
|
||||
@config = nil
|
||||
remove_instance_variable(:@private) if instance_variable_defined?(:@private)
|
||||
end
|
||||
@ -559,23 +562,15 @@ class Tap
|
||||
end
|
||||
|
||||
# Hash with audit exceptions
|
||||
sig { returns(Hash) }
|
||||
def audit_exceptions
|
||||
@audit_exceptions = {}
|
||||
@audit_exceptions = read_formula_list_directory "#{HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR}/*"
|
||||
end
|
||||
|
||||
Pathname.glob(path/HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR/"*").each do |exception_file|
|
||||
list_name = exception_file.basename.to_s.chomp(".json").to_sym
|
||||
list_contents = begin
|
||||
JSON.parse exception_file.read
|
||||
rescue JSON::ParserError
|
||||
opoo "#{exception_file} contains invalid JSON"
|
||||
end
|
||||
|
||||
next if list_contents.nil?
|
||||
|
||||
@audit_exceptions[list_name] = list_contents
|
||||
end
|
||||
|
||||
@audit_exceptions
|
||||
# Hash with pypi formula mappings
|
||||
sig { returns(Hash) }
|
||||
def pypi_formula_mappings
|
||||
@pypi_formula_mappings = read_formula_list path/HOMEBREW_TAP_PYPI_FORMULA_MAPPINGS
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
@ -636,6 +631,32 @@ class Tap
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(file: Pathname).returns(Hash) }
|
||||
def read_formula_list(file)
|
||||
JSON.parse file.read
|
||||
rescue JSON::ParserError
|
||||
opoo "#{file} contains invalid JSON"
|
||||
{}
|
||||
rescue Errno::ENOENT
|
||||
{}
|
||||
end
|
||||
|
||||
sig { params(directory: String).returns(Hash) }
|
||||
def read_formula_list_directory(directory)
|
||||
list = {}
|
||||
|
||||
Pathname.glob(path/directory).each do |exception_file|
|
||||
list_name = exception_file.basename.to_s.chomp(".json").to_sym
|
||||
list_contents = read_formula_list exception_file
|
||||
|
||||
next if list_contents.blank?
|
||||
|
||||
list[list_name] = list_contents
|
||||
end
|
||||
|
||||
list
|
||||
end
|
||||
end
|
||||
|
||||
# A specialized {Tap} class for the core formulae.
|
||||
@ -739,6 +760,13 @@ class CoreTap < Tap
|
||||
end
|
||||
end
|
||||
|
||||
def pypi_formula_mappings
|
||||
@pypi_formula_mappings ||= begin
|
||||
self.class.ensure_installed!
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
def formula_file_to_name(file)
|
||||
file.basename(".rb").to_s
|
||||
|
@ -8,20 +8,21 @@ module Homebrew
|
||||
class TapAuditor
|
||||
extend T::Sig
|
||||
|
||||
attr_reader :name, :path, :tap_audit_exceptions, :problems
|
||||
attr_reader :name, :path, :tap_audit_exceptions, :tap_pypi_formula_mappings, :problems
|
||||
|
||||
sig { params(tap: Tap, strict: T.nilable(T::Boolean)).void }
|
||||
def initialize(tap, strict:)
|
||||
@name = tap.name
|
||||
@path = tap.path
|
||||
@tap_audit_exceptions = tap.audit_exceptions
|
||||
@problems = []
|
||||
@name = tap.name
|
||||
@path = tap.path
|
||||
@tap_audit_exceptions = tap.audit_exceptions
|
||||
@tap_pypi_formula_mappings = tap.pypi_formula_mappings
|
||||
@problems = []
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def audit
|
||||
audit_json_files
|
||||
audit_tap_audit_exceptions
|
||||
audit_tap_formula_lists
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -35,38 +36,49 @@ module Homebrew
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def audit_tap_audit_exceptions
|
||||
@tap_audit_exceptions.each do |list_name, formula_names|
|
||||
unless [Hash, Array].include? formula_names.class
|
||||
problem <<~EOS
|
||||
audit_exceptions/#{list_name}.json should contain a JSON array
|
||||
of formula names or a JSON object mapping formula names to values
|
||||
EOS
|
||||
next
|
||||
end
|
||||
|
||||
formula_names = formula_names.keys if formula_names.is_a? Hash
|
||||
|
||||
invalid_formulae = []
|
||||
formula_names.each do |name|
|
||||
invalid_formulae << name if Formula[name].tap != @name
|
||||
rescue FormulaUnavailableError
|
||||
invalid_formulae << name
|
||||
end
|
||||
|
||||
next if invalid_formulae.empty?
|
||||
|
||||
problem <<~EOS
|
||||
audit_exceptions/#{list_name}.json references
|
||||
formulae that are not found in the #{@name} tap.
|
||||
Invalid formulae: #{invalid_formulae.join(", ")}
|
||||
EOS
|
||||
end
|
||||
def audit_tap_formula_lists
|
||||
check_formula_list_directory "audit_exceptions", @tap_audit_exceptions
|
||||
check_formula_list "pypi_formula_mappings", @tap_pypi_formula_mappings
|
||||
end
|
||||
|
||||
sig { params(message: String).void }
|
||||
def problem(message)
|
||||
@problems << ({ message: message, location: nil })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
sig { params(list_file: String, list: T.untyped).void }
|
||||
def check_formula_list(list_file, list)
|
||||
unless [Hash, Array].include? list.class
|
||||
problem <<~EOS
|
||||
#{list_file}.json should contain a JSON array
|
||||
of formula names or a JSON object mapping formula names to values
|
||||
EOS
|
||||
return
|
||||
end
|
||||
|
||||
invalid_formulae = []
|
||||
list.each do |name, _|
|
||||
invalid_formulae << name if Formula[name].tap != @name
|
||||
rescue FormulaUnavailableError
|
||||
invalid_formulae << name
|
||||
end
|
||||
|
||||
return if invalid_formulae.empty?
|
||||
|
||||
problem <<~EOS
|
||||
#{list_file}.json references
|
||||
formulae that are not found in the #{@name} tap.
|
||||
Invalid formulae: #{invalid_formulae.join(", ")}
|
||||
EOS
|
||||
end
|
||||
|
||||
sig { params(directory_name: String, lists: Hash).void }
|
||||
def check_formula_list_directory(directory_name, lists)
|
||||
lists.each do |list_name, list|
|
||||
check_formula_list "#{directory_name}/#{list_name}", list
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -8,7 +8,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
||||
|
||||
let(:artifact_dsl_key) { described_class.dsl_key }
|
||||
let(:artifact) { cask.artifacts.find { |a| a.is_a?(described_class) } }
|
||||
let(:fake_system_command) { FakeSystemCommand }
|
||||
let(:fake_system_command) { class_double(SystemCommand) }
|
||||
|
||||
context "using :launchctl" do
|
||||
let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-launchctl")) }
|
||||
@ -31,41 +31,37 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
||||
end
|
||||
|
||||
it "works when job is owned by user" do
|
||||
FakeSystemCommand.stubs_command(
|
||||
launchctl_list_cmd,
|
||||
service_info,
|
||||
)
|
||||
allow(fake_system_command).to receive(:run)
|
||||
.with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: false)
|
||||
.and_return(instance_double(SystemCommand::Result, stdout: service_info))
|
||||
allow(fake_system_command).to receive(:run)
|
||||
.with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: true)
|
||||
.and_return(instance_double(SystemCommand::Result, stdout: unknown_response))
|
||||
|
||||
FakeSystemCommand.stubs_command(
|
||||
sudo(launchctl_list_cmd),
|
||||
unknown_response,
|
||||
)
|
||||
|
||||
FakeSystemCommand.expects_command(launchctl_remove_cmd)
|
||||
expect(fake_system_command).to receive(:run!)
|
||||
.with("/bin/launchctl", args: ["remove", "my.fancy.package.service"], sudo: false)
|
||||
.and_return(instance_double(SystemCommand::Result))
|
||||
|
||||
subject.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command)
|
||||
end
|
||||
|
||||
it "works when job is owned by system" do
|
||||
FakeSystemCommand.stubs_command(
|
||||
launchctl_list_cmd,
|
||||
unknown_response,
|
||||
)
|
||||
allow(fake_system_command).to receive(:run)
|
||||
.with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: false)
|
||||
.and_return(instance_double(SystemCommand::Result, stdout: unknown_response))
|
||||
allow(fake_system_command).to receive(:run)
|
||||
.with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: true)
|
||||
.and_return(instance_double(SystemCommand::Result, stdout: service_info))
|
||||
|
||||
FakeSystemCommand.stubs_command(
|
||||
sudo(launchctl_list_cmd),
|
||||
service_info,
|
||||
)
|
||||
|
||||
FakeSystemCommand.expects_command(sudo(launchctl_remove_cmd))
|
||||
expect(fake_system_command).to receive(:run!)
|
||||
.with("/bin/launchctl", args: ["remove", "my.fancy.package.service"], sudo: true)
|
||||
.and_return(instance_double(SystemCommand::Result))
|
||||
|
||||
subject.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command)
|
||||
end
|
||||
end
|
||||
|
||||
context "using :pkgutil" do
|
||||
let(:fake_system_command) { class_double(SystemCommand) }
|
||||
|
||||
let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-pkgutil")) }
|
||||
|
||||
let(:main_pkg_id) { "my.fancy.package.main" }
|
||||
|
@ -6,7 +6,8 @@ require "test/cask/dsl/shared_examples/staged"
|
||||
|
||||
describe Cask::DSL::Postflight, :cask do
|
||||
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
||||
let(:dsl) { described_class.new(cask, FakeSystemCommand) }
|
||||
let(:fake_system_command) { class_double(SystemCommand) }
|
||||
let(:dsl) { described_class.new(cask, fake_system_command) }
|
||||
|
||||
it_behaves_like Cask::DSL::Base
|
||||
|
||||
|
@ -6,7 +6,8 @@ require "test/cask/dsl/shared_examples/staged"
|
||||
|
||||
describe Cask::DSL::Preflight, :cask do
|
||||
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
||||
let(:dsl) { described_class.new(cask, FakeSystemCommand) }
|
||||
let(:fake_system_command) { class_double(SystemCommand) }
|
||||
let(:dsl) { described_class.new(cask, fake_system_command) }
|
||||
|
||||
it_behaves_like Cask::DSL::Base
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
require "cask/staged"
|
||||
|
||||
shared_examples Cask::Staged do
|
||||
let(:existing_path) { Pathname.new("/path/to/file/that/exists") }
|
||||
let(:non_existent_path) { Pathname.new("/path/to/file/that/does/not/exist") }
|
||||
let(:existing_path) { Pathname("/path/to/file/that/exists") }
|
||||
let(:non_existent_path) { Pathname("/path/to/file/that/does/not/exist") }
|
||||
|
||||
before do
|
||||
allow(existing_path).to receive(:exist?).and_return(true)
|
||||
@ -17,9 +17,8 @@ shared_examples Cask::Staged do
|
||||
end
|
||||
|
||||
it "can run system commands with list-form arguments" do
|
||||
FakeSystemCommand.expects_command(
|
||||
["echo", "homebrew-cask", "rocks!"],
|
||||
)
|
||||
expect(fake_system_command).to receive(:run!)
|
||||
.with("echo", args: ["homebrew-cask", "rocks!"])
|
||||
|
||||
staged.system_command("echo", args: ["homebrew-cask", "rocks!"])
|
||||
end
|
||||
@ -28,9 +27,8 @@ shared_examples Cask::Staged do
|
||||
fake_pathname = existing_path
|
||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||
|
||||
FakeSystemCommand.expects_command(
|
||||
["/bin/chmod", "-R", "--", "777", fake_pathname],
|
||||
)
|
||||
expect(fake_system_command).to receive(:run!)
|
||||
.with("/bin/chmod", args: ["-R", "--", "777", fake_pathname], sudo: false)
|
||||
|
||||
staged.set_permissions(fake_pathname.to_s, "777")
|
||||
end
|
||||
@ -39,9 +37,8 @@ shared_examples Cask::Staged do
|
||||
fake_pathname = existing_path
|
||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||
|
||||
FakeSystemCommand.expects_command(
|
||||
["/bin/chmod", "-R", "--", "777", fake_pathname, fake_pathname],
|
||||
)
|
||||
expect(fake_system_command).to receive(:run!)
|
||||
.with("/bin/chmod", args: ["-R", "--", "777", fake_pathname, fake_pathname], sudo: false)
|
||||
|
||||
staged.set_permissions([fake_pathname.to_s, fake_pathname.to_s], "777")
|
||||
end
|
||||
@ -58,9 +55,8 @@ shared_examples Cask::Staged do
|
||||
allow(User).to receive(:current).and_return(User.new("fake_user"))
|
||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||
|
||||
FakeSystemCommand.expects_command(
|
||||
sudo("/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname),
|
||||
)
|
||||
expect(fake_system_command).to receive(:run!)
|
||||
.with("/usr/sbin/chown", args: ["-R", "--", "fake_user:staff", fake_pathname], sudo: true)
|
||||
|
||||
staged.set_ownership(fake_pathname.to_s)
|
||||
end
|
||||
@ -71,9 +67,8 @@ shared_examples Cask::Staged do
|
||||
allow(User).to receive(:current).and_return(User.new("fake_user"))
|
||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||
|
||||
FakeSystemCommand.expects_command(
|
||||
sudo("/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname, fake_pathname),
|
||||
)
|
||||
expect(fake_system_command).to receive(:run!)
|
||||
.with("/usr/sbin/chown", args: ["-R", "--", "fake_user:staff", fake_pathname, fake_pathname], sudo: true)
|
||||
|
||||
staged.set_ownership([fake_pathname.to_s, fake_pathname.to_s])
|
||||
end
|
||||
@ -83,9 +78,8 @@ shared_examples Cask::Staged do
|
||||
|
||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||
|
||||
FakeSystemCommand.expects_command(
|
||||
sudo("/usr/sbin/chown", "-R", "--", "other_user:other_group", fake_pathname),
|
||||
)
|
||||
expect(fake_system_command).to receive(:run!)
|
||||
.with("/usr/sbin/chown", args: ["-R", "--", "other_user:other_group", fake_pathname], sudo: true)
|
||||
|
||||
staged.set_ownership(fake_pathname.to_s, user: "other_user", group: "other_group")
|
||||
end
|
||||
|
@ -5,7 +5,7 @@ require "test/cask/dsl/shared_examples/base"
|
||||
|
||||
describe Cask::DSL::UninstallPostflight, :cask do
|
||||
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
||||
let(:dsl) { described_class.new(cask, FakeSystemCommand) }
|
||||
let(:dsl) { described_class.new(cask, class_double(SystemCommand)) }
|
||||
|
||||
it_behaves_like Cask::DSL::Base
|
||||
end
|
||||
|
@ -6,7 +6,8 @@ require "test/cask/dsl/shared_examples/staged"
|
||||
|
||||
describe Cask::DSL::UninstallPreflight, :cask do
|
||||
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
||||
let(:dsl) { described_class.new(cask, FakeSystemCommand) }
|
||||
let(:fake_system_command) { class_double(SystemCommand) }
|
||||
let(:dsl) { described_class.new(cask, fake_system_command) }
|
||||
|
||||
it_behaves_like Cask::DSL::Base
|
||||
|
||||
|
@ -153,8 +153,12 @@ describe Cask::Pkg, :cask do
|
||||
"/usr/sbin/pkgutil",
|
||||
args: ["--pkg-info-plist", pkg_id],
|
||||
).and_return(
|
||||
SystemCommand::Result.new(nil, [[:stdout, pkg_info_plist]], instance_double(Process::Status, exitstatus: 0),
|
||||
secrets: []),
|
||||
SystemCommand::Result.new(
|
||||
["/usr/sbin/pkgutil", "--pkg-info-plist", pkg_id],
|
||||
[[:stdout, pkg_info_plist]],
|
||||
instance_double(Process::Status, exitstatus: 0),
|
||||
secrets: [],
|
||||
),
|
||||
)
|
||||
|
||||
info = pkg.info
|
||||
|
@ -6,17 +6,3 @@ require "cmd/shared_examples/args_parse"
|
||||
describe "Homebrew.switch_args" do
|
||||
it_behaves_like "parseable arguments"
|
||||
end
|
||||
|
||||
describe "brew switch", :integration_test do
|
||||
it "allows switching between Formula versions" do
|
||||
install_test_formula "testball"
|
||||
|
||||
testball_rack = HOMEBREW_CELLAR/"testball"
|
||||
FileUtils.cp_r testball_rack/"0.1", testball_rack/"0.2"
|
||||
|
||||
expect { brew "switch", "testball", "0.2" }
|
||||
.to output(/links created/).to_stdout
|
||||
.and not_to_output.to_stderr
|
||||
.and be_a_success
|
||||
end
|
||||
end
|
||||
|
@ -794,21 +794,19 @@ describe Formula do
|
||||
f1 = formula "f1" do
|
||||
url "f1-1"
|
||||
|
||||
depends_on :java
|
||||
depends_on x11: :recommended
|
||||
depends_on xcode: ["1.0", :optional]
|
||||
end
|
||||
stub_formula_loader(f1)
|
||||
|
||||
java = JavaRequirement.new
|
||||
x11 = X11Requirement.new([:recommended])
|
||||
xcode = XcodeRequirement.new(["1.0", :optional])
|
||||
|
||||
expect(Set.new(f1.recursive_requirements)).to eq(Set[java, x11])
|
||||
expect(Set.new(f1.recursive_requirements)).to eq(Set[x11])
|
||||
|
||||
f1.build = BuildOptions.new(["--with-xcode", "--without-x11"], f1.options)
|
||||
|
||||
expect(Set.new(f1.recursive_requirements)).to eq(Set[java, xcode])
|
||||
expect(Set.new(f1.recursive_requirements)).to eq(Set[xcode])
|
||||
|
||||
f1.build = f1.stable.build
|
||||
f2 = formula "f2" do
|
||||
@ -817,14 +815,14 @@ describe Formula do
|
||||
depends_on "f1"
|
||||
end
|
||||
|
||||
expect(Set.new(f2.recursive_requirements)).to eq(Set[java, x11])
|
||||
expect(Set.new(f2.recursive_requirements {})).to eq(Set[java, x11, xcode])
|
||||
expect(Set.new(f2.recursive_requirements)).to eq(Set[x11])
|
||||
expect(Set.new(f2.recursive_requirements {})).to eq(Set[x11, xcode])
|
||||
|
||||
requirements = f2.recursive_requirements do |_dependent, requirement|
|
||||
Requirement.prune if requirement.is_a?(JavaRequirement)
|
||||
Requirement.prune if requirement.is_a?(X11Requirement)
|
||||
end
|
||||
|
||||
expect(Set.new(requirements)).to eq(Set[x11, xcode])
|
||||
expect(Set.new(requirements)).to eq(Set[xcode])
|
||||
end
|
||||
|
||||
specify "#to_hash" do
|
||||
|
@ -6,13 +6,13 @@ require "language/java"
|
||||
describe Language::Java do
|
||||
describe "::java_home" do
|
||||
if !OS.mac? || MacOS.version < :big_sur
|
||||
it "returns valid JAVA_HOME if version is specified", :needs_java do
|
||||
it "returns valid JAVA_HOME if version is specified", :needs_macos do
|
||||
java_home = described_class.java_home("1.6+")
|
||||
expect(java_home/"bin/java").to be_an_executable
|
||||
end
|
||||
end
|
||||
|
||||
it "returns valid JAVA_HOME if version is not specified", :needs_java do
|
||||
it "returns valid JAVA_HOME if version is not specified", :needs_macos do
|
||||
java_home = described_class.java_home
|
||||
expect(java_home/"bin/java").to be_an_executable
|
||||
end
|
||||
@ -24,7 +24,7 @@ describe Language::Java do
|
||||
expect(java_home[:JAVA_HOME]).to include("--version blah")
|
||||
end
|
||||
|
||||
it "returns java_home path without version if version is not specified", :needs_java do
|
||||
it "returns java_home path without version if version is not specified", :needs_macos do
|
||||
java_home = described_class.java_home_env
|
||||
expect(java_home[:JAVA_HOME]).not_to include("--version")
|
||||
end
|
||||
@ -36,7 +36,7 @@ describe Language::Java do
|
||||
expect(java_home[:JAVA_HOME]).to include("--version blah")
|
||||
end
|
||||
|
||||
it "returns java_home path without version if version is not specified", :needs_java do
|
||||
it "returns java_home path without version if version is not specified", :needs_macos do
|
||||
java_home = described_class.overridable_java_home_env
|
||||
expect(java_home[:JAVA_HOME]).not_to include("--version")
|
||||
end
|
||||
|
@ -1,38 +0,0 @@
|
||||
# typed: false
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "requirements/java_requirement"
|
||||
require "fileutils"
|
||||
|
||||
describe JavaRequirement do
|
||||
subject { described_class.new(%w[1.8]) }
|
||||
|
||||
let(:java_home) { mktmpdir }
|
||||
|
||||
before do
|
||||
FileUtils.mkdir java_home/"bin"
|
||||
FileUtils.touch java_home/"bin/java"
|
||||
allow(subject).to receive(:preferred_java).and_return(java_home/"bin/java")
|
||||
end
|
||||
|
||||
specify "Apple Java environment" do
|
||||
expect(subject).to be_satisfied
|
||||
|
||||
expect(ENV).to receive(:prepend_path)
|
||||
expect(ENV).to receive(:append_to_cflags)
|
||||
|
||||
subject.modify_build_environment
|
||||
expect(ENV["JAVA_HOME"]).to eq(java_home.to_s)
|
||||
end
|
||||
|
||||
specify "Oracle Java environment" do
|
||||
expect(subject).to be_satisfied
|
||||
|
||||
FileUtils.mkdir java_home/"include"
|
||||
expect(ENV).to receive(:prepend_path)
|
||||
expect(ENV).to receive(:append_to_cflags).twice
|
||||
|
||||
subject.modify_build_environment
|
||||
expect(ENV["JAVA_HOME"]).to eq(java_home.to_s)
|
||||
end
|
||||
end
|
@ -1,159 +0,0 @@
|
||||
# typed: false
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "requirements/java_requirement"
|
||||
|
||||
describe JavaRequirement do
|
||||
subject { described_class.new([]) }
|
||||
|
||||
before do
|
||||
ENV["JAVA_HOME"] = nil
|
||||
end
|
||||
|
||||
describe "#initialize" do
|
||||
it "parses '1.8' tag correctly" do
|
||||
req = described_class.new(["1.8"])
|
||||
expect(req.display_s).to eq("Java = 1.8")
|
||||
end
|
||||
|
||||
it "parses '9' tag correctly" do
|
||||
req = described_class.new(["9"])
|
||||
expect(req.display_s).to eq("Java = 9")
|
||||
end
|
||||
|
||||
it "parses '9+' tag correctly" do
|
||||
req = described_class.new(["9+"])
|
||||
expect(req.display_s).to eq("Java >= 9")
|
||||
end
|
||||
|
||||
it "parses '11' tag correctly" do
|
||||
req = described_class.new(["11"])
|
||||
expect(req.display_s).to eq("Java = 11")
|
||||
end
|
||||
|
||||
it "parses bogus tag correctly" do
|
||||
req = described_class.new(["bogus1.8"])
|
||||
expect(req.display_s).to eq("Java")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#message" do
|
||||
its(:message) { is_expected.to match(/Java is required for this software./) }
|
||||
end
|
||||
|
||||
describe "#inspect" do
|
||||
subject { described_class.new(%w[1.7+]) }
|
||||
|
||||
its(:inspect) { is_expected.to eq('#<JavaRequirement: version="1.7+" []>') }
|
||||
end
|
||||
|
||||
describe "#display_s" do
|
||||
context "without specific version" do
|
||||
its(:display_s) { is_expected.to eq("Java") }
|
||||
end
|
||||
|
||||
context "with version 1.8" do
|
||||
subject { described_class.new(%w[1.8]) }
|
||||
|
||||
its(:display_s) { is_expected.to eq("Java = 1.8") }
|
||||
end
|
||||
|
||||
context "with version 1.8+" do
|
||||
subject { described_class.new(%w[1.8+]) }
|
||||
|
||||
its(:display_s) { is_expected.to eq("Java >= 1.8") }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#satisfied?" do
|
||||
subject(:requirement) { described_class.new(%w[1.8]) }
|
||||
|
||||
if !OS.mac? || MacOS.version < :big_sur
|
||||
it "returns false if no `java` executable can be found" do
|
||||
allow(File).to receive(:executable?).and_return(false)
|
||||
expect(requirement).not_to be_satisfied
|
||||
end
|
||||
end
|
||||
|
||||
it "returns true if #preferred_java returns a path" do
|
||||
allow(requirement).to receive(:preferred_java).and_return(Pathname.new("/usr/bin/java"))
|
||||
expect(requirement).to be_satisfied
|
||||
end
|
||||
|
||||
context "when #possible_javas contains paths" do
|
||||
let(:path) { mktmpdir }
|
||||
let(:java) { path/"java" }
|
||||
|
||||
def setup_java_with_version(version)
|
||||
IO.write java, <<~SH
|
||||
#!/bin/sh
|
||||
echo 'java version "#{version}"' 1>&2
|
||||
SH
|
||||
FileUtils.chmod "+x", java
|
||||
end
|
||||
|
||||
before do
|
||||
allow(requirement).to receive(:possible_javas).and_return([java])
|
||||
end
|
||||
|
||||
context "and 1.7 is required" do
|
||||
subject(:requirement) { described_class.new(%w[1.7]) }
|
||||
|
||||
it "returns false if all are lower" do
|
||||
setup_java_with_version "1.6.0_5"
|
||||
expect(requirement).not_to be_satisfied
|
||||
end
|
||||
|
||||
it "returns true if one is equal" do
|
||||
setup_java_with_version "1.7.0_5"
|
||||
expect(requirement).to be_satisfied
|
||||
end
|
||||
|
||||
it "returns false if all are higher" do
|
||||
setup_java_with_version "1.8.0_5"
|
||||
expect(requirement).not_to be_satisfied
|
||||
end
|
||||
end
|
||||
|
||||
context "and 1.7+ is required" do
|
||||
subject(:requirement) { described_class.new(%w[1.7+]) }
|
||||
|
||||
it "returns false if all are lower" do
|
||||
setup_java_with_version "1.6.0_5"
|
||||
expect(requirement).not_to be_satisfied
|
||||
end
|
||||
|
||||
it "returns true if one is equal" do
|
||||
setup_java_with_version "1.7.0_5"
|
||||
expect(requirement).to be_satisfied
|
||||
end
|
||||
|
||||
it "returns true if one is higher" do
|
||||
setup_java_with_version "1.8.0_5"
|
||||
expect(requirement).to be_satisfied
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#suggestion" do
|
||||
context "without specific version" do
|
||||
its(:suggestion) { is_expected.to match(/brew install --cask adoptopenjdk/) }
|
||||
its(:cask) { is_expected.to eq("adoptopenjdk") }
|
||||
end
|
||||
|
||||
context "with version 1.8" do
|
||||
subject { described_class.new(%w[1.8]) }
|
||||
|
||||
its(:suggestion) { is_expected.to match(%r{brew install --cask homebrew/cask-versions/adoptopenjdk8}) }
|
||||
its(:cask) { is_expected.to eq("homebrew/cask-versions/adoptopenjdk8") }
|
||||
end
|
||||
|
||||
context "with version 1.8+" do
|
||||
subject { described_class.new(%w[1.8+]) }
|
||||
|
||||
its(:suggestion) { is_expected.to match(/brew install --cask adoptopenjdk/) }
|
||||
its(:cask) { is_expected.to eq("adoptopenjdk") }
|
||||
end
|
||||
end
|
||||
end
|
@ -324,6 +324,7 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do
|
||||
homepage "https://brew.sh"
|
||||
|
||||
on_macos do
|
||||
disable! because: :does_not_build
|
||||
depends_on "readline"
|
||||
end
|
||||
|
||||
@ -341,6 +342,7 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do
|
||||
homepage "https://brew.sh"
|
||||
|
||||
on_linux do
|
||||
deprecate! because: "it's deprecated"
|
||||
depends_on "readline"
|
||||
end
|
||||
|
||||
|
@ -250,61 +250,6 @@ describe RuboCop::Cop::FormulaAudit::Text do
|
||||
RUBY
|
||||
end
|
||||
|
||||
it "When using JAVA_HOME without a java dependency" do
|
||||
expect_offense(<<~RUBY)
|
||||
class Foo < Formula
|
||||
def install
|
||||
ohai "JAVA_HOME"
|
||||
^^^^^^^^^^^ Use `depends_on :java` to set JAVA_HOME
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it "When using JAVA_HOME with an openjdk dependency" do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
class Foo < Formula
|
||||
depends_on "openjdk"
|
||||
def install
|
||||
ohai "JAVA_HOME"
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it "When using JAVA_HOME with an openjdk build dependency" do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
class Foo < Formula
|
||||
depends_on "openjdk" => :build
|
||||
def install
|
||||
ohai "JAVA_HOME"
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it "When using JAVA_HOME with a java dependency" do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
class Foo < Formula
|
||||
depends_on :java
|
||||
def install
|
||||
ohai "JAVA_HOME"
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it "When using JAVA_HOME with a java build dependency" do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
class Foo < Formula
|
||||
depends_on :java => :build
|
||||
def install
|
||||
ohai "JAVA_HOME"
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it "When using `prefix + \"bin\"` instead of `bin`" do
|
||||
expect_offense(<<~RUBY)
|
||||
class Foo < Formula
|
||||
|
@ -1,74 +0,0 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
def sudo(*args)
|
||||
["/usr/bin/sudo", "-E", "--"] + args.flatten
|
||||
end
|
||||
|
||||
class FakeSystemCommand
|
||||
def self.responses
|
||||
@responses ||= {}
|
||||
end
|
||||
|
||||
def self.expectations
|
||||
@expectations ||= {}
|
||||
end
|
||||
|
||||
def self.system_calls
|
||||
@system_calls ||= Hash.new(0)
|
||||
end
|
||||
|
||||
def self.clear
|
||||
@responses = nil
|
||||
@expectations = nil
|
||||
@system_calls = nil
|
||||
end
|
||||
|
||||
def self.stubs_command(command, response = "")
|
||||
command = command.map(&:to_s)
|
||||
responses[command] = response
|
||||
end
|
||||
|
||||
def self.expects_command(command, response = "", times = 1)
|
||||
command = command.map(&:to_s)
|
||||
stubs_command(command, response)
|
||||
expectations[command] = times
|
||||
end
|
||||
|
||||
def self.verify_expectations!
|
||||
expectations.each do |command, times|
|
||||
unless system_calls[command] == times
|
||||
raise("expected #{command.inspect} to be run #{times} times, but got #{system_calls[command]}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.run(command_string, options = {})
|
||||
command = SystemCommand.new(command_string, options).command
|
||||
puts command
|
||||
unless responses.key?(command)
|
||||
raise("no response faked for #{command.inspect}, faked responses are: #{responses.inspect}")
|
||||
end
|
||||
|
||||
system_calls[command] += 1
|
||||
|
||||
response = responses[command]
|
||||
if response.respond_to?(:call)
|
||||
response.call(command_string, options)
|
||||
else
|
||||
SystemCommand::Result.new(command, [[:stdout, response]], OpenStruct.new(exitstatus: 0), secrets: [])
|
||||
end
|
||||
end
|
||||
|
||||
def self.run!(command, options = {})
|
||||
run(command, options.merge(must_succeed: true))
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.after do
|
||||
FakeSystemCommand.verify_expectations!
|
||||
ensure
|
||||
FakeSystemCommand.clear
|
||||
end
|
||||
end
|
@ -4,7 +4,6 @@
|
||||
require "cask/config"
|
||||
require "cask/cache"
|
||||
|
||||
require "test/support/helper/cask/fake_system_command"
|
||||
require "test/support/helper/cask/install_helper"
|
||||
require "test/support/helper/cask/never_sudo_system_command"
|
||||
|
||||
|
@ -61,18 +61,24 @@ describe GitHub do
|
||||
describe "::get_artifact_url", :needs_network do
|
||||
it "fails to find a nonexistant workflow" do
|
||||
expect {
|
||||
subject.get_artifact_url("Homebrew", "homebrew-core", 1)
|
||||
subject.get_artifact_url(
|
||||
subject.get_workflow_run("Homebrew", "homebrew-core", 1),
|
||||
)
|
||||
}.to raise_error(/No matching workflow run found/)
|
||||
end
|
||||
|
||||
it "fails to find artifacts that don't exist" do
|
||||
expect {
|
||||
subject.get_artifact_url("Homebrew", "homebrew-core", 51971, artifact_name: "false_bottles")
|
||||
subject.get_artifact_url(
|
||||
subject.get_workflow_run("Homebrew", "homebrew-core", 51971, artifact_name: "false_bottles"),
|
||||
)
|
||||
}.to raise_error(/No artifact .+ was found/)
|
||||
end
|
||||
|
||||
it "gets an artifact link" do
|
||||
url = subject.get_artifact_url("Homebrew", "homebrew-core", 51971, artifact_name: "bottles")
|
||||
url = subject.get_artifact_url(
|
||||
subject.get_workflow_run("Homebrew", "homebrew-core", 51971, artifact_name: "bottles"),
|
||||
)
|
||||
expect(url).to eq("https://api.github.com/repos/Homebrew/homebrew-core/actions/artifacts/3557392/zip")
|
||||
end
|
||||
end
|
||||
|
171
Library/Homebrew/test/utils/pypi_spec.rb
Normal file
171
Library/Homebrew/test/utils/pypi_spec.rb
Normal file
@ -0,0 +1,171 @@
|
||||
# typed: false
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "utils/pypi"
|
||||
|
||||
describe PyPI do
|
||||
let(:package_url) do
|
||||
"https://files.pythonhosted.org/packages/b0/3f/2e1dad67eb172b6443b5eb37eb885a054a55cfd733393071499514140282/"\
|
||||
"snakemake-5.29.0.tar.gz"
|
||||
end
|
||||
let(:old_package_url) do
|
||||
"https://files.pythonhosted.org/packages/6f/c4/da52bfdd6168ea46a0fe2b7c983b6c34c377a8733ec177cc00b197a96a9f/"\
|
||||
"snakemake-5.28.0.tar.gz"
|
||||
end
|
||||
|
||||
describe PyPI::Package do
|
||||
let(:package_checksum) { "47417307d08ecb0707b3b29effc933bd63d8c8e3ab15509c62b685b7614c6568" }
|
||||
let(:old_package_checksum) { "2367ce91baf7f8fa7738d33aff9670ffdf5410bbac49aeb209f73b45a3425046" }
|
||||
|
||||
let(:package) { described_class.new("snakemake") }
|
||||
let(:package_with_version) { described_class.new("snakemake==5.28.0") }
|
||||
let(:package_with_different_version) { described_class.new("snakemake==5.29.0") }
|
||||
let(:package_with_extra) { described_class.new("snakemake[foo]") }
|
||||
let(:package_with_extra_and_version) { described_class.new("snakemake[foo]==5.28.0") }
|
||||
let(:package_from_url) { described_class.new(package_url, is_url: true) }
|
||||
let(:other_package) { described_class.new("virtualenv==20.2.0") }
|
||||
|
||||
describe "initialize" do
|
||||
it "initializes name" do
|
||||
expect(described_class.new("foo").name).to eq "foo"
|
||||
end
|
||||
|
||||
it "initializes name with extra" do
|
||||
expect(described_class.new("foo[bar]").name).to eq "foo"
|
||||
end
|
||||
|
||||
it "initializes extra" do
|
||||
expect(described_class.new("foo[bar]").extras).to eq ["bar"]
|
||||
end
|
||||
|
||||
it "initializes multiple extras" do
|
||||
expect(described_class.new("foo[bar,baz]").extras).to eq ["bar", "baz"]
|
||||
end
|
||||
|
||||
it "initializes name with version" do
|
||||
expect(described_class.new("foo==1.2.3").name).to eq "foo"
|
||||
end
|
||||
|
||||
it "initializes version" do
|
||||
expect(described_class.new("foo==1.2.3").version).to eq "1.2.3"
|
||||
end
|
||||
|
||||
it "initializes extra with version" do
|
||||
expect(described_class.new("foo[bar]==1.2.3").extras).to eq ["bar"]
|
||||
end
|
||||
|
||||
it "initializes multiple extras with version" do
|
||||
expect(described_class.new("foo[bar,baz]==1.2.3").extras).to eq ["bar", "baz"]
|
||||
end
|
||||
|
||||
it "initializes version with extra" do
|
||||
expect(described_class.new("foo[bar]==1.2.3").version).to eq "1.2.3"
|
||||
end
|
||||
|
||||
it "initializes version with multiple extras" do
|
||||
expect(described_class.new("foo[bar,baz]==1.2.3").version).to eq "1.2.3"
|
||||
end
|
||||
|
||||
it "initializes name from url" do
|
||||
expect(described_class.new(package_url, is_url: true).name).to eq "snakemake"
|
||||
end
|
||||
|
||||
it "initializes version from url" do
|
||||
expect(described_class.new(package_url, is_url: true).version).to eq "5.29.0"
|
||||
end
|
||||
end
|
||||
|
||||
describe ".pypi_info", :needs_network do
|
||||
it "gets pypi info from a package name" do
|
||||
expect(package.pypi_info.first).to eq "snakemake"
|
||||
end
|
||||
|
||||
it "gets pypi info from a package name and specified version" do
|
||||
expect(package.pypi_info(version: "5.29.0")).to eq ["snakemake", package_url, package_checksum, "5.29.0"]
|
||||
end
|
||||
|
||||
it "gets pypi info from a package name with extra" do
|
||||
expect(package_with_extra.pypi_info.first).to eq "snakemake"
|
||||
end
|
||||
|
||||
it "gets pypi info from a package name and version" do
|
||||
expect(package_with_version.pypi_info).to eq ["snakemake", old_package_url, old_package_checksum, "5.28.0"]
|
||||
end
|
||||
|
||||
it "gets pypi info from a package name with overriden version" do
|
||||
expected_result = ["snakemake", package_url, package_checksum, "5.29.0"]
|
||||
expect(package_with_version.pypi_info(version: "5.29.0")).to eq expected_result
|
||||
end
|
||||
|
||||
it "gets pypi info from a package name, extras, and version" do
|
||||
expected_result = ["snakemake", old_package_url, old_package_checksum, "5.28.0"]
|
||||
expect(package_with_extra_and_version.pypi_info).to eq expected_result
|
||||
end
|
||||
|
||||
it "gets pypi info from a url" do
|
||||
expect(package_from_url.pypi_info).to eq ["snakemake", package_url, package_checksum, "5.29.0"]
|
||||
end
|
||||
|
||||
it "gets pypi info from a url with overriden version" do
|
||||
expected_result = ["snakemake", old_package_url, old_package_checksum, "5.28.0"]
|
||||
expect(package_from_url.pypi_info(version: "5.28.0")).to eq expected_result
|
||||
end
|
||||
end
|
||||
|
||||
describe ".to_s" do
|
||||
it "returns string representation of package name" do
|
||||
expect(package.to_s).to eq "snakemake"
|
||||
end
|
||||
|
||||
it "returns string representation of package with version" do
|
||||
expect(package_with_version.to_s).to eq "snakemake==5.28.0"
|
||||
end
|
||||
|
||||
it "returns string representation of package with extra" do
|
||||
expect(package_with_extra.to_s).to eq "snakemake[foo]"
|
||||
end
|
||||
|
||||
it "returns string representation of package with extra and version" do
|
||||
expect(package_with_extra_and_version.to_s).to eq "snakemake[foo]==5.28.0"
|
||||
end
|
||||
|
||||
it "returns string representation of package from url" do
|
||||
expect(package_from_url.to_s).to eq "snakemake==5.29.0"
|
||||
end
|
||||
end
|
||||
|
||||
describe ".same_package?" do
|
||||
it "returns false for different packages" do
|
||||
expect(package.same_package?(other_package)).to eq false
|
||||
end
|
||||
|
||||
it "returns true for the same package" do
|
||||
expect(package.same_package?(package_with_version)).to eq true
|
||||
end
|
||||
|
||||
it "returns true for the same package with different versions" do
|
||||
expect(package_with_version.same_package?(package_with_different_version)).to eq true
|
||||
end
|
||||
end
|
||||
|
||||
describe "<=>" do
|
||||
it "returns -1" do
|
||||
expect(package <=> other_package).to eq((-1))
|
||||
end
|
||||
|
||||
it "returns 0" do
|
||||
expect(package <=> package_with_version).to eq 0
|
||||
end
|
||||
|
||||
it "returns 1" do
|
||||
expect(other_package <=> package_with_extra_and_version).to eq 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "update_pypi_url", :needs_network do
|
||||
it "updates url to new version" do
|
||||
expect(described_class.update_pypi_url(old_package_url, "5.29.0")).to eq package_url
|
||||
end
|
||||
end
|
||||
end
|
@ -91,8 +91,10 @@ module UnpackStrategy
|
||||
Tempfile.open(["", ".bom"]) do |bomfile|
|
||||
bomfile.close
|
||||
|
||||
bom = path.bom
|
||||
|
||||
Tempfile.open(["", ".list"]) do |filelist|
|
||||
filelist.puts(path.bom)
|
||||
filelist.puts(bom)
|
||||
filelist.close
|
||||
|
||||
system_command! "mkbom",
|
||||
@ -100,9 +102,23 @@ module UnpackStrategy
|
||||
verbose: verbose
|
||||
end
|
||||
|
||||
system_command! "ditto",
|
||||
args: ["--bom", bomfile.path, "--", path, unpack_dir],
|
||||
verbose: verbose
|
||||
result = system_command! "ditto",
|
||||
args: ["--bom", bomfile.path, "--", path, unpack_dir],
|
||||
verbose: verbose
|
||||
|
||||
if result.stderr.include?("contains no files, nothing copied")
|
||||
all_paths_find = system_command("find", args: [".", "-print0"], chdir: path, print_stderr: false)
|
||||
.stdout
|
||||
.split("\0")
|
||||
|
||||
all_paths_ruby = Pathname.glob(path/"**/*", File::FNM_DOTMATCH)
|
||||
.map { |p| p.relative_path_from(path).to_s }
|
||||
|
||||
odebug "BOM contents:", bom
|
||||
odebug "BOM contents (retry):", path.bom
|
||||
odebug "Directory contents (find):", all_paths_find.join("\n")
|
||||
odebug "Directory contents (Ruby):", all_paths_ruby.join("\n")
|
||||
end
|
||||
|
||||
FileUtils.chmod "u+w", Pathname.glob(unpack_dir/"**/*", File::FNM_DOTMATCH).reject(&:symlink?)
|
||||
end
|
||||
|
@ -96,9 +96,7 @@ module GitHub
|
||||
return unless Homebrew::EnvConfig.github_api_username
|
||||
return unless Homebrew::EnvConfig.github_api_password
|
||||
|
||||
odeprecated "the GitHub API with HOMEBREW_GITHUB_API_PASSWORD", "HOMEBREW_GITHUB_API_TOKEN"
|
||||
|
||||
[Homebrew::EnvConfig.github_api_password, Homebrew::EnvConfig.github_api_username]
|
||||
odisabled "the GitHub API with HOMEBREW_GITHUB_API_PASSWORD", "HOMEBREW_GITHUB_API_TOKEN"
|
||||
end
|
||||
|
||||
def keychain_username_password
|
||||
@ -510,7 +508,7 @@ module GitHub
|
||||
open_api(url, data_binary_path: local_file, request_method: :POST, scopes: CREATE_ISSUE_FORK_OR_PR_SCOPES)
|
||||
end
|
||||
|
||||
def get_artifact_url(user, repo, pr, workflow_id: "tests.yml", artifact_name: "bottles")
|
||||
def get_workflow_run(user, repo, pr, workflow_id: "tests.yml", artifact_name: "bottles")
|
||||
scopes = CREATE_ISSUE_FORK_OR_PR_SCOPES
|
||||
base_url = "#{API_URL}/repos/#{user}/#{repo}"
|
||||
pr_payload = open_api("#{base_url}/pulls/#{pr}", scopes: scopes)
|
||||
@ -523,6 +521,11 @@ module GitHub
|
||||
run["head_sha"] == pr_sha
|
||||
end
|
||||
|
||||
[workflow_run, pr_sha, pr_branch, pr, workflow_id, scopes, artifact_name]
|
||||
end
|
||||
|
||||
def get_artifact_url(workflow_array)
|
||||
workflow_run, pr_sha, pr_branch, pr, workflow_id, scopes, artifact_name = *workflow_array
|
||||
if workflow_run.empty?
|
||||
raise Error, <<~EOS
|
||||
No matching workflow run found for these criteria!
|
||||
|
@ -34,7 +34,7 @@ module Utils
|
||||
# @api public
|
||||
sig do
|
||||
params(
|
||||
paths: T.any(T::Array[T.untyped], String),
|
||||
paths: T.any(T::Array[T.untyped], String, Pathname),
|
||||
before: T.nilable(T.any(Regexp, String)),
|
||||
after: T.nilable(T.any(String, Symbol)),
|
||||
audit_result: T::Boolean,
|
||||
|
@ -5,70 +5,161 @@
|
||||
#
|
||||
# @api private
|
||||
module PyPI
|
||||
extend T::Sig
|
||||
|
||||
module_function
|
||||
|
||||
PYTHONHOSTED_URL_PREFIX = "https://files.pythonhosted.org/packages/"
|
||||
private_constant :PYTHONHOSTED_URL_PREFIX
|
||||
|
||||
AUTOMATIC_RESOURCE_UPDATE_BLOCKLIST = %w[
|
||||
ansible
|
||||
ansible@2.8
|
||||
cloudformation-cli
|
||||
diffoscope
|
||||
dxpy
|
||||
ipython
|
||||
molecule
|
||||
salt
|
||||
].freeze
|
||||
private_constant :AUTOMATIC_RESOURCE_UPDATE_BLOCKLIST
|
||||
|
||||
@pipgrip_installed = nil
|
||||
|
||||
def url_to_pypi_package_name(url)
|
||||
return unless url.start_with? PYTHONHOSTED_URL_PREFIX
|
||||
# PyPI Package
|
||||
#
|
||||
# @api private
|
||||
class Package
|
||||
extend T::Sig
|
||||
|
||||
File.basename(url).match(/^(.+)-[a-z\d.]+$/)[1]
|
||||
attr_accessor :name
|
||||
attr_accessor :extras
|
||||
attr_accessor :version
|
||||
|
||||
sig { params(package_string: String, is_url: T::Boolean).void }
|
||||
def initialize(package_string, is_url: false)
|
||||
@pypi_info = nil
|
||||
|
||||
if is_url
|
||||
unless package_string.start_with?(PYTHONHOSTED_URL_PREFIX) &&
|
||||
match = File.basename(package_string).match(/^(.+)-([a-z\d.]+?)(?:.tar.gz|.zip)$/)
|
||||
raise ArgumentError, "package should be a valid PyPI url"
|
||||
end
|
||||
|
||||
@name = match[1]
|
||||
@version = match[2]
|
||||
return
|
||||
end
|
||||
|
||||
@name = package_string
|
||||
@name, @version = @name.split("==") if @name.include? "=="
|
||||
|
||||
return unless match = @name.match(/^(.*?)\[(.+)\]$/)
|
||||
|
||||
@name = match[1]
|
||||
@extras = match[2].split ","
|
||||
end
|
||||
|
||||
# Get name, URL, SHA-256 checksum, and latest version for a given PyPI package.
|
||||
sig { params(version: T.nilable(T.any(String, Version))).returns(T.nilable(T::Array[String])) }
|
||||
def pypi_info(version: nil)
|
||||
return @pypi_info if @pypi_info.present? && version.blank?
|
||||
|
||||
version ||= @version
|
||||
metadata_url = if version.present?
|
||||
"https://pypi.org/pypi/#{@name}/#{version}/json"
|
||||
else
|
||||
"https://pypi.org/pypi/#{@name}/json"
|
||||
end
|
||||
out, _, status = curl_output metadata_url, "--location"
|
||||
|
||||
return unless status.success?
|
||||
|
||||
begin
|
||||
json = JSON.parse out
|
||||
rescue JSON::ParserError
|
||||
return
|
||||
end
|
||||
|
||||
sdist = json["urls"].find { |url| url["packagetype"] == "sdist" }
|
||||
return json["info"]["name"] if sdist.nil?
|
||||
|
||||
@pypi_info = [json["info"]["name"], sdist["url"], sdist["digests"]["sha256"], json["info"]["version"]]
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def valid_pypi_package?
|
||||
info = pypi_info
|
||||
info.present? && info.is_a?(Array)
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
out = @name
|
||||
out += "[#{@extras.join(",")}]" if @extras.present?
|
||||
out += "==#{@version}" if @version.present?
|
||||
out
|
||||
end
|
||||
|
||||
sig { params(other: Package).returns(T::Boolean) }
|
||||
def same_package?(other)
|
||||
@name.tr("_", "-") == other.name.tr("_", "-")
|
||||
end
|
||||
|
||||
# Compare only names so we can use .include? on a Package array
|
||||
sig { params(other: Package).returns(T::Boolean) }
|
||||
def ==(other)
|
||||
same_package?(other)
|
||||
end
|
||||
|
||||
sig { params(other: Package).returns(T.nilable(Integer)) }
|
||||
def <=>(other)
|
||||
@name <=> other.name
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(url: String, version: T.any(String, Version)).returns(T.nilable(String)) }
|
||||
def update_pypi_url(url, version)
|
||||
package = url_to_pypi_package_name url
|
||||
return if package.nil?
|
||||
package = Package.new url, is_url: true
|
||||
|
||||
_, url = get_pypi_info(package, version)
|
||||
_, url = package.pypi_info(version: version)
|
||||
url
|
||||
end
|
||||
|
||||
# Get name, URL and SHA-256 checksum for a given PyPI package.
|
||||
def get_pypi_info(package, version)
|
||||
metadata_url = "https://pypi.org/pypi/#{package}/#{version}/json"
|
||||
out, _, status = curl_output metadata_url, "--location"
|
||||
|
||||
return unless status.success?
|
||||
|
||||
begin
|
||||
json = JSON.parse out
|
||||
rescue JSON::ParserError
|
||||
return
|
||||
end
|
||||
|
||||
sdist = json["urls"].find { |url| url["packagetype"] == "sdist" }
|
||||
return json["info"]["name"] if sdist.nil?
|
||||
|
||||
[json["info"]["name"], sdist["url"], sdist["digests"]["sha256"]]
|
||||
end
|
||||
|
||||
# Return true if resources were checked (even if no change).
|
||||
def update_python_resources!(formula, version = nil, print_only: false, silent: false,
|
||||
ignore_non_pypi_packages: false)
|
||||
sig do
|
||||
params(
|
||||
formula: Formula,
|
||||
version: T.nilable(String),
|
||||
package_name: T.nilable(String),
|
||||
extra_packages: T.nilable(T::Array[String]),
|
||||
exclude_packages: T.nilable(T::Array[String]),
|
||||
print_only: T::Boolean,
|
||||
silent: T::Boolean,
|
||||
ignore_non_pypi_packages: T::Boolean,
|
||||
).returns(T.nilable(T::Boolean))
|
||||
end
|
||||
def update_python_resources!(formula, version: nil, package_name: nil, extra_packages: nil, exclude_packages: nil,
|
||||
print_only: false, silent: false, ignore_non_pypi_packages: false)
|
||||
|
||||
if !print_only && AUTOMATIC_RESOURCE_UPDATE_BLOCKLIST.include?(formula.full_name)
|
||||
odie "The resources for \"#{formula.name}\" need special attention. Please update them manually."
|
||||
return
|
||||
auto_update_list = formula.tap&.pypi_formula_mappings
|
||||
if auto_update_list.present? && auto_update_list.key?(formula.full_name) &&
|
||||
package_name.blank? && extra_packages.blank? && exclude_packages.blank?
|
||||
|
||||
list_entry = auto_update_list[formula.full_name]
|
||||
case list_entry
|
||||
when false
|
||||
unless print_only
|
||||
odie "The resources for \"#{formula.name}\" need special attention. Please update them manually."
|
||||
end
|
||||
when String
|
||||
package_name = list_entry
|
||||
when Hash
|
||||
package_name = list_entry["package_name"]
|
||||
extra_packages = list_entry["extra_packages"]
|
||||
exclude_packages = list_entry["exclude_packages"]
|
||||
end
|
||||
end
|
||||
|
||||
pypi_name = url_to_pypi_package_name formula.stable.url
|
||||
main_package = if package_name.present?
|
||||
Package.new(package_name)
|
||||
else
|
||||
begin
|
||||
Package.new(formula.stable.url, is_url: true)
|
||||
rescue ArgumentError
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
if pypi_name.nil?
|
||||
if main_package.blank?
|
||||
return if ignore_non_pypi_packages
|
||||
|
||||
odie <<~EOS
|
||||
@ -77,47 +168,81 @@ module PyPI
|
||||
EOS
|
||||
end
|
||||
|
||||
version ||= formula.version
|
||||
unless main_package.valid_pypi_package?
|
||||
return if ignore_non_pypi_packages
|
||||
|
||||
if get_pypi_info(pypi_name, version).blank?
|
||||
odie "\"#{pypi_name}\" at version #{version} is not available on PyPI." unless ignore_non_pypi_packages
|
||||
return
|
||||
odie "\"#{main_package}\" is not available on PyPI."
|
||||
end
|
||||
|
||||
non_pypi_resources = formula.resources.reject do |resource|
|
||||
resource.url.start_with? PYTHONHOSTED_URL_PREFIX
|
||||
main_package.version = version if version.present?
|
||||
|
||||
extra_packages = (extra_packages || []).map { |p| Package.new p }
|
||||
exclude_packages = (exclude_packages || []).map { |p| Package.new p }
|
||||
|
||||
input_packages = [main_package]
|
||||
extra_packages.each do |extra_package|
|
||||
if !extra_package.valid_pypi_package? && !ignore_non_pypi_packages
|
||||
odie "\"#{extra_package}\" is not available on PyPI."
|
||||
end
|
||||
|
||||
input_packages.each do |existing_package|
|
||||
if existing_package.same_package?(extra_package) && existing_package.version != extra_package.version
|
||||
odie "Conflicting versions specified for the `#{extra_package.name}` package: "\
|
||||
"#{existing_package.version}, #{extra_package.version}"
|
||||
end
|
||||
end
|
||||
|
||||
input_packages << extra_package unless input_packages.include? extra_package
|
||||
end
|
||||
|
||||
if non_pypi_resources.present? && !print_only
|
||||
odie "\"#{formula.name}\" contains non-PyPI resources. Please update the resources manually."
|
||||
formula.resources.each do |resource|
|
||||
if !print_only && !resource.url.start_with?(PYTHONHOSTED_URL_PREFIX)
|
||||
odie "\"#{formula.name}\" contains non-PyPI resources. Please update the resources manually."
|
||||
end
|
||||
end
|
||||
|
||||
@pipgrip_installed ||= Formula["pipgrip"].any_version_installed?
|
||||
odie '"pipgrip" must be installed (`brew install pipgrip`)' unless @pipgrip_installed
|
||||
|
||||
ohai "Retrieving PyPI dependencies for \"#{pypi_name}==#{version}\"..." if !print_only && !silent
|
||||
pipgrip_output = Utils.popen_read Formula["pipgrip"].bin/"pipgrip", "--json", "--no-cache-dir",
|
||||
"#{pypi_name}==#{version}"
|
||||
unless $CHILD_STATUS.success?
|
||||
odie <<~EOS
|
||||
Unable to determine dependencies for \"#{pypi_name}\" because of a failure when running
|
||||
`pipgrip --json --no-cache-dir #{pypi_name}==#{version}`.
|
||||
Please update the resources for \"#{formula.name}\" manually.
|
||||
EOS
|
||||
end
|
||||
found_packages = []
|
||||
input_packages.each do |package|
|
||||
ohai "Retrieving PyPI dependencies for \"#{package}\"..." if !print_only && !silent
|
||||
pipgrip_output = Utils.popen_read Formula["pipgrip"].bin/"pipgrip", "--json", "--no-cache-dir", package.to_s
|
||||
unless $CHILD_STATUS.success?
|
||||
odie <<~EOS
|
||||
Unable to determine dependencies for \"#{package}\" because of a failure when running
|
||||
`pipgrip --json --no-cache-dir #{package}`.
|
||||
Please update the resources for \"#{formula.name}\" manually.
|
||||
EOS
|
||||
end
|
||||
|
||||
packages = JSON.parse(pipgrip_output).sort.to_h
|
||||
JSON.parse(pipgrip_output).to_h.each do |new_name, new_version|
|
||||
new_package = Package.new("#{new_name}==#{new_version}")
|
||||
|
||||
found_packages.each do |existing_package|
|
||||
if existing_package.same_package?(new_package) && existing_package.version != new_package.version
|
||||
odie "Conflicting versions found for the `#{new_package.name}` resource: "\
|
||||
"#{existing_package.version}, #{new_package.version}"
|
||||
end
|
||||
end
|
||||
|
||||
found_packages << new_package unless found_packages.include? new_package
|
||||
end
|
||||
end
|
||||
|
||||
# Remove extra packages that may be included in pipgrip output
|
||||
exclude_list = %W[#{pypi_name.downcase} argparse pip setuptools wheel wsgiref]
|
||||
packages.delete_if do |package|
|
||||
exclude_list.include? package
|
||||
end
|
||||
exclude_list = %W[#{main_package.name} argparse pip setuptools wheel wsgiref].map { |p| Package.new p }
|
||||
found_packages.delete_if { |package| exclude_list.include? package }
|
||||
|
||||
new_resource_blocks = ""
|
||||
packages.each do |package, package_version|
|
||||
ohai "Getting PyPI info for \"#{package}==#{package_version}\"" if !print_only && !silent
|
||||
name, url, checksum = get_pypi_info package, package_version
|
||||
found_packages.sort.each do |package|
|
||||
if exclude_packages.include? package
|
||||
ohai "Excluding \"#{package}\"" if !print_only && !silent
|
||||
next
|
||||
end
|
||||
|
||||
ohai "Getting PyPI info for \"#{package}\"" if !print_only && !silent
|
||||
name, url, checksum = package.pypi_info
|
||||
# Fail if unable to find name, url or checksum for any resource
|
||||
if name.blank?
|
||||
odie "Unable to resolve some dependencies. Please update the resources for \"#{formula.name}\" manually."
|
||||
|
@ -32,7 +32,6 @@ module SharedAudits
|
||||
end
|
||||
|
||||
GITHUB_PRERELEASE_ALLOWLIST = {
|
||||
"amd-power-gadget" => :all,
|
||||
"elm-format" => "0.8.3",
|
||||
"extraterm" => :all,
|
||||
"freetube" => :all,
|
||||
|
10
Library/Homebrew/vendor/bundle/bundler/setup.rb
vendored
10
Library/Homebrew/vendor/bundle/bundler/setup.rb
vendored
@ -47,11 +47,11 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrobots-0.1.2/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mechanize-2.7.6/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/method_source-1.0.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mustache-1.1.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.20.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.3.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.20.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.4.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-2.7.2.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.0.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.6100/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.6101/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parlour-4.0.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.3.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.5.0/lib"
|
||||
@ -68,8 +68,8 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-mocks-3.10.0/li
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-3.10.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-its-1.3.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-retry-0.6.2/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.6100-universal-darwin-19/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.6100/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.6101-universal-darwin-19/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.6101/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-sorbet-1.7.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.1.1/lib"
|
||||
|
@ -68,7 +68,6 @@ pr-publish
|
||||
pr-pull
|
||||
pr-upload
|
||||
prof
|
||||
pull
|
||||
readall
|
||||
reinstall
|
||||
release-notes
|
||||
|
@ -84,7 +84,7 @@ GEM
|
||||
html-pipeline (2.14.0)
|
||||
activesupport (>= 2)
|
||||
nokogiri (>= 1.4)
|
||||
html-proofer (3.17.0)
|
||||
html-proofer (3.17.1)
|
||||
addressable (~> 2.3)
|
||||
mercenary (~> 0.3)
|
||||
nokogumbo (~> 2.0)
|
||||
@ -219,12 +219,12 @@ GEM
|
||||
multipart-post (2.1.1)
|
||||
nokogiri (1.10.10)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
nokogumbo (2.0.2)
|
||||
nokogumbo (2.0.3)
|
||||
nokogiri (~> 1.8, >= 1.8.4)
|
||||
octokit (4.18.0)
|
||||
faraday (>= 0.9)
|
||||
sawyer (~> 0.8.0, >= 0.5.3)
|
||||
parallel (1.20.0)
|
||||
parallel (1.20.1)
|
||||
pathutil (0.16.2)
|
||||
forwardable-extended (~> 2.6)
|
||||
public_suffix (3.1.1)
|
||||
|
@ -11,7 +11,7 @@ it does it too. You have to confirm everything it will do before it starts.
|
||||
## macOS Requirements
|
||||
|
||||
* A 64-bit Intel CPU <sup>[1](#1)</sup>
|
||||
* macOS High Sierra (10.13) (or higher) <sup>[2](#2)</sup>
|
||||
* macOS Mojave (10.14) (or higher) <sup>[2](#2)</sup>
|
||||
* Command Line Tools (CLT) for Xcode: `xcode-select --install`,
|
||||
[developer.apple.com/downloads](https://developer.apple.com/downloads) or
|
||||
[Xcode](https://itunes.apple.com/us/app/xcode/id497799835) <sup>[3](#3)</sup>
|
||||
@ -52,7 +52,7 @@ Uninstallation is documented in the [FAQ](FAQ.md).
|
||||
<a name="1"><sup>1</sup></a> For 32-bit or PPC support see
|
||||
[Tigerbrew](https://github.com/mistydemeo/tigerbrew).
|
||||
|
||||
<a name="2"><sup>2</sup></a> 10.13 or higher is recommended. 10.9–10.12 are
|
||||
<a name="2"><sup>2</sup></a> 10.14 or higher is recommended. 10.9–10.13 are
|
||||
supported on a best-effort basis. For 10.4-10.6 see
|
||||
[Tigerbrew](https://github.com/mistydemeo/tigerbrew).
|
||||
|
||||
|
@ -905,14 +905,16 @@ Display the path to the file being used when invoking `brew` *`cmd`*.
|
||||
|
||||
### `create` [*`options`*] *`URL`*
|
||||
|
||||
Generate a formula for the downloadable file at *`URL`* and open it in the editor.
|
||||
Homebrew will attempt to automatically derive the formula name and version, but
|
||||
if it fails, you'll have to make your own template. The `wget` formula serves as
|
||||
a simple example. For the complete API, see:
|
||||
Generate a formula or, with `--cask`, a cask for the downloadable file at *`URL`*
|
||||
and open it in the editor. Homebrew will attempt to automatically derive the
|
||||
formula name and version, but if it fails, you'll have to make your own template.
|
||||
The `wget` formula serves as a simple example. For the complete API, see:
|
||||
<https://rubydoc.brew.sh/Formula>
|
||||
|
||||
* `--autotools`:
|
||||
Create a basic template for an Autotools-style build.
|
||||
* `--cask`:
|
||||
Create a basic template for a cask.
|
||||
* `--cmake`:
|
||||
Create a basic template for a CMake-style build.
|
||||
* `--crystal`:
|
||||
@ -936,9 +938,9 @@ a simple example. For the complete API, see:
|
||||
* `--HEAD`:
|
||||
Indicate that *`URL`* points to the package's repository rather than a file.
|
||||
* `--set-name`:
|
||||
Explicitly set the *`name`* of the new formula.
|
||||
Explicitly set the *`name`* of the new formula or cask.
|
||||
* `--set-version`:
|
||||
Explicitly set the *`version`* of the new formula.
|
||||
Explicitly set the *`version`* of the new formula or cask.
|
||||
* `--set-license`:
|
||||
Explicitly set the *`license`* of the new formula.
|
||||
* `--tap`:
|
||||
@ -961,17 +963,6 @@ Build bottles for these formulae with GitHub Actions.
|
||||
* `--upload`:
|
||||
Upload built bottles to Bintray.
|
||||
|
||||
### `diy` [*`options`*]
|
||||
|
||||
Automatically determine the installation prefix for non-Homebrew software.
|
||||
Using the output from this command, you can install your own software into
|
||||
the Cellar and then link it into Homebrew's prefix with `brew link`.
|
||||
|
||||
* `--name`:
|
||||
Explicitly set the *`name`* of the package being installed.
|
||||
* `--version`:
|
||||
Explicitly set the *`version`* of the package being installed.
|
||||
|
||||
### `edit` [*`formula`*|*`cask`*]
|
||||
|
||||
Open a *`formula`* or *`cask`* in the editor set by `EDITOR` or `HOMEBREW_EDITOR`,
|
||||
@ -1055,6 +1046,17 @@ Generate Homebrew's manpages.
|
||||
* `--link`:
|
||||
This is now done automatically by `brew update`.
|
||||
|
||||
### `mirror` *`formula`*
|
||||
|
||||
Reupload the stable URL of a formula to Bintray for use as a mirror.
|
||||
|
||||
* `--bintray-org`:
|
||||
Upload to the specified Bintray organisation (default: `homebrew`).
|
||||
* `--bintray-repo`:
|
||||
Upload to the specified Bintray repository (default: `mirror`).
|
||||
* `--no-publish`:
|
||||
Upload to Bintray, but don't publish.
|
||||
|
||||
### `pr-automerge` [*`options`*]
|
||||
|
||||
Find pull requests that can be automatically merged using `brew pr-publish`.
|
||||
@ -1115,7 +1117,7 @@ Requires write access to the repository.
|
||||
* `--message`:
|
||||
Message to include when autosquashing revision bumps, deletions, and rebuilds.
|
||||
* `--workflow`:
|
||||
Retrieve artifacts from the specified workflow (default: `tests.yml`).
|
||||
Retrieve artifacts from the specified workflow (default: `tests.yml`). Legacy: use --workflows instead
|
||||
* `--artifact`:
|
||||
Download artifacts with the specified name (default: `bottles`).
|
||||
* `--bintray-org`:
|
||||
@ -1126,6 +1128,10 @@ Requires write access to the repository.
|
||||
Use the specified *`URL`* as the root of the bottle's URL instead of Homebrew's default.
|
||||
* `--bintray-mirror`:
|
||||
Use the specified Bintray repository to automatically mirror stable URLs defined in the formulae (default: `mirror`).
|
||||
* `--workflows`:
|
||||
Retrieve artifacts from the specified workflow (default: `tests.yml`) Comma-separated list to include multiple workflows.
|
||||
* `--ignore-missing-artifacts`:
|
||||
Comma-separated list of workflows which can be ignored if they have not been run.
|
||||
|
||||
### `pr-upload` [*`options`*]
|
||||
|
||||
@ -1305,6 +1311,12 @@ Update versions for PyPI resource blocks in *`formula`*.
|
||||
Don't fail if *`formula`* is not a PyPI package.
|
||||
* `--version`:
|
||||
Use the specified *`version`* when finding resources for *`formula`*. If no version is specified, the current version for *`formula`* will be used.
|
||||
* `--package-name`:
|
||||
Use the specified *`package-name`* when finding resources for *`formula`*. If no package name is specified, it will be inferred from the formula's stable URL.
|
||||
* `--extra-packages`:
|
||||
Include these additional packages when finding resources.
|
||||
* `--exclude-packages`:
|
||||
Exclude these packages when finding resources.
|
||||
|
||||
### `update-test` [*`options`*]
|
||||
|
||||
|
@ -1241,13 +1241,17 @@ Treat all named arguments as casks\.
|
||||
Display the path to the file being used when invoking \fBbrew\fR \fIcmd\fR\.
|
||||
.
|
||||
.SS "\fBcreate\fR [\fIoptions\fR] \fIURL\fR"
|
||||
Generate a formula for the downloadable file at \fIURL\fR and open it in the editor\. Homebrew will attempt to automatically derive the formula name and version, but if it fails, you\'ll have to make your own template\. The \fBwget\fR formula serves as a simple example\. For the complete API, see: \fIhttps://rubydoc\.brew\.sh/Formula\fR
|
||||
Generate a formula or, with \fB\-\-cask\fR, a cask for the downloadable file at \fIURL\fR and open it in the editor\. Homebrew will attempt to automatically derive the formula name and version, but if it fails, you\'ll have to make your own template\. The \fBwget\fR formula serves as a simple example\. For the complete API, see: \fIhttps://rubydoc\.brew\.sh/Formula\fR
|
||||
.
|
||||
.TP
|
||||
\fB\-\-autotools\fR
|
||||
Create a basic template for an Autotools\-style build\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-cask\fR
|
||||
Create a basic template for a cask\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-cmake\fR
|
||||
Create a basic template for a CMake\-style build\.
|
||||
.
|
||||
@ -1293,11 +1297,11 @@ Indicate that \fIURL\fR points to the package\'s repository rather than a file\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-set\-name\fR
|
||||
Explicitly set the \fIname\fR of the new formula\.
|
||||
Explicitly set the \fIname\fR of the new formula or cask\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-set\-version\fR
|
||||
Explicitly set the \fIversion\fR of the new formula\.
|
||||
Explicitly set the \fIversion\fR of the new formula or cask\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-set\-license\fR
|
||||
@ -1334,17 +1338,6 @@ Dispatch specified workflow (default: \fBdispatch\-build\-bottle\.yml\fR)\.
|
||||
\fB\-\-upload\fR
|
||||
Upload built bottles to Bintray\.
|
||||
.
|
||||
.SS "\fBdiy\fR [\fIoptions\fR]"
|
||||
Automatically determine the installation prefix for non\-Homebrew software\. Using the output from this command, you can install your own software into the Cellar and then link it into Homebrew\'s prefix with \fBbrew link\fR\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-name\fR
|
||||
Explicitly set the \fIname\fR of the package being installed\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-version\fR
|
||||
Explicitly set the \fIversion\fR of the package being installed\.
|
||||
.
|
||||
.SS "\fBedit\fR [\fIformula\fR|\fIcask\fR]"
|
||||
Open a \fIformula\fR or \fIcask\fR in the editor set by \fBEDITOR\fR or \fBHOMEBREW_EDITOR\fR, or open the Homebrew repository for editing if no formula is provided\.
|
||||
.
|
||||
@ -1444,6 +1437,21 @@ Return a failing status code if changes are detected in the manpage outputs\. Th
|
||||
\fB\-\-link\fR
|
||||
This is now done automatically by \fBbrew update\fR\.
|
||||
.
|
||||
.SS "\fBmirror\fR \fIformula\fR"
|
||||
Reupload the stable URL of a formula to Bintray for use as a mirror\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-bintray\-org\fR
|
||||
Upload to the specified Bintray organisation (default: \fBhomebrew\fR)\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-bintray\-repo\fR
|
||||
Upload to the specified Bintray repository (default: \fBmirror\fR)\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-no\-publish\fR
|
||||
Upload to Bintray, but don\'t publish\.
|
||||
.
|
||||
.SS "\fBpr\-automerge\fR [\fIoptions\fR]"
|
||||
Find pull requests that can be automatically merged using \fBbrew pr\-publish\fR\.
|
||||
.
|
||||
@ -1539,7 +1547,7 @@ Message to include when autosquashing revision bumps, deletions, and rebuilds\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-workflow\fR
|
||||
Retrieve artifacts from the specified workflow (default: \fBtests\.yml\fR)\.
|
||||
Retrieve artifacts from the specified workflow (default: \fBtests\.yml\fR)\. Legacy: use \-\-workflows instead
|
||||
.
|
||||
.TP
|
||||
\fB\-\-artifact\fR
|
||||
@ -1561,6 +1569,14 @@ Use the specified \fIURL\fR as the root of the bottle\'s URL instead of Homebrew
|
||||
\fB\-\-bintray\-mirror\fR
|
||||
Use the specified Bintray repository to automatically mirror stable URLs defined in the formulae (default: \fBmirror\fR)\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-workflows\fR
|
||||
Retrieve artifacts from the specified workflow (default: \fBtests\.yml\fR) Comma\-separated list to include multiple workflows\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-ignore\-missing\-artifacts\fR
|
||||
Comma\-separated list of workflows which can be ignored if they have not been run\.
|
||||
.
|
||||
.SS "\fBpr\-upload\fR [\fIoptions\fR]"
|
||||
Apply the bottle commit and publish bottles to Bintray or GitHub Releases\.
|
||||
.
|
||||
@ -1797,6 +1813,18 @@ Don\'t fail if \fIformula\fR is not a PyPI package\.
|
||||
\fB\-\-version\fR
|
||||
Use the specified \fIversion\fR when finding resources for \fIformula\fR\. If no version is specified, the current version for \fIformula\fR will be used\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-package\-name\fR
|
||||
Use the specified \fIpackage\-name\fR when finding resources for \fIformula\fR\. If no package name is specified, it will be inferred from the formula\'s stable URL\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-extra\-packages\fR
|
||||
Include these additional packages when finding resources\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-exclude\-packages\fR
|
||||
Exclude these packages when finding resources\.
|
||||
.
|
||||
.SS "\fBupdate\-test\fR [\fIoptions\fR]"
|
||||
Run a test of \fBbrew update\fR with a new repository clone\. If no options are passed, use \fBorigin/master\fR as the start commit\.
|
||||
.
|
||||
|
Loading…
x
Reference in New Issue
Block a user