Merge branch 'master' into codecov-action
This commit is contained in:
commit
ff7c05a285
17
.github/ISSUE_TEMPLATE/bug.yml
vendored
17
.github/ISSUE_TEMPLATE/bug.yml
vendored
@ -1,38 +1,47 @@
|
|||||||
name: New issue for Reproducible Bug
|
name: New issue for Reproducible Bug
|
||||||
about: "If you're sure it's reproducible and not just your machine: submit an issue so we can investigate."
|
description: "If you're sure it's reproducible and not just your machine: submit an issue so we can investigate."
|
||||||
labels: bug
|
labels: bug
|
||||||
issue_body: false
|
issue_body: false
|
||||||
inputs:
|
body:
|
||||||
- type: description
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: Please note we will close your issue without comment if you do not fill out the issue checklist below and provide ALL the requested information. If you repeatedly fail to use the issue template, we will block you from ever submitting issues to Homebrew again.
|
value: Please note we will close your issue without comment if you do not fill out the issue checklist below and provide ALL the requested information. If you repeatedly fail to use the issue template, we will block you from ever submitting issues to Homebrew again.
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
|
render: shell
|
||||||
label: "`brew config` output"
|
label: "`brew config` output"
|
||||||
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
|
render: shell
|
||||||
label: "`brew doctor` output"
|
label: "`brew doctor` output"
|
||||||
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
description: Please verify that you've followed these steps
|
description: Please verify that you've followed these steps
|
||||||
choices:
|
options:
|
||||||
- label: The `brew doctor` above contains no "Warning" lines.
|
- label: The `brew doctor` above contains no "Warning" lines.
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: What were you trying to do (and why)?
|
label: What were you trying to do (and why)?
|
||||||
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: What happened (include all command output)?
|
label: What happened (include all command output)?
|
||||||
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: What did you expect to happen?
|
label: What did you expect to happen?
|
||||||
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
|
render: shell
|
||||||
label: Step-by-step reproduction instructions (by running `brew` commands)
|
label: Step-by-step reproduction instructions (by running `brew` commands)
|
||||||
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -9,7 +9,7 @@ contact_links:
|
|||||||
about: On macOS/Mac OS X? Having a `brew` problem with a `brew install` or `brew upgrade` of a single formula/package? Report it to Homebrew/homebrew-core (the macOS core tap/repository).
|
about: On macOS/Mac OS X? Having a `brew` problem with a `brew install` or `brew upgrade` of a single formula/package? Report it to Homebrew/homebrew-core (the macOS core tap/repository).
|
||||||
- name: New issue on Homebrew/homebrew-cask
|
- name: New issue on Homebrew/homebrew-cask
|
||||||
url: https://github.com/Homebrew/homebrew-cask/issues/new/choose
|
url: https://github.com/Homebrew/homebrew-cask/issues/new/choose
|
||||||
about: Having a `brew cask` problem? Report it to Homebrew/homebrew-cask (the cask tap/repository).
|
about: Having a `brew --cask` problem? Report it to Homebrew/homebrew-cask (the cask tap/repository).
|
||||||
- name: New issue on Homebrew/linuxbrew-core
|
- name: New issue on Homebrew/linuxbrew-core
|
||||||
url: https://github.com/Homebrew/linuxbrew-core/issues/new/choose
|
url: https://github.com/Homebrew/linuxbrew-core/issues/new/choose
|
||||||
about: On Linux? Having a `brew` problem with a `brew install` or `brew upgrade` of a single formula/package? Report it to Homebrew/linuxbrew-core (the Linux core tap/repository).
|
about: On Linux? Having a `brew` problem with a `brew install` or `brew upgrade` of a single formula/package? Report it to Homebrew/linuxbrew-core (the Linux core tap/repository).
|
||||||
|
|||||||
12
.github/ISSUE_TEMPLATE/feature.yml
vendored
12
.github/ISSUE_TEMPLATE/feature.yml
vendored
@ -1,27 +1,31 @@
|
|||||||
name: New issue for Feature Suggestion
|
name: New issue for Feature Suggestion
|
||||||
about: Request our thoughts on your suggestion for a new feature for Homebrew.
|
description: Request our thoughts on your suggestion for a new feature for Homebrew.
|
||||||
labels: features
|
labels: features
|
||||||
issue_body: false
|
issue_body: false
|
||||||
inputs:
|
body:
|
||||||
- type: description
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: Please note we will close your issue without comment if you do not fill out the issue checklist below and provide ALL the requested information. If you repeatedly fail to use the issue template, we will block you from ever submitting issues to Homebrew again.
|
value: Please note we will close your issue without comment if you do not fill out the issue checklist below and provide ALL the requested information. If you repeatedly fail to use the issue template, we will block you from ever submitting issues to Homebrew again.
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Provide a detailed description of the proposed feature
|
label: Provide a detailed description of the proposed feature
|
||||||
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: What is the motivation for the feature?
|
label: What is the motivation for the feature?
|
||||||
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: How will the feature be relevant to at least 90% of Homebrew users?
|
label: How will the feature be relevant to at least 90% of Homebrew users?
|
||||||
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: What alternatives to the feature have been considered?
|
label: What alternatives to the feature have been considered?
|
||||||
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: description
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: We will close this issue or ask you to create a pull-request if it's something the maintainers are not actively planning to work on.
|
value: We will close this issue or ask you to create a pull-request if it's something the maintainers are not actively planning to work on.
|
||||||
|
|||||||
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -5,6 +5,5 @@
|
|||||||
- [ ] Have you successfully run `brew style` with your changes locally?
|
- [ ] Have you successfully run `brew style` with your changes locally?
|
||||||
- [ ] Have you successfully run `brew typecheck` with your changes locally?
|
- [ ] Have you successfully run `brew typecheck` with your changes locally?
|
||||||
- [ ] Have you successfully run `brew tests` with your changes locally?
|
- [ ] Have you successfully run `brew tests` with your changes locally?
|
||||||
- [ ] Have you successfully run `brew man` locally and committed any changes?
|
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|||||||
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@ -10,10 +10,14 @@ updates:
|
|||||||
directory: /docs
|
directory: /docs
|
||||||
schedule:
|
schedule:
|
||||||
interval: weekly
|
interval: weekly
|
||||||
|
allow:
|
||||||
|
- dependency-type: all
|
||||||
|
|
||||||
- package-ecosystem: bundler
|
- package-ecosystem: bundler
|
||||||
directory: /Library/Homebrew
|
directory: /Library/Homebrew
|
||||||
schedule:
|
schedule:
|
||||||
interval: daily
|
interval: daily
|
||||||
|
allow:
|
||||||
|
- dependency-type: all
|
||||||
ignore:
|
ignore:
|
||||||
- dependency-name: sorbet-runtime
|
- dependency-name: sorbet-runtime
|
||||||
|
|||||||
2
.github/workflows/doctor.yml
vendored
2
.github/workflows/doctor.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
|||||||
tests:
|
tests:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
version: ['11-arm', '11.0', '10.15', '10.14']
|
version: ["11-arm", "11.0", "10.15", "10.14"]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
runs-on: ${{ matrix.version }}
|
runs-on: ${{ matrix.version }}
|
||||||
env:
|
env:
|
||||||
|
|||||||
78
.github/workflows/tests.yml
vendored
78
.github/workflows/tests.yml
vendored
@ -31,8 +31,6 @@ jobs:
|
|||||||
|
|
||||||
- run: brew style --display-cop-names
|
- run: brew style --display-cop-names
|
||||||
|
|
||||||
- run: brew man --fail-if-changed
|
|
||||||
|
|
||||||
- run: brew typecheck
|
- run: brew typecheck
|
||||||
|
|
||||||
- name: Run vale for docs linting
|
- name: Run vale for docs linting
|
||||||
@ -81,6 +79,58 @@ jobs:
|
|||||||
- name: Run brew audit --skip-style on all taps
|
- name: Run brew audit --skip-style on all taps
|
||||||
run: brew audit --skip-style
|
run: brew audit --skip-style
|
||||||
|
|
||||||
|
- name: Set up all Homebrew taps
|
||||||
|
run: |
|
||||||
|
HOMEBREW_REPOSITORY="$(brew --repo)"
|
||||||
|
HOMEBREW_CORE_REPOSITORY="$HOMEBREW_REPOSITORY/Library/Taps/homebrew/homebrew-core"
|
||||||
|
git -C "$HOMEBREW_CORE_REPOSITORY" remote add homebrew_core https://github.com/Homebrew/homebrew-core
|
||||||
|
git -C "$HOMEBREW_CORE_REPOSITORY" fetch homebrew_core || git -C "$HOMEBREW_CORE_REPOSITORY" fetch homebrew_core
|
||||||
|
git -C "$HOMEBREW_CORE_REPOSITORY" checkout --force -B master homebrew_core/master
|
||||||
|
|
||||||
|
brew tap homebrew/aliases
|
||||||
|
brew tap homebrew/bundle
|
||||||
|
brew tap homebrew/cask
|
||||||
|
brew tap homebrew/cask-drivers
|
||||||
|
brew tap homebrew/cask-fonts
|
||||||
|
brew tap homebrew/cask-versions
|
||||||
|
brew tap homebrew/command-not-found
|
||||||
|
brew tap homebrew/formula-analytics
|
||||||
|
brew tap homebrew/linux-dev
|
||||||
|
brew tap homebrew/portable-ruby
|
||||||
|
brew tap homebrew/services
|
||||||
|
|
||||||
|
brew update-reset Library/Taps/homebrew/homebrew-bundle
|
||||||
|
|
||||||
|
# brew style doesn't like world writable directories
|
||||||
|
sudo chmod -R g-w,o-w "$HOMEBREW_REPOSITORY/Library/Taps"
|
||||||
|
|
||||||
|
- name: Run brew style on homebrew-core
|
||||||
|
run: brew style --display-cop-names homebrew/core
|
||||||
|
|
||||||
|
- name: Run brew audit --skip-style on homebrew-core
|
||||||
|
run: brew audit --skip-style --tap=homebrew/core
|
||||||
|
env:
|
||||||
|
HOMEBREW_SIMULATE_MACOS_ON_LINUX: 1
|
||||||
|
|
||||||
|
- name: Run brew style on official taps
|
||||||
|
run: |
|
||||||
|
brew style --display-cop-names homebrew/bundle \
|
||||||
|
homebrew/services \
|
||||||
|
homebrew/test-bot
|
||||||
|
|
||||||
|
brew style --display-cop-names homebrew/aliases\
|
||||||
|
homebrew/command-not-found \
|
||||||
|
homebrew/formula-analytics \
|
||||||
|
homebrew/linux-dev \
|
||||||
|
homebrew/portable-ruby
|
||||||
|
|
||||||
|
- name: Run brew style on cask taps
|
||||||
|
run: |
|
||||||
|
brew style --display-cop-names homebrew/cask \
|
||||||
|
homebrew/cask-drivers \
|
||||||
|
homebrew/cask-fonts \
|
||||||
|
homebrew/cask-versions
|
||||||
|
|
||||||
vendored-gems:
|
vendored-gems:
|
||||||
name: vendored gems (Linux)
|
name: vendored gems (Linux)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -231,29 +281,17 @@ jobs:
|
|||||||
- name: Run brew readall on all taps
|
- name: Run brew readall on all taps
|
||||||
run: brew readall --aliases
|
run: brew readall --aliases
|
||||||
|
|
||||||
- name: Run brew style on homebrew-core
|
- name: Run brew audit --skip-style on Cask taps
|
||||||
run: brew style --display-cop-names homebrew/core
|
|
||||||
|
|
||||||
- name: Run brew style on official taps
|
|
||||||
run: |
|
run: |
|
||||||
brew style --display-cop-names homebrew/bundle \
|
brew audit --skip-style --tap=homebrew/cask
|
||||||
homebrew/services \
|
brew audit --skip-style --tap=homebrew/cask-drivers
|
||||||
homebrew/test-bot
|
brew audit --skip-style --tap=homebrew/cask-fonts
|
||||||
|
brew audit --skip-style --tap=homebrew/cask-versions
|
||||||
- name: Run brew style on cask taps
|
|
||||||
run: |
|
|
||||||
brew style --display-cop-names homebrew/cask \
|
|
||||||
homebrew/cask-drivers \
|
|
||||||
homebrew/cask-fonts \
|
|
||||||
homebrew/cask-versions
|
|
||||||
|
|
||||||
- name: Run brew audit --skip-style on all taps
|
|
||||||
run: brew audit --skip-style
|
|
||||||
|
|
||||||
- name: Install brew tests dependencies
|
- name: Install brew tests dependencies
|
||||||
run: |
|
run: |
|
||||||
brew install subversion
|
brew install subversion
|
||||||
Library/Homebrew/shims/scm/svn --homebrew=print-path
|
brew sh -c "svn --homebrew=print-path"
|
||||||
which svn
|
which svn
|
||||||
which svnadmin
|
which svnadmin
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/triage.yml
vendored
2
.github/workflows/triage.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Re-run this workflow
|
- name: Re-run this workflow
|
||||||
if: github.event_name == 'schedule' || github.event.action == 'closed'
|
if: github.event_name == 'schedule' || github.event.action == 'closed'
|
||||||
uses: reitermarkus/rerun-workflow@e2647e8885422412d5acbd61f9add5b1e77ad3ab
|
uses: reitermarkus/rerun-workflow@64cba9e834916060e77b7dad424d086837fdd0a6
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
|
token: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
|
||||||
continuous-label: waiting for feedback
|
continuous-label: waiting for feedback
|
||||||
|
|||||||
82
.github/workflows/update-manpage.yml
vendored
Normal file
82
.github/workflows/update-manpage.yml
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
name: Update maintainers, manpage and completions
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- .github/workflows/update-manpage.yml
|
||||||
|
- README.md
|
||||||
|
- Library/Homebrew/cmd/**
|
||||||
|
- Library/Homebrew/dev-cmd/**
|
||||||
|
- Library/Homebrew/completions/**
|
||||||
|
- Library/Homebrew/manpages/**
|
||||||
|
- Library/Homebrew/cli/parser.rb
|
||||||
|
- Library/Homebrew/completions.rb
|
||||||
|
- Library/Homebrew/env_config.rb
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-manpage:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository == 'Homebrew/brew'
|
||||||
|
steps:
|
||||||
|
- name: Setup Homebrew
|
||||||
|
uses: Homebrew/actions/setup-homebrew@master
|
||||||
|
|
||||||
|
- name: Configure Git user
|
||||||
|
uses: Homebrew/actions/git-user-config@master
|
||||||
|
with:
|
||||||
|
username: BrewTestBot
|
||||||
|
|
||||||
|
- name: Update maintainers, manpage and completions
|
||||||
|
id: update
|
||||||
|
run: |
|
||||||
|
git fetch origin
|
||||||
|
|
||||||
|
BRANCH=update-manpage
|
||||||
|
echo "::set-output name=branch::${BRANCH}"
|
||||||
|
|
||||||
|
if git ls-remote --exit-code --heads origin "$BRANCH"; then
|
||||||
|
git checkout "$BRANCH"
|
||||||
|
git reset --hard origin/master
|
||||||
|
else
|
||||||
|
git checkout -B "$BRANCH" origin/master
|
||||||
|
BRANCH_EXISTS="1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${{github.event_name}}" != "push" ]; then
|
||||||
|
brew update-maintainers
|
||||||
|
fi
|
||||||
|
|
||||||
|
if brew man --fail-if-not-changed; then
|
||||||
|
git add "$GITHUB_WORKSPACE/README.md" \
|
||||||
|
"$GITHUB_WORKSPACE/docs/Manpage.md" \
|
||||||
|
"$GITHUB_WORKSPACE/manpages/brew.1" \
|
||||||
|
"$GITHUB_WORKSPACE/completions"
|
||||||
|
git commit -m "Update maintainers, manpage and completions." \
|
||||||
|
-m "Autogenerated by the [update-manpage](https://github.com/Homebrew/brew/blob/HEAD/.github/workflows/update-manpage.yml) workflow."
|
||||||
|
echo "::set-output name=committed::true"
|
||||||
|
if [ -n "$BRANCH_EXISTS" ]; then
|
||||||
|
echo "::set-output name=pull_request::true"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
|
||||||
|
|
||||||
|
- name: Push commits
|
||||||
|
if: steps.update.outputs.committed == 'true'
|
||||||
|
uses: Homebrew/actions/git-try-push@master
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
|
||||||
|
branch: ${{ steps.update.outputs.branch }}
|
||||||
|
force: true
|
||||||
|
origin_branch: "master"
|
||||||
|
|
||||||
|
- name: Open a pull request
|
||||||
|
if: steps.update.outputs.pull_request == 'true'
|
||||||
|
run: hub pull-request --no-edit
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
|
||||||
@ -14,6 +14,7 @@ RUN apt-get update \
|
|||||||
file \
|
file \
|
||||||
fonts-dejavu-core \
|
fonts-dejavu-core \
|
||||||
g++ \
|
g++ \
|
||||||
|
gawk \
|
||||||
git \
|
git \
|
||||||
less \
|
less \
|
||||||
libz-dev \
|
libz-dev \
|
||||||
|
|||||||
@ -240,6 +240,12 @@ Layout/SpaceAroundOperators:
|
|||||||
Layout/RescueEnsureAlignment:
|
Layout/RescueEnsureAlignment:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
# significantly less indentation involved; more consistent
|
||||||
|
Layout/FirstArrayElementIndentation:
|
||||||
|
EnforcedStyle: consistent
|
||||||
|
Layout/FirstHashElementIndentation:
|
||||||
|
EnforcedStyle: consistent
|
||||||
|
|
||||||
# favour parens-less DSL-style arguments
|
# favour parens-less DSL-style arguments
|
||||||
Lint/AmbiguousBlockAssociation:
|
Lint/AmbiguousBlockAssociation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
@ -255,14 +261,6 @@ Naming/MemoizedInstanceVariableName:
|
|||||||
Exclude:
|
Exclude:
|
||||||
- "Homebrew/lazy_object.rb"
|
- "Homebrew/lazy_object.rb"
|
||||||
|
|
||||||
# so many of these in formulae and can't be autocorrected
|
|
||||||
# TODO: fix these as `ruby -w` complains about them.
|
|
||||||
Lint/AmbiguousRegexpLiteral:
|
|
||||||
Exclude:
|
|
||||||
- "Taps/*/*/*.rb"
|
|
||||||
- "/**/Formula/*.rb"
|
|
||||||
- "**/Formula/*.rb"
|
|
||||||
|
|
||||||
# useful for metaprogramming in RSpec
|
# useful for metaprogramming in RSpec
|
||||||
Lint/ConstantDefinitionInBlock:
|
Lint/ConstantDefinitionInBlock:
|
||||||
Exclude:
|
Exclude:
|
||||||
@ -462,6 +460,11 @@ Style/StringLiteralsInInterpolation:
|
|||||||
Style/TernaryParentheses:
|
Style/TernaryParentheses:
|
||||||
EnforcedStyle: require_parentheses_when_complex
|
EnforcedStyle: require_parentheses_when_complex
|
||||||
|
|
||||||
|
# `unless ... ||` and `unless ... &&` are hard to mentally parse
|
||||||
|
Style/UnlessLogicalOperators:
|
||||||
|
Enabled: true
|
||||||
|
EnforcedStyle: forbid_logical_operators
|
||||||
|
|
||||||
# a bit confusing to non-Rubyists but useful for longer arrays
|
# a bit confusing to non-Rubyists but useful for longer arrays
|
||||||
Style/WordArray:
|
Style/WordArray:
|
||||||
MinSize: 4
|
MinSize: 4
|
||||||
|
|||||||
@ -11,8 +11,6 @@ RSpec/SubjectStub:
|
|||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# TODO: try to enable these
|
# TODO: try to enable these
|
||||||
RSpec/ContextWording:
|
|
||||||
Enabled: false
|
|
||||||
RSpec/DescribeClass:
|
RSpec/DescribeClass:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
RSpec/LeakyConstantDeclaration:
|
RSpec/LeakyConstantDeclaration:
|
||||||
@ -21,8 +19,6 @@ RSpec/MessageSpies:
|
|||||||
Enabled: false
|
Enabled: false
|
||||||
RSpec/RepeatedDescription:
|
RSpec/RepeatedDescription:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
RSpec/RepeatedExampleGroupDescription:
|
|
||||||
Enabled: false
|
|
||||||
RSpec/StubbedMock:
|
RSpec/StubbedMock:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
|||||||
@ -7,10 +7,6 @@ Layout/MultilineMethodCallIndentation:
|
|||||||
Exclude:
|
Exclude:
|
||||||
- "**/*_spec.rb"
|
- "**/*_spec.rb"
|
||||||
|
|
||||||
# TODO: add parentheses for these and remove
|
|
||||||
Lint/AssignmentInCondition:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
# `formula do` uses nested method definitions
|
# `formula do` uses nested method definitions
|
||||||
Lint/NestedMethodDefinition:
|
Lint/NestedMethodDefinition:
|
||||||
Exclude:
|
Exclude:
|
||||||
@ -36,9 +32,8 @@ Metrics/PerceivedComplexity:
|
|||||||
Max: 90
|
Max: 90
|
||||||
Metrics/MethodLength:
|
Metrics/MethodLength:
|
||||||
Max: 260
|
Max: 260
|
||||||
# TODO: Reduce to 600 after refactoring utils/github
|
|
||||||
Metrics/ModuleLength:
|
Metrics/ModuleLength:
|
||||||
Max: 620
|
Max: 600
|
||||||
Exclude:
|
Exclude:
|
||||||
- "test/**/*"
|
- "test/**/*"
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ source "https://rubygems.org"
|
|||||||
# installed gems (should all be require: false)
|
# installed gems (should all be require: false)
|
||||||
gem "bootsnap", require: false
|
gem "bootsnap", require: false
|
||||||
gem "byebug", require: false
|
gem "byebug", require: false
|
||||||
|
gem "minitest", require: false
|
||||||
gem "nokogiri", require: false
|
gem "nokogiri", require: false
|
||||||
gem "parallel_tests", require: false
|
gem "parallel_tests", require: false
|
||||||
gem "ronn", require: false
|
gem "ronn", require: false
|
||||||
@ -20,6 +21,7 @@ gem "simplecov", require: false
|
|||||||
gem "sorbet", require: false
|
gem "sorbet", require: false
|
||||||
gem "sorbet-runtime", require: false
|
gem "sorbet-runtime", require: false
|
||||||
gem "tapioca", require: false
|
gem "tapioca", require: false
|
||||||
|
gem "warning", require: false
|
||||||
|
|
||||||
# vendored gems
|
# vendored gems
|
||||||
gem "activesupport"
|
gem "activesupport"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
activesupport (6.1.2)
|
activesupport (6.1.3)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
@ -28,7 +28,7 @@ GEM
|
|||||||
hpricot (0.8.6)
|
hpricot (0.8.6)
|
||||||
http-cookie (1.0.3)
|
http-cookie (1.0.3)
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
i18n (1.8.8)
|
i18n (1.8.9)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
mechanize (2.7.7)
|
mechanize (2.7.7)
|
||||||
domain_name (~> 0.5, >= 0.5.1)
|
domain_name (~> 0.5, >= 0.5.1)
|
||||||
@ -43,22 +43,22 @@ GEM
|
|||||||
method_source (1.0.0)
|
method_source (1.0.0)
|
||||||
mime-types (3.3.1)
|
mime-types (3.3.1)
|
||||||
mime-types-data (~> 3.2015)
|
mime-types-data (~> 3.2015)
|
||||||
mime-types-data (3.2020.1104)
|
mime-types-data (3.2021.0212)
|
||||||
mini_portile2 (2.5.0)
|
mini_portile2 (2.5.0)
|
||||||
minitest (5.14.3)
|
minitest (5.14.4)
|
||||||
msgpack (1.4.2)
|
msgpack (1.4.2)
|
||||||
mustache (1.1.1)
|
mustache (1.1.1)
|
||||||
net-http-digest_auth (1.4.1)
|
net-http-digest_auth (1.4.1)
|
||||||
net-http-persistent (4.0.1)
|
net-http-persistent (4.0.1)
|
||||||
connection_pool (~> 2.2)
|
connection_pool (~> 2.2)
|
||||||
nokogiri (1.11.1)
|
nokogiri (1.11.2)
|
||||||
mini_portile2 (~> 2.5.0)
|
mini_portile2 (~> 2.5.0)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
ntlm-http (0.1.1)
|
ntlm-http (0.1.1)
|
||||||
parallel (1.20.1)
|
parallel (1.20.1)
|
||||||
parallel_tests (3.4.0)
|
parallel_tests (3.5.2)
|
||||||
parallel
|
parallel
|
||||||
parlour (5.0.0)
|
parlour (6.0.0)
|
||||||
commander (~> 4.5)
|
commander (~> 4.5)
|
||||||
parser
|
parser
|
||||||
rainbow (~> 3.0)
|
rainbow (~> 3.0)
|
||||||
@ -68,14 +68,14 @@ GEM
|
|||||||
patchelf (1.3.0)
|
patchelf (1.3.0)
|
||||||
elftools (>= 1.1.3)
|
elftools (>= 1.1.3)
|
||||||
plist (3.6.0)
|
plist (3.6.0)
|
||||||
pry (0.13.1)
|
pry (0.14.0)
|
||||||
coderay (~> 1.1)
|
coderay (~> 1.1)
|
||||||
method_source (~> 1.0)
|
method_source (~> 1.0)
|
||||||
racc (1.5.2)
|
racc (1.5.2)
|
||||||
rack (2.2.3)
|
rack (2.2.3)
|
||||||
rainbow (3.0.0)
|
rainbow (3.0.0)
|
||||||
rdiscount (2.2.0.2)
|
rdiscount (2.2.0.2)
|
||||||
regexp_parser (2.0.3)
|
regexp_parser (2.1.1)
|
||||||
rexml (3.2.4)
|
rexml (3.2.4)
|
||||||
ronn (0.7.3)
|
ronn (0.7.3)
|
||||||
hpricot (>= 0.8.2)
|
hpricot (>= 0.8.2)
|
||||||
@ -85,9 +85,9 @@ GEM
|
|||||||
rspec-core (~> 3.10.0)
|
rspec-core (~> 3.10.0)
|
||||||
rspec-expectations (~> 3.10.0)
|
rspec-expectations (~> 3.10.0)
|
||||||
rspec-mocks (~> 3.10.0)
|
rspec-mocks (~> 3.10.0)
|
||||||
rspec-core (3.10.0)
|
rspec-core (3.10.1)
|
||||||
rspec-support (~> 3.10.0)
|
rspec-support (~> 3.10.0)
|
||||||
rspec-expectations (3.10.0)
|
rspec-expectations (3.10.1)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.10.0)
|
rspec-support (~> 3.10.0)
|
||||||
rspec-github (2.3.1)
|
rspec-github (2.3.1)
|
||||||
@ -95,7 +95,7 @@ GEM
|
|||||||
rspec-its (1.3.0)
|
rspec-its (1.3.0)
|
||||||
rspec-core (>= 3.0.0)
|
rspec-core (>= 3.0.0)
|
||||||
rspec-expectations (>= 3.0.0)
|
rspec-expectations (>= 3.0.0)
|
||||||
rspec-mocks (3.10.0)
|
rspec-mocks (3.10.2)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.10.0)
|
rspec-support (~> 3.10.0)
|
||||||
rspec-retry (0.6.2)
|
rspec-retry (0.6.2)
|
||||||
@ -103,10 +103,10 @@ GEM
|
|||||||
rspec-sorbet (1.8.0)
|
rspec-sorbet (1.8.0)
|
||||||
sorbet
|
sorbet
|
||||||
sorbet-runtime
|
sorbet-runtime
|
||||||
rspec-support (3.10.0)
|
rspec-support (3.10.2)
|
||||||
rspec-wait (0.0.9)
|
rspec-wait (0.0.9)
|
||||||
rspec (>= 3, < 4)
|
rspec (>= 3, < 4)
|
||||||
rubocop (1.9.1)
|
rubocop (1.11.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.0.0.0)
|
parser (>= 3.0.0.0)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
@ -117,7 +117,7 @@ GEM
|
|||||||
unicode-display_width (>= 1.4.0, < 3.0)
|
unicode-display_width (>= 1.4.0, < 3.0)
|
||||||
rubocop-ast (1.4.1)
|
rubocop-ast (1.4.1)
|
||||||
parser (>= 2.7.1.5)
|
parser (>= 2.7.1.5)
|
||||||
rubocop-performance (1.9.2)
|
rubocop-performance (1.10.1)
|
||||||
rubocop (>= 0.90.0, < 2.0)
|
rubocop (>= 0.90.0, < 2.0)
|
||||||
rubocop-ast (>= 0.4.0)
|
rubocop-ast (>= 0.4.0)
|
||||||
rubocop-rails (2.9.1)
|
rubocop-rails (2.9.1)
|
||||||
@ -127,7 +127,7 @@ GEM
|
|||||||
rubocop-rspec (2.2.0)
|
rubocop-rspec (2.2.0)
|
||||||
rubocop (~> 1.0)
|
rubocop (~> 1.0)
|
||||||
rubocop-ast (>= 1.1.0)
|
rubocop-ast (>= 1.1.0)
|
||||||
rubocop-sorbet (0.5.1)
|
rubocop-sorbet (0.6.1)
|
||||||
rubocop
|
rubocop
|
||||||
ruby-macho (2.5.0)
|
ruby-macho (2.5.0)
|
||||||
ruby-progressbar (1.11.0)
|
ruby-progressbar (1.11.0)
|
||||||
@ -139,28 +139,30 @@ GEM
|
|||||||
simplecov_json_formatter (0.1.2)
|
simplecov_json_formatter (0.1.2)
|
||||||
sorbet (0.5.6274)
|
sorbet (0.5.6274)
|
||||||
sorbet-static (= 0.5.6274)
|
sorbet-static (= 0.5.6274)
|
||||||
sorbet-runtime (0.5.6267)
|
sorbet-runtime (0.5.6274)
|
||||||
sorbet-runtime-stub (0.2.0)
|
sorbet-runtime-stub (0.2.0)
|
||||||
sorbet-static (0.5.6274-universal-darwin-14)
|
sorbet-static (0.5.6274-universal-darwin-14)
|
||||||
spoom (1.0.7)
|
spoom (1.0.9)
|
||||||
colorize
|
colorize
|
||||||
sorbet (~> 0.5.5)
|
sorbet (~> 0.5.5)
|
||||||
sorbet-runtime
|
sorbet-runtime
|
||||||
thor (>= 0.19.2)
|
thor (>= 0.19.2)
|
||||||
tapioca (0.4.13)
|
tapioca (0.4.17)
|
||||||
|
bundler (>= 1.17.3)
|
||||||
parlour (>= 2.1.0)
|
parlour (>= 2.1.0)
|
||||||
pry (>= 0.12.2)
|
pry (>= 0.12.2)
|
||||||
sorbet-runtime
|
sorbet-runtime
|
||||||
sorbet-static (>= 0.4.4471)
|
sorbet-static (>= 0.4.4471)
|
||||||
spoom
|
spoom
|
||||||
thor (>= 0.19.2)
|
thor (>= 0.19.2)
|
||||||
thor (1.0.1)
|
thor (1.1.0)
|
||||||
tzinfo (2.0.4)
|
tzinfo (2.0.4)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.7.7)
|
unf_ext (0.0.7.7)
|
||||||
unicode-display_width (2.0.0)
|
unicode-display_width (2.0.0)
|
||||||
|
warning (1.2.0)
|
||||||
webrick (1.7.0)
|
webrick (1.7.0)
|
||||||
webrobots (0.1.2)
|
webrobots (0.1.2)
|
||||||
zeitwerk (2.4.2)
|
zeitwerk (2.4.2)
|
||||||
@ -174,6 +176,7 @@ DEPENDENCIES
|
|||||||
byebug
|
byebug
|
||||||
concurrent-ruby
|
concurrent-ruby
|
||||||
mechanize
|
mechanize
|
||||||
|
minitest
|
||||||
nokogiri
|
nokogiri
|
||||||
parallel_tests
|
parallel_tests
|
||||||
patchelf
|
patchelf
|
||||||
@ -197,6 +200,7 @@ DEPENDENCIES
|
|||||||
sorbet-runtime
|
sorbet-runtime
|
||||||
sorbet-runtime-stub
|
sorbet-runtime-stub
|
||||||
tapioca
|
tapioca
|
||||||
|
warning
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.17.3
|
1.17.3
|
||||||
|
|||||||
180
Library/Homebrew/archive.rb
Normal file
180
Library/Homebrew/archive.rb
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
# typed: false
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "digest/md5"
|
||||||
|
require "utils/curl"
|
||||||
|
|
||||||
|
# The Internet Archive API client.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
class Archive
|
||||||
|
extend T::Sig
|
||||||
|
|
||||||
|
include Context
|
||||||
|
include Utils::Curl
|
||||||
|
|
||||||
|
class Error < RuntimeError
|
||||||
|
end
|
||||||
|
|
||||||
|
URL_PREFIX = "https://archive.org"
|
||||||
|
S3_DOMAIN = "s3.us.archive.org"
|
||||||
|
|
||||||
|
sig { returns(String) }
|
||||||
|
def inspect
|
||||||
|
"#<Archive: item=#{@archive_item}>"
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { params(item: T.nilable(String)).void }
|
||||||
|
def initialize(item: "homebrew")
|
||||||
|
raise UsageError, "Must set the Archive item!" unless item
|
||||||
|
|
||||||
|
@archive_item = item
|
||||||
|
end
|
||||||
|
|
||||||
|
def open_api(url, *args, auth: true)
|
||||||
|
if auth
|
||||||
|
key = Homebrew::EnvConfig.internet_archive_key
|
||||||
|
raise UsageError, "HOMEBREW_INTERNET_ARCHIVE_KEY is unset." if key.blank?
|
||||||
|
|
||||||
|
if key.exclude?(":")
|
||||||
|
raise UsageError, "Use HOMEBREW_INTERNET_ARCHIVE_KEY=access:secret. See #{URL_PREFIX}/account/s3.php"
|
||||||
|
end
|
||||||
|
|
||||||
|
args += ["--header", "Authorization: AWS #{key}"]
|
||||||
|
end
|
||||||
|
|
||||||
|
curl(*args, url, print_stdout: false, secrets: key)
|
||||||
|
end
|
||||||
|
|
||||||
|
sig {
|
||||||
|
params(local_file: String,
|
||||||
|
directory: String,
|
||||||
|
remote_file: String,
|
||||||
|
warn_on_error: T.nilable(T::Boolean)).void
|
||||||
|
}
|
||||||
|
def upload(local_file, directory:, remote_file:, warn_on_error: false)
|
||||||
|
local_file = Pathname.new(local_file)
|
||||||
|
unless local_file.exist?
|
||||||
|
msg = "#{local_file} for upload doesn't exist!"
|
||||||
|
raise Error, msg unless warn_on_error
|
||||||
|
|
||||||
|
# Warn and return early here since we know this upload is going to fail.
|
||||||
|
opoo msg
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
md5_base64 = Digest::MD5.base64digest(local_file.read)
|
||||||
|
url = "https://#{@archive_item}.#{S3_DOMAIN}/#{directory}/#{remote_file}"
|
||||||
|
args = ["--upload-file", local_file, "--header", "Content-MD5: #{md5_base64}"]
|
||||||
|
args << "--fail" unless warn_on_error
|
||||||
|
result = T.unsafe(self).open_api(url, *args)
|
||||||
|
return if result.success? && result.stdout.exclude?("Error")
|
||||||
|
|
||||||
|
msg = "Bottle upload failed: #{result.stdout}"
|
||||||
|
raise msg unless warn_on_error
|
||||||
|
|
||||||
|
opoo msg
|
||||||
|
end
|
||||||
|
|
||||||
|
sig {
|
||||||
|
params(formula: Formula,
|
||||||
|
directory: String,
|
||||||
|
warn_on_error: T::Boolean).returns(String)
|
||||||
|
}
|
||||||
|
def mirror_formula(formula, directory: "mirror", warn_on_error: false)
|
||||||
|
formula.downloader.fetch
|
||||||
|
|
||||||
|
filename = ERB::Util.url_encode(formula.downloader.basename)
|
||||||
|
destination_url = "#{URL_PREFIX}/download/#{@archive_item}/#{directory}/#{filename}"
|
||||||
|
|
||||||
|
odebug "Uploading to #{destination_url}"
|
||||||
|
|
||||||
|
upload(
|
||||||
|
formula.downloader.cached_location,
|
||||||
|
directory: directory,
|
||||||
|
remote_file: filename,
|
||||||
|
warn_on_error: warn_on_error,
|
||||||
|
)
|
||||||
|
|
||||||
|
destination_url
|
||||||
|
end
|
||||||
|
|
||||||
|
# Gets the MD5 hash of the specified remote file.
|
||||||
|
#
|
||||||
|
# @return the hash, the empty string (if the file doesn't have a hash), nil (if the file doesn't exist)
|
||||||
|
sig { params(directory: String, remote_file: String).returns(T.nilable(String)) }
|
||||||
|
def remote_md5(directory:, remote_file:)
|
||||||
|
url = "https://#{@archive_item}.#{S3_DOMAIN}/#{directory}/#{remote_file}"
|
||||||
|
result = curl_output "--fail", "--silent", "--head", "--location", url
|
||||||
|
if result.success?
|
||||||
|
result.stdout.match(/^ETag: "(\h{32})"/)&.values_at(1)&.first || ""
|
||||||
|
else
|
||||||
|
raise Error if result.status.exitstatus != 22 && result.stderr.exclude?("404 Not Found")
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { params(directory: String, filename: String).returns(String) }
|
||||||
|
def file_delete_instructions(directory, filename)
|
||||||
|
<<~EOS
|
||||||
|
Run:
|
||||||
|
curl -X DELETE -H "Authorization: AWS $HOMEBREW_INTERNET_ARCHIVE_KEY" https://#{@archive_item}.#{S3_DOMAIN}/#{directory}/#{filename}
|
||||||
|
Or run:
|
||||||
|
ia delete #{@archive_item} #{directory}/#{filename}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
sig {
|
||||||
|
params(bottles_hash: T::Hash[String, T.untyped],
|
||||||
|
warn_on_error: T.nilable(T::Boolean)).void
|
||||||
|
}
|
||||||
|
def upload_bottles(bottles_hash, warn_on_error: false)
|
||||||
|
bottles_hash.each do |_formula_name, bottle_hash|
|
||||||
|
directory = bottle_hash["bintray"]["repository"]
|
||||||
|
bottle_count = bottle_hash["bottle"]["tags"].length
|
||||||
|
|
||||||
|
bottle_hash["bottle"]["tags"].each_value do |tag_hash|
|
||||||
|
filename = tag_hash["filename"] # URL encoded in Bottle::Filename#archive
|
||||||
|
delete_instructions = file_delete_instructions(directory, filename)
|
||||||
|
|
||||||
|
local_filename = tag_hash["local_filename"]
|
||||||
|
md5 = Digest::MD5.hexdigest(File.read(local_filename))
|
||||||
|
|
||||||
|
odebug "Checking remote file #{@archive_item}/#{directory}/#{filename}"
|
||||||
|
result = remote_md5(directory: directory, remote_file: filename)
|
||||||
|
case result
|
||||||
|
when nil
|
||||||
|
# File doesn't exist.
|
||||||
|
odebug "Uploading #{@archive_item}/#{directory}/#{filename}"
|
||||||
|
upload(local_filename,
|
||||||
|
directory: directory,
|
||||||
|
remote_file: filename,
|
||||||
|
warn_on_error: warn_on_error)
|
||||||
|
when md5
|
||||||
|
# File exists, hash matches.
|
||||||
|
odebug "#{filename} is already published with matching hash."
|
||||||
|
bottle_count -= 1
|
||||||
|
when ""
|
||||||
|
# File exists, but can't find hash
|
||||||
|
failed_message = "#{filename} is already published!"
|
||||||
|
raise Error, "#{failed_message}\n#{delete_instructions}" unless warn_on_error
|
||||||
|
|
||||||
|
opoo failed_message
|
||||||
|
else
|
||||||
|
# File exists, but hash either doesn't exist or is mismatched.
|
||||||
|
failed_message = <<~EOS
|
||||||
|
#{filename} is already published with a mismatched hash!
|
||||||
|
Expected: #{md5}
|
||||||
|
Actual: #{result}
|
||||||
|
EOS
|
||||||
|
raise Error, "#{failed_message}#{delete_instructions}" unless warn_on_error
|
||||||
|
|
||||||
|
opoo failed_message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
odebug "Uploaded #{bottle_count} bottles"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -14,6 +14,7 @@ class Bintray
|
|||||||
include Utils::Curl
|
include Utils::Curl
|
||||||
|
|
||||||
API_URL = "https://api.bintray.com"
|
API_URL = "https://api.bintray.com"
|
||||||
|
URL_REGEX = %r{^https://[\w-]+\.bintray\.com/}.freeze
|
||||||
|
|
||||||
class Error < RuntimeError
|
class Error < RuntimeError
|
||||||
end
|
end
|
||||||
|
|||||||
@ -48,7 +48,6 @@ HOMEBREW_TEMP="${HOMEBREW_TEMP:-${HOMEBREW_DEFAULT_TEMP}}"
|
|||||||
# Don't need shellcheck to follow these `source`.
|
# Don't need shellcheck to follow these `source`.
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
case "$*" in
|
case "$*" in
|
||||||
--prefix) echo "$HOMEBREW_PREFIX"; exit 0 ;;
|
|
||||||
--cellar) echo "$HOMEBREW_CELLAR"; exit 0 ;;
|
--cellar) echo "$HOMEBREW_CELLAR"; exit 0 ;;
|
||||||
--repository|--repo) echo "$HOMEBREW_REPOSITORY"; exit 0 ;;
|
--repository|--repo) echo "$HOMEBREW_REPOSITORY"; exit 0 ;;
|
||||||
--caskroom) echo "$HOMEBREW_PREFIX/Caskroom"; exit 0 ;;
|
--caskroom) echo "$HOMEBREW_PREFIX/Caskroom"; exit 0 ;;
|
||||||
@ -56,6 +55,8 @@ case "$*" in
|
|||||||
shellenv) source "$HOMEBREW_LIBRARY/Homebrew/cmd/shellenv.sh"; homebrew-shellenv; exit 0 ;;
|
shellenv) source "$HOMEBREW_LIBRARY/Homebrew/cmd/shellenv.sh"; homebrew-shellenv; exit 0 ;;
|
||||||
formulae) source "$HOMEBREW_LIBRARY/Homebrew/cmd/formulae.sh"; homebrew-formulae; exit 0 ;;
|
formulae) source "$HOMEBREW_LIBRARY/Homebrew/cmd/formulae.sh"; homebrew-formulae; exit 0 ;;
|
||||||
casks) source "$HOMEBREW_LIBRARY/Homebrew/cmd/casks.sh"; homebrew-casks; exit 0 ;;
|
casks) source "$HOMEBREW_LIBRARY/Homebrew/cmd/casks.sh"; homebrew-casks; exit 0 ;;
|
||||||
|
# falls back to cmd/prefix.rb on a non-zero return
|
||||||
|
--prefix*) source "$HOMEBREW_LIBRARY/Homebrew/prefix.sh"; homebrew-prefix "$@" && exit 0 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
#####
|
#####
|
||||||
@ -187,9 +188,9 @@ update-preinstall() {
|
|||||||
# last $HOMEBREW_AUTO_UPDATE_SECS.
|
# last $HOMEBREW_AUTO_UPDATE_SECS.
|
||||||
if [[ "$HOMEBREW_COMMAND" = "cask" ]]
|
if [[ "$HOMEBREW_COMMAND" = "cask" ]]
|
||||||
then
|
then
|
||||||
tap_fetch_head="$HOMEBREW_LIBRARY/Taps/homebrew/homebrew-cask/.git/FETCH_HEAD"
|
tap_fetch_head="$HOMEBREW_CASK_REPOSITORY/.git/FETCH_HEAD"
|
||||||
else
|
else
|
||||||
tap_fetch_head="$HOMEBREW_LIBRARY/Taps/homebrew/homebrew-core/.git/FETCH_HEAD"
|
tap_fetch_head="$HOMEBREW_CORE_REPOSITORY/.git/FETCH_HEAD"
|
||||||
fi
|
fi
|
||||||
if [[ -f "$tap_fetch_head" &&
|
if [[ -f "$tap_fetch_head" &&
|
||||||
-n "$(find "$tap_fetch_head" -type f -mtime -"${HOMEBREW_AUTO_UPDATE_SECS}"s 2>/dev/null)" ]]
|
-n "$(find "$tap_fetch_head" -type f -mtime -"${HOMEBREW_AUTO_UPDATE_SECS}"s 2>/dev/null)" ]]
|
||||||
@ -313,6 +314,20 @@ then
|
|||||||
HOMEBREW_USER_AGENT_VERSION="2.X.Y"
|
HOMEBREW_USER_AGENT_VERSION="2.X.Y"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
HOMEBREW_CASK_REPOSITORY="$HOMEBREW_LIBRARY/Taps/homebrew/homebrew-cask"
|
||||||
|
HOMEBREW_CORE_REPOSITORY="$HOMEBREW_LIBRARY/Taps/homebrew/homebrew-core"
|
||||||
|
|
||||||
|
# Don't need shellcheck to follow these `source`.
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
case "$*" in
|
||||||
|
--version|-v) source "$HOMEBREW_LIBRARY/Homebrew/cmd/--version.sh"; homebrew-version; exit 0 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ -n "$HOMEBREW_SIMULATE_MACOS_ON_LINUX" ]]
|
||||||
|
then
|
||||||
|
export HOMEBREW_FORCE_HOMEBREW_ON_LINUX="1"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -n "$HOMEBREW_MACOS" ]]
|
if [[ -n "$HOMEBREW_MACOS" ]]
|
||||||
then
|
then
|
||||||
HOMEBREW_PRODUCT="Homebrew"
|
HOMEBREW_PRODUCT="Homebrew"
|
||||||
@ -439,13 +454,6 @@ curl_version_output="$("$HOMEBREW_CURL" --version 2>/dev/null)"
|
|||||||
curl_name_and_version="${curl_version_output%% (*}"
|
curl_name_and_version="${curl_version_output%% (*}"
|
||||||
HOMEBREW_USER_AGENT_CURL="$HOMEBREW_USER_AGENT ${curl_name_and_version// //}"
|
HOMEBREW_USER_AGENT_CURL="$HOMEBREW_USER_AGENT ${curl_name_and_version// //}"
|
||||||
|
|
||||||
# Declared in bin/brew
|
|
||||||
export HOMEBREW_BREW_FILE
|
|
||||||
export HOMEBREW_PREFIX
|
|
||||||
export HOMEBREW_REPOSITORY
|
|
||||||
export HOMEBREW_LIBRARY
|
|
||||||
|
|
||||||
# Declared in brew.sh
|
|
||||||
export HOMEBREW_VERSION
|
export HOMEBREW_VERSION
|
||||||
export HOMEBREW_DEFAULT_CACHE
|
export HOMEBREW_DEFAULT_CACHE
|
||||||
export HOMEBREW_CACHE
|
export HOMEBREW_CACHE
|
||||||
@ -567,16 +575,16 @@ then
|
|||||||
# Don't allow non-developers to customise Ruby warnings.
|
# Don't allow non-developers to customise Ruby warnings.
|
||||||
unset HOMEBREW_RUBY_WARNINGS
|
unset HOMEBREW_RUBY_WARNINGS
|
||||||
|
|
||||||
# Disable Ruby options we don't need. RubyGems provides a decent speedup.
|
# Disable Ruby options we don't need.
|
||||||
RUBY_DISABLE_OPTIONS="--disable=gems,did_you_mean,rubyopt"
|
RUBY_DISABLE_OPTIONS="--disable=did_you_mean,rubyopt"
|
||||||
else
|
else
|
||||||
# Don't disable did_you_mean for developers as it's useful.
|
# Don't disable did_you_mean for developers as it's useful.
|
||||||
RUBY_DISABLE_OPTIONS="--disable=gems,rubyopt"
|
RUBY_DISABLE_OPTIONS="--disable=rubyopt"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "$HOMEBREW_RUBY_WARNINGS" ]]
|
if [[ -z "$HOMEBREW_RUBY_WARNINGS" ]]
|
||||||
then
|
then
|
||||||
export HOMEBREW_RUBY_WARNINGS="-W0"
|
export HOMEBREW_RUBY_WARNINGS="-W1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "$HOMEBREW_BOTTLE_DOMAIN" ]]
|
if [[ -z "$HOMEBREW_BOTTLE_DOMAIN" ]]
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
old_trap = trap("INT") { exit! 130 }
|
old_trap = trap("INT") { exit! 130 }
|
||||||
|
|
||||||
require "global"
|
require_relative "global"
|
||||||
require "build_options"
|
require "build_options"
|
||||||
require "cxxstdlib"
|
require "cxxstdlib"
|
||||||
require "keg"
|
require "keg"
|
||||||
@ -240,7 +240,14 @@ rescue Exception => e # rubocop:disable Lint/RescueException
|
|||||||
error_hash["env"] = e.env
|
error_hash["env"] = e.env
|
||||||
when "ErrorDuringExecution"
|
when "ErrorDuringExecution"
|
||||||
error_hash["cmd"] = e.cmd
|
error_hash["cmd"] = e.cmd
|
||||||
error_hash["status"] = e.status.exitstatus
|
error_hash["status"] = if e.status.is_a?(Process::Status)
|
||||||
|
{
|
||||||
|
exitstatus: e.status.exitstatus,
|
||||||
|
termsig: e.status.termsig,
|
||||||
|
}
|
||||||
|
else
|
||||||
|
e.status
|
||||||
|
end
|
||||||
error_hash["output"] = e.output
|
error_hash["output"] = e.output
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -165,7 +165,7 @@ module Cask
|
|||||||
odebug "Auditing stanzas which require an uninstall"
|
odebug "Auditing stanzas which require an uninstall"
|
||||||
|
|
||||||
return if cask.artifacts.none? { |k| k.is_a?(Artifact::Pkg) || k.is_a?(Artifact::Installer) }
|
return if cask.artifacts.none? { |k| k.is_a?(Artifact::Pkg) || k.is_a?(Artifact::Installer) }
|
||||||
return if cask.artifacts.any? { |k| k.is_a?(Artifact::Uninstall) }
|
return if cask.artifacts.any?(Artifact::Uninstall)
|
||||||
|
|
||||||
add_error "installer and pkg stanzas require an uninstall stanza"
|
add_error "installer and pkg stanzas require an uninstall stanza"
|
||||||
end
|
end
|
||||||
@ -696,7 +696,7 @@ module Cask
|
|||||||
def check_denylist
|
def check_denylist
|
||||||
return unless cask.tap
|
return unless cask.tap
|
||||||
return unless cask.tap.official?
|
return unless cask.tap.official?
|
||||||
return unless reason = Denylist.reason(cask.token)
|
return unless (reason = Denylist.reason(cask.token))
|
||||||
|
|
||||||
add_error "#{cask.token} is not allowed: #{reason}"
|
add_error "#{cask.token} is not allowed: #{reason}"
|
||||||
end
|
end
|
||||||
@ -717,7 +717,12 @@ module Cask
|
|||||||
|
|
||||||
check_url_for_https_availability(cask.appcast, check_content: true) if cask.appcast && appcast?
|
check_url_for_https_availability(cask.appcast, check_content: true) if cask.appcast && appcast?
|
||||||
|
|
||||||
check_url_for_https_availability(cask.homepage, check_content: true, user_agents: [:browser]) if cask.homepage
|
return unless cask.homepage
|
||||||
|
|
||||||
|
check_url_for_https_availability(cask.homepage,
|
||||||
|
user_agents: [:browser, :default],
|
||||||
|
check_content: true,
|
||||||
|
strict: strict?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_url_for_https_availability(url_to_check, **options)
|
def check_url_for_https_availability(url_to_check, **options)
|
||||||
|
|||||||
@ -162,7 +162,7 @@ module Cask
|
|||||||
end
|
end
|
||||||
|
|
||||||
def eql?(other)
|
def eql?(other)
|
||||||
token == other.token
|
instance_of?(other.class) && token == other.token
|
||||||
end
|
end
|
||||||
alias == eql?
|
alias == eql?
|
||||||
|
|
||||||
|
|||||||
@ -157,7 +157,7 @@ module Cask
|
|||||||
end
|
end
|
||||||
|
|
||||||
def load(config:)
|
def load(config:)
|
||||||
tap.install unless tap.installed?
|
raise TapCaskUnavailableError.new(tap, token) unless tap.installed?
|
||||||
|
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|||||||
@ -39,9 +39,9 @@ module Cask
|
|||||||
Pathname.glob(path.join("*")).sort.select(&:directory?).map do |path|
|
Pathname.glob(path.join("*")).sort.select(&:directory?).map do |path|
|
||||||
token = path.basename.to_s
|
token = path.basename.to_s
|
||||||
|
|
||||||
if tap_path = CaskLoader.tap_paths(token).first
|
if (tap_path = CaskLoader.tap_paths(token).first)
|
||||||
CaskLoader::FromTapPathLoader.new(tap_path).load(config: config)
|
CaskLoader::FromTapPathLoader.new(tap_path).load(config: config)
|
||||||
elsif caskroom_path = Pathname.glob(path.join(".metadata/*/*/*/*.rb")).first
|
elsif (caskroom_path = Pathname.glob(path.join(".metadata/*/*/*/*.rb")).first)
|
||||||
CaskLoader::FromPathLoader.new(caskroom_path).load(config: config)
|
CaskLoader::FromPathLoader.new(caskroom_path).load(config: config)
|
||||||
else
|
else
|
||||||
CaskLoader.load(token, config: config)
|
CaskLoader.load(token, config: config)
|
||||||
|
|||||||
@ -19,9 +19,10 @@ module Cask
|
|||||||
@quarantine = quarantine
|
@quarantine = quarantine
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch(verify_download_integrity: true)
|
def fetch(quiet: nil, verify_download_integrity: true, timeout: nil)
|
||||||
downloaded_path = begin
|
downloaded_path = begin
|
||||||
downloader.fetch
|
downloader.shutup! if quiet
|
||||||
|
downloader.fetch(timeout: timeout)
|
||||||
downloader.cached_location
|
downloader.cached_location
|
||||||
rescue => e
|
rescue => e
|
||||||
error = CaskError.new("Download failed on Cask '#{cask}' with message: #{e}")
|
error = CaskError.new("Download failed on Cask '#{cask}' with message: #{e}")
|
||||||
@ -40,8 +41,8 @@ module Cask
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def time_file_size
|
def time_file_size(timeout: nil)
|
||||||
downloader.resolved_time_file_size
|
downloader.resolved_time_file_size(timeout: timeout)
|
||||||
end
|
end
|
||||||
|
|
||||||
def clear_cache
|
def clear_cache
|
||||||
|
|||||||
@ -181,7 +181,11 @@ module Cask
|
|||||||
|
|
||||||
set_unique_stanza(:url, args.empty? && options.empty? && !block_given?) do
|
set_unique_stanza(:url, args.empty? && options.empty? && !block_given?) do
|
||||||
if block_given?
|
if block_given?
|
||||||
LazyObject.new { URL.new(*yield, from_block: true, caller_location: caller_location) }
|
LazyObject.new do
|
||||||
|
*args = yield
|
||||||
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
||||||
|
URL.new(*args, **options, from_block: true, caller_location: caller_location)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
URL.new(*args, **options, caller_location: caller_location)
|
URL.new(*args, **options, caller_location: caller_location)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -103,6 +103,27 @@ module Cask
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Error when a cask in a specific tap is not available.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
class TapCaskUnavailableError < CaskUnavailableError
|
||||||
|
extend T::Sig
|
||||||
|
|
||||||
|
attr_reader :tap
|
||||||
|
|
||||||
|
def initialize(tap, token)
|
||||||
|
super("#{tap}/#{token}")
|
||||||
|
@tap = tap
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { returns(String) }
|
||||||
|
def to_s
|
||||||
|
s = super
|
||||||
|
s += "\nPlease tap it and then try again: brew tap #{tap}" unless tap.installed?
|
||||||
|
s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Error when a cask already exists.
|
# Error when a cask already exists.
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
|
|||||||
@ -62,13 +62,15 @@ module Cask
|
|||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch
|
sig { params(quiet: T.nilable(T::Boolean), timeout: T.nilable(T.any(Integer, Float))).void }
|
||||||
|
def fetch(quiet: nil, timeout: nil)
|
||||||
odebug "Cask::Installer#fetch"
|
odebug "Cask::Installer#fetch"
|
||||||
|
|
||||||
verify_has_sha if require_sha? && !force?
|
verify_has_sha if require_sha? && !force?
|
||||||
satisfy_dependencies
|
|
||||||
|
|
||||||
download
|
download(quiet: quiet, timeout: timeout)
|
||||||
|
|
||||||
|
satisfy_dependencies
|
||||||
end
|
end
|
||||||
|
|
||||||
def stage
|
def stage
|
||||||
@ -146,7 +148,7 @@ module Cask
|
|||||||
installed_cask = installed_caskfile.exist? ? CaskLoader.load(installed_caskfile) : @cask
|
installed_cask = installed_caskfile.exist? ? CaskLoader.load(installed_caskfile) : @cask
|
||||||
|
|
||||||
# Always force uninstallation, ignore method parameter
|
# Always force uninstallation, ignore method parameter
|
||||||
Installer.new(installed_cask, binaries: binaries?, verbose: verbose?, force: true, upgrade: upgrade?).uninstall
|
Installer.new(installed_cask, verbose: verbose?, force: true, upgrade: upgrade?).uninstall
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { returns(String) }
|
sig { returns(String) }
|
||||||
@ -162,9 +164,10 @@ module Cask
|
|||||||
@downloader ||= Download.new(@cask, quarantine: quarantine?)
|
@downloader ||= Download.new(@cask, quarantine: quarantine?)
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { returns(Pathname) }
|
sig { params(quiet: T.nilable(T::Boolean), timeout: T.nilable(T.any(Integer, Float))).returns(Pathname) }
|
||||||
def download
|
def download(quiet: nil, timeout: nil)
|
||||||
@download ||= downloader.fetch(verify_download_integrity: @verify_download_integrity)
|
@download ||= downloader.fetch(quiet: quiet, verify_download_integrity: @verify_download_integrity,
|
||||||
|
timeout: timeout)
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify_has_sha
|
def verify_has_sha
|
||||||
@ -179,7 +182,7 @@ module Cask
|
|||||||
|
|
||||||
def primary_container
|
def primary_container
|
||||||
@primary_container ||= begin
|
@primary_container ||= begin
|
||||||
downloaded_path = download
|
downloaded_path = download(quiet: true)
|
||||||
UnpackStrategy.detect(downloaded_path, type: @cask.container&.type, merge_xattrs: true)
|
UnpackStrategy.detect(downloaded_path, type: @cask.container&.type, merge_xattrs: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -191,7 +194,7 @@ module Cask
|
|||||||
|
|
||||||
basename = downloader.basename
|
basename = downloader.basename
|
||||||
|
|
||||||
if nested_container = @cask.container&.nested
|
if (nested_container = @cask.container&.nested)
|
||||||
Dir.mktmpdir do |tmpdir|
|
Dir.mktmpdir do |tmpdir|
|
||||||
tmpdir = Pathname(tmpdir)
|
tmpdir = Pathname(tmpdir)
|
||||||
primary_container.extract(to: tmpdir, basename: basename, verbose: verbose?)
|
primary_container.extract(to: tmpdir, basename: basename, verbose: verbose?)
|
||||||
|
|||||||
@ -32,9 +32,7 @@ module Cask
|
|||||||
odebug "Deleting pkg files"
|
odebug "Deleting pkg files"
|
||||||
@command.run!(
|
@command.run!(
|
||||||
"/usr/bin/xargs",
|
"/usr/bin/xargs",
|
||||||
args: [
|
args: ["-0", "--", "/bin/rm", "--"],
|
||||||
"-0", "--", "/bin/rm", "--"
|
|
||||||
],
|
|
||||||
input: pkgutil_bom_files.join("\0"),
|
input: pkgutil_bom_files.join("\0"),
|
||||||
sudo: true,
|
sudo: true,
|
||||||
)
|
)
|
||||||
@ -44,9 +42,7 @@ module Cask
|
|||||||
odebug "Deleting pkg symlinks and special files"
|
odebug "Deleting pkg symlinks and special files"
|
||||||
@command.run!(
|
@command.run!(
|
||||||
"/usr/bin/xargs",
|
"/usr/bin/xargs",
|
||||||
args: [
|
args: ["-0", "--", "/bin/rm", "--"],
|
||||||
"-0", "--", "/bin/rm", "--"
|
|
||||||
],
|
|
||||||
input: pkgutil_bom_specials.join("\0"),
|
input: pkgutil_bom_specials.join("\0"),
|
||||||
sudo: true,
|
sudo: true,
|
||||||
)
|
)
|
||||||
@ -54,19 +50,10 @@ module Cask
|
|||||||
|
|
||||||
unless pkgutil_bom_dirs.empty?
|
unless pkgutil_bom_dirs.empty?
|
||||||
odebug "Deleting pkg directories"
|
odebug "Deleting pkg directories"
|
||||||
deepest_path_first(pkgutil_bom_dirs).each do |dir|
|
rmdir(deepest_path_first(pkgutil_bom_dirs))
|
||||||
with_full_permissions(dir) do
|
|
||||||
clean_broken_symlinks(dir)
|
|
||||||
clean_ds_store(dir)
|
|
||||||
rmdir(dir)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if root.directory? && !MacOS.undeletable?(root)
|
rmdir(root) unless MacOS.undeletable?(root)
|
||||||
clean_ds_store(root)
|
|
||||||
rmdir(root)
|
|
||||||
end
|
|
||||||
|
|
||||||
forget
|
forget
|
||||||
end
|
end
|
||||||
@ -118,55 +105,51 @@ module Cask
|
|||||||
path.symlink? || path.chardev? || path.blockdev?
|
path.symlink? || path.chardev? || path.blockdev?
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { params(path: Pathname).void }
|
# Helper script to delete empty directories after deleting `.DS_Store` files and broken symlinks.
|
||||||
def rmdir(path)
|
# Needed in order to execute all file operations with `sudo`.
|
||||||
return unless path.children.empty?
|
RMDIR_SH = <<~'BASH'
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
if path.symlink?
|
for path in "${@}"; do
|
||||||
@command.run!("/bin/rm", args: ["-f", "--", path], sudo: true)
|
if [[ ! -e "${path}" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -e "${path}/.DS_Store" ]]; then
|
||||||
|
/bin/rm -f "${path}/.DS_Store"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Some packages leave broken symlinks around; we clean them out before
|
||||||
|
# attempting to `rmdir` to prevent extra cruft from accumulating.
|
||||||
|
/usr/bin/find "${path}" -mindepth 1 -maxdepth 1 -type l ! -exec /bin/test -e {} \; -delete
|
||||||
|
|
||||||
|
if [[ -L "${path}" ]]; then
|
||||||
|
# Delete directory symlink.
|
||||||
|
/bin/rm "${path}"
|
||||||
|
elif [[ -d "${path}" ]]; then
|
||||||
|
# Delete directory if empty.
|
||||||
|
/usr/bin/find "${path}" -maxdepth 0 -type d -empty -exec /bin/rmdir {} \;
|
||||||
else
|
else
|
||||||
@command.run!("/bin/rmdir", args: ["--", path], sudo: true)
|
# Try `rmdir` anyways to show a proper error.
|
||||||
end
|
/bin/rmdir "${path}"
|
||||||
end
|
fi
|
||||||
|
done
|
||||||
|
BASH
|
||||||
|
private_constant :RMDIR_SH
|
||||||
|
|
||||||
sig { params(path: Pathname, _block: T.proc.void).void }
|
sig { params(path: T.any(Pathname, T::Array[Pathname])).void }
|
||||||
def with_full_permissions(path, &_block)
|
def rmdir(path)
|
||||||
original_mode = (path.stat.mode % 01000).to_s(8)
|
@command.run!(
|
||||||
original_flags = @command.run!("/usr/bin/stat", args: ["-f", "%Of", "--", path]).stdout.chomp
|
"/usr/bin/xargs",
|
||||||
|
args: ["-0", "--", "/bin/bash", "-c", RMDIR_SH, "--"],
|
||||||
@command.run!("/bin/chmod", args: ["--", "777", path], sudo: true)
|
input: Array(path).join("\0"),
|
||||||
yield
|
sudo: true,
|
||||||
ensure
|
)
|
||||||
if path.exist? # block may have removed dir
|
|
||||||
@command.run!("/bin/chmod", args: ["--", original_mode, path], sudo: true)
|
|
||||||
@command.run!("/usr/bin/chflags", args: ["--", original_flags, path], sudo: true)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { params(paths: T::Array[Pathname]).returns(T::Array[Pathname]) }
|
sig { params(paths: T::Array[Pathname]).returns(T::Array[Pathname]) }
|
||||||
def deepest_path_first(paths)
|
def deepest_path_first(paths)
|
||||||
paths.sort_by { |path| -path.to_s.split(File::SEPARATOR).count }
|
paths.sort_by { |path| -path.to_s.split(File::SEPARATOR).count }
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { params(dir: Pathname).void }
|
|
||||||
def clean_ds_store(dir)
|
|
||||||
return unless (ds_store = dir.join(".DS_Store")).exist?
|
|
||||||
|
|
||||||
@command.run!("/bin/rm", args: ["--", ds_store], sudo: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Some packages leave broken symlinks around; we clean them out before
|
|
||||||
# attempting to `rmdir` to prevent extra cruft from accumulating.
|
|
||||||
sig { params(dir: Pathname).void }
|
|
||||||
def clean_broken_symlinks(dir)
|
|
||||||
dir.children.select(&method(:broken_symlink?)).each do |path|
|
|
||||||
@command.run!("/bin/rm", args: ["--", path], sudo: true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
sig { params(path: Pathname).returns(T::Boolean) }
|
|
||||||
def broken_symlink?(path)
|
|
||||||
path.symlink? && !path.exist?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
require "utils/bottles"
|
require "utils/bottles"
|
||||||
|
|
||||||
require "utils/gems"
|
|
||||||
require "formula"
|
require "formula"
|
||||||
require "cask/cask_loader"
|
require "cask/cask_loader"
|
||||||
require "set"
|
require "set"
|
||||||
@ -80,7 +79,7 @@ module Homebrew
|
|||||||
|
|
||||||
version = Version.new(version)
|
version = Version.new(version)
|
||||||
|
|
||||||
return false unless formula_name = basename.to_s[/\A(.*?)(?:--.*?)*--?(?:#{Regexp.escape(version)})/, 1]
|
return false unless (formula_name = basename.to_s[/\A(.*?)(?:--.*?)*--?(?:#{Regexp.escape(version)})/, 1])
|
||||||
|
|
||||||
formula = begin
|
formula = begin
|
||||||
Formulary.from_rack(HOMEBREW_CELLAR/formula_name)
|
Formulary.from_rack(HOMEBREW_CELLAR/formula_name)
|
||||||
@ -95,7 +94,7 @@ module Homebrew
|
|||||||
if resource_name == "patch"
|
if resource_name == "patch"
|
||||||
patch_hashes = formula.stable&.patches&.select(&:external?)&.map(&:resource)&.map(&:version)
|
patch_hashes = formula.stable&.patches&.select(&:external?)&.map(&:resource)&.map(&:version)
|
||||||
return true unless patch_hashes&.include?(Checksum.new(version.to_s))
|
return true unless patch_hashes&.include?(Checksum.new(version.to_s))
|
||||||
elsif resource_name && resource_version = formula.stable&.resources&.dig(resource_name)&.version
|
elsif resource_name && (resource_version = formula.stable&.resources&.dig(resource_name)&.version)
|
||||||
return true if resource_version != version
|
return true if resource_version != version
|
||||||
elsif version.is_a?(PkgVersion)
|
elsif version.is_a?(PkgVersion)
|
||||||
return true if formula.pkg_version > version
|
return true if formula.pkg_version > version
|
||||||
@ -111,7 +110,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
def stale_cask?(scrub)
|
def stale_cask?(scrub)
|
||||||
return false unless name = basename.to_s[/\A(.*?)--/, 1]
|
return false unless (name = basename.to_s[/\A(.*?)--/, 1])
|
||||||
|
|
||||||
cask = begin
|
cask = begin
|
||||||
Cask::CaskLoader.load(name)
|
Cask::CaskLoader.load(name)
|
||||||
|
|||||||
@ -132,6 +132,12 @@ module Homebrew
|
|||||||
|
|
||||||
raise unreadable_error if unreadable_error.present?
|
raise unreadable_error if unreadable_error.present?
|
||||||
|
|
||||||
|
user, repo, short_name = name.downcase.split("/", 3)
|
||||||
|
if repo.present? && short_name.present?
|
||||||
|
tap = Tap.fetch(user, repo)
|
||||||
|
raise TapFormulaOrCaskUnavailableError.new(tap, short_name)
|
||||||
|
end
|
||||||
|
|
||||||
raise FormulaOrCaskUnavailableError, name
|
raise FormulaOrCaskUnavailableError, name
|
||||||
end
|
end
|
||||||
private :load_formula_or_cask
|
private :load_formula_or_cask
|
||||||
@ -265,13 +271,10 @@ module Homebrew
|
|||||||
opt_prefix = HOMEBREW_PREFIX/"opt/#{rack.basename}"
|
opt_prefix = HOMEBREW_PREFIX/"opt/#{rack.basename}"
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if opt_prefix.symlink? && opt_prefix.directory?
|
return Keg.new(opt_prefix.resolved_path) if opt_prefix.symlink? && opt_prefix.directory?
|
||||||
Keg.new(opt_prefix.resolved_path)
|
return Keg.new(linked_keg_ref.resolved_path) if linked_keg_ref.symlink? && linked_keg_ref.directory?
|
||||||
elsif linked_keg_ref.symlink? && linked_keg_ref.directory?
|
return Keg.new(dirs.first) if dirs.length == 1
|
||||||
Keg.new(linked_keg_ref.resolved_path)
|
|
||||||
elsif dirs.length == 1
|
|
||||||
Keg.new(dirs.first)
|
|
||||||
else
|
|
||||||
f = if name.include?("/") || File.exist?(name)
|
f = if name.include?("/") || File.exist?(name)
|
||||||
Formulary.factory(name)
|
Formulary.factory(name)
|
||||||
else
|
else
|
||||||
@ -286,7 +289,6 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
Keg.new(prefix)
|
Keg.new(prefix)
|
||||||
end
|
|
||||||
rescue FormulaUnavailableError
|
rescue FormulaUnavailableError
|
||||||
raise MultipleVersionsInstalledError, <<~EOS
|
raise MultipleVersionsInstalledError, <<~EOS
|
||||||
Multiple kegs installed to #{rack}
|
Multiple kegs installed to #{rack}
|
||||||
|
|||||||
@ -474,7 +474,7 @@ module Homebrew
|
|||||||
|
|
||||||
"<#{type}>"
|
"<#{type}>"
|
||||||
end.compact
|
end.compact
|
||||||
types << "<subcommand>" if @named_args_type.any? { |type| type.is_a? String }
|
types << "<subcommand>" if @named_args_type.any?(String)
|
||||||
types.join("|")
|
types.join("|")
|
||||||
elsif SYMBOL_TO_USAGE_MAPPING.key? @named_args_type
|
elsif SYMBOL_TO_USAGE_MAPPING.key? @named_args_type
|
||||||
SYMBOL_TO_USAGE_MAPPING[@named_args_type]
|
SYMBOL_TO_USAGE_MAPPING[@named_args_type]
|
||||||
@ -623,7 +623,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
def split_non_options(argv)
|
def split_non_options(argv)
|
||||||
if sep = argv.index("--")
|
if (sep = argv.index("--"))
|
||||||
[argv.take(sep), argv.drop(sep + 1)]
|
[argv.take(sep), argv.drop(sep + 1)]
|
||||||
else
|
else
|
||||||
[argv, []]
|
[argv, []]
|
||||||
|
|||||||
@ -18,8 +18,7 @@ module Homebrew
|
|||||||
- macOS ARM: `#{HOMEBREW_MACOS_ARM_DEFAULT_PREFIX}`
|
- macOS ARM: `#{HOMEBREW_MACOS_ARM_DEFAULT_PREFIX}`
|
||||||
- Linux: `#{HOMEBREW_LINUX_DEFAULT_PREFIX}`
|
- Linux: `#{HOMEBREW_LINUX_DEFAULT_PREFIX}`
|
||||||
|
|
||||||
If <formula> is provided, display the location in the Cellar where <formula>
|
If <formula> is provided, display the location where <formula> is or would be installed.
|
||||||
is or would be installed.
|
|
||||||
EOS
|
EOS
|
||||||
switch "--unbrewed",
|
switch "--unbrewed",
|
||||||
description: "List files in Homebrew's prefix not installed by Homebrew."
|
description: "List files in Homebrew's prefix not installed by Homebrew."
|
||||||
@ -45,13 +44,10 @@ module Homebrew
|
|||||||
else
|
else
|
||||||
formulae = args.named.to_resolved_formulae
|
formulae = args.named.to_resolved_formulae
|
||||||
prefixes = formulae.map do |f|
|
prefixes = formulae.map do |f|
|
||||||
if f.opt_prefix.exist?
|
next nil if args.installed? && !f.opt_prefix.exist?
|
||||||
|
|
||||||
|
# this case wil be short-circuited by brew.sh logic for a single formula
|
||||||
f.opt_prefix
|
f.opt_prefix
|
||||||
elsif args.installed?
|
|
||||||
nil
|
|
||||||
else
|
|
||||||
f.latest_installed_prefix
|
|
||||||
end
|
|
||||||
end.compact
|
end.compact
|
||||||
puts prefixes
|
puts prefixes
|
||||||
if args.installed?
|
if args.installed?
|
||||||
|
|||||||
@ -1,30 +0,0 @@
|
|||||||
# typed: true
|
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require "cli/parser"
|
|
||||||
|
|
||||||
module Homebrew
|
|
||||||
extend T::Sig
|
|
||||||
|
|
||||||
module_function
|
|
||||||
|
|
||||||
sig { returns(CLI::Parser) }
|
|
||||||
def __version_args
|
|
||||||
Homebrew::CLI::Parser.new do
|
|
||||||
description <<~EOS
|
|
||||||
Print the version numbers of Homebrew, Homebrew/homebrew-core and Homebrew/homebrew-cask
|
|
||||||
(if tapped) to standard output.
|
|
||||||
EOS
|
|
||||||
|
|
||||||
named_args :none
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def __version
|
|
||||||
__version_args.parse
|
|
||||||
|
|
||||||
puts "Homebrew #{HOMEBREW_VERSION}"
|
|
||||||
puts "#{CoreTap.instance.full_name} #{CoreTap.instance.version_string}"
|
|
||||||
puts "#{Tap.default_cask_tap.full_name} #{Tap.default_cask_tap.version_string}" if Tap.default_cask_tap.installed?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
31
Library/Homebrew/cmd/--version.sh
Normal file
31
Library/Homebrew/cmd/--version.sh
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#: * `--version`, `-v`
|
||||||
|
#:
|
||||||
|
#: Print the version numbers of Homebrew, Homebrew/homebrew-core and Homebrew/homebrew-cask (if tapped) to standard output.
|
||||||
|
|
||||||
|
version_string() {
|
||||||
|
local repo="$1"
|
||||||
|
if ! [ -d "$repo" ]; then
|
||||||
|
echo "N/A"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local pretty_revision
|
||||||
|
pretty_revision="$(git -C "$repo" rev-parse --short --verify --quiet HEAD)"
|
||||||
|
if [ -z "$pretty_revision" ]; then
|
||||||
|
echo "(no Git repository)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local git_last_commit_date
|
||||||
|
git_last_commit_date=$(git -C "$repo" show -s --format='%cd' --date=short HEAD)
|
||||||
|
echo "(git revision ${pretty_revision}; last commit ${git_last_commit_date})"
|
||||||
|
}
|
||||||
|
|
||||||
|
homebrew-version() {
|
||||||
|
echo "Homebrew $HOMEBREW_VERSION"
|
||||||
|
echo "Homebrew/homebrew-core $(version_string "$HOMEBREW_CORE_REPOSITORY")"
|
||||||
|
|
||||||
|
if [ -d "$HOMEBREW_CASK_REPOSITORY" ]; then
|
||||||
|
echo "Homebrew/homebrew-cask $(version_string "$HOMEBREW_CASK_REPOSITORY")"
|
||||||
|
fi
|
||||||
|
}
|
||||||
@ -55,7 +55,7 @@ module Homebrew
|
|||||||
files["00.tap.out"] = { content: tap }
|
files["00.tap.out"] = { content: tap }
|
||||||
end
|
end
|
||||||
|
|
||||||
odie "`brew gist-logs` requires HOMEBREW_GITHUB_API_TOKEN to be set!" if GitHub.api_credentials_type == :none
|
odie "`brew gist-logs` requires HOMEBREW_GITHUB_API_TOKEN to be set!" if GitHub::API.credentials_type == :none
|
||||||
|
|
||||||
# Description formatted to work well as page title when viewing gist
|
# Description formatted to work well as page title when viewing gist
|
||||||
descr = if f.core_formula?
|
descr = if f.core_formula?
|
||||||
@ -63,9 +63,9 @@ module Homebrew
|
|||||||
else
|
else
|
||||||
"#{f.name} (#{f.full_name}) on #{OS_VERSION} - Homebrew build logs"
|
"#{f.name} (#{f.full_name}) on #{OS_VERSION} - Homebrew build logs"
|
||||||
end
|
end
|
||||||
url = create_gist(files, descr, private: args.private?)
|
url = GitHub.create_gist(files, descr, private: args.private?)
|
||||||
|
|
||||||
url = create_issue(f.tap, "#{f.name} failed to build on #{MacOS.full_version}", url) if args.new_issue?
|
url = GitHub.create_issue(f.tap, "#{f.name} failed to build on #{MacOS.full_version}", url) if args.new_issue?
|
||||||
|
|
||||||
puts url if url
|
puts url if url
|
||||||
end
|
end
|
||||||
@ -85,9 +85,9 @@ module Homebrew
|
|||||||
|
|
||||||
# Causes some terminals to display secure password entry indicators.
|
# Causes some terminals to display secure password entry indicators.
|
||||||
def noecho_gets
|
def noecho_gets
|
||||||
system "stty -echo"
|
system "stty", "-echo"
|
||||||
result = $stdin.gets
|
result = $stdin.gets
|
||||||
system "stty echo"
|
system "stty", "echo"
|
||||||
puts
|
puts
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
@ -108,20 +108,6 @@ module Homebrew
|
|||||||
logs
|
logs
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_gist(files, description, private:)
|
|
||||||
url = "https://api.github.com/gists"
|
|
||||||
data = { "public" => !private, "files" => files, "description" => description }
|
|
||||||
scopes = GitHub::CREATE_GIST_SCOPES
|
|
||||||
GitHub.open_api(url, data: data, scopes: scopes)["html_url"]
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_issue(repo, title, body)
|
|
||||||
url = "https://api.github.com/repos/#{repo}/issues"
|
|
||||||
data = { "title" => title, "body" => body }
|
|
||||||
scopes = GitHub::CREATE_ISSUE_FORK_OR_PR_SCOPES
|
|
||||||
GitHub.open_api(url, data: data, scopes: scopes)["html_url"]
|
|
||||||
end
|
|
||||||
|
|
||||||
def gist_logs
|
def gist_logs
|
||||||
args = gist_logs_args.parse
|
args = gist_logs_args.parse
|
||||||
|
|
||||||
|
|||||||
@ -227,7 +227,7 @@ module Homebrew
|
|||||||
def info_formula(f, args:)
|
def info_formula(f, args:)
|
||||||
specs = []
|
specs = []
|
||||||
|
|
||||||
if stable = f.stable
|
if (stable = f.stable)
|
||||||
s = "stable #{stable.version}"
|
s = "stable #{stable.version}"
|
||||||
s += " (bottled)" if stable.bottled? && f.pour_bottle?
|
s += " (bottled)" if stable.bottled? && f.pour_bottle?
|
||||||
specs << s
|
specs << s
|
||||||
@ -338,6 +338,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
def info_cask(cask, args:)
|
def info_cask(cask, args:)
|
||||||
|
require "cask/cmd"
|
||||||
require "cask/cmd/info"
|
require "cask/cmd/info"
|
||||||
|
|
||||||
Cask::Cmd::Info.info(cask)
|
Cask::Cmd::Info.info(cask)
|
||||||
|
|||||||
@ -264,7 +264,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
opoo msg if msg
|
opoo msg if msg
|
||||||
elsif !f.any_version_installed? && old_formula = f.old_installed_formulae.first
|
elsif !f.any_version_installed? && (old_formula = f.old_installed_formulae.first)
|
||||||
msg = "#{old_formula.full_name} #{old_formula.any_installed_version} already installed"
|
msg = "#{old_formula.full_name} #{old_formula.any_installed_version} already installed"
|
||||||
msg = if !old_formula.linked? && !old_formula.keg_only?
|
msg = if !old_formula.linked? && !old_formula.keg_only?
|
||||||
<<~EOS
|
<<~EOS
|
||||||
|
|||||||
@ -51,7 +51,7 @@ module Homebrew
|
|||||||
|
|
||||||
def git_log(cd_dir, path = nil, tap = nil, args:)
|
def git_log(cd_dir, path = nil, tap = nil, args:)
|
||||||
cd cd_dir
|
cd cd_dir
|
||||||
repo = Utils.popen_read("git rev-parse --show-toplevel").chomp
|
repo = Utils.popen_read("git", "rev-parse", "--show-toplevel").chomp
|
||||||
if tap
|
if tap
|
||||||
name = tap.to_s
|
name = tap.to_s
|
||||||
git_cd = "$(brew --repo #{tap})"
|
git_cd = "$(brew --repo #{tap})"
|
||||||
|
|||||||
@ -73,7 +73,7 @@ module Homebrew
|
|||||||
def search
|
def search
|
||||||
args = search_args.parse
|
args = search_args.parse
|
||||||
|
|
||||||
if package_manager = PACKAGE_MANAGERS.find { |name,| args[:"#{name}?"] }
|
if (package_manager = PACKAGE_MANAGERS.find { |name,| args[:"#{name}?"] })
|
||||||
_, url = package_manager
|
_, url = package_manager
|
||||||
exec_browser url.call(URI.encode_www_form_component(args.named.join(" ")))
|
exec_browser url.call(URI.encode_www_form_component(args.named.join(" ")))
|
||||||
return
|
return
|
||||||
|
|||||||
@ -54,6 +54,7 @@ module Homebrew
|
|||||||
|
|
||||||
Uninstall.uninstall_kegs(
|
Uninstall.uninstall_kegs(
|
||||||
kegs_by_rack,
|
kegs_by_rack,
|
||||||
|
casks: casks,
|
||||||
force: args.force?,
|
force: args.force?,
|
||||||
ignore_dependencies: args.ignore_dependencies?,
|
ignore_dependencies: args.ignore_dependencies?,
|
||||||
named_args: args.named,
|
named_args: args.named,
|
||||||
@ -68,7 +69,6 @@ module Homebrew
|
|||||||
else
|
else
|
||||||
T.unsafe(Cask::Cmd::Uninstall).uninstall_casks(
|
T.unsafe(Cask::Cmd::Uninstall).uninstall_casks(
|
||||||
*casks,
|
*casks,
|
||||||
binaries: EnvConfig.cask_opts_binaries?,
|
|
||||||
verbose: args.verbose?,
|
verbose: args.verbose?,
|
||||||
force: args.force?,
|
force: args.force?,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -129,15 +129,40 @@ module Homebrew
|
|||||||
if hub.empty?
|
if hub.empty?
|
||||||
puts_stdout_or_stderr "No changes to formulae." unless args.quiet?
|
puts_stdout_or_stderr "No changes to formulae." unless args.quiet?
|
||||||
else
|
else
|
||||||
hub.dump(updated_formula_report: !args.preinstall?)
|
hub.dump(updated_formula_report: !args.preinstall?) unless args.quiet?
|
||||||
hub.reporters.each(&:migrate_tap_migration)
|
hub.reporters.each(&:migrate_tap_migration)
|
||||||
hub.reporters.each { |r| r.migrate_formula_rename(force: args.force?, verbose: args.verbose?) }
|
hub.reporters.each { |r| r.migrate_formula_rename(force: args.force?, verbose: args.verbose?) }
|
||||||
CacheStoreDatabase.use(:descriptions) do |db|
|
CacheStoreDatabase.use(:descriptions) do |db|
|
||||||
DescriptionCacheStore.new(db)
|
DescriptionCacheStore.new(db)
|
||||||
.update_from_report!(hub)
|
.update_from_report!(hub)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if !args.preinstall? && !args.quiet?
|
||||||
|
outdated_formulae = Formula.installed.count(&:outdated?)
|
||||||
|
outdated_casks = Cask::Caskroom.casks.count(&:outdated?)
|
||||||
|
update_pronoun = if (outdated_formulae + outdated_casks) == 1
|
||||||
|
"it"
|
||||||
|
else
|
||||||
|
"them"
|
||||||
end
|
end
|
||||||
puts if args.preinstall?
|
msg = ""
|
||||||
|
if outdated_formulae.positive?
|
||||||
|
msg += "#{Tty.bold}#{outdated_formulae}#{Tty.reset} outdated #{"formula".pluralize(outdated_formulae)}"
|
||||||
|
end
|
||||||
|
if outdated_casks.positive?
|
||||||
|
msg += " and " if msg.present?
|
||||||
|
msg += "#{Tty.bold}#{outdated_casks}#{Tty.reset} outdated #{"cask".pluralize(outdated_casks)}"
|
||||||
|
end
|
||||||
|
if msg.present?
|
||||||
|
puts_stdout_or_stderr
|
||||||
|
puts_stdout_or_stderr <<~EOS
|
||||||
|
You have #{msg} installed.
|
||||||
|
You can update #{update_pronoun} with #{Tty.bold}brew upgrade#{Tty.reset}.
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
puts_stdout_or_stderr if args.preinstall?
|
||||||
elsif !args.preinstall? && !ENV["HOMEBREW_UPDATE_FAILED"]
|
elsif !args.preinstall? && !ENV["HOMEBREW_UPDATE_FAILED"]
|
||||||
puts_stdout_or_stderr "Already up-to-date." unless args.quiet?
|
puts_stdout_or_stderr "Already up-to-date." unless args.quiet?
|
||||||
end
|
end
|
||||||
@ -161,6 +186,7 @@ module Homebrew
|
|||||||
|
|
||||||
return if new_repository_version.blank?
|
return if new_repository_version.blank?
|
||||||
|
|
||||||
|
puts_stdout_or_stderr
|
||||||
ohai_stdout_or_stderr "Homebrew was updated to version #{new_repository_version}"
|
ohai_stdout_or_stderr "Homebrew was updated to version #{new_repository_version}"
|
||||||
if new_repository_version.split(".").last == "0"
|
if new_repository_version.split(".").last == "0"
|
||||||
puts_stdout_or_stderr <<~EOS
|
puts_stdout_or_stderr <<~EOS
|
||||||
|
|||||||
@ -308,6 +308,7 @@ homebrew-update() {
|
|||||||
-\?|-h|--help|--usage) brew help update; exit $? ;;
|
-\?|-h|--help|--usage) brew help update; exit $? ;;
|
||||||
--verbose) HOMEBREW_VERBOSE=1 ;;
|
--verbose) HOMEBREW_VERBOSE=1 ;;
|
||||||
--debug) HOMEBREW_DEBUG=1 ;;
|
--debug) HOMEBREW_DEBUG=1 ;;
|
||||||
|
--quiet) HOMEBREW_QUIET=1 ;;
|
||||||
--merge) HOMEBREW_MERGE=1 ;;
|
--merge) HOMEBREW_MERGE=1 ;;
|
||||||
--force) HOMEBREW_UPDATE_FORCE=1 ;;
|
--force) HOMEBREW_UPDATE_FORCE=1 ;;
|
||||||
--simulate-from-current-branch) HOMEBREW_SIMULATE_FROM_CURRENT_BRANCH=1 ;;
|
--simulate-from-current-branch) HOMEBREW_SIMULATE_FROM_CURRENT_BRANCH=1 ;;
|
||||||
@ -315,6 +316,7 @@ homebrew-update() {
|
|||||||
--*) ;;
|
--*) ;;
|
||||||
-*)
|
-*)
|
||||||
[[ "$option" = *v* ]] && HOMEBREW_VERBOSE=1
|
[[ "$option" = *v* ]] && HOMEBREW_VERBOSE=1
|
||||||
|
[[ "$option" = *q* ]] && HOMEBREW_QUIET=1
|
||||||
[[ "$option" = *d* ]] && HOMEBREW_DEBUG=1
|
[[ "$option" = *d* ]] && HOMEBREW_DEBUG=1
|
||||||
[[ "$option" = *f* ]] && HOMEBREW_UPDATE_FORCE=1
|
[[ "$option" = *f* ]] && HOMEBREW_UPDATE_FORCE=1
|
||||||
;;
|
;;
|
||||||
@ -661,7 +663,8 @@ EOS
|
|||||||
then
|
then
|
||||||
brew update-report "$@"
|
brew update-report "$@"
|
||||||
return $?
|
return $?
|
||||||
elif [[ -z "$HOMEBREW_UPDATE_PREINSTALL" ]]
|
elif [[ -z "$HOMEBREW_UPDATE_PREINSTALL" &&
|
||||||
|
-z "$HOMEBREW_QUIET" ]]
|
||||||
then
|
then
|
||||||
echo "Already up-to-date."
|
echo "Already up-to-date."
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -175,7 +175,7 @@ module Commands
|
|||||||
path = self.path(command)
|
path = self.path(command)
|
||||||
return if path.blank?
|
return if path.blank?
|
||||||
|
|
||||||
if cmd_parser = Homebrew::CLI::Parser.from_cmd_path(path)
|
if (cmd_parser = Homebrew::CLI::Parser.from_cmd_path(path))
|
||||||
cmd_parser.processed_options.map do |short, long, _, desc|
|
cmd_parser.processed_options.map do |short, long, _, desc|
|
||||||
[long || short, desc]
|
[long || short, desc]
|
||||||
end
|
end
|
||||||
@ -198,7 +198,7 @@ module Commands
|
|||||||
path = self.path(command)
|
path = self.path(command)
|
||||||
return if path.blank?
|
return if path.blank?
|
||||||
|
|
||||||
if cmd_parser = Homebrew::CLI::Parser.from_cmd_path(path)
|
if (cmd_parser = Homebrew::CLI::Parser.from_cmd_path(path))
|
||||||
if short
|
if short
|
||||||
cmd_parser.description.split(".").first
|
cmd_parser.description.split(".").first
|
||||||
else
|
else
|
||||||
|
|||||||
@ -129,8 +129,6 @@ module Homebrew
|
|||||||
|
|
||||||
sig { params(command: String).returns(T::Boolean) }
|
sig { params(command: String).returns(T::Boolean) }
|
||||||
def command_gets_completions?(command)
|
def command_gets_completions?(command)
|
||||||
return false if command.start_with? "cask " # TODO: (2.8) remove when `brew cask` commands are removed
|
|
||||||
|
|
||||||
command_options(command).any?
|
command_options(command).any?
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -167,7 +165,7 @@ module Homebrew
|
|||||||
return unless command_gets_completions? command
|
return unless command_gets_completions? command
|
||||||
|
|
||||||
named_completion_string = ""
|
named_completion_string = ""
|
||||||
if types = Commands.named_args_type(command)
|
if (types = Commands.named_args_type(command))
|
||||||
named_args_strings, named_args_types = types.partition { |type| type.is_a? String }
|
named_args_strings, named_args_types = types.partition { |type| type.is_a? String }
|
||||||
|
|
||||||
named_args_types.each do |type|
|
named_args_types.each do |type|
|
||||||
@ -215,29 +213,51 @@ module Homebrew
|
|||||||
def generate_zsh_subcommand_completion(command)
|
def generate_zsh_subcommand_completion(command)
|
||||||
return unless command_gets_completions? command
|
return unless command_gets_completions? command
|
||||||
|
|
||||||
options = command_options(command).sort.map do |opt, desc|
|
options = command_options(command)
|
||||||
next opt if desc.blank?
|
|
||||||
|
|
||||||
conflicts = generate_zsh_option_exclusions(command, opt)
|
args_options = []
|
||||||
"#{conflicts}#{opt}[#{format_description desc}]"
|
if (types = Commands.named_args_type(command))
|
||||||
end
|
|
||||||
if types = Commands.named_args_type(command)
|
|
||||||
named_args_strings, named_args_types = types.partition { |type| type.is_a? String }
|
named_args_strings, named_args_types = types.partition { |type| type.is_a? String }
|
||||||
|
|
||||||
named_args_types.each do |type|
|
named_args_types.each do |type|
|
||||||
next unless ZSH_NAMED_ARGS_COMPLETION_FUNCTION_MAPPING.key? type
|
next unless ZSH_NAMED_ARGS_COMPLETION_FUNCTION_MAPPING.key? type
|
||||||
|
|
||||||
options << "::#{type}:#{ZSH_NAMED_ARGS_COMPLETION_FUNCTION_MAPPING[type]}"
|
args_options << "- #{type}"
|
||||||
|
opt = "--#{type.to_s.gsub(/(installed|outdated)_/, "")}"
|
||||||
|
if options.key?(opt)
|
||||||
|
desc = options[opt]
|
||||||
|
|
||||||
|
if desc.blank?
|
||||||
|
args_options << opt
|
||||||
|
else
|
||||||
|
conflicts = generate_zsh_option_exclusions(command, opt)
|
||||||
|
args_options << "#{conflicts}#{opt}[#{format_description desc}]"
|
||||||
end
|
end
|
||||||
|
|
||||||
options << "::subcommand:(#{named_args_strings.join(" ")})" if named_args_strings.any?
|
options.delete(opt)
|
||||||
end
|
end
|
||||||
|
args_options << "*::#{type}:#{ZSH_NAMED_ARGS_COMPLETION_FUNCTION_MAPPING[type]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
if named_args_strings.any?
|
||||||
|
args_options << "- subcommand"
|
||||||
|
args_options << "*::subcommand:(#{named_args_strings.join(" ")})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
options = options.sort.map do |opt, desc|
|
||||||
|
next opt if desc.blank?
|
||||||
|
|
||||||
|
conflicts = generate_zsh_option_exclusions(command, opt)
|
||||||
|
"#{conflicts}#{opt}[#{format_description desc}]"
|
||||||
|
end
|
||||||
|
options += args_options
|
||||||
|
|
||||||
<<~COMPLETION
|
<<~COMPLETION
|
||||||
# brew #{command}
|
# brew #{command}
|
||||||
_brew_#{Commands.method_name command}() {
|
_brew_#{Commands.method_name command}() {
|
||||||
_arguments \\
|
_arguments \\
|
||||||
#{options.map! { |opt| "'#{opt}'" }.join(" \\\n ")}
|
#{options.map! { |opt| opt.start_with?("- ") ? opt : "'#{opt}'" }.join(" \\\n ")}
|
||||||
}
|
}
|
||||||
COMPLETION
|
COMPLETION
|
||||||
end
|
end
|
||||||
@ -291,7 +311,7 @@ module Homebrew
|
|||||||
|
|
||||||
subcommands = []
|
subcommands = []
|
||||||
named_args = []
|
named_args = []
|
||||||
if types = Commands.named_args_type(command)
|
if (types = Commands.named_args_type(command))
|
||||||
named_args_strings, named_args_types = types.partition { |type| type.is_a? String }
|
named_args_strings, named_args_types = types.partition { |type| type.is_a? String }
|
||||||
|
|
||||||
named_args_types.each do |type|
|
named_args_types.each do |type|
|
||||||
|
|||||||
@ -67,3 +67,9 @@ HOMEBREW_TEMP = Pathname(EnvVar["HOMEBREW_TEMP"]).yield_self do |tmp|
|
|||||||
tmp.mkpath unless tmp.exist?
|
tmp.mkpath unless tmp.exist?
|
||||||
tmp.realpath
|
tmp.realpath
|
||||||
end.freeze
|
end.freeze
|
||||||
|
|
||||||
|
# The Ruby path and args to use for forked Ruby calls
|
||||||
|
HOMEBREW_RUBY_EXEC_ARGS = [
|
||||||
|
RUBY_PATH,
|
||||||
|
ENV["HOMEBREW_RUBY_WARNINGS"],
|
||||||
|
].freeze
|
||||||
|
|||||||
@ -16,7 +16,7 @@ module Context
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.current
|
def self.current
|
||||||
if current_context = Thread.current[:context]
|
if (current_context = Thread.current[:context])
|
||||||
return current_context
|
return current_context
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class Descriptions
|
|||||||
private
|
private
|
||||||
|
|
||||||
def short_names
|
def short_names
|
||||||
@short_names ||= Hash[@descriptions.keys.map { |k| [k, k.split("/").last] }]
|
@short_names ||= @descriptions.keys.map { |k| [k, k.split("/").last] }.to_h
|
||||||
end
|
end
|
||||||
|
|
||||||
def short_name_counts
|
def short_name_counts
|
||||||
|
|||||||
@ -254,7 +254,7 @@ module Homebrew
|
|||||||
def bottle_formula(f, args:)
|
def bottle_formula(f, args:)
|
||||||
return ofail "Formula not installed or up-to-date: #{f.full_name}" unless f.latest_version_installed?
|
return ofail "Formula not installed or up-to-date: #{f.full_name}" unless f.latest_version_installed?
|
||||||
|
|
||||||
unless tap = f.tap
|
unless (tap = f.tap)
|
||||||
return ofail "Formula not from core or any installed taps: #{f.full_name}" unless args.force_core_tap?
|
return ofail "Formula not from core or any installed taps: #{f.full_name}" unless args.force_core_tap?
|
||||||
|
|
||||||
tap = CoreTap.instance
|
tap = CoreTap.instance
|
||||||
|
|||||||
@ -125,29 +125,21 @@ module Homebrew
|
|||||||
tmp_config = cask.config
|
tmp_config = cask.config
|
||||||
tmp_url = tmp_cask.url.to_s
|
tmp_url = tmp_cask.url.to_s
|
||||||
|
|
||||||
if new_hash.nil? && old_hash != :no_check
|
if old_hash != :no_check
|
||||||
resource_path = fetch_resource(cask, new_version, tmp_url)
|
new_hash = fetch_resource(cask, new_version, tmp_url) if new_hash.nil?
|
||||||
Utils::Tar.validate_file(resource_path)
|
|
||||||
new_hash = resource_path.sha256
|
if tmp_contents.include?("Hardware::CPU.intel?")
|
||||||
|
other_intel = !Hardware::CPU.intel?
|
||||||
|
other_contents = tmp_contents.gsub("Hardware::CPU.intel?", other_intel.to_s)
|
||||||
|
replacement_pairs << fetch_cask(other_contents, new_version)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
cask.languages.each do |language|
|
cask.languages.each do |language|
|
||||||
next if language == cask.language
|
next if language == cask.language
|
||||||
|
|
||||||
lang_config = tmp_config.merge(Cask::Config.new(explicit: { languages: [language] }))
|
lang_config = tmp_config.merge(Cask::Config.new(explicit: { languages: [language] }))
|
||||||
lang_cask = Cask::CaskLoader.load(tmp_contents)
|
replacement_pairs << fetch_cask(tmp_contents, new_version, config: lang_config)
|
||||||
lang_cask.config = lang_config
|
|
||||||
lang_url = lang_cask.url.to_s
|
|
||||||
lang_old_hash = lang_cask.sha256.to_s
|
|
||||||
|
|
||||||
resource_path = fetch_resource(cask, new_version, lang_url)
|
|
||||||
Utils::Tar.validate_file(resource_path)
|
|
||||||
lang_new_hash = resource_path.sha256
|
|
||||||
|
|
||||||
replacement_pairs << [
|
|
||||||
lang_old_hash,
|
|
||||||
lang_new_hash,
|
|
||||||
]
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -186,12 +178,24 @@ module Homebrew
|
|||||||
GitHub.create_bump_pr(pr_info, args: args)
|
GitHub.create_bump_pr(pr_info, args: args)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_resource(cask, new_version, url, **specs)
|
def fetch_resource(cask, version, url, **specs)
|
||||||
resource = Resource.new
|
resource = Resource.new
|
||||||
resource.url(url, specs)
|
resource.url(url, specs)
|
||||||
resource.owner = Resource.new(cask.token)
|
resource.owner = Resource.new(cask.token)
|
||||||
resource.version = new_version
|
resource.version = version
|
||||||
resource.fetch
|
|
||||||
|
resource_path = resource.fetch
|
||||||
|
Utils::Tar.validate_file(resource_path)
|
||||||
|
resource_path.sha256
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_cask(contents, version, config: nil)
|
||||||
|
cask = Cask::CaskLoader.load(contents)
|
||||||
|
cask.config = config if config.present?
|
||||||
|
url = cask.url.to_s
|
||||||
|
old_hash = cask.sha256.to_s
|
||||||
|
new_hash = fetch_resource(cask, version, url)
|
||||||
|
[old_hash, new_hash]
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_open_pull_requests(cask, args:)
|
def check_open_pull_requests(cask, args:)
|
||||||
|
|||||||
@ -103,7 +103,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
formula.tap.path.cd do
|
formula.tap.path.cd do
|
||||||
unless Utils.popen_read("git remote -v").match?(%r{^homebrew.*Homebrew/homebrew-core.*$})
|
unless Utils.popen_read("git", "remote", "-v").match?(%r{^homebrew.*Homebrew/homebrew-core.*$})
|
||||||
ohai "Adding #{homebrew_core_remote} remote"
|
ohai "Adding #{homebrew_core_remote} remote"
|
||||||
safe_system "git", "remote", "add", homebrew_core_remote, homebrew_core_url
|
safe_system "git", "remote", "add", homebrew_core_remote, homebrew_core_url
|
||||||
end
|
end
|
||||||
@ -193,7 +193,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
check_new_version(formula, tap_full_name, url: old_url, tag: new_tag, args: args) if new_version.blank?
|
check_new_version(formula, tap_full_name, url: old_url, tag: new_tag, args: args) if new_version.blank?
|
||||||
resource_path, forced_version = fetch_resource(formula, new_version, old_url, tag: new_tag)
|
resource_path, forced_version = fetch_resource(formula, new_version, old_url, tag: new_tag)
|
||||||
new_revision = Utils.popen_read("git -C \"#{resource_path}\" rev-parse -q --verify HEAD")
|
new_revision = Utils.popen_read("git", "-C", resource_path.to_s, "rev-parse", "-q", "--verify", "HEAD")
|
||||||
new_revision = new_revision.strip
|
new_revision = new_revision.strip
|
||||||
elsif new_revision.blank?
|
elsif new_revision.blank?
|
||||||
odie "#{formula}: the current URL requires specifying a `--revision=` argument."
|
odie "#{formula}: the current URL requires specifying a `--revision=` argument."
|
||||||
|
|||||||
@ -16,66 +16,148 @@ module Homebrew
|
|||||||
Display out-of-date brew formulae and the latest version available.
|
Display out-of-date brew formulae and the latest version available.
|
||||||
Also displays whether a pull request has been opened with the URL.
|
Also displays whether a pull request has been opened with the URL.
|
||||||
EOS
|
EOS
|
||||||
|
switch "--full-name",
|
||||||
|
description: "Print formulae/casks with fully-qualified names."
|
||||||
|
switch "--no-pull-requests",
|
||||||
|
description: "Do not retrieve pull requests from GitHub."
|
||||||
|
switch "--formula", "--formulae",
|
||||||
|
description: "Check only formulae."
|
||||||
|
switch "--cask", "--casks",
|
||||||
|
description: "Check only casks."
|
||||||
flag "--limit=",
|
flag "--limit=",
|
||||||
description: "Limit number of package results returned."
|
description: "Limit number of package results returned."
|
||||||
|
|
||||||
named_args :formula
|
conflicts "--cask", "--formula"
|
||||||
|
|
||||||
|
named_args [:formula, :cask]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def bump
|
def bump
|
||||||
args = bump_args.parse
|
args = bump_args.parse
|
||||||
|
|
||||||
requested_formulae = args.named.to_formulae.presence
|
if args.limit.present? && !args.formula? && !args.cask?
|
||||||
requested_limit = args.limit.to_i if args.limit.present?
|
raise UsageError, "`--limit` must be used with either `--formula` or `--cask`."
|
||||||
|
end
|
||||||
|
|
||||||
if requested_formulae
|
formulae_and_casks = if args.formula?
|
||||||
Livecheck.load_other_tap_strategies(requested_formulae)
|
args.named.to_formulae
|
||||||
|
elsif args.cask?
|
||||||
|
args.named.to_casks
|
||||||
|
else
|
||||||
|
args.named.to_formulae_and_casks
|
||||||
|
end
|
||||||
|
formulae_and_casks = formulae_and_casks&.sort_by do |formula_or_cask|
|
||||||
|
formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
|
||||||
|
end
|
||||||
|
|
||||||
requested_formulae.each_with_index do |formula, i|
|
limit = args.limit.to_i if args.limit.present?
|
||||||
|
|
||||||
|
if formulae_and_casks
|
||||||
|
Livecheck.load_other_tap_strategies(formulae_and_casks)
|
||||||
|
|
||||||
|
ambiguous_casks = []
|
||||||
|
if !args.formula? && !args.cask?
|
||||||
|
ambiguous_casks = formulae_and_casks.group_by { |item| Livecheck.formula_or_cask_name(item, full_name: true) }
|
||||||
|
.values
|
||||||
|
.select { |items| items.length > 1 }
|
||||||
|
.flatten
|
||||||
|
.select { |item| item.is_a?(Cask::Cask) }
|
||||||
|
end
|
||||||
|
|
||||||
|
ambiguous_names = []
|
||||||
|
unless args.full_name?
|
||||||
|
ambiguous_names =
|
||||||
|
(formulae_and_casks - ambiguous_casks).group_by { |item| Livecheck.formula_or_cask_name(item) }
|
||||||
|
.values
|
||||||
|
.select { |items| items.length > 1 }
|
||||||
|
.flatten
|
||||||
|
end
|
||||||
|
|
||||||
|
formulae_and_casks.each_with_index do |formula_or_cask, i|
|
||||||
puts if i.positive?
|
puts if i.positive?
|
||||||
|
|
||||||
if formula.head_only?
|
use_full_name = args.full_name? || ambiguous_names.include?(formula_or_cask)
|
||||||
ohai formula.name
|
name = Livecheck.formula_or_cask_name(formula_or_cask, full_name: use_full_name)
|
||||||
|
repository = if formula_or_cask.is_a?(Formula)
|
||||||
|
if formula_or_cask.head_only?
|
||||||
|
ohai name
|
||||||
puts "Formula is HEAD-only."
|
puts "Formula is HEAD-only."
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
package_data = Repology.single_package_query(formula.name)
|
Repology::HOMEBREW_CORE
|
||||||
retrieve_and_display_info(formula, package_data&.values&.first)
|
else
|
||||||
|
Repology::HOMEBREW_CASK
|
||||||
|
end
|
||||||
|
|
||||||
|
package_data = Repology.single_package_query(name, repository: repository)
|
||||||
|
retrieve_and_display_info(
|
||||||
|
formula_or_cask,
|
||||||
|
name,
|
||||||
|
package_data&.values&.first,
|
||||||
|
args: args,
|
||||||
|
ambiguous_cask: ambiguous_casks.include?(formula_or_cask),
|
||||||
|
)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
outdated_packages = Repology.parse_api_response(requested_limit)
|
api_response = {}
|
||||||
outdated_packages.each_with_index do |(_name, repositories), i|
|
unless args.cask?
|
||||||
puts if i.positive?
|
api_response[:formulae] =
|
||||||
|
Repology.parse_api_response(limit, repository: Repology::HOMEBREW_CORE)
|
||||||
|
end
|
||||||
|
unless args.formula?
|
||||||
|
api_response[:casks] =
|
||||||
|
Repology.parse_api_response(limit, repository: Repology::HOMEBREW_CASK)
|
||||||
|
end
|
||||||
|
|
||||||
|
api_response.each do |package_type, outdated_packages|
|
||||||
|
repository = if package_type == :formulae
|
||||||
|
Repology::HOMEBREW_CORE
|
||||||
|
else
|
||||||
|
Repology::HOMEBREW_CASK
|
||||||
|
end
|
||||||
|
|
||||||
|
outdated_packages.each_with_index do |(_name, repositories), i|
|
||||||
homebrew_repo = repositories.find do |repo|
|
homebrew_repo = repositories.find do |repo|
|
||||||
repo["repo"] == "homebrew"
|
repo["repo"] == repository
|
||||||
end
|
end
|
||||||
|
|
||||||
next if homebrew_repo.blank?
|
next if homebrew_repo.blank?
|
||||||
|
|
||||||
formula = begin
|
formula_or_cask = begin
|
||||||
|
if repository == Repology::HOMEBREW_CORE
|
||||||
Formula[homebrew_repo["srcname"]]
|
Formula[homebrew_repo["srcname"]]
|
||||||
|
else
|
||||||
|
Cask::CaskLoader.load(homebrew_repo["srcname"])
|
||||||
|
end
|
||||||
rescue
|
rescue
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
name = Livecheck.formula_or_cask_name(formula_or_cask)
|
||||||
|
ambiguous_cask = begin
|
||||||
|
formula_or_cask.is_a?(Cask::Cask) && !args.cask? && Formula[name]
|
||||||
|
rescue FormulaUnavailableError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
retrieve_and_display_info(formula, repositories)
|
puts if i.positive?
|
||||||
|
retrieve_and_display_info(formula_or_cask, name, repositories, args: args, ambiguous_cask: ambiguous_cask)
|
||||||
|
|
||||||
break if requested_limit && i >= requested_limit
|
break if limit && i >= limit
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def livecheck_result(formula)
|
def livecheck_result(formula_or_cask)
|
||||||
skip_result = Livecheck::SkipConditions.skip_information(formula)
|
skip_result = Livecheck::SkipConditions.skip_information(formula_or_cask)
|
||||||
if skip_result.present?
|
if skip_result.present?
|
||||||
return "#{skip_result[:status]}#{" - #{skip_result[:messages].join(", ")}" if skip_result[:messages].present?}"
|
return "#{skip_result[:status]}#{" - #{skip_result[:messages].join(", ")}" if skip_result[:messages].present?}"
|
||||||
end
|
end
|
||||||
|
|
||||||
version_info = Livecheck.latest_version(
|
version_info = Livecheck.latest_version(
|
||||||
formula,
|
formula_or_cask,
|
||||||
json: true, full_name: false, verbose: false, debug: false,
|
json: true, full_name: false, verbose: false, debug: false,
|
||||||
)
|
)
|
||||||
latest = version_info[:latest] if version_info.present?
|
latest = version_info[:latest] if version_info.present?
|
||||||
@ -83,10 +165,12 @@ module Homebrew
|
|||||||
return "unable to get versions" if latest.blank?
|
return "unable to get versions" if latest.blank?
|
||||||
|
|
||||||
latest.to_s
|
latest.to_s
|
||||||
|
rescue => e
|
||||||
|
"error: #{e}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def retrieve_pull_requests(formula)
|
def retrieve_pull_requests(formula_or_cask, name)
|
||||||
pull_requests = GitHub.fetch_pull_requests(formula.name, formula.tap&.full_name, state: "open")
|
pull_requests = GitHub.fetch_pull_requests(name, formula_or_cask.tap&.full_name, state: "open")
|
||||||
if pull_requests.try(:any?)
|
if pull_requests.try(:any?)
|
||||||
pull_requests = pull_requests.map { |pr| "#{pr["title"]} (#{Formatter.url(pr["html_url"])})" }.join(", ")
|
pull_requests = pull_requests.map { |pr| "#{pr["title"]} (#{Formatter.url(pr["html_url"])})" }.join(", ")
|
||||||
end
|
end
|
||||||
@ -96,8 +180,12 @@ module Homebrew
|
|||||||
pull_requests
|
pull_requests
|
||||||
end
|
end
|
||||||
|
|
||||||
def retrieve_and_display_info(formula, repositories)
|
def retrieve_and_display_info(formula_or_cask, name, repositories, args:, ambiguous_cask: false)
|
||||||
current_version = formula.stable.version.to_s
|
current_version = if formula_or_cask.is_a?(Formula)
|
||||||
|
formula_or_cask.stable.version
|
||||||
|
else
|
||||||
|
Version.new(formula_or_cask.version)
|
||||||
|
end
|
||||||
|
|
||||||
repology_latest = if repositories.present?
|
repology_latest = if repositories.present?
|
||||||
Repology.latest_version(repositories)
|
Repology.latest_version(repositories)
|
||||||
@ -105,14 +193,15 @@ module Homebrew
|
|||||||
"not found"
|
"not found"
|
||||||
end
|
end
|
||||||
|
|
||||||
livecheck_latest = livecheck_result(formula)
|
livecheck_latest = livecheck_result(formula_or_cask)
|
||||||
pull_requests = retrieve_pull_requests(formula)
|
pull_requests = retrieve_pull_requests(formula_or_cask, name) unless args.no_pull_requests?
|
||||||
|
|
||||||
|
name += " (cask)" if ambiguous_cask
|
||||||
title = if current_version == repology_latest &&
|
title = if current_version == repology_latest &&
|
||||||
current_version == livecheck_latest
|
current_version == livecheck_latest
|
||||||
"#{formula} is up to date!"
|
"#{name} is up to date!"
|
||||||
else
|
else
|
||||||
formula.name
|
name
|
||||||
end
|
end
|
||||||
|
|
||||||
ohai title
|
ohai title
|
||||||
@ -120,7 +209,7 @@ module Homebrew
|
|||||||
Current formula version: #{current_version}
|
Current formula version: #{current_version}
|
||||||
Latest Repology version: #{repology_latest}
|
Latest Repology version: #{repology_latest}
|
||||||
Latest livecheck version: #{livecheck_latest}
|
Latest livecheck version: #{livecheck_latest}
|
||||||
Open pull requests: #{pull_requests}
|
|
||||||
EOS
|
EOS
|
||||||
|
puts "Open pull requests: #{pull_requests}" unless args.no_pull_requests?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -179,7 +179,7 @@ module Homebrew
|
|||||||
# Check for disallowed formula, or names that shadow aliases,
|
# Check for disallowed formula, or names that shadow aliases,
|
||||||
# unless --force is specified.
|
# unless --force is specified.
|
||||||
unless args.force?
|
unless args.force?
|
||||||
if reason = MissingFormula.disallowed_reason(fc.name)
|
if (reason = MissingFormula.disallowed_reason(fc.name))
|
||||||
odie <<~EOS
|
odie <<~EOS
|
||||||
The formula '#{fc.name}' is not allowed to be created.
|
The formula '#{fc.name}' is not allowed to be created.
|
||||||
#{reason}
|
#{reason}
|
||||||
|
|||||||
@ -25,7 +25,10 @@ module Homebrew
|
|||||||
description: "Dispatch specified workflow (default: `dispatch-build-bottle.yml`)."
|
description: "Dispatch specified workflow (default: `dispatch-build-bottle.yml`)."
|
||||||
switch "--upload",
|
switch "--upload",
|
||||||
description: "Upload built bottles to Bintray."
|
description: "Upload built bottles to Bintray."
|
||||||
|
switch "--linux",
|
||||||
|
description: "Dispatch bottle for Linux (using GitHub runners)."
|
||||||
|
|
||||||
|
conflicts "--macos", "--linux"
|
||||||
named_args :formula, min: 1
|
named_args :formula, min: 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -33,18 +36,26 @@ module Homebrew
|
|||||||
def dispatch_build_bottle
|
def dispatch_build_bottle
|
||||||
args = dispatch_build_bottle_args.parse
|
args = dispatch_build_bottle_args.parse
|
||||||
|
|
||||||
|
tap = Tap.fetch(args.tap || CoreTap.instance.name)
|
||||||
|
user, repo = tap.full_name.split("/")
|
||||||
|
ref = "master"
|
||||||
|
workflow = args.workflow || "dispatch-build-bottle.yml"
|
||||||
|
|
||||||
|
# Ensure we dispatch the bottle in homebrew/homebrew-core
|
||||||
|
# TODO: remove when core taps are merged
|
||||||
|
repo.gsub!("linux", "home") unless args.tap
|
||||||
|
|
||||||
|
if (macos = args.macos)
|
||||||
# Fixup version for ARM/Apple Silicon
|
# Fixup version for ARM/Apple Silicon
|
||||||
# TODO: fix label name to be 11-arm64 instead and remove this.
|
# TODO: fix label name to be 11-arm64 instead and remove this.
|
||||||
args.macos&.gsub!(/^11-arm$/, "11-arm64")
|
macos.gsub!(/^11-arm$/, "11-arm64")
|
||||||
|
|
||||||
macos = args.macos&.yield_self do |s|
|
macos = macos.yield_self do |s|
|
||||||
MacOS::Version.from_symbol(s.to_sym)
|
MacOS::Version.from_symbol(s.to_sym)
|
||||||
rescue MacOSVersionError
|
rescue MacOSVersionError
|
||||||
MacOS::Version.new(s)
|
MacOS::Version.new(s)
|
||||||
end
|
end
|
||||||
|
|
||||||
raise UsageError, "Must specify --macos option" if macos.blank?
|
|
||||||
|
|
||||||
# Fixup label for ARM/Apple Silicon
|
# Fixup label for ARM/Apple Silicon
|
||||||
macos_label = if macos.arch == :arm64
|
macos_label = if macos.arch == :arm64
|
||||||
# TODO: fix label name to be 11-arm64 instead.
|
# TODO: fix label name to be 11-arm64 instead.
|
||||||
@ -53,25 +64,27 @@ module Homebrew
|
|||||||
macos.to_s
|
macos.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
tap = Tap.fetch(args.tap || CoreTap.instance.name)
|
dispatching_for = "macOS #{macos}"
|
||||||
user, repo = tap.full_name.split("/")
|
elsif T.unsafe(args).linux?
|
||||||
|
workflow = args.workflow || "linux-#{workflow}"
|
||||||
workflow = args.workflow || "dispatch-build-bottle.yml"
|
dispatching_for = "Linux"
|
||||||
ref = "master"
|
else
|
||||||
|
raise UsageError, "Must specify --macos or --linux option"
|
||||||
|
end
|
||||||
|
|
||||||
args.named.to_resolved_formulae.each do |formula|
|
args.named.to_resolved_formulae.each do |formula|
|
||||||
# Required inputs
|
# Required inputs
|
||||||
inputs = {
|
inputs = {
|
||||||
formula: formula.name,
|
formula: formula.name,
|
||||||
macos: macos_label,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Optional inputs
|
# Optional inputs
|
||||||
# These cannot be passed as nil to GitHub API
|
# These cannot be passed as nil to GitHub API
|
||||||
|
inputs[:macos] = macos_label if args.macos
|
||||||
inputs[:issue] = args.issue if args.issue
|
inputs[:issue] = args.issue if args.issue
|
||||||
inputs[:upload] = args.upload?.to_s if args.upload?
|
inputs[:upload] = args.upload?.to_s if args.upload?
|
||||||
|
|
||||||
ohai "Dispatching #{tap} bottling request of formula \"#{formula.name}\" for macOS #{macos}"
|
ohai "Dispatching #{tap} bottling request of formula \"#{formula.name}\" for #{dispatching_for}"
|
||||||
GitHub.workflow_dispatch_event(user, repo, workflow, ref, inputs)
|
GitHub.workflow_dispatch_event(user, repo, workflow, ref, inputs)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -61,8 +61,7 @@ module Homebrew
|
|||||||
puts ENV["HOMEBREW_LIVECHECK_WATCHLIST"] if ENV["HOMEBREW_LIVECHECK_WATCHLIST"].present?
|
puts ENV["HOMEBREW_LIVECHECK_WATCHLIST"] if ENV["HOMEBREW_LIVECHECK_WATCHLIST"].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
formulae_and_casks_to_check =
|
formulae_and_casks_to_check = if args.tap
|
||||||
if args.tap
|
|
||||||
tap = Tap.fetch(args.tap)
|
tap = Tap.fetch(args.tap)
|
||||||
formulae = args.cask? ? [] : tap.formula_files.map { |path| Formulary.factory(path) }
|
formulae = args.cask? ? [] : tap.formula_files.map { |path| Formulary.factory(path) }
|
||||||
casks = args.formula? ? [] : tap.cask_files.map { |path| Cask::CaskLoader.load(path) }
|
casks = args.formula? ? [] : tap.cask_files.map { |path| Cask::CaskLoader.load(path) }
|
||||||
@ -96,7 +95,8 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise UsageError, "A watchlist file is required when no arguments are given."
|
raise UsageError, "A watchlist file is required when no arguments are given."
|
||||||
end&.sort_by do |formula_or_cask|
|
end
|
||||||
|
formulae_and_casks_to_check = formulae_and_casks_to_check.sort_by do |formula_or_cask|
|
||||||
formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
|
formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -105,6 +105,7 @@ module Homebrew
|
|||||||
options = {
|
options = {
|
||||||
json: args.json?,
|
json: args.json?,
|
||||||
full_name: args.full_name?,
|
full_name: args.full_name?,
|
||||||
|
handle_name_conflict: !args.formula? && !args.cask?,
|
||||||
newer_only: args.newer_only?,
|
newer_only: args.newer_only?,
|
||||||
quiet: args.quiet?,
|
quiet: args.quiet?,
|
||||||
debug: args.debug?,
|
debug: args.debug?,
|
||||||
|
|||||||
@ -24,9 +24,9 @@ module Homebrew
|
|||||||
|
|
||||||
*Note:* Not (yet) working on Apple Silicon.
|
*Note:* Not (yet) working on Apple Silicon.
|
||||||
EOS
|
EOS
|
||||||
switch "--fail-if-changed",
|
switch "--fail-if-not-changed",
|
||||||
description: "Return a failing status code if changes are detected in the manpage outputs. This "\
|
description: "Return a failing status code if no changes are detected in the manpage outputs. "\
|
||||||
"can be used to notify CI when the manpages are out of date. Additionally, "\
|
"This can be used to notify CI when the manpages are out of date. Additionally, "\
|
||||||
"the date used in new manpages will match those in the existing manpages (to allow "\
|
"the date used in new manpages will match those in the existing manpages (to allow "\
|
||||||
"comparison without factoring in the date)."
|
"comparison without factoring in the date)."
|
||||||
named_args :none
|
named_args :none
|
||||||
@ -42,19 +42,17 @@ module Homebrew
|
|||||||
args = man_args.parse
|
args = man_args.parse
|
||||||
|
|
||||||
Commands.rebuild_internal_commands_completion_list
|
Commands.rebuild_internal_commands_completion_list
|
||||||
regenerate_man_pages(preserve_date: args.fail_if_changed?, quiet: args.quiet?)
|
regenerate_man_pages(preserve_date: args.fail_if_not_changed?, quiet: args.quiet?)
|
||||||
Completions.update_shell_completions!
|
Completions.update_shell_completions!
|
||||||
|
|
||||||
diff = system_command "git", args: [
|
diff = system_command "git", args: [
|
||||||
"-C", HOMEBREW_REPOSITORY, "diff", "--exit-code", "docs/Manpage.md", "manpages", "completions"
|
"-C", HOMEBREW_REPOSITORY, "diff", "--exit-code", "docs/Manpage.md", "manpages", "completions"
|
||||||
]
|
]
|
||||||
if diff.status.success?
|
|
||||||
|
return unless diff.status.success?
|
||||||
|
|
||||||
puts "No changes to manpage or completions output detected."
|
puts "No changes to manpage or completions output detected."
|
||||||
elsif args.fail_if_changed?
|
Homebrew.failed = true if args.fail_if_not_changed?
|
||||||
puts "Changes to manpage or completions detected:"
|
|
||||||
puts diff.stdout
|
|
||||||
Homebrew.failed = true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def regenerate_man_pages(preserve_date:, quiet:)
|
def regenerate_man_pages(preserve_date:, quiet:)
|
||||||
@ -62,6 +60,7 @@ module Homebrew
|
|||||||
|
|
||||||
markup = build_man_page(quiet: quiet)
|
markup = build_man_page(quiet: quiet)
|
||||||
convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md", preserve_date: preserve_date)
|
convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md", preserve_date: preserve_date)
|
||||||
|
markup = I18n.transliterate(markup, locale: :en)
|
||||||
convert_man_page(markup, TARGET_MAN_PATH/"brew.1", preserve_date: preserve_date)
|
convert_man_page(markup, TARGET_MAN_PATH/"brew.1", preserve_date: preserve_date)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -164,7 +163,7 @@ module Homebrew
|
|||||||
# preserve existing manpage order
|
# preserve existing manpage order
|
||||||
cmd_paths.sort_by(&method(:sort_key_for_path))
|
cmd_paths.sort_by(&method(:sort_key_for_path))
|
||||||
.each do |cmd_path|
|
.each do |cmd_path|
|
||||||
cmd_man_page_lines = if cmd_parser = CLI::Parser.from_cmd_path(cmd_path)
|
cmd_man_page_lines = if (cmd_parser = CLI::Parser.from_cmd_path(cmd_path))
|
||||||
next if cmd_parser.hide_from_man_page
|
next if cmd_parser.hide_from_man_page
|
||||||
|
|
||||||
cmd_parser_manpage_lines(cmd_parser).join
|
cmd_parser_manpage_lines(cmd_parser).join
|
||||||
|
|||||||
@ -49,6 +49,8 @@ module Homebrew
|
|||||||
description: "Message to include when autosquashing revision bumps, deletions, and rebuilds."
|
description: "Message to include when autosquashing revision bumps, deletions, and rebuilds."
|
||||||
flag "--artifact=",
|
flag "--artifact=",
|
||||||
description: "Download artifacts with the specified name (default: `bottles`)."
|
description: "Download artifacts with the specified name (default: `bottles`)."
|
||||||
|
flag "--archive-item=",
|
||||||
|
description: "Upload to the specified Internet Archive item (default: `homebrew`)."
|
||||||
flag "--bintray-org=",
|
flag "--bintray-org=",
|
||||||
description: "Upload to the specified Bintray organisation (default: `homebrew`)."
|
description: "Upload to the specified Bintray organisation (default: `homebrew`)."
|
||||||
flag "--tap=",
|
flag "--tap=",
|
||||||
@ -65,6 +67,7 @@ module Homebrew
|
|||||||
description: "Comma-separated list of workflows which can be ignored if they have not been run."
|
description: "Comma-separated list of workflows which can be ignored if they have not been run."
|
||||||
|
|
||||||
conflicts "--clean", "--autosquash"
|
conflicts "--clean", "--autosquash"
|
||||||
|
conflicts "--archive-item", "--bintray-org"
|
||||||
|
|
||||||
named_args :pull_request, min: 1
|
named_args :pull_request, min: 1
|
||||||
end
|
end
|
||||||
@ -337,9 +340,9 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
def download_artifact(url, dir, pr)
|
def download_artifact(url, dir, pr)
|
||||||
odie "Credentials must be set to access the Artifacts API" if GitHub.api_credentials_type == :none
|
odie "Credentials must be set to access the Artifacts API" if GitHub::API.credentials_type == :none
|
||||||
|
|
||||||
token = GitHub.api_credentials
|
token = GitHub::API.credentials
|
||||||
curl_args = ["--header", "Authorization: token #{token}"]
|
curl_args = ["--header", "Authorization: token #{token}"]
|
||||||
|
|
||||||
# Download the artifact as a zip file and unpack it into `dir`. This is
|
# Download the artifact as a zip file and unpack it into `dir`. This is
|
||||||
@ -357,6 +360,7 @@ module Homebrew
|
|||||||
|
|
||||||
workflows = args.workflows.presence || ["tests.yml"]
|
workflows = args.workflows.presence || ["tests.yml"]
|
||||||
artifact = args.artifact || "bottles"
|
artifact = args.artifact || "bottles"
|
||||||
|
archive_item = args.archive_item
|
||||||
bintray_org = args.bintray_org || "homebrew"
|
bintray_org = args.bintray_org || "homebrew"
|
||||||
mirror_repo = args.bintray_mirror || "mirror"
|
mirror_repo = args.bintray_mirror || "mirror"
|
||||||
tap = Tap.fetch(args.tap || CoreTap.instance.name)
|
tap = Tap.fetch(args.tap || CoreTap.instance.name)
|
||||||
@ -424,7 +428,11 @@ module Homebrew
|
|||||||
upload_args << "--keep-old" if args.keep_old?
|
upload_args << "--keep-old" if args.keep_old?
|
||||||
upload_args << "--warn-on-upload-failure" if args.warn_on_upload_failure?
|
upload_args << "--warn-on-upload-failure" if args.warn_on_upload_failure?
|
||||||
upload_args << "--root-url=#{args.root_url}" if args.root_url
|
upload_args << "--root-url=#{args.root_url}" if args.root_url
|
||||||
upload_args << "--bintray-org=#{bintray_org}"
|
upload_args << if archive_item.present?
|
||||||
|
"--archive-item=#{archive_item}"
|
||||||
|
else
|
||||||
|
"--bintray-org=#{bintray_org}"
|
||||||
|
end
|
||||||
safe_system HOMEBREW_BREW_FILE, *upload_args
|
safe_system HOMEBREW_BREW_FILE, *upload_args
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -2,7 +2,10 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "cli/parser"
|
require "cli/parser"
|
||||||
|
require "archive"
|
||||||
require "bintray"
|
require "bintray"
|
||||||
|
require "github_packages"
|
||||||
|
require "github_releases"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
extend T::Sig
|
extend T::Sig
|
||||||
@ -13,7 +16,7 @@ module Homebrew
|
|||||||
def pr_upload_args
|
def pr_upload_args
|
||||||
Homebrew::CLI::Parser.new do
|
Homebrew::CLI::Parser.new do
|
||||||
description <<~EOS
|
description <<~EOS
|
||||||
Apply the bottle commit and publish bottles to Bintray or GitHub Releases.
|
Apply the bottle commit and publish bottles to a host.
|
||||||
EOS
|
EOS
|
||||||
switch "--no-publish",
|
switch "--no-publish",
|
||||||
description: "Apply the bottle commit and upload the bottles, but don't publish them."
|
description: "Apply the bottle commit and upload the bottles, but don't publish them."
|
||||||
@ -27,8 +30,12 @@ module Homebrew
|
|||||||
switch "--warn-on-upload-failure",
|
switch "--warn-on-upload-failure",
|
||||||
description: "Warn instead of raising an error if the bottle upload fails. "\
|
description: "Warn instead of raising an error if the bottle upload fails. "\
|
||||||
"Useful for repairing bottle uploads that previously failed."
|
"Useful for repairing bottle uploads that previously failed."
|
||||||
|
flag "--archive-item=",
|
||||||
|
description: "Upload to the specified Internet Archive item (default: `homebrew`)."
|
||||||
flag "--bintray-org=",
|
flag "--bintray-org=",
|
||||||
description: "Upload to the specified Bintray organisation (default: `homebrew`)."
|
description: "Upload to the specified Bintray organisation (default: `homebrew`)."
|
||||||
|
flag "--github-org=",
|
||||||
|
description: "Upload to the specified GitHub organisation's GitHub Packages (default: `homebrew`)."
|
||||||
flag "--root-url=",
|
flag "--root-url=",
|
||||||
description: "Use the specified <URL> as the root of the bottle's URL instead of Homebrew's default."
|
description: "Use the specified <URL> as the root of the bottle's URL instead of Homebrew's default."
|
||||||
|
|
||||||
@ -47,16 +54,34 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def internet_archive?(bottles_hash)
|
||||||
|
@internet_archive ||= bottles_hash.values.all? do |bottle_hash|
|
||||||
|
bottle_hash["bottle"]["root_url"].start_with? "#{Archive::URL_PREFIX}/"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def bintray?(bottles_hash)
|
||||||
|
@bintray ||= bottles_hash.values.all? do |bottle_hash|
|
||||||
|
bottle_hash["bottle"]["root_url"].match? Bintray::URL_REGEX
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def github_releases?(bottles_hash)
|
def github_releases?(bottles_hash)
|
||||||
@github_releases ||= bottles_hash.values.all? do |bottle_hash|
|
@github_releases ||= bottles_hash.values.all? do |bottle_hash|
|
||||||
root_url = bottle_hash["bottle"]["root_url"]
|
root_url = bottle_hash["bottle"]["root_url"]
|
||||||
url_match = root_url.match HOMEBREW_RELEASES_URL_REGEX
|
url_match = root_url.match GitHubReleases::URL_REGEX
|
||||||
_, _, _, tag = *url_match
|
_, _, _, tag = *url_match
|
||||||
|
|
||||||
tag
|
tag
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def github_packages?(bottles_hash)
|
||||||
|
@github_packages ||= bottles_hash.values.all? do |bottle_hash|
|
||||||
|
bottle_hash["bottle"]["root_url"].match? GitHubPackages::URL_REGEX
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def pr_upload
|
def pr_upload
|
||||||
args = pr_upload_args.parse
|
args = pr_upload_args.parse
|
||||||
|
|
||||||
@ -76,10 +101,17 @@ module Homebrew
|
|||||||
bottle_args += json_files
|
bottle_args += json_files
|
||||||
|
|
||||||
if args.dry_run?
|
if args.dry_run?
|
||||||
service = if github_releases?(bottles_hash)
|
service =
|
||||||
"GitHub Releases"
|
if internet_archive?(bottles_hash)
|
||||||
else
|
"Internet Archive"
|
||||||
|
elsif bintray?(bottles_hash)
|
||||||
"Bintray"
|
"Bintray"
|
||||||
|
elsif github_releases?(bottles_hash)
|
||||||
|
"GitHub Releases"
|
||||||
|
elsif github_packages?(bottles_hash)
|
||||||
|
"GitHub Packages"
|
||||||
|
else
|
||||||
|
odie "Service specified by root_url is not recognized"
|
||||||
end
|
end
|
||||||
puts <<~EOS
|
puts <<~EOS
|
||||||
brew #{bottle_args.join " "}
|
brew #{bottle_args.join " "}
|
||||||
@ -102,38 +134,26 @@ module Homebrew
|
|||||||
safe_system HOMEBREW_BREW_FILE, *audit_args
|
safe_system HOMEBREW_BREW_FILE, *audit_args
|
||||||
end
|
end
|
||||||
|
|
||||||
if github_releases?(bottles_hash)
|
if internet_archive?(bottles_hash)
|
||||||
# Handle uploading to GitHub Releases.
|
archive_item = args.archive_item || "homebrew"
|
||||||
bottles_hash.each_value do |bottle_hash|
|
archive = Archive.new(item: archive_item)
|
||||||
root_url = bottle_hash["bottle"]["root_url"]
|
archive.upload_bottles(bottles_hash,
|
||||||
url_match = root_url.match HOMEBREW_RELEASES_URL_REGEX
|
warn_on_error: args.warn_on_upload_failure?)
|
||||||
_, user, repo, tag = *url_match
|
elsif bintray?(bottles_hash)
|
||||||
|
|
||||||
# Ensure a release is created.
|
|
||||||
release = begin
|
|
||||||
rel = GitHub.get_release user, repo, tag
|
|
||||||
odebug "Existing GitHub release \"#{tag}\" found"
|
|
||||||
rel
|
|
||||||
rescue GitHub::HTTPNotFoundError
|
|
||||||
odebug "Creating new GitHub release \"#{tag}\""
|
|
||||||
GitHub.create_or_update_release user, repo, tag
|
|
||||||
end
|
|
||||||
|
|
||||||
# Upload bottles as release assets.
|
|
||||||
bottle_hash["bottle"]["tags"].each_value do |tag_hash|
|
|
||||||
remote_file = tag_hash["filename"]
|
|
||||||
local_file = tag_hash["local_filename"]
|
|
||||||
odebug "Uploading #{remote_file}"
|
|
||||||
GitHub.upload_release_asset user, repo, release["id"], local_file: local_file, remote_file: remote_file
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
# Handle uploading to Bintray.
|
|
||||||
bintray_org = args.bintray_org || "homebrew"
|
bintray_org = args.bintray_org || "homebrew"
|
||||||
bintray = Bintray.new(org: bintray_org)
|
bintray = Bintray.new(org: bintray_org)
|
||||||
bintray.upload_bottles(bottles_hash,
|
bintray.upload_bottles(bottles_hash,
|
||||||
publish_package: !args.no_publish?,
|
publish_package: !args.no_publish?,
|
||||||
warn_on_error: args.warn_on_upload_failure?)
|
warn_on_error: args.warn_on_upload_failure?)
|
||||||
|
elsif github_releases?(bottles_hash)
|
||||||
|
github_releases = GitHubReleases.new
|
||||||
|
github_releases.upload_bottles(bottles_hash)
|
||||||
|
elsif github_packages?(bottles_hash)
|
||||||
|
github_org = args.github_org || "homebrew"
|
||||||
|
github_packages = GitHubPackages.new(org: github_org)
|
||||||
|
github_packages.upload_bottles(bottles_hash)
|
||||||
|
else
|
||||||
|
odie "Service specified by root_url is not recognized"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -13,15 +13,19 @@ module Homebrew
|
|||||||
Homebrew::CLI::Parser.new do
|
Homebrew::CLI::Parser.new do
|
||||||
description <<~EOS
|
description <<~EOS
|
||||||
Run Homebrew with a Ruby profiler. For example, `brew prof readall`.
|
Run Homebrew with a Ruby profiler. For example, `brew prof readall`.
|
||||||
|
|
||||||
|
*Note:* Not (yet) working on Apple Silicon.
|
||||||
EOS
|
EOS
|
||||||
switch "--stackprof",
|
switch "--stackprof",
|
||||||
description: "Use `stackprof` instead of `ruby-prof` (the default)."
|
description: "Use `stackprof` instead of `ruby-prof` (the default)."
|
||||||
|
|
||||||
named_args :command
|
named_args :command, min: 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def prof
|
def prof
|
||||||
|
raise UsageError, "not (yet) working on Apple Silicon!" if Hardware::CPU.arm?
|
||||||
|
|
||||||
args = prof_args.parse
|
args = prof_args.parse
|
||||||
|
|
||||||
brew_rb = (HOMEBREW_LIBRARY_PATH/"brew.rb").resolved_path
|
brew_rb = (HOMEBREW_LIBRARY_PATH/"brew.rb").resolved_path
|
||||||
|
|||||||
@ -39,7 +39,7 @@ module Homebrew
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
latest_release = GitHub.get_latest_release "Homebrew", "brew"
|
latest_release = GitHub.get_latest_release "Homebrew", "brew"
|
||||||
rescue GitHub::HTTPNotFoundError
|
rescue GitHub::API::HTTPNotFoundError
|
||||||
odie "No existing releases found!"
|
odie "No existing releases found!"
|
||||||
end
|
end
|
||||||
latest_version = Version.new latest_release["tag_name"]
|
latest_version = Version.new latest_release["tag_name"]
|
||||||
@ -48,7 +48,7 @@ module Homebrew
|
|||||||
one_month_ago = Date.today << 1
|
one_month_ago = Date.today << 1
|
||||||
latest_major_minor_release = begin
|
latest_major_minor_release = begin
|
||||||
GitHub.get_release "Homebrew", "brew", "#{latest_version.major_minor}.0"
|
GitHub.get_release "Homebrew", "brew", "#{latest_version.major_minor}.0"
|
||||||
rescue GitHub::HTTPNotFoundError
|
rescue GitHub::API::HTTPNotFoundError
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ module Homebrew
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
release = GitHub.create_or_update_release "Homebrew", "brew", new_version, body: release_notes, draft: true
|
release = GitHub.create_or_update_release "Homebrew", "brew", new_version, body: release_notes, draft: true
|
||||||
rescue *GitHub::API_ERRORS => e
|
rescue *GitHub::API::ERRORS => e
|
||||||
odie "Unable to create release: #{e.message}!"
|
odie "Unable to create release: #{e.message}!"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -18,8 +18,6 @@ homebrew-rubocop() {
|
|||||||
export GEM_HOME
|
export GEM_HOME
|
||||||
export PATH="$GEM_HOME/bin:$PATH"
|
export PATH="$GEM_HOME/bin:$PATH"
|
||||||
|
|
||||||
# Unconditional -W0 to avoid printing e.g.:
|
RUBOCOP="$HOMEBREW_LIBRARY/Homebrew/utils/rubocop.rb"
|
||||||
# warning: parser/current is loading parser/ruby26, which recognizes
|
exec "$HOMEBREW_RUBY_PATH" "$RUBOCOP" "$@"
|
||||||
# warning: 2.6.6-compliant syntax, but you are running 2.6.3.
|
|
||||||
exec "$HOMEBREW_RUBY_PATH" "$RUBY_DISABLE_OPTIONS" -W0 -S rubocop "$@"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,55 +9,68 @@ module Homebrew
|
|||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
|
NAMED_TIER_AMOUNT = 100
|
||||||
|
URL_TIER_AMOUNT = 1000
|
||||||
|
|
||||||
sig { returns(CLI::Parser) }
|
sig { returns(CLI::Parser) }
|
||||||
def sponsors_args
|
def sponsors_args
|
||||||
Homebrew::CLI::Parser.new do
|
Homebrew::CLI::Parser.new do
|
||||||
description <<~EOS
|
description <<~EOS
|
||||||
Print a Markdown summary of Homebrew's GitHub Sponsors, suitable for pasting into a README.
|
Update the list of GitHub Sponsors in the `Homebrew/brew` README.
|
||||||
EOS
|
EOS
|
||||||
|
|
||||||
named_args :none
|
named_args :none
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sponsor_name(s)
|
||||||
|
s["name"] || s["login"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def sponsor_logo(s)
|
||||||
|
"https://github.com/#{s["login"]}.png?size=64"
|
||||||
|
end
|
||||||
|
|
||||||
|
def sponsor_url(s)
|
||||||
|
"https://github.com/#{s["login"]}"
|
||||||
|
end
|
||||||
|
|
||||||
def sponsors
|
def sponsors
|
||||||
sponsors_args.parse
|
sponsors_args.parse
|
||||||
|
|
||||||
sponsors = {
|
named_sponsors = []
|
||||||
"named" => [],
|
logo_sponsors = []
|
||||||
"users" => 0,
|
|
||||||
"orgs" => 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
GitHub.sponsors_by_tier("Homebrew").each do |tier|
|
GitHub.sponsors_by_tier("Homebrew").each do |tier|
|
||||||
sponsors["named"] += tier["sponsors"] if tier["tier"] >= 100
|
if tier["tier"] >= NAMED_TIER_AMOUNT
|
||||||
sponsors["users"] += tier["count"]
|
named_sponsors += tier["sponsors"].map do |s|
|
||||||
sponsors["orgs"] += tier["sponsors"].count { |s| s["type"] == "organization" }
|
"[#{sponsor_name(s)}](#{sponsor_url(s)})"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
items = []
|
next if tier["tier"] < URL_TIER_AMOUNT
|
||||||
items += sponsors["named"].map { |s| "[#{s["name"]}](https://github.com/#{s["login"]})" }
|
|
||||||
|
|
||||||
anon_users = sponsors["users"] - sponsors["named"].length - sponsors["orgs"]
|
logo_sponsors += tier["sponsors"].map do |s|
|
||||||
|
"[})](#{sponsor_url(s)})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
items << if items.length > 1
|
named_sponsors << "many other users and organisations via [GitHub Sponsors](https://github.com/sponsors/Homebrew)"
|
||||||
"#{anon_users} other users"
|
|
||||||
|
readme = HOMEBREW_REPOSITORY/"README.md"
|
||||||
|
content = readme.read
|
||||||
|
content.gsub!(/(Homebrew is generously supported by) .*\Z/m, "\\1 #{named_sponsors.to_sentence}.\n")
|
||||||
|
content << "\n#{logo_sponsors.join}\n" if logo_sponsors.presence
|
||||||
|
|
||||||
|
File.open(readme, "w+") { |f| f.write(content) }
|
||||||
|
|
||||||
|
diff = system_command "git", args: [
|
||||||
|
"-C", HOMEBREW_REPOSITORY, "diff", "--exit-code", "README.md"
|
||||||
|
]
|
||||||
|
if diff.status.success?
|
||||||
|
puts "No changes to list of sponsors."
|
||||||
else
|
else
|
||||||
"#{anon_users} users"
|
puts "List of sponsors updated in the README."
|
||||||
end
|
end
|
||||||
|
|
||||||
if sponsors["orgs"] == 1
|
|
||||||
items << "#{sponsors["orgs"]} organization"
|
|
||||||
elsif sponsors["orgs"] > 1
|
|
||||||
items << "#{sponsors["orgs"]} organizations"
|
|
||||||
end
|
|
||||||
|
|
||||||
sponsor_text = if items.length > 2
|
|
||||||
items[0..-2].join(", ") + " and #{items.last}"
|
|
||||||
else
|
|
||||||
items.join(" and ")
|
|
||||||
end
|
|
||||||
|
|
||||||
puts "Homebrew is generously supported by #{sponsor_text} via [GitHub Sponsors](https://github.com/sponsors/Homebrew)."
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -22,9 +22,8 @@ module Homebrew
|
|||||||
flag "--pull-label=",
|
flag "--pull-label=",
|
||||||
description: "Label name for pull requests ready to be pulled (default: `pr-pull`)."
|
description: "Label name for pull requests ready to be pulled (default: `pr-pull`)."
|
||||||
flag "--branch=",
|
flag "--branch=",
|
||||||
description: "Initialize Git repository with the specified branch name (default: `main`)."
|
description: "Initialize Git repository and setup GitHub Actions workflows with the " \
|
||||||
|
"specified branch name (default: `main`)."
|
||||||
conflicts "--no-git", "--branch"
|
|
||||||
|
|
||||||
named_args :tap, number: 1
|
named_args :tap, number: 1
|
||||||
end
|
end
|
||||||
@ -50,11 +49,13 @@ module Homebrew
|
|||||||
# #{titleized_user} #{titleized_repo}
|
# #{titleized_user} #{titleized_repo}
|
||||||
|
|
||||||
## How do I install these formulae?
|
## How do I install these formulae?
|
||||||
|
|
||||||
`brew install #{tap}/<formula>`
|
`brew install #{tap}/<formula>`
|
||||||
|
|
||||||
Or `brew tap #{tap}` and then `brew install <formula>`.
|
Or `brew tap #{tap}` and then `brew install <formula>`.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
`brew help`, `man brew` or check [Homebrew's documentation](https://docs.brew.sh).
|
`brew help`, `man brew` or check [Homebrew's documentation](https://docs.brew.sh).
|
||||||
MARKDOWN
|
MARKDOWN
|
||||||
write_path(tap, "README.md", readme)
|
write_path(tap, "README.md", readme)
|
||||||
@ -63,13 +64,14 @@ module Homebrew
|
|||||||
name: brew test-bot
|
name: brew test-bot
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: #{branch}
|
branches:
|
||||||
|
- #{branch}
|
||||||
pull_request:
|
pull_request:
|
||||||
jobs:
|
jobs:
|
||||||
test-bot:
|
test-bot:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macOS-latest]
|
os: [ubuntu-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Homebrew
|
- name: Set up Homebrew
|
||||||
|
|||||||
@ -35,6 +35,8 @@ module Homebrew
|
|||||||
def test
|
def test
|
||||||
args = test_args.parse
|
args = test_args.parse
|
||||||
|
|
||||||
|
Homebrew.install_bundler_gems!(setup_path: false)
|
||||||
|
|
||||||
require "formula_assertions"
|
require "formula_assertions"
|
||||||
require "formula_free_port"
|
require "formula_free_port"
|
||||||
|
|
||||||
@ -75,10 +77,7 @@ module Homebrew
|
|||||||
env = ENV.to_hash
|
env = ENV.to_hash
|
||||||
|
|
||||||
begin
|
begin
|
||||||
exec_args = %W[
|
exec_args = HOMEBREW_RUBY_EXEC_ARGS + %W[
|
||||||
#{RUBY_PATH}
|
|
||||||
#{ENV["HOMEBREW_RUBY_WARNINGS"]}
|
|
||||||
-I #{$LOAD_PATH.join(File::PATH_SEPARATOR)}
|
|
||||||
--
|
--
|
||||||
#{HOMEBREW_LIBRARY_PATH}/test.rb
|
#{HOMEBREW_LIBRARY_PATH}/test.rb
|
||||||
#{f.path}
|
#{f.path}
|
||||||
@ -106,7 +105,7 @@ module Homebrew
|
|||||||
rescue Exception => e # rubocop:disable Lint/RescueException
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
||||||
retry if retry_test?(f, args: args)
|
retry if retry_test?(f, args: args)
|
||||||
ofail "#{f.full_name}: failed"
|
ofail "#{f.full_name}: failed"
|
||||||
puts e, e.backtrace
|
$stderr.puts e, e.backtrace
|
||||||
ensure
|
ensure
|
||||||
ENV.replace(env)
|
ENV.replace(env)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -78,7 +78,7 @@ module Homebrew
|
|||||||
elsif args.dependents?
|
elsif args.dependents?
|
||||||
formulae = all_formulae = Formula.to_a
|
formulae = all_formulae = Formula.to_a
|
||||||
|
|
||||||
@sort = " (sorted by installs in the last 90 days)"
|
@sort = " (sorted by number of dependents)"
|
||||||
else
|
else
|
||||||
formula_installs = {}
|
formula_installs = {}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ module Homebrew
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end.compact
|
end.compact
|
||||||
@sort = " (sorted by installs in the last 90 days)"
|
@sort = " (sorted by installs in the last 90 days; top 10,000 only)"
|
||||||
|
|
||||||
all_formulae = Formula
|
all_formulae = Formula
|
||||||
end
|
end
|
||||||
@ -154,20 +154,51 @@ module Homebrew
|
|||||||
|
|
||||||
formulae.each do |f|
|
formulae.each do |f|
|
||||||
name = f.name.downcase
|
name = f.name.downcase
|
||||||
if f.bottle_specification.tag?(@bottle_tag)
|
if f.bottle_specification.tag?(@bottle_tag, exact: true)
|
||||||
puts "#{Tty.bold}#{Tty.green}#{name}#{Tty.reset}: already bottled" if any_named_args
|
puts "#{Tty.bold}#{Tty.green}#{name}#{Tty.reset}: already bottled" if any_named_args
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
requirement_classes = f.recursive_requirements.map(&:class)
|
if f.disabled?
|
||||||
|
puts "#{Tty.bold}#{Tty.green}#{name}#{Tty.reset}: formula disabled" if any_named_args
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
requirements = f.recursive_requirements
|
||||||
if @bottle_tag.to_s.end_with?("_linux")
|
if @bottle_tag.to_s.end_with?("_linux")
|
||||||
if requirement_classes.include?(MacOSRequirement)
|
if requirements.any?(MacOSRequirement)
|
||||||
puts "#{Tty.bold}#{Tty.red}#{name}#{Tty.reset}: requires macOS" if any_named_args
|
puts "#{Tty.bold}#{Tty.red}#{name}#{Tty.reset}: requires macOS" if any_named_args
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
elsif requirement_classes.include?(LinuxRequirement)
|
elsif requirements.any?(LinuxRequirement)
|
||||||
puts "#{Tty.bold}#{Tty.red}#{name}#{Tty.reset}: requires Linux" if any_named_args
|
puts "#{Tty.bold}#{Tty.red}#{name}#{Tty.reset}: requires Linux" if any_named_args
|
||||||
next
|
next
|
||||||
|
else
|
||||||
|
macos_version = MacOS::Version.from_symbol(@bottle_tag)
|
||||||
|
macos_satisfied = requirements.all? do |r|
|
||||||
|
case r
|
||||||
|
when MacOSRequirement
|
||||||
|
next true unless r.version_specified?
|
||||||
|
|
||||||
|
macos_version.public_send(r.comparator, r.version)
|
||||||
|
when XcodeRequirement
|
||||||
|
next true unless r.version
|
||||||
|
|
||||||
|
Version.new(MacOS::Xcode.latest_version(macos: macos_version)) >= r.version
|
||||||
|
when ArchRequirement
|
||||||
|
arch = r.arch
|
||||||
|
arch = :intel if arch == :x86_64
|
||||||
|
arch = :arm64 if arch == :arm
|
||||||
|
|
||||||
|
arch == macos_version.arch
|
||||||
|
else
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
unless macos_satisfied
|
||||||
|
puts "#{Tty.bold}#{Tty.red}#{name}#{Tty.reset}: doesn't support this macOS" if any_named_args
|
||||||
|
next
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if f.bottle_unneeded? || f.bottle_disabled?
|
if f.bottle_unneeded? || f.bottle_disabled?
|
||||||
@ -181,7 +212,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
deps = Array(deps_hash[f.name]).reject do |dep|
|
deps = Array(deps_hash[f.name]).reject do |dep|
|
||||||
dep.bottle_specification.tag?(@bottle_tag) || dep.bottle_unneeded?
|
dep.bottle_specification.tag?(@bottle_tag, exact: true) || dep.bottle_unneeded?
|
||||||
end
|
end
|
||||||
|
|
||||||
if deps.blank?
|
if deps.blank?
|
||||||
|
|||||||
@ -38,7 +38,7 @@ module Homebrew
|
|||||||
|
|
||||||
formulae = args.named.to_formulae
|
formulae = args.named.to_formulae
|
||||||
|
|
||||||
if dir = args.destdir
|
if (dir = args.destdir)
|
||||||
unpack_dir = Pathname.new(dir).expand_path
|
unpack_dir = Pathname.new(dir).expand_path
|
||||||
unpack_dir.mkpath
|
unpack_dir.mkpath
|
||||||
else
|
else
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
require "cli/parser"
|
require "cli/parser"
|
||||||
require "utils/github"
|
require "utils/github"
|
||||||
|
require "dev-cmd/man"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
extend T::Sig
|
extend T::Sig
|
||||||
@ -61,7 +62,8 @@ module Homebrew
|
|||||||
if diff.status.success?
|
if diff.status.success?
|
||||||
puts "No changes to list of maintainers."
|
puts "No changes to list of maintainers."
|
||||||
else
|
else
|
||||||
puts "List of maintainers updated in README."
|
Homebrew.regenerate_man_pages(preserve_date: true, quiet: true)
|
||||||
|
puts "List of maintainers updated in the README and the generated man pages."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -54,9 +54,9 @@ module Homebrew
|
|||||||
|
|
||||||
start_commit, end_commit = nil
|
start_commit, end_commit = nil
|
||||||
cd HOMEBREW_REPOSITORY do
|
cd HOMEBREW_REPOSITORY do
|
||||||
start_commit = if commit = args.commit
|
start_commit = if (commit = args.commit)
|
||||||
commit
|
commit
|
||||||
elsif date = args.before
|
elsif (date = args.before)
|
||||||
Utils.popen_read("git", "rev-list", "-n1", "--before=#{date}", "origin/master").chomp
|
Utils.popen_read("git", "rev-list", "-n1", "--before=#{date}", "origin/master").chomp
|
||||||
elsif args.to_tag?
|
elsif args.to_tag?
|
||||||
tags = Utils.popen_read("git", "tag", "--list", "--sort=-version:refname")
|
tags = Utils.popen_read("git", "tag", "--list", "--sort=-version:refname")
|
||||||
|
|||||||
@ -43,7 +43,7 @@ class DevelopmentTools
|
|||||||
def clang_version
|
def clang_version
|
||||||
@clang_version ||= begin
|
@clang_version ||= begin
|
||||||
if (path = locate("clang")) &&
|
if (path = locate("clang")) &&
|
||||||
build_version = `#{path} --version`[/(?:clang|LLVM) version (\d+\.\d)/, 1]
|
(build_version = `#{path} --version`[/(?:clang|LLVM) version (\d+\.\d)/, 1])
|
||||||
Version.new build_version
|
Version.new build_version
|
||||||
else
|
else
|
||||||
Version::NULL
|
Version::NULL
|
||||||
@ -54,7 +54,7 @@ class DevelopmentTools
|
|||||||
def clang_build_version
|
def clang_build_version
|
||||||
@clang_build_version ||= begin
|
@clang_build_version ||= begin
|
||||||
if (path = locate("clang")) &&
|
if (path = locate("clang")) &&
|
||||||
build_version = `#{path} --version`[%r{clang(-| version [^ ]+ \(tags/RELEASE_)(\d{2,})}, 2]
|
(build_version = `#{path} --version`[%r{clang(-| version [^ ]+ \(tags/RELEASE_)(\d{2,})}, 2])
|
||||||
Version.new build_version
|
Version.new build_version
|
||||||
else
|
else
|
||||||
Version::NULL
|
Version::NULL
|
||||||
@ -66,7 +66,7 @@ class DevelopmentTools
|
|||||||
@llvm_clang_build_version ||= begin
|
@llvm_clang_build_version ||= begin
|
||||||
path = Formulary.factory("llvm").opt_prefix/"bin/clang"
|
path = Formulary.factory("llvm").opt_prefix/"bin/clang"
|
||||||
if path.executable? &&
|
if path.executable? &&
|
||||||
build_version = `#{path} --version`[/clang version (\d\.\d\.\d)/, 1]
|
(build_version = `#{path} --version`[/clang version (\d+\.\d\.\d)/, 1])
|
||||||
Version.new build_version
|
Version.new build_version
|
||||||
else
|
else
|
||||||
Version::NULL
|
Version::NULL
|
||||||
@ -76,10 +76,10 @@ class DevelopmentTools
|
|||||||
|
|
||||||
def non_apple_gcc_version(cc)
|
def non_apple_gcc_version(cc)
|
||||||
(@non_apple_gcc_version ||= {}).fetch(cc) do
|
(@non_apple_gcc_version ||= {}).fetch(cc) do
|
||||||
path = HOMEBREW_PREFIX/"opt/gcc/bin"/cc
|
path = HOMEBREW_PREFIX/"opt/#{CompilerSelector.preferred_gcc}/bin"/cc
|
||||||
path = locate(cc) unless path.exist?
|
path = locate(cc) unless path.exist?
|
||||||
version = if path &&
|
version = if path &&
|
||||||
build_version = `#{path} --version`[/gcc(?:(?:-\d+(?:\.\d)?)? \(.+\))? (\d+\.\d\.\d)/, 1]
|
(build_version = `#{path} --version`[/gcc(?:(?:-\d+(?:\.\d)?)? \(.+\))? (\d+\.\d\.\d)/, 1])
|
||||||
Version.new build_version
|
Version.new build_version
|
||||||
else
|
else
|
||||||
Version::NULL
|
Version::NULL
|
||||||
|
|||||||
@ -13,6 +13,11 @@ require "mechanize/http/content_disposition_parser"
|
|||||||
|
|
||||||
require "utils/curl"
|
require "utils/curl"
|
||||||
|
|
||||||
|
require "github_packages"
|
||||||
|
|
||||||
|
require "extend/time"
|
||||||
|
using TimeRemaining
|
||||||
|
|
||||||
# @abstract Abstract superclass for all download strategies.
|
# @abstract Abstract superclass for all download strategies.
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
@ -50,7 +55,7 @@ class AbstractDownloadStrategy
|
|||||||
# Download and cache the resource at {#cached_location}.
|
# Download and cache the resource at {#cached_location}.
|
||||||
#
|
#
|
||||||
# @api public
|
# @api public
|
||||||
def fetch; end
|
def fetch(timeout: nil); end
|
||||||
|
|
||||||
# Disable any output during downloading.
|
# Disable any output during downloading.
|
||||||
#
|
#
|
||||||
@ -66,30 +71,38 @@ class AbstractDownloadStrategy
|
|||||||
Context.current.quiet? || @quiet
|
Context.current.quiet? || @quiet
|
||||||
end
|
end
|
||||||
|
|
||||||
# Unpack {#cached_location} into the current working directory, and possibly
|
# Unpack {#cached_location} into the current working directory.
|
||||||
# chdir into the newly-unpacked directory.
|
#
|
||||||
# Unlike {Resource#stage}, this does not take a block.
|
# Additionally, if a block is given, the working directory was previously empty
|
||||||
|
# and a single directory is extracted from the archive, the block will be called
|
||||||
|
# with the working directory changed to that directory. Otherwise this method
|
||||||
|
# will return, or the block will be called, without changing the current working
|
||||||
|
# directory.
|
||||||
#
|
#
|
||||||
# @api public
|
# @api public
|
||||||
def stage
|
def stage(&block)
|
||||||
UnpackStrategy.detect(cached_location,
|
UnpackStrategy.detect(cached_location,
|
||||||
prioritise_extension: true,
|
prioritise_extension: true,
|
||||||
ref_type: @ref_type, ref: @ref)
|
ref_type: @ref_type, ref: @ref)
|
||||||
.extract_nestedly(basename: basename,
|
.extract_nestedly(basename: basename,
|
||||||
prioritise_extension: true,
|
prioritise_extension: true,
|
||||||
verbose: verbose? && !quiet?)
|
verbose: verbose? && !quiet?)
|
||||||
chdir
|
chdir(&block) if block
|
||||||
end
|
end
|
||||||
|
|
||||||
def chdir
|
def chdir(&block)
|
||||||
entries = Dir["*"]
|
entries = Dir["*"]
|
||||||
raise "Empty archive" if entries.length.zero?
|
raise "Empty archive" if entries.length.zero?
|
||||||
return if entries.length != 1
|
|
||||||
|
|
||||||
begin
|
if entries.length != 1
|
||||||
Dir.chdir entries.first
|
yield
|
||||||
rescue
|
return
|
||||||
nil
|
end
|
||||||
|
|
||||||
|
if File.directory? entries.first
|
||||||
|
Dir.chdir(entries.first, &block)
|
||||||
|
else
|
||||||
|
yield
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
private :chdir
|
private :chdir
|
||||||
@ -166,18 +179,20 @@ class VCSDownloadStrategy < AbstractDownloadStrategy
|
|||||||
# Download and cache the repository at {#cached_location}.
|
# Download and cache the repository at {#cached_location}.
|
||||||
#
|
#
|
||||||
# @api public
|
# @api public
|
||||||
def fetch
|
def fetch(timeout: nil)
|
||||||
|
end_time = Time.now + timeout if timeout
|
||||||
|
|
||||||
ohai "Cloning #{url}"
|
ohai "Cloning #{url}"
|
||||||
|
|
||||||
if cached_location.exist? && repo_valid?
|
if cached_location.exist? && repo_valid?
|
||||||
puts "Updating #{cached_location}"
|
puts "Updating #{cached_location}"
|
||||||
update
|
update(timeout: timeout)
|
||||||
elsif cached_location.exist?
|
elsif cached_location.exist?
|
||||||
puts "Removing invalid repository from cache"
|
puts "Removing invalid repository from cache"
|
||||||
clear_cache
|
clear_cache
|
||||||
clone_repo
|
clone_repo(timeout: end_time)
|
||||||
else
|
else
|
||||||
clone_repo
|
clone_repo(timeout: end_time)
|
||||||
end
|
end
|
||||||
|
|
||||||
version.update_commit(last_commit) if head?
|
version.update_commit(last_commit) if head?
|
||||||
@ -222,9 +237,11 @@ class VCSDownloadStrategy < AbstractDownloadStrategy
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
def clone_repo; end
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
|
def clone_repo(timeout: nil); end
|
||||||
|
|
||||||
def update; end
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
|
def update(timeout: nil); end
|
||||||
|
|
||||||
def current_revision; end
|
def current_revision; end
|
||||||
|
|
||||||
@ -303,7 +320,7 @@ class AbstractFileDownloadStrategy < AbstractDownloadStrategy
|
|||||||
query_params = CGI.parse(uri.query)
|
query_params = CGI.parse(uri.query)
|
||||||
query_params["response-content-disposition"].each do |param|
|
query_params["response-content-disposition"].each do |param|
|
||||||
query_basename = param[/attachment;\s*filename=(["']?)(.+)\1/i, 2]
|
query_basename = param[/attachment;\s*filename=(["']?)(.+)\1/i, 2]
|
||||||
return query_basename if query_basename
|
return File.basename(query_basename) if query_basename
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -343,7 +360,9 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
|
|||||||
# Download and cache the file at {#cached_location}.
|
# Download and cache the file at {#cached_location}.
|
||||||
#
|
#
|
||||||
# @api public
|
# @api public
|
||||||
def fetch
|
def fetch(timeout: nil)
|
||||||
|
end_time = Time.now + timeout if timeout
|
||||||
|
|
||||||
download_lock = LockFile.new(temporary_path.basename)
|
download_lock = LockFile.new(temporary_path.basename)
|
||||||
download_lock.lock
|
download_lock.lock
|
||||||
|
|
||||||
@ -354,7 +373,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
|
|||||||
|
|
||||||
ohai "Downloading #{url}"
|
ohai "Downloading #{url}"
|
||||||
|
|
||||||
resolved_url, _, url_time, = resolve_url_basename_time_file_size(url)
|
resolved_url, _, url_time, = resolve_url_basename_time_file_size(url, timeout: end_time&.remaining!)
|
||||||
|
|
||||||
fresh = if cached_location.exist? && url_time
|
fresh = if cached_location.exist? && url_time
|
||||||
url_time <= cached_location.mtime
|
url_time <= cached_location.mtime
|
||||||
@ -368,7 +387,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
|
|||||||
puts "Already downloaded: #{cached_location}"
|
puts "Already downloaded: #{cached_location}"
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
_fetch(url: url, resolved_url: resolved_url)
|
_fetch(url: url, resolved_url: resolved_url, timeout: end_time&.remaining!)
|
||||||
rescue ErrorDuringExecution
|
rescue ErrorDuringExecution
|
||||||
raise CurlDownloadStrategyError, url
|
raise CurlDownloadStrategyError, url
|
||||||
end
|
end
|
||||||
@ -385,6 +404,8 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
|
|||||||
|
|
||||||
puts "Trying a mirror..."
|
puts "Trying a mirror..."
|
||||||
retry
|
retry
|
||||||
|
rescue Timeout::Error => e
|
||||||
|
raise Timeout::Error, "Timed out downloading #{self.url}: #{e}"
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
download_lock&.unlock
|
download_lock&.unlock
|
||||||
@ -396,19 +417,19 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
|
|||||||
rm_rf(temporary_path)
|
rm_rf(temporary_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def resolved_time_file_size
|
def resolved_time_file_size(timeout: nil)
|
||||||
_, _, time, file_size = resolve_url_basename_time_file_size(url)
|
_, _, time, file_size = resolve_url_basename_time_file_size(url, timeout: timeout)
|
||||||
[time, file_size]
|
[time, file_size]
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def resolved_url_and_basename
|
def resolved_url_and_basename(timeout: nil)
|
||||||
resolved_url, basename, = resolve_url_basename_time_file_size(url)
|
resolved_url, basename, = resolve_url_basename_time_file_size(url, timeout: nil)
|
||||||
[resolved_url, basename]
|
[resolved_url, basename]
|
||||||
end
|
end
|
||||||
|
|
||||||
def resolve_url_basename_time_file_size(url)
|
def resolve_url_basename_time_file_size(url, timeout: nil)
|
||||||
@resolved_info_cache ||= {}
|
@resolved_info_cache ||= {}
|
||||||
return @resolved_info_cache[url] if @resolved_info_cache.include?(url)
|
return @resolved_info_cache[url] if @resolved_info_cache.include?(url)
|
||||||
|
|
||||||
@ -416,7 +437,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
|
|||||||
url = url.sub(%r{^((ht|f)tps?://)?}, "#{domain.chomp("/")}/")
|
url = url.sub(%r{^((ht|f)tps?://)?}, "#{domain.chomp("/")}/")
|
||||||
end
|
end
|
||||||
|
|
||||||
out, _, status= curl_output("--location", "--silent", "--head", "--request", "GET", url.to_s)
|
out, _, status= curl_output("--location", "--silent", "--head", "--request", "GET", url.to_s, timeout: timeout)
|
||||||
|
|
||||||
lines = status.success? ? out.lines.map(&:chomp) : []
|
lines = status.success? ? out.lines.map(&:chomp) : []
|
||||||
|
|
||||||
@ -441,16 +462,19 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
|
|||||||
content_disposition_parser = Mechanize::HTTP::ContentDispositionParser.new
|
content_disposition_parser = Mechanize::HTTP::ContentDispositionParser.new
|
||||||
|
|
||||||
parse_content_disposition = lambda do |line|
|
parse_content_disposition = lambda do |line|
|
||||||
next unless content_disposition = content_disposition_parser.parse(line.sub(/; *$/, ""), true)
|
next unless (content_disposition = content_disposition_parser.parse(line.sub(/; *$/, ""), true))
|
||||||
|
|
||||||
filename = nil
|
filename = nil
|
||||||
|
|
||||||
if filename_with_encoding = content_disposition.parameters["filename*"]
|
if (filename_with_encoding = content_disposition.parameters["filename*"])
|
||||||
encoding, encoded_filename = filename_with_encoding.split("''", 2)
|
encoding, encoded_filename = filename_with_encoding.split("''", 2)
|
||||||
filename = URI.decode_www_form_component(encoded_filename).encode(encoding) if encoding && encoded_filename
|
filename = URI.decode_www_form_component(encoded_filename).encode(encoding) if encoding && encoded_filename
|
||||||
end
|
end
|
||||||
|
|
||||||
filename || content_disposition.filename
|
# Servers may include '/' in their Content-Disposition filename header. Take only the basename of this, because:
|
||||||
|
# - Unpacking code assumes this is a single file - not something living in a subdirectory.
|
||||||
|
# - Directory traversal attacks are possible without limiting this to just the basename.
|
||||||
|
File.basename(filename || content_disposition.filename)
|
||||||
end
|
end
|
||||||
|
|
||||||
filenames = lines.map(&parse_content_disposition).compact
|
filenames = lines.map(&parse_content_disposition).compact
|
||||||
@ -472,7 +496,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
|
|||||||
@resolved_info_cache[url] = [redirect_url, basename, time, file_size]
|
@resolved_info_cache[url] = [redirect_url, basename, time, file_size]
|
||||||
end
|
end
|
||||||
|
|
||||||
def _fetch(url:, resolved_url:)
|
def _fetch(url:, resolved_url:, timeout:)
|
||||||
ohai "Downloading from #{resolved_url}" if url != resolved_url
|
ohai "Downloading from #{resolved_url}" if url != resolved_url
|
||||||
|
|
||||||
if Homebrew::EnvConfig.no_insecure_redirect? &&
|
if Homebrew::EnvConfig.no_insecure_redirect? &&
|
||||||
@ -481,7 +505,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
|
|||||||
raise CurlDownloadStrategyError, url
|
raise CurlDownloadStrategyError, url
|
||||||
end
|
end
|
||||||
|
|
||||||
curl_download resolved_url, to: temporary_path
|
curl_download resolved_url, to: temporary_path, timeout: timeout
|
||||||
end
|
end
|
||||||
|
|
||||||
# Curl options to be always passed to curl,
|
# Curl options to be always passed to curl,
|
||||||
@ -516,6 +540,25 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Strategy for downloading a file from an GitHub Packages URL.
|
||||||
|
#
|
||||||
|
# @api public
|
||||||
|
class CurlGitHubPackagesDownloadStrategy < CurlDownloadStrategy
|
||||||
|
attr_accessor :checksum, :name
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def _fetch(url:, resolved_url:)
|
||||||
|
raise "Empty checksum" if checksum.blank?
|
||||||
|
raise "Empty name" if name.blank?
|
||||||
|
|
||||||
|
_, org, repo, = *url.match(GitHubPackages::URL_REGEX)
|
||||||
|
|
||||||
|
blob_url = "https://ghcr.io/v2/#{org}/#{repo}/#{name}/blobs/sha256:#{checksum}"
|
||||||
|
curl_download(blob_url, "--header", "Authorization: Bearer", to: temporary_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Strategy for downloading a file from an Apache Mirror URL.
|
# Strategy for downloading a file from an Apache Mirror URL.
|
||||||
#
|
#
|
||||||
# @api public
|
# @api public
|
||||||
@ -535,9 +578,9 @@ class CurlApacheMirrorDownloadStrategy < CurlDownloadStrategy
|
|||||||
@combined_mirrors = [*@mirrors, *backup_mirrors]
|
@combined_mirrors = [*@mirrors, *backup_mirrors]
|
||||||
end
|
end
|
||||||
|
|
||||||
def resolve_url_basename_time_file_size(url)
|
def resolve_url_basename_time_file_size(url, timeout: nil)
|
||||||
if url == self.url
|
if url == self.url
|
||||||
super("#{apache_mirrors["preferred"]}#{apache_mirrors["path_info"]}")
|
super("#{apache_mirrors["preferred"]}#{apache_mirrors["path_info"]}", timeout: timeout)
|
||||||
else
|
else
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
@ -560,7 +603,7 @@ end
|
|||||||
class CurlPostDownloadStrategy < CurlDownloadStrategy
|
class CurlPostDownloadStrategy < CurlDownloadStrategy
|
||||||
private
|
private
|
||||||
|
|
||||||
def _fetch(url:, resolved_url:)
|
def _fetch(url:, resolved_url:, timeout:)
|
||||||
args = if meta.key?(:data)
|
args = if meta.key?(:data)
|
||||||
escape_data = ->(d) { ["-d", URI.encode_www_form([d])] }
|
escape_data = ->(d) { ["-d", URI.encode_www_form([d])] }
|
||||||
[url, *meta[:data].flat_map(&escape_data)]
|
[url, *meta[:data].flat_map(&escape_data)]
|
||||||
@ -569,7 +612,7 @@ class CurlPostDownloadStrategy < CurlDownloadStrategy
|
|||||||
query.nil? ? [url, "-X", "POST"] : [url, "-d", query]
|
query.nil? ? [url, "-X", "POST"] : [url, "-d", query]
|
||||||
end
|
end
|
||||||
|
|
||||||
curl_download(*args, to: temporary_path)
|
curl_download(*args, to: temporary_path, timeout: timeout)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -582,6 +625,7 @@ class NoUnzipCurlDownloadStrategy < CurlDownloadStrategy
|
|||||||
UnpackStrategy::Uncompressed.new(cached_location)
|
UnpackStrategy::Uncompressed.new(cached_location)
|
||||||
.extract(basename: basename,
|
.extract(basename: basename,
|
||||||
verbose: verbose? && !quiet?)
|
verbose: verbose? && !quiet?)
|
||||||
|
yield if block_given?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -608,7 +652,7 @@ class SubversionDownloadStrategy < VCSDownloadStrategy
|
|||||||
# Download and cache the repository at {#cached_location}.
|
# Download and cache the repository at {#cached_location}.
|
||||||
#
|
#
|
||||||
# @api public
|
# @api public
|
||||||
def fetch
|
def fetch(timeout: nil)
|
||||||
if @url.chomp("/") != repo_url || !silent_command("svn", args: ["switch", @url, cached_location]).success?
|
if @url.chomp("/") != repo_url || !silent_command("svn", args: ["switch", @url, cached_location]).success?
|
||||||
clear_cache
|
clear_cache
|
||||||
end
|
end
|
||||||
@ -649,7 +693,11 @@ class SubversionDownloadStrategy < VCSDownloadStrategy
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_repo(target, url, revision = nil, ignore_externals: false)
|
sig {
|
||||||
|
params(target: Pathname, url: String, revision: T.nilable(String), ignore_externals: T::Boolean,
|
||||||
|
timeout: T.nilable(Time)).void
|
||||||
|
}
|
||||||
|
def fetch_repo(target, url, revision = nil, ignore_externals: false, timeout: nil)
|
||||||
# Use "svn update" when the repository already exists locally.
|
# Use "svn update" when the repository already exists locally.
|
||||||
# This saves on bandwidth and will have a similar effect to verifying the
|
# This saves on bandwidth and will have a similar effect to verifying the
|
||||||
# cache as it will make any changes to get the right revision.
|
# cache as it will make any changes to get the right revision.
|
||||||
@ -669,9 +717,9 @@ class SubversionDownloadStrategy < VCSDownloadStrategy
|
|||||||
end
|
end
|
||||||
|
|
||||||
if target.directory?
|
if target.directory?
|
||||||
command!("svn", args: ["update", *args], chdir: target.to_s)
|
command! "svn", args: ["update", *args], chdir: target.to_s, timeout: timeout&.remaining
|
||||||
else
|
else
|
||||||
command!("svn", args: ["checkout", url, target, *args])
|
command! "svn", args: ["checkout", url, target, *args], timeout: timeout&.remaining
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -684,20 +732,22 @@ class SubversionDownloadStrategy < VCSDownloadStrategy
|
|||||||
(cached_location/".svn").directory?
|
(cached_location/".svn").directory?
|
||||||
end
|
end
|
||||||
|
|
||||||
def clone_repo
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
|
def clone_repo(timeout: nil)
|
||||||
case @ref_type
|
case @ref_type
|
||||||
when :revision
|
when :revision
|
||||||
fetch_repo cached_location, @url, @ref
|
fetch_repo cached_location, @url, @ref, timeout: timeout
|
||||||
when :revisions
|
when :revisions
|
||||||
# nil is OK for main_revision, as fetch_repo will then get latest
|
# nil is OK for main_revision, as fetch_repo will then get latest
|
||||||
main_revision = @ref[:trunk]
|
main_revision = @ref[:trunk]
|
||||||
fetch_repo cached_location, @url, main_revision, ignore_externals: true
|
fetch_repo cached_location, @url, main_revision, ignore_externals: true, timeout: timeout
|
||||||
|
|
||||||
externals do |external_name, external_url|
|
externals do |external_name, external_url|
|
||||||
fetch_repo cached_location/external_name, external_url, @ref[external_name], ignore_externals: true
|
fetch_repo cached_location/external_name, external_url, @ref[external_name], ignore_externals: true,
|
||||||
|
timeout: timeout
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
fetch_repo cached_location, @url
|
fetch_repo cached_location, @url, timeout: timeout
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
alias update clone_repo
|
alias update clone_repo
|
||||||
@ -746,12 +796,13 @@ class GitDownloadStrategy < VCSDownloadStrategy
|
|||||||
0
|
0
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
|
def update(timeout: nil)
|
||||||
config_repo
|
config_repo
|
||||||
update_repo
|
update_repo(timeout: timeout)
|
||||||
checkout
|
checkout(timeout: timeout)
|
||||||
reset
|
reset
|
||||||
update_submodules if submodules?
|
update_submodules(timeout: timeout) if submodules?
|
||||||
end
|
end
|
||||||
|
|
||||||
def shallow_clone?
|
def shallow_clone?
|
||||||
@ -812,6 +863,7 @@ class GitDownloadStrategy < VCSDownloadStrategy
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { void }
|
||||||
def config_repo
|
def config_repo
|
||||||
command! "git",
|
command! "git",
|
||||||
args: ["config", "remote.origin.url", @url],
|
args: ["config", "remote.origin.url", @url],
|
||||||
@ -824,35 +876,42 @@ class GitDownloadStrategy < VCSDownloadStrategy
|
|||||||
chdir: cached_location
|
chdir: cached_location
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_repo
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
|
def update_repo(timeout: nil)
|
||||||
return if @ref_type != :branch && ref?
|
return if @ref_type != :branch && ref?
|
||||||
|
|
||||||
if !shallow_clone? && shallow_dir?
|
if !shallow_clone? && shallow_dir?
|
||||||
command! "git",
|
command! "git",
|
||||||
args: ["fetch", "origin", "--unshallow"],
|
args: ["fetch", "origin", "--unshallow"],
|
||||||
chdir: cached_location
|
chdir: cached_location,
|
||||||
|
timeout: timeout&.remaining
|
||||||
else
|
else
|
||||||
command! "git",
|
command! "git",
|
||||||
args: ["fetch", "origin"],
|
args: ["fetch", "origin"],
|
||||||
chdir: cached_location
|
chdir: cached_location,
|
||||||
|
timeout: timeout&.remaining
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def clone_repo
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
command! "git", args: clone_args
|
def clone_repo(timeout: nil)
|
||||||
|
command! "git", args: clone_args, timeout: timeout&.remaining
|
||||||
|
|
||||||
command! "git",
|
command! "git",
|
||||||
args: ["config", "homebrew.cacheversion", cache_version],
|
args: ["config", "homebrew.cacheversion", cache_version],
|
||||||
chdir: cached_location
|
chdir: cached_location,
|
||||||
checkout
|
timeout: timeout&.remaining
|
||||||
update_submodules if submodules?
|
checkout(timeout: timeout)
|
||||||
|
update_submodules(timeout: timeout) if submodules?
|
||||||
end
|
end
|
||||||
|
|
||||||
def checkout
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
|
def checkout(timeout: nil)
|
||||||
ohai "Checking out #{@ref_type} #{@ref}" if @ref_type && @ref
|
ohai "Checking out #{@ref_type} #{@ref}" if @ref_type && @ref
|
||||||
command! "git", args: ["checkout", "-f", @ref, "--"], chdir: cached_location
|
command! "git", args: ["checkout", "-f", @ref, "--"], chdir: cached_location, timeout: timeout&.remaining
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { void }
|
||||||
def reset
|
def reset
|
||||||
ref = case @ref_type
|
ref = case @ref_type
|
||||||
when :branch
|
when :branch
|
||||||
@ -866,13 +925,16 @@ class GitDownloadStrategy < VCSDownloadStrategy
|
|||||||
chdir: cached_location
|
chdir: cached_location
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_submodules
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
|
def update_submodules(timeout: nil)
|
||||||
command! "git",
|
command! "git",
|
||||||
args: ["submodule", "foreach", "--recursive", "git submodule sync"],
|
args: ["submodule", "foreach", "--recursive", "git submodule sync"],
|
||||||
chdir: cached_location
|
chdir: cached_location,
|
||||||
|
timeout: timeout&.remaining
|
||||||
command! "git",
|
command! "git",
|
||||||
args: ["submodule", "update", "--init", "--recursive"],
|
args: ["submodule", "update", "--init", "--recursive"],
|
||||||
chdir: cached_location
|
chdir: cached_location,
|
||||||
|
timeout: timeout&.remaining
|
||||||
fix_absolute_submodule_gitdir_references!
|
fix_absolute_submodule_gitdir_references!
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1024,23 +1086,27 @@ class CVSDownloadStrategy < VCSDownloadStrategy
|
|||||||
"-Q" unless verbose?
|
"-Q" unless verbose?
|
||||||
end
|
end
|
||||||
|
|
||||||
def clone_repo
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
|
def clone_repo(timeout: nil)
|
||||||
# Login is only needed (and allowed) with pserver; skip for anoncvs.
|
# Login is only needed (and allowed) with pserver; skip for anoncvs.
|
||||||
command! "cvs", args: [*quiet_flag, "-d", @url, "login"] if @url.include? "pserver"
|
command! "cvs", args: [*quiet_flag, "-d", @url, "login"], timeout: timeout&.remaining if @url.include? "pserver"
|
||||||
|
|
||||||
command! "cvs",
|
command! "cvs",
|
||||||
args: [*quiet_flag, "-d", @url, "checkout", "-d", cached_location.basename, @module],
|
args: [*quiet_flag, "-d", @url, "checkout", "-d", cached_location.basename, @module],
|
||||||
chdir: cached_location.dirname
|
chdir: cached_location.dirname,
|
||||||
|
timeout: timeout&.remaining
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
|
def update(timeout: nil)
|
||||||
command! "cvs",
|
command! "cvs",
|
||||||
args: [*quiet_flag, "update"],
|
args: [*quiet_flag, "update"],
|
||||||
chdir: cached_location
|
chdir: cached_location,
|
||||||
|
timeout: timeout&.remaining
|
||||||
end
|
end
|
||||||
|
|
||||||
def split_url(in_url)
|
def split_url(in_url)
|
||||||
parts = in_url.split(/:/)
|
parts = in_url.split(":")
|
||||||
mod = parts.pop
|
mod = parts.pop
|
||||||
url = parts.join(":")
|
url = parts.join(":")
|
||||||
[mod, url]
|
[mod, url]
|
||||||
@ -1088,12 +1154,14 @@ class MercurialDownloadStrategy < VCSDownloadStrategy
|
|||||||
(cached_location/".hg").directory?
|
(cached_location/".hg").directory?
|
||||||
end
|
end
|
||||||
|
|
||||||
def clone_repo
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
command! "hg", args: ["clone", @url, cached_location]
|
def clone_repo(timeout: nil)
|
||||||
|
command! "hg", args: ["clone", @url, cached_location], timeout: timeout&.remaining
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
command! "hg", args: ["--cwd", cached_location, "pull", "--update"]
|
def update(timeout: nil)
|
||||||
|
command! "hg", args: ["--cwd", cached_location, "pull", "--update"], timeout: timeout&.remaining
|
||||||
|
|
||||||
update_args = if @ref_type && @ref
|
update_args = if @ref_type && @ref
|
||||||
ohai "Checking out #{@ref_type} #{@ref}"
|
ohai "Checking out #{@ref_type} #{@ref}"
|
||||||
@ -1102,7 +1170,7 @@ class MercurialDownloadStrategy < VCSDownloadStrategy
|
|||||||
["--clean"]
|
["--clean"]
|
||||||
end
|
end
|
||||||
|
|
||||||
command! "hg", args: ["--cwd", cached_location, "update", *update_args]
|
command! "hg", args: ["--cwd", cached_location, "update", *update_args], timeout: timeout&.remaining
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1151,16 +1219,20 @@ class BazaarDownloadStrategy < VCSDownloadStrategy
|
|||||||
(cached_location/".bzr").directory?
|
(cached_location/".bzr").directory?
|
||||||
end
|
end
|
||||||
|
|
||||||
def clone_repo
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
|
def clone_repo(timeout: nil)
|
||||||
# "lightweight" means history-less
|
# "lightweight" means history-less
|
||||||
command! "bzr",
|
command! "bzr",
|
||||||
args: ["checkout", "--lightweight", @url, cached_location]
|
args: ["checkout", "--lightweight", @url, cached_location],
|
||||||
|
timeout: timeout&.remaining
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
|
def update(timeout: nil)
|
||||||
command! "bzr",
|
command! "bzr",
|
||||||
args: ["update"],
|
args: ["update"],
|
||||||
chdir: cached_location
|
chdir: cached_location,
|
||||||
|
timeout: timeout&.remaining
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1203,12 +1275,14 @@ class FossilDownloadStrategy < VCSDownloadStrategy
|
|||||||
"fossil"
|
"fossil"
|
||||||
end
|
end
|
||||||
|
|
||||||
def clone_repo
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
silent_command!("fossil", args: ["clone", @url, cached_location])
|
def clone_repo(timeout: nil)
|
||||||
|
silent_command! "fossil", args: ["clone", @url, cached_location], timeout: timeout&.remaining
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
sig { params(timeout: T.nilable(Time)).void }
|
||||||
silent_command!("fossil", args: ["pull", "-R", cached_location])
|
def update(timeout: nil)
|
||||||
|
silent_command! "fossil", args: ["pull", "-R", cached_location], timeout: timeout&.remaining
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1231,6 +1305,8 @@ class DownloadStrategyDetector
|
|||||||
|
|
||||||
def self.detect_from_url(url)
|
def self.detect_from_url(url)
|
||||||
case url
|
case url
|
||||||
|
when GitHubPackages::URL_REGEX
|
||||||
|
CurlGitHubPackagesDownloadStrategy
|
||||||
when %r{^https?://github\.com/[^/]+/[^/]+\.git$}
|
when %r{^https?://github\.com/[^/]+/[^/]+\.git$}
|
||||||
GitHubGitDownloadStrategy
|
GitHubGitDownloadStrategy
|
||||||
when %r{^https?://.+\.git$},
|
when %r{^https?://.+\.git$},
|
||||||
|
|||||||
@ -46,8 +46,12 @@ module Homebrew
|
|||||||
},
|
},
|
||||||
HOMEBREW_BOTTLE_DOMAIN: {
|
HOMEBREW_BOTTLE_DOMAIN: {
|
||||||
description: "Use this URL as the download mirror for bottles. " \
|
description: "Use this URL as the download mirror for bottles. " \
|
||||||
|
"If bottles at that URL are temporarily unavailable, " \
|
||||||
|
"the default bottle domain will be used as a fallback mirror. " \
|
||||||
"For example, `HOMEBREW_BOTTLE_DOMAIN=http://localhost:8080` will cause all bottles to " \
|
"For example, `HOMEBREW_BOTTLE_DOMAIN=http://localhost:8080` will cause all bottles to " \
|
||||||
"download from the prefix `http://localhost:8080/`.",
|
"download from the prefix `http://localhost:8080/`. " \
|
||||||
|
"If bottles are not available at `HOMEBREW_BOTTLE_DOMAIN` " \
|
||||||
|
"they will be downloaded from the default bottle domain.",
|
||||||
default_text: "macOS: `https://homebrew.bintray.com/`, " \
|
default_text: "macOS: `https://homebrew.bintray.com/`, " \
|
||||||
"Linux: `https://linuxbrew.bintray.com/`.",
|
"Linux: `https://linuxbrew.bintray.com/`.",
|
||||||
default: HOMEBREW_BOTTLE_DEFAULT_DOMAIN,
|
default: HOMEBREW_BOTTLE_DEFAULT_DOMAIN,
|
||||||
@ -168,6 +172,13 @@ module Homebrew
|
|||||||
"\n\n *Note:* Homebrew doesn't require permissions for any of the scopes, but some " \
|
"\n\n *Note:* Homebrew doesn't require permissions for any of the scopes, but some " \
|
||||||
"developer commands may require additional permissions.",
|
"developer commands may require additional permissions.",
|
||||||
},
|
},
|
||||||
|
HOMEBREW_GITHUB_PACKAGES_TOKEN: {
|
||||||
|
description: "Use this GitHub personal access token when accessing the GitHub Packages Registry "\
|
||||||
|
"(where bottles may be stored).",
|
||||||
|
},
|
||||||
|
HOMEBREW_GITHUB_PACKAGES_USER: {
|
||||||
|
description: "Use this username when accessing the GitHub Packages Registry (where bottles may be stored).",
|
||||||
|
},
|
||||||
HOMEBREW_GIT_EMAIL: {
|
HOMEBREW_GIT_EMAIL: {
|
||||||
description: "Set the Git author and committer email to this value.",
|
description: "Set the Git author and committer email to this value.",
|
||||||
},
|
},
|
||||||
@ -179,6 +190,10 @@ module Homebrew
|
|||||||
default_text: 'The "Beer Mug" emoji.',
|
default_text: 'The "Beer Mug" emoji.',
|
||||||
default: "🍺",
|
default: "🍺",
|
||||||
},
|
},
|
||||||
|
HOMEBREW_INTERNET_ARCHIVE_KEY: {
|
||||||
|
description: "Use this API key when accessing the Internet Archive S3 API, where bottles are stored. " \
|
||||||
|
"The format is access:secret. See https://archive.org/account/s3.php",
|
||||||
|
},
|
||||||
HOMEBREW_LIVECHECK_WATCHLIST: {
|
HOMEBREW_LIVECHECK_WATCHLIST: {
|
||||||
description: "Consult this file for the list of formulae to check by default when no formula argument " \
|
description: "Consult this file for the list of formulae to check by default when no formula argument " \
|
||||||
"is passed to `brew livecheck`.",
|
"is passed to `brew livecheck`.",
|
||||||
@ -204,19 +219,14 @@ module Homebrew
|
|||||||
boolean: true,
|
boolean: true,
|
||||||
},
|
},
|
||||||
HOMEBREW_NO_AUTO_UPDATE: {
|
HOMEBREW_NO_AUTO_UPDATE: {
|
||||||
description: "If set, do not automatically update before running " \
|
description: "If set, do not automatically update before running some commands e.g. " \
|
||||||
"`brew install`, `brew upgrade` or `brew tap`.",
|
"`brew install`, `brew upgrade` and `brew tap`.",
|
||||||
boolean: true,
|
boolean: true,
|
||||||
},
|
},
|
||||||
HOMEBREW_NO_BOOTSNAP: {
|
HOMEBREW_NO_BOOTSNAP: {
|
||||||
description: "If set, do not use Bootsnap to speed up repeated `brew` calls.",
|
description: "If set, do not use Bootsnap to speed up repeated `brew` calls.",
|
||||||
boolean: true,
|
boolean: true,
|
||||||
},
|
},
|
||||||
HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: {
|
|
||||||
description: "If set, fail on the failure of installation from a bottle rather than " \
|
|
||||||
"falling back to building from source.",
|
|
||||||
boolean: true,
|
|
||||||
},
|
|
||||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: {
|
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: {
|
||||||
description: "If set, do not check for broken dependents after installing, upgrading or reinstalling " \
|
description: "If set, do not check for broken dependents after installing, upgrading or reinstalling " \
|
||||||
"formulae.",
|
"formulae.",
|
||||||
@ -257,6 +267,11 @@ module Homebrew
|
|||||||
description: "If set, use Pry for the `brew irb` command.",
|
description: "If set, use Pry for the `brew irb` command.",
|
||||||
boolean: true,
|
boolean: true,
|
||||||
},
|
},
|
||||||
|
HOMEBREW_SIMULATE_MACOS_ON_LINUX: {
|
||||||
|
description: "If set, running Homebrew on Linux will simulate certain macOS code paths. This is useful " \
|
||||||
|
"when auditing macOS formulae while on Linux. Implies `HOMEBREW_FORCE_HOMEBREW_ON_LINUX`.",
|
||||||
|
boolean: true,
|
||||||
|
},
|
||||||
HOMEBREW_SKIP_OR_LATER_BOTTLES: {
|
HOMEBREW_SKIP_OR_LATER_BOTTLES: {
|
||||||
description: "If set along with `HOMEBREW_DEVELOPER`, do not use bottles from older versions " \
|
description: "If set along with `HOMEBREW_DEVELOPER`, do not use bottles from older versions " \
|
||||||
"of macOS. This is useful in development on new macOS versions.",
|
"of macOS. This is useful in development on new macOS versions.",
|
||||||
|
|||||||
@ -97,6 +97,25 @@ class FormulaOrCaskUnavailableError < RuntimeError
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Raised when a formula or cask in a specific tap is not available.
|
||||||
|
class TapFormulaOrCaskUnavailableError < FormulaOrCaskUnavailableError
|
||||||
|
extend T::Sig
|
||||||
|
|
||||||
|
attr_reader :tap
|
||||||
|
|
||||||
|
def initialize(tap, name)
|
||||||
|
super "#{tap}/#{name}"
|
||||||
|
@tap = tap
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { returns(String) }
|
||||||
|
def to_s
|
||||||
|
s = super
|
||||||
|
s += "\nPlease tap it and then try again: brew tap #{tap}" unless tap.installed?
|
||||||
|
s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Raised when a formula is not available.
|
# Raised when a formula is not available.
|
||||||
class FormulaUnavailableError < FormulaOrCaskUnavailableError
|
class FormulaUnavailableError < FormulaOrCaskUnavailableError
|
||||||
extend T::Sig
|
extend T::Sig
|
||||||
@ -423,7 +442,7 @@ class BuildError < RuntimeError
|
|||||||
|
|
||||||
def fetch_issues
|
def fetch_issues
|
||||||
GitHub.issues_for_formula(formula.name, tap: formula.tap, state: "open")
|
GitHub.issues_for_formula(formula.name, tap: formula.tap, state: "open")
|
||||||
rescue GitHub::RateLimitExceededError => e
|
rescue GitHub::API::RateLimitExceededError => e
|
||||||
opoo e.message
|
opoo e.message
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
@ -453,7 +472,7 @@ class BuildError < RuntimeError
|
|||||||
if formula.tap && defined?(OS::ISSUES_URL)
|
if formula.tap && defined?(OS::ISSUES_URL)
|
||||||
if formula.tap.official?
|
if formula.tap.official?
|
||||||
puts Formatter.error(Formatter.url(OS::ISSUES_URL), label: "READ THIS")
|
puts Formatter.error(Formatter.url(OS::ISSUES_URL), label: "READ THIS")
|
||||||
elsif issues_url = formula.tap.issues_url
|
elsif (issues_url = formula.tap.issues_url)
|
||||||
puts <<~EOS
|
puts <<~EOS
|
||||||
If reporting this issue please do so at (not Homebrew/brew or Homebrew/core):
|
If reporting this issue please do so at (not Homebrew/brew or Homebrew/core):
|
||||||
#{Formatter.url(issues_url)}
|
#{Formatter.url(issues_url)}
|
||||||
@ -579,19 +598,32 @@ class ErrorDuringExecution < RuntimeError
|
|||||||
@status = status
|
@status = status
|
||||||
@output = output
|
@output = output
|
||||||
|
|
||||||
|
raise ArgumentError, "Status cannot be nil." if status.nil?
|
||||||
|
|
||||||
exitstatus = case status
|
exitstatus = case status
|
||||||
when Integer
|
when Integer
|
||||||
status
|
status
|
||||||
|
when Hash
|
||||||
|
status["exitstatus"]
|
||||||
else
|
else
|
||||||
status&.exitstatus
|
status.exitstatus
|
||||||
|
end
|
||||||
|
|
||||||
|
termsig = case status
|
||||||
|
when Integer
|
||||||
|
nil
|
||||||
|
when Hash
|
||||||
|
status["termsig"]
|
||||||
|
else
|
||||||
|
status.termsig
|
||||||
end
|
end
|
||||||
|
|
||||||
redacted_cmd = redact_secrets(cmd.shelljoin.gsub('\=', "="), secrets)
|
redacted_cmd = redact_secrets(cmd.shelljoin.gsub('\=', "="), secrets)
|
||||||
|
|
||||||
reason = if exitstatus
|
reason = if exitstatus
|
||||||
"exited with #{exitstatus}"
|
"exited with #{exitstatus}"
|
||||||
elsif (uncaught_signal = status&.termsig)
|
elsif termsig
|
||||||
"was terminated by uncaught signal #{Signal.signame(uncaught_signal)}"
|
"was terminated by uncaught signal #{Signal.signame(termsig)}"
|
||||||
else
|
else
|
||||||
raise ArgumentError, "Status neither has `exitstatus` nor `termsig`."
|
raise ArgumentError, "Status neither has `exitstatus` nor `termsig`."
|
||||||
end
|
end
|
||||||
|
|||||||
@ -35,7 +35,7 @@ module EnvActivation
|
|||||||
params(
|
params(
|
||||||
env: T.nilable(String),
|
env: T.nilable(String),
|
||||||
cc: T.nilable(String),
|
cc: T.nilable(String),
|
||||||
build_bottle: T.nilable(T::Boolean),
|
build_bottle: T::Boolean,
|
||||||
bottle_arch: T.nilable(String),
|
bottle_arch: T.nilable(String),
|
||||||
_block: T.proc.returns(T.untyped),
|
_block: T.proc.returns(T.untyped),
|
||||||
).returns(T.untyped)
|
).returns(T.untyped)
|
||||||
|
|||||||
@ -38,10 +38,11 @@ module SharedEnvExtension
|
|||||||
formula: T.nilable(Formula),
|
formula: T.nilable(Formula),
|
||||||
cc: T.nilable(String),
|
cc: T.nilable(String),
|
||||||
build_bottle: T.nilable(T::Boolean),
|
build_bottle: T.nilable(T::Boolean),
|
||||||
bottle_arch: T.nilable(T::Boolean),
|
bottle_arch: T.nilable(String),
|
||||||
|
testing_formula: T::Boolean,
|
||||||
).void
|
).void
|
||||||
}
|
}
|
||||||
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil)
|
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
|
||||||
@formula = formula
|
@formula = formula
|
||||||
@cc = cc
|
@cc = cc
|
||||||
@build_bottle = build_bottle
|
@build_bottle = build_bottle
|
||||||
|
|||||||
@ -19,10 +19,11 @@ module Stdenv
|
|||||||
formula: T.nilable(Formula),
|
formula: T.nilable(Formula),
|
||||||
cc: T.nilable(String),
|
cc: T.nilable(String),
|
||||||
build_bottle: T.nilable(T::Boolean),
|
build_bottle: T.nilable(T::Boolean),
|
||||||
bottle_arch: T.nilable(T::Boolean),
|
bottle_arch: T.nilable(String),
|
||||||
|
testing_formula: T::Boolean,
|
||||||
).void
|
).void
|
||||||
}
|
}
|
||||||
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil)
|
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
|
||||||
super
|
super
|
||||||
|
|
||||||
self["HOMEBREW_ENV"] = "std"
|
self["HOMEBREW_ENV"] = "std"
|
||||||
|
|||||||
@ -47,10 +47,11 @@ module Superenv
|
|||||||
formula: T.nilable(Formula),
|
formula: T.nilable(Formula),
|
||||||
cc: T.nilable(String),
|
cc: T.nilable(String),
|
||||||
build_bottle: T.nilable(T::Boolean),
|
build_bottle: T.nilable(T::Boolean),
|
||||||
bottle_arch: T.nilable(T::Boolean),
|
bottle_arch: T.nilable(String),
|
||||||
|
testing_formula: T::Boolean,
|
||||||
).void
|
).void
|
||||||
}
|
}
|
||||||
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil)
|
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
|
||||||
super
|
super
|
||||||
send(compiler)
|
send(compiler)
|
||||||
|
|
||||||
|
|||||||
@ -32,14 +32,14 @@ module GitRepositoryExtension
|
|||||||
# Gets the full commit hash of the HEAD commit.
|
# Gets the full commit hash of the HEAD commit.
|
||||||
sig { params(safe: T::Boolean).returns(T.nilable(String)) }
|
sig { params(safe: T::Boolean).returns(T.nilable(String)) }
|
||||||
def git_head(safe: false)
|
def git_head(safe: false)
|
||||||
popen_git("rev-parse", "--verify", "-q", "HEAD", safe: safe)
|
popen_git("rev-parse", "--verify", "--quiet", "HEAD", safe: safe)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Gets a short commit hash of the HEAD commit.
|
# Gets a short commit hash of the HEAD commit.
|
||||||
sig { params(length: T.nilable(Integer), safe: T::Boolean).returns(T.nilable(String)) }
|
sig { params(length: T.nilable(Integer), safe: T::Boolean).returns(T.nilable(String)) }
|
||||||
def git_short_head(length: nil, safe: false)
|
def git_short_head(length: nil, safe: false)
|
||||||
short_arg = length.present? ? "--short=#{length}" : "--short"
|
short_arg = length.present? ? "--short=#{length}" : "--short"
|
||||||
popen_git("rev-parse", short_arg, "--verify", "-q", "HEAD", safe: safe)
|
popen_git("rev-parse", short_arg, "--verify", "--quiet", "HEAD", safe: safe)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Gets the relative date of the last commit, e.g. "1 hour ago"
|
# Gets the relative date of the last commit, e.g. "1 hour ago"
|
||||||
|
|||||||
@ -3,7 +3,10 @@
|
|||||||
|
|
||||||
module Stdenv
|
module Stdenv
|
||||||
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
|
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
|
||||||
generic_setup_build_environment(formula: formula, cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch)
|
generic_setup_build_environment(
|
||||||
|
formula: formula, cc: cc, build_bottle: build_bottle,
|
||||||
|
bottle_arch: bottle_arch, testing_formula: testing_formula
|
||||||
|
)
|
||||||
|
|
||||||
prepend_path "CPATH", HOMEBREW_PREFIX/"include"
|
prepend_path "CPATH", HOMEBREW_PREFIX/"include"
|
||||||
prepend_path "LIBRARY_PATH", HOMEBREW_PREFIX/"lib"
|
prepend_path "LIBRARY_PATH", HOMEBREW_PREFIX/"lib"
|
||||||
|
|||||||
@ -11,7 +11,10 @@ module Superenv
|
|||||||
|
|
||||||
# @private
|
# @private
|
||||||
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
|
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
|
||||||
generic_setup_build_environment(formula: formula, cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch)
|
generic_setup_build_environment(
|
||||||
|
formula: formula, cc: cc, build_bottle: build_bottle,
|
||||||
|
bottle_arch: bottle_arch, testing_formula: testing_formula
|
||||||
|
)
|
||||||
self["HOMEBREW_OPTIMIZATION_LEVEL"] = "O2"
|
self["HOMEBREW_OPTIMIZATION_LEVEL"] = "O2"
|
||||||
self["HOMEBREW_DYNAMIC_LINKER"] = determine_dynamic_linker_path
|
self["HOMEBREW_DYNAMIC_LINKER"] = determine_dynamic_linker_path
|
||||||
self["HOMEBREW_RPATH_PATHS"] = determine_rpath_paths(@formula)
|
self["HOMEBREW_RPATH_PATHS"] = determine_rpath_paths(@formula)
|
||||||
|
|||||||
@ -80,7 +80,11 @@ class Keg
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.relocation_formulae
|
def self.relocation_formulae
|
||||||
|
@relocation_formulae ||= if HOMEBREW_PATCHELF_RB_WRITE
|
||||||
|
[]
|
||||||
|
else
|
||||||
["patchelf"]
|
["patchelf"]
|
||||||
|
end.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.bottle_dependencies
|
def self.bottle_dependencies
|
||||||
|
|||||||
@ -51,10 +51,7 @@ class DevelopmentTools
|
|||||||
|
|
||||||
sig { returns(String) }
|
sig { returns(String) }
|
||||||
def installation_instructions
|
def installation_instructions
|
||||||
<<~EOS
|
MacOS::CLT.installation_instructions
|
||||||
Install the Command Line Tools:
|
|
||||||
xcode-select --install
|
|
||||||
EOS
|
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { returns(String) }
|
sig { returns(String) }
|
||||||
|
|||||||
@ -64,6 +64,7 @@ module Homebrew
|
|||||||
check_clt_minimum_version
|
check_clt_minimum_version
|
||||||
check_if_xcode_needs_clt_installed
|
check_if_xcode_needs_clt_installed
|
||||||
check_if_supported_sdk_available
|
check_if_supported_sdk_available
|
||||||
|
check_broken_sdks
|
||||||
].freeze
|
].freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -425,7 +426,7 @@ module Homebrew
|
|||||||
|
|
||||||
source = if locator.source == :clt
|
source = if locator.source == :clt
|
||||||
update_instructions = MacOS::CLT.update_instructions
|
update_instructions = MacOS::CLT.update_instructions
|
||||||
"CLT"
|
"Command Line Tools (CLT)"
|
||||||
else
|
else
|
||||||
update_instructions = MacOS::Xcode.update_instructions
|
update_instructions = MacOS::Xcode.update_instructions
|
||||||
"Xcode"
|
"Xcode"
|
||||||
@ -438,6 +439,40 @@ module Homebrew
|
|||||||
#{update_instructions}
|
#{update_instructions}
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# The CLT 10.x -> 11.x upgrade process on 10.14 contained a bug which broke the SDKs.
|
||||||
|
# Notably, MacOSX10.14.sdk would indirectly symlink to MacOSX10.15.sdk.
|
||||||
|
# This diagnostic was introduced to check for this and recommend a full reinstall.
|
||||||
|
def check_broken_sdks
|
||||||
|
locator = MacOS.sdk_locator
|
||||||
|
|
||||||
|
return if locator.all_sdks.all? do |sdk|
|
||||||
|
path_version = sdk.path.basename.to_s[MacOS::SDK::VERSIONED_SDK_REGEX, 1]
|
||||||
|
next true if path_version.blank?
|
||||||
|
|
||||||
|
sdk.version == MacOS::Version.new(path_version).strip_patch
|
||||||
|
end
|
||||||
|
|
||||||
|
if locator.source == :clt
|
||||||
|
source = "Command Line Tools (CLT)"
|
||||||
|
path_to_remove = MacOS::CLT::PKG_PATH
|
||||||
|
installation_instructions = MacOS::CLT.installation_instructions
|
||||||
|
else
|
||||||
|
source = "Xcode"
|
||||||
|
path_to_remove = MacOS::Xcode.bundle_path
|
||||||
|
installation_instructions = MacOS::Xcode.installation_instructions
|
||||||
|
end
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
The contents of the SDKs in your #{source} installation do not match the SDK folder names.
|
||||||
|
A clean reinstall of #{source} should fix this.
|
||||||
|
|
||||||
|
Remove the broken installation before reinstalling:
|
||||||
|
sudo rm -rf #{path_to_remove}
|
||||||
|
|
||||||
|
#{installation_instructions}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -11,7 +11,10 @@ module Stdenv
|
|||||||
end
|
end
|
||||||
|
|
||||||
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
|
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
|
||||||
generic_setup_build_environment(formula: formula, cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch)
|
generic_setup_build_environment(
|
||||||
|
formula: formula, cc: cc, build_bottle: build_bottle,
|
||||||
|
bottle_arch: bottle_arch, testing_formula: testing_formula
|
||||||
|
)
|
||||||
|
|
||||||
# sed is strict, and errors out when it encounters files with
|
# sed is strict, and errors out when it encounters files with
|
||||||
# mixed character sets
|
# mixed character sets
|
||||||
|
|||||||
@ -98,8 +98,6 @@ module Superenv
|
|||||||
|
|
||||||
def determine_cccfg
|
def determine_cccfg
|
||||||
s = +""
|
s = +""
|
||||||
# Fix issue with sed barfing on unicode characters on Mountain Lion
|
|
||||||
s << "s"
|
|
||||||
# Fix issue with >= Mountain Lion apr-1-config having broken paths
|
# Fix issue with >= Mountain Lion apr-1-config having broken paths
|
||||||
s << "a"
|
s << "a"
|
||||||
s.freeze
|
s.freeze
|
||||||
@ -121,7 +119,10 @@ module Superenv
|
|||||||
self["HOMEBREW_SDKROOT"] = nil
|
self["HOMEBREW_SDKROOT"] = nil
|
||||||
self["HOMEBREW_DEVELOPER_DIR"] = nil
|
self["HOMEBREW_DEVELOPER_DIR"] = nil
|
||||||
end
|
end
|
||||||
generic_setup_build_environment(formula: formula, cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch)
|
generic_setup_build_environment(
|
||||||
|
formula: formula, cc: cc, build_bottle: build_bottle,
|
||||||
|
bottle_arch: bottle_arch, testing_formula: testing_formula
|
||||||
|
)
|
||||||
|
|
||||||
# Filter out symbols known not to be defined since GNU Autotools can't
|
# Filter out symbols known not to be defined since GNU Autotools can't
|
||||||
# reliably figure this out with Xcode 8 and above.
|
# reliably figure this out with Xcode 8 and above.
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
# typed: false
|
# typed: false
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# The Library/Homebrew/extend/os/software_spec.rb conditional logic will need to be more nuanced
|
||||||
|
# if this file ever includes more than `uses_from_macos`.
|
||||||
class SoftwareSpec
|
class SoftwareSpec
|
||||||
undef uses_from_macos
|
undef uses_from_macos
|
||||||
|
|
||||||
@ -9,11 +11,12 @@ class SoftwareSpec
|
|||||||
|
|
||||||
if deps.is_a?(Hash)
|
if deps.is_a?(Hash)
|
||||||
bounds = deps.dup
|
bounds = deps.dup
|
||||||
deps = Hash[*bounds.shift]
|
deps = bounds.shift
|
||||||
end
|
end
|
||||||
|
|
||||||
bounds = bounds.transform_values { |v| MacOS::Version.from_symbol(v) }
|
bounds = bounds.transform_values { |v| MacOS::Version.from_symbol(v) }
|
||||||
if MacOS.version >= bounds[:since]
|
if MacOS.version >= bounds[:since] ||
|
||||||
|
(Homebrew::EnvConfig.simulate_macos_on_linux? && !bounds.key?(:since))
|
||||||
@uses_from_macos_elements << deps
|
@uses_from_macos_elements << deps
|
||||||
else
|
else
|
||||||
depends_on deps
|
depends_on deps
|
||||||
|
|||||||
@ -20,10 +20,10 @@ module Utils
|
|||||||
|
|
||||||
alias generic_find_matching_tag find_matching_tag
|
alias generic_find_matching_tag find_matching_tag
|
||||||
|
|
||||||
def find_matching_tag(tag)
|
def find_matching_tag(tag, exact: false)
|
||||||
# Used primarily by developers testing beta macOS releases.
|
# Used primarily by developers testing beta macOS releases.
|
||||||
if OS::Mac.prerelease? && Homebrew::EnvConfig.developer? &&
|
if exact || (OS::Mac.prerelease? && Homebrew::EnvConfig.developer? &&
|
||||||
Homebrew::EnvConfig.skip_or_later_bottles?
|
Homebrew::EnvConfig.skip_or_later_bottles?)
|
||||||
generic_find_matching_tag(tag)
|
generic_find_matching_tag(tag)
|
||||||
else
|
else
|
||||||
generic_find_matching_tag(tag) ||
|
generic_find_matching_tag(tag) ||
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# typed: strict
|
# typed: strict
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
if OS.mac?
|
if OS.mac? || Homebrew::EnvConfig.simulate_macos_on_linux?
|
||||||
require "extend/os/mac/on_os"
|
require "extend/os/mac/on_os"
|
||||||
elsif OS.linux?
|
elsif OS.linux?
|
||||||
require "extend/os/linux/on_os"
|
require "extend/os/linux/on_os"
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
# typed: strict
|
# typed: strict
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
if OS.linux?
|
# This logic will need to be more nuanced if this file includes more than `uses_from_macos`.
|
||||||
require "extend/os/linux/software_spec"
|
if OS.mac? || Homebrew::EnvConfig.simulate_macos_on_linux?
|
||||||
elsif OS.mac?
|
|
||||||
require "extend/os/mac/software_spec"
|
require "extend/os/mac/software_spec"
|
||||||
|
elsif OS.linux?
|
||||||
|
require "extend/os/linux/software_spec"
|
||||||
end
|
end
|
||||||
|
|||||||
18
Library/Homebrew/extend/time.rb
Normal file
18
Library/Homebrew/extend/time.rb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# typed: false
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module TimeRemaining
|
||||||
|
refine Time do
|
||||||
|
def remaining
|
||||||
|
[0, self - Time.now].max
|
||||||
|
end
|
||||||
|
|
||||||
|
def remaining!
|
||||||
|
r = remaining
|
||||||
|
|
||||||
|
raise Timeout::Error if r <= 0
|
||||||
|
|
||||||
|
r
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -2061,7 +2061,7 @@ class Formula
|
|||||||
|
|
||||||
if verbose_using_dots
|
if verbose_using_dots
|
||||||
last_dot = Time.at(0)
|
last_dot = Time.at(0)
|
||||||
while buf = rd.gets
|
while (buf = rd.gets)
|
||||||
log.puts buf
|
log.puts buf
|
||||||
# make sure dots printed with interval of at least 1 min.
|
# make sure dots printed with interval of at least 1 min.
|
||||||
next unless (Time.now - last_dot) > 60
|
next unless (Time.now - last_dot) > 60
|
||||||
@ -2072,7 +2072,7 @@ class Formula
|
|||||||
end
|
end
|
||||||
puts
|
puts
|
||||||
else
|
else
|
||||||
while buf = rd.gets
|
while (buf = rd.gets)
|
||||||
log.puts buf
|
log.puts buf
|
||||||
puts buf
|
puts buf
|
||||||
end
|
end
|
||||||
|
|||||||
@ -8,8 +8,54 @@ module Homebrew
|
|||||||
module Assertions
|
module Assertions
|
||||||
include Context
|
include Context
|
||||||
|
|
||||||
require "test/unit/assertions"
|
require "minitest"
|
||||||
include ::Test::Unit::Assertions
|
require "minitest/assertions"
|
||||||
|
include ::Minitest::Assertions
|
||||||
|
|
||||||
|
attr_writer :assertions
|
||||||
|
|
||||||
|
def assertions
|
||||||
|
@assertions ||= 0
|
||||||
|
end
|
||||||
|
|
||||||
|
# Test::Unit backwards compatibility methods
|
||||||
|
{
|
||||||
|
assert_include: :assert_includes,
|
||||||
|
assert_path_exist: :assert_path_exists,
|
||||||
|
assert_raise: :assert_raises,
|
||||||
|
assert_throw: :assert_throws,
|
||||||
|
assert_not_empty: :refute_empty,
|
||||||
|
assert_not_equal: :refute_equal,
|
||||||
|
assert_not_in_delta: :refute_in_delta,
|
||||||
|
assert_not_in_epsilon: :refute_in_epsilon,
|
||||||
|
assert_not_include: :refute_includes,
|
||||||
|
assert_not_includes: :refute_includes,
|
||||||
|
assert_not_instance_of: :refute_instance_of,
|
||||||
|
assert_not_kind_of: :refute_kind_of,
|
||||||
|
assert_not_match: :refute_match,
|
||||||
|
assert_no_match: :refute_match,
|
||||||
|
assert_not_nil: :refute_nil,
|
||||||
|
assert_not_operator: :refute_operator,
|
||||||
|
assert_path_not_exist: :refute_path_exists,
|
||||||
|
assert_not_predicate: :refute_predicate,
|
||||||
|
assert_not_respond_to: :refute_respond_to,
|
||||||
|
assert_not_same: :refute_same,
|
||||||
|
}.each do |old_method, new_method|
|
||||||
|
define_method(old_method) do |*args|
|
||||||
|
# odeprecated old_method, new_method
|
||||||
|
send(new_method, *args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_true(act, msg = nil)
|
||||||
|
# odeprecated "assert_true", "assert(...) or assert_equal(true, ...)"
|
||||||
|
assert_equal(true, act, msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_false(act, msg = nil)
|
||||||
|
# odeprecated "assert_false", "assert(!...) or assert_equal(false, ...)"
|
||||||
|
assert_equal(false, act, msg)
|
||||||
|
end
|
||||||
|
|
||||||
# Returns the output of running cmd, and asserts the exit status.
|
# Returns the output of running cmd, and asserts the exit status.
|
||||||
# @api public
|
# @api public
|
||||||
@ -18,7 +64,7 @@ module Homebrew
|
|||||||
output = `#{cmd}`
|
output = `#{cmd}`
|
||||||
assert_equal result, $CHILD_STATUS.exitstatus
|
assert_equal result, $CHILD_STATUS.exitstatus
|
||||||
output
|
output
|
||||||
rescue Test::Unit::AssertionFailedError
|
rescue Minitest::Assertion
|
||||||
puts output if verbose?
|
puts output if verbose?
|
||||||
raise
|
raise
|
||||||
end
|
end
|
||||||
@ -35,7 +81,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
assert_equal result, $CHILD_STATUS.exitstatus unless result.nil?
|
assert_equal result, $CHILD_STATUS.exitstatus unless result.nil?
|
||||||
output
|
output
|
||||||
rescue Test::Unit::AssertionFailedError
|
rescue Minitest::Assertion
|
||||||
puts output if verbose?
|
puts output if verbose?
|
||||||
raise
|
raise
|
||||||
end
|
end
|
||||||
|
|||||||
@ -133,7 +133,7 @@ module Homebrew
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if oldname = CoreTap.instance.formula_renames[name]
|
if (oldname = CoreTap.instance.formula_renames[name])
|
||||||
problem "'#{name}' is reserved as the old name of #{oldname} in homebrew/core."
|
problem "'#{name}' is reserved as the old name of #{oldname} in homebrew/core."
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -282,7 +282,7 @@ module Homebrew
|
|||||||
|
|
||||||
# The number of conflicts on Linux is absurd.
|
# The number of conflicts on Linux is absurd.
|
||||||
# TODO: remove this and check these there too.
|
# TODO: remove this and check these there too.
|
||||||
return if OS.linux?
|
return if OS.linux? && !Homebrew::EnvConfig.simulate_macos_on_linux?
|
||||||
|
|
||||||
recursive_runtime_formulae = formula.runtime_formula_dependencies(undeclared: false)
|
recursive_runtime_formulae = formula.runtime_formula_dependencies(undeclared: false)
|
||||||
version_hash = {}
|
version_hash = {}
|
||||||
@ -339,6 +339,18 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def audit_glibc
|
||||||
|
return if formula.name != "glibc"
|
||||||
|
return unless @core_tap
|
||||||
|
|
||||||
|
version = formula.version.to_s
|
||||||
|
return if version == "2.23"
|
||||||
|
|
||||||
|
problem "The glibc version must be #{version}, as this is the version used by our CI on Linux. " \
|
||||||
|
"Glibc is for users who have a system Glibc with a lower version, " \
|
||||||
|
"which allows them to use our Linux bottles, which were compiled against system Glibc on CI."
|
||||||
|
end
|
||||||
|
|
||||||
def audit_versioned_keg_only
|
def audit_versioned_keg_only
|
||||||
return unless @versioned_formula
|
return unless @versioned_formula
|
||||||
return unless @core_tap
|
return unless @core_tap
|
||||||
@ -367,10 +379,10 @@ module Homebrew
|
|||||||
|
|
||||||
return unless DevelopmentTools.curl_handles_most_https_certificates?
|
return unless DevelopmentTools.curl_handles_most_https_certificates?
|
||||||
|
|
||||||
if http_content_problem = curl_check_http_content(homepage,
|
if (http_content_problem = curl_check_http_content(homepage,
|
||||||
user_agents: [:browser, :default],
|
user_agents: [:browser, :default],
|
||||||
check_content: true,
|
check_content: true,
|
||||||
strict: @strict)
|
strict: @strict))
|
||||||
problem http_content_problem
|
problem http_content_problem
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -472,7 +484,7 @@ module Homebrew
|
|||||||
|
|
||||||
%w[Stable HEAD].each do |name|
|
%w[Stable HEAD].each do |name|
|
||||||
spec_name = name.downcase.to_sym
|
spec_name = name.downcase.to_sym
|
||||||
next unless spec = formula.send(spec_name)
|
next unless (spec = formula.send(spec_name))
|
||||||
|
|
||||||
ra = ResourceAuditor.new(spec, spec_name, online: @online, strict: @strict).audit
|
ra = ResourceAuditor.new(spec, spec_name, online: @online, strict: @strict).audit
|
||||||
ra.problems.each do |message|
|
ra.problems.each do |message|
|
||||||
@ -497,7 +509,7 @@ module Homebrew
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
if stable = formula.stable
|
if (stable = formula.stable)
|
||||||
version = stable.version
|
version = stable.version
|
||||||
problem "Stable: version (#{version}) is set to a string without a digit" if version.to_s !~ /\d/
|
problem "Stable: version (#{version}) is set to a string without a digit" if version.to_s !~ /\d/
|
||||||
if version.to_s.start_with?("HEAD")
|
if version.to_s.start_with?("HEAD")
|
||||||
|
|||||||
@ -79,7 +79,7 @@ module Homebrew
|
|||||||
@desc = metadata["description"]
|
@desc = metadata["description"]
|
||||||
@homepage = metadata["homepage"]
|
@homepage = metadata["homepage"]
|
||||||
@license = metadata["license"]["spdx_id"] if metadata["license"]
|
@license = metadata["license"]["spdx_id"] if metadata["license"]
|
||||||
rescue GitHub::HTTPNotFoundError
|
rescue GitHub::API::HTTPNotFoundError
|
||||||
# If there was no repository found assume the network connection is at
|
# If there was no repository found assume the network connection is at
|
||||||
# fault rather than the input URL.
|
# fault rather than the input URL.
|
||||||
nil
|
nil
|
||||||
@ -153,13 +153,14 @@ module Homebrew
|
|||||||
def install
|
def install
|
||||||
# ENV.deparallelize # if your formula fails when building in parallel
|
# ENV.deparallelize # if your formula fails when building in parallel
|
||||||
<% if mode == :cmake %>
|
<% if mode == :cmake %>
|
||||||
system "cmake", ".", *std_cmake_args
|
system "cmake", "-S", ".", "-B", "build", *std_cmake_args
|
||||||
|
system "cmake", "--build", "build"
|
||||||
|
system "cmake", "--install", "build"
|
||||||
<% elsif mode == :autotools %>
|
<% elsif mode == :autotools %>
|
||||||
# Remove unrecognized options if warned by configure
|
# Remove unrecognized options if warned by configure
|
||||||
system "./configure", "--disable-debug",
|
# https://rubydoc.brew.sh/Formula.html#std_configure_args-instance_method
|
||||||
"--disable-dependency-tracking",
|
system "./configure", *std_configure_args, "--disable-silent-rules"
|
||||||
"--disable-silent-rules",
|
system "make", "install" # if this fails, try separate make/make install steps
|
||||||
"--prefix=\#{prefix}"
|
|
||||||
<% elsif mode == :crystal %>
|
<% elsif mode == :crystal %>
|
||||||
system "shards", "build", "--release"
|
system "shards", "build", "--release"
|
||||||
bin.install "bin/#{name}"
|
bin.install "bin/#{name}"
|
||||||
@ -206,14 +207,9 @@ module Homebrew
|
|||||||
system "cargo", "install", *std_cargo_args
|
system "cargo", "install", *std_cargo_args
|
||||||
<% else %>
|
<% else %>
|
||||||
# Remove unrecognized options if warned by configure
|
# Remove unrecognized options if warned by configure
|
||||||
system "./configure", "--disable-debug",
|
# https://rubydoc.brew.sh/Formula.html#std_configure_args-instance_method
|
||||||
"--disable-dependency-tracking",
|
system "./configure", *std_configure_args, "--disable-silent-rules"
|
||||||
"--disable-silent-rules",
|
# system "cmake", "-S", ".", "-B", "build", *std_cmake_args
|
||||||
"--prefix=\#{prefix}"
|
|
||||||
# system "cmake", ".", *std_cmake_args
|
|
||||||
<% end %>
|
|
||||||
<% if mode == :autotools || mode == :cmake %>
|
|
||||||
system "make", "install" # if this fails, try separate make/make install steps
|
|
||||||
<% end %>
|
<% end %>
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -16,13 +16,11 @@ class FormulaInfo
|
|||||||
# Returns nil if formula is absent or if there was an error reading it.
|
# Returns nil if formula is absent or if there was an error reading it.
|
||||||
def self.lookup(name)
|
def self.lookup(name)
|
||||||
json = Utils.popen_read(
|
json = Utils.popen_read(
|
||||||
RUBY_PATH,
|
*HOMEBREW_RUBY_EXEC_ARGS,
|
||||||
ENV["HOMEBREW_RUBY_WARNINGS"],
|
|
||||||
"-I", $LOAD_PATH.join(File::PATH_SEPARATOR),
|
|
||||||
HOMEBREW_LIBRARY_PATH/"brew.rb",
|
HOMEBREW_LIBRARY_PATH/"brew.rb",
|
||||||
"info",
|
"info",
|
||||||
"--json=v1",
|
"--json=v1",
|
||||||
name
|
name,
|
||||||
)
|
)
|
||||||
|
|
||||||
return unless $CHILD_STATUS.success?
|
return unless $CHILD_STATUS.success?
|
||||||
|
|||||||
@ -94,7 +94,6 @@ class FormulaInstaller
|
|||||||
@options = options
|
@options = options
|
||||||
@requirement_messages = []
|
@requirement_messages = []
|
||||||
@poured_bottle = false
|
@poured_bottle = false
|
||||||
@pour_failed = false
|
|
||||||
@start_time = nil
|
@start_time = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -154,8 +153,6 @@ class FormulaInstaller
|
|||||||
|
|
||||||
sig { params(output_warning: T::Boolean).returns(T::Boolean) }
|
sig { params(output_warning: T::Boolean).returns(T::Boolean) }
|
||||||
def pour_bottle?(output_warning: false)
|
def pour_bottle?(output_warning: false)
|
||||||
return false if @pour_failed
|
|
||||||
|
|
||||||
return false if !formula.bottle_tag? && !formula.local_bottle_path
|
return false if !formula.bottle_tag? && !formula.local_bottle_path
|
||||||
return true if force_bottle?
|
return true if force_bottle?
|
||||||
return false if build_from_source? || build_bottle? || interactive?
|
return false if build_from_source? || build_bottle? || interactive?
|
||||||
@ -230,13 +227,12 @@ class FormulaInstaller
|
|||||||
raise CannotInstallFormulaError, "--force-bottle passed but #{formula.full_name} has no bottle!"
|
raise CannotInstallFormulaError, "--force-bottle passed but #{formula.full_name} has no bottle!"
|
||||||
end
|
end
|
||||||
|
|
||||||
if Homebrew.default_prefix? && !Homebrew::EnvConfig.developer? &&
|
if Homebrew.default_prefix? &&
|
||||||
# TODO: re-enable this on Linux when we merge linuxbrew-core into
|
# TODO: re-enable this on Linux when we merge linuxbrew-core into
|
||||||
# homebrew-core and have full bottle coverage.
|
# homebrew-core and have full bottle coverage.
|
||||||
(OS.mac? || ENV["CI"]) &&
|
(OS.mac? || ENV["CI"]) &&
|
||||||
!build_from_source? && !build_bottle? &&
|
!build_from_source? && !build_bottle? && !formula.head? &&
|
||||||
!installed_as_dependency? &&
|
formula.tap&.core_tap? && !formula.bottle_unneeded? &&
|
||||||
formula.tap&.core_tap? && !formula.bottle_unneeded? && !formula.any_version_installed? &&
|
|
||||||
# Integration tests override homebrew-core locations
|
# Integration tests override homebrew-core locations
|
||||||
ENV["HOMEBREW_TEST_TMPDIR"].nil? &&
|
ENV["HOMEBREW_TEST_TMPDIR"].nil? &&
|
||||||
!pour_bottle?
|
!pour_bottle?
|
||||||
@ -244,12 +240,21 @@ class FormulaInstaller
|
|||||||
formula_message = formula.pour_bottle_check_unsatisfied_reason
|
formula_message = formula.pour_bottle_check_unsatisfied_reason
|
||||||
formula_message[0] = formula_message[0].downcase
|
formula_message[0] = formula_message[0].downcase
|
||||||
|
|
||||||
"#{formula}: #{formula_message}"
|
<<~EOS
|
||||||
else
|
#{formula}: #{formula_message}
|
||||||
|
EOS
|
||||||
|
# don't want to complain about no bottle available if doing an
|
||||||
|
# upgrade/reinstall/dependency install (but do in the case the bottle
|
||||||
|
# check fails)
|
||||||
|
elsif !Homebrew::EnvConfig.developer? &&
|
||||||
|
(!installed_as_dependency? || !formula.any_version_installed?) &&
|
||||||
|
(!OS.mac? || !OS::Mac.outdated_release?)
|
||||||
<<~EOS
|
<<~EOS
|
||||||
#{formula}: no bottle available!
|
#{formula}: no bottle available!
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if message
|
||||||
message += <<~EOS
|
message += <<~EOS
|
||||||
You can try to install from source with:
|
You can try to install from source with:
|
||||||
brew install --build-from-source #{formula}
|
brew install --build-from-source #{formula}
|
||||||
@ -260,6 +265,7 @@ class FormulaInstaller
|
|||||||
EOS
|
EOS
|
||||||
raise CannotInstallFormulaError, message
|
raise CannotInstallFormulaError, message
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
type, reason = DeprecateDisable.deprecate_disable_info formula
|
type, reason = DeprecateDisable.deprecate_disable_info formula
|
||||||
|
|
||||||
@ -282,49 +288,51 @@ class FormulaInstaller
|
|||||||
|
|
||||||
return if ignore_deps?
|
return if ignore_deps?
|
||||||
|
|
||||||
recursive_deps = formula.recursive_dependencies
|
if Homebrew::EnvConfig.developer?
|
||||||
recursive_formulae = recursive_deps.map(&:to_formula)
|
# `recursive_dependencies` trims cyclic dependencies, so we do one level and take the recursive deps of that.
|
||||||
|
# Mapping direct dependencies to deeper dependencies in a hash is also useful for the cyclic output below.
|
||||||
|
recursive_dep_map = formula.deps.to_h { |dep| [dep, dep.to_formula.recursive_dependencies] }
|
||||||
|
|
||||||
recursive_dependencies = []
|
cyclic_dependencies = []
|
||||||
invalid_arch_dependencies = []
|
recursive_dep_map.each do |dep, recursive_deps|
|
||||||
recursive_formulae.each do |dep|
|
if [formula.name, formula.full_name].include?(dep.name)
|
||||||
dep_recursive_dependencies = dep.recursive_dependencies.map(&:to_s)
|
cyclic_dependencies << "#{formula.full_name} depends on itself directly"
|
||||||
if dep_recursive_dependencies.include?(formula.name)
|
elsif recursive_deps.any? { |rdep| [formula.name, formula.full_name].include?(rdep.name) }
|
||||||
recursive_dependencies << "#{formula.full_name} depends on #{dep.full_name}"
|
cyclic_dependencies << "#{formula.full_name} depends on itself via #{dep.name}"
|
||||||
recursive_dependencies << "#{dep.full_name} depends on #{formula.full_name}"
|
|
||||||
end
|
|
||||||
|
|
||||||
if (tab = Tab.for_formula(dep)) && tab.arch.present? && tab.arch.to_s != Hardware::CPU.arch.to_s
|
|
||||||
invalid_arch_dependencies << "#{dep} was built for #{tab.arch}"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
unless recursive_dependencies.empty?
|
if cyclic_dependencies.present?
|
||||||
raise CannotInstallFormulaError, <<~EOS
|
raise CannotInstallFormulaError, <<~EOS
|
||||||
#{formula.full_name} contains a recursive dependency on itself:
|
#{formula.full_name} contains a recursive dependency on itself:
|
||||||
#{recursive_dependencies.join("\n ")}
|
#{cyclic_dependencies.join("\n ")}
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
if recursive_formulae.flat_map(&:recursive_dependencies)
|
# Merge into one list
|
||||||
.map(&:to_s)
|
recursive_deps = recursive_dep_map.flat_map { |dep, rdeps| [dep] + rdeps }
|
||||||
.include?(formula.name)
|
Dependency.merge_repeats(recursive_deps)
|
||||||
raise CannotInstallFormulaError, <<~EOS
|
else
|
||||||
#{formula.full_name} contains a recursive dependency on itself!
|
recursive_deps = formula.recursive_dependencies
|
||||||
EOS
|
|
||||||
end
|
end
|
||||||
|
|
||||||
unless invalid_arch_dependencies.empty?
|
invalid_arch_dependencies = []
|
||||||
|
pinned_unsatisfied_deps = []
|
||||||
|
recursive_deps.each do |dep|
|
||||||
|
if (tab = Tab.for_formula(dep.to_formula)) && tab.arch.present? && tab.arch.to_s != Hardware::CPU.arch.to_s
|
||||||
|
invalid_arch_dependencies << "#{dep} was built for #{tab.arch}"
|
||||||
|
end
|
||||||
|
|
||||||
|
pinned_unsatisfied_deps << dep if dep.to_formula.pinned? && !dep.satisfied?(inherited_options_for(dep))
|
||||||
|
end
|
||||||
|
|
||||||
|
if invalid_arch_dependencies.present?
|
||||||
raise CannotInstallFormulaError, <<~EOS
|
raise CannotInstallFormulaError, <<~EOS
|
||||||
#{formula.full_name} dependencies not built for the #{Hardware::CPU.arch} CPU architecture:
|
#{formula.full_name} dependencies not built for the #{Hardware::CPU.arch} CPU architecture:
|
||||||
#{invalid_arch_dependencies.join("\n ")}
|
#{invalid_arch_dependencies.join("\n ")}
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
pinned_unsatisfied_deps = recursive_deps.select do |dep|
|
|
||||||
dep.to_formula.pinned? && !dep.satisfied?(inherited_options_for(dep))
|
|
||||||
end
|
|
||||||
|
|
||||||
return if pinned_unsatisfied_deps.empty?
|
return if pinned_unsatisfied_deps.empty?
|
||||||
|
|
||||||
raise CannotInstallFormulaError,
|
raise CannotInstallFormulaError,
|
||||||
@ -429,7 +437,7 @@ class FormulaInstaller
|
|||||||
if pour_bottle?
|
if pour_bottle?
|
||||||
begin
|
begin
|
||||||
pour
|
pour
|
||||||
rescue Exception => e # rubocop:disable Lint/RescueException
|
rescue Exception # rubocop:disable Lint/RescueException
|
||||||
# any exceptions must leave us with nothing installed
|
# any exceptions must leave us with nothing installed
|
||||||
ignore_interrupts do
|
ignore_interrupts do
|
||||||
begin
|
begin
|
||||||
@ -442,17 +450,7 @@ class FormulaInstaller
|
|||||||
end
|
end
|
||||||
formula.rack.rmdir_if_possible
|
formula.rack.rmdir_if_possible
|
||||||
end
|
end
|
||||||
raise if Homebrew::EnvConfig.developer? ||
|
raise
|
||||||
Homebrew::EnvConfig.no_bottle_source_fallback? ||
|
|
||||||
force_bottle? ||
|
|
||||||
e.is_a?(Interrupt)
|
|
||||||
|
|
||||||
@pour_failed = true
|
|
||||||
onoe e.message
|
|
||||||
opoo "Bottle installation failed: building from source."
|
|
||||||
raise UnbottledError, [formula] unless DevelopmentTools.installed?
|
|
||||||
|
|
||||||
compute_and_install_dependencies unless ignore_deps?
|
|
||||||
else
|
else
|
||||||
@poured_bottle = true
|
@poured_bottle = true
|
||||||
end
|
end
|
||||||
@ -513,7 +511,7 @@ class FormulaInstaller
|
|||||||
|
|
||||||
$stderr.puts "Please report this issue to the #{formula.tap} tap (not Homebrew/brew or Homebrew/core)!"
|
$stderr.puts "Please report this issue to the #{formula.tap} tap (not Homebrew/brew or Homebrew/core)!"
|
||||||
false
|
false
|
||||||
else # rubocop:disable Layout/ElseAlignment
|
else
|
||||||
f.linked_keg.exist? && f.opt_prefix.exist?
|
f.linked_keg.exist? && f.opt_prefix.exist?
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -523,10 +521,12 @@ class FormulaInstaller
|
|||||||
# Compute and collect the dependencies needed by the formula currently
|
# Compute and collect the dependencies needed by the formula currently
|
||||||
# being installed.
|
# being installed.
|
||||||
def compute_dependencies
|
def compute_dependencies
|
||||||
|
@compute_dependencies ||= begin
|
||||||
req_map, req_deps = expand_requirements
|
req_map, req_deps = expand_requirements
|
||||||
check_requirements(req_map)
|
check_requirements(req_map)
|
||||||
expand_dependencies(req_deps + formula.deps)
|
expand_dependencies(req_deps + formula.deps)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def unbottled_dependencies(deps)
|
def unbottled_dependencies(deps)
|
||||||
deps.map(&:first).map(&:to_formula).reject do |dep_f|
|
deps.map(&:first).map(&:to_formula).reject do |dep_f|
|
||||||
@ -575,7 +575,7 @@ class FormulaInstaller
|
|||||||
formula_deps_map = Dependency.expand(formula)
|
formula_deps_map = Dependency.expand(formula)
|
||||||
.index_by(&:name)
|
.index_by(&:name)
|
||||||
|
|
||||||
while f = formulae.pop
|
while (f = formulae.pop)
|
||||||
runtime_requirements = runtime_requirements(f)
|
runtime_requirements = runtime_requirements(f)
|
||||||
f.recursive_requirements do |dependent, req|
|
f.recursive_requirements do |dependent, req|
|
||||||
build = effective_build_options_for(dependent)
|
build = effective_build_options_for(dependent)
|
||||||
@ -707,16 +707,17 @@ class FormulaInstaller
|
|||||||
quiet: quiet?,
|
quiet: quiet?,
|
||||||
verbose: verbose?,
|
verbose: verbose?,
|
||||||
)
|
)
|
||||||
|
fi.prelude
|
||||||
fi.fetch
|
fi.fetch
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { params(dep: Dependency, inherited_options: Options).void }
|
sig { params(dep: Dependency, inherited_options: Options).void }
|
||||||
def install_dependency(dep, inherited_options)
|
def install_dependency(dep, inherited_options)
|
||||||
df = dep.to_formula
|
df = dep.to_formula
|
||||||
tab = Tab.for_formula(df)
|
|
||||||
|
|
||||||
if df.linked_keg.directory?
|
if df.linked_keg.directory?
|
||||||
linked_keg = Keg.new(df.linked_keg.resolved_path)
|
linked_keg = Keg.new(df.linked_keg.resolved_path)
|
||||||
|
tab = Tab.for_keg(linked_keg)
|
||||||
keg_had_linked_keg = true
|
keg_had_linked_keg = true
|
||||||
keg_was_linked = linked_keg.linked?
|
keg_was_linked = linked_keg.linked?
|
||||||
linked_keg.unlink
|
linked_keg.unlink
|
||||||
@ -724,12 +725,13 @@ class FormulaInstaller
|
|||||||
|
|
||||||
if df.latest_version_installed?
|
if df.latest_version_installed?
|
||||||
installed_keg = Keg.new(df.prefix)
|
installed_keg = Keg.new(df.prefix)
|
||||||
|
tab ||= Tab.for_keg(installed_keg)
|
||||||
tmp_keg = Pathname.new("#{installed_keg}.tmp")
|
tmp_keg = Pathname.new("#{installed_keg}.tmp")
|
||||||
installed_keg.rename(tmp_keg)
|
installed_keg.rename(tmp_keg)
|
||||||
end
|
end
|
||||||
|
|
||||||
tab_tap = tab.source["tap"]
|
if df.tap.present? && tab.present? && (tab_tap = tab.source["tap"].presence) &&
|
||||||
if tab_tap.present? && df.tap.present? && df.tap.to_s != tab_tap.to_s
|
df.tap.to_s != tab_tap.to_s
|
||||||
odie <<~EOS
|
odie <<~EOS
|
||||||
#{df} is already installed from #{tab_tap}!
|
#{df} is already installed from #{tab_tap}!
|
||||||
Please `brew uninstall #{df}` first."
|
Please `brew uninstall #{df}` first."
|
||||||
@ -737,7 +739,7 @@ class FormulaInstaller
|
|||||||
end
|
end
|
||||||
|
|
||||||
options = Options.new
|
options = Options.new
|
||||||
options |= tab.used_options
|
options |= tab.used_options if tab.present?
|
||||||
options |= Tab.remap_deprecated_options(df.deprecated_options, dep.options)
|
options |= Tab.remap_deprecated_options(df.deprecated_options, dep.options)
|
||||||
options |= inherited_options
|
options |= inherited_options
|
||||||
options &= df.options
|
options &= df.options
|
||||||
@ -748,7 +750,7 @@ class FormulaInstaller
|
|||||||
options: options,
|
options: options,
|
||||||
link_keg: keg_had_linked_keg ? keg_was_linked : nil,
|
link_keg: keg_had_linked_keg ? keg_was_linked : nil,
|
||||||
installed_as_dependency: true,
|
installed_as_dependency: true,
|
||||||
installed_on_request: df.any_version_installed? && tab.installed_on_request,
|
installed_on_request: df.any_version_installed? && tab.present? && tab.installed_on_request,
|
||||||
force_bottle: false,
|
force_bottle: false,
|
||||||
include_test_formulae: @include_test_formulae,
|
include_test_formulae: @include_test_formulae,
|
||||||
build_from_source_formulae: @build_from_source_formulae,
|
build_from_source_formulae: @build_from_source_formulae,
|
||||||
@ -759,7 +761,6 @@ class FormulaInstaller
|
|||||||
verbose: verbose?,
|
verbose: verbose?,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
fi.prelude
|
|
||||||
oh1 "Installing #{formula.full_name} dependency: #{Formatter.identifier(dep.name)}"
|
oh1 "Installing #{formula.full_name} dependency: #{Formatter.identifier(dep.name)}"
|
||||||
fi.install
|
fi.install
|
||||||
fi.finish
|
fi.finish
|
||||||
@ -901,13 +902,12 @@ class FormulaInstaller
|
|||||||
# 1. formulae can modify ENV, so we must ensure that each
|
# 1. formulae can modify ENV, so we must ensure that each
|
||||||
# installation has a pristine ENV when it starts, forking now is
|
# installation has a pristine ENV when it starts, forking now is
|
||||||
# the easiest way to do this
|
# the easiest way to do this
|
||||||
args = %W[
|
args = [
|
||||||
nice #{RUBY_PATH}
|
"nice",
|
||||||
#{ENV["HOMEBREW_RUBY_WARNINGS"]}
|
*HOMEBREW_RUBY_EXEC_ARGS,
|
||||||
-I #{$LOAD_PATH.join(File::PATH_SEPARATOR)}
|
"--",
|
||||||
--
|
HOMEBREW_LIBRARY_PATH/"build.rb",
|
||||||
#{HOMEBREW_LIBRARY_PATH}/build.rb
|
formula.specified_path,
|
||||||
#{formula.specified_path}
|
|
||||||
].concat(build_argv)
|
].concat(build_argv)
|
||||||
|
|
||||||
Utils.safe_fork do
|
Utils.safe_fork do
|
||||||
@ -1123,25 +1123,10 @@ class FormulaInstaller
|
|||||||
|
|
||||||
return if only_deps?
|
return if only_deps?
|
||||||
|
|
||||||
if pour_bottle?(output_warning: true)
|
unless pour_bottle?(output_warning: true)
|
||||||
begin
|
|
||||||
downloader.fetch
|
|
||||||
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
||||||
raise if Homebrew::EnvConfig.developer? ||
|
|
||||||
Homebrew::EnvConfig.no_bottle_source_fallback? ||
|
|
||||||
force_bottle? ||
|
|
||||||
e.is_a?(Interrupt)
|
|
||||||
|
|
||||||
@pour_failed = true
|
|
||||||
onoe e.message
|
|
||||||
opoo "Bottle installation failed: building from source."
|
|
||||||
fetch_dependencies
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return if pour_bottle?
|
|
||||||
|
|
||||||
formula.fetch_patches
|
formula.fetch_patches
|
||||||
formula.resources.each(&:fetch)
|
formula.resources.each(&:fetch)
|
||||||
|
end
|
||||||
downloader.fetch
|
downloader.fetch
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1170,10 +1155,12 @@ class FormulaInstaller
|
|||||||
|
|
||||||
tab = Tab.for_keg(keg)
|
tab = Tab.for_keg(keg)
|
||||||
|
|
||||||
|
unless ignore_deps?
|
||||||
CxxStdlib.check_compatibility(
|
CxxStdlib.check_compatibility(
|
||||||
formula, formula.recursive_dependencies,
|
formula, formula.recursive_dependencies,
|
||||||
Keg.new(formula.prefix), tab.compiler
|
Keg.new(formula.prefix), tab.compiler
|
||||||
)
|
)
|
||||||
|
end
|
||||||
|
|
||||||
tab.tap = formula.tap
|
tab.tap = formula.tap
|
||||||
tab.poured_from_bottle = true
|
tab.poured_from_bottle = true
|
||||||
@ -1253,10 +1240,9 @@ class FormulaInstaller
|
|||||||
end
|
end
|
||||||
|
|
||||||
return if forbidden_licenses.blank?
|
return if forbidden_licenses.blank?
|
||||||
|
return if ignore_deps?
|
||||||
|
|
||||||
compute_dependencies.each do |dep, _|
|
compute_dependencies.each do |dep, _|
|
||||||
next if @ignore_deps
|
|
||||||
|
|
||||||
dep_f = dep.to_formula
|
dep_f = dep.to_formula
|
||||||
next unless SPDX.licenses_forbid_installation? dep_f.license, forbidden_licenses
|
next unless SPDX.licenses_forbid_installation? dep_f.license, forbidden_licenses
|
||||||
|
|
||||||
@ -1265,7 +1251,8 @@ class FormulaInstaller
|
|||||||
#{SPDX.license_expression_to_string dep_f.license}.
|
#{SPDX.license_expression_to_string dep_f.license}.
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
return if @only_deps
|
|
||||||
|
return if only_deps?
|
||||||
|
|
||||||
return unless SPDX.licenses_forbid_installation? formula.license, forbidden_licenses
|
return unless SPDX.licenses_forbid_installation? formula.license, forbidden_licenses
|
||||||
|
|
||||||
|
|||||||
@ -33,6 +33,19 @@ module Formulary
|
|||||||
cache.fetch(path)
|
cache.fetch(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.clear_cache
|
||||||
|
cache.each do |key, klass|
|
||||||
|
next if key == :formulary_factory
|
||||||
|
|
||||||
|
namespace = klass.name.deconstantize
|
||||||
|
next if namespace.deconstantize != name
|
||||||
|
|
||||||
|
remove_const(namespace.demodulize)
|
||||||
|
end
|
||||||
|
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
def self.load_formula(name, path, contents, namespace, flags:)
|
def self.load_formula(name, path, contents, namespace, flags:)
|
||||||
raise "Formula loading disabled by HOMEBREW_DISABLE_LOAD_FORMULA!" if Homebrew::EnvConfig.disable_load_formula?
|
raise "Formula loading disabled by HOMEBREW_DISABLE_LOAD_FORMULA!" if Homebrew::EnvConfig.disable_load_formula?
|
||||||
|
|
||||||
@ -47,6 +60,7 @@ module Formulary
|
|||||||
mod.const_set(:BUILD_FLAGS, flags)
|
mod.const_set(:BUILD_FLAGS, flags)
|
||||||
mod.module_eval(contents, path)
|
mod.module_eval(contents, path)
|
||||||
rescue NameError, ArgumentError, ScriptError, MethodDeprecatedError => e
|
rescue NameError, ArgumentError, ScriptError, MethodDeprecatedError => e
|
||||||
|
remove_const(namespace)
|
||||||
raise FormulaUnreadableError.new(name, e)
|
raise FormulaUnreadableError.new(name, e)
|
||||||
end
|
end
|
||||||
class_name = class_s(name)
|
class_name = class_s(name)
|
||||||
@ -58,6 +72,7 @@ module Formulary
|
|||||||
.map { |const_name| mod.const_get(const_name) }
|
.map { |const_name| mod.const_get(const_name) }
|
||||||
.select { |const| const.is_a?(Class) }
|
.select { |const| const.is_a?(Class) }
|
||||||
new_exception = FormulaClassUnavailableError.new(name, path, class_name, class_list)
|
new_exception = FormulaClassUnavailableError.new(name, path, class_name, class_list)
|
||||||
|
remove_const(namespace)
|
||||||
raise new_exception, "", e.backtrace
|
raise new_exception, "", e.backtrace
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -467,14 +482,14 @@ module Formulary
|
|||||||
return FormulaLoader.new(name, path)
|
return FormulaLoader.new(name, path)
|
||||||
end
|
end
|
||||||
|
|
||||||
if newref = CoreTap.instance.formula_renames[ref]
|
if (newref = CoreTap.instance.formula_renames[ref])
|
||||||
formula_with_that_oldname = core_path(newref)
|
formula_with_that_oldname = core_path(newref)
|
||||||
return FormulaLoader.new(newref, formula_with_that_oldname) if formula_with_that_oldname.file?
|
return FormulaLoader.new(newref, formula_with_that_oldname) if formula_with_that_oldname.file?
|
||||||
end
|
end
|
||||||
|
|
||||||
possible_tap_newname_formulae = []
|
possible_tap_newname_formulae = []
|
||||||
Tap.each do |tap|
|
Tap.each do |tap|
|
||||||
if newref = tap.formula_renames[ref]
|
if (newref = tap.formula_renames[ref])
|
||||||
possible_tap_newname_formulae << "#{tap.name}/#{newref}"
|
possible_tap_newname_formulae << "#{tap.name}/#{newref}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
185
Library/Homebrew/github_packages.rb
Normal file
185
Library/Homebrew/github_packages.rb
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
# typed: false
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "utils/curl"
|
||||||
|
require "json"
|
||||||
|
|
||||||
|
# GitHub Packages client.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
class GitHubPackages
|
||||||
|
extend T::Sig
|
||||||
|
|
||||||
|
include Context
|
||||||
|
include Utils::Curl
|
||||||
|
|
||||||
|
URL_DOMAIN = "ghcr.io"
|
||||||
|
URL_PREFIX = "https://#{URL_DOMAIN}/v2/"
|
||||||
|
URL_REGEX = %r{#{Regexp.escape(URL_PREFIX)}([\w-]+)/([\w-]+)}.freeze
|
||||||
|
|
||||||
|
sig { returns(String) }
|
||||||
|
def inspect
|
||||||
|
"#<GitHubPackages: org=#{@github_org}>"
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { params(org: T.nilable(String)).void }
|
||||||
|
def initialize(org: "homebrew")
|
||||||
|
@github_org = org
|
||||||
|
|
||||||
|
raise UsageError, "Must set a GitHub organisation!" unless @github_org
|
||||||
|
|
||||||
|
ENV["HOMEBREW_FORCE_HOMEBREW_ON_LINUX"] = "1" if @github_org == "homebrew" && !OS.mac?
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { params(bottles_hash: T::Hash[String, T.untyped]).void }
|
||||||
|
def upload_bottles(bottles_hash)
|
||||||
|
user = Homebrew::EnvConfig.github_packages_user
|
||||||
|
token = Homebrew::EnvConfig.github_packages_token
|
||||||
|
|
||||||
|
raise UsageError, "HOMEBREW_GITHUB_PACKAGES_USER is unset." if user.blank?
|
||||||
|
raise UsageError, "HOMEBREW_GITHUB_PACKAGES_TOKEN is unset." if token.blank?
|
||||||
|
|
||||||
|
docker = HOMEBREW_PREFIX/"bin/docker"
|
||||||
|
unless docker.exist?
|
||||||
|
ohai "Installing `docker` for upload..."
|
||||||
|
safe_system HOMEBREW_BREW_FILE, "install", "--formula", "docker"
|
||||||
|
docker = Formula["docker"].opt_bin/"docker"
|
||||||
|
end
|
||||||
|
|
||||||
|
puts
|
||||||
|
system_command!(docker, verbose: true, print_stdout: true, input: token, args: [
|
||||||
|
"login", "--username", user, "--password-stdin", URL_DOMAIN
|
||||||
|
])
|
||||||
|
|
||||||
|
oras = HOMEBREW_PREFIX/"bin/oras"
|
||||||
|
unless oras.exist?
|
||||||
|
ohai "Installing `oras` for upload..."
|
||||||
|
safe_system HOMEBREW_BREW_FILE, "install", "oras"
|
||||||
|
oras = Formula["oras"].opt_bin/"oras"
|
||||||
|
end
|
||||||
|
|
||||||
|
bottles_hash.each do |formula_name, bottle_hash|
|
||||||
|
_, org, repo, = *bottle_hash["bottle"]["root_url"].match(URL_REGEX)
|
||||||
|
|
||||||
|
# docker CLI insists on lowercase org ("repository name")
|
||||||
|
org = org.downcase
|
||||||
|
image = "#{URL_DOMAIN}/#{org}/#{repo}/#{formula_name}"
|
||||||
|
|
||||||
|
version = bottle_hash["formula"]["pkg_version"]
|
||||||
|
rebuild = if (rebuild = bottle_hash["bottle"]["rebuild"]).positive?
|
||||||
|
".#{rebuild}"
|
||||||
|
end
|
||||||
|
|
||||||
|
formula_path = HOMEBREW_REPOSITORY/bottle_hash["formula"]["path"]
|
||||||
|
formula = Formulary.factory(formula_path)
|
||||||
|
|
||||||
|
image_tags = bottle_hash["bottle"]["tags"].map do |bottle_tag, tag_hash|
|
||||||
|
local_file = tag_hash["local_filename"]
|
||||||
|
odebug "Uploading #{local_file}"
|
||||||
|
|
||||||
|
tag = "#{version}.#{bottle_tag}#{rebuild}"
|
||||||
|
|
||||||
|
tab = Tab.from_file_content(
|
||||||
|
Utils.safe_popen_read("tar", "xfO", local_file, "#{formula_name}/#{version}/INSTALL_RECEIPT.json"),
|
||||||
|
"#{local_file}/#{formula_name}/#{version}",
|
||||||
|
)
|
||||||
|
created_time = tab.source_modified_time
|
||||||
|
created_time ||= Time.now
|
||||||
|
|
||||||
|
# TODO: ideally most/all of these attributes would be stored in the
|
||||||
|
# bottle JSON rather than reading them from the formula.
|
||||||
|
git_revision = formula.tap.git_head
|
||||||
|
git_path = formula_path.to_s.delete_prefix("#{formula.tap.path}/")
|
||||||
|
manifest_hash = {
|
||||||
|
"org.opencontainers.image.title" => formula.full_name,
|
||||||
|
"org.opencontainers.image.url" => formula.homepage,
|
||||||
|
"org.opencontainers.image.version" => version,
|
||||||
|
"org.opencontainers.image.revision" => git_revision,
|
||||||
|
"org.opencontainers.image.source" => "https://github.com/#{org}/#{repo}/blob/#{git_revision}/#{git_path}",
|
||||||
|
"org.opencontainers.image.created" => created_time.strftime("%F"),
|
||||||
|
}
|
||||||
|
manifest_hash["org.opencontainers.image.description"] = formula.desc if formula.desc.present?
|
||||||
|
manifest_hash["org.opencontainers.image.license"] = formula.license if formula.license.present?
|
||||||
|
|
||||||
|
manifest_annotations = Pathname("#{formula_name}.#{tag}.annotations.json")
|
||||||
|
manifest_annotations.unlink if manifest_annotations.exist?
|
||||||
|
manifest_annotations.write({ "$manifest" => manifest_hash }.to_json)
|
||||||
|
|
||||||
|
os_version = if tab.built_on.present?
|
||||||
|
/(\d+\.)*\d+/ =~ tab.built_on["os_version"]
|
||||||
|
Regexp.last_match(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO: ideally most/all of these attributes would be stored in the
|
||||||
|
# bottle JSON rather than reading them from the formula.
|
||||||
|
os, arch = if @bottle_tag.to_s.end_with?("_linux")
|
||||||
|
["linux", "amd64"]
|
||||||
|
else
|
||||||
|
os = "darwin"
|
||||||
|
macos_version = MacOS::Version.from_symbol(bottle_tag.to_sym)
|
||||||
|
os_version ||= macos_version.to_f.to_s
|
||||||
|
arch = if macos_version.arch == :arm64
|
||||||
|
"arm64"
|
||||||
|
else
|
||||||
|
"amd64"
|
||||||
|
end
|
||||||
|
[os, arch]
|
||||||
|
end
|
||||||
|
|
||||||
|
tar_sha256 = Digest::SHA256.hexdigest(
|
||||||
|
Utils.safe_popen_read("gunzip", "--stdout", "--decompress", local_file),
|
||||||
|
)
|
||||||
|
|
||||||
|
config_hash = {
|
||||||
|
"architecture" => arch,
|
||||||
|
"os" => os,
|
||||||
|
"os.version" => os_version,
|
||||||
|
"rootfs" => {
|
||||||
|
"type" => "layers",
|
||||||
|
"diff_ids" => ["sha256:#{tar_sha256}"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest_config = Pathname("#{formula_name}.#{tag}.config.json")
|
||||||
|
manifest_config.unlink if manifest_config.exist?
|
||||||
|
manifest_config.write(config_hash.to_json)
|
||||||
|
|
||||||
|
# TODO: If we push the architecture-specific images to the tag :latest,
|
||||||
|
# then we don't need to delete the architecture-specific tags.
|
||||||
|
image_tag = "#{image}:#{tag}"
|
||||||
|
puts
|
||||||
|
system_command!(oras, verbose: true, print_stdout: true, args: [
|
||||||
|
"push", image_tag,
|
||||||
|
"--verbose",
|
||||||
|
"--manifest-annotations=#{manifest_annotations}",
|
||||||
|
"--manifest-config=#{manifest_config}:application/vnd.oci.image.config.v1+json",
|
||||||
|
"--username", user,
|
||||||
|
"--password", token,
|
||||||
|
"#{local_file}:application/vnd.oci.image.layer.v1.tar+gzip"
|
||||||
|
])
|
||||||
|
|
||||||
|
image_tag
|
||||||
|
end
|
||||||
|
|
||||||
|
image_tag = "#{image}:#{version}#{rebuild}"
|
||||||
|
puts
|
||||||
|
system_command!(docker, verbose: true, print_stdout: true, args: [
|
||||||
|
"buildx", "imagetools", "create", "--tag", image_tag, *image_tags
|
||||||
|
])
|
||||||
|
|
||||||
|
# TODO: once the main image metadata is working correctly delete the package using:
|
||||||
|
# `curl -X DELETE -u $HOMEBREW_GITHUB_PACKAGES_USER:$HOMEBREW_GITHUB_PACKAGES_TOKEN
|
||||||
|
# https://api.github.com/orgs/Homebrew/packages/container/homebrew-core%2F$PACKAGE/versions/$VERSION`
|
||||||
|
# Alternatively, if we push the architecture-specific images to the tag :latest,
|
||||||
|
# then we don't need to delete the architecture-specific tags.
|
||||||
|
# Alternatively, remove all usage of `docker` here instead.
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
if docker
|
||||||
|
puts
|
||||||
|
system_command!(docker, verbose: true, print_stdout: true, args: [
|
||||||
|
"logout", URL_DOMAIN
|
||||||
|
])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
44
Library/Homebrew/github_releases.rb
Normal file
44
Library/Homebrew/github_releases.rb
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# typed: false
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "utils/github"
|
||||||
|
require "json"
|
||||||
|
|
||||||
|
# GitHub Releases client.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
class GitHubReleases
|
||||||
|
extend T::Sig
|
||||||
|
|
||||||
|
include Context
|
||||||
|
include Utils::Curl
|
||||||
|
|
||||||
|
URL_REGEX = %r{https://github\.com/([\w-]+)/([\w-]+)?/releases/download/(.+)}.freeze
|
||||||
|
|
||||||
|
sig { params(bottles_hash: T::Hash[String, T.untyped]).void }
|
||||||
|
def upload_bottles(bottles_hash)
|
||||||
|
bottles_hash.each_value do |bottle_hash|
|
||||||
|
root_url = bottle_hash["bottle"]["root_url"]
|
||||||
|
url_match = root_url.match URL_REGEX
|
||||||
|
_, user, repo, tag = *url_match
|
||||||
|
|
||||||
|
# Ensure a release is created.
|
||||||
|
release = begin
|
||||||
|
rel = GitHub.get_release user, repo, tag
|
||||||
|
odebug "Existing GitHub release \"#{tag}\" found"
|
||||||
|
rel
|
||||||
|
rescue GitHub::API::HTTPNotFoundError
|
||||||
|
odebug "Creating new GitHub release \"#{tag}\""
|
||||||
|
GitHub.create_or_update_release user, repo, tag
|
||||||
|
end
|
||||||
|
|
||||||
|
# Upload bottles as release assets.
|
||||||
|
bottle_hash["bottle"]["tags"].each_value do |tag_hash|
|
||||||
|
remote_file = tag_hash["filename"]
|
||||||
|
local_file = tag_hash["local_filename"]
|
||||||
|
odebug "Uploading #{remote_file}"
|
||||||
|
GitHub.upload_release_asset user, repo, release["id"], local_file: local_file, remote_file: remote_file
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -16,7 +16,6 @@ require "rbconfig"
|
|||||||
RUBY_PATH = Pathname.new(RbConfig.ruby).freeze
|
RUBY_PATH = Pathname.new(RbConfig.ruby).freeze
|
||||||
RUBY_BIN = RUBY_PATH.dirname.freeze
|
RUBY_BIN = RUBY_PATH.dirname.freeze
|
||||||
|
|
||||||
require "rubygems"
|
|
||||||
# Only require "core_ext" here to ensure we're only requiring the minimum of
|
# Only require "core_ext" here to ensure we're only requiring the minimum of
|
||||||
# what we need.
|
# what we need.
|
||||||
require "active_support/core_ext/object/blank"
|
require "active_support/core_ext/object/blank"
|
||||||
@ -72,8 +71,6 @@ HOMEBREW_PULL_API_REGEX =
|
|||||||
%r{https://api\.github\.com/repos/([\w-]+)/([\w-]+)?/pulls/(\d+)}.freeze
|
%r{https://api\.github\.com/repos/([\w-]+)/([\w-]+)?/pulls/(\d+)}.freeze
|
||||||
HOMEBREW_PULL_OR_COMMIT_URL_REGEX =
|
HOMEBREW_PULL_OR_COMMIT_URL_REGEX =
|
||||||
%r[https://github\.com/([\w-]+)/([\w-]+)?/(?:pull/(\d+)|commit/[0-9a-fA-F]{4,40})].freeze
|
%r[https://github\.com/([\w-]+)/([\w-]+)?/(?:pull/(\d+)|commit/[0-9a-fA-F]{4,40})].freeze
|
||||||
HOMEBREW_RELEASES_URL_REGEX =
|
|
||||||
%r{https://github\.com/([\w-]+)/([\w-]+)?/releases/download/(.+)}.freeze
|
|
||||||
|
|
||||||
require "fileutils"
|
require "fileutils"
|
||||||
|
|
||||||
|
|||||||
@ -1,22 +1,27 @@
|
|||||||
# typed: false
|
# typed: false
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
if !ENV["HOMEBREW_NO_BOOTSNAP"] &&
|
homebrew_bootsnap_enabled = !ENV["HOMEBREW_NO_BOOTSNAP"] && ENV["HOMEBREW_BOOTSNAP"]
|
||||||
ENV["HOMEBREW_BOOTSNAP"] &&
|
|
||||||
# portable ruby doesn't play nice with bootsnap
|
# portable ruby doesn't play nice with bootsnap
|
||||||
!ENV["HOMEBREW_FORCE_VENDOR_RUBY"] &&
|
# Can't use .exclude? here because we haven't required active_support yet.
|
||||||
(!ENV["HOMEBREW_MACOS_VERSION"] || ENV["HOMEBREW_MACOS_SYSTEM_RUBY_NEW_ENOUGH"]) &&
|
homebrew_bootsnap_enabled &&= !ENV["HOMEBREW_RUBY_PATH"].to_s.include?("/vendor/portable-ruby/") # rubocop:disable Rails/NegateInclude
|
||||||
|
|
||||||
|
homebrew_bootsnap_enabled &&= if ENV["HOMEBREW_MACOS_VERSION"]
|
||||||
# Apple Silicon doesn't play nice with bootsnap
|
# Apple Silicon doesn't play nice with bootsnap
|
||||||
(ENV["HOMEBREW_PROCESSOR"] == "Intel")
|
ENV["HOMEBREW_PROCESSOR"] == "Intel" &&
|
||||||
|
# we need some development tools to build bootsnap native code
|
||||||
require "rubygems"
|
(File.directory?("/Applications/Xcode.app") || File.directory?("/Library/Developer/CommandLineTools"))
|
||||||
|
else
|
||||||
|
File.executable?("/usr/bin/clang") || File.executable?("/usr/bin/gcc")
|
||||||
|
end
|
||||||
|
|
||||||
|
if homebrew_bootsnap_enabled
|
||||||
begin
|
begin
|
||||||
require "bootsnap"
|
require "bootsnap"
|
||||||
rescue LoadError
|
rescue LoadError
|
||||||
unless ENV["HOMEBREW_BOOTSNAP_RETRY"]
|
unless ENV["HOMEBREW_BOOTSNAP_RETRY"]
|
||||||
require "utils/gems"
|
Homebrew.install_bundler_gems!(only_warn_on_failure: true)
|
||||||
Homebrew.install_bundler_gems!
|
|
||||||
|
|
||||||
ENV["HOMEBREW_BOOTSNAP_RETRY"] = "1"
|
ENV["HOMEBREW_BOOTSNAP_RETRY"] = "1"
|
||||||
exec ENV["HOMEBREW_BREW_FILE"], *ARGV
|
exec ENV["HOMEBREW_BREW_FILE"], *ARGV
|
||||||
|
|||||||
74
Library/Homebrew/installed_dependents.rb
Normal file
74
Library/Homebrew/installed_dependents.rb
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# typed: false
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "cask_dependent"
|
||||||
|
|
||||||
|
# Helper functions for installed dependents.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
module InstalledDependents
|
||||||
|
extend T::Sig
|
||||||
|
|
||||||
|
module_function
|
||||||
|
|
||||||
|
# Given an array of kegs, this method will try to find some other kegs
|
||||||
|
# or casks that depend on them. If it does, it returns:
|
||||||
|
#
|
||||||
|
# - some kegs in the passed array that have installed dependents
|
||||||
|
# - some installed dependents of those kegs.
|
||||||
|
#
|
||||||
|
# If it doesn't, it returns nil.
|
||||||
|
#
|
||||||
|
# Note that nil will be returned if the only installed dependents of the
|
||||||
|
# passed kegs are other kegs in the array or casks present in the casks
|
||||||
|
# parameter.
|
||||||
|
#
|
||||||
|
# For efficiency, we don't bother trying to get complete data.
|
||||||
|
def find_some_installed_dependents(kegs, casks: [])
|
||||||
|
keg_names = kegs.select(&:optlinked?).map(&:name)
|
||||||
|
keg_formulae = []
|
||||||
|
kegs_by_source = kegs.group_by do |keg|
|
||||||
|
# First, attempt to resolve the keg to a formula
|
||||||
|
# to get up-to-date name and tap information.
|
||||||
|
f = keg.to_formula
|
||||||
|
keg_formulae << f
|
||||||
|
[f.name, f.tap]
|
||||||
|
rescue
|
||||||
|
# If the formula for the keg can't be found,
|
||||||
|
# fall back to the information in the tab.
|
||||||
|
[keg.name, keg.tab.tap]
|
||||||
|
end
|
||||||
|
|
||||||
|
all_required_kegs = Set.new
|
||||||
|
all_dependents = []
|
||||||
|
|
||||||
|
# Don't include dependencies of kegs that were in the given array.
|
||||||
|
dependents_to_check = (Formula.installed - keg_formulae) + (Cask::Caskroom.casks - casks)
|
||||||
|
|
||||||
|
dependents_to_check.each do |dependent|
|
||||||
|
required = case dependent
|
||||||
|
when Formula
|
||||||
|
dependent.missing_dependencies(hide: keg_names)
|
||||||
|
when Cask::Cask
|
||||||
|
CaskDependent.new(dependent).runtime_dependencies.map(&:to_formula)
|
||||||
|
end
|
||||||
|
|
||||||
|
required_kegs = required.map do |f|
|
||||||
|
f_kegs = kegs_by_source[[f.name, f.tap]]
|
||||||
|
next unless f_kegs
|
||||||
|
|
||||||
|
f_kegs.max_by(&:version)
|
||||||
|
end.compact
|
||||||
|
|
||||||
|
next if required_kegs.empty?
|
||||||
|
|
||||||
|
all_required_kegs += required_kegs
|
||||||
|
all_dependents << dependent.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
return if all_required_kegs.empty?
|
||||||
|
return if all_dependents.empty?
|
||||||
|
|
||||||
|
[all_required_kegs.to_a, all_dependents.sort]
|
||||||
|
end
|
||||||
|
end
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user