Merge branch 'master' into mohammad

This commit is contained in:
Mohammad Zain Abbas 2022-09-14 05:19:50 +02:00
commit e058da1706
762 changed files with 8725 additions and 7268 deletions

View File

@ -11,7 +11,7 @@ on:
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
permissions:
actions: read
contents: read

View File

@ -14,7 +14,7 @@ permissions:
jobs:
ubuntu:
if: startsWith(github.repository, 'Homebrew/')
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:

View File

@ -46,12 +46,13 @@ jobs:
if git ls-remote --exit-code --heads origin "${BRANCH}"
then
git checkout "${BRANCH}"
git reset --hard origin/master
git checkout "${GITHUB_WORKSPACE}/Library/Homebrew/sorbet"
else
git checkout --no-track -B "${BRANCH}" origin/master
fi
if brew typecheck --update --fail-if-not-changed
brew typecheck --update
if ! git diff --stat --exit-code "${GITHUB_WORKSPACE}/Library/Homebrew/sorbet"
then
git add "${GITHUB_WORKSPACE}/Library/Homebrew/sorbet"
git commit -m "sorbet: Update RBI files." \

View File

@ -7,12 +7,15 @@ on:
- master
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
permissions:
contents: read
jobs:
spdx:
if: github.repository == 'Homebrew/brew'
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Set up Homebrew
id: set-up-homebrew
@ -42,12 +45,12 @@ jobs:
if git ls-remote --exit-code --heads origin "${BRANCH}"
then
git checkout "${BRANCH}"
git reset --hard origin/master
git checkout "${GITHUB_WORKSPACE}/Library/Homebrew/data/spdx"
else
git checkout --no-track -B "${BRANCH}" origin/master
fi
if brew update-license-data --fail-if-not-changed
if brew update-license-data
then
git add "${GITHUB_WORKSPACE}/Library/Homebrew/data/spdx"
git commit -m "spdx: update license data." -m "Autogenerated by [a scheduled GitHub Action](https://github.com/Homebrew/brew/blob/master/.github/workflows/spdx.yml)."

View File

@ -1,9 +1,9 @@
name: Update maintainers, manpage and completions
name: Update sponsors, maintainers, manpage and completions
on:
push:
paths:
- .github/workflows/update-man-completions.yml
- .github/workflows/sponsors-maintainers-man-completions.yml
- README.md
- Library/Homebrew/cmd/**
- Library/Homebrew/dev-cmd/**
@ -12,8 +12,6 @@ on:
- Library/Homebrew/cli/parser.rb
- Library/Homebrew/completions.rb
- Library/Homebrew/env_config.rb
branches:
- master
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
@ -22,11 +20,12 @@ permissions:
contents: read
jobs:
update-manpage:
runs-on: ubuntu-latest
updates:
runs-on: ubuntu-22.04
if: github.repository == 'Homebrew/brew'
steps:
- name: Setup Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
- name: Configure Git user
@ -39,35 +38,68 @@ jobs:
with:
signing_key: ${{ secrets.BREWTESTBOT_GPG_SIGNING_SUBKEY }}
- name: Update maintainers, manpage and completions
- name: Cache Bundler RubyGems
uses: actions/cache@v1
with:
path: ${{ steps.set-up-homebrew.outputs.gems-path }}
key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }}
restore-keys: ${{ runner.os }}-rubygems-
- name: Update sponsors, maintainers, manpage and completions
id: update
run: |
git fetch origin
BRANCH=update-man-completions
if [[ -n "$GITHUB_REF_NAME" && "$GITHUB_REF_NAME" != "master" ]]
then
BRANCH="$GITHUB_REF_NAME"
else
BRANCH=sponsors-maintainers-man-completions
fi
echo "::set-output name=branch::${BRANCH}"
if git ls-remote --exit-code --heads origin "${BRANCH}"
then
git checkout "${BRANCH}"
git reset --hard origin/master
git checkout "${GITHUB_WORKSPACE}/README.md" \
"${GITHUB_WORKSPACE}/docs/Manpage.md" \
"${GITHUB_WORKSPACE}/manpages/brew.1" \
"${GITHUB_WORKSPACE}/completions"
else
git checkout --no-track -B "${BRANCH}" origin/master
fi
if [[ "${{github.event_name}}" != "push" ]]
if brew update-sponsors
then
brew update-maintainers
git add "${GITHUB_WORKSPACE}/README.md"
git commit -m "Update sponsors." \
-m "Autogenerated by the [sponsors-maintainers-man-completions](https://github.com/Homebrew/brew/blob/HEAD/.github/workflows/sponsors-maintainers-man-completions.yml) workflow."
COMMITTED=true
fi
if brew generate-man-completions --fail-if-not-changed
if brew update-maintainers
then
git add "${GITHUB_WORKSPACE}/README.md" \
"${GITHUB_WORKSPACE}/docs/Manpage.md" \
"${GITHUB_WORKSPACE}/manpages/brew.1"
git commit -m "Update maintainers." \
-m "Autogenerated by the [sponsors-maintainers-man-completions](https://github.com/Homebrew/brew/blob/HEAD/.github/workflows/sponsors-maintainers-man-completions.yml) workflow."
COMMITTED=true
fi
if brew generate-man-completions
then
git add "${GITHUB_WORKSPACE}/README.md" \
"${GITHUB_WORKSPACE}/docs/Manpage.md" \
"${GITHUB_WORKSPACE}/manpages/brew.1" \
"${GITHUB_WORKSPACE}/completions"
git commit -m "Update maintainers, manpage and completions." \
-m "Autogenerated by the [update-man-completions](https://github.com/Homebrew/brew/blob/HEAD/.github/workflows/update-man-completions.yml) workflow."
git commit -m "Update manpage and completions." \
-m "Autogenerated by the [sponsors-maintainers-man-completions](https://github.com/Homebrew/brew/blob/HEAD/.github/workflows/sponsors-maintainers-man-completions.yml) workflow."
COMMITTED=true
fi
if [[ -n "$COMMITTED" ]]
then
echo "::set-output name=committed::true"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state")"
if [[ "${PULL_REQUEST_STATE}" != "OPEN" ]]
@ -77,7 +109,7 @@ jobs:
fi
env:
GITHUB_TOKEN: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.HOMEBREW_BREW_UPDATE_MAINTAINERS_TOKEN }}
HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.HOMEBREW_BREW_UPDATE_SPONSORS_MAINTAINERS_TOKEN }}
HOMEBREW_GPG_PASSPHRASE: ${{ secrets.BREWTESTBOT_GPG_SIGNING_SUBKEY_PASSPHRASE }}
- name: Push commits

View File

@ -20,7 +20,7 @@ concurrency:
jobs:
syntax:
if: github.repository == 'Homebrew/brew'
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Set up Homebrew
id: set-up-homebrew
@ -52,7 +52,7 @@ jobs:
name: tap syntax (Linux)
needs: syntax
if: startsWith(github.repository, 'Homebrew/')
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Set up Homebrew
id: set-up-homebrew
@ -82,13 +82,13 @@ jobs:
brew update-test --commit=HEAD
- name: Run brew readall on all taps
run: brew readall --aliases
run: brew readall --eval-all --aliases
- name: Run brew style on homebrew-core for Linux
run: brew style --display-cop-names homebrew/core
- name: Run brew audit --skip-style on all taps
run: brew audit --skip-style --except=version --display-failures-only
run: brew audit --eval-all --skip-style --except=version --display-failures-only
- name: Set up all Homebrew taps
run: |
@ -146,7 +146,7 @@ jobs:
vendored-gems:
name: vendored gems (Linux)
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Set up Homebrew
id: set-up-homebrew
@ -167,31 +167,62 @@ jobs:
docker:
needs: syntax
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
- name: Build Docker image
run: docker build -t brew --build-arg=version=16.04 .
run: |
docker build -t brew --build-arg=version=22.04 \
--label org.opencontainers.image.created="$(date --rfc-3339=seconds --utc)" \
--label org.opencontainers.image.url="https://brew.sh" \
--label org.opencontainers.image.documentation="https://docs.brew.sh" \
--label org.opencontainers.image.source="https://github.com/${GITHUB_REPOSITORY}" \
--label org.opencontainers.image.revision="${GITHUB_SHA}" \
--label org.opencontainers.image.vendor="${GITHUB_REPOSITORY_OWNER}" \
--label org.opencontainers.image.licenses="BSD-2-Clause" \
.
- name: Deploy the Docker image to GitHub Packages and Docker Hub
if: github.ref == 'refs/heads/master'
run: |
echo ${{secrets.HOMEBREW_BREW_GITHUB_PACKAGES_TOKEN}} |
docker login ghcr.io -u BrewTestBot --password-stdin
docker tag brew "ghcr.io/homebrew/ubuntu16.04:master"
docker push "ghcr.io/homebrew/ubuntu16.04:master"
docker tag brew "ghcr.io/homebrew/ubuntu22.04:master"
docker push "ghcr.io/homebrew/ubuntu22.04:master"
echo ${{secrets.HOMEBREW_BREW_DOCKER_TOKEN}} |
docker login -u brewtestbot --password-stdin
docker tag brew "homebrew/ubuntu16.04:master"
docker tag brew "homebrew/ubuntu22.04:master"
docker push "homebrew/ubuntu22.04:master"
- name: Build deprecated 16.04 Docker image
run: |
echo "homebrew/ubuntu16.04:master is deprecated and will soon be retired. Use homebrew/ubuntu22.04:master or homebrew/ubuntu16.04 or homebrew/brew. For CI, homebrew/ubuntu22.04:master is recommended." > .docker-deprecate
docker build -t brew-deprecated --build-arg=version=16.04 \
--label org.opencontainers.image.created="$(date --rfc-3339=seconds --utc)" \
--label org.opencontainers.image.url="https://brew.sh" \
--label org.opencontainers.image.documentation="https://docs.brew.sh" \
--label org.opencontainers.image.source="https://github.com/${GITHUB_REPOSITORY}" \
--label org.opencontainers.image.revision="${GITHUB_SHA}" \
--label org.opencontainers.image.vendor="${GITHUB_REPOSITORY_OWNER}" \
--label org.opencontainers.image.licenses="BSD-2-Clause" \
--label org.opencontainers.image.support.end-of-support="2022-09-07T00:00:00Z" \
.
- name: Deploy the deprecated 16.04 Docker image to GitHub Packages and Docker Hub
if: github.ref == 'refs/heads/master'
run: |
docker tag brew-deprecated "ghcr.io/homebrew/ubuntu16.04:master"
docker push "ghcr.io/homebrew/ubuntu16.04:master"
docker tag brew-deprecated "homebrew/ubuntu16.04:master"
docker push "homebrew/ubuntu16.04:master"
tests:
name: ${{ matrix.name }}
needs: syntax
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
strategy:
matrix:
include:
@ -244,7 +275,7 @@ jobs:
test-default-formula-linux:
name: test default formula (Linux)
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
env:
HOMEBREW_BOOTSNAP: 1
steps:
@ -301,7 +332,7 @@ jobs:
Library/Taps/homebrew/homebrew-services
- name: Run brew readall on all taps
run: brew readall --aliases
run: brew readall --eval-all --aliases
- name: Install brew tests dependencies
run: brew install subversion curl

View File

@ -29,7 +29,7 @@ jobs:
contains(github.event.pull_request.labels.*.name, 'stale')
)
)
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Mark/Close Stale Issues and Pull Requests
uses: actions/stale@v5
@ -55,7 +55,7 @@ jobs:
contains(github.event.pull_request.labels.*.name, 'stale')
)
)
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Mark/Close Stale `bump-formula-pr` and `bump-cask-pr` Pull Requests
uses: actions/stale@v5
@ -72,7 +72,7 @@ jobs:
lock-threads:
if: startsWith(github.repository, 'Homebrew/') && github.event_name != 'issue_comment'
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Lock Outdated Threads
uses: dessant/lock-threads@e460dfeb36e731f3aeb214be6b0c9a9d9a67eda6

View File

@ -18,7 +18,7 @@ concurrency: triage-${{ github.head_ref }}
jobs:
review:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
if: startsWith(github.repository, 'Homebrew/')
steps:
- name: Re-run this workflow

View File

@ -60,16 +60,12 @@ jobs:
GEM_NAME: ${{ steps.checkout.outputs.gem_name }}
HOMEBREW_GPG_PASSPHRASE: ${{ secrets.BREWTESTBOT_GPG_SIGNING_SUBKEY_PASSPHRASE }}
run: |
set -u
if brew typecheck --update --fail-if-not-changed
brew typecheck --update
if ! git diff --stat --exit-code "${GITHUB_WORKSPACE}/Library/Homebrew/sorbet"
then
if git add Library/Homebrew/sorbet
then
git commit -m "Update RBI files for ${GEM_NAME}."
fi
git reset --hard
git add "${GITHUB_WORKSPACE}/Library/Homebrew/sorbet"
git commit -m "Update RBI files for ${GEM_NAME}." \
-m "Autogenerated by the [vendor-gems](https://github.com/Homebrew/brew/blob/HEAD/.github/workflows/vendor-gemss.yml) workflow."
fi
- name: Push to pull request

View File

@ -21,6 +21,8 @@ RSpec/RepeatedDescription:
Enabled: false
RSpec/StubbedMock:
Enabled: false
RSpec/NoExpectationExample:
Enabled: false
# TODO: try to reduce these
RSpec/ExampleLength:

View File

@ -1,7 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (6.1.6.1)
activesupport (6.1.7)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
@ -58,7 +58,7 @@ GEM
mime-types-data (3.2022.0105)
mini_portile2 (2.8.0)
minitest (5.16.3)
msgpack (1.5.5)
msgpack (1.5.6)
mustache (1.1.1)
net-http-digest_auth (1.4.1)
net-http-persistent (4.0.1)
@ -67,7 +67,7 @@ GEM
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
parallel (1.22.1)
parallel_tests (3.11.1)
parallel_tests (3.12.0)
parallel
parlour (8.0.0)
commander (~> 4.5)
@ -84,7 +84,7 @@ GEM
method_source (~> 1.0)
public_suffix (5.0.0)
racc (1.6.0)
rack (2.2.4)
rack (3.0.0)
rainbow (3.1.1)
rbi (0.0.14)
ast
@ -104,7 +104,7 @@ GEM
rspec-mocks (~> 3.11.0)
rspec-core (3.11.0)
rspec-support (~> 3.11.0)
rspec-expectations (3.11.0)
rspec-expectations (3.11.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-github (2.3.1)
@ -117,9 +117,9 @@ GEM
rspec-support (~> 3.11.0)
rspec-retry (0.6.2)
rspec-core (> 3.3)
rspec-sorbet (1.8.3)
rspec-sorbet (1.9.0)
sorbet-runtime
rspec-support (3.11.0)
rspec-support (3.11.1)
rspec-wait (0.0.9)
rspec (>= 3, < 4)
rspec_junit_formatter (0.5.1)
@ -136,15 +136,15 @@ GEM
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.21.0)
parser (>= 3.1.1.0)
rubocop-performance (1.14.3)
rubocop-performance (1.15.0)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.15.2)
rubocop-rails (2.16.0)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.7.0, < 2.0)
rubocop-rspec (2.12.1)
rubocop (~> 1.31)
rubocop (>= 1.33.0, < 2.0)
rubocop-rspec (2.13.1)
rubocop (~> 1.33)
rubocop-sorbet (0.6.11)
rubocop (>= 0.90.0)
ruby-macho (3.0.0)

View File

@ -33,7 +33,7 @@ module Homebrew
if cached_formula_json_file.exist? && !cached_formula_json_file.empty?
curl_args.prepend("--time-cond", cached_formula_json_file)
end
curl_download(*curl_args, to: HOMEBREW_CACHE_API/"#{formula_api_path}.json", max_time: 5)
curl_download(*curl_args, to: cached_formula_json_file, max_time: 5)
json_formulae = JSON.parse(cached_formula_json_file.read)

View File

@ -7,6 +7,7 @@ if ENV["HOMEBREW_STACKPROF"]
end
raise "HOMEBREW_BREW_FILE was not exported! Please call bin/brew directly!" unless ENV["HOMEBREW_BREW_FILE"]
raise "#{__FILE__} must not be loaded via `require`." if $PROGRAM_NAME != __FILE__
std_trap = trap("INT") { exit! 130 } # no backtrace thanks
@ -86,7 +87,8 @@ begin
end
if internal_cmd || Commands.external_ruby_v2_cmd_path(cmd)
if Commands::INSTALL_FROM_API_FORBIDDEN_COMMANDS.include?(cmd) && Homebrew::EnvConfig.install_from_api?
if Commands::INSTALL_FROM_API_FORBIDDEN_COMMANDS.include?(cmd) &&
Homebrew::EnvConfig.install_from_api? && !Homebrew::EnvConfig.developer?
odie "This command cannot be run while HOMEBREW_INSTALL_FROM_API is set!"
end
@ -120,8 +122,9 @@ begin
# Unset HOMEBREW_HELP to avoid confusing the tap
with_env HOMEBREW_HELP: nil do
tap_commands = []
cgroup = Utils.popen_read("cat", "/proc/1/cgroup")
if %w[azpl_job actions_job docker garden kubepods].none? { |container| cgroup.include?(container) }
if File.exist?("/.dockerenv") ||
((cgroup = Utils.popen_read("cat", "/proc/1/cgroup").presence) &&
%w[azpl_job actions_job docker garden kubepods].none? { |type| cgroup.include?(type) })
brew_uid = HOMEBREW_BREW_FILE.stat.uid
tap_commands += %W[/usr/bin/sudo -u ##{brew_uid}] if Process.uid.zero? && !brew_uid.zero?
end

View File

@ -197,6 +197,7 @@ check-run-command-as-root() {
[[ "$(id -u)" == 0 ]] || return
# Allow Azure Pipelines/GitHub Actions/Docker/Concourse/Kubernetes to do everything as root (as it's normal there)
[[ -f /.dockerenv ]] && return
[[ -f /proc/1/cgroup ]] && grep -E "azpl_job|actions_job|docker|garden|kubepods" -q /proc/1/cgroup && return
# Homebrew Services may need `sudo` for system-wide daemons.
@ -358,6 +359,18 @@ fi
##### Now, do everything else (that may be a bit slower).
#####
# Docker image deprecation
if [[ -f "${HOMEBREW_REPOSITORY}/.docker-deprecate" ]]
then
DOCKER_DEPRECATION_MESSAGE="$(cat "${HOMEBREW_REPOSITORY}/.docker-deprecate")"
if [[ -n "${GITHUB_ACTIONS}" ]]
then
echo "::warning::${DOCKER_DEPRECATION_MESSAGE}" >&2
else
opoo "${DOCKER_DEPRECATION_MESSAGE}"
fi
fi
# USER isn't always set so provide a fall back for `brew` and subprocesses.
export USER="${USER:-$(id -un)}"

View File

@ -4,6 +4,8 @@
# This script is loaded by formula_installer as a separate instance.
# Thrown exceptions are propagated back to the parent process over a pipe
raise "#{__FILE__} must not be loaded via `require`." if $PROGRAM_NAME != __FILE__
old_trap = trap("INT") { exit! 130 }
require_relative "global"

View File

@ -33,9 +33,17 @@ class BuildEnvironment
module DSL
extend T::Sig
# Initialise @env for each class which may use this DSL (e.g. each formula subclass).
# `env` may never be called, and it needs to be initialised before the class is frozen.
def inherited(child)
super
child.instance_eval do
@env = BuildEnvironment.new
end
end
sig { params(settings: Symbol).returns(BuildEnvironment) }
def env(*settings)
@env ||= BuildEnvironment.new
@env.merge(settings)
end
end

View File

@ -1,6 +1,8 @@
# typed: false
# frozen_string_literal: true
require "active_support/core_ext/object/deep_dup"
module Cask
module Artifact
# Abstract superclass for all artifacts.
@ -127,8 +129,9 @@ module Cask
attr_reader :cask
def initialize(cask)
def initialize(cask, *dsl_args)
@cask = cask
@dsl_args = dsl_args.deep_dup
end
def config
@ -139,6 +142,10 @@ module Cask
def to_s
"#{summarize} (#{self.class.english_name})"
end
def to_args
@dsl_args.reject(&:blank?)
end
end
end
end

View File

@ -32,6 +32,10 @@ module Cask
abstract_phase(self.class.uninstall_dsl_key)
end
def summarize
directives.keys.map(&:to_s).join(", ")
end
private
def class_for_dsl_key(dsl_key)
@ -44,10 +48,6 @@ module Cask
class_for_dsl_key(dsl_key).new(cask).instance_eval(&block)
end
def summarize
directives.keys.map(&:to_s).join(", ")
end
end
end
end

View File

@ -40,7 +40,7 @@ module Cask
def initialize(cask, directives)
directives.assert_valid_keys!(*ORDERED_DIRECTIVES)
super(cask)
super(cask, **directives)
directives[:signal] = Array(directives[:signal]).flatten.each_slice(2).to_a
@directives = directives

View File

@ -72,7 +72,7 @@ module Cask
attr_reader :path, :args
def initialize(cask, **args)
super(cask)
super(cask, **args)
if args.key?(:manual)
@path = Pathname(args[:manual])

View File

@ -23,7 +23,7 @@ module Cask
end
def initialize(cask, path, **stanza_options)
super(cask)
super(cask, path, **stanza_options)
@path = cask.staged_path.join(path)
@stanza_options = stanza_options
end

View File

@ -42,12 +42,13 @@ module Cask
attr_reader :source, :target
sig {
params(cask: Cask, source: T.nilable(T.any(String, Pathname)), target: T.nilable(T.any(String, Pathname)))
params(cask: Cask, source: T.nilable(T.any(String, Pathname)), target_hash: T.any(String, Pathname))
.void
}
def initialize(cask, source, target: nil)
super(cask)
def initialize(cask, source, **target_hash)
super(cask, source, **target_hash)
target = target_hash[:target]
@source_string = source.to_s
@target_string = target.to_s
source = cask.staged_path.join(source)

View File

@ -14,7 +14,7 @@ module Cask
def self.from_args(cask, *args)
raise CaskInvalidError.new(cask.token, "'stage_only' takes only a single argument: true") if args != [true]
new(cask)
new(cask, true)
end
sig { returns(T::Array[T::Boolean]) }

View File

@ -581,7 +581,19 @@ module Cask
next unless path.exist?
result = system_command("codesign", args: ["--verify", path], print_stderr: false)
add_warning result.merged_output unless result.success?
next if result.success?
message = "Signature verification failed:\n#{result.merged_output}\nmacOS on ARM requires applications " \
"to be signed. Please contact the upstream developer to let them know they should "
message += if result.stderr.include?("not signed at all")
"sign their app."
else
"fix the signature of their app."
end
add_warning message
end
end
end

View File

@ -24,6 +24,11 @@ module Cask
attr_accessor :download, :allow_reassignment
def self.all
# TODO: uncomment for 3.7.0 and ideally avoid using ARGV by moving to e.g. CLI::Parser
# if !ARGV.include?("--eval-all") && !Homebrew::EnvConfig.eval_all?
# odeprecated "Cask::Cask#all without --all or HOMEBREW_EVAL_ALL"
# end
Tap.flat_map(&:cask_files).map do |f|
CaskLoader::FromTapPathLoader.new(f).load(config: nil)
rescue CaskUnreadableError => e
@ -235,7 +240,7 @@ module Cask
"installed" => versions.last,
"outdated" => outdated?,
"sha256" => sha256,
"artifacts" => artifacts.map(&method(:to_h_gsubs)),
"artifacts" => artifacts_list,
"caveats" => (to_h_string_gsubs(caveats) unless caveats.empty?),
"depends_on" => depends_on,
"conflicts_with" => conflicts_with,
@ -281,6 +286,18 @@ module Cask
private
def artifacts_list
artifacts.map do |artifact|
key, value = if artifact.is_a? Artifact::AbstractFlightBlock
artifact.summarize
else
[artifact.class.dsl_key, to_h_gsubs(artifact.to_args)]
end
{ key => value }
end
end
def to_h_string_gsubs(string)
string.to_s
.gsub(Dir.home, "$HOME")

View File

@ -1,8 +1,17 @@
# typed: true
# frozen_string_literal: true
require "requirement"
# An adapter for casks to provide dependency information in a formula-like interface.
class CaskDependent
# Defines a dependency on another cask
class Requirement < ::Requirement
satisfy(build_env: false) do
Cask::CaskLoader.load(cask).installed?
end
end
attr_reader :cask
def initialize(cask)
@ -33,11 +42,21 @@ class CaskDependent
dsl_reqs = @cask.depends_on
dsl_reqs.arch&.each do |arch|
requirements << ArchRequirement.new([:x86_64]) if arch[:bits] == 64
requirements << ArchRequirement.new([arch[:type]])
arch = if arch[:bits] == 64
if arch[:type] == :intel
:x86_64
else
:"#{arch[:type]}64"
end
elsif arch[:type] == :intel && arch[:bits] == 32
:i386
else
arch[:type]
end
requirements << ArchRequirement.new([arch])
end
dsl_reqs.cask.each do |cask_ref|
requirements << Requirement.new([{ cask: cask_ref }])
requirements << CaskDependent::Requirement.new([{ cask: cask_ref }])
end
requirements << dsl_reqs.macos if dsl_reqs.macos

View File

@ -235,6 +235,7 @@ module Homebrew
cleanup_cache
cleanup_logs
cleanup_lockfiles
cleanup_python_site_packages
prune_prefix_symlinks_and_directories
unless dry_run?
@ -484,6 +485,55 @@ module Homebrew
end
end
def cleanup_python_site_packages
pyc_files = Hash.new { |h, k| h[k] = [] }
seen_non_pyc_file = Hash.new { |h, k| h[k] = false }
unused_pyc_files = []
HOMEBREW_PREFIX.glob("lib/python*/site-packages").each do |site_packages|
site_packages.each_child do |child|
next unless child.directory?
# TODO: Work out a sensible way to clean up pip's, setuptools', and wheel's
# {dist,site}-info directories. Alternatively, consider always removing
# all `-info` directories, because we may not be making use of them.
next if child.basename.to_s.end_with?("-info")
# Clean up old *.pyc files in the top-level __pycache__.
if child.basename.to_s == "__pycache__"
child.find do |path|
next unless path.extname == ".pyc"
next unless path.prune?(days)
unused_pyc_files << path
end
next
end
# Look for directories that contain only *.pyc files.
child.find do |path|
next if path.directory?
if path.extname == ".pyc"
pyc_files[child] << path
else
seen_non_pyc_file[child] = true
break
end
end
end
end
unused_pyc_files += pyc_files.reject { |k,| seen_non_pyc_file[k] }
.values
.flatten
return if unused_pyc_files.blank?
unused_pyc_files.each do |pyc|
cleanup_path(pyc) { pyc.unlink }
end
end
def prune_prefix_symlinks_and_directories
ObserverPathnameExtension.reset_counts!

View File

@ -135,6 +135,9 @@ module Homebrew
sig { returns(T::Boolean) }
def all?; end
sig { returns(T::Boolean) }
def eval_all?; end
sig { returns(T::Boolean) }
def full?; end

View File

@ -22,10 +22,10 @@ module Homebrew
may be appended to the command. When given multiple formula arguments,
show the intersection of dependencies for each formula.
EOS
switch "-n",
switch "-n", "--topological",
description: "Sort dependencies in topological order."
switch "--1",
description: "Only show dependencies one level down, instead of recursing."
switch "-1", "--direct", "--declared", "--1",
description: "Show only the direct dependencies declared in the formula."
switch "--union",
description: "Show the union of dependencies for multiple <formula>, instead of the intersection."
switch "--full-name",
@ -54,20 +54,22 @@ module Homebrew
switch "--installed",
description: "List dependencies for formulae that are currently installed. If <formula> is " \
"specified, list only its dependencies that are currently installed."
switch "--eval-all",
description: "Evaluate all available formulae and casks, whether installed or not, to list " \
"their dependencies."
switch "--all",
description: "List dependencies for all available formulae."
hidden: true
switch "--for-each",
description: "Switch into the mode used by the `--all` option, but only list dependencies " \
"for each provided <formula>, one formula per line. This is used for " \
"debugging the `--installed`/`--all` display mode."
switch "--formula", "--formulae",
depends_on: "--installed",
description: "Treat all named arguments as formulae."
switch "--cask", "--casks",
depends_on: "--installed",
description: "Treat all named arguments as casks."
conflicts "--tree", "--graph"
conflicts "--installed", "--eval-all"
conflicts "--installed", "--all"
conflicts "--formula", "--cask"
formula_options
@ -79,9 +81,18 @@ module Homebrew
def deps
args = deps_args.parse
all = args.eval_all?
if args.all?
unless all
odeprecated "brew deps --all",
"brew deps --eval-all or HOMEBREW_EVAL_ALL"
end
all = true
end
Formulary.enable_factory_cache!
recursive = !args.send(:"1?")
recursive = !args.direct?
installed = args.installed? || dependents(args.named.to_formulae_and_casks).all?(&:any_version_installed?)
@use_runtime_dependencies = installed && recursive &&
@ -120,7 +131,7 @@ module Homebrew
puts_deps_tree dependents, recursive: recursive, args: args
return
elsif args.all?
elsif all
puts_deps sorted_dependents(Formula.all + Cask::Cask.all), recursive: recursive, args: args
return
elsif !args.no_named? && args.for_each?
@ -149,7 +160,7 @@ module Homebrew
condense_requirements(all_deps, args: args)
all_deps.map! { |d| dep_display_name(d, args: args) }
all_deps.uniq!
all_deps.sort! unless args.n?
all_deps.sort! unless args.topological?
puts all_deps
end
@ -286,8 +297,14 @@ module Homebrew
end
display_s = "#{tree_lines} #{dep_display_name(dep, args: args)}"
# Detect circular dependencies and consider them a failure if present.
is_circular = dep_stack.include?(dep.name)
display_s = "#{display_s} (CIRCULAR DEPENDENCY)" if is_circular
if is_circular
display_s = "#{display_s} (CIRCULAR DEPENDENCY)"
Homebrew.failed = true
end
puts "#{prefix}#{display_s}"
next if !recursive || is_circular

View File

@ -18,8 +18,7 @@ module Homebrew
Homebrew::CLI::Parser.new do
description <<~EOS
Display <formula>'s name and one-line description.
Formula descriptions are cached; the cache is created on the
first search, making that search slower than subsequent ones.
The cache is created on the first search, making that search slower than subsequent ones.
EOS
switch "-s", "--search",
description: "Search both names and descriptions for <text>. If <text> is flanked by " \
@ -30,6 +29,9 @@ module Homebrew
switch "-d", "--description",
description: "Search just descriptions for <text>. If <text> is flanked by slashes, " \
"it is interpreted as a regular expression."
switch "--eval-all",
description: "Evaluate all available formulae and casks, whether installed or not, to search their " \
"descriptions. Implied if HOMEBREW_EVAL_ALL is set."
switch "--formula", "--formulae",
description: "Treat all named arguments as formulae."
switch "--cask", "--casks",
@ -44,6 +46,10 @@ module Homebrew
def desc
args = desc_args.parse
if !args.eval_all? && !Homebrew::EnvConfig.eval_all?
odeprecated "brew desc", "brew desc --eval-all or HOMEBREW_EVAL_ALL"
end
search_type = if args.search?
:either
elsif args.name?

View File

@ -0,0 +1,24 @@
# typed: true
# frozen_string_literal: true
require "cli/parser"
module Homebrew
extend T::Sig
module_function
sig { returns(CLI::Parser) }
def docs_args
Homebrew::CLI::Parser.new do
description <<~EOS
Open Homebrew's online documentation (#{HOMEBREW_DOCS_WWW}) in a browser.
EOS
end
end
sig { void }
def docs
exec_browser HOMEBREW_DOCS_WWW
end
end

View File

@ -13,6 +13,8 @@ module Homebrew
module_function
FETCH_MAX_TRIES = 5
sig { returns(CLI::Parser) }
def fetch_args
Homebrew::CLI::Parser.new do
@ -31,7 +33,8 @@ module Homebrew
"seeing if an existing VCS cache has been updated."
switch "--retry",
description: "Retry if downloading fails or re-download if the checksum of a previously cached " \
"version no longer matches."
"version no longer matches. Tries at most #{FETCH_MAX_TRIES} times with " \
"exponential backoff."
switch "--deps",
description: "Also download dependencies for any listed <formula>."
switch "-s", "--build-from-source",
@ -159,10 +162,17 @@ module Homebrew
end
def retry_fetch?(f, args:)
@fetch_failed ||= Set.new
if args.retry? && @fetch_failed.add?(f)
ohai "Retrying download"
@fetch_tries ||= Hash.new { |h, k| h[k] = 1 }
if args.retry? && (@fetch_tries[f] < FETCH_MAX_TRIES)
wait = 2 ** @fetch_tries[f]
remaining = FETCH_MAX_TRIES - @fetch_tries[f]
what = "try".pluralize(remaining)
ohai "Retrying download in #{wait}s... (#{remaining} #{what} left)"
sleep wait
f.clear_cache
@fetch_tries[f] += 1
true
else
Homebrew.failed = true

View File

@ -58,9 +58,13 @@ module Homebrew
switch "--installed",
depends_on: "--json",
description: "Print JSON of formulae that are currently installed."
switch "--all",
switch "--eval-all",
depends_on: "--json",
description: "Print JSON of all available formulae."
description: "Evaluate all available formulae and casks, whether installed or not, to print their " \
"JSON. Implied if HOMEBREW_EVAL_ALL is set."
switch "--all",
hidden: true,
depends_on: "--json"
switch "--variations",
depends_on: "--json",
description: "Include the variations hash in each formula's JSON output."
@ -71,6 +75,7 @@ module Homebrew
switch "--cask", "--casks",
description: "Treat all named arguments as casks."
conflicts "--installed", "--eval-all"
conflicts "--installed", "--all"
conflicts "--formula", "--cask"
@ -103,7 +108,13 @@ module Homebrew
print_analytics(args: args)
elsif args.json
print_json(args: args)
all = args.eval_all?
if !all && args.all? && !Homebrew::EnvConfig.eval_all?
odeprecated "brew info --all", "brew info --eval-all or HOMEBREW_EVAL_ALL"
all = true
end
print_json(all, args: args)
elsif args.github?
raise FormulaOrCaskUnspecifiedError if args.no_named?
@ -187,15 +198,15 @@ module Homebrew
version_hash[version]
end
sig { params(args: CLI::Args).void }
def print_json(args:)
raise FormulaOrCaskUnspecifiedError if !(args.all? || args.installed?) && args.no_named?
sig { params(all: T::Boolean, args: CLI::Args).void }
def print_json(all, args:)
raise FormulaOrCaskUnspecifiedError if !(all || args.installed?) && args.no_named?
json = case json_version(args.json)
when :v1, :default
raise UsageError, "cannot specify --cask with --json=v1!" if args.cask?
formulae = if args.all?
formulae = if all
Formula.all.sort
elsif args.installed?
Formula.installed.sort
@ -211,7 +222,7 @@ module Homebrew
formulae.map(&:to_hash)
end
when :v2
formulae, casks = if args.all?
formulae, casks = if all
[Formula.all.sort, Cask::Cask.all.sort_by(&:full_name)]
elsif args.installed?
[Formula.installed.sort, Cask::Caskroom.casks.sort_by(&:full_name)]

View File

@ -19,8 +19,11 @@ module Homebrew
description: "Show all options on a single line separated by spaces."
switch "--installed",
description: "Show options for formulae that are currently installed."
switch "--eval-all",
description: "Evaluate all available formulae and casks, whether installed or not, to show their " \
"options."
switch "--all",
description: "Show options for all available formulae."
hidden: true
flag "--command=",
description: "Show options for the specified <command>."
@ -33,7 +36,13 @@ module Homebrew
def options
args = options_args.parse
all = args.eval_all?
if args.all?
odeprecated "brew info --all", "brew info --eval-all" if !all && !Homebrew::EnvConfig.eval_all?
all = true
end
if all
puts_options Formula.all.sort, args: args
elsif args.installed?
puts_options Formula.installed.sort, args: args

View File

@ -3,6 +3,7 @@
require "readall"
require "cli/parser"
require "env_config"
module Homebrew
extend T::Sig
@ -22,6 +23,9 @@ module Homebrew
description: "Verify any alias symlinks in each tap."
switch "--syntax",
description: "Syntax-check all of Homebrew's Ruby files (if no `<tap>` is passed)."
switch "--eval-all",
description: "Evaluate all available formulae and casks, whether installed or not. " \
"Implied if HOMEBREW_EVAL_ALL is set."
named_args :tap
end
@ -39,6 +43,9 @@ module Homebrew
options = { aliases: args.aliases? }
taps = if args.no_named?
if !args.eval_all? && !Homebrew::EnvConfig.eval_all?
odeprecated "brew readall", "brew readall --eval-all or HOMEBREW_EVAL_ALL"
end
Tap
else
args.named.to_installed_taps

View File

@ -44,6 +44,10 @@ module Homebrew
switch "--desc",
description: "Search for formulae with a description matching <text> and casks with " \
"a name or description matching <text>."
switch "--eval-all",
depends_on: "--desc",
description: "Evaluate all available formulae and casks, whether installed or not, to search their " \
"descriptions. Implied if HOMEBREW_EVAL_ALL is set."
switch "--pull-request",
description: "Search for GitHub pull requests containing <text>."
switch "--open",
@ -75,6 +79,9 @@ module Homebrew
string_or_regex = query_regexp(query)
if args.desc?
if !args.eval_all? && !Homebrew::EnvConfig.eval_all?
odeprecated "brew search --desc", "brew search --desc --eval-all or HOMEBREW_EVAL_ALL"
end
search_descriptions(string_or_regex, args)
elsif args.pull_request?
search_pull_requests(query, args)

View File

@ -43,6 +43,9 @@ module Homebrew
description: "Migrate tapped formulae from symlink-based to directory-based structure."
switch "--list-pinned",
description: "List all pinned taps."
switch "--eval-all",
description: "Evaluate all the formulae, casks and aliases in the new tap to check validity. " \
"Implied if HOMEBREW_EVAL_ALL is set."
named_args :tap, max: 2
end
@ -65,7 +68,8 @@ module Homebrew
tap.install clone_target: args.named.second,
force_auto_update: args.force_auto_update?,
custom_remote: args.custom_remote?,
quiet: args.quiet?
quiet: args.quiet?,
verify: args.eval_all? || Homebrew::EnvConfig.eval_all?
rescue TapRemoteMismatchError, TapNoCustomRemoteError => e
odie e
rescue TapAlreadyTappedError

View File

@ -547,7 +547,7 @@ EOS
for DIR in "${HOMEBREW_REPOSITORY}" "${HOMEBREW_LIBRARY}"/Taps/*/*
do
if [[ -n "${HOMEBREW_INSTALL_FROM_API}" ]] &&
[[ -n "${HOMEBREW_UPDATE_AUTO}" ]] &&
[[ -z "${HOMEBREW_DEVELOPER}" || -n "${HOMEBREW_UPDATE_AUTO}" ]] &&
[[ "${DIR}" == "${HOMEBREW_CORE_REPOSITORY}" ]]
then
continue
@ -705,6 +705,7 @@ EOS
for DIR in "${HOMEBREW_REPOSITORY}" "${HOMEBREW_LIBRARY}"/Taps/*/*
do
if [[ -n "${HOMEBREW_INSTALL_FROM_API}" ]] &&
[[ -z "${HOMEBREW_DEVELOPER}" || -n "${HOMEBREW_UPDATE_AUTO}" ]] &&
[[ "${DIR}" == "${HOMEBREW_CORE_REPOSITORY}" ||
"${DIR}" == "${HOMEBREW_LIBRARY}/Taps/homebrew/homebrew-cask" ]]
then
@ -748,11 +749,11 @@ EOS
if [[ -n "${HOMEBREW_INSTALL_FROM_API}" ]]
then
mkdir -p "${HOMEBREW_CACHE}/api"
# TODO: use --header If-Modified-Since
curl \
"${CURL_DISABLE_CURLRC_ARGS[@]}" \
--fail --compressed --silent --max-time 5 \
--location --remote-time --output "${HOMEBREW_CACHE}/api/formula.json" \
--time-cond "${HOMEBREW_CACHE}/api/formula.json" \
--user-agent "${HOMEBREW_USER_AGENT_CURL}" \
"https://formulae.brew.sh/api/formula.json"
# TODO: we probably want to print an error if this fails.

View File

@ -30,9 +30,11 @@ module Homebrew
description: "Resolve more than one level of dependencies."
switch "--installed",
description: "Only list formulae and casks that are currently installed."
switch "--eval-all",
description: "Evaluate all available formulae and casks, whether installed or not, to show " \
"their dependents."
switch "--all",
description: "List all formulae and casks whether installed or not.",
hidden: true
hidden: true
switch "--include-build",
description: "Include all formulae that specify <formula> as `:build` type dependency."
switch "--include-test",
@ -88,8 +90,6 @@ module Homebrew
show_formulae_and_casks = !args.formula? && !args.cask?
includes, ignores = args_includes_ignores(args)
# TODO: 3.6.0: odeprecate not specifying args.all?, require args.installed?
deps = []
if use_runtime_dependents
if show_formulae_and_casks || args.formula?
@ -106,6 +106,18 @@ module Homebrew
deps
else
all = args.eval_all?
if args.all?
unless all
odeprecated "brew uses --all",
"brew uses --eval-all or HOMEBREW_EVAL_ALL"
end
all = true
end
if !args.installed? && !(all || Homebrew::EnvConfig.eval_all?)
odeprecated "brew uses", "brew uses --eval-all or HOMEBREW_EVAL_ALL"
end
if show_formulae_and_casks || args.formula?
deps += args.installed? ? Formula.installed : Formula.all
end

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "delegate"
require "cask_dependent"
# A collection of dependencies.
#

View File

@ -26,16 +26,25 @@ class DependencyCollector
sig { void }
def initialize
# Ensure this is synced with `initialize_dup` and `freeze` (excluding simple objects like integers and booleans)
@deps = Dependencies.new
@requirements = Requirements.new
init_global_dep_tree_if_needed!
end
def initialize_copy(other)
def initialize_dup(other)
super
@deps = @deps.dup
@requirements = @requirements.dup
end
def freeze
@deps.freeze
@requirements.freeze
super
end
def add(spec)
case dep = fetch(spec)
when Dependency
@ -68,6 +77,12 @@ class DependencyCollector
parse_spec(spec, Array(tags))
end
sig { params(related_formula_names: T::Array[String]).returns(T.nilable(Dependency)) }
def gcc_dep_if_needed(related_formula_names); end
sig { params(related_formula_names: T::Array[String]).returns(T.nilable(Dependency)) }
def glibc_dep_if_needed(related_formula_names); end
def git_dep_if_needed(tags)
return if Utils::Git.available?
@ -110,6 +125,9 @@ class DependencyCollector
private
sig { void }
def init_global_dep_tree_if_needed!; end
def parse_spec(spec, tags)
case spec
when String

View File

@ -34,9 +34,9 @@ class DescriptionCacheStore < CacheStore
#
# @return [nil]
def populate_if_empty!
return unless Homebrew::EnvConfig.eval_all?
return unless database.empty?
# TODO: 3.6.0: consider if we want to actually read all contents of all formulae or odeprecate.
Formula.all.each { |f| update!(f.full_name, f.desc) }
end
@ -45,6 +45,7 @@ class DescriptionCacheStore < CacheStore
# @param report [Report] an update report generated by cmd/update.rb
# @return [nil]
def update_from_report!(report)
return unless Homebrew::EnvConfig.eval_all?
return populate_if_empty! if database.empty?
return if report.empty?
@ -63,6 +64,7 @@ class DescriptionCacheStore < CacheStore
# @param formula_names [Array] the formulae to update
# @return [nil]
def update_from_formula_names!(formula_names)
return unless Homebrew::EnvConfig.eval_all?
return populate_if_empty! if database.empty?
formula_names.each do |name|
@ -100,9 +102,9 @@ class CaskDescriptionCacheStore < DescriptionCacheStore
#
# @return [nil]
def populate_if_empty!
return unless Homebrew::EnvConfig.eval_all?
return unless database.empty?
# TODO: 3.6.0: consider if we want to actually read all contents of all casks or odeprecate.
Cask::Cask.all.each { |c| update!(c.full_name, [c.name.join(", "), c.desc.presence]) }
end
@ -111,6 +113,7 @@ class CaskDescriptionCacheStore < DescriptionCacheStore
# @param report [Report] an update report generated by cmd/update.rb
# @return [nil]
def update_from_report!(report)
return unless Homebrew::EnvConfig.eval_all?
return populate_if_empty! if database.empty?
return if report.empty?
@ -126,6 +129,7 @@ class CaskDescriptionCacheStore < DescriptionCacheStore
# @param cask_tokens [Array] the casks to update
# @return [nil]
def update_from_cask_tokens!(cask_tokens)
return unless Homebrew::EnvConfig.eval_all?
return populate_if_empty! if database.empty?
cask_tokens.each do |token|

View File

@ -41,9 +41,11 @@ module Homebrew
description: "Run additional, slower style checks that require a network connection."
switch "--installed",
description: "Only check formulae and casks that are currently installed."
switch "--eval-all",
description: "Evaluate all available formulae and casks, whether installed or not, to audit them. " \
"Implied if HOMEBREW_EVAL_ALL is set."
switch "--all",
description: "Check all formulae and casks whether installed or not.",
hidden: true
hidden: true
switch "--new", "--new-formula", "--new-cask",
description: "Run various additional style checks to determine if a new formula or cask is eligible " \
"for Homebrew. This should be used when creating new formula and implies " \
@ -118,8 +120,6 @@ module Homebrew
ENV.activate_extensions!
ENV.setup_build_environment
# TODO: 3.6.0: odeprecate not specifying args.all?, require args.installed?
audit_formulae, audit_casks = if args.tap
Tap.fetch(args.tap).then do |tap|
[
@ -131,6 +131,10 @@ module Homebrew
no_named_args = true
[Formula.installed, Cask::Caskroom.casks]
elsif args.no_named?
if !args.eval_all? && !Homebrew::EnvConfig.eval_all?
odeprecated "brew audit",
"brew audit --eval-all or HOMEBREW_EVAL_ALL"
end
no_named_args = true
[Formula.all, Cask::Cask.all]
else

View File

@ -121,8 +121,8 @@ module Homebrew
if new_version.present?
if new_version.latest?
opoo "Ignoring specified `--sha256=` argument." if new_hash.present?
new_hash = :no_check
elsif new_hash.nil? || cask.languages.present?
replacement_pairs << [old_hash, ":no_check"]
elsif old_hash != :no_check && (new_hash.nil? || cask.languages.present?)
tmp_contents = Utils::Inreplace.inreplace_pairs(cask.sourcefile_path,
replacement_pairs.uniq.compact,
read_only_run: true,
@ -131,43 +131,34 @@ module Homebrew
tmp_cask = Cask::CaskLoader.load(tmp_contents)
tmp_config = tmp_cask.config
new_hash = fetch_cask(tmp_contents)[1] if old_hash != :no_check && new_hash.nil?
[:arm, :intel].each do |arch|
Homebrew::SimulateSystem.arch = arch
cask.languages.each do |language|
lang_config = tmp_config.merge(Cask::Config.new(explicit: { languages: [language] }))
replacement_pairs << fetch_cask(tmp_contents, config: lang_config)
end
languages = cask.languages
languages = [nil] if languages.empty?
languages.each do |language|
new_hash_config = if language.blank?
tmp_config
else
tmp_config.merge(Cask::Config.new(explicit: { languages: [language] }))
end
# TODO: remove the `Hardware::CPU.intel?` substitution once no casks use the conditional
other_intel = !Hardware::CPU.intel?
Homebrew::SimulateSystem.arch = other_intel ? :intel : :arm
other_contents = tmp_contents.gsub("Hardware::CPU.intel?", other_intel.to_s)
other_cask = Cask::CaskLoader.load(other_contents)
new_hash_cask = Cask::CaskLoader.load(tmp_contents)
new_hash_cask.config = new_hash_config
old_hash = new_hash_cask.sha256.to_s
if other_cask.url.to_s != tmp_cask.url.to_s
if other_cask.sha256 != :no_check && other_cask.language.blank?
replacement_pairs << fetch_cask(other_contents)
cask_download = Cask::Download.new(new_hash_cask, quarantine: true)
download = cask_download.fetch(verify_download_integrity: false)
Utils::Tar.validate_file(download)
replacement_pairs << [new_hash_cask.sha256.to_s, download.sha256]
end
other_cask.languages.each do |language|
lang_config = other_cask.config.merge(Cask::Config.new(explicit: { languages: [language] }))
replacement_pairs << fetch_cask(other_contents, config: lang_config)
end
Homebrew::SimulateSystem.clear
end
Homebrew::SimulateSystem.clear
end
end
if new_hash.present? && cask.language.blank? # avoid repeated replacement for multilanguage cask
hash_regex = (old_hash == :no_check) ? ":no_check" : "[\"']#{Regexp.escape(old_hash.to_s)}[\"']"
replacement_pairs << [
/#{hash_regex}/m,
((new_hash == :no_check) ? ":no_check" : "\"#{new_hash}\"").to_s,
]
end
Utils::Inreplace.inreplace_pairs(cask.sourcefile_path,
replacement_pairs.uniq.compact,
read_only_run: args.dry_run?,

View File

@ -18,8 +18,8 @@ module Homebrew
Create a pull request to update <formula> with a new URL or a new tag.
If a <URL> is specified, the <SHA-256> checksum of the new download should also
be specified. A best effort to determine the <SHA-256> and <formula> name will
be made if either or both values are not supplied by the user.
be specified. A best effort to determine the <SHA-256> will be made if not supplied
by the user.
If a <tag> is specified, the Git commit <revision> corresponding to that tag
should also be specified. A best effort to determine the <revision> will be made
@ -34,9 +34,6 @@ module Homebrew
EOS
switch "-n", "--dry-run",
description: "Print what would be done rather than doing it."
switch "--all",
description: "Read all formulae if necessary to determine URL.",
hidden: true
switch "--write-only",
description: "Make the expected file modifications without taking any Git actions."
switch "--commit",
@ -89,7 +86,6 @@ module Homebrew
conflicts "--no-audit", "--strict"
conflicts "--no-audit", "--online"
conflicts "--url", "--tag"
conflicts "--installed", "--all"
named_args :formula, max: 1
end
@ -110,9 +106,7 @@ module Homebrew
ENV["BROWSER"] = Homebrew::EnvConfig.browser
formula = args.named.to_formulae.first
new_url = args.url
formula ||= determine_formula_from_url(new_url) if new_url.present?
raise FormulaUnspecifiedError if formula.blank?
odie "This formula is disabled!" if formula.disabled?
@ -368,27 +362,6 @@ module Homebrew
GitHub.create_bump_pr(pr_info, args: args)
end
def determine_formula_from_url(url)
# Split the new URL on / and find any formulae that have the same URL
# except for the last component, but don't try to match any more than the
# first five components since sometimes the last component isn't the only
# one to change.
url_split = url.split("/")
maximum_url_components_to_match = 5
components_to_match = [url_split.count - 1, maximum_url_components_to_match].min
base_url = url_split.first(components_to_match).join("/")
base_url = /#{Regexp.escape(base_url)}/
guesses = []
# TODO: 3.6.0: odeprecate not specifying args.all?
Formula.all.each do |f|
guesses << f if f.stable&.url&.match(base_url)
end
return guesses.shift if guesses.count == 1
return if guesses.count <= 1
odie "Couldn't guess formula for sure; could be one of these:\n#{guesses.map(&:name).join(", ")}"
end
def determine_mirror(url)
case url
when %r{.*ftp\.gnu\.org/gnu.*}

View File

@ -23,6 +23,7 @@ module Homebrew
Generate Homebrew's manpages and shell completions.
EOS
switch "--fail-if-not-changed",
hidden: true,
description: "Return a failing status code if no changes are detected in the manpage outputs. " \
"This can be used to notify CI when the manpages are out of date. Additionally, " \
"the date used in new manpages will match those in the existing manpages (to allow " \
@ -34,27 +35,30 @@ module Homebrew
def generate_man_completions
args = generate_man_completions_args.parse
odeprecated "brew generate-man-completions --fail-if-not-changed" if args.fail_if_not_changed?
Commands.rebuild_internal_commands_completion_list
regenerate_man_pages(preserve_date: args.fail_if_not_changed?, quiet: args.quiet?)
regenerate_man_pages(quiet: args.quiet?)
Completions.update_shell_completions!
diff = system_command "git", args: [
"-C", HOMEBREW_REPOSITORY, "diff", "--exit-code", "docs/Manpage.md", "manpages", "completions"
]
return unless diff.status.success?
puts "No changes to manpage or completions output detected."
Homebrew.failed = true if args.fail_if_not_changed?
if diff.status.success?
ofail "No changes to manpage or completions."
else
puts "Manpage and completions updated."
end
end
def regenerate_man_pages(preserve_date:, quiet:)
# TODO: move this method and all called functions to manpages.rb
def regenerate_man_pages(quiet:)
Homebrew.install_bundler_gems!
markup = build_man_page(quiet: quiet)
convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md", preserve_date: preserve_date)
convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md")
markup = I18n.transliterate(markup, locale: :en)
convert_man_page(markup, TARGET_MAN_PATH/"brew.1", preserve_date: preserve_date)
convert_man_page(markup, TARGET_MAN_PATH/"brew.1")
end
def build_man_page(quiet:)
@ -94,13 +98,13 @@ module Homebrew
path.basename.to_s.sub(/\.(rb|sh)$/, "").sub(/^--/, "~~")
end
def convert_man_page(markup, target, preserve_date:)
def convert_man_page(markup, target)
manual = target.basename(".1")
organisation = "Homebrew"
# Set the manpage date to the existing one if we're checking for changes.
# Set the manpage date to the existing one if we're updating.
# This avoids the only change being e.g. a new date.
date = if preserve_date && target.extname == ".1" && target.exist?
date = if target.extname == ".1" && target.exist?
/"(\d{1,2})" "([A-Z][a-z]+) (\d{4})" "#{organisation}" "#{manual}"/ =~ target.read
Date.parse("#{Regexp.last_match(1)} #{Regexp.last_match(2)} #{Regexp.last_match(3)}")
else

View File

@ -24,13 +24,15 @@ module Homebrew
`~/.brew_livecheck_watchlist`.
EOS
switch "--full-name",
description: "Print formulae/casks with fully-qualified names."
description: "Print formulae and casks with fully-qualified names."
flag "--tap=",
description: "Check formulae/casks within the given tap, specified as <user>`/`<repo>."
description: "Check formulae and casks within the given tap, specified as <user>`/`<repo>."
switch "--eval-all",
description: "Evaluate all available formulae and casks, whether installed or not, to check them."
switch "--all",
description: "Check all available formulae/casks."
hidden: true
switch "--installed",
description: "Check formulae/casks that are currently installed."
description: "Check formulae and casks that are currently installed."
switch "--newer-only",
description: "Show the latest version only if it's newer than the formula/cask."
switch "--json",
@ -45,7 +47,7 @@ module Homebrew
description: "Only check casks."
conflicts "--debug", "--json"
conflicts "--tap=", "--all", "--installed"
conflicts "--tap=", "--eval-all", "--installed"
conflicts "--cask", "--formula"
named_args [:formula, :cask]
@ -55,6 +57,12 @@ module Homebrew
def livecheck
args = livecheck_args.parse
all = args.eval_all?
if args.all?
odeprecated "brew livecheck --all", "brew livecheck --eval-all" if !all && !Homebrew::EnvConfig.eval_all?
all = true
end
if args.debug? && args.verbose?
puts args
puts Homebrew::EnvConfig.livecheck_watchlist if Homebrew::EnvConfig.livecheck_watchlist.present?
@ -69,7 +77,7 @@ module Homebrew
formulae = args.cask? ? [] : Formula.installed
casks = args.formula? ? [] : Cask::Caskroom.casks
formulae + casks
elsif args.all?
elsif all
formulae = args.cask? ? [] : Formula.all
casks = args.formula? ? [] : Cask::Cask.all
formulae + casks

View File

@ -368,28 +368,32 @@ module Homebrew
end
end
def pr_check_conflicts(user, repo, pr)
long_build_pr_files = GitHub.search_issues(
"org:#{user}", repo: repo, state: "open", label: "\"no long build conflict\""
def pr_check_conflicts(repo, pr)
long_build_pr_files = GitHub.issues(
repo: repo, state: "open", labels: "no long build conflict",
).each_with_object({}) do |long_build_pr, hash|
next unless long_build_pr.key?("pull_request")
number = long_build_pr["number"]
next if number == pr.to_i
GitHub.get_pull_request_changed_files("#{user}/#{repo}", number).each do |file|
GitHub.get_pull_request_changed_files(repo, number).each do |file|
key = file["filename"]
hash[key] ||= []
hash[key] << number
end
end
this_pr_files = GitHub.get_pull_request_changed_files("#{user}/#{repo}", pr)
return if long_build_pr_files.blank?
this_pr_files = GitHub.get_pull_request_changed_files(repo, pr)
conflicts = this_pr_files.each_with_object({}) do |file, hash|
filename = file["filename"]
next unless long_build_pr_files.key?(filename)
long_build_pr_files[filename].each do |pr_number|
key = "#{user}/#{repo}/pull/#{pr_number}"
key = "#{repo}/pull/#{pr_number}"
hash[key] ||= []
hash[key] << filename
end
@ -440,7 +444,7 @@ module Homebrew
opoo "Current branch is #{tap.path.git_branch}: do you need to pull inside #{tap.path.git_origin_branch}?"
end
pr_check_conflicts(user, repo, pr)
pr_check_conflicts("#{user}/#{repo}", pr)
ohai "Fetching #{tap} pull request ##{pr}"
Dir.mktmpdir pr do |dir|

View File

@ -20,13 +20,13 @@ module Homebrew
description: "Silence all non-critical errors."
switch "--update",
description: "Update RBI files."
switch "--all",
depends_on: "--update",
description: "Regenerate all RBI files rather than just updated gems."
switch "--update-all",
description: "Update all RBI files rather than just updated gems."
switch "--suggest-typed",
depends_on: "--update",
description: "Try upgrading `typed` sigils."
switch "--fail-if-not-changed",
hidden: true,
description: "Return a failing status code if all gems are up to date " \
"and gem definitions do not need a tapioca update."
flag "--dir=",
@ -50,7 +50,9 @@ module Homebrew
Homebrew.install_bundler_gems!(groups: ["sorbet"])
HOMEBREW_LIBRARY_PATH.cd do
if args.update?
if args.update? || args.update_all?
odeprecated "brew typecheck --update --fail-if-not-changed" if args.fail_if_not_changed?
excluded_gems = [
"did_you_mean", # RBI file is already provided by Sorbet
"webrobots", # RBI file is bugged
@ -60,7 +62,7 @@ module Homebrew
"msgpack:false", # Investigate removing this with Tapioca 0.8
]
tapioca_args = ["--exclude", *excluded_gems, "--typed-overrides", *typed_overrides]
tapioca_args << "--all" if args.all?
tapioca_args << "--all" if args.update_all?
ohai "Updating Tapioca RBI files..."
safe_system "bundle", "exec", "tapioca", "gem", *tapioca_args
@ -100,8 +102,6 @@ module Homebrew
end
end
Homebrew.failed = system("git", "diff", "--stat", "--exit-code") if args.fail_if_not_changed?
return
end

View File

@ -20,11 +20,13 @@ module Homebrew
description: "Use the specified bottle tag (e.g. `big_sur`) instead of the current OS."
switch "--dependents",
description: "Skip getting analytics data and sort by number of dependents instead."
switch "--all", "--total",
switch "--total",
description: "Print the number of unbottled and total formulae."
switch "--eval-all",
description: "Evaluate all available formulae and casks, whether installed or not, to check them. " \
"Implied if HOMEBREW_EVAL_ALL is set."
conflicts "--dependents", "--all"
conflicts "--installed", "--all"
conflicts "--dependents", "--total"
named_args :formula
end
@ -42,16 +44,22 @@ module Homebrew
Utils::Bottles.tag
end
# TODO: 3.6.0: odeprecate args.total?
all = args.eval_all?
if args.total?
if !all && !Homebrew::EnvConfig.eval_all?
odeprecated "brew unbottled --total", "brew unbottled --total --eval-all or HOMEBREW_EVAL_ALL"
end
all = true
end
if args.named.blank?
ohai "Getting formulae..."
elsif args.all?
raise UsageError, "cannot specify `<formula>` and `--all`/`--total`."
elsif all
raise UsageError, "cannot specify `<formula>` and `--eval-all`/`--total`."
end
formulae, all_formulae, formula_installs =
formulae_all_installs_from_args(args)
formulae_all_installs_from_args(args, all)
deps_hash, uses_hash = deps_uses_from_formulae(all_formulae)
if args.dependents?
@ -60,9 +68,7 @@ module Homebrew
dependents = uses_hash[f.name]&.length || 0
formula_dependents[f.name] ||= dependents
end.reverse
end
if args.all?
elsif all
output_total(formulae)
return
end
@ -78,16 +84,18 @@ module Homebrew
output_unbottled(formulae, deps_hash, noun, hash, args.named.present?)
end
def formulae_all_installs_from_args(args)
def formulae_all_installs_from_args(args, all)
if args.named.present?
formulae = all_formulae = args.named.to_formulae
elsif args.all?
formulae = all_formulae = Formula.all
elsif args.dependents?
# TODO: 3.6.0: odeprecate not specifying args.all? for args.dependents?
if !args.all? && !Homebrew::EnvConfig.eval_all?
odeprecated "brew unbottled --dependents", "brew unbottled --all --dependents or HOMEBREW_EVAL_ALL"
end
formulae = all_formulae = Formula.all
@sort = " (sorted by number of dependents)"
elsif all
formulae = all_formulae = Formula.all
else
formula_installs = {}

View File

@ -3,9 +3,11 @@
require "cli/parser"
require "utils/spdx"
require "system_command"
module Homebrew
extend T::Sig
include SystemCommand::Mixin
module_function
@ -16,6 +18,7 @@ module Homebrew
Update SPDX license data in the Homebrew repository.
EOS
switch "--fail-if-not-changed",
hidden: true,
description: "Return a failing status code if current license data's version is the same as " \
"the upstream. This can be used to notify CI when the SPDX license data is out of date."
@ -25,11 +28,16 @@ module Homebrew
def update_license_data
args = update_license_data_args.parse
ohai "Updating SPDX license data..."
odeprecated "brew update-license-data --fail-if-not-changed" if args.fail_if_not_changed?
SPDX.download_latest_license_data!
return unless args.fail_if_not_changed?
Homebrew.failed = system("git", "diff", "--stat", "--exit-code", SPDX::DATA_PATH)
diff = system_command "git", args: [
"-C", HOMEBREW_REPOSITORY, "diff", "--exit-code", SPDX::DATA_PATH
]
if diff.status.success?
ofail "No changes to SPDX license data."
else
puts "SPDX license data updated."
end
end
end

View File

@ -3,6 +3,8 @@
require "cli/parser"
require "utils/github"
# TODO: move function to manpages.rb and require that instead
require "dev-cmd/generate-man-completions"
module Homebrew
@ -57,9 +59,10 @@ module Homebrew
"-C", HOMEBREW_REPOSITORY, "diff", "--exit-code", "README.md"
]
if diff.status.success?
puts "No changes to list of maintainers."
ofail "No changes to list of maintainers."
else
Homebrew.regenerate_man_pages(preserve_date: true, quiet: true)
# TODO: move function to manpages.rb and call that instead
Homebrew.regenerate_man_pages(quiet: true)
puts "List of maintainers updated in the README and the generated man pages."
end
end

View File

@ -9,11 +9,11 @@ module Homebrew
module_function
NAMED_TIER_AMOUNT = 100
URL_TIER_AMOUNT = 1000
NAMED_MONTHLY_AMOUNT = 100
URL_MONTHLY_AMOUNT = 1000
sig { returns(CLI::Parser) }
def sponsors_args
def update_sponsors_args
Homebrew::CLI::Parser.new do
description <<~EOS
Update the list of GitHub Sponsors in the `Homebrew/brew` README.
@ -23,38 +23,36 @@ module Homebrew
end
end
def sponsor_name(s)
s["name"] || s["login"]
def sponsor_name(sponsor)
sponsor[:name] || sponsor[:login]
end
def sponsor_logo(s)
"https://github.com/#{s["login"]}.png?size=64"
def sponsor_logo(sponsor)
"https://github.com/#{sponsor[:login]}.png?size=64"
end
def sponsor_url(s)
"https://github.com/#{s["login"]}"
def sponsor_url(sponsor)
"https://github.com/#{sponsor[:login]}"
end
def sponsors
sponsors_args.parse
def update_sponsors
update_sponsors_args.parse
named_sponsors = []
logo_sponsors = []
largest_monthly_amount = 0
GitHub.sponsors_by_tier("Homebrew").each do |tier|
if tier["tier"] >= NAMED_TIER_AMOUNT
named_sponsors += tier["sponsors"].map do |s|
"[#{sponsor_name(s)}](#{sponsor_url(s)})"
end
end
GitHub.sponsorships("Homebrew").each do |s|
largest_monthly_amount = [s[:monthly_amount], s[:closest_tier_monthly_amount]].max
named_sponsors << "[#{sponsor_name(s)}](#{sponsor_url(s)})" if largest_monthly_amount >= NAMED_MONTHLY_AMOUNT
next if tier["tier"] < URL_TIER_AMOUNT
next if largest_monthly_amount < URL_MONTHLY_AMOUNT
logo_sponsors += tier["sponsors"].map do |s|
"[![#{sponsor_name(s)}](#{sponsor_logo(s)})](#{sponsor_url(s)})"
end
logo_sponsors << "[![#{sponsor_name(s)}](#{sponsor_logo(s)})](#{sponsor_url(s)})"
end
odie "No sponsorships amounts found! Ensure you have sufficient permissions!" if largest_monthly_amount.zero?
named_sponsors << "many other users and organisations via [GitHub Sponsors](https://github.com/sponsors/Homebrew)"
readme = HOMEBREW_REPOSITORY/"README.md"
@ -68,7 +66,7 @@ module Homebrew
"-C", HOMEBREW_REPOSITORY, "diff", "--exit-code", "README.md"
]
if diff.status.success?
puts "No changes to list of sponsors."
ofail "No changes to list of sponsors."
else
puts "List of sponsors updated in the README."
end

View File

@ -98,6 +98,16 @@ class DevelopmentTools
@gcc_version = {}
end
sig { returns(T::Boolean) }
def build_system_too_old?
false
end
sig { returns(T::Boolean) }
def system_gcc_too_old?
false
end
sig { returns(T::Boolean) }
def ca_file_handles_most_https_certificates?
# The system CA file is too old for some modern HTTPS certificates on

View File

@ -591,7 +591,11 @@ module Homebrew
def check_coretap_integrity
coretap = CoreTap.instance
return if !coretap.installed? && EnvConfig.install_from_api?
unless coretap.installed?
return if EnvConfig.install_from_api?
CoreTap.ensure_installed!
end
broken_tap(coretap) || examine_git_origin(coretap.path, Homebrew::EnvConfig.core_git_remote)
end

View File

@ -153,6 +153,11 @@ module Homebrew
"editors will do strange things in this case.",
default_text: "`$EDITOR` or `$VISUAL`.",
},
HOMEBREW_EVAL_ALL: {
description: "If set, `brew` commands evaluate all formulae and casks, executing their arbitrary code, by " \
"default without requiring --eval-all. Required to cache formula and cask descriptions.",
boolean: true,
},
HOMEBREW_FAIL_LOG_LINES: {
description: "Output this many lines of output on formula `system` failures.",
default: 15,

View File

@ -5,11 +5,17 @@ class Module
def attr_rw(*attrs)
attrs.each do |attr|
module_eval <<-EOS, __FILE__, __LINE__+1
def #{attr}(val=nil) # def prefix(val=nil)
@#{attr} ||= nil # @prefix ||= nil
return @#{attr} if val.nil? # return @prefix if val.nil?
@#{attr} = val # @prefix = val
end # end
def #{attr}(val=nil) # def prefix(val=nil)
if val.nil? # if val.nil?
if instance_variable_defined?(:@#{attr}) # if instance_variable_defined?(:@prefix)
return @#{attr} # return @prefix
else # else
return nil # return nil
end # end
end # end
#
@#{attr} = val # @prefix = val
end # end
EOS
end
end

View File

@ -1,4 +1,8 @@
# typed: strict
# frozen_string_literal: true
require "extend/os/mac/dependency_collector" if OS.mac?
if OS.mac?
require "extend/os/mac/dependency_collector"
elsif OS.linux?
require "extend/os/linux/dependency_collector"
end

View File

@ -0,0 +1,89 @@
# typed: true
# frozen_string_literal: true
require "os/linux/glibc"
class DependencyCollector
extend T::Sig
undef gcc_dep_if_needed
undef glibc_dep_if_needed
undef init_global_dep_tree_if_needed!
sig { params(related_formula_names: T::Set[String]).returns(T.nilable(Dependency)) }
def gcc_dep_if_needed(related_formula_names)
# gcc is required for libgcc_s.so.1 if glibc or gcc are too old
return unless DevelopmentTools.build_system_too_old?
return if building_global_dep_tree?
return if related_formula_names.include?(GCC)
return if global_dep_tree[GCC]&.intersect?(related_formula_names)
Dependency.new(GCC)
end
sig { params(related_formula_names: T::Set[String]).returns(T.nilable(Dependency)) }
def glibc_dep_if_needed(related_formula_names)
return unless OS::Linux::Glibc.below_ci_version?
return if building_global_dep_tree?
return if related_formula_names.include?(GLIBC)
return if global_dep_tree[GLIBC]&.intersect?(related_formula_names)
Dependency.new(GLIBC)
end
private
GLIBC = "glibc"
GCC = CompilerSelector.preferred_gcc.freeze
sig { void }
def init_global_dep_tree_if_needed!
return unless DevelopmentTools.build_system_too_old?
return if building_global_dep_tree?
return unless global_dep_tree.empty?
building_global_dep_tree!
global_dep_tree[GLIBC] = Set.new(global_deps_for(GLIBC))
# gcc depends on glibc
global_dep_tree[GCC] = Set.new([*global_deps_for(GCC), GLIBC, *@@global_dep_tree[GLIBC]])
built_global_dep_tree!
end
sig { params(name: String).returns(T::Array[String]) }
def global_deps_for(name)
@global_deps_for ||= {}
# Always strip out glibc and gcc from all parts of dependency tree when
# we're calculating their dependency trees. Other parts of Homebrew will
# catch any circular dependencies.
@global_deps_for[name] ||= Formula[name].deps.map(&:name).flat_map do |dep|
[dep, *global_deps_for(dep)].compact
end.uniq
end
# Use class variables to avoid this expensive logic needing to be done more
# than once.
# rubocop:disable Style/ClassVars
@@global_dep_tree = {}
@@building_global_dep_tree = false
sig { returns(T::Hash[String, T::Set[String]]) }
def global_dep_tree
@@global_dep_tree
end
sig { void }
def building_global_dep_tree!
@@building_global_dep_tree = true
end
sig { void }
def built_global_dep_tree!
@@building_global_dep_tree = false
end
sig { returns(T::Boolean) }
def building_global_dep_tree?
@@building_global_dep_tree.present?
end
# rubocop:enable Style/ClassVars
end

View File

@ -21,6 +21,18 @@ class DevelopmentTools
:gcc
end
sig { returns(T::Boolean) }
def build_system_too_old?
return @build_system_too_old if defined? @build_system_too_old
@build_system_too_old = (system_gcc_too_old? || OS::Linux::Glibc.below_ci_version?)
end
sig { returns(T::Boolean) }
def system_gcc_too_old?
gcc_version("gcc") < OS::LINUX_GCC_CI_VERSION
end
sig { returns(T::Hash[String, T.nilable(String)]) }
def build_system_info
generic_build_system_info.merge({

View File

@ -144,6 +144,7 @@ module Homebrew
gcc_dependents = Formula.installed.select do |formula|
next false unless formula.tap&.core_tap?
# FIXME: This includes formulae that have no runtime dependency on GCC.
formula.recursive_dependencies.map(&:name).include? "gcc"
rescue TapFormulaUnavailableError
false
@ -153,7 +154,7 @@ module Homebrew
badly_linked = gcc_dependents.select do |dependent|
keg = Keg.new(dependent.prefix)
keg.binary_executable_or_library_files.any? do |binary|
paths = binary.rpath.split(":")
paths = binary.rpaths
versioned_linkage = paths.any? { |path| path.match?(%r{lib/gcc/\d+$}) }
unversioned_linkage = paths.any? { |path| path.match?(%r{lib/gcc/current$}) }

View File

@ -0,0 +1,5 @@
# typed: strict
class Pathname
include ELFShim
end

View File

@ -5,6 +5,7 @@ class Formula
undef shared_library
undef loader_path
undef deuniversalize_machos
undef add_global_deps_to_spec
sig { params(name: String, version: T.nilable(T.any(String, Integer))).returns(String) }
def shared_library(name, version = nil)
@ -23,4 +24,22 @@ class Formula
sig { params(targets: T.nilable(T.any(Pathname, String))).void }
def deuniversalize_machos(*targets); end
sig { params(spec: SoftwareSpec).void }
def add_global_deps_to_spec(spec)
return unless DevelopmentTools.build_system_too_old?
@global_deps ||= begin
dependency_collector = spec.dependency_collector
related_formula_names = Set.new([
name,
*versioned_formulae_names,
])
[
dependency_collector.gcc_dep_if_needed(related_formula_names),
dependency_collector.glibc_dep_if_needed(related_formula_names),
].compact.freeze
end
@global_deps.each { |dep| spec.dependency_collector.add(dep) }
end
end

View File

@ -5,21 +5,45 @@ module Homebrew
module Install
module_function
DYNAMIC_LINKERS = [
"/lib64/ld-linux-x86-64.so.2",
"/lib64/ld64.so.2",
"/lib/ld-linux.so.3",
"/lib/ld-linux.so.2",
"/lib/ld-linux-aarch64.so.1",
"/lib/ld-linux-armhf.so.3",
"/system/bin/linker64",
"/system/bin/linker",
# This is a list of known paths to the host dynamic linker on Linux if
# the host glibc is new enough. The symlink_ld_so method will fail if
# the host linker cannot be found in this list.
DYNAMIC_LINKERS = %w[
/lib64/ld-linux-x86-64.so.2
/lib64/ld64.so.2
/lib/ld-linux.so.3
/lib/ld-linux.so.2
/lib/ld-linux-aarch64.so.1
/lib/ld-linux-armhf.so.3
/system/bin/linker64
/system/bin/linker
].freeze
private_constant :DYNAMIC_LINKERS
GCC_VERSION_SUFFIX = OS::LINUX_GCC_CI_VERSION.delete_suffix(".0").freeze
# We link GCC runtime libraries that are not specificaly used for Fortran,
# which are linked by the GCC formula. We only use the versioned shared libraries
# as the other shared and static libraries are only used at build time where
# GCC can find its own libraries.
GCC_RUNTIME_LIBS = %w[
libatomic.so.1
libgcc_s.so.1
libgomp.so.1
libstdc++.so.6
].freeze
private_constant :GCC_RUNTIME_LIBS
def perform_preinstall_checks(all_fatal: false, cc: nil)
generic_perform_preinstall_checks(all_fatal: all_fatal, cc: cc)
symlink_ld_so
symlink_gcc_libs
end
def global_post_install
generic_global_post_install
symlink_ld_so
symlink_gcc_libs
end
def check_cpu
@ -51,5 +75,24 @@ module Homebrew
FileUtils.ln_sf ld_so, brew_ld_so
end
private_class_method :symlink_ld_so
def symlink_gcc_libs
gcc_opt_prefix = HOMEBREW_PREFIX/"opt/#{OS::LINUX_PREFERRED_GCC_FORMULA}"
GCC_RUNTIME_LIBS.each do |library|
gcc_library = gcc_opt_prefix/"lib/gcc/#{GCC_VERSION_SUFFIX}/#{library}"
gcc_library_symlink = HOMEBREW_PREFIX/"lib/#{library}"
# Skip if the link target doesn't exist.
next unless gcc_library.readable?
# Also skip if the symlink already exists.
next if gcc_library_symlink.readable? && (gcc_library_symlink.readlink == gcc_library)
odie "#{HOMEBREW_PREFIX}/lib does not exist!" unless (HOMEBREW_PREFIX/"lib").readable?
FileUtils.ln_sf gcc_library, gcc_library_symlink
end
end
private_class_method :symlink_gcc_libs
end
end

View File

@ -80,9 +80,14 @@ class LinkageChecker
@unwanted_system_dylibs = @system_dylibs.reject do |s|
SYSTEM_LIBRARY_ALLOWLIST.include? File.basename(s)
end
# FIXME: Remove this when these dependencies are injected correctly (e.g. through `DependencyCollector`)
# See discussion at
# https://github.com/Homebrew/brew/pull/13577
@undeclared_deps -= [CompilerSelector.preferred_gcc, "glibc", "gcc"]
# We build all formulae with an RPATH that includes the gcc formula's runtime lib directory.
# See: https://github.com/Homebrew/brew/blob/e689cc07/Library/Homebrew/extend/os/linux/extend/ENV/super.rb#L53
# This results in formulae showing linkage with gcc whenever it is installed, even if no dependency is declared.
# See discussions at:
# https://github.com/Homebrew/brew/pull/13659
# https://github.com/Homebrew/brew/pull/13796
# TODO: Find a nicer way to handle this. (e.g. examining the ELF file to determine the required libstdc++.)
@undeclared_deps.delete("gcc")
end
end

View File

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

View File

@ -0,0 +1,5 @@
# typed: strict
class Pathname
include MachOShim
end

View File

@ -181,6 +181,14 @@ class Formula
# @private
def initialize(name, path, spec, alias_path: nil, force_bottle: false)
# Only allow instances of subclasses. The base class does not hold any spec information (URLs etc).
raise "Do not call `Formula.new' directly without a subclass." unless self.class < Formula
# Stop any subsequent modification of a formula's definition.
# Changes do not propagate to existing instances of formulae.
# Now that we have an instance, it's too late to make any changes to the class-level definition.
self.class.freeze
@name = name
@path = path
@alias_path = alias_path
@ -262,9 +270,13 @@ class Formula
return unless spec.url
spec.owner = self
add_global_deps_to_spec(spec)
instance_variable_set("@#{name}", spec)
end
sig { params(spec: SoftwareSpec).void }
def add_global_deps_to_spec(spec); end
def determine_active_spec(requested)
spec = send(requested) || stable || head
spec || raise(FormulaSpecificationError, "formulae require at least a URL")
@ -443,7 +455,17 @@ class Formula
# Returns any `@`-versioned formulae names for any formula (including versioned formulae).
sig { returns(T::Array[String]) }
def versioned_formulae_names
@versioned_formulae_names ||= Pathname.glob(path.to_s.gsub(/(@[\d.]+)?\.rb$/, "@*.rb")).map do |versioned_path|
versioned_paths = if tap
# Faster path, due to `tap.versioned_formula_files` caching.
name_prefix = "#{name.gsub(/(@[\d.]+)?$/, "")}@"
tap.versioned_formula_files.select do |file|
file.basename.to_s.start_with?(name_prefix)
end
else
Pathname.glob(path.to_s.gsub(/(@[\d.]+)?\.rb$/, "@*.rb"))
end
versioned_paths.map do |versioned_path|
next if versioned_path == path
versioned_path.basename(".rb").to_s
@ -453,7 +475,7 @@ class Formula
# Returns any `@`-versioned Formula objects for any Formula (including versioned formulae).
sig { returns(T::Array[Formula]) }
def versioned_formulae
@versioned_formulae ||= versioned_formulae_names.map do |name|
versioned_formulae_names.map do |name|
Formula[name]
rescue FormulaUnavailableError
nil
@ -1723,14 +1745,14 @@ class Formula
elsif shell_parameter_format == :arg
"--shell=#{shell}"
elsif shell_parameter_format == :none
""
nil
else
"#{shell_parameter_format}#{shell}"
end
popen_read_args = %w[]
popen_read_args << commands
popen_read_args << shell_parameter
popen_read_args << shell_parameter if shell_parameter.present?
popen_read_args.flatten!
script_path.dirname.mkpath
@ -1784,7 +1806,10 @@ class Formula
# this should only be used when users specify `--all` to a command
# @private
def self.all
# TODO: 3.6.0: consider checking ARGV for --all
# TODO: uncomment for 3.7.0 and ideally avoid using ARGV by moving to e.g. CLI::Parser
# if !ARGV.include?("--eval-all") && !Homebrew::EnvConfig.eval_all?
# odeprecated "Formula#all without --all or HOMEBREW_EVAL_ALL"
# end
files.map do |file|
Formulary.factory(file)
@ -2678,9 +2703,26 @@ class Formula
# The methods below define the formula DSL.
class << self
extend Predicable
extend T::Sig
include BuildEnvironment::DSL
include OnSystem::MacOSAndLinux
# Initialise instance variables for each subclass. These need to be initialised before the class is frozen,
# and some DSL may never be called so it can't be done lazily.
def inherited(child)
super
child.instance_eval do
# Ensure this is synced with `freeze`
@stable = SoftwareSpec.new(flags: build_flags)
@head = HeadSoftwareSpec.new(flags: build_flags)
@livecheck = Livecheck.new(self)
@conflicts = []
@skip_clean_paths = Set.new
@link_overwrite_paths = Set.new
@allowed_missing_libraries = Set.new
end
end
def method_added(method)
super
@ -2692,6 +2734,16 @@ class Formula
end
end
def freeze
specs.each(&:freeze)
@livecheck.freeze
@conflicts.freeze
@skip_clean_paths.freeze
@link_overwrite_paths.freeze
@allowed_missing_libraries.freeze
super
end
# Whether this formula contains OS/arch-specific blocks
# (e.g. `on_macos`, `on_arm`, `on_monterey :or_older`, `on_system :linux, macos: :big_sur_or_newer`).
# @private
@ -2772,6 +2824,18 @@ class Formula
# @private
attr_reader :plist_manual
# @private
attr_reader :conflicts
# @private
attr_reader :skip_clean_paths
# @private
attr_reader :link_overwrite_paths
# @private
attr_reader :allowed_missing_libraries
# If `pour_bottle?` returns `false` the user-visible reason to display for
# why they cannot use the bottle.
# @private
@ -2802,7 +2866,7 @@ class Formula
# A list of the {.stable} and {.head} {SoftwareSpec}s.
# @private
def specs
@specs ||= [stable, head].freeze
[stable, head].freeze
end
# @!attribute [w] url
@ -2886,8 +2950,9 @@ class Formula
#
# Formulae which should not be bottled should be tagged with:
# <pre>bottle :disable, "reasons"</pre>
def bottle(*args, &block)
stable.bottle(*args, &block)
sig { params(block: T.proc.bind(BottleSpecification).void).void }
def bottle(&block)
stable.bottle(&block)
end
# @private
@ -2918,7 +2983,6 @@ class Formula
# depends_on "libffi"
# end</pre>
def stable(&block)
@stable ||= SoftwareSpec.new(flags: build_flags)
return @stable unless block
@stable.instance_eval(&block)
@ -2937,7 +3001,6 @@ class Formula
# or (if autodetect fails):
# <pre>head "https://hg.is.awesome.but.git.has.won.example.com/", using: :hg</pre>
def head(val = nil, specs = {}, &block)
@head ||= HeadSoftwareSpec.new(flags: build_flags)
if block
@head.instance_eval(&block)
elsif val
@ -3088,11 +3151,6 @@ class Formula
@plist_manual = options[:manual]
end
# @private
def conflicts
@conflicts ||= []
end
# One or more formulae that conflict with this one and why.
# <pre>conflicts_with "imagemagick", because: "both install `convert` binaries"</pre>
def conflicts_with(*names)
@ -3113,11 +3171,6 @@ class Formula
skip_clean_paths.merge(paths)
end
# @private
def skip_clean_paths
@skip_clean_paths ||= Set.new
end
# Software that will not be symlinked into the `brew --prefix` and will
# only live in its Cellar. Other formulae can depend on it and Homebrew
# will add the necessary includes, libraries, and other paths while
@ -3221,7 +3274,6 @@ class Formula
# regex /foo-(\d+(?:\.\d+)+)\.tar/
# end</pre>
def livecheck(&block)
@livecheck ||= Livecheck.new(self)
return @livecheck unless block
@livecheckable = true
@ -3377,11 +3429,6 @@ class Formula
link_overwrite_paths.merge(paths)
end
# @private
def link_overwrite_paths
@link_overwrite_paths ||= Set.new
end
# Permit links to certain libraries that don't exist. Available on Linux only.
def ignore_missing_libraries(*libs)
unless Homebrew::SimulateSystem.simulating_or_running_on_linux?
@ -3395,11 +3442,6 @@ class Formula
allowed_missing_libraries.merge(libraries)
end
# @private
def allowed_missing_libraries
@allowed_missing_libraries ||= Set.new
end
end
end

View File

@ -52,14 +52,16 @@ module Homebrew
def audit_file
if formula.core_formula? && @versioned_formula
unversioned_name = formula.name.gsub(/@.*$/, "")
# ignore when an unversioned formula doesn't exist after an explicit rename
return if formula.tap.formula_renames.key?(unversioned_name)
# build this ourselves as we want e.g. homebrew/core to be present
full_name = "#{formula.tap}/#{unversioned_name}"
unversioned_formula = begin
# build this ourselves as we want e.g. homebrew/core to be present
full_name = if formula.tap
"#{formula.tap}/#{formula.name}"
else
formula.name
end
Formulary.factory(full_name.gsub(/@.*$/, "")).path
Formulary.factory(full_name).path
rescue FormulaUnavailableError, TapFormulaAmbiguityError,
TapFormulaWithOldnameAmbiguityError
Pathname.new formula.path.to_s.gsub(/@.*\.rb$/, ".rb")
@ -194,6 +196,13 @@ module Homebrew
if formula.license.present?
licenses, exceptions = SPDX.parse_license_expression formula.license
sspl_licensed = licenses.any? { |license| license.to_s.start_with?("SSPL") }
if sspl_licensed && @core_tap
problem <<~EOS
Formula #{formula.name} is SSPL-licensed. Software under the SSPL must not be packaged in homebrew/core.
EOS
end
non_standard_licenses = licenses.reject { |license| SPDX.valid_license? license }
if non_standard_licenses.present?
problem <<~EOS
@ -263,10 +272,7 @@ module Homebrew
next
end
# FIXME: Remove `glib-utils` exemption when the following PRs are merged:
# https://github.com/Homebrew/homebrew-core/pull/108307
# https://github.com/Homebrew/homebrew-core/pull/108497
if dep_f.oldname && dep.name.split("/").last == dep_f.oldname && dep_f.oldname != "glib-utils"
if dep_f.oldname && dep.name.split("/").last == dep_f.oldname
problem "Dependency '#{dep.name}' was renamed; use new name '#{dep_f.name}'."
end
@ -335,13 +341,6 @@ module Homebrew
end
return unless @core_tap
bad_gcc_dep = linux_only_gcc_dep?(formula) && (@strict || begin
fv = FormulaVersions.new(formula)
fv.formula_at_revision("origin/HEAD") { |prev_f| !linux_only_gcc_dep?(prev_f) }
end)
problem "Formulae in homebrew/core should not have a Linux-only dependency on GCC." if bad_gcc_dep
return if formula.tap&.audit_exception :versioned_dependencies_conflicts_allowlist, formula.name
# The number of conflicts on Linux is absurd.
@ -415,6 +414,21 @@ module Homebrew
end
end
def audit_gcc_dependency
return unless @core_tap
return if !@strict && !(@git && formula.tap.git?) # git log is required for non-strict audit
return unless Homebrew::SimulateSystem.simulating_or_running_on_linux?
return unless linux_only_gcc_dep?(formula)
bad_gcc_dep = @strict || begin
fv = FormulaVersions.new(formula)
fv.formula_at_revision("origin/HEAD") { |prev_f| !linux_only_gcc_dep?(prev_f) }
end
return unless bad_gcc_dep
problem "Formulae in homebrew/core should not have a Linux-only dependency on GCC."
end
def audit_postgresql
return unless formula.name == "postgresql"
return unless @core_tap
@ -477,13 +491,10 @@ module Homebrew
return unless DevelopmentTools.curl_handles_most_https_certificates?
use_homebrew_curl = false
%w[Stable HEAD].each do |name|
spec_name = name.downcase.to_sym
next unless (spec = formula.send(spec_name))
use_homebrew_curl = [:stable, :head].any? do |spec_name|
next false unless (spec = formula.send(spec_name))
use_homebrew_curl = spec.using == :homebrew_curl
break if use_homebrew_curl
spec.using == :homebrew_curl
end
if (http_content_problem = curl_check_http_content(homepage,
@ -865,14 +876,30 @@ module Homebrew
end
def linux_only_gcc_dep?(formula)
# TODO: Make this check work when running on Linux and not simulating macOS too.
return false unless Homebrew::SimulateSystem.simulating_or_running_on_macos?
odie "`#linux_only_gcc_dep?` works only on Linux!" if Homebrew::SimulateSystem.simulating_or_running_on_macos?
return false if formula.deps.map(&:name).exclude?("gcc")
formula_hash = formula.to_hash_with_variations
deps = formula_hash["dependencies"]
linux_deps = formula_hash.dig("variations", :x86_64_linux, "dependencies")
variations = formula.to_hash_with_variations["variations"]
# The formula has no variations, so all OS-version-arch triples depend on GCC.
return false if variations.blank?
deps.exclude?("gcc") && linux_deps&.include?("gcc")
MacOSVersions::SYMBOLS.each_key do |macos_version|
[:arm, :intel].each do |arch|
bottle_tag = Utils::Bottles::Tag.new(system: macos_version, arch: arch)
next unless bottle_tag.valid_combination?
variation_dependencies = variations.dig(bottle_tag.to_sym, "dependencies")
# This variation either:
# 1. does not exist
# 2. has no variation-specific dependencies
# In either case, it matches Linux.
return false if variation_dependencies.blank?
# We found a non-Linux variation that depends on GCC.
return false if variation_dependencies.include?("gcc")
end
end
true
end
end
end

View File

@ -581,11 +581,9 @@ class FormulaInstaller
end
def expand_dependencies_for_formula(formula, inherited_options)
any_bottle_used = false
# Cache for this expansion only. FormulaInstaller has a lot of inputs which can alter expansion.
cache_key = "FormulaInstaller-#{formula.full_name}-#{Time.now.to_f}"
expanded_deps = Dependency.expand(formula, cache_key: cache_key) do |dependent, dep|
Dependency.expand(formula, cache_key: cache_key) do |dependent, dep|
inherited_options[dep.name] |= inherited_options_for(dep)
build = effective_build_options_for(
dependent,
@ -601,36 +599,14 @@ class FormulaInstaller
Dependency.prune
elsif dep.satisfied?(inherited_options[dep.name])
Dependency.skip
else
any_bottle_used ||= install_bottle_for?(dep.to_formula, build)
end
end
[expanded_deps, any_bottle_used]
end
def expand_dependencies
inherited_options = Hash.new { |hash, key| hash[key] = Options.new }
any_bottle_used = pour_bottle?
expanded_deps, any_dep_bottle_used = expand_dependencies_for_formula(formula, inherited_options)
any_bottle_used ||= any_dep_bottle_used
# We require some dependencies (glibc, GCC 5, etc.) if binaries were built.
# Native binaries shouldn't exist in cross-platform `all` bottles.
if any_bottle_used && !formula.bottled?(:all) && !Keg.bottle_dependencies.empty?
all_bottle_deps = Keg.bottle_dependencies.flat_map do |bottle_dep|
bottle_dep.recursive_dependencies.map(&:name) + [bottle_dep.name]
end
if all_bottle_deps.exclude?(formula.name)
bottle_deps = Keg.bottle_dependencies.flat_map do |bottle_dep|
expanded_bottle_deps, = expand_dependencies_for_formula(bottle_dep, inherited_options)
expanded_bottle_deps
end
expanded_deps = Dependency.merge_repeats(bottle_deps + expanded_deps)
end
end
expanded_deps = expand_dependencies_for_formula(formula, inherited_options)
expanded_deps.map { |dep| [dep, inherited_options[dep.name]] }
end
@ -799,6 +775,8 @@ class FormulaInstaller
fix_dynamic_linkage(keg) if !@poured_bottle || !formula.bottle_specification.skip_relocation?
Homebrew::Install.global_post_install
if build_bottle?
ohai "Not running 'post_install' as we're building a bottle"
puts "You can run it manually using:"
@ -1187,6 +1165,8 @@ class FormulaInstaller
if pour_bottle?(output_warning: true)
formula.fetch_bottle_tab
elsif Homebrew::EnvConfig.install_from_api?
odie "Unable to build #{formula.name} from source with HOMEBREW_INSTALL_FROM_API."
else
formula.fetch_patches
formula.resources.each(&:fetch)

View File

@ -45,6 +45,7 @@ HOMEBREW_REQUIRED_RUBY_VERSION = ENV.fetch("HOMEBREW_REQUIRED_RUBY_VERSION").fre
HOMEBREW_PRODUCT = ENV.fetch("HOMEBREW_PRODUCT").freeze
HOMEBREW_VERSION = ENV.fetch("HOMEBREW_VERSION").freeze
HOMEBREW_WWW = "https://brew.sh"
HOMEBREW_DOCS_WWW = "https://docs.brew.sh"
HOMEBREW_SYSTEM = ENV.fetch("HOMEBREW_SYSTEM").freeze
HOMEBREW_PROCESSOR = ENV.fetch("HOMEBREW_PROCESSOR").freeze

View File

@ -30,6 +30,10 @@ module Homebrew
Diagnostic.checks(:build_from_source_checks, fatal: all_fatal)
end
def global_post_install; end
alias generic_global_post_install global_post_install
module_function :generic_global_post_install
def check_prefix
if (Hardware::CPU.intel? || Hardware::CPU.in_rosetta2?) &&
HOMEBREW_PREFIX.to_s == HOMEBREW_MACOS_ARM_DEFAULT_PREFIX

View File

@ -366,17 +366,6 @@ class Keg
def self.file_linked_libraries(_file, _string)
[]
end
def self.bottle_dependencies
return [] unless Homebrew::SimulateSystem.simulating_or_running_on_linux?
@bottle_dependencies ||= begin
formulae = []
gcc = Formulary.factory(CompilerSelector.preferred_gcc)
formulae << gcc if DevelopmentTools.gcc_version("gcc") < gcc.version.to_i
formulae
end
end
end
require "extend/os/keg_relocate"

View File

@ -82,9 +82,20 @@ class Options
end
def initialize(*args)
# Ensure this is synced with `initialize_dup` and `freeze` (excluding simple objects like integers and booleans)
@options = Set.new(*args)
end
def initialize_dup(other)
super
@options = @options.dup
end
def freeze
@options.dup
super
end
def each(*args, &block)
@options.each(*args, &block)
end

View File

@ -45,15 +45,12 @@ module OS
::OS_VERSION = ENV.fetch("HOMEBREW_OS_VERSION").freeze
LINUX_CI_OS_VERSION = "Ubuntu 16.04"
LINUX_GLIBC_CI_VERSION = "2.23"
LINUX_GCC_CI_VERSION = "5.0"
LINUX_PREFERRED_GCC_FORMULA = "gcc@5"
# Ubuntu 22.04 (see Linux-CI.md)
# See Linux-CI.md
LINUX_CI_OS_VERSION = "Ubuntu 22.04"
LINUX_GLIBC_CI_VERSION = "2.35"
LINUX_GLIBC_NEXT_CI_VERSION = "2.35"
# LINUX_GCC_CI_VERSION = "11.0"
# LINUX_PREFERRED_GCC_FORMULA = "gcc@11"
LINUX_GCC_CI_VERSION = "11.0"
LINUX_PREFERRED_GCC_FORMULA = "gcc@11"
if OS.mac?
require "os/mac"

View File

@ -97,7 +97,7 @@ module ELFShim
# An array of runtime search path entries, such as:
# ["/lib", "/usr/lib", "/usr/local/lib"]
def rpaths
rpath.split(":")
Array(rpath&.split(":"))
end
def interpreter

View File

@ -44,6 +44,11 @@ module OS
def below_minimum_version?
system_version < minimum_version
end
sig { returns(T::Boolean) }
def below_ci_version?
system_version < LINUX_GLIBC_CI_VERSION
end
end
end
end

View File

@ -1,6 +1,8 @@
# typed: strict
# frozen_string_literal: true
raise "#{__FILE__} must not be loaded via `require`." if $PROGRAM_NAME != __FILE__
old_trap = trap("INT") { exit! 130 }
require_relative "global"

View File

@ -1,4 +1,4 @@
# typed: false
# typed: true
# frozen_string_literal: true
require "formula"

View File

@ -20,6 +20,10 @@ class Requirement
attr_reader :tags, :name, :cask, :download
def initialize(tags = [])
# Only allow instances of subclasses. This base class enforces no constraints on its own.
# Individual subclasses use the `satisfy` DSL to define those constraints.
raise "Do not call `Requirement.new' directly without a subclass." unless self.class < Requirement
@cask = self.class.cask
@download = self.class.download
tags.each do |tag|
@ -141,9 +145,9 @@ class Requirement
private
def infer_name
klass = self.class.name || self.class.to_s
klass = klass.sub(/(Dependency|Requirement)$/, "")
.sub(/^(\w+::)*/, "")
klass = self.class.name
klass = klass&.sub(/(Dependency|Requirement)$/, "")
&.sub(/^(\w+::)*/, "")
return klass.downcase if klass.present?
return @cask if @cask.present?

View File

@ -29,6 +29,7 @@ class Resource
attr_accessor :name
def initialize(name = nil, &block)
# Ensure this is synced with `initialize_dup` and `freeze` (excluding simple objects like integers and booleans)
@name = name
@url = nil
@version = nil
@ -37,11 +38,35 @@ class Resource
@checksum = nil
@using = nil
@patches = []
@livecheck = nil
@livecheck = Livecheck.new(self)
@livecheckable = false
instance_eval(&block) if block
end
def initialize_dup(other)
super
@name = @name.dup
@version = @version.dup
@mirrors = @mirrors.dup
@specs = @specs.dup
@checksum = @checksum.dup
@using = @using.dup
@patches = @patches.dup
@livecheck = @livecheck.dup
end
def freeze
@name.freeze
@version.freeze
@mirrors.freeze
@specs.freeze
@checksum.freeze
@using.freeze
@patches.freeze
@livecheck.freeze
super
end
def owner=(owner)
@owner = owner
patches.each { |p| p.owner = owner }
@ -185,7 +210,6 @@ class Resource
# regex /foo-(\d+(?:\.\d+)+)\.tar/
# end</pre>
def livecheck(&block)
@livecheck ||= Livecheck.new(self) if block
return @livecheck unless block
@livecheckable = true
@ -215,13 +239,13 @@ class Resource
@download_strategy = DownloadStrategyDetector.detect(url, using)
@specs.merge!(specs)
@downloader = nil
@version = detect_version(@version)
end
def version(val = nil)
@version ||= begin
version = detect_version(val)
version.null? ? nil : version
end
return @version if val.nil?
@version = detect_version(val)
end
def mirror(val)
@ -242,15 +266,15 @@ class Resource
private
def detect_version(val)
return Version::NULL if val.nil? && url.nil?
case val
when nil then Version.detect(url, **specs)
version = case val
when nil then url.nil? ? Version::NULL : Version.detect(url, **specs)
when String then Version.create(val)
when Version then val
else
raise TypeError, "version '#{val.inspect}' should be a string"
end
version unless version.null?
end
# A resource containing a Go package.

View File

@ -49,7 +49,7 @@ module RuboCop
stanzas.sort do |s1, s2|
i1 = stanza_order_index(s1)
i2 = stanza_order_index(s2)
if i1 == i2
if i1 == i2 || i1.blank? || i2.blank?
i1 = stanzas.index(s1)
i2 = stanzas.index(s2)
end

View File

@ -55,6 +55,8 @@ module RuboCop
end.freeze
STANZA_ORDER = STANZA_GROUPS.flatten.freeze
ON_SYSTEM_METHODS = [:arm, :intel, *MacOSVersions::SYMBOLS.keys].map { |option| :"on_#{option}" }.freeze
end
end
end

View File

@ -19,8 +19,10 @@ module RuboCop
def stanza?
return true if arch_variable?
return false if !send_type? && !block_type?
return true if ON_SYSTEM_METHODS.include?(method_name)
(send_type? || block_type?) && STANZA_ORDER.include?(method_name)
STANZA_ORDER.include?(method_name)
end
def heredoc?

View File

@ -39,6 +39,9 @@ module RuboCop
audit_on_system_blocks(stanza.stanza_node, stanza.stanza_name)
end
audit_arch_conditionals(cask_body)
simplify_sha256_stanzas
end
private
@ -46,6 +49,33 @@ module RuboCop
attr_reader :cask_block
def_delegators :cask_block, :toplevel_stanzas, :cask_body
def simplify_sha256_stanzas
nodes = {}
sha256_on_arch_stanzas(cask_body) do |node, method, value|
nodes[method.to_s.delete_prefix("on_").to_sym] = { node: node, value: value }
end
return if !nodes.key?(:arm) || !nodes.key?(:intel)
offending_node(nodes[:arm][:node])
replacement_string = "sha256 arm: #{nodes[:arm][:value].inspect}, intel: #{nodes[:intel][:value].inspect}"
problem "Use `#{replacement_string}` instead of nesting the `sha256` stanzas in " \
"`on_intel` and `on_arm` blocks" do |corrector|
corrector.replace(nodes[:arm][:node].source_range, replacement_string)
corrector.replace(nodes[:intel][:node].source_range, "")
end
end
def_node_search :sha256_on_arch_stanzas, <<~PATTERN
$(block
(send nil? ${:on_intel :on_arm})
(args)
(send nil? :sha256
(str $_)))
PATTERN
end
end
end

View File

@ -0,0 +1,17 @@
# typed: strict
module RuboCop
module Cop
module Cask
class OnSystemConditionals < Base
sig {
params(
base_node: Parser::AST::Node,
block: T.proc.params(node: Parser::AST::Node, method: Symbol, value: String).void,
).void
}
def sha256_on_arch_stanzas(base_node, &block); end
end
end
end
end

View File

@ -415,6 +415,151 @@ module RuboCop
end
end
# This cop makes sure that the `generate_completions_from_executable` DSL is used.
#
# @api private
class GenerateCompletionsDSL < FormulaCop
extend AutoCorrector
def audit_formula(_node, _class_node, _parent_class_node, body_node)
install = find_method_def(body_node, :install)
return if install.blank?
correctable_shell_completion_node(install) do |node, shell, base_name, executable, subcmd, shell_parameter| # rubocop:disable Metrics/ParameterLists
# generate_completions_from_executable only applicable if shell is passed
next unless shell_parameter.match?(/(bash|zsh|fish)/)
base_name = base_name.delete_prefix("_").delete_suffix(".fish")
shell = shell.to_s.delete_suffix("_completion").to_sym
shell_parameter_stripped = shell_parameter
.delete_suffix("bash")
.delete_suffix("zsh")
.delete_suffix("fish")
shell_parameter_format = if shell_parameter_stripped.empty?
nil
elsif shell_parameter_stripped == "--"
:flag
elsif shell_parameter_stripped == "--shell="
:arg
else
shell_parameter_stripped
end
replacement_args = %w[]
replacement_args << executable.source
replacement_args << subcmd.source
replacement_args << "base_name: \"#{base_name}\"" unless base_name == @formula_name
replacement_args << "shells: [:#{shell}]"
unless shell_parameter_format.nil?
replacement_args << "shell_parameter_format: #{shell_parameter_format.inspect}"
end
offending_node(node)
replacement = "generate_completions_from_executable(#{replacement_args.join(", ")})"
problem "Use `#{replacement}` instead of `#{@offensive_node.source}`." do |corrector|
corrector.replace(@offensive_node.source_range, replacement)
end
end
shell_completion_node(install) do |node|
next if node.source.include?("<<~") # skip heredoc completion scripts
next if node.source.match?(/{.*=>.*}/) # skip commands needing custom ENV variables
offending_node(node)
problem "Use `generate_completions_from_executable` DSL instead of `#{@offensive_node.source}`."
end
end
# match ({bash,zsh,fish}_completion/"_?foo{.fish}?").write Utils.safe_popen_read(foo, subcmd, shell_parameter)
def_node_search :correctable_shell_completion_node, <<~EOS
$(send
(begin
(send
(send nil? ${:bash_completion :zsh_completion :fish_completion}) :/
(str $_))) :write
(send
(const nil? :Utils) :safe_popen_read
$(send
(send nil? :bin) :/
(str _))
$(str _)
(str $_)))
EOS
# matches ({bash,zsh,fish}_completion/"_?foo{.fish}?").write output
def_node_search :shell_completion_node, <<~EOS
$(send
(begin
(send
(send nil? {:bash_completion :zsh_completion :fish_completion}) :/
(str _))) :write _)
EOS
end
# This cop makes sure that the `generate_completions_from_executable` DSL is used with only
# a single, combined call for all shells.
#
# @api private
class SingleGenerateCompletionsDSLCall < FormulaCop
extend AutoCorrector
def audit_formula(_node, _class_node, _parent_class_node, body_node)
install = find_method_def(body_node, :install)
return if install.blank?
methods = find_every_method_call_by_name(install, :generate_completions_from_executable)
return if methods.length <= 1
offenses = []
shells = []
methods.each do |method|
next unless method.source.include?("shells:")
shells << method.source.match(/shells: \[(:bash|:zsh|:fish)\]/).captures.first
offenses << method
end
return if offenses.blank?
T.must(offenses[0...-1]).each_with_index do |node, i|
# commands have to be the same to be combined
# send_type? matches `bin/"foo"`, str_type? matches remaining command parts,
# the rest are kwargs we need to filter out
method_commands = node.arguments.filter { |arg| arg.send_type? || arg.str_type? }
next_method_commands = offenses[i + 1].arguments.filter { |arg| arg.send_type? || arg.str_type? }
unless method_commands == next_method_commands
shells.delete_at(i)
next
end
offending_node(node)
problem "Use a single `generate_completions_from_executable` " \
"call combining all specified shells." do |corrector|
# adjust range by -4 and +1 to also include & remove leading spaces and trailing \n
corrector.replace(@offensive_node.source_range.adjust(begin_pos: -4, end_pos: 1), "")
end
end
return if shells.length <= 1 # no shells to combine left
offending_node(offenses.last)
replacement = if (%w[:bash :zsh :fish] - shells).empty?
@offensive_node.source.sub(/shells: \[(:bash|:zsh|:fish)\]/, "")
.sub(", )", ")") # clean up dangling trailing comma
.sub("(, ", "(") # clean up dangling leading comma
.sub(", , ", ", ") # clean up dangling enclosed comma
else
@offensive_node.source.sub(/shells: \[(:bash|:zsh|:fish)\]/,
"shells: [#{shells.join(", ")}]")
end
problem "Use `#{replacement}` instead of `#{@offensive_node.source}`." do |corrector|
corrector.replace(@offensive_node.source_range, replacement)
end
end
end
# This cop checks for other miscellaneous style violations.
#
# @api private

View File

@ -1,2 +1,3 @@
#!/bin/bash
exec brew rubocop "$@"
HOMEBREW_PREFIX_BIN="$(cd "$(dirname "$0")"/../../../../ && pwd)/bin/"
exec "${HOMEBREW_PREFIX_BIN}"brew rubocop "$@"

View File

@ -36,6 +36,7 @@ class SoftwareSpec
def_delegators :@resource, :sha256
def initialize(flags: [])
# Ensure this is synced with `initialize_dup` and `freeze` (excluding simple objects like integers and booleans)
@resource = Resource.new
@resources = {}
@dependency_collector = DependencyCollector.new
@ -50,6 +51,38 @@ class SoftwareSpec
@uses_from_macos_elements = []
end
def initialize_dup(other)
super
@resource = @resource.dup
@resources = @resources.dup
@dependency_collector = @dependency_collector.dup
@bottle_specification = @bottle_specification.dup
@patches = @patches.dup
@options = @options.dup
@flags = @flags.dup
@deprecated_flags = @deprecated_flags.dup
@deprecated_options = @deprecated_options.dup
@build = @build.dup
@compiler_failures = @compiler_failures.dup
@uses_from_macos_elements = @uses_from_macos_elements.dup
end
def freeze
@resource.freeze
@resources.freeze
@dependency_collector.freeze
@bottle_specification.freeze
@patches.freeze
@options.freeze
@flags.freeze
@deprecated_flags.freeze
@deprecated_options.freeze
@build.freeze
@compiler_failures.freeze
@uses_from_macos_elements.freeze
super
end
def owner=(owner)
@name = owner.name
@full_name = owner.full_name
@ -321,7 +354,7 @@ class Bottle
@cellar = tag_spec.cellar
@rebuild = spec.rebuild
@resource.version = formula.pkg_version
@resource.version = formula.pkg_version.to_s
@resource.checksum = tag_spec.checksum
@fetch_tab_retried = false

View File

@ -2784,7 +2784,6 @@ end
module ActiveSupport::VERSION; end
ActiveSupport::VERSION::MAJOR = T.let(T.unsafe(nil), Integer)
ActiveSupport::VERSION::MINOR = T.let(T.unsafe(nil), Integer)
ActiveSupport::VERSION::PRE = T.let(T.unsafe(nil), String)
ActiveSupport::VERSION::STRING = T.let(T.unsafe(nil), String)
ActiveSupport::VERSION::TINY = T.let(T.unsafe(nil), Integer)

View File

@ -220,6 +220,7 @@ class Addressable::URI
protected
def force_utf8_encoding_if_needed(str); end
def remove_composite_values; end
def replace_self(uri); end
def split_path(path); end

View File

@ -51,10 +51,12 @@ class Bootsnap::InvalidConfiguration < ::StandardError; end
module Bootsnap::LoadPathCache
class << self
def enabled?; end
def load_path_cache; end
def loaded_features_index; end
def setup(cache_path:, development_mode:); end
def supported?; end
def unload!; end
end
end
@ -63,7 +65,7 @@ Bootsnap::LoadPathCache::CACHED_EXTENSIONS = T.let(T.unsafe(nil), Array)
class Bootsnap::LoadPathCache::Cache
def initialize(store, path_obj, development_mode: T.unsafe(nil)); end
def find(feature, try_extensions: T.unsafe(nil)); end
def find(feature); end
def load_dir(dir); end
def push_paths(sender, *paths); end
def reinitialize(path_obj = T.unsafe(nil)); end
@ -76,7 +78,7 @@ class Bootsnap::LoadPathCache::Cache
def maybe_append_extension(feature); end
def now; end
def push_paths_locked(*paths); end
def search_index(feature, try_extensions: T.unsafe(nil)); end
def search_index(feature); end
def stale?; end
def try_ext(feature); end
def try_index(feature); end
@ -88,7 +90,8 @@ Bootsnap::LoadPathCache::Cache::BUILTIN_FEATURES = T.let(T.unsafe(nil), Hash)
module Bootsnap::LoadPathCache::ChangeObserver
class << self
def register(observer, arr); end
def register(arr, observer); end
def unregister(arr); end
end
end

View File

@ -1288,6 +1288,7 @@ class Nokogiri::XML::Reader
def attribute(_arg0); end
def attribute_at(_arg0); end
def attribute_count; end
def attribute_hash; end
def attribute_nodes; end
def attributes; end
def attributes?; end

View File

@ -1430,6 +1430,7 @@ end
class Parser::Source::Range
include ::Comparable
include ::RuboCop::AST::Ext::Range
include ::RuboCop::Ext::Range
def initialize(source_buffer, begin_pos, end_pos); end

View File

@ -150,7 +150,7 @@ class Rack::Builder
def call(env); end
def freeze_app; end
def map(path, &block); end
def run(app); end
def run(app = T.unsafe(nil), &block); end
def to_app; end
def use(middleware, *args, &block); end
def warmup(prc = T.unsafe(nil), &block); end
@ -161,9 +161,9 @@ class Rack::Builder
class << self
def app(default_app = T.unsafe(nil), &block); end
def load_file(path, opts = T.unsafe(nil)); end
def load_file(path); end
def new_from_string(builder_script, file = T.unsafe(nil)); end
def parse_file(config, opts = T.unsafe(nil)); end
def parse_file(path); end
end
end
@ -221,7 +221,7 @@ class Rack::CommonLogger
private
def extract_content_length(headers); end
def log(env, status, header, began_at); end
def log(env, status, response_headers, began_at); end
end
Rack::CommonLogger::FORMAT = T.let(T.unsafe(nil), String)
@ -281,6 +281,8 @@ class Rack::Deflater::GzipStream
def write(data); end
end
Rack::Deflater::GzipStream::BUFFER_LENGTH = T.let(T.unsafe(nil), Integer)
class Rack::Directory
def initialize(root, app = T.unsafe(nil)); end
@ -319,7 +321,6 @@ class Rack::ETag
private
def digest_body(body); end
def etag_body?(body); end
def etag_status?(status); end
def skip_caching?(headers); end
end
@ -381,10 +382,6 @@ class Rack::Files
def fail(status, body, headers = T.unsafe(nil)); end
def filesize(path); end
def mime_type(path, default_mime); end
class << self
def method_added(name); end
end
end
Rack::Files::ALLOWED_VERBS = T.let(T.unsafe(nil), Array)
@ -426,40 +423,6 @@ Rack::HTTPS = T.let(T.unsafe(nil), String)
Rack::HTTP_COOKIE = T.let(T.unsafe(nil), String)
Rack::HTTP_HOST = T.let(T.unsafe(nil), String)
Rack::HTTP_PORT = T.let(T.unsafe(nil), String)
Rack::HTTP_VERSION = T.let(T.unsafe(nil), String)
module Rack::Handler
class << self
def default; end
def get(server); end
def pick(server_names); end
def register(server, klass); end
def try_require(prefix, const_name); end
end
end
class Rack::Handler::CGI
class << self
def run(app, **options); end
def send_body(body); end
def send_headers(status, headers); end
def serve(app); end
end
end
Rack::Handler::SERVER_NAMES = T.let(T.unsafe(nil), Array)
class Rack::Handler::WEBrick < ::WEBrick::HTTPServlet::AbstractServlet
def initialize(server, app); end
def service(req, res); end
class << self
def run(app, **options); end
def shutdown; end
def valid_options; end
end
end
class Rack::Head
def initialize(app); end
@ -467,36 +430,77 @@ class Rack::Head
def call(env); end
end
class Rack::Headers < ::Hash
def [](key); end
def []=(key, value); end
def assoc(key); end
def compare_by_identity; end
def delete(key); end
def dig(key, *a); end
def fetch(key, *default, &block); end
def fetch_values(*a); end
def has_key?(key); end
def include?(key); end
def invert; end
def key?(key); end
def member?(key); end
def merge(hash, &block); end
def merge!(hash, &block); end
def reject(&block); end
def replace(hash); end
def select(&block); end
def slice(*a); end
def store(key, value); end
def to_proc; end
def transform_keys(&block); end
def transform_keys!; end
def transform_values(&block); end
def update(hash, &block); end
def values_at(*keys); end
private
def downcase_key(key); end
class << self
def [](*items); end
end
end
Rack::LINK = T.let(T.unsafe(nil), String)
class Rack::Lint
include ::Rack::Lint::Assertion
def initialize(app); end
def _call(env); end
def call(env = T.unsafe(nil)); end
end
class Rack::Lint::LintError < ::RuntimeError; end
class Rack::Lint::Wrapper
def initialize(app, env); end
def call(stream); end
def check_content_length(status, headers); end
def check_content_type(status, headers); end
def check_env(env); end
def check_environment(env); end
def check_error(error); end
def check_headers(header); end
def check_header_value(key, value); end
def check_headers(headers); end
def check_hijack(env); end
def check_hijack_response(headers, env); end
def check_input(input); end
def check_status(status); end
def close; end
def each; end
def verify_content_length(bytes); end
def respond_to?(name, *_arg1); end
def response; end
def to_ary; end
def verify_content_length(size); end
def verify_to_path; end
end
module Rack::Lint::Assertion
def assert(message); end
end
class Rack::Lint::ErrorWrapper
include ::Rack::Lint::Assertion
class Rack::Lint::Wrapper::ErrorWrapper
def initialize(error); end
def close(*args); end
@ -505,38 +509,31 @@ class Rack::Lint::ErrorWrapper
def write(str); end
end
class Rack::Lint::HijackWrapper
include ::Rack::Lint::Assertion
extend ::Forwardable
def initialize(io); end
def close(*args, &block); end
def close_read(*args, &block); end
def close_write(*args, &block); end
def closed?(*args, &block); end
def flush(*args, &block); end
def read(*args, &block); end
def read_nonblock(*args, &block); end
def write(*args, &block); end
def write_nonblock(*args, &block); end
end
Rack::Lint::HijackWrapper::REQUIRED_METHODS = T.let(T.unsafe(nil), Array)
class Rack::Lint::InputWrapper
include ::Rack::Lint::Assertion
class Rack::Lint::Wrapper::InputWrapper
def initialize(input); end
def close(*args); end
def each(*args); end
def gets(*args); end
def read(*args); end
def rewind(*args); end
end
class Rack::Lint::LintError < ::RuntimeError; end
class Rack::Lint::Wrapper::StreamWrapper
extend ::Forwardable
def initialize(stream); end
def <<(*args, &block); end
def close(*args, &block); end
def close_read(*args, &block); end
def close_write(*args, &block); end
def closed?(*args, &block); end
def flush(*args, &block); end
def read(*args, &block); end
def write(*args, &block); end
end
Rack::Lint::Wrapper::StreamWrapper::REQUIRED_METHODS = T.let(T.unsafe(nil), Array)
class Rack::Lock
def initialize(app, mutex = T.unsafe(nil)); end
@ -653,7 +650,7 @@ end
module Rack::Multipart
class << self
def build_multipart(params, first = T.unsafe(nil)); end
def extract_multipart(req, params = T.unsafe(nil)); end
def extract_multipart(request, params = T.unsafe(nil)); end
def parse_multipart(env, params = T.unsafe(nil)); end
end
end
@ -671,6 +668,8 @@ Rack::Multipart::EXTENDED_OTHER_NAME = T.let(T.unsafe(nil), Regexp)
Rack::Multipart::EXTENDED_OTHER_PARAMETER = T.let(T.unsafe(nil), Regexp)
Rack::Multipart::EXTENDED_OTHER_VALUE = T.let(T.unsafe(nil), Regexp)
Rack::Multipart::EXTENDED_PARAMETER = T.let(T.unsafe(nil), Regexp)
class Rack::Multipart::EmptyContentError < ::EOFError; end
class Rack::Multipart::Error < ::StandardError; end
class Rack::Multipart::Generator
def initialize(params, first = T.unsafe(nil)); end
@ -695,21 +694,21 @@ class Rack::Multipart::MultipartPartLimitError < ::Errno::EMFILE; end
class Rack::Multipart::Parser
def initialize(boundary, tempfile, bufsize, query_parser); end
def on_read(content); end
def parse(io); end
def result; end
def state; end
private
def consume_boundary; end
def full_boundary; end
def dequote(str); end
def get_filename(head); end
def handle_consume_token; end
def handle_empty_content!(content); end
def handle_fast_forward; end
def handle_mime_body; end
def handle_mime_head; end
def run_parser; end
def read_data(io, outbuf); end
def tag_multipart_encoding(filename, content_type, name, body); end
class << self
@ -718,14 +717,12 @@ class Rack::Multipart::Parser
end
end
Rack::Multipart::Parser::BOUNDARY_REGEX = T.let(T.unsafe(nil), Regexp)
Rack::Multipart::Parser::BUFSIZE = T.let(T.unsafe(nil), Integer)
class Rack::Multipart::Parser::BoundedIO
def initialize(io, content_length); end
def read(size, outbuf = T.unsafe(nil)); end
def rewind; end
end
Rack::Multipart::Parser::CHARSET = T.let(T.unsafe(nil), String)
@ -807,23 +804,30 @@ class Rack::NullLogger
def datetime_format; end
def datetime_format=(datetime_format); end
def debug(progname = T.unsafe(nil), &block); end
def debug!; end
def debug?; end
def error(progname = T.unsafe(nil), &block); end
def error!; end
def error?; end
def fatal(progname = T.unsafe(nil), &block); end
def fatal!; end
def fatal?; end
def formatter; end
def formatter=(formatter); end
def info(progname = T.unsafe(nil), &block); end
def info!; end
def info?; end
def level; end
def level=(level); end
def log(severity, message = T.unsafe(nil), progname = T.unsafe(nil), &block); end
def progname; end
def progname=(progname); end
def reopen(logdev = T.unsafe(nil)); end
def sev_threshold; end
def sev_threshold=(sev_threshold); end
def unknown(progname = T.unsafe(nil), &block); end
def warn(progname = T.unsafe(nil), &block); end
def warn!; end
def warn?; end
end
@ -835,25 +839,24 @@ Rack::PUT = T.let(T.unsafe(nil), String)
Rack::QUERY_STRING = T.let(T.unsafe(nil), String)
class Rack::QueryParser
def initialize(params_class, key_space_limit, param_depth_limit); end
def initialize(params_class, _key_space_limit = T.unsafe(nil), param_depth_limit); end
def key_space_limit; end
def make_params; end
def new_depth_limit(param_depth_limit); end
def new_space_limit(key_space_limit); end
def normalize_params(params, name, v, depth); end
def normalize_params(params, name, v, _depth = T.unsafe(nil)); end
def param_depth_limit; end
def parse_nested_query(qs, d = T.unsafe(nil)); end
def parse_query(qs, d = T.unsafe(nil), &unescaper); end
def parse_nested_query(qs, separator = T.unsafe(nil)); end
def parse_query(qs, separator = T.unsafe(nil), &unescaper); end
private
def _normalize_params(params, name, v, depth); end
def params_hash_has_key?(hash, key); end
def params_hash_type?(obj); end
def unescape(s); end
class << self
def make_default(key_space_limit, param_depth_limit); end
def make_default(_key_space_limit = T.unsafe(nil), param_depth_limit); end
end
end
@ -863,7 +866,7 @@ class Rack::QueryParser::InvalidParameterError < ::ArgumentError; end
class Rack::QueryParser::ParameterTypeError < ::TypeError; end
class Rack::QueryParser::Params
def initialize(limit); end
def initialize; end
def [](key); end
def []=(key, value); end
@ -875,15 +878,12 @@ end
class Rack::QueryParser::ParamsTooDeepError < ::RangeError; end
Rack::RACK_ERRORS = T.let(T.unsafe(nil), String)
Rack::RACK_HIJACK = T.let(T.unsafe(nil), String)
Rack::RACK_HIJACK_IO = T.let(T.unsafe(nil), String)
Rack::RACK_INPUT = T.let(T.unsafe(nil), String)
Rack::RACK_IS_HIJACK = T.let(T.unsafe(nil), String)
Rack::RACK_LOGGER = T.let(T.unsafe(nil), String)
Rack::RACK_METHODOVERRIDE_ORIGINAL_METHOD = T.let(T.unsafe(nil), String)
Rack::RACK_MULTIPART_BUFFER_SIZE = T.let(T.unsafe(nil), String)
Rack::RACK_MULTIPART_TEMPFILE_FACTORY = T.let(T.unsafe(nil), String)
Rack::RACK_MULTIPROCESS = T.let(T.unsafe(nil), String)
Rack::RACK_MULTITHREAD = T.let(T.unsafe(nil), String)
Rack::RACK_RECURSIVE_INCLUDE = T.let(T.unsafe(nil), String)
Rack::RACK_REQUEST_COOKIE_HASH = T.let(T.unsafe(nil), String)
Rack::RACK_REQUEST_COOKIE_STRING = T.let(T.unsafe(nil), String)
@ -892,10 +892,9 @@ Rack::RACK_REQUEST_FORM_INPUT = T.let(T.unsafe(nil), String)
Rack::RACK_REQUEST_FORM_VARS = T.let(T.unsafe(nil), String)
Rack::RACK_REQUEST_QUERY_HASH = T.let(T.unsafe(nil), String)
Rack::RACK_REQUEST_QUERY_STRING = T.let(T.unsafe(nil), String)
Rack::RACK_RUNONCE = T.let(T.unsafe(nil), String)
Rack::RACK_RESPONSE_FINISHED = T.let(T.unsafe(nil), String)
Rack::RACK_SESSION = T.let(T.unsafe(nil), String)
Rack::RACK_SESSION_OPTIONS = T.let(T.unsafe(nil), String)
Rack::RACK_SESSION_UNPACKED_COOKIE_DATA = T.let(T.unsafe(nil), String)
Rack::RACK_SHOWSTATUS_DETAIL = T.let(T.unsafe(nil), String)
Rack::RACK_TEMPFILES = T.let(T.unsafe(nil), String)
Rack::RACK_URL_SCHEME = T.let(T.unsafe(nil), String)
@ -941,8 +940,12 @@ class Rack::Request
def xhr?; end
class << self
def forwarded_priority; end
def forwarded_priority=(_arg0); end
def ip_filter; end
def ip_filter=(_arg0); end
def x_forwarded_proto_priority; end
def x_forwarded_proto_priority=(_arg0); end
end
end
@ -997,7 +1000,6 @@ module Rack::Request::Helpers
def logger; end
def media_type; end
def media_type_params; end
def multithread?; end
def options?; end
def params; end
def parseable_data?; end
@ -1034,8 +1036,9 @@ module Rack::Request::Helpers
def allowed_scheme(header); end
def default_session; end
def extract_proto_header(header); end
def forwarded_priority; end
def forwarded_scheme; end
def get_http_forwarded(token); end
def parse_http_accept_header(header); end
def parse_multipart; end
def parse_query(qs, d = T.unsafe(nil)); end
@ -1044,11 +1047,14 @@ module Rack::Request::Helpers
def split_authority(authority); end
def split_header(value); end
def wrap_ipv6(host); end
def x_forwarded_proto_priority; end
end
Rack::Request::Helpers::AUTHORITY = T.let(T.unsafe(nil), Regexp)
Rack::Request::Helpers::DEFAULT_PORTS = T.let(T.unsafe(nil), Hash)
Rack::Request::Helpers::FORM_DATA_MEDIA_TYPES = T.let(T.unsafe(nil), Array)
Rack::Request::Helpers::FORWARDED_SCHEME_HEADERS = T.let(T.unsafe(nil), Hash)
Rack::Request::Helpers::HTTP_FORWARDED = T.let(T.unsafe(nil), String)
Rack::Request::Helpers::HTTP_X_FORWARDED_FOR = T.let(T.unsafe(nil), String)
Rack::Request::Helpers::HTTP_X_FORWARDED_HOST = T.let(T.unsafe(nil), String)
Rack::Request::Helpers::HTTP_X_FORWARDED_PORT = T.let(T.unsafe(nil), String)
@ -1056,7 +1062,6 @@ Rack::Request::Helpers::HTTP_X_FORWARDED_PROTO = T.let(T.unsafe(nil), String)
Rack::Request::Helpers::HTTP_X_FORWARDED_SCHEME = T.let(T.unsafe(nil), String)
Rack::Request::Helpers::HTTP_X_FORWARDED_SSL = T.let(T.unsafe(nil), String)
Rack::Request::Helpers::PARSEABLE_DATA_MEDIA_TYPES = T.let(T.unsafe(nil), Array)
Rack::Request::SCHEME_WHITELIST = T.let(T.unsafe(nil), Array)
class Rack::Response
include ::Rack::Response::Helpers
@ -1064,7 +1069,7 @@ class Rack::Response
def initialize(body = T.unsafe(nil), status = T.unsafe(nil), headers = T.unsafe(nil)); end
def [](key); end
def []=(key, v); end
def []=(key, value); end
def body; end
def body=(_arg0); end
def chunked?; end
@ -1080,7 +1085,7 @@ class Rack::Response
def length; end
def length=(_arg0); end
def redirect(target, status = T.unsafe(nil)); end
def set_header(key, v); end
def set_header(key, value); end
def status; end
def status=(_arg0); end
def to_a(&block); end
@ -1095,11 +1100,11 @@ Rack::Response::CHUNKED = T.let(T.unsafe(nil), String)
module Rack::Response::Helpers
def accepted?; end
def add_header(key, v); end
def add_header(key, value); end
def bad_request?; end
def cache!(duration = T.unsafe(nil), directive: T.unsafe(nil)); end
def cache_control; end
def cache_control=(v); end
def cache_control=(value); end
def client_error?; end
def content_length; end
def content_type; end
@ -1108,7 +1113,7 @@ module Rack::Response::Helpers
def delete_cookie(key, value = T.unsafe(nil)); end
def do_not_cache!; end
def etag; end
def etag=(v); end
def etag=(value); end
def forbidden?; end
def include?(header); end
def informational?; end
@ -1120,15 +1125,17 @@ module Rack::Response::Helpers
def method_not_allowed?; end
def moved_permanently?; end
def no_content?; end
def not_acceptable?; end
def not_found?; end
def ok?; end
def precondition_failed?; end
def redirect?; end
def redirection?; end
def request_timeout?; end
def server_error?; end
def set_cookie(key, value); end
def set_cookie_header; end
def set_cookie_header=(v); end
def set_cookie_header=(value); end
def successful?; end
def unauthorized?; end
def unprocessable?; end
@ -1148,7 +1155,7 @@ class Rack::Response::Raw
def get_header(key); end
def has_header?(key); end
def headers; end
def set_header(key, v); end
def set_header(key, value); end
def status; end
def status=(_arg0); end
end
@ -1163,6 +1170,7 @@ class Rack::RewindableInput
def gets; end
def read(*args); end
def rewind; end
def size; end
private
@ -1170,6 +1178,12 @@ class Rack::RewindableInput
def make_rewindable; end
end
class Rack::RewindableInput::Middleware
def initialize(app); end
def call(env); end
end
class Rack::Runtime
def initialize(app, name = T.unsafe(nil)); end
@ -1195,238 +1209,6 @@ class Rack::Sendfile
def variation(env); end
end
class Rack::Server
def initialize(options = T.unsafe(nil)); end
def app; end
def default_options; end
def middleware; end
def options; end
def options=(_arg0); end
def server; end
def start(&block); end
private
def build_app(app); end
def build_app_and_options_from_config; end
def build_app_from_string; end
def check_pid!; end
def daemonize_app; end
def handle_profiling(heapfile, profile_mode, filename); end
def make_profile_name(filename); end
def opt_parser; end
def parse_options(args); end
def pidfile_process_status; end
def wrapped_app; end
def write_pid; end
class << self
def default_middleware_by_environment; end
def logging_middleware; end
def middleware; end
def start(options = T.unsafe(nil)); end
end
end
class Rack::Server::Options
def handler_opts(options); end
def parse!(args); end
end
module Rack::Session; end
module Rack::Session::Abstract; end
class Rack::Session::Abstract::ID < ::Rack::Session::Abstract::Persisted
def delete_session(req, sid, options); end
def find_session(req, sid); end
def write_session(req, sid, session, options); end
class << self
def inherited(klass); end
end
end
class Rack::Session::Abstract::Persisted
def initialize(app, options = T.unsafe(nil)); end
def call(env); end
def commit_session(req, res); end
def context(env, app = T.unsafe(nil)); end
def default_options; end
def key; end
def sid_secure; end
private
def commit_session?(req, session, options); end
def cookie_value(data); end
def current_session_id(req); end
def delete_session(req, sid, options); end
def extract_session_id(request); end
def find_session(env, sid); end
def force_options?(options); end
def forced_session_update?(session, options); end
def generate_sid(secure = T.unsafe(nil)); end
def initialize_sid; end
def load_session(req); end
def loaded_session?(session); end
def make_request(env); end
def prepare_session(req); end
def security_matches?(request, options); end
def session_class; end
def session_exists?(req); end
def set_cookie(request, res, cookie); end
def write_session(req, sid, session, options); end
end
Rack::Session::Abstract::Persisted::DEFAULT_OPTIONS = T.let(T.unsafe(nil), Hash)
class Rack::Session::Abstract::PersistedSecure < ::Rack::Session::Abstract::Persisted
def extract_session_id(*_arg0); end
def generate_sid(*_arg0); end
private
def cookie_value(data); end
def session_class; end
end
class Rack::Session::Abstract::PersistedSecure::SecureSessionHash < ::Rack::Session::Abstract::SessionHash
def [](key); end
end
class Rack::Session::Abstract::SessionHash
include ::Enumerable
def initialize(store, req); end
def [](key); end
def []=(key, value); end
def clear; end
def delete(key); end
def destroy; end
def dig(key, *keys); end
def each(&block); end
def empty?; end
def exists?; end
def fetch(key, default = T.unsafe(nil), &block); end
def has_key?(key); end
def id; end
def id=(_arg0); end
def include?(key); end
def inspect; end
def key?(key); end
def keys; end
def loaded?; end
def merge!(hash); end
def options; end
def replace(hash); end
def store(key, value); end
def to_hash; end
def update(hash); end
def values; end
private
def load!; end
def load_for_read!; end
def load_for_write!; end
def stringify_keys(other); end
class << self
def find(req); end
def set(req, session); end
def set_options(req, options); end
end
end
Rack::Session::Abstract::SessionHash::Unspecified = T.let(T.unsafe(nil), Object)
class Rack::Session::Cookie < ::Rack::Session::Abstract::PersistedSecure
def initialize(app, options = T.unsafe(nil)); end
def coder; end
private
def delete_session(req, session_id, options); end
def digest_match?(data, digest); end
def extract_session_id(request); end
def find_session(req, sid); end
def generate_hmac(data, secret); end
def persistent_session_id!(data, sid = T.unsafe(nil)); end
def secure?(options); end
def unpacked_cookie_data(request); end
def write_session(req, session_id, session, options); end
end
class Rack::Session::Cookie::Base64
def decode(str); end
def encode(str); end
end
class Rack::Session::Cookie::Base64::JSON < ::Rack::Session::Cookie::Base64
def decode(str); end
def encode(obj); end
end
class Rack::Session::Cookie::Base64::Marshal < ::Rack::Session::Cookie::Base64
def decode(str); end
def encode(str); end
end
class Rack::Session::Cookie::Base64::ZipJSON < ::Rack::Session::Cookie::Base64
def decode(str); end
def encode(obj); end
end
class Rack::Session::Cookie::Identity
def decode(str); end
def encode(str); end
end
class Rack::Session::Cookie::SessionId
def initialize(session_id, cookie_value); end
def cookie_value; end
end
class Rack::Session::Pool < ::Rack::Session::Abstract::PersistedSecure
def initialize(app, options = T.unsafe(nil)); end
def delete_session(req, session_id, options); end
def find_session(req, sid); end
def generate_sid; end
def mutex; end
def pool; end
def with_lock(req); end
def write_session(req, session_id, new_session, options); end
private
def get_session_with_fallback(sid); end
end
Rack::Session::Pool::DEFAULT_OPTIONS = T.let(T.unsafe(nil), Hash)
class Rack::Session::SessionId
def initialize(public_id); end
def cookie_value; end
def empty?; end
def inspect; end
def private_id; end
def public_id; end
def to_s; end
private
def hash_sid(sid); end
end
Rack::Session::SessionId::ID_VERSION = T.let(T.unsafe(nil), Integer)
class Rack::ShowExceptions
def initialize(app); end
@ -1498,22 +1280,25 @@ module Rack::Utils
def byte_ranges(env, size); end
def clean_path_info(path_info); end
def clock_time; end
def delete_cookie_header!(header, key, value = T.unsafe(nil)); end
def delete_cookie_header!(headers, key, value = T.unsafe(nil)); end
def delete_set_cookie_header(key, value = T.unsafe(nil)); end
def delete_set_cookie_header!(header, key, value = T.unsafe(nil)); end
def escape(s); end
def escape_html(string); end
def escape_path(s); end
def forwarded_values(forwarded_header); end
def get_byte_ranges(http_range, size); end
def make_delete_cookie_header(header, key, value); end
def parse_cookies(env); end
def parse_cookies_header(header); end
def parse_cookies_header(value); end
def parse_nested_query(qs, d = T.unsafe(nil)); end
def parse_query(qs, d = T.unsafe(nil), &unescaper); end
def q_values(q_value_header); end
def rfc2109(time); end
def rfc2822(time); end
def secure_compare(a, b); end
def select_best_encoding(available_encodings, accept_encoding); end
def set_cookie_header!(header, key, value); end
def set_cookie_header(key, value); end
def set_cookie_header!(headers, key, value); end
def status_code(status); end
def unescape(s, encoding = T.unsafe(nil)); end
def unescape_path(s); end
@ -1530,10 +1315,13 @@ module Rack::Utils
def clock_time; end
def default_query_parser; end
def default_query_parser=(_arg0); end
def delete_cookie_header!(header, key, value = T.unsafe(nil)); end
def delete_cookie_header!(headers, key, value = T.unsafe(nil)); end
def delete_set_cookie_header(key, value = T.unsafe(nil)); end
def delete_set_cookie_header!(header, key, value = T.unsafe(nil)); end
def escape(s); end
def escape_html(string); end
def escape_path(s); end
def forwarded_values(forwarded_header); end
def get_byte_ranges(http_range, size); end
def key_space_limit; end
def key_space_limit=(v); end
@ -1543,15 +1331,15 @@ module Rack::Utils
def param_depth_limit; end
def param_depth_limit=(v); end
def parse_cookies(env); end
def parse_cookies_header(header); end
def parse_cookies_header(value); end
def parse_nested_query(qs, d = T.unsafe(nil)); end
def parse_query(qs, d = T.unsafe(nil), &unescaper); end
def q_values(q_value_header); end
def rfc2109(time); end
def rfc2822(time); end
def secure_compare(a, b); end
def select_best_encoding(available_encodings, accept_encoding); end
def set_cookie_header!(header, key, value); end
def set_cookie_header(key, value); end
def set_cookie_header!(headers, key, value); end
def status_code(status); end
def unescape(s, encoding = T.unsafe(nil)); end
def unescape_path(s); end
@ -1577,32 +1365,10 @@ Rack::Utils::ESCAPE_HTML_PATTERN = T.let(T.unsafe(nil), Regexp)
Rack::Utils::HTTP_STATUS_CODES = T.let(T.unsafe(nil), Hash)
class Rack::Utils::HeaderHash < ::Hash
def initialize(hash = T.unsafe(nil)); end
def [](k); end
def []=(k, v); end
def clear; end
def delete(k); end
def each; end
def has_key?(k); end
def include?(k); end
def key?(k); end
def member?(k); end
def merge(other); end
def merge!(other); end
def replace(other); end
def to_hash; end
protected
def names; end
private
def initialize_copy(other); end
class << self
def [](headers); end
def allocate; end
def new(hash = T.unsafe(nil)); end
end
end
@ -1611,14 +1377,8 @@ Rack::Utils::KeySpaceConstrainedParams = Rack::QueryParser::Params
Rack::Utils::NULL_BYTE = T.let(T.unsafe(nil), String)
Rack::Utils::PATH_SEPS = T.let(T.unsafe(nil), Regexp)
Rack::Utils::ParameterTypeError = Rack::QueryParser::ParameterTypeError
Rack::Utils::RFC2822_DAY_NAME = T.let(T.unsafe(nil), Array)
Rack::Utils::RFC2822_MONTH_NAME = T.let(T.unsafe(nil), Array)
Rack::Utils::ParamsTooDeepError = Rack::QueryParser::ParamsTooDeepError
Rack::Utils::STATUS_WITH_NO_ENTITY_BODY = T.let(T.unsafe(nil), Hash)
Rack::Utils::SYMBOL_TO_STATUS_CODE = T.let(T.unsafe(nil), Hash)
Rack::VERSION = T.let(T.unsafe(nil), Array)
class WEBrick::HTTPResponse
def rack; end
def rack=(_arg0); end
def setup_header; end
end
Rack::VERSION_STRING = T.let(T.unsafe(nil), String)

View File

@ -875,6 +875,7 @@ class RSpec::Matchers::BuiltIn::ContainExactly < ::RSpec::Matchers::BuiltIn::Bas
def description; end
def failure_message; end
def failure_message_when_negated; end
def matches?(actual); end
private

Some files were not shown because too many files have changed in this diff Show More