Merge remote-tracking branch 'origin/master' into cask-move-contents

This commit is contained in:
JBYoshi 2023-04-15 21:37:56 -05:00
commit 2e85f2beb2
No known key found for this signature in database
GPG Key ID: AE4430116622D05D
449 changed files with 4269 additions and 2010 deletions

17
.github/actionlint-matcher.json vendored Normal file
View File

@ -0,0 +1,17 @@
{
"problemMatcher": [
{
"owner": "actionlint",
"pattern": [
{
"regexp": "^(?:\\x1b\\[\\d+m)?(.+?)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*: (?:\\x1b\\[\\d+m)*(.+?)(?:\\x1b\\[\\d+m)* \\[(.+?)\\]$",
"file": 1,
"line": 2,
"column": 3,
"message": 4,
"code": 5
}
]
}
]
}

8
.github/actionlint.yaml vendored Normal file
View File

@ -0,0 +1,8 @@
self-hosted-runner:
# Labels of self-hosted runner in array of strings.
labels:
- 11-arm64
# Configuration variables in array of strings defined in your repository or
# organization. `null` means disabling configuration variables check.
# Empty array means no configuration variable is allowed.
config-variables: []

47
.github/workflows/actionlint.yml vendored Normal file
View File

@ -0,0 +1,47 @@
name: actionlint
on:
push:
branches:
- master
paths:
- '.github/workflows/*.ya?ml'
pull_request:
paths:
- '.github/workflows/*.ya?ml'
merge_group:
env:
HOMEBREW_DEVELOPER: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_ENV_HINTS: 1
concurrency:
group: "actionlint-${{ github.ref }}"
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
workflow_syntax:
if: github.repository_owner == 'Homebrew'
runs-on: ubuntu-22.04
steps:
- name: Set up Homebrew
id: setup-homebrew
uses: Homebrew/actions/setup-homebrew@master
with:
test-bot: false
- name: Set up actionlint
env:
HOMEBREW_REPOSITORY: ${{ steps.setup-homebrew.outputs.repository-path }}
run: |
brew install actionlint shellcheck
# Annotations work only relative to GITHUB_WORKSPACE
(shopt -s dotglob; rm -rf "${GITHUB_WORKSPACE:?}"/*; mv "${HOMEBREW_REPOSITORY:?}"/* "$GITHUB_WORKSPACE")
rmdir "$HOMEBREW_REPOSITORY"
ln -vs "$GITHUB_WORKSPACE" "$HOMEBREW_REPOSITORY"
echo "::add-matcher::.github/actionlint-matcher.json"
- run: actionlint

View File

@ -23,7 +23,7 @@ jobs:
- name: Version name
id: print-version
run: |
echo "version=$(git -C brew describe --tags --always)" > $GITHUB_OUTPUT
echo "version=$(git -C brew describe --tags --always)" >> "$GITHUB_OUTPUT"
- name: Build package
run: |
pkgbuild --root brew \

View File

@ -64,4 +64,4 @@ jobs:
- name: Process rubydoc comments
working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }}/Library/Homebrew
run: bundle exec yard doc --plugin sorbet --no-output --fail-on-warning
run: bundle exec yard doc --no-output --fail-on-warning

View File

@ -17,13 +17,14 @@ jobs:
tests:
strategy:
matrix:
runner:
- "13-arm64-${{github.run_id}}-${{github.run_attempt}}"
- "12-arm64"
- "12-${{github.run_id}}-${{github.run_attempt}}"
- "11-arm64"
- "11-${{github.run_id}}-${{github.run_attempt}}"
- "10.15-${{github.run_id}}-${{github.run_attempt}}"
include:
- runner: "13-arm64-${{github.run_id}}-${{github.run_attempt}}"
- runner: "12-arm64-${{github.run_id}}-${{github.run_attempt}}"
- runner: "12-${{github.run_id}}-${{github.run_attempt}}"
- runner: "11-arm64"
cleanup: true
- runner: "11-${{github.run_id}}-${{github.run_attempt}}"
- runner: "10.15-${{github.run_id}}-${{github.run_attempt}}"
fail-fast: false
runs-on: ${{ matrix.runner }}
env:
@ -37,9 +38,9 @@ jobs:
uses: Homebrew/actions/setup-homebrew@master
- run: brew test-bot --only-cleanup-before
if: !contains(matrix.runner, github.run_id)
if: matrix.cleanup
- run: brew doctor
- run: brew test-bot --only-cleanup-after
if: always() && !contains(matrix.runner, github.run_id)
if: always() && matrix.cleanup

View File

@ -1,6 +1,11 @@
name: Update Sorbet files
on:
pull_request:
paths:
- Library/Homebrew/dev-cmd/typecheck.rb
- Library/Homebrew/sorbet/**
- "!Library/Homebrew/sorbet/rbi/**"
push:
paths:
- .github/workflows/sorbet.yml
@ -23,26 +28,25 @@ jobs:
uses: Homebrew/actions/setup-homebrew@master
- name: Configure Git user
if: github.event_name != 'pull_request'
uses: Homebrew/actions/git-user-config@master
with:
username: BrewTestBot
- name: Set up commit signing
if: github.event_name != 'pull_request'
uses: Homebrew/actions/setup-commit-signing@master
with:
signing_key: ${{ secrets.BREWTESTBOT_GPG_SIGNING_SUBKEY }}
- name: Update RBI files
id: update
env:
GITHUB_TOKEN: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
HOMEBREW_GPG_PASSPHRASE: ${{ secrets.BREWTESTBOT_GPG_SIGNING_SUBKEY_PASSPHRASE }}
working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
run: |
git fetch origin
BRANCH="sorbet-files-update"
echo "branch=${BRANCH}" >> $GITHUB_OUTPUT
echo "branch=${BRANCH}" >> "$GITHUB_OUTPUT"
if git ls-remote --exit-code --heads origin "${BRANCH}"
then
@ -53,6 +57,15 @@ jobs:
fi
brew typecheck --update --suggest-typed
- name: Commit changes
id: commit
if: github.event_name != 'pull_request'
env:
GITHUB_TOKEN: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
HOMEBREW_GPG_PASSPHRASE: ${{ secrets.BREWTESTBOT_GPG_SIGNING_SUBKEY_PASSPHRASE }}
working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
run: |
if ! git diff --stat --exit-code "Library/Homebrew/sorbet"
then
git add "Library/Homebrew/sorbet"
@ -66,16 +79,16 @@ jobs:
-m "Autogenerated by the [sorbet](https://github.com/Homebrew/brew/blob/master/.github/workflows/sorbet.yml) workflow."
fi
echo "committed=true" >> $GITHUB_OUTPUT
echo "committed=true" >> "$GITHUB_OUTPUT"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state")"
if [[ "${PULL_REQUEST_STATE}" != "OPEN" ]]
then
echo "pull_request=true" >> $GITHUB_OUTPUT
echo "pull_request=true" >> "$GITHUB_OUTPUT"
fi
fi
- name: Push commits
if: steps.update.outputs.committed == 'true'
if: steps.commit.outputs.committed == 'true'
uses: Homebrew/actions/git-try-push@master
with:
token: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
@ -85,7 +98,7 @@ jobs:
origin_branch: "master"
- name: Open a pull request
if: steps.update.outputs.pull_request == 'true'
if: steps.commit.outputs.pull_request == 'true'
run: hub pull-request --no-edit
env:
GITHUB_TOKEN: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}

View File

@ -41,7 +41,7 @@ jobs:
git fetch origin
BRANCH="spdx-update"
echo "branch=${BRANCH}" >> $GITHUB_OUTPUT
echo "branch=${BRANCH}" >> "$GITHUB_OUTPUT"
if git ls-remote --exit-code --heads origin "${BRANCH}"
then
@ -55,11 +55,11 @@ jobs:
then
git add "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)."
echo "committed=true" >> $GITHUB_OUTPUT
echo "committed=true" >> "$GITHUB_OUTPUT"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state")"
if [[ "${PULL_REQUEST_STATE}" != "OPEN" ]]
then
echo "pull_request=true" >> $GITHUB_OUTPUT
echo "pull_request=true" >> "$GITHUB_OUTPUT"
fi
fi

View File

@ -56,7 +56,7 @@ jobs:
else
BRANCH=sponsors-maintainers-man-completions
fi
echo "branch=${BRANCH}" >> $GITHUB_OUTPUT
echo "branch=${BRANCH}" >> "$GITHUB_OUTPUT"
if git ls-remote --exit-code --heads origin "${BRANCH}"
then
@ -100,11 +100,11 @@ jobs:
if [[ -n "$COMMITTED" ]]
then
echo "committed=true" >> $GITHUB_OUTPUT
echo "committed=true" >> "$GITHUB_OUTPUT"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state")"
if [[ "${PULL_REQUEST_STATE}" != "OPEN" ]]
then
echo "pull_request=true" >> $GITHUB_OUTPUT
echo "pull_request=true" >> "$GITHUB_OUTPUT"
fi
fi
env:
@ -121,7 +121,6 @@ jobs:
directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
branch: ${{ steps.update.outputs.branch }}
force: true
origin_branch: "master"
- name: Open a pull request
if: steps.update.outputs.pull_request == 'true'

View File

@ -43,7 +43,7 @@ jobs:
- name: Install shellcheck and shfmt
run: brew install shellcheck shfmt
- run: brew style --display-cop-names
- run: brew style
- run: brew typecheck
@ -83,7 +83,7 @@ jobs:
run: brew install-bundler-gems --groups=all
- name: Run brew style on homebrew-core
run: brew style --display-cop-names homebrew/core
run: brew style homebrew/core
- name: Set up all Homebrew taps
run: |
@ -105,22 +105,22 @@ jobs:
- name: Run brew style on official taps
run: |
brew style --display-cop-names homebrew/bundle \
homebrew/services \
homebrew/test-bot
brew style homebrew/bundle \
homebrew/services \
homebrew/test-bot
brew style --display-cop-names homebrew/aliases\
homebrew/autoupdate\
homebrew/command-not-found \
homebrew/formula-analytics \
homebrew/portable-ruby
brew style homebrew/aliases \
homebrew/autoupdate\
homebrew/command-not-found \
homebrew/formula-analytics \
homebrew/portable-ruby
- name: Run brew style on cask taps
run: |
brew style --display-cop-names homebrew/cask \
homebrew/cask-drivers \
homebrew/cask-fonts \
homebrew/cask-versions
brew style homebrew/cask \
homebrew/cask-drivers \
homebrew/cask-fonts \
homebrew/cask-versions
formula-audit:
name: formula audit
@ -151,7 +151,7 @@ jobs:
run: brew readall --aliases homebrew/core
- name: Run brew audit --skip-style on homebrew/core
run: brew audit --skip-style --except=version --display-failures-only --tap=homebrew/core
run: brew audit --skip-style --except=version --tap=homebrew/core
cask-audit:
name: cask audit
@ -187,10 +187,10 @@ jobs:
- name: Run brew audit --skip-style on casks
run: |
brew audit --skip-style --except=version --display-failures-only --tap=homebrew/cask
brew audit --skip-style --except=version --display-failures-only --tap=homebrew/cask-drivers
brew audit --skip-style --except=version --display-failures-only --tap=homebrew/cask-fonts
brew audit --skip-style --except=version --display-failures-only --tap=homebrew/cask-versions
brew audit --skip-style --except=version --tap=homebrew/cask
brew audit --skip-style --except=version --tap=homebrew/cask-drivers
brew audit --skip-style --except=version --tap=homebrew/cask-fonts
brew audit --skip-style --except=version --tap=homebrew/cask-versions
vendored-gems:
name: vendored gems
@ -373,7 +373,7 @@ jobs:
HOMEBREW_BUILDPULSE_ACCOUNT_ID: 1503512
HOMEBREW_BUILDPULSE_REPOSITORY_ID: 53238813
- uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70
- uses: codecov/codecov-action@40a12dcee2df644d47232dde008099a3e9e4f865
with:
directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
files: Library/Homebrew/test/coverage/coverage.xml

View File

@ -1,6 +1,15 @@
name: Vendor Gems
on:
pull_request:
paths:
- Library/Homebrew/dev-cmd/vendor-gems.rb
- Library/Homebrew/Gemfile*
push:
paths:
- .github/workflows/vendor-gems.yml
branches-ignore:
- master
pull_request_target:
workflow_dispatch:
inputs:
@ -15,8 +24,10 @@ permissions:
jobs:
vendor-gems:
if: >
startsWith(github.repository, 'Homebrew/') && (
github.event_name == 'workflow_dispatch' || (
github.repository_owner == 'Homebrew' && (
github.event_name == 'workflow_dispatch' ||
github.event_name == 'pull_request' ||
github.event_name == 'push' || (
github.event.pull_request.user.login == 'dependabot[bot]' &&
contains(github.event.pull_request.title, '/Library/Homebrew')
)
@ -28,25 +39,28 @@ jobs:
uses: Homebrew/actions/setup-homebrew@master
- name: Configure Git user
if: github.event_name == 'pull_request_target' || github.event_name == 'workflow_dispatch'
uses: Homebrew/actions/git-user-config@master
with:
username: BrewTestBot
- name: Set up commit signing
if: github.event_name == 'pull_request_target' || github.event_name == 'workflow_dispatch'
uses: Homebrew/actions/setup-commit-signing@master
with:
signing_key: ${{ secrets.BREWTESTBOT_GPG_SIGNING_SUBKEY }}
- name: Check out pull request
id: checkout
if: github.event_name == 'pull_request_target' || github.event_name == 'workflow_dispatch'
run: |
gh pr checkout '${{ github.event.pull_request.number || github.event.inputs.pull_request }}'
branch="$(git branch --show-current)"
echo "branch=${branch}" >> $GITHUB_OUTPUT
echo "branch=${branch}" >> "$GITHUB_OUTPUT"
gem_name="$(echo "${branch}" | sed -E 's|.*/||;s|(.*)-.*$|\1|')"
echo "gem_name=${gem_name}" >> $GITHUB_OUTPUT
echo "gem_name=${gem_name}" >> "$GITHUB_OUTPUT"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
@ -54,15 +68,24 @@ jobs:
- name: Vendor Gems
env:
HOMEBREW_GPG_PASSPHRASE: ${{ secrets.BREWTESTBOT_GPG_SIGNING_SUBKEY_PASSPHRASE }}
run: brew vendor-gems
run: |
if [[ "${GITHUB_EVENT_NAME}" == "pull_request_target" || "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]
then
brew vendor-gems
else
brew vendor-gems --no-commit
fi
- name: Update RBI files
run: brew typecheck --update
- name: Commit RBI changes
if: github.event_name == 'pull_request_target' || github.event_name == 'workflow_dispatch'
env:
GEM_NAME: ${{ steps.checkout.outputs.gem_name }}
HOMEBREW_GPG_PASSPHRASE: ${{ secrets.BREWTESTBOT_GPG_SIGNING_SUBKEY_PASSPHRASE }}
working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
run: |
brew typecheck --update
if ! git diff --stat --exit-code "Library/Homebrew/sorbet"
then
git add "Library/Homebrew/sorbet"
@ -71,6 +94,7 @@ jobs:
fi
- name: Push to pull request
if: github.event_name == 'pull_request_target' || github.event_name == 'workflow_dispatch'
uses: Homebrew/actions/git-try-push@master
with:
token: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}

View File

@ -13,7 +13,6 @@ inherit_mode:
AllCops:
TargetRubyVersion: 2.6
DisplayCopNames: false
ActiveSupportExtensionsEnabled: true
NewCops: enable
Include:

View File

@ -2,6 +2,7 @@
--main README.md
--markup markdown
--no-private
--plugin sorbet
--load yard/ignore_directives.rb
--template-path yard/templates
--exclude test/

View File

@ -7,7 +7,7 @@ GEM
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.1)
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
ast (2.4.2)
bindata (2.4.15)
@ -41,7 +41,7 @@ GEM
hana (~> 1.3)
regexp_parser (~> 2.0)
uri_template (~> 0.7)
mechanize (2.8.5)
mechanize (2.9.0)
addressable (~> 2.8)
domain_name (~> 0.5, >= 0.5.20190701)
http-cookie (~> 1.0, >= 1.0.3)
@ -82,7 +82,7 @@ GEM
parser
rainbow (~> 3.0)
sorbet-runtime (>= 0.5)
parser (3.2.1.1)
parser (3.2.2.0)
ast (~> 2.4.1)
patchelf (1.4.0)
elftools (>= 1.2)
@ -130,24 +130,24 @@ GEM
rspec-support (3.12.0)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.48.1)
rubocop (1.50.1)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.2.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.26.0, < 2.0)
rubocop-ast (>= 1.28.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.28.0)
parser (>= 3.2.1.0)
rubocop-capybara (2.17.1)
rubocop (~> 1.41)
rubocop-performance (1.16.0)
rubocop-performance (1.17.1)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.18.0)
rubocop-rails (2.19.0)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
@ -189,7 +189,7 @@ GEM
sorbet (>= 0.5.9204)
sorbet-runtime (>= 0.5.9204)
thor (>= 0.19.2)
stackprof (0.2.24)
stackprof (0.2.25)
tapioca (0.7.3)
bundler (>= 1.17.3)
pry (>= 0.12.2)
@ -213,7 +213,7 @@ GEM
warning (1.3.0)
webrick (1.8.1)
webrobots (0.1.2)
yard (0.9.26)
yard (0.9.34)
yard-sorbet (0.6.1)
sorbet-runtime (>= 0.5)
yard (>= 0.9)
@ -266,7 +266,7 @@ DEPENDENCIES
warning
RUBY VERSION
ruby 2.6.8p205
ruby 2.6.10p210
BUNDLED WITH
2.3.26

View File

@ -116,11 +116,13 @@ module Homebrew
end
end
sig { params(name: String, git_head: T.nilable(String), sha256: T.nilable(String)).returns(String) }
def self.fetch_homebrew_cask_source(name, git_head: nil, sha256: nil)
sig {
params(name: String, path: T.any(Pathname, String), git_head: String,
sha256: T.nilable(String)).returns(String)
}
def self.fetch_homebrew_cask_source(name, path:, git_head:, sha256: nil)
# TODO: unify with formula logic (https://github.com/Homebrew/brew/issues/14746)
git_head = "master" if git_head.blank?
raw_endpoint = "#{git_head}/Casks/#{name}.rb"
raw_endpoint = "#{git_head}/#{path}"
return cache[raw_endpoint] if cache.present? && cache.key?(raw_endpoint)
# This API sometimes returns random 404s so needs a fallback at formulae.brew.sh.

View File

@ -20,9 +20,12 @@ module Homebrew
Homebrew::API.fetch "cask/#{token}.json"
end
sig { params(token: String, git_head: T.nilable(String), sha256: T.nilable(String)).returns(String) }
def fetch_source(token, git_head: nil, sha256: nil)
Homebrew::API.fetch_homebrew_cask_source token, git_head: git_head, sha256: sha256
sig {
params(token: String, path: T.any(String, Pathname), git_head: String,
sha256: T.nilable(String)).returns(String)
}
def fetch_source(token, path:, git_head:, sha256: nil)
Homebrew::API.fetch_homebrew_cask_source token, path: path, git_head: git_head, sha256: sha256
end
sig { returns(T::Boolean) }

View File

@ -540,7 +540,7 @@ then
# Set a variable when the macOS system Ruby is new enough to avoid spawning
# a Ruby process unnecessarily.
if [[ "${HOMEBREW_MACOS_VERSION_NUMERIC}" -lt "120000" ]]
if [[ "${HOMEBREW_MACOS_VERSION_NUMERIC}" -lt "120601" ]]
then
unset HOMEBREW_MACOS_SYSTEM_RUBY_NEW_ENOUGH
else

View File

@ -82,6 +82,7 @@ module Cask
Service,
InputMethod,
InternetPlugin,
KeyboardLayout,
AudioUnitPlugin,
VstPlugin,
Vst3Plugin,

View File

@ -11,11 +11,6 @@ module Cask
class KeyboardLayout < Moved
extend T::Sig
sig { returns(String) }
def self.english_name
"Keyboard Layout"
end
def install_phase(**options)
super(**options)
delete_keyboard_layout_cache(**options)

View File

@ -56,7 +56,7 @@ module Cask
message = "It seems there is already #{self.class.english_article} " \
"#{self.class.english_name} at '#{target}'"
if force && target.symlink? && \
if force && target.symlink? &&
(target.realpath == source.realpath || target.realpath.to_s.start_with?("#{cask.caskroom_path}/"))
opoo "#{message}; overwriting."
target.delete

View File

@ -9,6 +9,12 @@ module Cask
#
# @api private
class Vst3Plugin < Moved
extend T::Sig
sig { returns(String) }
def self.english_name
"VST3 Plugin"
end
end
end
end

View File

@ -9,6 +9,12 @@ module Cask
#
# @api private
class VstPlugin < Moved
extend T::Sig
sig { returns(String) }
def self.english_name
"VST Plugin"
end
end
end
end

View File

@ -71,53 +71,31 @@ module Cask
@errors ||= []
end
def warnings
@warnings ||= []
end
sig { returns(T::Boolean) }
def errors?
errors.any?
end
sig { returns(T::Boolean) }
def warnings?
warnings.any?
end
sig { returns(T::Boolean) }
def success?
!(errors? || warnings?)
!errors?
end
sig { params(message: T.nilable(String), location: T.nilable(String)).void }
def add_error(message, location: nil)
sig { params(message: T.nilable(String), location: T.nilable(String), strict_only: T::Boolean).void }
def add_error(message, location: nil, strict_only: false)
# Only raise non-critical audits if the user specified `--strict`.
return if strict_only && !@strict
errors << ({ message: message, location: location })
end
sig { params(message: T.nilable(String), location: T.nilable(String)).void }
def add_warning(message, location: nil)
if strict?
add_error message, location: location
else
warnings << ({ message: message, location: location })
end
end
def result
if errors?
Formatter.error("failed")
elsif warnings?
Formatter.warning("warning")
else
Formatter.success("passed")
end
Formatter.error("failed") if errors?
end
sig { params(include_passed: T::Boolean, include_warnings: T::Boolean).returns(T.nilable(String)) }
def summary(include_passed: false, include_warnings: true)
return if success? && !include_passed
return if warnings? && !errors? && !include_warnings
sig { returns(T.nilable(String)) }
def summary
return if success?
summary = ["audit for #{cask}: #{result}"]
@ -125,12 +103,6 @@ module Cask
summary << " #{Formatter.error("-")} #{error[:message]}"
end
if include_warnings
warnings.each do |warning|
summary << " #{Formatter.warning("-")} #{warning[:message]}"
end
end
summary.join("\n")
end
@ -220,7 +192,7 @@ module Cask
# increases the maintenance burden.
return if cask.tap == "homebrew/cask-fonts"
add_warning "Cask should have a description. Please add a `desc` stanza." if cask.desc.blank?
add_error("Cask should have a description. Please add a `desc` stanza.", strict_only: true) if cask.desc.blank?
end
sig { void }
@ -408,8 +380,10 @@ module Cask
return unless token_conflicts?
return unless core_formula_names.include?(cask.token)
add_warning "possible duplicate, cask token conflicts with Homebrew core formula: " \
"#{Formatter.url(core_formula_url)}"
add_error(
"possible duplicate, cask token conflicts with Homebrew core formula: #{Formatter.url(core_formula_url)}",
strict_only: true,
)
end
sig { void }
@ -443,18 +417,19 @@ module Cask
add_error "cask token contains version designation '#{match_data[:designation]}'"
end
add_warning "cask token mentions launcher" if token.end_with? "launcher"
add_error("cask token mentions launcher", strict_only: true) if token.end_with? "launcher"
add_warning "cask token mentions desktop" if token.end_with? "desktop"
add_error("cask token mentions desktop", strict_only: true) if token.end_with? "desktop"
add_warning "cask token mentions platform" if token.end_with? "mac", "osx", "macos"
add_error("cask token mentions platform", strict_only: true) if token.end_with? "mac", "osx", "macos"
add_warning "cask token mentions architecture" if token.end_with? "x86", "32_bit", "x86_64", "64_bit"
add_error("cask token mentions architecture", strict_only: true) if token.end_with? "x86", "32_bit", "x86_64",
"64_bit"
frameworks = %w[cocoa qt gtk wx java]
return if frameworks.include?(token) || !token.end_with?(*frameworks)
add_warning "cask token mentions framework"
add_error("cask token mentions framework", strict_only: true)
end
sig { void }
@ -474,7 +449,10 @@ module Cask
return if cask.url.to_s.include? cask.version.csv.second
return if cask.version.csv.third.present? && cask.url.to_s.include?(cask.version.csv.third)
add_warning "Download does not require additional version components. Use `&:short_version` in the livecheck"
add_error(
"Download does not require additional version components. Use `&:short_version` in the livecheck",
strict_only: true,
)
end
sig { void }
@ -496,55 +474,21 @@ module Cask
primary_container.extract_nestedly(to: tmpdir, basename: downloaded_path.basename, verbose: false)
artifacts.each do |artifact|
case artifact
when Artifact::Moved
path = tmpdir/artifact.source.basename
next unless path.exist?
artifact_path = artifact.is_a?(Artifact::Pkg) ? artifact.path : artifact.source
path = tmpdir/artifact_path.relative_path_from(cask.staged_path)
result = system_command("codesign", args: ["--verify", path], print_stderr: false)
next unless path.exist?
next if result.success?
result = system_command("spctl", args: ["--assess", "--type", "install", path], print_stderr: false)
message = <<~EOS
Signature verification failed:
#{result.merged_output}
macOS on ARM requires applications to be signed.
Please contact the upstream developer to let them know they should
EOS
next if result.success?
message = if result.stderr.include?("not signed at all")
"#{message} sign their app."
else
"#{message} fix the signature of their app."
end
add_warning message
when Artifact::Pkg
path = downloaded_path
next unless path.exist?
result = system_command("pkgutil", args: ["--check-signature", path], print_stderr: false)
unless result.success?
add_warning <<~EOS
Signature verification failed:
#{result.merged_output}
macOS on ARM requires applications to be signed.
Please contact the upstream developer to let them know they should sign their package.
EOS
next
end
result = system_command("stapler", args: ["validate", path], print_stderr: false)
next if result.success?
add_warning <<~EOS
Signature verification failed:
#{result.merged_output}
macOS on ARM requires applications to be signed.
Please contact the upstream developer to let them know they should notarize their package.
EOS
end
add_error(<<~EOS, strict_only: true)
Signature verification failed:
#{result.merged_output}
macOS on ARM requires software to be signed.
Please contact the upstream developer to let them know they should sign and notarize their software.
EOS
end
end
end
@ -656,6 +600,9 @@ module Cask
sig { void }
def audit_github_repository_archived
# Discontinued casks may have an archived repo.
return if cask.discontinued?
user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if online?
return if user.nil?
@ -664,19 +611,14 @@ module Cask
metadata = SharedAudits.github_repo_data(user, repo)
return if metadata.nil?
return unless metadata["archived"]
message = "GitHub repo is archived"
if cask.discontinued?
add_warning message
else
add_error message
end
add_error "GitHub repo is archived" if metadata["archived"]
end
sig { void }
def audit_gitlab_repository_archived
# Discontinued casks may have an archived repo.
return if cask.discontinued?
user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*}) if online?
return if user.nil?
@ -685,15 +627,7 @@ module Cask
metadata = SharedAudits.gitlab_repo_data(user, repo)
return if metadata.nil?
return unless metadata["archived"]
message = "GitLab repo is archived"
if cask.discontinued?
add_warning message
else
add_error message
end
add_error "GitLab repo is archived" if metadata["archived"]
end
sig { void }

View File

@ -25,8 +25,6 @@ module Cask
quarantine: nil,
any_named_args: nil,
language: nil,
display_passes: nil,
display_failures_only: nil,
only: [],
except: []
)
@ -40,8 +38,6 @@ module Cask
@audit_token_conflicts = audit_token_conflicts
@any_named_args = any_named_args
@language = language
@display_passes = display_passes
@display_failures_only = display_failures_only
@only = only
@except = except
end
@ -49,7 +45,6 @@ module Cask
LANGUAGE_BLOCK_LIMIT = 10
def audit
warnings = Set.new
errors = Set.new
if !language && language_blocks
@ -63,23 +58,19 @@ module Cask
sample_languages.each_key do |l|
audit = audit_languages(l)
summary = audit.summary(include_passed: output_passed?, include_warnings: output_warnings?)
if summary.present? && output_summary?(audit)
if audit.summary.present? && output_summary?(audit)
ohai "Auditing language: #{l.map { |lang| "'#{lang}'" }.to_sentence}" if output_summary?
puts summary
puts audit.summary
end
warnings += audit.warnings
errors += audit.errors
end
else
audit = audit_cask_instance(cask)
summary = audit.summary(include_passed: output_passed?, include_warnings: output_warnings?)
puts summary if summary.present? && output_summary?(audit)
warnings += audit.warnings
puts audit.summary if audit.summary.present? && output_summary?(audit)
errors += audit.errors
end
{ warnings: warnings, errors: errors }
errors
end
private
@ -92,19 +83,6 @@ module Cask
audit.errors?
end
def output_passed?
return false if @display_failures_only.present?
return true if @display_passes.present?
false
end
def output_warnings?
return false if @display_failures_only.present?
true
end
def audit_languages(languages)
original_config = cask.config
localized_config = original_config.merge(Config.new(explicit: { languages: languages }))

View File

@ -241,6 +241,15 @@ module Cask
end
end
def ruby_source_path
return @ruby_source_path if defined?(@ruby_source_path)
return unless sourcefile_path
return unless tap
@ruby_source_path = sourcefile_path.relative_path_from(tap.path)
end
def ruby_source_checksum
@ruby_source_checksum ||= {
"sha256" => Digest::SHA256.file(sourcefile_path).hexdigest,
@ -259,7 +268,9 @@ module Cask
raise ArgumentError, "Expected cask to be loaded from the API" unless loaded_from_api?
@languages = json_cask[:languages]
@tap_git_head = json_cask[:tap_git_head]
@tap_git_head = json_cask.fetch(:tap_git_head, "HEAD")
@ruby_source_path = json_cask[:ruby_source_path]
@ruby_source_checksum = json_cask[:ruby_source_checksum].freeze
end
@ -308,6 +319,7 @@ module Cask
"auto_updates" => auto_updates,
"tap_git_head" => tap_git_head,
"languages" => languages,
"ruby_source_path" => ruby_source_path,
"ruby_source_checksum" => ruby_source_checksum,
}
end

View File

@ -12,7 +12,6 @@ require "cask/config"
require "cask/cmd/abstract_command"
require "cask/cmd/audit"
require "cask/cmd/install"
require "cask/cmd/reinstall"
module Cask
# Implementation of the `brew cask` command-line interface.

View File

@ -30,8 +30,6 @@ module Cask
description: "Run various additional style checks to determine if a new cask is eligible " \
"for Homebrew. This should be used when creating new casks and implies " \
"`--strict` and `--online`"
switch "--display-failures-only",
description: "Only display casks that fail the audit. This is the default for formulae."
end
end
@ -49,19 +47,17 @@ module Cask
results = self.class.audit_casks(
*casks,
download: args.download?,
online: args.online?,
strict: args.strict?,
signing: args.signing?,
new_cask: args.new_cask?,
token_conflicts: args.token_conflicts?,
quarantine: args.quarantine?,
any_named_args: any_named_args,
language: args.language,
display_passes: args.verbose? || args.named.count == 1,
display_failures_only: args.display_failures_only?,
only: [],
except: [],
download: args.download?,
online: args.online?,
strict: args.strict?,
signing: args.signing?,
new_cask: args.new_cask?,
token_conflicts: args.token_conflicts?,
quarantine: args.quarantine?,
any_named_args: any_named_args,
language: args.language,
only: [],
except: [],
)
failed_casks = results.reject { |_, result| result[:errors].empty? }.map(&:first)
@ -81,8 +77,6 @@ module Cask
quarantine:,
any_named_args:,
language:,
display_passes:,
display_failures_only:,
only:,
except:
)
@ -96,8 +90,6 @@ module Cask
quarantine: quarantine,
language: language,
any_named_args: any_named_args,
display_passes: display_passes,
display_failures_only: display_failures_only,
only: only,
except: except,
}.compact
@ -110,7 +102,7 @@ module Cask
casks.to_h do |cask|
odebug "Auditing Cask #{cask}"
[cask.sourcefile_path, Auditor.audit(cask, **options)]
[cask.sourcefile_path, { errors: Auditor.audit(cask, **options), warnings: [] }]
end
end
end

View File

@ -1,57 +0,0 @@
# typed: true
# frozen_string_literal: true
module Cask
class Cmd
# Cask implementation of the `brew reinstall` command.
#
# @api private
class Reinstall < Install
extend T::Sig
sig { void }
def run
self.class.reinstall_casks(
*casks,
binaries: args.binaries?,
verbose: args.verbose?,
force: args.force?,
skip_cask_deps: args.skip_cask_deps?,
require_sha: args.require_sha?,
quarantine: args.quarantine?,
zap: args.zap?,
)
end
def self.reinstall_casks(
*casks,
verbose: nil,
force: nil,
skip_cask_deps: nil,
binaries: nil,
require_sha: nil,
quarantine: nil,
zap: nil
)
require "cask/installer"
options = {
binaries: binaries,
verbose: verbose,
force: force,
skip_cask_deps: skip_cask_deps,
require_sha: require_sha,
reinstall: true,
quarantine: quarantine,
zap: zap,
}.compact
options[:quarantine] = true if options[:quarantine].nil?
casks.each do |cask|
Installer.new(cask, **options).install
end
end
end
end
end

View File

@ -568,8 +568,12 @@ on_request: true)
end
def load_cask_from_source_api!
options = { git_head: @cask.tap_git_head, sha256: @cask.ruby_source_checksum["sha256"] }
cask_source = Homebrew::API::Cask.fetch_source(@cask.token, **options)
cask_source = Homebrew::API::Cask.fetch_source(
@cask.token,
path: @cask.ruby_source_path || "Casks/#{@cask.token}.rb",
git_head: @cask.tap_git_head,
sha256: @cask.ruby_source_checksum["sha256"],
)
@cask = CaskLoader::FromContentLoader.new(cask_source, tap: @cask.tap).load(config: @cask.config)
end
end

View File

@ -0,0 +1,35 @@
# typed: true
# frozen_string_literal: true
module Cask
#
# @api private
class Reinstall
def self.reinstall_casks(
*casks,
verbose: nil,
force: nil,
skip_cask_deps: nil,
binaries: nil,
require_sha: nil,
quarantine: nil,
zap: nil
)
require "cask/installer"
quarantine = true if quarantine.nil?
casks.each do |cask|
Installer.new(cask,
binaries: binaries,
verbose: verbose,
force: force,
skip_cask_deps: skip_cask_deps,
require_sha: require_sha,
reinstall: true,
quarantine: quarantine,
zap: zap).install
end
end
end
end

View File

@ -42,6 +42,8 @@ module Cask
quarantine = true if quarantine.nil?
greedy = true if Homebrew::EnvConfig.upgrade_greedy?
outdated_casks = if casks.empty?
Caskroom.casks(config: Config.from_args(args)).select do |cask|
cask.outdated?(greedy: greedy, greedy_latest: greedy_latest,

View File

@ -104,7 +104,7 @@ module Cask
message << "during #{section} " if section
message << "on Cask #{token}."
opoo "#{message}\n#{error_message_with_suggestions}"
ofail "#{message}\n#{error_message_with_suggestions}"
end
end
end

View File

@ -20,9 +20,9 @@ module Homebrew
Download a bottle (if available) or source packages for <formula>e
and binaries for <cask>s. For files, also print SHA-256 checksums.
EOS
# This is needed for testing cask downloads on CI.
# This is needed for downloading ARM casks in CI.
flag "--arch=",
description: "Download for the given arch.",
description: "Download for the given CPU architecture.",
hidden: true
flag "--bottle-tag=",
description: "Download a bottle for given tag."

View File

@ -315,8 +315,8 @@ module Homebrew
ohai "Searching for similarly named #{package_types.join(" and ")}..."
# Don't treat formula/cask name as a regex
query = string_or_regex = name
all_formulae, all_casks = Search.search_names(query, string_or_regex, args)
string_or_regex = name
all_formulae, all_casks = Search.search_names(string_or_regex, args)
if all_formulae.any?
ohai "Formulae", Formatter.columns(all_formulae)

View File

@ -11,6 +11,7 @@ require "cleanup"
require "cask/cmd"
require "cask/utils"
require "cask/macos"
require "cask/reinstall"
require "upgrade"
require "api"
@ -150,7 +151,7 @@ module Homebrew
)
if casks.any?
Cask::Cmd::Reinstall.reinstall_casks(
Cask::Reinstall.reinstall_casks(
*casks,
binaries: args.binaries?,
verbose: args.verbose?,

View File

@ -33,12 +33,11 @@ module Homebrew
description <<~EOS
Perform a substring search of cask tokens and formula names for <text>. If <text>
is flanked by slashes, it is interpreted as a regular expression.
The search for <text> is extended online to `homebrew/core` and `homebrew/cask`.
EOS
switch "--formula", "--formulae",
description: "Search online and locally for formulae."
description: "Search for formulae."
switch "--cask", "--casks",
description: "Search online and locally for casks."
description: "Search for casks."
switch "--desc",
description: "Search for formulae with a description matching <text> and casks with " \
"a name or description matching <text>."
@ -84,7 +83,7 @@ module Homebrew
elsif args.pull_request?
search_pull_requests(query, args)
else
formulae, casks = Search.search_names(query, string_or_regex, args)
formulae, casks = Search.search_names(string_or_regex, args)
print_results(formulae, casks, query)
end

View File

@ -20,19 +20,19 @@ then
# use a x86_64 Portable Ruby.
[[ "${HOMEBREW_PHYSICAL_PROCESSOR}" == "arm64" && "${HOMEBREW_PREFIX}" == "/usr/local" ]]
then
ruby_FILENAME="portable-ruby-2.6.8_1.el_capitan.bottle.tar.gz"
ruby_SHA="1f50bf80583bd436c9542d4fa5ad47df0ef0f0bea22ae710c4f04c42d7560bca"
ruby_FILENAME="portable-ruby-2.6.10_1.el_capitan.bottle.tar.gz"
ruby_SHA="61029cec31c68a1fae1fa90fa876adf43d0becff777da793f9b5c5577f00567a"
elif [[ "${HOMEBREW_PHYSICAL_PROCESSOR}" == "arm64" ]]
then
ruby_FILENAME="portable-ruby-2.6.8_1.arm64_big_sur.bottle.tar.gz"
ruby_SHA="cf9137b1da5568d4949f71161a69b101f60ddb765e94d2b423c9801b67a1cb43"
ruby_FILENAME="portable-ruby-2.6.10_1.arm64_big_sur.bottle.tar.gz"
ruby_SHA="905b0c3896164ae8067a22fff2fd0b80b16d3c8bb72441403eedf69da71ec717"
fi
elif [[ -n "${HOMEBREW_LINUX}" ]]
then
case "${HOMEBREW_PROCESSOR}" in
x86_64)
ruby_FILENAME="portable-ruby-2.6.8_1.x86_64_linux.bottle.tar.gz"
ruby_SHA="fc45ee6eddf4c7a17f4373dde7b1bc8a58255ea61e6847d3bf895225b28d072a"
ruby_FILENAME="portable-ruby-2.6.10_1.x86_64_linux.bottle.tar.gz"
ruby_SHA="68923daf3e139482b977c3deba63a3b54ea37bb5f716482948878819ef911bad"
;;
*) ;;
esac
@ -53,7 +53,7 @@ then
fi
ruby_URLs+=(
"https://ghcr.io/v2/homebrew/portable-ruby/portable-ruby/blobs/sha256:${ruby_SHA}"
"https://github.com/Homebrew/homebrew-portable-ruby/releases/download/2.6.8_1/${ruby_FILENAME}"
"https://github.com/Homebrew/homebrew-portable-ruby/releases/download/2.6.10_1/${ruby_FILENAME}"
)
ruby_URL="${ruby_URLs[0]}"
fi

View File

@ -32,6 +32,11 @@ module Commands
"lc" => "livecheck",
"tc" => "typecheck",
}.freeze
# This pattern is used to split descriptions at full stops. We only consider a
# dot as a full stop if it is either followed by a whitespace or at the end of
# the description. In this way we can prevent cutting off a sentence in the
# middle due to dots in URLs or paths.
DESCRIPTION_SPLITTING_PATTERN = /\.(?>\s|$)/.freeze
def valid_internal_cmd?(cmd)
require?(HOMEBREW_CMD_PATH/cmd)
@ -203,7 +208,7 @@ module Commands
if (cmd_parser = Homebrew::CLI::Parser.from_cmd_path(path))
if short
cmd_parser.description.split(".").first
cmd_parser.description.split(DESCRIPTION_SPLITTING_PATTERN).first
else
cmd_parser.description
end
@ -215,7 +220,7 @@ module Commands
match_data = /^#: (?<desc>\w.*+)$/.match(line)
if match_data
desc = match_data[:desc]
return T.must(desc).split(".").first if short
return T.must(desc).split(DESCRIPTION_SPLITTING_PATTERN).first if short
return desc
end

View File

@ -98,28 +98,15 @@ end
######################
# These functions return lists of suggestions for arguments completion
function __fish_brew_ruby_parse_json -a file parser -d 'Parses given JSON file with Ruby'
# parser is any chain of methods to call on the parsed JSON
ruby -e "require('json'); JSON.parse(File.read('$file'))$parser"
end
function __fish_brew_suggest_formulae_all -d 'Lists all available formulae with their descriptions'
# store the brew cache path in a var (because calling (brew --cache) is slow)
set -q __brew_cache_path
or set -gx __brew_cache_path (brew --cache)
if test -f "$__brew_cache_path/descriptions.json"
__fish_brew_ruby_parse_json "$__brew_cache_path/descriptions.json" \
'.each{ |k, v| puts([k, v].reject(&:nil?).join("\t")) }'
else
brew formulae
end
brew formulae
end
function __fish_brew_suggest_formulae_installed
brew list --formula
command ls -1 (brew --cellar)
end
function __fish_brew_suggest_formulae_outdated -d "List of outdated formulae with the information about potential upgrade"
brew outdated --formula --verbose \
# replace first space with tab to make the following a description in the completions list:
@ -143,7 +130,7 @@ function __fish_brew_suggest_casks_all -d "Lists locally available casks"
end
function __fish_brew_suggest_casks_installed -d "Lists installed casks"
brew list --cask -1
command ls -1 (brew --caskroom)
end
function __fish_brew_suggest_casks_outdated -d "Lists outdated casks with the information about potential upgrade"
@ -153,7 +140,9 @@ function __fish_brew_suggest_casks_outdated -d "Lists outdated casks with the in
end
function __fish_brew_suggest_taps_installed -d "List all available taps"
brew tap
command find (brew --repo)/Library/Taps -mindepth 2 -maxdepth 2 -type d \
| string replace homebrew- "" \
| string replace (brew --repo)/Library/Taps/ ""
end
function __fish_brew_suggest_commands -d "Lists all commands names, including aliases"

View File

@ -102,7 +102,7 @@ module Debrew
raise(exception) if !active? || !debugged_exceptions.add?(exception) || !mu_try_lock
begin
puts exception.backtrace.first.to_s
puts exception.backtrace.first
puts Formatter.error(exception, label: exception.class.name)
loop do

View File

@ -31,6 +31,10 @@ module Homebrew
locally available formulae and casks and skip style checks. Will exit with a
non-zero status if any errors are found.
EOS
# This is needed for auditing ARM casks in CI.
flag "--arch=",
description: "Audit the given CPU architecture.",
hidden: true
switch "--strict",
description: "Run additional, stricter style checks."
switch "--git",
@ -60,12 +64,14 @@ module Homebrew
switch "--fix",
description: "Fix style violations automatically using RuboCop's auto-correct feature."
switch "--display-cop-names",
description: "Include the RuboCop cop name for each violation in the output."
description: "Include the RuboCop cop name for each violation in the output. This is the default.",
hidden: true
switch "--display-filename",
description: "Prefix every line of output with the file or formula name being audited, to " \
"make output easy to grep."
switch "--display-failures-only",
description: "Only display casks that fail the audit. This is the default for formulae."
description: "Only display casks that fail the audit. This is the default for formulae and casks.",
hidden: true
switch "--skip-style",
description: "Skip running non-RuboCop style checks. Useful if you plan on running " \
"`brew style` separately. Enabled by default unless a formula is specified by name."
@ -91,9 +97,6 @@ module Homebrew
conflicts "--only", "--except"
conflicts "--only-cops", "--except-cops", "--strict"
conflicts "--only-cops", "--except-cops", "--only"
conflicts "--display-cop-names", "--skip-style"
conflicts "--display-cop-names", "--only-cops"
conflicts "--display-cop-names", "--except-cops"
conflicts "--formula", "--cask"
conflicts "--installed", "--all"
@ -105,6 +108,10 @@ module Homebrew
def self.audit
args = audit_args.parse
if (arch = args.arch)
SimulateSystem.arch = arch.to_sym
end
Homebrew.auditing = true
inject_dump_stats!(FormulaAuditor, /^audit_/) if args.audit_debug?
@ -207,7 +214,6 @@ module Homebrew
spdx_license_data: spdx_license_data,
spdx_exception_data: spdx_exception_data,
style_offenses: style_offenses&.for_path(f.path),
display_cop_names: args.display_cop_names?,
}.compact
audit_proc = proc { FormulaAuditor.new(f, **options).tap(&:audit) }
@ -242,24 +248,26 @@ module Homebrew
require "cask/cmd/abstract_command"
require "cask/cmd/audit"
if args.display_failures_only?
odeprecated "`brew audit <cask> --display-failures-only`", "`brew audit <cask>` without the argument"
end
# For switches, we add `|| nil` so that `nil` will be passed instead of `false` if they aren't set.
# This way, we can distinguish between "not set" and "set to false".
Cask::Cmd::Audit.audit_casks(
*audit_casks,
download: nil,
download: nil,
# No need for `|| nil` for `--[no-]signing` because boolean switches are already `nil` if not passed
signing: args.signing?,
online: args.online? || nil,
strict: args.strict? || nil,
new_cask: args.new_cask? || nil,
token_conflicts: args.token_conflicts? || nil,
quarantine: nil,
any_named_args: !no_named_args,
language: nil,
display_passes: args.verbose? || args.named.count == 1,
display_failures_only: args.display_failures_only?,
only: args.only,
except: args.except,
signing: args.signing?,
online: args.online? || nil,
strict: args.strict? || nil,
new_cask: args.new_cask? || nil,
token_conflicts: args.token_conflicts? || nil,
quarantine: nil,
any_named_args: !no_named_args,
language: nil,
only: args.only,
except: args.except,
)
end
@ -267,7 +275,7 @@ module Homebrew
cask_count = failed_casks.count
cask_problem_count = failed_casks.sum { |_, result| result[:warnings].count + result[:errors].count }
cask_problem_count = failed_casks.sum { |_, result| result.count }
new_formula_problem_count += new_formula_problem_lines.count
total_problems_count = problem_count + new_formula_problem_count + cask_problem_count + tap_problem_count

View File

@ -231,23 +231,29 @@ module Homebrew
system "/usr/bin/sudo", "--non-interactive", "/usr/sbin/purge"
end
def self.setup_tar_and_args!(args, mtime)
# Without --only-json-tab bottles are never reproducible
default_tar_args = ["tar", [].freeze].freeze
return default_tar_args unless args.only_json_tab?
sig { returns(T::Array[String]) }
def self.tar_args
[].freeze
end
# Ensure tar is set up for reproducibility.
sig { params(mtime: String).returns(T::Array[String]) }
def self.reproducible_gnutar_args(mtime)
# Ensure gnu tar is set up for reproducibility.
# https://reproducible-builds.org/docs/archives/
gnutar_args = [
[
"--format", "pax", "--owner", "0", "--group", "0", "--sort", "name", "--mtime=#{mtime}",
# Set exthdr names to exclude PID (for GNU tar <1.33). Also don't store atime and ctime.
"--pax-option", "globexthdr.name=/GlobalHead.%n,exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime"
].freeze
end
# TODO: Refactor and move to extend/os
return ["tar", gnutar_args].freeze if OS.linux? # rubocop:disable Homebrew/MoveToExtendOS
sig { params(args: T.untyped, mtime: String).returns([String, T::Array[String]]) }
def self.setup_tar_and_args!(args, mtime)
# Without --only-json-tab bottles are never reproducible
default_tar_args = ["tar", tar_args].freeze
return default_tar_args unless args.only_json_tab?
# Use gnu-tar on macOS as it can be set up for reproducibility better than libarchive.
# Use gnu-tar as it can be set up for reproducibility better than libarchive.
begin
gnu_tar = Formula["gnu-tar"]
rescue FormulaUnavailableError
@ -256,7 +262,7 @@ module Homebrew
ensure_formula_installed!(gnu_tar, reason: "bottling")
["#{gnu_tar.opt_bin}/gtar", gnutar_args].freeze
["#{gnu_tar.opt_bin}/gtar", reproducible_gnutar_args(mtime)].freeze
end
def self.formula_ignores(formula)
@ -799,3 +805,5 @@ module Homebrew
checksums
end
end
require "extend/os/dev-cmd/bottle"

View File

@ -342,7 +342,7 @@ module Homebrew
pr_message += <<~EOS
`resource` blocks may require updates.
- [ ] `resource` blocks have been checked for updates.
EOS
end

View File

@ -72,7 +72,7 @@ module Homebrew
ambiguous_casks = []
if !args.formula? && !args.cask?
ambiguous_casks = formulae_and_casks \
ambiguous_casks = formulae_and_casks
.group_by { |item| Livecheck.package_or_resource_name(item, full_name: true) }
.values
.select { |items| items.length > 1 }

View File

@ -0,0 +1,53 @@
# typed: strict
# frozen_string_literal: true
require "cli/parser"
require "test_runner_formula"
require "github_runner_matrix"
module Homebrew
extend T::Sig
sig { returns(Homebrew::CLI::Parser) }
def self.determine_test_runners_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`determine-test-runners` <testing-formulae> [<deleted-formulae>]
Determines the runners used to test formulae or their dependents.
EOS
switch "--eval-all",
description: "Evaluate all available formulae, whether installed or not, to determine testing " \
"dependents."
switch "--dependents",
description: "Determine runners for testing dependents. Requires `--eval-all` or `HOMEBREW_EVAL_ALL`."
named_args min: 1, max: 2
hide_from_man_page!
end
end
sig { void }
def self.determine_test_runners
args = determine_test_runners_args.parse
eval_all = args.eval_all? || Homebrew::EnvConfig.eval_all?
odie "`--dependents` requires `--eval-all` or `HOMEBREW_EVAL_ALL`!" if args.dependents? && !eval_all
testing_formulae = args.named.first.split(",")
testing_formulae.map! { |name| TestRunnerFormula.new(Formulary.factory(name), eval_all: eval_all) }
.freeze
deleted_formulae = args.named.second&.split(",").freeze
runner_matrix = GitHubRunnerMatrix.new(testing_formulae, deleted_formulae, dependent_matrix: args.dependents?)
runners = runner_matrix.active_runner_specs_hash
github_output = ENV.fetch("GITHUB_OUTPUT")
File.open(github_output, "a") do |f|
f.puts("runners=#{runners.to_json}")
f.puts("runners_present=#{runners.present?}")
end
end
end

View File

@ -30,7 +30,7 @@ module Homebrew
Homebrew::Settings.delete(:gemgroups) if groups
groups ||= []
groups |= VALID_GEM_GROUPS if groups.delete("all")
groups |= Homebrew.valid_gem_groups if groups.delete("all")
Homebrew.install_bundler_gems!(groups: groups)
end

View File

@ -95,7 +95,7 @@ module Homebrew
.reject { |line| line.start_with?("#") || line.blank? }
.map(&:strip)
named_args = T.unsafe(CLI::NamedArgs).new(*names, parent: args)
named_args = CLI::NamedArgs.new(*names, parent: args)
named_args.to_formulae_and_casks(ignore_unavailable: true)
rescue Errno::ENOENT => e
onoe e

View File

@ -24,7 +24,8 @@ module Homebrew
switch "--fix",
description: "Fix style violations automatically using RuboCop's auto-correct feature."
switch "--display-cop-names",
description: "Include the RuboCop cop name for each violation in the output."
description: "Include the RuboCop cop name for each violation in the output.",
hidden: true
switch "--reset-cache",
description: "Reset the RuboCop cache."
switch "--formula", "--formulae",
@ -58,11 +59,10 @@ module Homebrew
except_cops = args.except_cops
options = {
fix: args.fix?,
display_cop_names: args.display_cop_names?,
reset_cache: args.reset_cache?,
debug: args.debug?,
verbose: args.verbose?,
fix: args.fix?,
reset_cache: args.reset_cache?,
debug: args.debug?,
verbose: args.verbose?,
}
if only_cops
options[:only_cops] = only_cops

View File

@ -1,4 +1,4 @@
# typed: false
# typed: true
# frozen_string_literal: true
require "cli/parser"
@ -6,10 +6,8 @@ require "cli/parser"
module Homebrew
extend T::Sig
module_function
sig { returns(CLI::Parser) }
def typecheck_args
def self.typecheck_args
Homebrew::CLI::Parser.new do
description <<~EOS
Check for typechecking errors using Sorbet.
@ -44,13 +42,15 @@ module Homebrew
end
sig { void }
def typecheck
def self.typecheck
args = typecheck_args.parse
Homebrew.install_bundler_gems!(groups: ["sorbet"])
update = args.update? || args.update_all?
groups = update ? Homebrew.valid_gem_groups : ["sorbet"]
Homebrew.install_bundler_gems!(groups: groups)
HOMEBREW_LIBRARY_PATH.cd do
if args.update? || args.update_all?
if update
odisabled "brew typecheck --update --fail-if-not-changed" if args.fail_if_not_changed?
excluded_gems = [
@ -95,9 +95,10 @@ module Homebrew
srb_exec += ["--ignore", args.ignore] if args.ignore.present?
if args.file.present? || args.dir.present?
cd("sorbet")
srb_exec += ["--file", "../#{args.file}"] if args.file
srb_exec += ["--dir", "../#{args.dir}"] if args.dir
cd("sorbet") do
srb_exec += ["--file", "../#{args.file}"] if args.file
srb_exec += ["--dir", "../#{args.dir}"] if args.dir
end
end
success = system(*srb_exec)
return if success

View File

@ -202,7 +202,7 @@ module Homebrew
when MacOSRequirement
next true unless r.version_specified?
macos_version.public_send(r.comparator, r.version)
macos_version.compare(r.comparator, r.version)
when XcodeRequirement
next true unless r.version

View File

@ -1,4 +1,4 @@
# typed: false
# typed: true
# frozen_string_literal: true
require "stringio"
@ -8,10 +8,8 @@ require "cli/parser"
module Homebrew
extend T::Sig
module_function
sig { returns(CLI::Parser) }
def unpack_args
def self.unpack_args
Homebrew::CLI::Parser.new do
description <<~EOS
Unpack the source files for <formula> into subdirectories of the current
@ -33,7 +31,7 @@ module Homebrew
end
end
def unpack
def self.unpack
args = unpack_args.parse
formulae = args.named.to_formulae
@ -69,10 +67,11 @@ module Homebrew
next unless args.git?
ohai "Setting up Git repository"
cd stage_dir
system "git", "init", "-q"
system "git", "add", "-A"
system "git", "commit", "-q", "-m", "brew-unpack"
cd(stage_dir) do
system "git", "init", "-q"
system "git", "add", "-A"
system "git", "commit", "-q", "-m", "brew-unpack"
end
end
end
end

View File

@ -5,6 +5,8 @@ require "cli/parser"
require "utils/github"
require "manpages"
require "active_support/core_ext/hash/slice"
module Homebrew
extend T::Sig

View File

@ -1,4 +1,4 @@
# typed: false
# typed: true
# frozen_string_literal: true
require "cli/parser"
@ -40,7 +40,8 @@ module Homebrew
named_sponsors = []
logo_sponsors = []
largest_monthly_amount = 0
# FIXME: This T.let should be unnecessary https://github.com/sorbet/sorbet/issues/6894
largest_monthly_amount = T.let(0, T.untyped)
GitHub.sponsorships("Homebrew").each do |s|
largest_monthly_amount = [s[:monthly_amount], s[:closest_tier_monthly_amount]].max

View File

@ -1,4 +1,4 @@
# typed: false
# typed: true
# frozen_string_literal: true
require "cli/parser"
@ -30,7 +30,7 @@ module Homebrew
Homebrew.install_bundler!
ENV["BUNDLE_WITH"] = VALID_GEM_GROUPS.join(":")
ENV["BUNDLE_WITH"] = Homebrew.valid_gem_groups.join(":")
# System Ruby does not pick up the correct SDK by default.
ENV["SDKROOT"] = MacOS.sdk_path if ENV["HOMEBREW_MACOS_SYSTEM_RUBY_NEW_ENOUGH"]

View File

@ -463,15 +463,10 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
url = url.sub(%r{^https?://#{GitHubPackages::URL_DOMAIN}/}o, "#{domain.chomp("/")}/")
end
output, _, _status = curl_output(
"--location", "--silent", "--head", "--request", "GET", url.to_s,
timeout: timeout
)
parsed_output = parse_curl_output(output)
parsed_output = curl_head(url.to_s, timeout: timeout)
parsed_headers = parsed_output.fetch(:responses).map { |r| r.fetch(:headers) }
lines = output.to_s.lines.map(&:chomp)
final_url = curl_response_follow_redirections(parsed_output[:responses], url)
final_url = curl_response_follow_redirections(parsed_output.fetch(:responses), url)
content_disposition_parser = Mechanize::HTTP::ContentDispositionParser.new
@ -500,19 +495,20 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
File.basename(filename)
end
filenames = lines.map(&parse_content_disposition).compact
filenames = parsed_headers.flat_map do |headers|
next [] unless (header = headers["content-disposition"])
time =
lines.map { |line| line[/^Last-Modified:\s*(.+)/i, 1] }
.compact
[*parse_content_disposition.call("Content-Disposition: #{header}")]
end
time = parsed_headers
.flat_map { |headers| [*headers["last-modified"]] }
.map { |t| t.match?(/^\d+$/) ? Time.at(t.to_i) : Time.parse(t) }
.last
file_size =
lines.map { |line| line[/^Content-Length:\s*(\d+)/i, 1] }
.compact
.map(&:to_i)
.last
file_size = parsed_headers
.flat_map { |headers| [*headers["content-length"]&.to_i] }
.last
is_redirection = url != final_url
basename = filenames.last || parse_basename(final_url, search_query: !is_redirection)

View File

@ -344,6 +344,10 @@ module Homebrew
description: "If set, use Pry for the `brew irb` command.",
boolean: true,
},
HOMEBREW_UPGRADE_GREEDY: {
description: "If set, pass `--greedy` to all cask upgrade commands.",
boolean: true,
},
HOMEBREW_SIMULATE_MACOS_ON_LINUX: {
description: "If set, running Homebrew on Linux will simulate certain macOS code paths. This is useful " \
"when auditing macOS formulae while on Linux.",

View File

@ -229,6 +229,9 @@ module Homebrew::EnvConfig
sig { returns(T::Boolean) }
def self.update_to_tag?; end
sig { returns(T::Boolean) }
def self.upgrade_greedy?; end
sig { returns(T::Boolean) }
def self.verbose?; end

View File

@ -28,13 +28,13 @@ module OnSystem
return false if Homebrew::SimulateSystem.simulating_or_running_on_linux?
base_os = MacOS::Version.from_symbol(os_name)
base_os = OS::Mac::Version.from_symbol(os_name)
current_os = if Homebrew::SimulateSystem.current_os == :macos
# Assume the oldest macOS version when simulating a generic macOS version
# Version::NULL is always treated as less than any other version.
Version::NULL
else
MacOS::Version.from_symbol(Homebrew::SimulateSystem.current_os)
OS::Mac::Version.from_symbol(Homebrew::SimulateSystem.current_os)
end
return current_os >= base_os if or_condition == :or_newer

View File

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

View File

@ -0,0 +1,12 @@
# typed: true
# frozen_string_literal: true
module Homebrew
sig { params(args: T.untyped, mtime: String).returns([String, T::Array[String]]) }
def self.setup_tar_and_args!(args, mtime)
# Without --only-json-tab bottles are never reproducible
return ["tar", tar_args].freeze unless args.only_json_tab?
["tar", reproducible_gnutar_args(mtime)].freeze
end
end

View File

@ -0,0 +1,9 @@
# typed: true
# frozen_string_literal: true
module Homebrew
sig { returns(T::Array[String]) }
def self.tar_args
["--no-mac-metadata", "--no-acls", "--no-xattrs"].freeze
end
end

View File

@ -206,7 +206,6 @@ module Homebrew
def check_ruby_version
return if RUBY_VERSION == HOMEBREW_REQUIRED_RUBY_VERSION
return if RUBY_VERSION == "2.6.10" # TODO: require 2.6.10
return if Homebrew::EnvConfig.developer? && OS::Mac.version.prerelease?
<<~EOS

View File

@ -19,7 +19,7 @@ module Readall
# Fine to have missing URLs for unsupported macOS
macos_req = cask.depends_on.macos
next if macos_req&.version && Array(macos_req.version).none? do |macos_version|
current_macos_version.public_send(macos_req.comparator, macos_version)
current_macos_version.compare(macos_req.comparator, macos_version)
end
raise "Missing URL" if cask.url.nil?

View File

@ -1152,7 +1152,7 @@ class Formula
ENV.activate_extensions!
etc_var_dirs = [bottle_prefix/"etc", bottle_prefix/"var"]
T.unsafe(Find).find(*etc_var_dirs.select(&:directory?)) do |path|
Find.find(*etc_var_dirs.select(&:directory?)) do |path|
path = Pathname.new(path)
path.extend(InstallRenamed)
path.cp_path_sub(bottle_prefix, HOMEBREW_PREFIX)
@ -2199,6 +2199,7 @@ class Formula
"sha256" => resource("ruby-source").checksum.hexdigest,
}
elsif !self.class.loaded_from_api && path.exist?
hsh["ruby_source_path"] = path.relative_path_from(tap.path).to_s
hsh["ruby_source_checksum"] = {
"sha256" => Digest::SHA256.file(path).hexdigest,
}
@ -2672,7 +2673,7 @@ class Formula
out.close
args.map!(&:to_s)
begin
T.unsafe(Kernel).exec(cmd, *args)
Kernel.exec(cmd, *args)
rescue
nil
end

View File

@ -255,10 +255,12 @@ module Formulary
end
resource "ruby-source" do
url "https://raw.githubusercontent.com/Homebrew/homebrew-core/#{json_formula["tap_git_head"]}/Formula/#{name}.rb"
if (ruby_source_sha256 = json_formula.dig("ruby_source_checksum", "sha256")).present?
sha256 ruby_source_sha256
end
tap_git_head = json_formula.fetch("tap_git_head", "HEAD")
ruby_source_path = json_formula.fetch("ruby_source_path", "Formula/#{name}.rb")
ruby_source_sha256 = json_formula.dig("ruby_source_checksum", "sha256")
url "https://raw.githubusercontent.com/Homebrew/homebrew-core/#{tap_git_head}/#{ruby_source_path}"
sha256 ruby_source_sha256 if ruby_source_sha256
end
def install

View File

@ -0,0 +1,35 @@
# typed: strict
# frozen_string_literal: true
require "linux_runner_spec"
require "macos_runner_spec"
class GitHubRunner < T::Struct
extend T::Sig
const :platform, Symbol
const :arch, Symbol
const :spec, T.any(LinuxRunnerSpec, MacOSRunnerSpec)
const :macos_version, T.nilable(OS::Mac::Version)
prop :active, T::Boolean, default: false
sig { returns(T::Boolean) }
def macos?
platform == :macos
end
sig { returns(T::Boolean) }
def linux?
platform == :linux
end
sig { returns(T::Boolean) }
def x86_64?
arch == :x86_64
end
sig { returns(T::Boolean) }
def arm64?
arch == :arm64
end
end

View File

@ -0,0 +1,192 @@
# typed: strict
# frozen_string_literal: true
require "test_runner_formula"
require "github_runner"
class GitHubRunnerMatrix
extend T::Sig
# FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
# rubocop:disable Style/MutableConstant
MaybeStringArray = T.type_alias { T.nilable(T::Array[String]) }
private_constant :MaybeStringArray
RunnerSpec = T.type_alias { T.any(LinuxRunnerSpec, MacOSRunnerSpec) }
private_constant :RunnerSpec
MacOSRunnerSpecHash = T.type_alias { { name: String, runner: String, cleanup: T::Boolean } }
private_constant :MacOSRunnerSpecHash
LinuxRunnerSpecHash = T.type_alias do
{
name: String,
runner: String,
container: T::Hash[Symbol, String],
workdir: String,
timeout: Integer,
cleanup: T::Boolean,
}
end
private_constant :LinuxRunnerSpecHash
RunnerSpecHash = T.type_alias { T.any(LinuxRunnerSpecHash, MacOSRunnerSpecHash) }
private_constant :RunnerSpecHash
# rubocop:enable Style/MutableConstant
sig { returns(T::Array[GitHubRunner]) }
attr_reader :runners
sig {
params(
testing_formulae: T::Array[TestRunnerFormula],
deleted_formulae: MaybeStringArray,
dependent_matrix: T::Boolean,
).void
}
def initialize(testing_formulae, deleted_formulae, dependent_matrix:)
@testing_formulae = T.let(testing_formulae, T::Array[TestRunnerFormula])
@deleted_formulae = T.let(deleted_formulae, MaybeStringArray)
@dependent_matrix = T.let(dependent_matrix, T::Boolean)
@runners = T.let([], T::Array[GitHubRunner])
generate_runners!
freeze
end
sig { returns(T::Array[RunnerSpecHash]) }
def active_runner_specs_hash
runners.select(&:active)
.map(&:spec)
.map(&:to_h)
end
private
sig { returns(LinuxRunnerSpec) }
def linux_runner_spec
linux_runner = ENV.fetch("HOMEBREW_LINUX_RUNNER")
linux_cleanup = ENV.fetch("HOMEBREW_LINUX_CLEANUP")
LinuxRunnerSpec.new(
name: "Linux",
runner: linux_runner,
container: {
image: "ghcr.io/homebrew/ubuntu22.04:master",
options: "--user=linuxbrew -e GITHUB_ACTIONS_HOMEBREW_SELF_HOSTED",
},
workdir: "/github/home",
timeout: 4320,
cleanup: linux_cleanup == "true",
)
end
VALID_PLATFORMS = T.let([:macos, :linux].freeze, T::Array[Symbol])
VALID_ARCHES = T.let([:arm64, :x86_64].freeze, T::Array[Symbol])
sig {
params(
platform: Symbol,
arch: Symbol,
spec: RunnerSpec,
macos_version: T.nilable(OS::Mac::Version),
).returns(GitHubRunner)
}
def create_runner(platform, arch, spec, macos_version = nil)
raise "Unexpected platform: #{platform}" if VALID_PLATFORMS.exclude?(platform)
raise "Unexpected arch: #{arch}" if VALID_ARCHES.exclude?(arch)
runner = GitHubRunner.new(platform: platform, arch: arch, spec: spec, macos_version: macos_version)
runner.active = active_runner?(runner)
runner.freeze
end
sig { void }
def generate_runners!
return if @runners.present?
@runners << create_runner(:linux, :x86_64, linux_runner_spec)
github_run_id = ENV.fetch("GITHUB_RUN_ID")
github_run_attempt = ENV.fetch("GITHUB_RUN_ATTEMPT")
ephemeral_suffix = +"-#{github_run_id}-#{github_run_attempt}"
ephemeral_suffix << "-deps" if @dependent_matrix
ephemeral_suffix.freeze
MacOSVersions::SYMBOLS.each_value do |version|
macos_version = OS::Mac::Version.new(version)
next if macos_version.unsupported_release?
spec = MacOSRunnerSpec.new(
name: "macOS #{version}-x86_64",
runner: "#{version}#{ephemeral_suffix}",
cleanup: false,
)
@runners << create_runner(:macos, :x86_64, spec, macos_version)
next unless macos_version >= :big_sur
# Use bare metal runner when testing dependents on ARM64 Monterey.
use_ephemeral = (macos_version >= :ventura && @dependent_matrix) ||
(macos_version >= :monterey && !@dependent_matrix)
runner, cleanup = if use_ephemeral
["#{version}-arm64#{ephemeral_suffix}", false]
else
["#{version}-arm64", true]
end
spec = MacOSRunnerSpec.new(name: "macOS #{version}-arm64", runner: runner, cleanup: cleanup)
@runners << create_runner(:macos, :arm64, spec, macos_version)
end
@runners.freeze
end
sig { params(runner: GitHubRunner).returns(T::Boolean) }
def active_runner?(runner)
if @dependent_matrix
formulae_have_untested_dependents?(runner)
else
return true if @deleted_formulae.present?
compatible_formulae = @testing_formulae.dup
platform = runner.platform
arch = runner.arch
macos_version = runner.macos_version
compatible_formulae.select! { |formula| formula.public_send(:"#{platform}_compatible?") }
compatible_formulae.select! { |formula| formula.public_send(:"#{arch}_compatible?") }
compatible_formulae.select! { |formula| formula.compatible_with?(macos_version) } if macos_version
compatible_formulae.present?
end
end
sig { params(runner: GitHubRunner).returns(T::Boolean) }
def formulae_have_untested_dependents?(runner)
platform = runner.platform
arch = runner.arch
macos_version = runner.macos_version
@testing_formulae.any? do |formula|
# If the formula has a platform/arch/macOS version requirement, then its
# dependents don't need to be tested if these requirements are not satisfied.
next false unless formula.public_send(:"#{platform}_compatible?")
next false unless formula.public_send(:"#{arch}_compatible?")
next false if macos_version.present? && !formula.compatible_with?(macos_version)
compatible_dependents = formula.dependents(platform: platform, arch: arch, macos_version: macos_version&.to_sym)
.dup
compatible_dependents.select! { |dependent_f| dependent_f.public_send(:"#{platform}_compatible?") }
compatible_dependents.select! { |dependent_f| dependent_f.public_send(:"#{arch}_compatible?") }
compatible_dependents.select! { |dependent_f| dependent_f.compatible_with?(macos_version) } if macos_version
# These arrays will generally have been generated by different Formulary caches,
# so we can only compare them by name and not directly.
(compatible_dependents.map(&:name) - @testing_formulae.map(&:name)).present?
end
end
end

View File

@ -0,0 +1,34 @@
# typed: strict
# frozen_string_literal: true
class LinuxRunnerSpec < T::Struct
extend T::Sig
const :name, String
const :runner, String
const :container, T::Hash[Symbol, String]
const :workdir, String
const :timeout, Integer
const :cleanup, T::Boolean
sig {
returns({
name: String,
runner: String,
container: T::Hash[Symbol, String],
workdir: String,
timeout: Integer,
cleanup: T::Boolean,
})
}
def to_h
{
name: name,
runner: runner,
container: container,
workdir: workdir,
timeout: timeout,
cleanup: cleanup,
}
end
end

View File

@ -182,7 +182,7 @@ module Homebrew
ambiguous_casks = []
if handle_name_conflict
ambiguous_casks = formulae_and_casks_to_check \
ambiguous_casks = formulae_and_casks_to_check
.group_by { |item| package_or_resource_name(item, full_name: true) }
.values
.select { |items| items.length > 1 }

View File

@ -93,13 +93,13 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
generated = generate_input_values(url)
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
end
end
end

View File

@ -96,13 +96,13 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
generated = generate_input_values(url)
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
end
end
end

View File

@ -80,13 +80,13 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
generated = generate_input_values(url)
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
end
end
end

View File

@ -45,7 +45,7 @@ module Homebrew
regex: T.nilable(Regexp),
provided_content: T.nilable(String),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, provided_content: nil, **unused, &block)
@ -54,7 +54,7 @@ module Homebrew
"#{Utils.demodulize(T.must(name))} only supports a regex when using a `strategy` block"
end
T.unsafe(Yaml).find_versions(
Yaml.find_versions(
url: url,
regex: regex,
provided_content: provided_content,

View File

@ -64,7 +64,7 @@ module Homebrew
params(
items: T::Hash[String, Item],
regex: T.nilable(Regexp),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Array[String])
}
def self.versions_from_items(items, regex = nil, &block)
@ -92,7 +92,7 @@ module Homebrew
url: T.nilable(String),
regex: T.nilable(Regexp),
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(cask:, url: nil, regex: nil, **_unused, &block)

View File

@ -85,7 +85,7 @@ module Homebrew
params(
tags: T::Array[String],
regex: T.nilable(Regexp),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Array[String])
}
def self.versions_from_tags(tags, regex = nil, &block)
@ -125,7 +125,7 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **_unused, &block)

View File

@ -92,13 +92,13 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
generated = generate_input_values(url)
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || DEFAULT_REGEX, **unused, &block)
PageMatch.find_versions(url: generated[:url], regex: regex || DEFAULT_REGEX, **unused, &block)
end
end
end

View File

@ -82,13 +82,13 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
generated = generate_input_values(url)
version_data = T.unsafe(PageMatch).find_versions(
version_data = PageMatch.find_versions(
url: generated[:url],
regex: regex || generated[:regex],
**unused,

View File

@ -92,13 +92,13 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
generated = generate_input_values(url)
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
end
end
end

View File

@ -78,13 +78,13 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
generated = generate_input_values(url)
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
end
end
end

View File

@ -44,7 +44,7 @@ module Homebrew
params(
headers: T::Hash[String, String],
regex: T.nilable(Regexp),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Array[String])
}
def self.versions_from_headers(headers, regex = nil, &block)
@ -79,7 +79,7 @@ module Homebrew
regex: T.nilable(Regexp),
homebrew_curl: T::Boolean,
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, homebrew_curl: false, **_unused, &block)

View File

@ -70,7 +70,7 @@ module Homebrew
params(
content: String,
regex: T.nilable(Regexp),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Array[String])
}
def self.versions_from_content(content, regex = nil, &block)
@ -105,7 +105,7 @@ module Homebrew
provided_content: T.nilable(String),
homebrew_curl: T::Boolean,
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **_unused, &block)

View File

@ -75,13 +75,13 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
generated = generate_input_values(url)
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || DEFAULT_REGEX, **unused, &block)
PageMatch.find_versions(url: generated[:url], regex: regex || DEFAULT_REGEX, **unused, &block)
end
end
end

View File

@ -73,13 +73,13 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
generated = generate_input_values(url)
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
end
end
end

View File

@ -51,7 +51,7 @@ module Homebrew
params(
content: String,
regex: T.nilable(Regexp),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Array[String])
}
def self.versions_from_content(content, regex, &block)
@ -88,7 +88,7 @@ module Homebrew
provided_content: T.nilable(String),
homebrew_curl: T::Boolean,
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **_unused, &block)

View File

@ -87,13 +87,13 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
generated = generate_input_values(url)
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
end
end
end

View File

@ -92,13 +92,13 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
generated = generate_input_values(url)
T.unsafe(PageMatch).find_versions(
PageMatch.find_versions(
url: generated[:url] || url,
regex: regex || generated[:regex],
**unused,

View File

@ -146,7 +146,7 @@ module Homebrew
params(
content: String,
regex: T.nilable(Regexp),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Array[String])
}
def self.versions_from_content(content, regex = nil, &block)
@ -181,7 +181,7 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **_unused, &block)

View File

@ -87,7 +87,7 @@ module Homebrew
params(
content: String,
regex: T.nilable(Regexp),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Array[String])
}
def self.versions_from_content(content, regex = nil, &block)
@ -123,7 +123,7 @@ module Homebrew
provided_content: T.nilable(String),
homebrew_curl: T::Boolean,
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **_unused, &block)

View File

@ -114,7 +114,7 @@ module Homebrew
url: String,
regex: T.nilable(Regexp),
unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, **unused, &block)
@ -123,7 +123,7 @@ module Homebrew
# Use the cached page content to avoid duplicate fetches
cached_content = @page_data[generated_url]
match_data = T.unsafe(PageMatch).find_versions(
match_data = PageMatch.find_versions(
url: generated_url,
regex: regex || generated[:regex],
provided_content: cached_content,

View File

@ -70,7 +70,7 @@ module Homebrew
params(
content: String,
regex: T.nilable(Regexp),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Array[String])
}
def self.versions_from_content(content, regex = nil, &block)
@ -105,7 +105,7 @@ module Homebrew
provided_content: T.nilable(String),
homebrew_curl: T::Boolean,
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
block: T.untyped,
block: T.nilable(Proc),
).returns(T::Hash[Symbol, T.untyped])
}
def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **_unused, &block)

View File

@ -17,14 +17,14 @@ class Locale
LANGUAGE_REGEX = /(?:[a-z]{2,3})/.freeze
private_constant :LANGUAGE_REGEX
# ISO 3166-1 or UN M.49
REGION_REGEX = /(?:[A-Z]{2}|\d{3})/.freeze
private_constant :REGION_REGEX
# ISO 15924
SCRIPT_REGEX = /(?:[A-Z][a-z]{3})/.freeze
private_constant :SCRIPT_REGEX
# ISO 3166-1 or UN M.49
REGION_REGEX = /(?:[A-Z]{2}|\d{3})/.freeze
private_constant :REGION_REGEX
LOCALE_REGEX = /\A((?:#{LANGUAGE_REGEX}|#{REGION_REGEX}|#{SCRIPT_REGEX})(?:-|$)){1,3}\Z/.freeze
private_constant :LOCALE_REGEX
@ -56,18 +56,18 @@ class Locale
return unless scanner.eos?
new(language, region, script)
new(language, script, region)
end
attr_reader :language, :region, :script
attr_reader :language, :script, :region
def initialize(language, region, script)
def initialize(language, script, region)
raise ArgumentError, "#{self.class} cannot be empty" if language.nil? && region.nil? && script.nil?
{
language: language,
region: region,
script: script,
region: region,
}.each do |key, value|
next if value.nil?
@ -84,7 +84,7 @@ class Locale
return false if other.nil?
end
[:language, :region, :script].all? do |var|
[:language, :script, :region].all? do |var|
if other.public_send(var).nil?
true
else
@ -99,7 +99,7 @@ class Locale
return false if other.nil?
end
[:language, :region, :script].all? do |var|
[:language, :script, :region].all? do |var|
public_send(var) == other.public_send(var)
end
end
@ -112,6 +112,6 @@ class Locale
sig { returns(String) }
def to_s
[@language, @region, @script].compact.join("-")
[@language, @script, @region].compact.join("-")
end
end

View File

@ -0,0 +1,19 @@
# typed: strict
# frozen_string_literal: true
class MacOSRunnerSpec < T::Struct
extend T::Sig
const :name, String
const :runner, String
const :cleanup, T::Boolean
sig { returns({ name: String, runner: String, cleanup: T::Boolean }) }
def to_h
{
name: name,
runner: runner,
cleanup: cleanup,
}
end
end

View File

@ -360,14 +360,14 @@ class Migrator
# Remove `opt/oldname` link if it belongs to newname.
def unlink_oldname_opt
return unless old_opt_record
return if old_opt_record.to_s.blank?
return unless old_opt_record.symlink?
return unless old_opt_record.exist?
return unless new_linked_keg_record.exist?
return if new_linked_keg_record.realpath != old_opt_record.realpath
if old_opt_record.symlink? && old_opt_record.exist? \
&& new_linked_keg_record.exist? \
&& new_linked_keg_record.realpath == old_opt_record.realpath
old_opt_record.unlink
old_opt_record.parent.rmdir_if_possible
end
old_opt_record.unlink
old_opt_record.parent.rmdir_if_possible
end
# Remove `Cellar/oldname` if it exists.

View File

@ -5,7 +5,7 @@ libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: expat
Version: 2.4.8
Version: 2.5.0
Description: expat XML parser
URL: https://libexpat.github.io/
Libs: -L${libdir} -lexpat

View File

@ -36,7 +36,7 @@ supported_features="alt-svc AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IPv6 Kerber
Name: libcurl
URL: https://curl.se/
Description: Library to transfer files with ftp, http, etc.
Version: 7.84.0
Version: 7.87.0
Libs: -L${libdir} -lcurl
Libs.private: -lldap -lz
Cflags:

View File

@ -6,7 +6,7 @@ includedir=${prefix}/include
Name: SQLite
Description: SQL database engine
Version: 3.39.4
Version: 3.39.5
Libs: -L${libdir} -lsqlite3
Libs.private:
Cflags:

View File

@ -72,6 +72,11 @@ module OS
self >= HOMEBREW_MACOS_NEWEST_UNSUPPORTED
end
sig { returns(T::Boolean) }
def unsupported_release?
outdated_release? || prerelease?
end
# For {OS::Mac::Version} compatibility.
sig { returns(T::Boolean) }
def requires_nehalem_cpu?

View File

@ -21,10 +21,10 @@ module OS
# This may be a beta version for a beta macOS.
sig { params(macos: MacOS::Version).returns(String) }
def latest_version(macos: MacOS.version)
latest_stable = "13.4"
latest_stable = "14.3"
case macos
when "13" then "14.1"
when "12" then latest_stable
when "13" then latest_stable
when "12" then "14.2"
when "11" then "13.2.1"
when "10.15" then "12.4"
when "10.14" then "11.3.1"
@ -246,7 +246,8 @@ module OS
when "12.0.5" then "12.5.1"
when "13.0.0" then "13.2.1"
when "13.1.6" then "13.4.1"
else "14.1"
when "14.0.0" then "14.2"
else "14.3"
end
end
@ -344,8 +345,8 @@ module OS
sig { returns(String) }
def latest_clang_version
case MacOS.version
when "13" then "1400.0.29.202"
when "12" then "1316.0.21.2.5"
when "13" then "1403.0.22.14.1"
when "12" then "1400.0.29.202"
when "11" then "1300.0.29.30"
when "10.15" then "1200.0.32.29"
when "10.14" then "1100.0.33.17"

View File

@ -23,9 +23,9 @@ class MacOSRequirement < Requirement
def initialize(tags = [], comparator: ">=")
@version = begin
if comparator == "==" && tags.first.respond_to?(:map)
tags.first.map { |s| MacOS::Version.from_symbol(s) }
tags.first.map { |s| OS::Mac::Version.from_symbol(s) }
else
MacOS::Version.from_symbol(tags.first) unless tags.empty?
OS::Mac::Version.from_symbol(tags.first) unless tags.empty?
end
rescue MacOSVersionError => e
if DISABLED_MACOS_VERSIONS.include?(e.version)
@ -43,7 +43,7 @@ class MacOSRequirement < Requirement
end
# Otherwise fallback to the oldest allowed if comparator is >=.
MacOS::Version.new(HOMEBREW_MACOS_OLDEST_ALLOWED) if comparator == ">="
OS::Mac::Version.new(HOMEBREW_MACOS_OLDEST_ALLOWED) if comparator == ">="
end
@comparator = comparator
@ -56,7 +56,7 @@ class MacOSRequirement < Requirement
satisfy(build_env: false) do
T.bind(self, MacOSRequirement)
next Array(@version).any? { |v| MacOS.version.public_send(@comparator, v) } if OS.mac? && version_specified?
next Array(@version).any? { |v| OS::Mac.version.compare(@comparator, v) } if OS.mac? && version_specified?
next true if OS.mac?
next true if @version

View File

@ -24,6 +24,7 @@ require_relative "lines"
require_relative "livecheck"
require_relative "options"
require_relative "patches"
require_relative "service"
require_relative "text"
require_relative "urls"
require_relative "uses_from_macos"

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