Merge branch 'master' into master

This commit is contained in:
Thibaut Hérault 2025-06-17 20:49:18 -04:00 committed by GitHub
commit 27a040cc32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
112 changed files with 2281 additions and 1511 deletions

View File

@ -0,0 +1,7 @@
# This file is synced from the `.github` repository, do not modify it directly.
extensions:
- addsTo:
pack: codeql/actions-all
extensible: trustedActionsOwnerDataModel
data:
- ["Homebrew"]

View File

@ -1,18 +1,19 @@
name: actionlint
# This file is synced from the `.github` repository, do not modify it directly.
name: Actionlint
on:
push:
branches:
- main
- master
paths:
- '.github/workflows/*.ya?ml'
- 'Formula/a/actionlint.rb'
- 'Formula/s/shellcheck.rb'
- 'Formula/z/zizmor.rb'
pull_request:
paths:
- '.github/workflows/*.ya?ml'
- '.github/actionlint.yaml'
env:
HOMEBREW_DEVELOPER: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_ENV_HINTS: 1
defaults:
run:
@ -22,16 +23,23 @@ concurrency:
group: "actionlint-${{ github.ref }}"
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
HOMEBREW_DEVELOPER: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_ENV_HINTS: 1
permissions: {}
jobs:
workflow_syntax:
if: github.repository_owner == 'Homebrew'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Set up Homebrew
id: setup-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -40,31 +48,42 @@ jobs:
- name: Install tools
run: brew install actionlint shellcheck zizmor
- name: Set up GITHUB_WORKSPACE
env:
HOMEBREW_REPOSITORY: ${{ steps.setup-homebrew.outputs.repository-path }}
run: |
# 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"
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
echo "::add-matcher::.github/actionlint-matcher.json"
- run: |
# NOTE: exit code intentionally suppressed here
zizmor --format sarif . > results.sarif || true
- run: zizmor --format sarif . > results.sarif
- name: Upload SARIF file
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
# We can't use the SARIF file when triggered by `merge_group` so we don't upload it.
if: always() && github.event_name != 'merge_group'
with:
name: results.sarif
path: results.sarif
- name: Set up actionlint
run: |
# In homebrew-core, setting `shell: /bin/bash` prevents shellcheck from running on
# those steps, so let's change them to `shell: bash` temporarily for better linting.
sed -i 's|shell: /bin/bash -x|shell: bash -x|' .github/workflows/*.y*ml
# In homebrew-core, the JSON matcher needs to be accessible to the container host.
cp "$(brew --repository)/.github/actionlint-matcher.json" "$HOME"
echo "::add-matcher::$HOME/actionlint-matcher.json"
- run: actionlint
upload_sarif:
needs: workflow_syntax
# We want to always upload this even if `actionlint` failed.
# This is only available on public repositories.
if: >
always() &&
!contains(fromJSON('["cancelled", "skipped"]'), needs.workflow_syntax.result) &&
!github.event.repository.private &&
github.event_name != 'merge_group'
runs-on: ubuntu-latest
permissions:
contents: read
@ -77,7 +96,7 @@ jobs:
path: results.sarif
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
uses: github/codeql-action/upload-sarif@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
with:
sarif_file: results.sarif
category: zizmor

View File

@ -27,7 +27,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false

View File

@ -3,10 +3,9 @@ name: "CodeQL"
on:
push:
branches:
- main
- master
pull_request:
branches:
- master
defaults:
run:
@ -28,7 +27,7 @@ jobs:
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
with:
languages: ruby
config: |
@ -36,4 +35,4 @@ jobs:
- Library/Homebrew/vendor
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0

View File

@ -4,6 +4,7 @@ on:
pull_request:
push:
branches:
- main
- master
merge_group:
release:
@ -38,8 +39,8 @@ jobs:
fetch-depth: 0
persist-credentials: false
- name: Fetch origin/master from Git
run: git fetch origin master
- name: Fetch origin/HEAD from Git
run: git fetch origin HEAD
- name: Determine build attributes
id: attributes
@ -83,12 +84,16 @@ jobs:
)
fi
elif [[ "${GITHUB_EVENT_NAME}" == "push" &&
"${GITHUB_REF}" == "refs/heads/master" &&
("${GITHUB_REF}" == "refs/heads/master" || "${GITHUB_REF}" == "refs/heads/main") &&
"${version}" == "22.04" ]]; then
tags+=(
"ghcr.io/homebrew/brew:main"
"ghcr.io/homebrew/brew:master"
"ghcr.io/homebrew/ubuntu${version}:main"
"ghcr.io/homebrew/ubuntu${version}:master"
"homebrew/brew:main"
"homebrew/brew:master"
"homebrew/ubuntu${version}:main"
"homebrew/ubuntu${version}:master"
)
fi
@ -160,8 +165,8 @@ jobs:
fetch-depth: 0
persist-credentials: false
- name: Fetch origin/master from Git
run: git fetch origin master
- name: Fetch origin/HEAD from Git
run: git fetch origin HEAD
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0

View File

@ -24,7 +24,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -52,7 +52,7 @@ jobs:
run: vale docs/
- name: Install Ruby
uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
with:
bundler-cache: true
working-directory: docs
@ -67,7 +67,7 @@ jobs:
- name: Generate formulae.brew.sh API samples
if: github.repository == 'Homebrew/formulae.brew.sh'
working-directory: docs
run: ../script/generate-api-samples.rb
run: ../script/generate-api-samples.rb --template
- name: Build the site and check for broken links
working-directory: docs

View File

@ -28,7 +28,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -55,7 +55,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false

View File

@ -43,7 +43,7 @@ jobs:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -135,7 +135,7 @@ jobs:
fi
- name: Generate build provenance
uses: actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd # v2.3.0
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
with:
subject-path: Homebrew-${{ steps.homebrew-version.outputs.version }}.pkg
@ -251,7 +251,7 @@ jobs:
issues: write
steps:
- name: Open, update, or close pkg installer issue
uses: Homebrew/actions/create-or-update-issue@master
uses: Homebrew/actions/create-or-update-issue@main
with:
title: Failed to publish pkg installer
body: >
@ -259,7 +259,7 @@ jobs:
${{ github.ref_name }}. No pkg installer was uploaded to the GitHub
release.
labels: bug,release blocker
update-existing: ${{ contains(needs.*.result, 'failure') }}
update-existing: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }}
close-existing: ${{ needs.upload.result == 'success' }}
close-from-author: github-actions[bot]
close-comment: >

View File

@ -3,6 +3,7 @@ name: Ruby Documentation CI
on:
push:
branches:
- main
- master
pull_request:
@ -28,7 +29,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -42,7 +43,7 @@ jobs:
persist-credentials: false
- name: Install Ruby
uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
with:
bundler-cache: true
working-directory: rubydoc

View File

@ -1,9 +1,10 @@
name: Update schema data
name: Update SBOM schema
on:
push:
paths:
- .github/workflows/schemas.yml
- .github/workflows/sbom.yml
branches-ignore:
- main
- master
schedule:
- cron: "0 0 * * *"
@ -17,25 +18,25 @@ defaults:
shell: bash -xeuo pipefail {0}
jobs:
spdx:
sbom:
if: github.repository == 'Homebrew/brew'
runs-on: ubuntu-latest
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
test-bot: false
- name: Configure Git user
uses: Homebrew/actions/git-user-config@master
uses: Homebrew/actions/git-user-config@main
with:
username: BrewTestBot
- name: Set up commit signing
uses: Homebrew/actions/setup-commit-signing@master
uses: Homebrew/actions/setup-commit-signing@main
with:
signing_key: ${{ secrets.BREWTESTBOT_SSH_SIGNING_KEY }}
@ -55,7 +56,7 @@ jobs:
git checkout "${BRANCH}"
git checkout "Library/Homebrew/data/schemas"
else
git checkout --no-track -B "${BRANCH}" origin/master
git checkout --no-track -B "${BRANCH}" origin/HEAD
fi
# Intentionally tracking 2.3.x to match what we output in sbom.rb. 3.0 also doesn't have a JSON Schema.
@ -67,9 +68,10 @@ jobs:
if ! git diff --exit-code Library/Homebrew/data/schemas
then
git add "Library/Homebrew/data/schemas"
git commit -m "data/schemas: update schema data." -m "Autogenerated by [a scheduled GitHub Action](https://github.com/Homebrew/brew/blob/master/.github/workflows/schemas.yml)."
git commit -m "data/schemas: update schema data." -m "Autogenerated by [a scheduled GitHub Action](https://github.com/Homebrew/brew/blob/HEAD/.github/workflows/schemas.yml)."
echo "committed=true" >> "$GITHUB_OUTPUT"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state")"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state" || true)"
if [[ "${PULL_REQUEST_STATE}" != "OPEN" ]]
then
echo "pull_request=true" >> "$GITHUB_OUTPUT"
@ -78,13 +80,13 @@ jobs:
- name: Push commits
if: steps.update.outputs.committed == 'true'
uses: Homebrew/actions/git-try-push@master
uses: Homebrew/actions/git-try-push@main
with:
token: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
branch: ${{ steps.update.outputs.branch }}
force: true
origin_branch: "master"
origin_branch: "HEAD"
- name: Open a pull request
if: steps.update.outputs.pull_request == 'true'
@ -92,3 +94,26 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
issue:
needs: sbom
if: always() && github.event_name == 'schedule'
runs-on: ubuntu-latest
env:
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
permissions:
# To create or update issues
issues: write
steps:
- name: Open, update, or close schema issue
uses: Homebrew/actions/create-or-update-issue@main
with:
title: Failed to update SBOM schema
body: >
The SBOM schema workflow [failed](${{ env.RUN_URL }}). No SBOM schema was updated.
labels: bug
update-existing: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }}
close-existing: ${{ needs.sbom.result == 'success' }}
close-from-author: github-actions[bot]
close-comment: >
The SBOM schema workflow [succeeded](${{ env.RUN_URL }}). Closing this issue.

View File

@ -10,6 +10,7 @@ on:
paths:
- .github/workflows/sorbet.yml
branches-ignore:
- main
- master
schedule:
- cron: "0 0 * * *"
@ -29,7 +30,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -37,13 +38,13 @@ jobs:
- name: Configure Git user
if: github.event_name != 'pull_request'
uses: Homebrew/actions/git-user-config@master
uses: Homebrew/actions/git-user-config@main
with:
username: BrewTestBot
- name: Set up commit signing
if: github.event_name != 'pull_request'
uses: Homebrew/actions/setup-commit-signing@master
uses: Homebrew/actions/setup-commit-signing@main
with:
signing_key: ${{ secrets.BREWTESTBOT_SSH_SIGNING_KEY }}
@ -63,7 +64,7 @@ jobs:
git checkout "${BRANCH}"
git checkout "Library/Homebrew/sorbet"
else
git checkout --no-track -B "${BRANCH}" origin/master
git checkout --no-track -B "${BRANCH}" origin/HEAD
fi
fi
@ -80,17 +81,17 @@ jobs:
then
git add "Library/Homebrew/sorbet"
git commit -m "sorbet: Update RBI files." \
-m "Autogenerated by the [sorbet](https://github.com/Homebrew/brew/blob/master/.github/workflows/sorbet.yml) workflow."
-m "Autogenerated by the [sorbet](https://github.com/Homebrew/brew/blob/HEAD/.github/workflows/sorbet.yml) workflow."
if ! git diff --stat --exit-code "Library/Homebrew"
then
git add "Library/Homebrew/"
git commit -m "sorbet: Autobump sigils via Spoom" \
-m "Autogenerated by the [sorbet](https://github.com/Homebrew/brew/blob/master/.github/workflows/sorbet.yml) workflow."
-m "Autogenerated by the [sorbet](https://github.com/Homebrew/brew/blob/HEAD/.github/workflows/sorbet.yml) workflow."
fi
echo "committed=true" >> "$GITHUB_OUTPUT"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state")"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state" || true)"
if [[ "${PULL_REQUEST_STATE}" != "OPEN" ]]
then
echo "pull_request=true" >> "$GITHUB_OUTPUT"
@ -99,13 +100,13 @@ jobs:
- name: Push commits
if: steps.commit.outputs.committed == 'true'
uses: Homebrew/actions/git-try-push@master
uses: Homebrew/actions/git-try-push@main
with:
token: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
branch: ${{ steps.update.outputs.branch }}
force: true
origin_branch: "master"
origin_branch: "HEAD"
- name: Open a pull request
if: steps.commit.outputs.pull_request == 'true'
@ -113,3 +114,26 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
issue:
needs: tapioca
if: always() && github.event_name == 'schedule'
runs-on: ubuntu-latest
env:
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
permissions:
# To create or update issues
issues: write
steps:
- name: Open, update, or close Sorbet issue
uses: Homebrew/actions/create-or-update-issue@main
with:
title: Failed to update RBI files
body: >
The Sorbet workflow [failed](${{ env.RUN_URL }}). No RBI files were updated.
labels: bug
update-existing: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }}
close-existing: ${{ needs.tapioca.result == 'success' }}
close-from-author: github-actions[bot]
close-comment: >
The Sorbet workflow [succeeded](${{ env.RUN_URL }}). Closing this issue.

View File

@ -4,6 +4,7 @@ on:
paths:
- .github/workflows/spdx.yml
branches-ignore:
- main
- master
schedule:
- cron: "0 0 * * *"
@ -23,19 +24,19 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
test-bot: false
- name: Configure Git user
uses: Homebrew/actions/git-user-config@master
uses: Homebrew/actions/git-user-config@main
with:
username: BrewTestBot
- name: Set up commit signing
uses: Homebrew/actions/setup-commit-signing@master
uses: Homebrew/actions/setup-commit-signing@main
with:
signing_key: ${{ secrets.BREWTESTBOT_SSH_SIGNING_KEY }}
@ -55,15 +56,16 @@ jobs:
git checkout "${BRANCH}"
git checkout "Library/Homebrew/data/spdx"
else
git checkout --no-track -B "${BRANCH}" origin/master
git checkout --no-track -B "${BRANCH}" origin/HEAD
fi
if brew update-license-data
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)."
git commit -m "spdx: update license data." -m "Autogenerated by [a scheduled GitHub Action](https://github.com/Homebrew/brew/blob/HEAD/.github/workflows/spdx.yml)."
echo "committed=true" >> "$GITHUB_OUTPUT"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state")"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state" || true)"
if [[ "${PULL_REQUEST_STATE}" != "OPEN" ]]
then
echo "pull_request=true" >> "$GITHUB_OUTPUT"
@ -72,13 +74,13 @@ jobs:
- name: Push commits
if: steps.update.outputs.committed == 'true'
uses: Homebrew/actions/git-try-push@master
uses: Homebrew/actions/git-try-push@main
with:
token: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
branch: ${{ steps.update.outputs.branch }}
force: true
origin_branch: "master"
origin_branch: "HEAD"
- name: Open a pull request
if: steps.update.outputs.pull_request == 'true'
@ -86,3 +88,26 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
issue:
needs: spdx
if: always() && github.event_name == 'schedule'
runs-on: ubuntu-latest
env:
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
permissions:
# To create or update issues
issues: write
steps:
- name: Open, update, or close SPDX issue
uses: Homebrew/actions/create-or-update-issue@main
with:
title: Failed to update SPDX license data
body: >
The SPDX license data workflow [failed](${{ env.RUN_URL }}). No SPDX license data was updated.
labels: bug
update-existing: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }}
close-existing: ${{ needs.spdx.result == 'success' }}
close-from-author: github-actions[bot]
close-comment: >
The SPDX license data workflow [succeeded](${{ env.RUN_URL }}). Closing this issue.

View File

@ -3,6 +3,7 @@ name: Update sponsors, maintainers, manpage and completions
on:
push:
branches:
- main
- master
paths:
- .github/workflows/sponsors-maintainers-man-completions.yml
@ -32,19 +33,19 @@ jobs:
steps:
- name: Setup Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
test-bot: false
- name: Configure Git user
uses: Homebrew/actions/git-user-config@master
uses: Homebrew/actions/git-user-config@main
with:
username: BrewTestBot
- name: Set up commit signing
uses: Homebrew/actions/setup-commit-signing@master
uses: Homebrew/actions/setup-commit-signing@main
with:
signing_key: ${{ secrets.BREWTESTBOT_SSH_SIGNING_KEY }}
@ -60,7 +61,7 @@ jobs:
run: |
git fetch origin
if [[ -n "$GITHUB_REF_NAME" && "$GITHUB_REF_NAME" != "master" ]]
if [[ -n "$GITHUB_REF_NAME" && "$GITHUB_REF_NAME" != "master" && "$GITHUB_REF_NAME" != "main" ]]
then
BRANCH="$GITHUB_REF_NAME"
else
@ -76,7 +77,7 @@ jobs:
"manpages/brew.1" \
"completions"
else
git checkout --force --no-track -B "${BRANCH}" origin/master
git checkout --force --no-track -B "${BRANCH}" origin/HEAD
fi
if brew update-sponsors
@ -111,7 +112,7 @@ jobs:
if [[ -n "${COMMITTED-}" ]]
then
echo "committed=true" >> "$GITHUB_OUTPUT"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state")"
PULL_REQUEST_STATE="$(gh pr view --json=state | jq -r ".state" || true)"
if [[ "${PULL_REQUEST_STATE}" != "OPEN" ]]
then
echo "pull_request=true" >> "$GITHUB_OUTPUT"
@ -124,7 +125,7 @@ jobs:
- name: Push commits
if: steps.update.outputs.committed == 'true'
uses: Homebrew/actions/git-try-push@master
uses: Homebrew/actions/git-try-push@main
with:
token: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
@ -137,3 +138,26 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.HOMEBREW_GITHUB_PUBLIC_REPO_TOKEN }}
working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
issue:
needs: updates
if: always() && github.event_name == 'schedule'
runs-on: ubuntu-latest
env:
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
permissions:
# To create or update issues
issues: write
steps:
- name: Open, update, or close sponsors, maintainers, manpage and completions issue
uses: Homebrew/actions/create-or-update-issue@main
with:
title: Failed to update sponsors, maintainers, manpage and completions
body: >
The sponsors, maintainers, manpage and completions workflow [failed](${{ env.RUN_URL }}). No sponsors, maintainers, manpage and completions were updated.
labels: bug
update-existing: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }}
close-existing: ${{ needs.updates.result == 'success' }}
close-from-author: github-actions[bot]
close-comment: >
The sponsors, maintainers, manpage and completions workflow [succeeded](${{ env.RUN_URL }}). Closing this issue.

View File

@ -0,0 +1,63 @@
name: Sync default branches
on:
push:
branches:
- main
- master
pull_request:
paths:
- .github/workflows/sync-default-branches.yml
permissions: {}
defaults:
run:
shell: bash -xeuo pipefail {0}
concurrency:
group: "sync-default-branches-${{ github.ref }}"
cancel-in-progress: true
jobs:
sync:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Configure Git user
uses: Homebrew/actions/git-user-config@main
with:
username: github-actions[bot]
- name: Determine source and target branches
id: branches
run: |
if [[ "${GITHUB_REF_NAME}" == "main" ]]; then
target="master"
source="main"
else
target="main"
source="master"
fi
echo "target=${target}" >> "$GITHUB_OUTPUT"
echo "source=${source}" >> "$GITHUB_OUTPUT"
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
persist-credentials: true
- name: Setup target branch
run: |
git checkout "${TARGET_BRANCH}" || git checkout -b "${TARGET_BRANCH}"
git reset --hard "origin/${SOURCE_BRANCH}"
env:
SOURCE_BRANCH: ${{ steps.branches.outputs.source }}
TARGET_BRANCH: ${{ steps.branches.outputs.target }}
- name: Push target branch
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
run: git push origin "${TARGET_BRANCH}" --force-with-lease
env:
TARGET_BRANCH: ${{ steps.branches.outputs.target }}

View File

@ -3,6 +3,7 @@ name: CI
on:
push:
branches:
- main
- master
pull_request:
merge_group:
@ -32,7 +33,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -84,7 +85,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: true
cask: true
@ -135,11 +136,12 @@ jobs:
if: github.repository_owner == 'Homebrew' && github.event_name != 'push'
runs-on: ubuntu-latest
container:
# TODO: switch to main when we're pushing those images
image: ghcr.io/homebrew/brew:master
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -162,7 +164,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: true
@ -185,14 +187,14 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
test-bot: false
- name: Configure Git user
uses: Homebrew/actions/git-user-config@master
uses: Homebrew/actions/git-user-config@main
with:
username: BrewTestBot
@ -220,7 +222,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -255,7 +257,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
# We only test needs_homebrew_core tests on macOS because
# homebrew/core is not available by default on GitHub-hosted Ubuntu
@ -355,6 +357,7 @@ jobs:
container: ghcr.io/homebrew/ubuntu24.04:latest
- name: test-bot (Linux x86_64)
runs-on: ubuntu-latest
# TODO: switch to main when we've migrated to it
container: ghcr.io/homebrew/ubuntu22.04:master
# Use Debian Old Stable for testing Homebrew's glibc support.
- name: test-bot (Linux Homebrew glibc)
@ -402,7 +405,7 @@ jobs:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -442,7 +445,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -496,7 +499,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
- name: Setup Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0

View File

@ -9,6 +9,7 @@ on:
paths:
- .github/workflows/vendor-gems.yml
branches-ignore:
- main
- master
workflow_dispatch:
inputs:
@ -31,7 +32,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false
@ -39,13 +40,13 @@ jobs:
- name: Configure Git user
if: github.event_name == 'workflow_dispatch'
uses: Homebrew/actions/git-user-config@master
uses: Homebrew/actions/git-user-config@main
with:
username: BrewTestBot
- name: Set up commit signing
if: github.event_name == 'workflow_dispatch'
uses: Homebrew/actions/setup-commit-signing@master
uses: Homebrew/actions/setup-commit-signing@main
with:
signing_key: ${{ secrets.BREWTESTBOT_SSH_SIGNING_KEY }}
@ -100,7 +101,7 @@ jobs:
- name: Push to pull request
if: github.event_name == 'workflow_dispatch'
uses: Homebrew/actions/git-try-push@master
uses: Homebrew/actions/git-try-push@main
with:
token: ${{ steps.app-token.outputs.token }}
directory: ${{ steps.set-up-homebrew.outputs.repository-path }}

View File

@ -19,7 +19,7 @@ jobs:
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
core: false
cask: false

1
.github/zizmor.yml vendored
View File

@ -1,3 +1,4 @@
# This file is synced from the `.github` repository, do not modify it directly.
rules:
unpinned-uses:
config:

11
.vscode/mcp.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"servers": {
"Homebrew": {
"type": "stdio",
"command": "brew",
"args": [
"mcp-server"
]
}
}
}

View File

@ -1,5 +1,12 @@
#!/bin/bash
HOMEBREW_PREFIX="$(cd "$(dirname "$0")"/../ && pwd)"
if [[ -n "${BASH_SOURCE[0]}" ]]; then
SCRIPT_PATH="${BASH_SOURCE[0]}"
elif [[ -n "${ZSH_VERSION}" ]]; then
SCRIPT_PATH="${(%):-%x}"
else
SCRIPT_PATH="$0"
fi
HOMEBREW_PREFIX="$(cd "$(dirname "${SCRIPT_PATH}")"/../ && pwd)"
"${HOMEBREW_PREFIX}/bin/brew" install-bundler-gems --add-groups=style,typecheck,vscode >/dev/null 2>&1

View File

@ -40,7 +40,6 @@
"id": "default",
"name": "Brew Typecheck",
"description": "Default configuration",
"cwd": "${workspaceFolder}",
"command": [
"./bin/brew",
"typecheck",

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "api/analytics"
@ -11,10 +11,10 @@ module Homebrew
module API
extend Cachable
HOMEBREW_CACHE_API = (HOMEBREW_CACHE/"api").freeze
HOMEBREW_CACHE_API_SOURCE = (HOMEBREW_CACHE/"api-source").freeze
HOMEBREW_CACHE_API = T.let((HOMEBREW_CACHE/"api").freeze, Pathname)
HOMEBREW_CACHE_API_SOURCE = T.let((HOMEBREW_CACHE/"api-source").freeze, Pathname)
sig { params(endpoint: String).returns(Hash) }
sig { params(endpoint: String).returns(T::Hash[String, T.untyped]) }
def self.fetch(endpoint)
return cache[endpoint] if cache.present? && cache.key?(endpoint)
@ -33,7 +33,8 @@ module Homebrew
end
sig {
params(endpoint: String, target: Pathname, stale_seconds: Integer).returns([T.any(Array, Hash), T::Boolean])
params(endpoint: String, target: Pathname,
stale_seconds: Integer).returns([T.any(T::Array[T.untyped], T::Hash[String, T.untyped]), T::Boolean])
}
def self.fetch_json_api_file(endpoint, target: HOMEBREW_CACHE_API/endpoint,
stale_seconds: Homebrew::EnvConfig.api_auto_update_secs.to_i)
@ -96,7 +97,8 @@ module Homebrew
mtime = insecure_download ? Time.new(1970, 1, 1) : Time.now
FileUtils.touch(target, mtime:) unless skip_download
JSON.parse(target.read(encoding: Encoding::UTF_8), freeze: true)
# Can use `target.read` again when/if https://github.com/sorbet/sorbet/pull/8999 is merged/released.
JSON.parse(File.read(target, encoding: Encoding::UTF_8), freeze: true)
rescue JSON::ParserError
target.unlink
retry_count += 1
@ -122,8 +124,11 @@ module Homebrew
end
end
sig { params(json: Hash, bottle_tag: T.nilable(::Utils::Bottles::Tag)).returns(Hash) }
def self.merge_variations(json, bottle_tag: nil)
sig {
params(json: T::Hash[String, T.untyped],
bottle_tag: ::Utils::Bottles::Tag).returns(T::Hash[String, T.untyped])
}
def self.merge_variations(json, bottle_tag: T.unsafe(nil))
return json unless json.key?("variations")
bottle_tag ||= Homebrew::SimulateSystem.current_tag
@ -147,7 +152,10 @@ module Homebrew
false
end
sig { params(json_data: Hash).returns([T::Boolean, T.any(String, Array, Hash)]) }
sig {
params(json_data: T::Hash[String, T.untyped])
.returns([T::Boolean, T.any(String, T::Array[T.untyped], T::Hash[String, T.untyped])])
}
private_class_method def self.verify_and_parse_jws(json_data)
signatures = json_data["signatures"]
homebrew_signature = signatures&.find { |sig| sig.dig("header", "kid") == "homebrew-1" }

View File

@ -10,7 +10,6 @@ module Homebrew
def analytics_api_path
"analytics"
end
alias generic_analytics_api_path analytics_api_path
sig { params(category: String, days: T.any(Integer, String)).returns(T::Hash[String, T.untyped]) }
def fetch(category, days)

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "cachable"
@ -21,7 +21,7 @@ module Homebrew
private_class_method :cache
sig { params(token: String).returns(Hash) }
sig { params(token: String).returns(T::Hash[String, T.untyped]) }
def self.fetch(token)
Homebrew::API.fetch "cask/#{token}.json"
end
@ -47,6 +47,7 @@ module Homebrew
.load(config: cask.config)
end
sig { returns(Pathname) }
def self.cached_json_file_path
HOMEBREW_CACHE_API/api_filename
end
@ -70,7 +71,7 @@ module Homebrew
end
private_class_method :download_and_cache_data!
sig { returns(T::Hash[String, Hash]) }
sig { returns(T::Hash[String, T::Hash[String, T.untyped]]) }
def self.all_casks
unless cache.key?("casks")
json_updated = download_and_cache_data!

View File

@ -1,22 +1,26 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
# Used to substitute common paths with generic placeholders when generating JSON for the API.
module APIHashable
sig { void }
def generating_hash!
return if generating_hash?
# Apply monkeypatches for API generation
@old_homebrew_prefix = HOMEBREW_PREFIX
@old_homebrew_cellar = HOMEBREW_CELLAR
@old_home = Dir.home
@old_homebrew_prefix = T.let(HOMEBREW_PREFIX, T.nilable(Pathname))
@old_homebrew_cellar = T.let(HOMEBREW_CELLAR, T.nilable(Pathname))
@old_home = T.let(Dir.home, T.nilable(String))
@old_git_config_global = T.let(ENV.fetch("GIT_CONFIG_GLOBAL", nil), T.nilable(String))
Object.send(:remove_const, :HOMEBREW_PREFIX)
Object.const_set(:HOMEBREW_PREFIX, Pathname.new(HOMEBREW_PREFIX_PLACEHOLDER))
ENV["HOME"] = HOMEBREW_HOME_PLACEHOLDER
ENV["GIT_CONFIG_GLOBAL"] = File.join(@old_home, ".gitconfig")
@generating_hash = true
@generating_hash = T.let(true, T.nilable(T::Boolean))
end
sig { void }
def generated_hash!
return unless generating_hash?
@ -24,10 +28,12 @@ module APIHashable
Object.send(:remove_const, :HOMEBREW_PREFIX)
Object.const_set(:HOMEBREW_PREFIX, @old_homebrew_prefix)
ENV["HOME"] = @old_home
ENV["GIT_CONFIG_GLOBAL"] = @old_git_config_global
@generating_hash = false
end
sig { returns(T::Boolean) }
def generating_hash?
@generating_hash ||= false
@generating_hash == true

View File

@ -52,4 +52,4 @@ FORMULA_COMPONENT_PRECEDENCE_LIST = T.let([
[{ name: :caveats, type: :method_definition }],
[{ name: :plist_options, type: :method_call }, { name: :plist, type: :method_definition }],
[{ name: :test, type: :block_call }],
].freeze, T::Array[[{ name: Symbol, type: Symbol }]])
].freeze, T::Array[T::Array[{ name: Symbol, type: Symbol }]])

View File

@ -614,6 +614,8 @@ esac
# and, if needed:
# - MacOSVersion::SYMBOLS
HOMEBREW_MACOS_NEWEST_UNSUPPORTED="16"
# TODO: bump version when new macOS is released
HOMEBREW_MACOS_NEWEST_SUPPORTED="15"
# TODO: bump version when new macOS is released and update references in:
# - docs/Installation.md
# - HOMEBREW_MACOS_OLDEST_SUPPORTED in .github/workflows/pkg-installer.yml
@ -841,6 +843,7 @@ export HOMEBREW_OS_VERSION
export HOMEBREW_MACOS_VERSION
export HOMEBREW_MACOS_VERSION_NUMERIC
export HOMEBREW_MACOS_NEWEST_UNSUPPORTED
export HOMEBREW_MACOS_NEWEST_SUPPORTED
export HOMEBREW_MACOS_OLDEST_SUPPORTED
export HOMEBREW_MACOS_OLDEST_ALLOWED
export HOMEBREW_USER_AGENT

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "bundle/adder"
@ -7,6 +7,7 @@ module Homebrew
module Bundle
module Commands
module Add
sig { params(args: String, type: Symbol, global: T::Boolean, file: T.nilable(String)).void }
def self.run(*args, type:, global:, file:)
Homebrew::Bundle::Adder.add(*args, type:, global:, file:)
end

View File

@ -19,7 +19,6 @@ module Homebrew
puts "Installing #{name} tap. It is not currently installed." if verbose
args = []
args << "--force" if force
args.append("--force-auto-update") if options[:force_auto_update]
success = if options[:clone_target]
Bundle.brew("tap", name, options[:clone_target], *args, verbose:)

View File

@ -139,7 +139,11 @@ module Cask
def initialize(cask, *dsl_args)
@cask = cask
@dirmethod = nil
@dsl_args = dsl_args.deep_dup
@dsl_key = nil
@english_article = nil
@english_name = nil
end
def config

View File

@ -41,7 +41,9 @@ module Cask
super
target = target_hash[:target]
@source = nil
@source_string = source.to_s
@target = nil
@target_string = target.to_s
end

View File

@ -1,9 +1,14 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
module Cask
# Sorted set containing all cask artifacts.
class ArtifactSet < ::Set
extend T::Generic
Elem = type_member(:out) { { fixed: Artifact::AbstractArtifact } }
sig { params(block: T.nilable(T.proc.params(arg0: Elem).returns(T.untyped))).void }
def each(&block)
return enum_for(T.must(__method__)) { size } unless block
@ -11,6 +16,7 @@ module Cask
self
end
sig { returns(T::Array[Artifact::AbstractArtifact]) }
def to_a
super.sort
end

View File

@ -653,11 +653,12 @@ module Cask
supports_arm = result.merged_output.include?("arm64")
mentions_rosetta = cask.caveats.include?("requires Rosetta 2")
requires_intel = cask.depends_on.arch&.any? { |arch| arch[:type] == :intel }
if supports_arm && mentions_rosetta
add_error "Artifacts do not require Rosetta 2 but the caveats say otherwise!",
location: url.location
elsif !supports_arm && !mentions_rosetta
elsif !supports_arm && !mentions_rosetta && !requires_intel
add_error "Artifacts require Rosetta 2 but this is not indicated by the caveats!",
location: url.location
end
@ -701,45 +702,53 @@ module Cask
return unless online?
return unless strict?
odebug "Auditing minimum OS version"
odebug "Auditing minimum macOS version"
plist_min_os = cask_plist_min_os
sparkle_min_os = livecheck_min_os
bundle_min_os = cask_bundle_min_os
sparkle_min_os = cask_sparkle_min_os
app_min_os = [bundle_min_os, sparkle_min_os].compact.max
debug_messages = []
debug_messages << "Plist #{plist_min_os}" if plist_min_os
debug_messages << "Sparkle #{sparkle_min_os}" if sparkle_min_os
odebug "Detected minimum OS version: #{debug_messages.join(" | ")}" unless debug_messages.empty?
min_os = [plist_min_os, sparkle_min_os].compact.max
return if min_os.nil? || min_os <= HOMEBREW_MACOS_OLDEST_ALLOWED
debug_messages << "from artifact: #{bundle_min_os.to_sym}" if bundle_min_os
debug_messages << "from upstream: #{sparkle_min_os.to_sym}" if sparkle_min_os
odebug "Detected minimum macOS: #{app_min_os.to_sym} (#{debug_messages.join(" | ")})" if app_min_os
return if app_min_os.nil? || app_min_os <= HOMEBREW_MACOS_OLDEST_ALLOWED
on_system_block_min_os = cask.on_system_block_min_os
cask_min_os = [on_system_block_min_os, cask.depends_on.macos&.minimum_version].compact.max
odebug "Declared minimum OS version: #{cask_min_os&.to_sym}"
return if cask_min_os&.to_sym == min_os.to_sym
return if cask.on_system_blocks_exist? &&
OnSystem.arch_condition_met?(:arm) &&
depends_on_min_os = cask.depends_on.macos&.minimum_version
cask_min_os = [on_system_block_min_os, depends_on_min_os].compact.max
debug_messages = []
debug_messages << "from on_system block: #{on_system_block_min_os.to_sym}" if on_system_block_min_os
if depends_on_min_os > HOMEBREW_MACOS_OLDEST_ALLOWED
debug_messages << "from depends_on stanza: #{depends_on_min_os.to_sym}"
end
odebug "Declared minimum macOS: #{cask_min_os.to_sym} (#{debug_messages.join(" | ").presence || "default"})"
return if cask_min_os.to_sym == app_min_os.to_sym
# ignore declared minimum OS < 11.x when auditing as ARM a cask with arch-specific artifacts
return if OnSystem.arch_condition_met?(:arm) &&
cask.on_system_blocks_exist? &&
cask_min_os.present? &&
cask_min_os < MacOSVersion.new("11")
min_os_definition = if cask_min_os.present?
if on_system_block_min_os.present? &&
on_system_block_min_os > cask.depends_on.macos&.minimum_version
"a block with a minimum OS version of #{cask_min_os.to_sym.inspect}"
min_os_definition = if cask_min_os > HOMEBREW_MACOS_OLDEST_ALLOWED
definition = if T.must(on_system_block_min_os.to_s <=> depends_on_min_os.to_s).positive?
"an on_system block"
else
cask_min_os.to_sym.inspect
"a depends_on stanza"
end
"#{definition} with a minimum macOS version of #{cask_min_os.to_sym.inspect}"
else
"no minimum OS version"
"no minimum macOS version"
end
add_error "Upstream defined #{min_os.to_sym.inspect} as the minimum OS version " \
source = T.must(bundle_min_os.to_s <=> sparkle_min_os.to_s).positive? ? "Artifact" : "Upstream"
add_error "#{source} defined #{app_min_os.to_sym.inspect} as the minimum macOS version " \
"but the cask declared #{min_os_definition}",
strict_only: true
end
sig { returns(T.nilable(MacOSVersion)) }
def livecheck_min_os
def cask_sparkle_min_os
return unless online?
return unless cask.livecheck_defined?
return if cask.livecheck.strategy != :sparkle
@ -772,10 +781,10 @@ module Cask
end
sig { returns(T.nilable(MacOSVersion)) }
def cask_plist_min_os
def cask_bundle_min_os
return unless online?
plist_min_os = T.let(nil, T.untyped)
min_os = T.let(nil, T.untyped)
@staged_path ||= cask.staged_path
extract_artifacts do |artifacts, tmpdir|
@ -786,13 +795,33 @@ module Cask
next unless File.exist?(plist_path)
plist = system_command!("plutil", args: ["-convert", "xml1", "-o", "-", plist_path]).plist
plist_min_os = plist["LSMinimumSystemVersion"].presence
break if plist_min_os
min_os = plist["LSMinimumSystemVersion"].presence
break if min_os
next unless (main_binary = get_plist_main_binary(path))
next if !File.exist?(main_binary) || File.open(main_binary, "rb") { |f| f.read(2) == "#!" }
macho = MachO.open(main_binary)
min_os = case macho
when MachO::MachOFile
[
macho[:LC_VERSION_MIN_MACOSX].first&.version_string,
macho[:LC_BUILD_VERSION].first&.minos_string,
]
when MachO::FatFile
macho.machos.map do |slice|
[
slice[:LC_VERSION_MIN_MACOSX].first&.version_string,
slice[:LC_BUILD_VERSION].first&.minos_string,
]
end.flatten
end.compact.min
break if min_os
end
end
begin
MacOSVersion.new(plist_min_os).strip_patch
MacOSVersion.new(min_os).strip_patch
rescue MacOSVersion::Error
nil
end

View File

@ -295,7 +295,7 @@ module Cask
sig { returns(Pathname) }
attr_reader :path
sig { returns(T.nilable(T::Hash[T.any(String, Symbol), T.anything])) }
sig { returns(T.nilable(T::Hash[String, T.untyped])) }
attr_reader :from_json
sig {
@ -320,7 +320,7 @@ module Cask
sig {
params(
token: String,
from_json: T.nilable(T::Hash[T.any(String, Symbol), T.anything]),
from_json: T.nilable(T::Hash[String, T.untyped]),
path: T.nilable(Pathname),
).void
}

View File

@ -69,7 +69,6 @@ module Cask
].freeze
DSL_METHODS = Set.new([
:appcast,
:arch,
:artifacts,
:auto_updates,
@ -123,15 +122,21 @@ module Cask
sig { params(cask: Cask).void }
def initialize(cask)
# NOTE: Variables set by `set_unique_stanza` must be initialized to `nil`.
@auto_updates = T.let(nil, T.nilable(T::Boolean))
# NOTE: `:"@#{stanza}"` variables set by `set_unique_stanza` must be
# initialized to `nil`.
@arch = T.let(nil, T.nilable(String))
@arch_set_in_block = T.let(false, T::Boolean)
@artifacts = T.let(ArtifactSet.new, ArtifactSet)
@auto_updates = T.let(nil, T.nilable(T::Boolean))
@auto_updates_set_in_block = T.let(false, T::Boolean)
@autobump = T.let(true, T::Boolean)
@called_in_on_system_block = T.let(false, T::Boolean)
@cask = T.let(cask, Cask)
@caveats = T.let(DSL::Caveats.new(cask), DSL::Caveats)
@conflicts_with = T.let(nil, T.nilable(DSL::ConflictsWith))
@conflicts_with_set_in_block = T.let(false, T::Boolean)
@container = T.let(nil, T.nilable(DSL::Container))
@container_set_in_block = T.let(false, T::Boolean)
@depends_on = T.let(DSL::DependsOn.new, DSL::DependsOn)
@depends_on_set_in_block = T.let(false, T::Boolean)
@deprecated = T.let(false, T::Boolean)
@ -140,27 +145,32 @@ module Cask
@deprecation_replacement_cask = T.let(nil, T.nilable(String))
@deprecation_replacement_formula = T.let(nil, T.nilable(String))
@desc = T.let(nil, T.nilable(String))
@desc_set_in_block = T.let(false, T::Boolean)
@disable_date = T.let(nil, T.nilable(Date))
@disable_reason = T.let(nil, T.nilable(T.any(String, Symbol)))
@disable_replacement_cask = T.let(nil, T.nilable(String))
@disable_replacement_formula = T.let(nil, T.nilable(String))
@disabled = T.let(false, T::Boolean)
@homepage = T.let(nil, T.nilable(String))
@homepage_set_in_block = T.let(false, T::Boolean)
@language_blocks = T.let({}, T::Hash[T::Array[String], Proc])
@language_eval = T.let(nil, T.nilable(String))
@livecheck = T.let(Livecheck.new(cask), Livecheck)
@livecheck_defined = T.let(false, T::Boolean)
@name = T.let([], T::Array[String])
@autobump = T.let(true, T::Boolean)
@no_autobump_defined = T.let(false, T::Boolean)
@on_system_blocks_exist = T.let(false, T::Boolean)
@os = T.let(nil, T.nilable(String))
@on_system_block_min_os = T.let(nil, T.nilable(MacOSVersion))
@os = T.let(nil, T.nilable(String))
@os_set_in_block = T.let(false, T::Boolean)
@sha256 = T.let(nil, T.nilable(T.any(Checksum, Symbol)))
@sha256_set_in_block = T.let(false, T::Boolean)
@staged_path = T.let(nil, T.nilable(Pathname))
@token = T.let(cask.token, String)
@url = T.let(nil, T.nilable(URL))
@url_set_in_block = T.let(false, T::Boolean)
@version = T.let(nil, T.nilable(DSL::Version))
@version_set_in_block = T.let(false, T::Boolean)
end
sig { returns(T::Boolean) }
@ -216,7 +226,7 @@ module Cask
raise CaskInvalidError.new(cask, "'#{stanza}' stanza may only appear once.")
end
if instance_variable_defined?(:"@#{stanza}_set_in_block") && @called_in_on_system_block
if instance_variable_get(:"@#{stanza}_set_in_block") && @called_in_on_system_block
raise CaskInvalidError.new(cask, "'#{stanza}' stanza may only be overridden once.")
end
end
@ -476,7 +486,7 @@ module Cask
def add_implicit_macos_dependency
return if (cask_depends_on = @depends_on).present? && cask_depends_on.macos.present?
depends_on macos: ">= :#{MacOSVersion::SYMBOLS.key MacOSVersion::SYMBOLS.values.min}"
depends_on macos: ">= #{MacOSVersion.new(HOMEBREW_MACOS_OLDEST_ALLOWED).to_sym.inspect}"
end
# Declare conflicts that keep a cask from installing or working correctly.

View File

@ -52,16 +52,17 @@ module Cask
raise "Only a single 'depends_on macos' is allowed." if defined?(@macos)
# workaround for https://github.com/sorbet/sorbet/issues/6860
first_arg = args.first&.to_s
first_arg = args.first
first_arg_s = first_arg&.to_s
begin
@macos = if args.count > 1
MacOSRequirement.new([args], comparator: "==")
elsif MacOSVersion::SYMBOLS.key?(args.first)
elsif first_arg.is_a?(Symbol) && MacOSVersion::SYMBOLS.key?(first_arg)
MacOSRequirement.new([args.first], comparator: "==")
elsif (md = /^\s*(?<comparator><|>|[=<>]=)\s*:(?<version>\S+)\s*$/.match(first_arg))
elsif (md = /^\s*(?<comparator><|>|[=<>]=)\s*:(?<version>\S+)\s*$/.match(first_arg_s))
MacOSRequirement.new([T.must(md[:version]).to_sym], comparator: md[:comparator])
elsif (md = /^\s*(?<comparator><|>|[=<>]=)\s*(?<version>\S+)\s*$/.match(first_arg))
elsif (md = /^\s*(?<comparator><|>|[=<>]=)\s*(?<version>\S+)\s*$/.match(first_arg_s))
MacOSRequirement.new([md[:version]], comparator: md[:comparator])
# This is not duplicate of the first case: see `args.first` and a different comparator.
else # rubocop:disable Lint/DuplicateBranch

View File

@ -4,6 +4,7 @@
require "formula_installer"
require "unpack_strategy"
require "utils/topological_hash"
require "utils/analytics"
require "cask/config"
require "cask/download"
@ -303,6 +304,20 @@ on_request: true)
next if artifact.is_a?(Artifact::Binary) && !binaries?
artifact = T.cast(
artifact,
T.any(
Artifact::AbstractFlightBlock,
Artifact::Installer,
Artifact::KeyboardLayout,
Artifact::Mdimporter,
Artifact::Moved,
Artifact::Pkg,
Artifact::Qlplugin,
Artifact::Symlinked,
),
)
artifact.install_phase(
command: @command, verbose: verbose?, adopt: adopt?, auto_updates: @cask.auto_updates,
force: force?, predecessor:
@ -548,6 +563,18 @@ on_request: true)
artifacts.each do |artifact|
if artifact.respond_to?(:uninstall_phase)
artifact = T.cast(
artifact,
T.any(
Artifact::AbstractFlightBlock,
Artifact::KeyboardLayout,
Artifact::Moved,
Artifact::Qlplugin,
Artifact::Symlinked,
Artifact::Uninstall,
),
)
odebug "Uninstalling artifact of class #{artifact.class}"
artifact.uninstall_phase(
command: @command,
@ -562,6 +589,8 @@ on_request: true)
next unless artifact.respond_to?(:post_uninstall_phase)
artifact = T.cast(artifact, Artifact::Uninstall)
odebug "Post-uninstalling artifact of class #{artifact.class}"
artifact.post_uninstall_phase(
command: @command,

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "abstract_command"
@ -6,6 +6,7 @@ require "formula"
require "fetch"
require "cask/download"
require "retryable_download"
require "download_queue"
module Homebrew
module Cmd
@ -69,15 +70,16 @@ module Homebrew
named_args [:formula, :cask], min: 1
end
sig { returns(Integer) }
def concurrency
@concurrency ||= args.concurrency&.to_i || 1
@concurrency ||= T.let(args.concurrency&.to_i || 1, T.nilable(Integer))
end
sig { returns(DownloadQueue) }
def download_queue
@download_queue ||= begin
require "download_queue"
@download_queue ||= T.let(begin
DownloadQueue.new(concurrency)
end
end, T.nilable(DownloadQueue))
end
class Spinner
@ -96,8 +98,8 @@ module Homebrew
sig { void }
def initialize
@start = Time.now
@i = 0
@start = T.let(Time.now, Time)
@i = T.let(0, Integer)
end
sig { returns(String) }
@ -136,7 +138,7 @@ module Homebrew
bucket.each do |formula_or_cask|
case formula_or_cask
when Formula
formula = T.cast(formula_or_cask, Formula)
formula = formula_or_cask
ref = formula.loaded_from_api? ? formula.full_name : formula.path
os_arch_combinations.each do |os, arch|
@ -189,7 +191,9 @@ module Homebrew
next if fetched_bottle
fetch_downloadable(formula.resource)
if (resource = formula.resource)
fetch_downloadable(resource)
end
formula.resources.each do |r|
fetch_downloadable(r)
@ -231,7 +235,7 @@ module Homebrew
end
else
spinner = Spinner.new
remaining_downloads = downloads.dup
remaining_downloads = downloads.dup.to_a
previous_pending_line_count = 0
begin
@ -332,10 +336,13 @@ module Homebrew
private
sig { returns(T::Hash[T.any(Resource, Bottle, Cask::Download), Concurrent::Promises::Future]) }
def downloads
@downloads ||= {}
@downloads ||= T.let({}, T.nilable(T::Hash[T.any(Resource, Bottle, Cask::Download),
Concurrent::Promises::Future]))
end
sig { params(downloadable: T.any(Resource, Bottle, Cask::Download)).void }
def fetch_downloadable(downloadable)
downloads[downloadable] ||= begin
tries = args.retry? ? {} : { tries: 1 }

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "abstract_command"
@ -18,7 +18,7 @@ module Homebrew
class Info < AbstractCommand
VALID_DAYS = %w[30 90 365].freeze
VALID_FORMULA_CATEGORIES = %w[install install-on-request build-error].freeze
VALID_CATEGORIES = (VALID_FORMULA_CATEGORIES + %w[cask-install os-version]).freeze
VALID_CATEGORIES = T.let((VALID_FORMULA_CATEGORIES + %w[cask-install os-version]).freeze, T::Array[String])
cmd_args do
description <<~EOS
@ -96,14 +96,17 @@ module Homebrew
end
print_analytics
elsif args.json
elsif (json = args.json)
all = args.eval_all?
print_json(all)
print_json(json, all)
elsif args.github?
raise FormulaOrCaskUnspecifiedError if args.no_named?
exec_browser(*args.named.to_formulae_and_casks.map { |f| github_info(f) })
exec_browser(*args.named.to_formulae_and_casks.map do |formula_keg_or_cask|
formula_or_cask = T.cast(formula_keg_or_cask, T.any(Formula, Cask::Cask))
github_info(formula_or_cask)
end)
elsif args.no_named?
print_statistics
else
@ -111,6 +114,7 @@ module Homebrew
end
end
sig { params(remote: String, path: String).returns(String) }
def github_remote_path(remote, path)
if remote =~ %r{^(?:https?://|git(?:@|://))github\.com[:/](.+)/(.+?)(?:\.git)?$}
"https://github.com/#{Regexp.last_match(1)}/#{Regexp.last_match(2)}/blob/HEAD/#{path}"
@ -175,6 +179,7 @@ module Homebrew
end
end
sig { params(version: T.any(T::Boolean, String)).returns(Symbol) }
def json_version(version)
version_hash = {
true => :default,
@ -187,11 +192,11 @@ module Homebrew
version_hash[version]
end
sig { params(all: T::Boolean).void }
def print_json(all)
sig { params(json: T.any(T::Boolean, String), all: T::Boolean).void }
def print_json(json, all)
raise FormulaOrCaskUnspecifiedError if !(all || args.installed?) && args.no_named?
json = case json_version(args.json)
json = case json_version(json)
when :v1, :default
raise UsageError, "Cannot specify `--cask` when using `--json=v1`!" if args.cask?
@ -240,25 +245,31 @@ module Homebrew
puts JSON.pretty_generate(json)
end
sig { params(formula_or_cask: T.any(Formula, Cask::Cask)).returns(String) }
def github_info(formula_or_cask)
return formula_or_cask.path if formula_or_cask.tap.blank? || formula_or_cask.tap.remote.blank?
path = case formula_or_cask
when Formula
formula = formula_or_cask
formula.path.relative_path_from(T.must(formula.tap).path)
tap = formula.tap
return formula.path.to_s if tap.blank? || tap.remote.blank?
formula.path.relative_path_from(tap.path)
when Cask::Cask
cask = formula_or_cask
tap = cask.tap
return cask.sourcefile_path.to_s if tap.blank? || tap.remote.blank?
if cask.sourcefile_path.blank? || cask.sourcefile_path.extname != ".rb"
return "#{cask.tap.default_remote}/blob/HEAD/#{cask.tap.relative_cask_path(cask.token)}"
return "#{tap.default_remote}/blob/HEAD/#{tap.relative_cask_path(cask.token)}"
end
cask.sourcefile_path.relative_path_from(cask.tap.path)
cask.sourcefile_path.relative_path_from(tap.path)
end
github_remote_path(formula_or_cask.tap.remote, path)
github_remote_path(tap.remote, path.to_s)
end
sig { params(formula: Formula).void }
def info_formula(formula)
specs = []
@ -356,6 +367,7 @@ module Homebrew
Utils::Analytics.formula_output(formula, args:)
end
sig { params(dependencies: T::Array[Dependency]).returns(String) }
def decorate_dependencies(dependencies)
deps_status = dependencies.map do |dep|
if dep.satisfied?([])
@ -367,6 +379,7 @@ module Homebrew
deps_status.join(", ")
end
sig { params(requirements: T::Array[Requirement]).returns(String) }
def decorate_requirements(requirements)
req_status = requirements.map do |req|
req_s = req.display_s
@ -375,12 +388,14 @@ module Homebrew
req_status.join(", ")
end
sig { params(dep: Dependency).returns(String) }
def dep_display_s(dep)
return dep.name if dep.option_tags.empty?
"#{dep.name} #{dep.option_tags.map { |o| "--#{o}" }.join(" ")}"
end
sig { params(cask: Cask::Cask).void }
def info_cask(cask)
require "cask/info"

View File

@ -63,6 +63,8 @@ module Homebrew
puts info
else
info = ""
default_branches = %w[main master].freeze
taps.each_with_index do |tap, i|
puts unless i.zero?
info = "#{tap}: "
@ -79,7 +81,7 @@ module Homebrew
info += "\norigin: #{tap.remote}" if tap.remote != tap.default_remote
info += "\nHEAD: #{tap.git_head || "(none)"}"
info += "\nlast commit: #{tap.git_last_commit || "never"}"
info += "\nbranch: #{tap.git_branch || "(none)"}" if tap.git_branch != "master"
info += "\nbranch: #{tap.git_branch || "(none)"}" if default_branches.exclude?(tap.git_branch)
else
info += "Not installed"
end

View File

@ -33,8 +33,6 @@ module Homebrew
"integration.",
replacement: false,
disable: true
switch "--[no-]force-auto-update",
hidden: true
switch "--custom-remote",
description: "Install or change a tap with a custom remote. Useful for mirrors."
switch "--repair",

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "abstract_command"
@ -39,13 +39,15 @@ module Homebrew
private
sig { void }
def auto_update_header
@auto_update_header ||= begin
@auto_update_header ||= T.let(begin
ohai "Auto-updated Homebrew!" if args.auto_update?
true
end
end, T.nilable(T::Boolean))
end
sig { void }
def output_update_report
# Run `brew update` (again) if we've got a linuxbrew-core CoreTap
if CoreTap.instance.installed? && CoreTap.instance.linuxbrew_core? &&
@ -293,14 +295,17 @@ module Homebrew
EOS
end
sig { returns(String) }
def no_changes_message
"No changes to formulae or casks."
end
sig { params(revision: String).returns(String) }
def shorten_revision(revision)
Utils.popen_read("git", "-C", HOMEBREW_REPOSITORY, "rev-parse", "--short", revision).chomp
end
sig { void }
def tap_or_untap_core_taps_if_necessary
return if ENV["HOMEBREW_UPDATE_TEST"]
@ -320,10 +325,11 @@ module Homebrew
return if (HOMEBREW_PREFIX/".homebrewdocker").exist?
tap_output_header_printed = T.let(false, T::Boolean)
default_branches = %w[main master].freeze
[CoreTap.instance, CoreCaskTap.instance].each do |tap|
next unless tap.installed?
if tap.git_branch == "master" &&
if default_branches.include?(tap.git_branch) &&
(Date.parse(T.must(tap.git_repository.last_commit_date)) <= Date.today.prev_month)
ohai "#{tap.name} is old and unneeded, untapping to save space..."
tap.uninstall
@ -339,6 +345,7 @@ module Homebrew
end
end
sig { params(repository: Pathname).void }
def link_completions_manpages_and_docs(repository = HOMEBREW_REPOSITORY)
command = "brew update"
Utils::Link.link_completions(repository, command)
@ -351,10 +358,12 @@ module Homebrew
EOS
end
sig { void }
def migrate_gcc_dependents_if_needed
# do nothing
end
sig { void }
def analytics_message
return if Utils::Analytics.messages_displayed?
return if Utils::Analytics.no_message_output?
@ -384,6 +393,7 @@ module Homebrew
Utils::Analytics.messages_displayed! if $stdout.tty?
end
sig { void }
def donation_message
return if Settings.read("donationmessage") == "true"
@ -394,6 +404,7 @@ module Homebrew
Settings.write "donationmessage", true if $stdout.tty?
end
sig { void }
def install_from_api_message
return if Settings.read("installfromapimessage") == "true"
@ -418,30 +429,38 @@ require "extend/os/cmd/update-report"
class Reporter
class ReporterRevisionUnsetError < RuntimeError
sig { params(var_name: String).void }
def initialize(var_name)
super "#{var_name} is unset!"
end
end
sig {
params(tap: Tap, api_names_txt: T.nilable(Pathname), api_names_before_txt: T.nilable(Pathname),
api_dir_prefix: T.nilable(Pathname)).void
}
def initialize(tap, api_names_txt: nil, api_names_before_txt: nil, api_dir_prefix: nil)
@tap = tap
# This is slightly involved/weird but all the #report logic is shared so it's worth it.
if installed_from_api?(api_names_txt, api_names_before_txt, api_dir_prefix)
@api_names_txt = api_names_txt
@api_names_before_txt = api_names_before_txt
@api_dir_prefix = api_dir_prefix
@api_names_txt = T.let(api_names_txt, T.nilable(Pathname))
@api_names_before_txt = T.let(api_names_before_txt, T.nilable(Pathname))
@api_dir_prefix = T.let(api_dir_prefix, T.nilable(Pathname))
else
initial_revision_var = "HOMEBREW_UPDATE_BEFORE#{tap.repository_var_suffix}"
@initial_revision = ENV[initial_revision_var].to_s
@initial_revision = T.let(ENV[initial_revision_var].to_s, String)
raise ReporterRevisionUnsetError, initial_revision_var if @initial_revision.empty?
current_revision_var = "HOMEBREW_UPDATE_AFTER#{tap.repository_var_suffix}"
@current_revision = ENV[current_revision_var].to_s
@current_revision = T.let(ENV[current_revision_var].to_s, String)
raise ReporterRevisionUnsetError, current_revision_var if @current_revision.empty?
end
@report = T.let(nil, T.nilable(T::Hash[Symbol, T::Array[String]]))
end
sig { params(auto_update: T::Boolean).returns(T::Hash[Symbol, T::Array[String]]) }
def report(auto_update: false)
return @report if @report
@ -482,9 +501,9 @@ class Reporter
case status
when "A", "D"
full_name = tap.formula_file_to_name(src)
name = full_name.split("/").last
name = T.must(full_name.split("/").last)
new_tap = tap.tap_migrations[name]
@report[status.to_sym] << full_name unless new_tap
@report[T.must(status).to_sym] << full_name unless new_tap
when "M"
name = tap.formula_file_to_name(src)
@ -584,6 +603,7 @@ class Reporter
@report
end
sig { returns(T::Boolean) }
def updated?
if installed_from_api?
diff.present?
@ -592,9 +612,10 @@ class Reporter
end
end
sig { void }
def migrate_tap_migration
(report[:D] + report[:DC]).each do |full_name|
name = full_name.split("/").last
(Array(report[:D]) + Array(report[:DC])).each do |full_name|
name = T.must(full_name.split("/").last)
new_tap_name = tap.tap_migrations[name]
next if new_tap_name.nil? # skip if not in tap_migrations list.
@ -609,7 +630,7 @@ class Reporter
end
# This means it is a cask
if report[:DC].include? full_name
if Array(report[:DC]).include? full_name
next unless (HOMEBREW_PREFIX/"Caskroom"/new_name).exist?
new_tap = Tap.fetch(new_tap_name)
@ -675,12 +696,14 @@ class Reporter
end
end
sig { void }
def migrate_cask_rename
Cask::Caskroom.casks.each do |cask|
Cask::Migrator.migrate_if_needed(cask)
end
end
sig { params(force: T::Boolean, verbose: T::Boolean).void }
def migrate_formula_rename(force:, verbose:)
Formula.installed.each do |formula|
next unless Migrator.needs_migration?(formula)
@ -704,14 +727,36 @@ class Reporter
private
attr_reader :tap, :initial_revision, :current_revision, :api_names_txt, :api_names_before_txt, :api_dir_prefix
sig { returns(Tap) }
attr_reader :tap
sig { returns(String) }
attr_reader :initial_revision
sig { returns(String) }
attr_reader :current_revision
sig { returns(T.nilable(Pathname)) }
attr_reader :api_names_txt
sig { returns(T.nilable(Pathname)) }
attr_reader :api_names_before_txt
sig { returns(T.nilable(Pathname)) }
attr_reader :api_dir_prefix
sig {
params(api_names_txt: T.nilable(Pathname), api_names_before_txt: T.nilable(Pathname),
api_dir_prefix: T.nilable(Pathname)).returns(T::Boolean)
}
def installed_from_api?(api_names_txt = @api_names_txt, api_names_before_txt = @api_names_before_txt,
api_dir_prefix = @api_dir_prefix)
!api_names_txt.nil? && !api_names_before_txt.nil? && !api_dir_prefix.nil?
end
sig { returns(String) }
def diff
@diff ||= T.let(nil, T.nilable(String))
@diff ||= if installed_from_api?
# Hack `git diff` output with regexes to look like `git diff-tree` output.
# Yes, I know this is a bit filthy but it saves duplicating the #report logic.
@ -719,12 +764,14 @@ class Reporter
header_regex = /^(---|\+\+\+) /
add_delete_characters = ["+", "-"].freeze
api_dir_prefix_basename = T.must(api_dir_prefix).basename
diff_output.lines.filter_map do |line|
next if line.match?(header_regex)
next unless add_delete_characters.include?(line[0])
line.sub(/^\+/, "A #{api_dir_prefix.basename}/")
.sub(/^-/, "D #{api_dir_prefix.basename}/")
line.sub(/^\+/, "A #{api_dir_prefix_basename}/")
.sub(/^-/, "D #{api_dir_prefix_basename}/")
.sub(/$/, ".rb")
.chomp
end.join("\n")
@ -738,28 +785,33 @@ class Reporter
end
class ReporterHub
sig { returns(T::Array[Reporter]) }
attr_reader :reporters
sig { void }
def initialize
@hash = {}
@reporters = []
@hash = T.let({}, T::Hash[Symbol, T::Array[String]])
@reporters = T.let([], T::Array[Reporter])
end
sig { params(key: Symbol).returns(T::Array[String]) }
def select_formula_or_cask(key)
@hash.fetch(key, [])
end
sig { params(reporter: Reporter, auto_update: T::Boolean).void }
def add(reporter, auto_update: false)
@reporters << reporter
report = reporter.report(auto_update:).delete_if { |_k, v| v.empty? }
@hash.update(report) { |_key, oldval, newval| oldval.concat(newval) }
end
sig { returns(T::Boolean) }
def empty?
@hash.empty?
end
sig { params(auto_update: T::Boolean).void }
def dump(auto_update: false)
unless Homebrew::EnvConfig.no_update_report_new?
dump_new_formula_report
@ -814,12 +866,14 @@ class ReporterHub
private
sig { void }
def dump_new_formula_report
formulae = select_formula_or_cask(:A).sort.reject { |name| installed?(name) }
output_dump_formula_or_cask_report "New Formulae", formulae
end
sig { void }
def dump_new_cask_report
return if Homebrew::SimulateSystem.simulating_or_running_on_linux?
@ -830,6 +884,7 @@ class ReporterHub
output_dump_formula_or_cask_report "New Casks", casks
end
sig { void }
def dump_deleted_formula_report
formulae = select_formula_or_cask(:D).sort.filter_map do |name|
pretty_uninstalled(name) if installed?(name)
@ -838,37 +893,43 @@ class ReporterHub
output_dump_formula_or_cask_report "Deleted Installed Formulae", formulae
end
sig { void }
def dump_deleted_cask_report
return if Homebrew::SimulateSystem.simulating_or_running_on_linux?
casks = select_formula_or_cask(:DC).sort.filter_map do |name|
name = name.split("/").last
name = T.must(name.split("/").last)
pretty_uninstalled(name) if cask_installed?(name)
end
output_dump_formula_or_cask_report "Deleted Installed Casks", casks
end
sig { params(title: String, formulae_or_casks: T::Array[String]).void }
def output_dump_formula_or_cask_report(title, formulae_or_casks)
return if formulae_or_casks.blank?
ohai title, Formatter.columns(formulae_or_casks.sort)
end
sig { params(formula: String).returns(T::Boolean) }
def installed?(formula)
(HOMEBREW_CELLAR/formula.split("/").last).directory?
end
sig { params(formula: String).returns(T::Boolean) }
def outdated?(formula)
Formula[formula].outdated?
rescue FormulaUnavailableError
false
end
sig { params(cask: String).returns(T::Boolean) }
def cask_installed?(cask)
(Cask::Caskroom.path/cask).directory?
end
sig { params(cask: String).returns(T::Boolean) }
def cask_outdated?(cask)
Cask::CaskLoader.load(cask).outdated?
rescue Cask::CaskError

View File

@ -54,9 +54,10 @@ git_init_if_necessary() {
fi
git config remote.origin.url "${HOMEBREW_BREW_GIT_REMOTE}"
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git config fetch.prune true
git fetch --force --tags origin
git remote set-head origin --auto >/dev/null
git reset --hard origin/master
git reset --hard origin/HEAD
SKIP_FETCH_BREW_REPOSITORY=1
set +e
trap - EXIT
@ -77,9 +78,10 @@ git_init_if_necessary() {
fi
git config remote.origin.url "${HOMEBREW_CORE_GIT_REMOTE}"
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch --force origin refs/heads/master:refs/remotes/origin/master
git config fetch.prune true
git fetch --force origin
git remote set-head origin --auto >/dev/null
git reset --hard origin/master
git reset --hard origin/HEAD
SKIP_FETCH_CORE_REPOSITORY=1
set +e
trap - EXIT
@ -110,7 +112,7 @@ upstream_branch() {
upstream_branch="$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null)"
fi
upstream_branch="${upstream_branch#refs/remotes/origin/}"
[[ -z "${upstream_branch}" ]] && upstream_branch="master"
[[ -z "${upstream_branch}" ]] && upstream_branch="main"
echo "${upstream_branch}"
}
@ -242,7 +244,7 @@ merge_or_rebase() {
Could not 'git stash' in ${DIR}!
Please stash/commit manually if you need to keep your changes or, if not, run:
cd ${DIR}
git reset --hard origin/master
git reset --hard origin/HEAD
EOS
fi
git reset --hard "${QUIET_ARGS[@]}"
@ -260,10 +262,12 @@ EOS
then
git checkout --force "${UPSTREAM_BRANCH}" "${QUIET_ARGS[@]}"
else
if [[ -n "${UPSTREAM_TAG}" && "${UPSTREAM_BRANCH}" != "master" ]] &&
[[ "${INITIAL_BRANCH}" != "master" ]]
if [[ -n "${UPSTREAM_TAG}" && "${UPSTREAM_BRANCH}" != "master" && "${UPSTREAM_BRANCH}" != "main" ]] &&
[[ "${INITIAL_BRANCH}" != "master" && "${INITIAL_BRANCH}" != "main" ]]
then
git branch --force "master" "origin/master" "${QUIET_ARGS[@]}"
local detected_upstream_branch
detected_upstream_branch="$(upstream_branch)"
git branch --force "${detected_upstream_branch}" "origin/${detected_upstream_branch}" "${QUIET_ARGS[@]}"
fi
git checkout --force -B "${UPSTREAM_BRANCH}" "${REMOTE_REF}" "${QUIET_ARGS[@]}"
@ -541,7 +545,8 @@ EOS
echo "HOMEBREW_CORE_GIT_REMOTE set: using ${HOMEBREW_CORE_GIT_REMOTE} as the Homebrew/homebrew-core Git remote."
git remote set-url origin "${HOMEBREW_CORE_GIT_REMOTE}"
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch --force origin refs/heads/master:refs/remotes/origin/master
git config fetch.prune true
git fetch --force origin
SKIP_FETCH_CORE_REPOSITORY=1
fi
@ -642,9 +647,9 @@ EOS
UPDATING_MESSAGE_SHOWN=1
fi
# The upstream repository's default branch may not be master;
# The upstream repository's default branch may not be main or master;
# check refs/remotes/origin/HEAD to see what the default
# origin branch name is, and use that. If not set, fall back to "master".
# origin branch name is, and use that. If not set, fall back to "main".
# the refspec ensures that the default upstream branch gets updated
(
UPSTREAM_REPOSITORY_URL="$(git config remote.origin.url)"
@ -732,9 +737,9 @@ EOS
then
local git_errors
git_errors="$(cat "${tmp_failure_file}")"
# Attempt migration from master to main branch.
if [[ "${git_errors}" == "fatal: couldn't find remote ref refs/heads/master" ]]
then
# Attempt migration from master to main branch.
if git fetch --tags --force "${QUIET_ARGS[@]}" origin \
"refs/heads/main:refs/remotes/origin/main" 2>>"${tmp_failure_file}"
then

View File

@ -1,12 +1,12 @@
{
"$schema" : "https://json-schema.org/draft/2019-09/schema",
"$id" : "http://spdx.org/rdf/terms/2.3",
"title" : "SPDX 2.3",
"title" : "SPDX 2.3.1-dev",
"type" : "object",
"properties" : {
"$schema": {
"type": "string",
"description": "Reference the SPDX 2.3 JSON schema."
"description": "Reference the SPDX 2.3.1 JSON schema."
},
"SPDXID" : {
"type" : "string",
@ -90,7 +90,7 @@
"enum" : [ "SHA1", "BLAKE3", "SHA3-384", "SHA256", "SHA384", "BLAKE2b-512", "BLAKE2b-256", "SHA3-512", "MD2", "ADLER32", "MD4", "SHA3-256", "BLAKE2b-384", "SHA512", "MD6", "MD5", "SHA224" ]
},
"checksumValue" : {
"description" : "The checksumValue property provides a lower case hexidecimal encoded digest value produced using a specific algorithm.",
"description" : "The checksumValue property provides a lower case hexadecimal encoded digest value produced using a specific algorithm.",
"type" : "string"
}
},
@ -270,10 +270,10 @@
}
},
"attributionTexts" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConcluded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "array",
"items" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConcluded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "string"
}
},
@ -293,7 +293,7 @@
"enum" : [ "SHA1", "BLAKE3", "SHA3-384", "SHA256", "SHA384", "BLAKE2b-512", "BLAKE2b-256", "SHA3-512", "MD2", "ADLER32", "MD4", "SHA3-256", "BLAKE2b-384", "SHA512", "MD6", "MD5", "SHA224" ]
},
"checksumValue" : {
"description" : "The checksumValue property provides a lower case hexidecimal encoded digest value produced using a specific algorithm.",
"description" : "The checksumValue property provides a lower case hexadecimal encoded digest value produced using a specific algorithm.",
"type" : "string"
}
},
@ -417,7 +417,7 @@
"primaryPackagePurpose" : {
"description" : "This field provides information about the primary purpose of the identified package. Package Purpose is intrinsic to how the package is being used rather than the content of the package.",
"type" : "string",
"enum" : [ "OTHER", "INSTALL", "ARCHIVE", "FIRMWARE", "APPLICATION", "FRAMEWORK", "LIBRARY", "CONTAINER", "SOURCE", "DEVICE", "OPERATING_SYSTEM", "FILE" ]
"enum" : [ "OTHER", "INSTALL", "ARCHIVE", "FIRMWARE", "APPLICATION", "FRAMEWORK", "LIBRARY", "CONTAINER", "SOURCE", "DEVICE", "OPERATING-SYSTEM", "FILE" ]
},
"releaseDate" : {
"description" : "This field provides a place for recording the date the package was released.",
@ -494,10 +494,10 @@
}
},
"attributionTexts" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConcluded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "array",
"items" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConcluded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "string"
}
},
@ -514,7 +514,7 @@
"enum" : [ "SHA1", "BLAKE3", "SHA3-384", "SHA256", "SHA384", "BLAKE2b-512", "BLAKE2b-256", "SHA3-512", "MD2", "ADLER32", "MD4", "SHA3-256", "BLAKE2b-384", "SHA512", "MD6", "MD5", "SHA224" ]
},
"checksumValue" : {
"description" : "The checksumValue property provides a lower case hexidecimal encoded digest value produced using a specific algorithm.",
"description" : "The checksumValue property provides a lower case hexadecimal encoded digest value produced using a specific algorithm.",
"type" : "string"
}
},
@ -624,10 +624,10 @@
}
},
"attributionTexts" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConcluded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "array",
"items" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConcluded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "string"
}
},
@ -709,7 +709,7 @@
}
},
"snippetFromFile" : {
"description" : "SPDX ID for File. File containing the SPDX element (e.g. the file contaning a snippet).",
"description" : "SPDX ID for File. File containing the SPDX element (e.g. the file containing a snippet).",
"type" : "string"
}
},

View File

@ -1,13 +1,15 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "irb"
module IRB
sig { params(binding: Binding).void }
def self.start_within(binding)
old_stdout_sync = $stdout.sync
$stdout.sync = true
@setup_done ||= T.let(false, T.nilable(T::Boolean))
unless @setup_done
setup(nil, argv: [])
@setup_done = true

View File

@ -190,7 +190,7 @@ module Homebrew
def generate_system_options(cask)
current_os = Homebrew::SimulateSystem.current_os
current_os_is_macos = MacOSVersion::SYMBOLS.include?(current_os)
newest_macos = MacOSVersion::SYMBOLS.keys.first
newest_macos = MacOSVersion.new(HOMEBREW_MACOS_NEWEST_SUPPORTED).to_sym
depends_on_archs = cask.depends_on.arch&.filter_map { |arch| arch[:type] }&.uniq

View File

@ -399,7 +399,7 @@ module Homebrew
nil
end
if github_release_data.present?
if github_release_data.present? && github_release_data["body"].present?
pre = "pre" if github_release_data["prerelease"].present?
# maximum length of PR body is 65,536 characters so let's truncate release notes to half of that.
body = Formatter.truncate(github_release_data["body"], max: 32_768)

View File

@ -183,41 +183,42 @@ module Homebrew
:zig
end
fc = FormulaCreator.new(
args.set_name,
args.set_version,
tap: args.tap,
formula_creator = FormulaCreator.new(
url: args.named.fetch(0),
name: args.set_name,
version: args.set_version,
tap: args.tap,
mode:,
license: args.set_license,
fetch: !args.no_fetch?,
head: args.HEAD?,
)
fc.parse_url
# ask for confirmation if name wasn't passed explicitly
if args.set_name.blank?
print "Formula name [#{fc.name}]: "
fc.name = __gets || fc.name
print "Formula name [#{formula_creator.name}]: "
confirmed_name = __gets
formula_creator.name = confirmed_name if confirmed_name.present?
end
fc.verify
formula_creator.verify_tap_available!
# Check for disallowed formula, or names that shadow aliases,
# unless --force is specified.
unless args.force?
if (reason = MissingFormula.disallowed_reason(fc.name))
if (reason = MissingFormula.disallowed_reason(formula_creator.name))
odie <<~EOS
The formula '#{fc.name}' is not allowed to be created.
The formula '#{formula_creator.name}' is not allowed to be created.
#{reason}
If you really want to create this formula use `--force`.
EOS
end
Homebrew.with_no_api_env do
if Formula.aliases.include? fc.name
realname = Formulary.canonical_name(fc.name)
if Formula.aliases.include?(formula_creator.name)
realname = Formulary.canonical_name(formula_creator.name)
odie <<~EOS
The formula '#{realname}' is already aliased to '#{fc.name}'.
The formula '#{realname}' is already aliased to '#{formula_creator.name}'.
Please check that you are not creating a duplicate.
To force creation use `--force`.
EOS
@ -225,19 +226,19 @@ module Homebrew
end
end
path = fc.write_formula!
path = formula_creator.write_formula!
formula = Homebrew.with_no_api_env do
CoreTap.instance.clear_cache
Formula[fc.name]
Formula[formula_creator.name]
end
PyPI.update_python_resources! formula, ignore_non_pypi_packages: true if args.python?
puts <<~EOS
Please audit and test formula before submitting:
HOMEBREW_NO_INSTALL_FROM_API=1 brew audit --new #{fc.name}
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source --verbose --debug #{fc.name}
HOMEBREW_NO_INSTALL_FROM_API=1 brew test #{fc.name}
HOMEBREW_NO_INSTALL_FROM_API=1 brew audit --new #{formula_creator.name}
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source --verbose --debug #{formula_creator.name}
HOMEBREW_NO_INSTALL_FROM_API=1 brew test #{formula_creator.name}
EOS
path
end

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:disable Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "abstract_command"
@ -172,7 +172,8 @@ module Homebrew
with_monkey_patch { Formulary.from_contents(name, file, contents, ignore_errors: true) }
end
def with_monkey_patch
sig { params(_block: T.proc.void).returns(T.untyped) }
def with_monkey_patch(&_block)
# Since `method_defined?` is not a supported type guard, the use of `alias_method` below is not typesafe:
BottleSpecification.class_eval do
T.unsafe(self).alias_method :old_method_missing, :method_missing if method_defined?(:method_missing)
@ -210,28 +211,28 @@ module Homebrew
BottleSpecification.class_eval do
if method_defined?(:old_method_missing)
T.unsafe(self).alias_method :method_missing, :old_method_missing
undef :old_method_missing
T.unsafe(self).undef :old_method_missing
end
end
Module.class_eval do
if method_defined?(:old_method_missing)
T.unsafe(self).alias_method :method_missing, :old_method_missing
undef :old_method_missing
T.unsafe(self).undef :old_method_missing
end
end
Resource.class_eval do
if method_defined?(:old_method_missing)
T.unsafe(self).alias_method :method_missing, :old_method_missing
undef :old_method_missing
T.unsafe(self).undef :old_method_missing
end
end
DependencyCollector.class_eval do
if method_defined?(:old_parse_symbol_spec)
T.unsafe(self).alias_method :parse_symbol_spec, :old_parse_symbol_spec
undef :old_parse_symbol_spec
T.unsafe(self).undef :old_parse_symbol_spec
end
end
end

View File

@ -45,7 +45,7 @@ module Homebrew
Cask::Cask.generating_hash!
all_casks = {}
latest_macos = MacOSVersion.new((HOMEBREW_MACOS_NEWEST_UNSUPPORTED.to_i - 1).to_s).to_sym
latest_macos = MacOSVersion.new(HOMEBREW_MACOS_NEWEST_SUPPORTED).to_sym
Homebrew::SimulateSystem.with(os: latest_macos, arch: :arm) do
tap.cask_files.each do |path|
cask = Cask::CaskLoader.load(path)

View File

@ -67,8 +67,8 @@ module Homebrew
end
raise UsageError, "Only one url can be specified" if pr_url&.count&.> 1
labels = if pr_url
pr = GitHub::API.open_rest(pr_url.first)
labels = if pr_url && (first_pr_url = pr_url.first)
pr = GitHub::API.open_rest(first_pr_url)
pr.fetch("labels").map { |l| l.fetch("name") }
else
[]
@ -263,11 +263,10 @@ module Homebrew
audit_exceptions << %w[homepage_https_availability] if labels.include?("ci-skip-homepage")
if labels.include?("ci-skip-livecheck")
audit_exceptions << %w[hosting_with_livecheck livecheck_https_availability
livecheck_min_os livecheck_version]
audit_exceptions << %w[hosting_with_livecheck livecheck_https_availability livecheck_version min_os]
end
audit_exceptions << "livecheck_min_os" if labels.include?("ci-skip-livecheck-min-os")
audit_exceptions << "min_os" if labels.include?("ci-skip-livecheck-min-os")
if labels.include?("ci-skip-repository")
audit_exceptions << %w[github_repository github_prerelease_version

View File

@ -44,12 +44,11 @@ module Homebrew
titleized_repository = tap.repository.dup
titleized_user[0] = titleized_user[0].upcase
titleized_repository[0] = titleized_repository[0].upcase
root_url = GitHubPackages.root_url(tap.user, "homebrew-#{tap.repository}") if args.github_packages?
# Duplicate assignment to silence `assigned but unused variable` warning
root_url = root_url = GitHubPackages.root_url(tap.user, "homebrew-#{tap.repository}") if args.github_packages?
(tap.path/"Formula").mkpath
# FIXME: https://github.com/errata-ai/vale/issues/818
# <!-- vale off -->
readme = <<~MARKDOWN
# #{titleized_user} #{titleized_repository}
@ -70,7 +69,6 @@ module Homebrew
`brew help`, `man brew` or check [Homebrew's documentation](https://docs.brew.sh).
MARKDOWN
# <!-- vale on -->
write_path(tap, "README.md", readme)
tests_yml = <<~ERB
@ -99,7 +97,7 @@ module Homebrew
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
token: ${{ github.token }}
@ -164,12 +162,12 @@ module Homebrew
pull-requests: write
steps:
- name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
with:
token: ${{ github.token }}
- name: Set up git
uses: Homebrew/actions/git-user-config@master
uses: Homebrew/actions/git-user-config@main
- name: Pull bottles
env:
@ -182,7 +180,7 @@ module Homebrew
run: brew pr-pull --debug --tap="$GITHUB_REPOSITORY" "$PULL_REQUEST"
- name: Push commits
uses: Homebrew/actions/git-try-push@master
uses: Homebrew/actions/git-try-push@main
with:
branch: <%= branch %>

View File

@ -51,6 +51,11 @@ module Homebrew
HOMEBREW_LIBRARY_PATH.cd do
setup_environment!
# Needs required here, after `setup_environment!`, so that
# `HOMEBREW_TEST_GENERIC_OS` is set and `OS.linux?` and `OS.mac?` both
# `return false`.
require "extend/os/dev-cmd/tests"
parallel = !args.no_parallel?
only = args.only
@ -267,5 +272,3 @@ module Homebrew
end
end
end
require "extend/os/dev-cmd/tests"

View File

@ -142,6 +142,7 @@ module Homebrew
private
sig { returns(String) }
def git_tags
tags = Utils.popen_read("git", "tag", "--list", "--sort=-version:refname")
if tags.blank?

View File

@ -350,7 +350,6 @@ module Homebrew
sudo chmod +t #{HOMEBREW_TEMP}
EOS
end
alias generic_check_tmpdir_sticky_bit check_tmpdir_sticky_bit
def check_exist_directories
return if HOMEBREW_PREFIX.writable?

View File

@ -54,8 +54,6 @@ module SharedEnvExtension
@debug_symbols = debug_symbols
reset
end
alias generic_shared_setup_build_environment setup_build_environment
private :generic_shared_setup_build_environment
sig { void }
def reset

View File

@ -68,7 +68,6 @@ module Stdenv
gcc_formula = gcc_version_formula(cc)
append_path "PATH", gcc_formula.opt_bin.to_s
end
alias generic_setup_build_environment setup_build_environment
sig { returns(T.nilable(PATH)) }
def determine_pkg_config_libdir

View File

@ -125,7 +125,6 @@ module Superenv
# These flags will also be present:
# a - apply fix for apr-1-config path
end
alias generic_setup_build_environment setup_build_environment
private
@ -152,7 +151,6 @@ module Superenv
.reverse
.map { |d| d.opt_libexec/"bin" }
end
alias generic_homebrew_extra_paths homebrew_extra_paths
sig { returns(T.nilable(PATH)) }
def determine_path
@ -372,8 +370,8 @@ module Superenv
append_to_cccfg "O"
end
# This is an exception where we want to use this method name format.
# rubocop: disable Naming/MethodName
# Fixes style error `Naming/MethodName: Use snake_case for method names.`
sig { params(block: T.nilable(T.proc.void)).void }
def O0(&block)
if block

View File

@ -15,6 +15,11 @@ module OS
def os_bundle_args(bundle_args)
non_macos_bundle_args(bundle_args)
end
sig { params(files: T::Array[String]).returns(T::Array[String]) }
def os_files(files)
non_macos_files(files)
end
end
end
end

View File

@ -1,19 +1,19 @@
# typed: strict
# frozen_string_literal: true
module Homebrew
module OS
module Linux
module DevCmd
class UpdateTest < AbstractCommand
alias generic_git_tags git_tags
module UpdateTest
private
sig { returns(String) }
def git_tags
tags = generic_git_tags
tags = Utils.popen_read("git tag --list | sort -rV") if tags.blank?
tags
super.presence || Utils.popen_read("git tag --list | sort -rV")
end
end
end
end
end
Homebrew::DevCmd::UpdateTest.prepend(OS::Linux::DevCmd::UpdateTest)

View File

@ -62,7 +62,7 @@ module OS
def build_system_info
super.merge({
"glibc_version" => OS::Linux::Glibc.version.to_s.presence,
"oldest_cpu_family" => Hardware.oldest_cpu.to_s,
"oldest_cpu_family" => ::Hardware.oldest_cpu.to_s,
})
end
end

View File

@ -32,7 +32,7 @@ module OS
end
def check_tmpdir_sticky_bit
message = generic_check_tmpdir_sticky_bit
message = super
return if message.nil?
message + <<~EOS
@ -74,11 +74,11 @@ module OS
end
def check_supported_architecture
return if Hardware::CPU.intel?
return if Homebrew::EnvConfig.developer? && ENV["HOMEBREW_ARM64_TESTING"].present? && Hardware::CPU.arm?
return if ::Hardware::CPU.intel?
return if Homebrew::EnvConfig.developer? && ENV["HOMEBREW_ARM64_TESTING"].present? && ::Hardware::CPU.arm?
<<~EOS
Your CPU architecture (#{Hardware::CPU.arch}) is not supported. We only support
Your CPU architecture (#{::Hardware::CPU.arch}) is not supported. We only support
x86_64 CPU architectures. You will be unable to use binary packages (bottles).
#{support_tier_message(tier: 2)}

View File

@ -1,16 +1,22 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# frozen_string_literal: true
module OS
module Linux
module SharedEnvExtension
def effective_arch
if @build_bottle && @bottle_arch
@bottle_arch.to_sym
elsif @build_bottle
Hardware.oldest_cpu
elsif Hardware::CPU.intel? || Hardware::CPU.arm?
::Hardware.oldest_cpu
elsif ::Hardware::CPU.intel? || ::Hardware::CPU.arm?
:native
else
:dunno
end
end
end
end
end
SharedEnvExtension.prepend(OS::Linux::SharedEnvExtension)

View File

@ -1,10 +1,16 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# frozen_string_literal: true
module OS
module Linux
module Stdenv
extend T::Helpers
requires_ancestor { ::SharedEnvExtension }
sig {
params(
formula: T.nilable(Formula),
formula: T.nilable(::Formula),
cc: T.nilable(String),
build_bottle: T.nilable(T::Boolean),
bottle_arch: T.nilable(String),
@ -12,10 +18,9 @@ module Stdenv
debug_symbols: T.nilable(T::Boolean),
).void
}
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:,
testing_formula:, debug_symbols:)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil,
testing_formula: false, debug_symbols: false)
super
prepend_path "CPATH", HOMEBREW_PREFIX/"include"
prepend_path "LIBRARY_PATH", HOMEBREW_PREFIX/"lib"
@ -29,8 +34,12 @@ module Stdenv
end
def libxml2
append "CPPFLAGS", "-I#{Formula["libxml2"].include/"libxml2"}"
append "CPPFLAGS", "-I#{::Formula["libxml2"].include/"libxml2"}"
rescue FormulaUnavailableError
nil
end
end
end
end
Stdenv.prepend(OS::Linux::Stdenv)

View File

@ -1,16 +1,25 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# frozen_string_literal: true
module OS
module Linux
module Superenv
extend T::Helpers
requires_ancestor { SharedEnvExtension }
requires_ancestor { ::Superenv }
module ClassMethods
sig { returns(Pathname) }
def self.shims_path
def shims_path
HOMEBREW_SHIMS_PATH/"linux/super"
end
sig { returns(T.nilable(Pathname)) }
def self.bin
def bin
shims_path.realpath
end
end
sig {
params(
@ -22,10 +31,10 @@ module Superenv
debug_symbols: T.nilable(T::Boolean),
).void
}
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:,
testing_formula:, debug_symbols:)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil,
testing_formula: false, debug_symbols: false)
super
self["HOMEBREW_OPTIMIZATION_LEVEL"] = "O2"
self["HOMEBREW_DYNAMIC_LINKER"] = determine_dynamic_linker_path
self["HOMEBREW_RPATH_PATHS"] = determine_rpath_paths(@formula)
@ -35,11 +44,11 @@ module Superenv
# Pointer authentication and BTI are hardening techniques most distros
# use by default on their packages. arm64 Linux we're packaging
# everything from scratch so the entire dependency tree can have it.
append_to_cccfg "b" if Hardware::CPU.arch == :arm64 && DevelopmentTools.gcc_version("gcc") >= 9
append_to_cccfg "b" if ::Hardware::CPU.arch == :arm64 && ::DevelopmentTools.gcc_version("gcc") >= 9
end
def homebrew_extra_paths
paths = generic_homebrew_extra_paths
paths = super
paths += %w[binutils make].filter_map do |f|
bin = Formulary.factory(f).opt_bin
bin if bin.directory?
@ -77,3 +86,8 @@ module Superenv
path
end
end
end
end
Superenv.singleton_class.prepend(OS::Linux::Superenv::ClassMethods)
Superenv.prepend(OS::Linux::Superenv)

View File

@ -1,9 +1,15 @@
# typed: strict
# frozen_string_literal: true
module OS
module Linux
module FormulaCellarChecks
sig { params(filename: Pathname).returns(T::Boolean) }
def valid_library_extension?(filename)
generic_valid_library_extension?(filename) || filename.basename.to_s.include?(".so.")
super || filename.basename.to_s.include?(".so.")
end
end
end
end
FormulaCellarChecks.prepend(OS::Linux::FormulaCellarChecks)

View File

@ -1,12 +1,18 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# frozen_string_literal: true
module OS
module Linux
module Hardware
class CPU
class << self
module CPU
module ClassMethods
extend T::Helpers
requires_ancestor { T.class_of(::Hardware::CPU) }
def optimization_flags
@optimization_flags ||= begin
flags = generic_optimization_flags.dup
flags = super.dup
flags[:native] = arch_flag(Homebrew::EnvConfig.arch)
flags
end
@ -138,7 +144,7 @@ module Hardware
%w[aes altivec avx avx2 lm ssse3 sse4_2].each do |flag|
define_method(:"#{flag}?") do
T.bind(self, T.class_of(Hardware::CPU))
T.bind(self, OS::Linux::Hardware::CPU::ClassMethods)
flags.include? flag
end
end
@ -159,3 +165,7 @@ module Hardware
end
end
end
end
end
Hardware::CPU.singleton_class.prepend(OS::Linux::Hardware::CPU::ClassMethods)

View File

@ -1,8 +1,10 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# frozen_string_literal: true
module Homebrew
module OS
module Linux
module Install
module ClassMethods
# 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.
@ -16,7 +18,6 @@ module Homebrew
/system/bin/linker64
/system/bin/linker
].freeze
private_constant :DYNAMIC_LINKERS
# We link GCC runtime libraries that are not specifically used for Fortran,
# which are linked by the GCC formula. We only use the versioned shared libraries
@ -28,44 +29,41 @@ module Homebrew
libgomp.so.1
libstdc++.so.6
].freeze
private_constant :GCC_RUNTIME_LIBS
def self.perform_preinstall_checks(all_fatal: false)
generic_perform_preinstall_checks(all_fatal:)
symlink_ld_so
setup_preferred_gcc_libs
end
private_class_method :perform_preinstall_checks
def self.global_post_install
generic_global_post_install
def perform_preinstall_checks(all_fatal: false)
super
symlink_ld_so
setup_preferred_gcc_libs
end
def self.check_cpu
return if Hardware::CPU.intel? && Hardware::CPU.is_64_bit?
return if Hardware::CPU.arm?
def global_post_install
super
symlink_ld_so
setup_preferred_gcc_libs
end
def check_cpu
return if ::Hardware::CPU.intel? && ::Hardware::CPU.is_64_bit?
return if ::Hardware::CPU.arm?
message = "Sorry, Homebrew does not support your computer's CPU architecture!"
if Hardware::CPU.ppc64le?
if ::Hardware::CPU.ppc64le?
message += <<~EOS
For OpenPOWER Linux (PPC64LE) support, see:
#{Formatter.url("https://github.com/homebrew-ppc64le/brew")}
EOS
end
abort message
::Kernel.abort message
end
private_class_method :check_cpu
def self.symlink_ld_so
def symlink_ld_so
brew_ld_so = HOMEBREW_PREFIX/"lib/ld.so"
ld_so = HOMEBREW_PREFIX/"opt/glibc/bin/ld.so"
unless ld_so.readable?
ld_so = DYNAMIC_LINKERS.find { |s| File.executable? s }
if ld_so.blank?
raise "Unable to locate the system's dynamic linker" unless brew_ld_so.readable?
::Kernel.raise "Unable to locate the system's dynamic linker" unless brew_ld_so.readable?
return
end
@ -76,9 +74,8 @@ module Homebrew
FileUtils.mkdir_p HOMEBREW_PREFIX/"lib"
FileUtils.ln_sf ld_so, brew_ld_so
end
private_class_method :symlink_ld_so
def self.setup_preferred_gcc_libs
def setup_preferred_gcc_libs
gcc_opt_prefix = HOMEBREW_PREFIX/"opt/#{OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA}"
glibc_installed = (HOMEBREW_PREFIX/"opt/glibc/bin/ld.so").readable?
@ -103,10 +100,10 @@ module Homebrew
FileUtils.chmod "u=rw,go-wx", ld_gcc_conf
FileUtils.rm_f HOMEBREW_PREFIX/"etc/ld.so.cache"
system HOMEBREW_PREFIX/"opt/glibc/sbin/ldconfig"
::Kernel.system HOMEBREW_PREFIX/"opt/glibc/sbin/ldconfig"
end
else
odie "#{HOMEBREW_PREFIX}/lib does not exist!" unless (HOMEBREW_PREFIX/"lib").readable?
::Kernel.odie "#{HOMEBREW_PREFIX}/lib does not exist!" unless (HOMEBREW_PREFIX/"lib").readable?
end
GCC_RUNTIME_LIBS.each do |library|
@ -127,6 +124,9 @@ module Homebrew
end
end
end
private_class_method :setup_preferred_gcc_libs
end
end
end
end
Homebrew::Install.singleton_class.prepend(OS::Linux::Install::ClassMethods)

View File

@ -3,7 +3,9 @@
require "compilers"
class LinkageChecker
module OS
module Linux
module LinkageChecker
# Libraries provided by glibc and gcc.
SYSTEM_LIBRARY_ALLOWLIST = %w[
ld-linux-x86-64.so.2
@ -29,7 +31,7 @@ class LinkageChecker
private
def check_dylibs(rebuild_cache:)
generic_check_dylibs(rebuild_cache:)
super
# glibc and gcc are implicit dependencies.
# No other linkage to system libraries is expected or desired.
@ -39,7 +41,8 @@ class LinkageChecker
# 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.
# 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
@ -48,3 +51,7 @@ class LinkageChecker
@indirect_deps.delete("gcc")
end
end
end
end
LinkageChecker.prepend(OS::Linux::LinkageChecker)

View File

@ -5,12 +5,14 @@ require "compilers"
require "os/linux/glibc"
require "system_command"
module OS
module Linux
module SystemConfig
module ClassMethods
include SystemCommand::Mixin
HOST_RUBY_PATH = "/usr/bin/ruby"
class << self
def host_glibc_version
version = OS::Linux::Glibc.system_version
return "N/A" if version.null?
@ -19,10 +21,10 @@ module SystemConfig
end
def host_gcc_version
gcc = DevelopmentTools.host_gcc_path
gcc = ::DevelopmentTools.host_gcc_path
return "N/A" unless gcc.executable?
`#{gcc} --version 2>/dev/null`[/ (\d+\.\d+\.\d+)/, 1]
Utils.popen_read(gcc, "--version")[/ (\d+\.\d+\.\d+)/, 1]
end
def formula_linked_version(formula)
@ -42,12 +44,12 @@ module SystemConfig
def dump_verbose_config(out = $stdout)
kernel = Utils.safe_popen_read("uname", "-mors").chomp
dump_generic_verbose_config(out)
super
out.puts "Kernel: #{kernel}"
out.puts "OS: #{OS::Linux.os_version}"
out.puts "WSL: #{OS::Linux.wsl_version}" if OS::Linux.wsl?
out.puts "Host glibc: #{host_glibc_version}"
out.puts "#{DevelopmentTools.host_gcc_path}: #{host_gcc_version}"
out.puts "#{::DevelopmentTools.host_gcc_path}: #{host_gcc_version}"
out.puts "/usr/bin/ruby: #{host_ruby_version}" if RUBY_PATH != HOST_RUBY_PATH
["glibc", CompilerSelector.preferred_gcc, OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA, "xorg"].each do |f|
out.puts "#{f}: #{formula_linked_version(f)}"
@ -55,3 +57,7 @@ module SystemConfig
end
end
end
end
end
SystemConfig.singleton_class.prepend(OS::Linux::SystemConfig::ClassMethods)

View File

@ -15,6 +15,11 @@ module OS
def os_bundle_args(bundle_args)
non_linux_bundle_args(bundle_args)
end
sig { params(files: T::Array[String]).returns(T::Array[String]) }
def os_files(files)
non_linux_files(files)
end
end
end
end

View File

@ -1,10 +1,16 @@
# typed: strict
# frozen_string_literal: true
module OS
module Mac
module SharedEnvExtension
extend T::Helpers
requires_ancestor { ::SharedEnvExtension }
sig {
params(
formula: T.nilable(Formula),
formula: T.nilable(::Formula),
cc: T.nilable(String),
build_bottle: T.nilable(T::Boolean),
bottle_arch: T.nilable(String),
@ -12,11 +18,9 @@ module SharedEnvExtension
debug_symbols: T.nilable(T::Boolean),
).void
}
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
generic_shared_setup_build_environment(formula:, cc:, build_bottle:,
bottle_arch:, testing_formula:,
debug_symbols:)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil,
testing_formula: false, debug_symbols: false)
super
# Normalise the system Perl version used, where multiple may be available
self["VERSIONER_PERL_VERSION"] = MacOS.preferred_perl_version
@ -40,3 +44,7 @@ module SharedEnvExtension
OS::Mac::DevelopmentTools.ld64_version >= 711
end
end
end
end
SharedEnvExtension.prepend(OS::Mac::SharedEnvExtension)

View File

@ -1,8 +1,13 @@
# typed: true # rubocop:disable Sorbet/StrictSigil
# frozen_string_literal: true
module OS
module Mac
module Stdenv
undef homebrew_extra_pkg_config_paths
extend T::Helpers
requires_ancestor { SharedEnvExtension }
requires_ancestor { ::Stdenv }
sig { returns(T::Array[Pathname]) }
def homebrew_extra_pkg_config_paths
@ -20,10 +25,9 @@ module Stdenv
debug_symbols: T.nilable(T::Boolean),
).void
}
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:,
testing_formula:, debug_symbols:)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil,
testing_formula: false, debug_symbols: false)
super
append "LDFLAGS", "-Wl,-headerpad_max_install_names"
@ -115,3 +119,7 @@ module Stdenv
append "LDFLAGS", "-Wl,-no_fixup_chains" if no_fixup_chains_support?
end
end
end
end
Stdenv.prepend(OS::Mac::Stdenv)

View File

@ -1,34 +1,32 @@
# typed: true # rubocop:disable Sorbet/StrictSigil
# frozen_string_literal: true
module OS
module Mac
module Superenv
class << self
# The location of Homebrew's shims on macOS.
extend T::Helpers
requires_ancestor { SharedEnvExtension }
requires_ancestor { ::Superenv }
module ClassMethods
sig { returns(Pathname) }
def shims_path
HOMEBREW_SHIMS_PATH/"mac/super"
end
undef bin
sig { returns(T.nilable(Pathname)) }
def bin
return unless DevelopmentTools.installed?
return unless ::DevelopmentTools.installed?
shims_path.realpath
end
end
undef homebrew_extra_pkg_config_paths,
homebrew_extra_isystem_paths, homebrew_extra_library_paths,
homebrew_extra_cmake_include_paths,
homebrew_extra_cmake_library_paths,
homebrew_extra_cmake_frameworks_paths,
determine_cccfg
sig { returns(T::Array[Pathname]) }
def homebrew_extra_pkg_config_paths
[Pathname("/usr/lib/pkgconfig"), Pathname("#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}")]
end
private :homebrew_extra_pkg_config_paths
sig { returns(T::Boolean) }
def libxml2_include_needed?
@ -37,7 +35,6 @@ module Superenv
true
end
private :libxml2_include_needed?
def homebrew_extra_isystem_paths
paths = []
@ -51,7 +48,7 @@ module Superenv
paths = []
if compiler == :llvm_clang
paths << "#{self["HOMEBREW_SDKROOT"]}/usr/lib"
paths << Formula["llvm"].opt_lib.to_s
paths << ::Formula["llvm"].opt_lib.to_s
end
paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries"
paths
@ -66,7 +63,8 @@ module Superenv
end
def homebrew_extra_cmake_library_paths
[Pathname("#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries")]
brew_sdkroot = self["HOMEBREW_SDKROOT"]
[Pathname("#{brew_sdkroot}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries")]
end
def homebrew_extra_cmake_frameworks_paths
@ -83,8 +81,8 @@ module Superenv
end
# @private
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil,
testing_formula: false, debug_symbols: false)
sdk = formula ? MacOS.sdk_for_formula(formula) : MacOS.sdk
is_xcode_sdk = sdk&.source == :xcode
@ -105,12 +103,11 @@ module Superenv
if deps.none? { |d| d.name == "m4" } &&
MacOS.active_developer_dir == MacOS::CLT::PKG_PATH &&
!File.exist?("#{MacOS::CLT::PKG_PATH}/usr/bin/m4") &&
(gm4 = DevelopmentTools.locate("gm4").to_s).present?
(gm4 = ::DevelopmentTools.locate("gm4").to_s).present?
self["M4"] = gm4
end
generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:,
testing_formula:, debug_symbols:)
super
# Filter out symbols known not to be defined since GNU Autotools can't
# reliably figure this out with Xcode 8 and above.
@ -169,3 +166,8 @@ module Superenv
append_to_cccfg "f" if no_fixup_chains_support?
end
end
end
end
Superenv.singleton_class.prepend(OS::Mac::Superenv::ClassMethods)
Superenv.prepend(OS::Mac::Superenv)

View File

@ -4,7 +4,14 @@
require "cache_store"
require "linkage_checker"
module OS
module Mac
module FormulaCellarChecks
extend T::Helpers
requires_ancestor { Homebrew::FormulaAuditor }
requires_ancestor { ::FormulaCellarChecks }
sig { returns(T.nilable(String)) }
def check_shadowed_headers
return if ["libtool", "subversion", "berkeley-db"].any? do |formula_name|
@ -31,7 +38,7 @@ module FormulaCellarChecks
def check_openssl_links
return unless formula.prefix.directory?
keg = Keg.new(formula.prefix)
keg = ::Keg.new(formula.prefix)
system_openssl = keg.mach_o_files.select do |obj|
dlls = obj.dynamically_linked_libraries
dlls.any? { |dll| %r{/usr/lib/lib(crypto|ssl|tls)\..*dylib}.match? dll }
@ -69,10 +76,10 @@ module FormulaCellarChecks
def check_linkage
return unless formula.prefix.directory?
keg = Keg.new(formula.prefix)
keg = ::Keg.new(formula.prefix)
CacheStoreDatabase.use(:linkage) do |db|
checker = LinkageChecker.new(keg, formula, cache_db: db)
checker = ::LinkageChecker.new(keg, formula, cache_db: db)
next unless checker.broken_library_linkage?
output = <<~EOS
@ -85,14 +92,14 @@ module FormulaCellarChecks
output += <<~EOS
Rebuild this from source with:
brew reinstall --build-from-source #{formula}
If that's successful, file an issue#{formula.tap ? " here:\n #{T.must(formula.tap).issues_url}" : "."}
If that's successful, file an issue#{formula.tap ? " here:\n #{formula.tap.issues_url}" : "."}
EOS
end
problem_if_output output
end
end
sig { params(formula: Formula).returns(T.nilable(String)) }
sig { params(formula: ::Formula).returns(T.nilable(String)) }
def check_flat_namespace(formula)
return unless formula.prefix.directory?
return if formula.tap&.audit_exception(:flat_namespace_allowlist, formula.name)
@ -120,7 +127,7 @@ module FormulaCellarChecks
sig { void }
def audit_installed
generic_audit_installed
super
problem_if_output(check_shadowed_headers)
problem_if_output(check_openssl_links)
problem_if_output(check_python_framework_links(formula.lib))
@ -128,9 +135,14 @@ module FormulaCellarChecks
problem_if_output(check_flat_namespace(formula))
end
MACOS_LIB_EXTENSIONS = %w[.dylib .framework].freeze
sig { params(filename: Pathname).returns(T::Boolean) }
def valid_library_extension?(filename)
macos_lib_extensions = %w[.dylib .framework]
generic_valid_library_extension?(filename) || macos_lib_extensions.include?(filename.extname)
super || MACOS_LIB_EXTENSIONS.include?(filename.extname)
end
end
end
end
FormulaCellarChecks.prepend(OS::Mac::FormulaCellarChecks)

View File

@ -1,15 +1,18 @@
# typed: strict
# frozen_string_literal: true
module OS
module Mac
module Hardware
sig { params(version: T.nilable(Version)).returns(Symbol) }
def self.oldest_cpu(version = nil)
module ClassMethods
sig { params(version: T.nilable(MacOSVersion)).returns(Symbol) }
def oldest_cpu(version = nil)
version = if version
MacOSVersion.new(version.to_s)
else
MacOS.version
end
if CPU.arch == :arm64
if ::Hardware::CPU.arch == :arm64
:arm_vortex_tempest
# This cannot use a newer CPU e.g. haswell because Rosetta 2 does not
# support AVX instructions in bottles:
@ -19,7 +22,12 @@ module Hardware
elsif version >= :mojave
:nehalem
else
generic_oldest_cpu
super
end
end
end
end
end
end
Hardware.singleton_class.prepend(OS::Mac::Hardware::ClassMethods)

View File

@ -95,7 +95,7 @@ module OS
end
end
generic_fix_dynamic_linkage
super
end
def loader_name_for(file, target)
@ -199,7 +199,7 @@ module OS
end
def prepare_relocation_to_locations
relocation = generic_prepare_relocation_to_locations
relocation = super
brewed_perl = runtime_dependencies&.any? { |dep| dep["full_name"] == "perl" && dep["declared_directly"] }
perl_path = if brewed_perl || name == "perl"

View File

@ -5,9 +5,10 @@ require "cask/info"
require "cask/cask_loader"
require "cask/caskroom"
module Homebrew
module OS
module Mac
module MissingFormula
class << self
module ClassMethods
sig { params(name: String).returns(T.nilable(String)) }
def disallowed_reason(name)
case name.downcase
@ -16,7 +17,7 @@ module Homebrew
Xcode can be installed from the App Store.
EOS
else
generic_disallowed_reason(name)
super
end
end
@ -36,24 +37,27 @@ module Homebrew
EOS
case command
when "install"
Cask::CaskLoader.load(name)
::Cask::CaskLoader.load(name)
when "uninstall"
cask = Cask::Caskroom.casks.find { |installed_cask| installed_cask.to_s == name }
raise Cask::CaskUnavailableError, name if cask.nil?
cask = ::Cask::Caskroom.casks.find { |installed_cask| installed_cask.to_s == name }
Kernel.raise ::Cask::CaskUnavailableError, name if cask.nil?
when "info"
cask = Cask::CaskLoader.load(name)
cask = ::Cask::CaskLoader.load(name)
suggestion = <<~EOS
Found a cask named "#{name}" instead.
#{Cask::Info.get_info(cask)}
#{::Cask::Info.get_info(cask)}
EOS
else
return
end
suggestion
rescue Cask::CaskUnavailableError
rescue ::Cask::CaskUnavailableError
nil
end
end
end
end
end
Homebrew::MissingFormula.singleton_class.prepend(OS::Mac::MissingFormula::ClassMethods)

View File

@ -6,6 +6,11 @@ require "system_command"
module OS
module Mac
module SystemConfig
module ClassMethods
extend T::Helpers
requires_ancestor { T.class_of(::SystemConfig) }
sig { returns(String) }
def describe_clang
return "N/A" if ::SystemConfig.clang.null?
@ -13,15 +18,6 @@ module OS
clang_build_info = ::SystemConfig.clang_build.null? ? "(parse error)" : ::SystemConfig.clang_build
"#{::SystemConfig.clang} build #{clang_build_info}"
end
end
end
end
SystemConfig.prepend(OS::Mac::SystemConfig)
module SystemConfig
class << self
include SystemCommand::Mixin
def xcode
@xcode ||= if MacOS::Xcode.installed?
@ -41,11 +37,14 @@ module SystemConfig
end
def dump_verbose_config(out = $stdout)
dump_generic_verbose_config(out)
super
out.puts "macOS: #{MacOS.full_version}-#{kernel}"
out.puts "CLT: #{clt || "N/A"}"
out.puts "Xcode: #{xcode || "N/A"}"
out.puts "Rosetta 2: #{Hardware::CPU.in_rosetta2?}" if Hardware::CPU.physical_cpu_arm64?
out.puts "Rosetta 2: #{::Hardware::CPU.in_rosetta2?}" if ::Hardware::CPU.physical_cpu_arm64?
end
end
end
end
end
SystemConfig.singleton_class.prepend(OS::Mac::SystemConfig::ClassMethods)

View File

@ -1,37 +1,40 @@
# typed: strict
# frozen_string_literal: true
module Utils
module OS
module Mac
module Bottles
class << self
module MacOSOverride
sig { params(tag: T.nilable(T.any(Symbol, Tag))).returns(Tag) }
module ClassMethods
sig { params(tag: T.nilable(T.any(Symbol, Utils::Bottles::Tag))).returns(Utils::Bottles::Tag) }
def tag(tag = nil)
return Tag.new(system: MacOS.version.to_sym, arch: Hardware::CPU.arch) if tag.nil?
if tag.nil?
Utils::Bottles::Tag.new(system: MacOS.version.to_sym, arch: ::Hardware::CPU.arch)
else
super
end
end
prepend MacOSOverride
end
class Collector
module Collector
extend T::Helpers
requires_ancestor { Utils::Bottles::Collector }
private
alias generic_find_matching_tag find_matching_tag
sig { params(tag: Utils::Bottles::Tag, no_older_versions: T::Boolean).returns(T.nilable(Utils::Bottles::Tag)) }
sig {
params(tag: Utils::Bottles::Tag,
no_older_versions: T::Boolean).returns(T.nilable(Utils::Bottles::Tag))
}
def find_matching_tag(tag, no_older_versions: false)
# Used primarily by developers testing beta macOS releases.
if no_older_versions ||
(OS::Mac.version.prerelease? &&
Homebrew::EnvConfig.developer? &&
Homebrew::EnvConfig.skip_or_later_bottles?)
generic_find_matching_tag(tag)
super(tag)
else
generic_find_matching_tag(tag) ||
find_older_compatible_tag(tag)
super(tag) || find_older_compatible_tag(tag)
end
end
@ -57,3 +60,7 @@ module Utils
end
end
end
end
Utils::Bottles.singleton_class.prepend(OS::Mac::Bottles::ClassMethods)
Utils::Bottles::Collector.prepend(OS::Mac::Bottles::Collector)

View File

@ -84,7 +84,6 @@ module FormulaCellarChecks
def valid_library_extension?(filename)
VALID_LIBRARY_EXTENSIONS.include? filename.extname
end
alias generic_valid_library_extension? valid_library_extension?
sig { returns(T.nilable(String)) }
def check_non_libraries
@ -437,7 +436,6 @@ module FormulaCellarChecks
problem_if_output(check_cpuid_instruction(formula))
problem_if_output(check_binary_arches(formula))
end
alias generic_audit_installed audit_installed
private

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "digest"
@ -7,62 +7,81 @@ require "erb"
module Homebrew
# Class for generating a formula from a template.
class FormulaCreator
sig { returns(String) }
attr_accessor :name
sig { returns(Version) }
attr_reader :version
sig { returns(T::Boolean) }
attr_reader :head
sig {
params(name: T.nilable(String), version: T.nilable(String), tap: T.nilable(String), url: String,
params(url: String, name: T.nilable(String), version: T.nilable(String), tap: T.nilable(String),
mode: T.nilable(Symbol), license: T.nilable(String), fetch: T::Boolean, head: T::Boolean).void
}
def initialize(name, version, tap:, url:, mode:, license:, fetch:, head:)
@name = name
@version = Version.new(version) if version
@tap = Tap.fetch(tap || "homebrew/core")
def initialize(url:, name: nil, version: nil, tap: nil, mode: nil, license: nil, fetch: false, head: false)
@url = url
@mode = mode
@license = license
@fetch = fetch
@head = head
end
sig { void }
def verify
raise TapUnavailableError, @tap.name unless @tap.installed?
end
sig { params(url: String).returns(T.nilable(String)) }
def self.name_from_url(url)
if name.blank?
stem = Pathname.new(url).stem
name = if stem.start_with?("index.cgi") && stem.include?("=")
# special cases first
if stem.start_with? "index.cgi"
# gitweb URLs e.g. http://www.codesrc.com/gitweb/index.cgi?p=libzipper.git;a=summary
stem.rpartition("=").last
elsif url =~ %r{github\.com/\S+/(\S+)/(archive|releases)/}
# e.g. https://github.com/stella-emu/stella/releases/download/6.7/stella-6.7-src.tar.xz
Regexp.last_match(1)
T.must(Regexp.last_match(1))
else
# e.g. http://digit-labs.org/files/tools/synscan/releases/synscan-5.02.tar.gz
pathver = Version.parse(stem).to_s
stem.sub(/[-_.]?#{Regexp.escape(pathver)}$/, "")
end
odebug "name from url: #{name}"
end
@name = T.let(name, String)
version = if version.present?
Version.new(version)
else
Version.detect(url)
end
@version = T.let(version, Version)
tap = if tap.blank?
CoreTap.instance
else
Tap.fetch(tap)
end
@tap = T.let(tap, Tap)
@mode = T.let(mode.presence, T.nilable(Symbol))
@license = T.let(license.presence, T.nilable(String))
@fetch = fetch
case url
when %r{github\.com/(\S+)/(\S+)\.git}
head = true
user = Regexp.last_match(1)
repository = Regexp.last_match(2)
github = GitHub.repository(user, repository) if fetch
when %r{github\.com/(\S+)/(\S+)/(archive|releases)/}
user = Regexp.last_match(1)
repository = Regexp.last_match(2)
github = GitHub.repository(user, repository) if fetch
end
@head = head
@github = T.let(github, T.untyped)
@sha256 = T.let(nil, T.nilable(String))
@desc = T.let(nil, T.nilable(String))
@homepage = T.let(nil, T.nilable(String))
@license = T.let(nil, T.nilable(String))
end
sig { void }
def parse_url
@name = FormulaCreator.name_from_url(@url) if @name.blank?
odebug "name_from_url: #{@name}"
@version = Version.detect(@url) if @version.nil?
case @url
when %r{github\.com/(\S+)/(\S+)\.git}
@head = true
user = Regexp.last_match(1)
repo = Regexp.last_match(2)
@github = GitHub.repository(user, repo) if @fetch
when %r{github\.com/(\S+)/(\S+)/(archive|releases)/}
user = Regexp.last_match(1)
repo = Regexp.last_match(2)
@github = GitHub.repository(user, repo) if @fetch
end
def verify_tap_available!
raise TapUnavailableError, @tap.name unless @tap.installed?
end
sig { returns(Pathname) }
@ -91,7 +110,7 @@ module Homebrew
raise "Downloaded URL is not archive"
end
@sha256 = filepath.sha256
@sha256 = T.let(filepath.sha256, T.nilable(String))
end
if @github
@ -106,6 +125,8 @@ module Homebrew
path
end
private
sig { params(name: String).returns(String) }
def latest_versioned_formula(name)
name_prefix = "#{name}@"
@ -116,8 +137,6 @@ module Homebrew
sig { returns(String) }
def template
# FIXME: https://github.com/errata-ai/vale/issues/818
# <!-- vale off -->
<<~ERB
# Documentation: https://docs.brew.sh/Formula-Cookbook
# https://rubydoc.brew.sh/Formula
@ -261,7 +280,6 @@ module Homebrew
end
end
ERB
# <!-- vale on -->
end
end
end

View File

@ -51,6 +51,7 @@ HOMEBREW_HOME_PLACEHOLDER = "/$HOME"
HOMEBREW_CASK_APPDIR_PLACEHOLDER = "$APPDIR"
HOMEBREW_MACOS_NEWEST_UNSUPPORTED = ENV.fetch("HOMEBREW_MACOS_NEWEST_UNSUPPORTED").freeze
HOMEBREW_MACOS_NEWEST_SUPPORTED = ENV.fetch("HOMEBREW_MACOS_NEWEST_SUPPORTED").freeze
HOMEBREW_MACOS_OLDEST_SUPPORTED = ENV.fetch("HOMEBREW_MACOS_OLDEST_SUPPORTED").freeze
HOMEBREW_MACOS_OLDEST_ALLOWED = ENV.fetch("HOMEBREW_MACOS_OLDEST_ALLOWED").freeze

View File

@ -42,7 +42,6 @@ module Hardware
ppc64le: "-mcpu=powerpc64le",
}.freeze, T.nilable(T::Hash[Symbol, String]))
end
alias generic_optimization_flags optimization_flags
sig { returns(Symbol) }
def arch_32_bit
@ -219,6 +218,7 @@ module Hardware
end
end
sig { params(_version: T.nilable(MacOSVersion)).returns(Symbol) }
def oldest_cpu(_version = nil)
if Hardware::CPU.intel?
if Hardware::CPU.is_64_bit?
@ -242,7 +242,6 @@ module Hardware
Hardware::CPU.family
end
end
alias generic_oldest_cpu oldest_cpu
# Returns a Rust flag to set the target CPU if necessary.
# Defaults to nil.

View File

@ -37,7 +37,6 @@ module Homebrew
end
def global_post_install; end
alias generic_global_post_install global_post_install
def check_prefix
if (Hardware::CPU.intel? || Hardware::CPU.in_rosetta2?) &&
@ -399,7 +398,6 @@ module Homebrew
Diagnostic.checks(:supported_configuration_checks, fatal: all_fatal)
Diagnostic.checks(:fatal_preinstall_checks)
end
alias generic_perform_preinstall_checks perform_preinstall_checks
def attempt_directory_creation
Keg.must_exist_directories.each do |dir|

View File

@ -77,7 +77,6 @@ class Keg
FileUtils.ln_s(new_src, file)
end
end
alias generic_fix_dynamic_linkage fix_dynamic_linkage
def relocate_dynamic_linkage(_relocation)
[]
@ -102,7 +101,6 @@ class Keg
relocation
end
alias generic_prepare_relocation_to_placeholders prepare_relocation_to_placeholders
def replace_locations_with_placeholders
relocation = prepare_relocation_to_placeholders.freeze
@ -123,7 +121,6 @@ class Keg
relocation
end
alias generic_prepare_relocation_to_locations prepare_relocation_to_locations
def replace_placeholders_with_locations(files, skip_linkage: false)
relocation = prepare_relocation_to_locations.freeze
@ -221,7 +218,6 @@ class Keg
[grep_bin, grep_args]
end
alias generic_egrep_args egrep_args
def each_unique_file_matching(string)
Utils.popen_read("fgrep", recursive_fgrep_args, string, to_s) do |io|

View File

@ -188,12 +188,10 @@ class LinkageChecker
store&.update!(keg_files_dylibs:)
end
alias generic_check_dylibs check_dylibs
def system_libraries_exist_in_cache?
false
end
alias generic_system_libraries_exist_in_cache? system_libraries_exist_in_cache?
def dylib_found_in_shared_cache?(dylib)
@dyld_shared_cache_contains_path ||= begin

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strong
# frozen_string_literal: true
require "version"
@ -10,6 +10,7 @@ class MacOSVersion < Version
sig { returns(T.nilable(T.any(String, Symbol))) }
attr_reader :version
sig { params(version: T.nilable(T.any(String, Symbol))).void }
def initialize(version)
@version = version
super "unknown or unsupported macOS version: #{version.inspect}"
@ -18,7 +19,7 @@ class MacOSVersion < Version
# NOTE: When removing symbols here, ensure that they are added
# to `DEPRECATED_MACOS_VERSIONS` in `MacOSRequirement`.
SYMBOLS = {
SYMBOLS = T.let({
tahoe: "26",
sequoia: "15",
sonoma: "14",
@ -30,7 +31,7 @@ class MacOSVersion < Version
high_sierra: "10.13",
sierra: "10.12",
el_capitan: "10.11",
}.freeze
}.freeze, T::Hash[Symbol, String])
sig { params(macos_version: MacOSVersion).returns(Version) }
def self.kernel_major_version(macos_version)
@ -57,7 +58,9 @@ class MacOSVersion < Version
super(T.must(version))
@comparison_cache = {}
@comparison_cache = T.let({}, T::Hash[T.untyped, T.nilable(Integer)])
@pretty_name = T.let(nil, T.nilable(String))
@sym = T.let(nil, T.nilable(Symbol))
end
sig { override.params(other: T.untyped).returns(T.nilable(Integer)) }
@ -95,7 +98,7 @@ class MacOSVersion < Version
sig { returns(Symbol) }
def to_sym
return @sym if defined?(@sym)
return @sym if @sym
sym = SYMBOLS.invert.fetch(strip_patch.to_s, :dunno)
@ -106,7 +109,7 @@ class MacOSVersion < Version
sig { returns(String) }
def pretty_name
return @pretty_name if defined?(@pretty_name)
return @pretty_name if @pretty_name
pretty_name = to_sym.to_s.split("_").map(&:capitalize).join(" ").freeze
@ -154,5 +157,7 @@ class MacOSVersion < Version
# Represents the absence of a version.
#
# NOTE: Constructor needs to called with an arbitrary macOS-like version which is then set to `nil`.
NULL = MacOSVersion.new("10.0").tap { |v| v.instance_variable_set(:@version, nil) }.freeze
NULL = T.let(MacOSVersion.new("10.0").tap do |v|
T.let(v, MacOSVersion).instance_variable_set(:@version, nil)
end.freeze, MacOSVersion)
end

View File

@ -93,7 +93,6 @@ module Homebrew
EOS
end
end
alias generic_disallowed_reason disallowed_reason
sig { params(name: String).returns(T.nilable(String)) }
def tap_migration_reason(name)
@ -195,8 +194,10 @@ module Homebrew
end
end
sig { params(name: String, silent: T::Boolean, show_info: T::Boolean).returns(T.nilable(String)) }
def cask_reason(name, silent: false, show_info: false); end
sig { params(name: String, command: String).returns(T.nilable(String)) }
def suggest_command(name, command); end
require "extend/os/missing_formula"

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "requirement"
@ -7,10 +7,14 @@ require "requirement"
class ArchRequirement < Requirement
fatal true
@arch = T.let(nil, T.nilable(Symbol))
sig { returns(T.nilable(Symbol)) }
attr_reader :arch
sig { params(tags: T::Array[Symbol]).void }
def initialize(tags)
@arch = tags.shift
@arch = T.let(tags.shift, T.nilable(Symbol))
super
end

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "requirement"
@ -7,6 +7,7 @@ require "requirement"
class XcodeRequirement < Requirement
fatal true
sig { returns(T.nilable(String)) }
attr_reader :version
satisfy(build_env: false) do
@ -14,8 +15,10 @@ class XcodeRequirement < Requirement
xcode_installed_version
end
sig { params(tags: T::Array[String]).void }
def initialize(tags = [])
@version = tags.shift if tags.first.to_s.match?(/(\d\.)+\d/)
version = tags.shift if tags.first.to_s.match?(/(\d\.)+\d/)
@version = T.let(version, T.nilable(String))
super
end
@ -53,6 +56,7 @@ class XcodeRequirement < Requirement
"#<#{self.class.name}: version>=#{@version.inspect} #{tags.inspect}>"
end
sig { returns(String) }
def display_s
return "#{name.capitalize} (on macOS)" unless @version

View File

@ -9,9 +9,6 @@ class Cask::Cask
sig { params(args: T.untyped, block: T.untyped).returns(T.untyped) }
def app(*args, &block); end
sig { params(args: T.untyped, block: T.untyped).returns(T.untyped) }
def appcast(*args, &block); end
sig { params(args: T.untyped, block: T.untyped).returns(T.untyped) }
def appdir(*args, &block); end

View File

@ -0,0 +1,58 @@
# typed: true
# DO NOT EDIT MANUALLY
# This is an autogenerated file for dynamic methods in `Cask::Config`.
# Please instead update this file by running `bin/tapioca dsl Cask::Config`.
module Cask
class Config
sig { returns(String) }
def appdir; end
sig { returns(String) }
def audio_unit_plugindir; end
sig { returns(String) }
def colorpickerdir; end
sig { returns(String) }
def dictionarydir; end
sig { returns(String) }
def fontdir; end
sig { returns(String) }
def input_methoddir; end
sig { returns(String) }
def internet_plugindir; end
sig { returns(String) }
def keyboard_layoutdir; end
sig { returns(T::Array[String]) }
def languages; end
sig { returns(String) }
def mdimporterdir; end
sig { returns(String) }
def prefpanedir; end
sig { returns(String) }
def qlplugindir; end
sig { returns(String) }
def screen_saverdir; end
sig { returns(String) }
def servicedir; end
sig { returns(String) }
def vst3_plugindir; end
sig { returns(String) }
def vst_plugindir; end
end
end

View File

@ -23,9 +23,6 @@ class Homebrew::Cmd::TapCmd::Args < Homebrew::CLI::Args
sig { returns(T::Boolean) }
def force?; end
sig { returns(T::Boolean) }
def force_auto_update?; end
sig { returns(T::Boolean) }
def repair?; end
end

View File

@ -0,0 +1,37 @@
# typed: strict
# frozen_string_literal: true
require_relative "../../../../global"
require "cask/config"
module Tapioca
module Compilers
class CaskConfig < Tapioca::Dsl::Compiler
ConstantType = type_member { { fixed: Module } }
sig { override.returns(T::Enumerable[Module]) }
def self.gather_constants = [Cask::Config]
sig { override.void }
def decorate
root.create_module("Cask") do |mod|
mod.create_class("Config") do |klass|
Cask::Config.defaults.each do |key, value|
return_type = if key == :languages
# :languages is a `LazyObject`, so it lazily evaluates to an
# array of strings when a method is called on it.
"T::Array[String]"
elsif key.end_with?("?")
"T::Boolean"
else
value.class.to_s
end
klass.create_method(key.to_s, return_type:, class_method: false)
end
end
end
end
end
end
end

View File

@ -128,10 +128,12 @@ module SystemConfig
out.puts "#{tap_name} origin: #{tap.remote}" if tap.remote != tap.default_remote
out.puts "#{tap_name} HEAD: #{tap.git_head || "(none)"}"
out.puts "#{tap_name} last commit: #{tap.git_last_commit || "never"}"
out.puts "#{tap_name} branch: #{tap.git_branch || "(none)"}" if tap.git_branch != "master"
default_branches = %w[main master].freeze
out.puts "#{tap_name} branch: #{tap.git_branch || "(none)"}" if default_branches.exclude?(tap.git_branch)
end
if (json_file = Homebrew::API::HOMEBREW_CACHE_API/json_file_name) && json_file.exist?
json_file = Homebrew::API::HOMEBREW_CACHE_API/json_file_name
if json_file.exist?
out.puts "#{tap_name} JSON: #{json_file.mtime.utc.strftime("%d %b %H:%M UTC")}"
elsif !tap.installed?
out.puts "#{tap_name}: N/A"
@ -194,7 +196,6 @@ module SystemConfig
out.puts hardware if hardware
host_software_config(out)
end
alias dump_generic_verbose_config dump_verbose_config
end
end

View File

@ -15,7 +15,7 @@ RSpec.describe Homebrew::Bundle::Dsl do
cask_args appdir: '/Applications'
tap 'homebrew/cask'
tap 'telemachus/brew', 'https://telemachus@bitbucket.org/telemachus/brew.git'
tap 'auto/update', 'https://bitbucket.org/auto/update.git', force_auto_update: true
tap 'auto/update', 'https://bitbucket.org/auto/update.git'
brew 'imagemagick'
brew 'mysql@5.6', restart_service: true, link: true, conflicts_with: ['mysql']
brew 'emacs', args: ['with-cocoa', 'with-gnutls'], link: :overwrite
@ -40,10 +40,7 @@ RSpec.describe Homebrew::Bundle::Dsl do
expect(dsl.entries[0].name).to eql("homebrew/cask")
expect(dsl.entries[1].name).to eql("telemachus/brew")
expect(dsl.entries[1].options).to eql(clone_target: "https://telemachus@bitbucket.org/telemachus/brew.git")
expect(dsl.entries[2].options).to eql(
clone_target: "https://bitbucket.org/auto/update.git",
force_auto_update: true,
)
expect(dsl.entries[2].options).to eql(clone_target: "https://bitbucket.org/auto/update.git")
expect(dsl.entries[3].name).to eql("imagemagick")
expect(dsl.entries[4].name).to eql("mysql@5.6")
expect(dsl.entries[4].options).to eql(restart_service: true, link: true, conflicts_with: ["mysql"])

View File

@ -55,25 +55,5 @@ RSpec.describe Homebrew::Bundle::TapInstaller do
expect(described_class.install("homebrew/cask", clone_target: "clone_target_path")).to be(false)
end
end
context "with force_auto_update" do
it "taps" do
expect(Homebrew::Bundle).to receive(:system).with(HOMEBREW_BREW_FILE, "tap", "homebrew/cask",
"--force-auto-update",
verbose: false)
.and_return(true)
expect(described_class.preinstall("homebrew/cask", force_auto_update: true)).to be(true)
expect(described_class.install("homebrew/cask", force_auto_update: true)).to be(true)
end
it "fails" do
expect(Homebrew::Bundle).to receive(:system).with(HOMEBREW_BREW_FILE, "tap", "homebrew/cask",
"--force-auto-update",
verbose: false)
.and_return(false)
expect(described_class.preinstall("homebrew/cask", force_auto_update: true)).to be(true)
expect(described_class.install("homebrew/cask", force_auto_update: true)).to be(false)
end
end
end
end

View File

@ -19,7 +19,7 @@ RSpec.describe Cask::Artifact::Artifact, :cask do
end
context "without target" do
it "fails to load" do
it "fails to load", :no_api do
expect do
Cask::CaskLoader.load("invalid-generic-artifact-no-target")
end.to raise_error(Cask::CaskInvalidError, /Generic Artifact.*requires.*target/)

View File

@ -6,7 +6,7 @@ RSpec.describe Cask::Artifact::Manpage, :cask do
context "without section" do
let(:cask_token) { "invalid-manpage-no-section" }
it "fails to load a cask without section" do
it "fails to load a cask without section", :no_api do
expect { cask }.to raise_error(Cask::CaskInvalidError, /is not a valid man page name/)
end
end

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